Skip to content

Commit

Permalink
feat: unaccepted requests in admin page
Browse files Browse the repository at this point in the history
  • Loading branch information
tomaspalma committed Feb 10, 2025
1 parent 1e91f63 commit df2ed9e
Show file tree
Hide file tree
Showing 6 changed files with 209 additions and 5 deletions.
2 changes: 2 additions & 0 deletions src/@types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -130,8 +130,10 @@ export type MarketplaceRequest = {
date: string,
options?: Array<ExchangeOption>,
classes?: Array<ClassInfo>,
admin_state: string,
pending_motive?: DirectExchangePendingMotive,
accepted: boolean,
admin_state: string,
canceled: boolean
}

Expand Down
16 changes: 13 additions & 3 deletions src/components/admin/AdminMainContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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<number | undefined>(undefined);
Expand Down Expand Up @@ -39,24 +40,30 @@ export const AdminMainContent = () => {
</div>
<Tabs defaultValue="exchange-with-student">
<TabsList className="w-full">
<TabsTrigger
<TabsTrigger
value="exchange-with-student"
onClick={() => setCurrPage(1)}
>
Trocas entre estudantes
</TabsTrigger>
<TabsTrigger
<TabsTrigger
value="exchange-singular"
onClick={() => setCurrPage(1)}
>
Trocas individuais
</TabsTrigger>
<TabsTrigger
<TabsTrigger
value="enrollments"
onClick={() => setCurrPage(1)}
>
Inscrições
</TabsTrigger>
<TabsTrigger
value="admin-marketplace"
onClick={() => setCurrPage(1)}
>
Marketplace
</TabsTrigger>
</TabsList>
<TabsContent value="exchange-with-student">
<MultipleStudentExchanges />
Expand All @@ -67,6 +74,9 @@ export const AdminMainContent = () => {
<TabsContent value="enrollments">
<StudentEnrollments />
</TabsContent>
<TabsContent value="admin-marketplace">
<AdminMarketplaceExhanges />
</TabsContent>

<div className="mt-8">
<AdminPagination />
Expand Down
126 changes: 126 additions & 0 deletions src/components/admin/AdminMarketplaceExchangesCard.tsx
Original file line number Diff line number Diff line change
@@ -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<boolean>(false);
const [exchangeState, setExchangeState] = useState(exchange);

const { schedule } = useStudentsSchedule(exchange.issuer_nmec);

return (<>
<Card>
<CardHeader className="flex flex-row justify-between items-center">
<div className="flex gap-4 items-center">
<div className="flex flex-col gap-1 ">
<div className="flex gap-2 items-center">
<CardTitle>
<h2 className="font-bold">
{`#${exchange.id}`}
</h2>
</CardTitle>
<ExchangeStatus exchange={exchangeState} />

Check failure on line 38 in src/components/admin/AdminMarketplaceExchangesCard.tsx

View workflow job for this annotation

GitHub Actions / Lint (21.x)

Type 'MarketplaceRequest' is not assignable to type 'DirectExchangeRequest | UrgentRequest | CourseUnitEnrollment'.
</div>
<RequestDate
date={exchange.date}
/>
</div>
{!open && <>
<Person name={exchange.issuer_name} nmec={exchange.issuer_nmec} />
</>}

</div>
<div>
<Button
onClick={() => setOpen(prev => !prev)}
className="bg-white text-black border-2 border-black hover:text-white"
>
{open
? <ChevronUpIcon className="w-5 h-5" />
: <ChevronDownIcon className="w-5 h-5" />
}
</Button>
</div>
</CardHeader>

<CardContent className="w-full ">
{open &&
<div className="flex flex-col gap-y-8" key={crypto.randomUUID()}>
<div className="flex justify-between">
<Person name={exchange.issuer_name} nmec={exchange.issuer_nmec} />
<div>
<div
key={crypto.randomUUID()}
className="flex flex-col gap-y-2 items-center border-gray-200 border-2 rounded-md p-2 px-4"
>
<>{exchange.options.map((option) => (
<div key={crypto.randomUUID()} className="flex gap-5 items-center">
<h2 className="font-bold">{option.course_info.acronym}</h2>
<div className="flex gap-2 items-center">
<p>{option.class_issuer_goes_from.name}</p>
<ArrowRightIcon className="w-5 h-5" />
<p>{option.class_issuer_goes_to.name}</p>
</div>
</div>
))}
</>
</div>
</div>
<div>
<AdminPreviewSchedule
originalSchedule={schedule}
classesToAdd={
exchange.options.map((option): ClassDescriptor => {
return {
classInfo: option.class_issuer_goes_to,
courseInfo: option.course_info,
slotInfo: null
}
})
}

/>
</div>
</div>
</div>
}
</CardContent>

{open &&
<AdminRequestCardFooter
nmecs={[exchange.issuer_nmec]}
exchangeMessage={listEmailExchanges(
exchange.options.map(option => ({
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)}
/>
}
</Card>
</>
)
}
24 changes: 24 additions & 0 deletions src/components/admin/requests/AdminMarketplaceExhanges.tsx
Original file line number Diff line number Diff line change
@@ -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 && <BarLoader className="w-full" />}

{exchanges?.map((exchange) => (
<AdminMarketplaceExhangesCard
key={`admin-marketplace-${exchange.id}`}
exchange={exchange}
/>
))}
</>
)
}
Original file line number Diff line number Diff line change
@@ -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"
Expand All @@ -15,7 +15,7 @@ type Props = {
requestType: AdminRequestType,
requestId: number,
showTreatButton?: boolean,
setExchange?: Dispatch<SetStateAction<DirectExchangeRequest | UrgentRequest | CourseUnitEnrollment>>
setExchange?: Dispatch<SetStateAction<DirectExchangeRequest | UrgentRequest | CourseUnitEnrollment | MarketplaceRequest>>
courseId: Array<number>
}

Expand Down
42 changes: 42 additions & 0 deletions src/hooks/admin/useAdminAllMarketplaceExchanges.tsx
Original file line number Diff line number Diff line change
@@ -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,
};
};


0 comments on commit df2ed9e

Please sign in to comment.