From 6986b85bca4c861fdda1dceb6c42697fe0a60a83 Mon Sep 17 00:00:00 2001 From: Juan Carlos Sigler Priego Date: Tue, 29 Oct 2024 22:03:14 -0400 Subject: [PATCH] use swr in getMentorAvailabilities --- package-lock.json | 22 +++ package.json | 1 + src/components/mentorias/index.tsx | 224 +++++++++++++++++++---------- src/pages/mentorias.tsx | 55 +------ src/types/mentor.schema.ts | 22 +-- 5 files changed, 188 insertions(+), 136 deletions(-) diff --git a/package-lock.json b/package-lock.json index e264f89..2ccc490 100644 --- a/package-lock.json +++ b/package-lock.json @@ -47,6 +47,7 @@ "remark-gfm": "^4.0.0", "remark-mdx-frontmatter": "^4.0.0", "sharp": "^0.33.5", + "swr": "^2.2.5", "tailwindest": "^2.2.1", "typescript": "5.2.2" }, @@ -10726,6 +10727,18 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/swr": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/swr/-/swr-2.2.5.tgz", + "integrity": "sha512-QtxqyclFeAsxEUeZIYmsaQ0UjimSq1RZ9Un7I68/0ClKK/U3LoyQunwkQfJZr2fc22DfIXLNDc2wFyTEikCUpg==", + "dependencies": { + "client-only": "^0.0.1", + "use-sync-external-store": "^1.2.0" + }, + "peerDependencies": { + "react": "^16.11.0 || ^17.0.0 || ^18.0.0" + } + }, "node_modules/symbol-tree": { "version": "3.2.4", "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", @@ -19729,6 +19742,15 @@ "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==" }, + "swr": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/swr/-/swr-2.2.5.tgz", + "integrity": "sha512-QtxqyclFeAsxEUeZIYmsaQ0UjimSq1RZ9Un7I68/0ClKK/U3LoyQunwkQfJZr2fc22DfIXLNDc2wFyTEikCUpg==", + "requires": { + "client-only": "^0.0.1", + "use-sync-external-store": "^1.2.0" + } + }, "symbol-tree": { "version": "3.2.4", "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", diff --git a/package.json b/package.json index 26971f7..c949c9c 100644 --- a/package.json +++ b/package.json @@ -57,6 +57,7 @@ "remark-gfm": "^4.0.0", "remark-mdx-frontmatter": "^4.0.0", "sharp": "^0.33.5", + "swr": "^2.2.5", "tailwindest": "^2.2.1", "typescript": "5.2.2" }, diff --git a/src/components/mentorias/index.tsx b/src/components/mentorias/index.tsx index c9ac568..619a966 100644 --- a/src/components/mentorias/index.tsx +++ b/src/components/mentorias/index.tsx @@ -1,20 +1,83 @@ -import { UserAvailability } from "@/types/mentor.schema"; +import useSWR from "swr"; +import { + type GetAvailabilitiesRequest, + UserAvailability, + GetAvailabilitiesResponseSchema, +} from "@/types/mentor.schema"; import Calendar from "react-calendar"; import { useState } from "react"; import { InlineWidget } from "react-calendly"; import { Link } from "../link"; -import { getLocalDateTimeWithOffset } from "@/utils/time"; +import { getLocalDateTimeWithOffset, nextHalfHour } from "@/utils/time"; +import { Value } from "@sinclair/typebox/value"; + +const fetcher = (args: RequestInfo): Promise => + fetch(args).then((res) => res.json()); + +function useGetMentorAvailabilities({ + ofmiEdition, + startTimeISOString, + endTimeISOString, +}: { + ofmiEdition: number; + startTimeISOString: string; + endTimeISOString: string; +}): Array | null { + const request: GetAvailabilitiesRequest = { + startTime: startTimeISOString, + endTime: endTimeISOString, + ofmiEdition, + }; + const { data } = useSWR( + `/api/volunteer/getMentorAvailabilities?${new URLSearchParams({ + ...request, + ofmiEdition: request.ofmiEdition.toString(), + }).toString()}`, + fetcher, + ); + if (Value.Check(GetAvailabilitiesResponseSchema, data)) { + return data.availabilities; + } + return null; +} + +function Loading(): JSX.Element { + return ( +
+ + Loading... +
+ ); +} // Receives a list of connected providers export default function Mentorias({ - startTime, - endTime, - availabilities, + ofmiEdition, }: { - startTime: Date; - endTime: Date; - availabilities: Array; + ofmiEdition: number; }): JSX.Element { + const startTime = nextHalfHour(new Date(Date.now())); + const endTime = new Date(startTime.getTime() + 7 * 24 * 60 * 60 * 1000); + const availabilities = useGetMentorAvailabilities({ + ofmiEdition, + startTimeISOString: startTime.toISOString(), + endTimeISOString: endTime.toISOString(), + }); const [selectedDay, setSelectedDay] = useState(); const [selectedStartTime, setSelectedStartTime] = useState(); const [schedulingUrlToShow, setSchedulingUrlToShow] = useState(); @@ -30,18 +93,21 @@ export default function Mentorias({ : schedulingUrlToShow) ); }; - const availableLocalDates = new Set( - availabilities - .map((v) => - v.availableStartTimes.map((startTime) => { - const time = new Date(startTime); - return time.toLocaleDateString(); - }), - ) - .flat(), - ); + const availableLocalDates = + availabilities && + new Set( + availabilities + .map((v) => + v.availableStartTimes.map((startTime) => { + const time = new Date(startTime); + return time.toLocaleDateString(); + }), + ) + .flat(), + ); const availableLocalStartTimes = + availabilities && selectedDay && Array.from( new Set( @@ -64,9 +130,10 @@ export default function Mentorias({ .map((v) => new Date(v)); return ( -
+
{/* Filter calendar */} -
+

MentorĂ­as

+
{schedulingUrlToShow && (
diff --git a/src/pages/mentorias.tsx b/src/pages/mentorias.tsx index d72a499..a8906c6 100644 --- a/src/pages/mentorias.tsx +++ b/src/pages/mentorias.tsx @@ -3,68 +3,21 @@ import type { InferGetServerSidePropsType, } from "next/types"; import { findMostRecentOfmi } from "@/lib/ofmi"; -import { Alert } from "@/components/alert"; -import { getAllAvailabilities } from "@/lib/volunteer/mentor"; -import { nextHalfHour } from "@/utils/time"; -import { UserAvailability } from "@/types/mentor.schema"; import Mentorias from "@/components/mentorias"; export default function MentoriasPage({ - startTime, - endTime, - availabilities, - errorMsg, + ofmiEdition, }: InferGetServerSidePropsType): JSX.Element { - if (errorMsg != null) { - return ( -
- -
- ); - } - - return ( - - ); + return ; } export const getServerSideProps: GetServerSideProps<{ - startTime: string; - endTime: string; - availabilities: Array; - errorMsg: string | null; + ofmiEdition: number; }> = async () => { const ofmi = await findMostRecentOfmi(); - - const startTime = nextHalfHour(new Date(Date.now())); - const endTime = new Date(startTime.getTime() + 7 * 24 * 60 * 60 * 1000); - - const availabilities = - ofmi && - (await getAllAvailabilities({ - ofmiEdition: ofmi.edition, - startTime, - endTime, - })); - - let errorMsg: string | null = null; - if (!ofmi) { - errorMsg = "No hay ninguna ofmi en curso."; - } - return { props: { - startTime: startTime.toISOString(), - endTime: endTime.toISOString(), - availabilities: availabilities || [], - errorMsg, + ofmiEdition: ofmi.edition, }, }; }; diff --git a/src/types/mentor.schema.ts b/src/types/mentor.schema.ts index 00b7853..4bd1cd2 100644 --- a/src/types/mentor.schema.ts +++ b/src/types/mentor.schema.ts @@ -10,13 +10,17 @@ export const GetAvailabilitiesRequestSchema = Type.Object({ endTime: Type.String({ pattern: toISOStringReg }), }); -export type UserAvailability = { - firstName: string; - lastName: string; - calendlySchedulingUrl: string; - availableStartTimes: Array; -}; +export type UserAvailability = Static; +export const UserAvailabilitySchema = Type.Object({ + firstName: Type.String(), + lastName: Type.String(), + calendlySchedulingUrl: Type.String(), + availableStartTimes: Type.Array(Type.String()), +}); -export type GetAvailabilitiesResponse = { - availabilities: Array; -}; +export type GetAvailabilitiesResponse = Static< + typeof GetAvailabilitiesResponseSchema +>; +export const GetAvailabilitiesResponseSchema = Type.Object({ + availabilities: Type.Array(UserAvailabilitySchema), +});