From 8136c7c1b25ba5ef38eb22d6b84fabf616908e1c Mon Sep 17 00:00:00 2001 From: Sosokker Date: Fri, 15 Nov 2024 16:16:40 +0700 Subject: [PATCH] feat: disable non-freetime and overlap time for meeting --- src/app/calendar/MeetEventDialog.tsx | 149 ++++++++++++++++++++------- src/app/calendar/overlapEvent.ts | 36 +++++++ src/app/calendar/page.tsx | 10 +- 3 files changed, 153 insertions(+), 42 deletions(-) create mode 100644 src/app/calendar/overlapEvent.ts diff --git a/src/app/calendar/MeetEventDialog.tsx b/src/app/calendar/MeetEventDialog.tsx index 59fed9e..f0a6488 100644 --- a/src/app/calendar/MeetEventDialog.tsx +++ b/src/app/calendar/MeetEventDialog.tsx @@ -14,14 +14,19 @@ import { import { Input } from "@/components/ui/input"; import { Clock } from "lucide-react"; import { Label } from "@/components/ui/label"; -import { createCalendarEvent, createMeetingLog } from "./actions"; +import { createCalendarEvent, createMeetingLog, getFreeDate } from "./actions"; import { Session } from "@supabase/supabase-js"; import { createSupabaseClient } from "@/lib/supabase/clientComponentClient"; import { TimeInput } from "@nextui-org/date-input"; -import { Calendar } from "@nextui-org/calendar"; +import { Calendar, DateValue } from "@nextui-org/calendar"; import { TimeValue } from "@react-types/datepicker"; import { CalendarDate, getLocalTimeZone, today } from "@internationalized/date"; +// import { useLocale } from "@react-aria/i18n"; +import { getMeetingLog } from "./actions"; import toast from "react-hot-toast"; +import { useQuery } from "@supabase-cache-helpers/postgrest-react-query"; +import { LegacyLoader } from "@/components/loading/LegacyLoader"; +import { isEventOverlapping } from "./overlapEvent"; interface DialogProps { children?: React.ReactNode; @@ -32,7 +37,7 @@ interface DialogProps { modal?: boolean; session: Session; projectName: string; - projectId?: number; + projectId: number; } export function MeetEventDialog(props: DialogProps) { @@ -49,12 +54,24 @@ export function MeetEventDialog(props: DialogProps) { const [noteToBusiness, setNoteToBusiness] = useState(""); const session = props.session; + const { + data: freeDate, + error: freeDateError, + isLoading: isLoadingFreeDate, + } = useQuery(getFreeDate(supabase, props.projectId), { enabled: !!props.projectId }); + useEffect(() => { if (props.projectName) { setEventName(`Meet with ${props.projectName}`); } }, [props.projectName]); + const { + data: meetingLog, + error: meetingLogError, + isLoading: isLoadingMeetingLog, + } = useQuery(getMeetingLog(supabase, props.projectId), { enabled: !!props.projectId }); + const handleCreateEvent = async () => { if (!session || !eventDate || !startTime || !endTime || !eventName) { toast.error("Please fill in all event details."); @@ -70,6 +87,18 @@ export function MeetEventDialog(props: DialogProps) { const endDate = eventDate.toDate(timezone); endDate.setHours(endTime.hour, startTime.minute); + const existingEvents = (meetingLog || []).map((log) => ({ + meet_date: log.meet_date, + start_time: log.start_time, + end_time: log.end_time, + })); + const hasOverlap = isEventOverlapping(eventDate, startTime, endTime, existingEvents); + + if (hasOverlap) { + toast.error("This current selected date and time is overlaped with any existing events."); + return; + } + await createCalendarEvent(session, startDate, endDate, eventName, eventDescription); const { status, error } = await createMeetingLog({ @@ -98,6 +127,33 @@ export function MeetEventDialog(props: DialogProps) { } }; + const meetingLogRanges = (meetingLog || []).map((log) => { + const [year, month, day] = log.meet_date.split("-").map(Number); + const startDate = new CalendarDate(year, month, day); + const endDate = new CalendarDate(year, month, day); + return [startDate, endDate]; + }); + + const freetimeLogRanges = (freeDate || []).map((log) => { + const [year, month, day] = log.meet_date.split("-").map(Number); + const startDate = new CalendarDate(year, month, day); + const endDate = new CalendarDate(year, month, day); + return [startDate, endDate]; + }); + + // const disabledRanges = [...meetingLogRanges]; + // const { locale } = useLocale(); + + const isDateUnavailable = (date: DateValue) => { + const isFreeDate = freetimeLogRanges.some( + (interval) => date.compare(interval[0]) >= 0 && date.compare(interval[1]) <= 0 + ); + const isMeetingDate = meetingLogRanges.some( + (interval) => date.compare(interval[0]) >= 0 && date.compare(interval[1]) <= 0 + ); + return !isFreeDate || isMeetingDate; + }; + return ( @@ -111,49 +167,62 @@ export function MeetEventDialog(props: DialogProps) { -
-
- - setEventName(e.target.value)} - /> + {meetingLogError || freeDateError ? ( +
+

Error loading meeting logs

-
- - setEventDescription(e.target.value)} - /> -
-
- - setNoteToBusiness(e.target.value)} - /> -
-
- - -
-
+ ) : !isLoadingMeetingLog || !isLoadingFreeDate ? ( +
- - + + setEventName(e.target.value)} + />
- - + + setEventDescription(e.target.value)} + /> +
+
+ + setNoteToBusiness(e.target.value)} + /> +
+
+ + +
+
+
+ + +
+
+ + +
-
+ ) : ( + + )}
{ + setShowModal(open); + if (!open) { + setCurrentProjectId(undefined); + setCurrentProjectName(""); + } + }} session={session} projectName={currentProjectName} - projectId={currentProjectId} + projectId={currentProjectId!} />
);