diff --git a/src/@types/index.d.ts b/src/@types/index.d.ts index cc0a1a10..f187d2c8 100644 --- a/src/@types/index.d.ts +++ b/src/@types/index.d.ts @@ -130,8 +130,10 @@ export type MarketplaceRequest = { date: string, options?: Array, classes?: Array, + admin_state: string, pending_motive?: DirectExchangePendingMotive, accepted: boolean, + admin_state: string, canceled: boolean } diff --git a/src/components/admin/AdminMainContent.tsx b/src/components/admin/AdminMainContent.tsx index ef279fa1..1a0ecb32 100644 --- a/src/components/admin/AdminMainContent.tsx +++ b/src/components/admin/AdminMainContent.tsx @@ -8,6 +8,7 @@ import { AdminRequestState } from "../../contexts/admin/RequestFiltersContext"; import RequestFiltersContext from "../../contexts/admin/RequestFiltersContext"; import { AdminPagination } from "./AdminPagination"; import AdminPaginationContext from "../../contexts/admin/AdminPaginationContext"; +import { AdminMarketplaceExhanges } from "./requests/AdminMarketplaceExhanges"; export const AdminMainContent = () => { const [activeCourse, setActiveCourse] = useState(undefined); @@ -39,24 +40,30 @@ export const AdminMainContent = () => { - setCurrPage(1)} > Trocas entre estudantes - setCurrPage(1)} > Trocas individuais - setCurrPage(1)} > Inscrições + setCurrPage(1)} + > + Marketplace + @@ -67,6 +74,9 @@ export const AdminMainContent = () => { + + +
diff --git a/src/components/admin/AdminMarketplaceExchangesCard.tsx b/src/components/admin/AdminMarketplaceExchangesCard.tsx new file mode 100644 index 00000000..6b0fa538 --- /dev/null +++ b/src/components/admin/AdminMarketplaceExchangesCard.tsx @@ -0,0 +1,126 @@ +import { useState } from "react" +import { Button } from "../ui/button" +import { Card, CardContent, CardHeader, CardTitle } from "../ui/card" +import { ExchangeStatus } from "./requests/cards/ExchangeStatus" +import { Person } from "./requests/cards/Person" +import { RequestDate } from "./requests/cards/RequestDate" +import { ArrowRightIcon, ChevronDownIcon, ChevronUpIcon } from "lucide-react" +import { AdminPreviewSchedule } from "./requests/AdminPreviewSchedule" +import useStudentsSchedule from "../../hooks/admin/useStudentsSchedule" +import { ClassDescriptor, MarketplaceRequest } from "../../@types" +import { AdminRequestCardFooter } from "./requests/cards/AdminRequestCardFooter" +import { listEmailExchanges } from "../../utils/mail" +import { AdminRequestType } from "../../utils/exchange" + +type Props = { + exchange: MarketplaceRequest +} + +export const AdminMarketplaceExhangesCard = ({ + exchange +}: Props) => { + const [open, setOpen] = useState(false); + const [exchangeState, setExchangeState] = useState(exchange); + + const { schedule } = useStudentsSchedule(exchange.issuer_nmec); + + return (<> + + +
+
+
+ +

+ {`#${exchange.id}`} +

+
+ +
+ +
+ {!open && <> + + } + +
+
+ +
+
+ + + {open && +
+
+ +
+
+ <>{exchange.options.map((option) => ( +
+

{option.course_info.acronym}

+
+

{option.class_issuer_goes_from.name}

+ +

{option.class_issuer_goes_to.name}

+
+
+ ))} + +
+
+
+ { + return { + classInfo: option.class_issuer_goes_to, + courseInfo: option.course_info, + slotInfo: null + } + }) + } + + /> +
+
+
+ } +
+ + {open && + ({ + participant_name: undefined, + participant_nmec: exchange.issuer_nmec, + goes_from: option.class_issuer_goes_from.name, + goes_to: option.class_issuer_goes_to.name, + course_acronym: option.course_info.acronym + })) + )} + requestType={AdminRequestType.URGENT_EXCHANGE} + requestId={exchange.id} + setExchange={setExchangeState} + courseId={exchange.options.map(option => option.course_info.course)} + /> + } +
+ + ) +} \ No newline at end of file diff --git a/src/components/admin/requests/AdminMarketplaceExhanges.tsx b/src/components/admin/requests/AdminMarketplaceExhanges.tsx new file mode 100644 index 00000000..0721cfa9 --- /dev/null +++ b/src/components/admin/requests/AdminMarketplaceExhanges.tsx @@ -0,0 +1,24 @@ +import { useContext, useState } from "react"; +import RequestFiltersContext from "../../../contexts/admin/RequestFiltersContext"; +import useAdminAllMarketplaceExchanges from "../../../hooks/admin/useAdminAllMarketplaceExchanges" +import AdminPaginationContext from "../../../contexts/admin/AdminPaginationContext"; +import { BarLoader } from "react-spinners"; +import { AdminMarketplaceExhangesCard } from "../AdminMarketplaceExchangesCard"; + +export const AdminMarketplaceExhanges = () => { + const filterContext = useContext(RequestFiltersContext); + const { currPage } = useContext(AdminPaginationContext); + const { exchanges, loading } = useAdminAllMarketplaceExchanges(filterContext, currPage); + + return (<> + {loading && } + + {exchanges?.map((exchange) => ( + + ))} + + ) +} \ No newline at end of file diff --git a/src/components/admin/requests/cards/AdminRequestCardFooter.tsx b/src/components/admin/requests/cards/AdminRequestCardFooter.tsx index 8b948c96..0ee952df 100644 --- a/src/components/admin/requests/cards/AdminRequestCardFooter.tsx +++ b/src/components/admin/requests/cards/AdminRequestCardFooter.tsx @@ -1,5 +1,5 @@ import { Dispatch, SetStateAction } from "react" -import { CourseUnitEnrollment, DirectExchangeRequest, UrgentRequest } from "../../../../@types" +import { CourseUnitEnrollment, DirectExchangeRequest, MarketplaceRequest, UrgentRequest } from "../../../../@types" import { AdminRequestType } from "../../../../utils/exchange" import exchangeRequestService from "../../../../api/services/exchangeRequestService" import { mailtoStringBuilder } from "../../../../utils/mail" @@ -15,7 +15,7 @@ type Props = { requestType: AdminRequestType, requestId: number, showTreatButton?: boolean, - setExchange?: Dispatch> + setExchange?: Dispatch> courseId: Array } diff --git a/src/hooks/admin/useAdminAllMarketplaceExchanges.tsx b/src/hooks/admin/useAdminAllMarketplaceExchanges.tsx new file mode 100644 index 00000000..5a972b37 --- /dev/null +++ b/src/hooks/admin/useAdminAllMarketplaceExchanges.tsx @@ -0,0 +1,42 @@ +import { useMemo } from "react"; +import api from "../../api/backend"; +import useSWR from "swr"; +import { RequestFiltersContextContent } from "../../contexts/admin/RequestFiltersContext"; +import { buildUrlWithFilterParams } from "../../utils/admin/filters"; + +/** + * Gets the exchanges that a student made not involving any other student. +*/ +export default (filterContext: RequestFiltersContextContent, pageIndex: number) => { + const getExchanges = async (url: string) => { + try { + const res = await fetch(url, { + credentials: "include" + }); + + if(res.ok) { + return await res.json(); + } + } catch (error) { + console.error(error); + } + }; + + const { data, error, mutate } = useSWR( + buildUrlWithFilterParams(`${api.BACKEND_URL}/exchange/admin/marketplace?page=${pageIndex}`, filterContext), + getExchanges + ); + + const exchanges = useMemo(() => data ? [].concat(...data["exchanges"]) : null, [data]); + const totalPages = useMemo(() => data ? data["total_pages"] : null, [data]); + + return { + exchanges, + totalPages, + error, + loading: !data, + mutate, + }; +}; + +