From 7567c323c9f5a87d81020de028e09044bb150dd9 Mon Sep 17 00:00:00 2001 From: Christian Walker Date: Sun, 6 Apr 2025 23:56:56 -0500 Subject: [PATCH 01/11] updates tz --- .../src/components/events/EventsCardView.tsx | 21 +++++---- apps/web/src/components/events/EventsView.tsx | 5 +-- .../src/components/events/id/EventDetails.tsx | 45 +++++-------------- .../events/id/checkin/EventCheckin.tsx | 15 +++---- .../shared/EventDetailsLiveIndicator.tsx | 11 ----- apps/web/src/lib/utils.ts | 16 ------- 6 files changed, 28 insertions(+), 85 deletions(-) delete mode 100644 apps/web/src/components/events/shared/EventDetailsLiveIndicator.tsx diff --git a/apps/web/src/components/events/EventsCardView.tsx b/apps/web/src/components/events/EventsCardView.tsx index fe0922b4..093b1bc6 100644 --- a/apps/web/src/components/events/EventsCardView.tsx +++ b/apps/web/src/components/events/EventsCardView.tsx @@ -1,8 +1,7 @@ import type { EventAndCategoriesType } from "@/lib/types/events"; import EventCardComponent from "./EventCardComponent"; import { ScrollArea } from "../ui/scroll-area"; -import { isAfter } from "date-fns"; -import { isEventCurrentlyHappening, isEventCheckinAllowed } from "@/lib/utils"; +import {isAfter, isWithinInterval } from "date-fns"; export default function EventsCardView({ events, clientTimeZone, @@ -21,16 +20,16 @@ export default function EventsCardView({ key={event.id} event={event} isPast={isAfter(currentDateUTC, event.end)} - isEventCurrentlyHappening={isEventCurrentlyHappening( - currentDateUTC, - event.start, - event.end, - )} - isEventCheckinAllowed={isEventCheckinAllowed( - currentDateUTC, - event.checkinStart, - event.checkinEnd, + isEventCurrentlyHappening={isWithinInterval(currentDateUTC, { + start: event.start, + end: event.end, + } )} + isEventCheckinAllowed={isWithinInterval(currentDateUTC,{ + start: event.checkinStart, + end: event.checkinEnd, + }, + )} clientTimezone={clientTimeZone} /> ))} diff --git a/apps/web/src/components/events/EventsView.tsx b/apps/web/src/components/events/EventsView.tsx index 35dcf72b..49b3f162 100644 --- a/apps/web/src/components/events/EventsView.tsx +++ b/apps/web/src/components/events/EventsView.tsx @@ -1,12 +1,11 @@ import EventsCardView from "./EventsCardView"; import EventsCalendarView from "./EventsCalendarView"; -import { db, like, gte, and, lt } from "db"; +import { db, like, gte, and, lt, eq } from "db"; import { events } from "db/schema"; import type { SearchParams } from "@/lib/types/shared"; import { EVENT_FILTERS } from "@/lib/constants/events"; import { unstable_noStore as noStore } from "next/cache"; import PageError from "../shared/PageError"; -import { headers } from "next/headers"; import { getClientTimeZone, getUTCDate } from "@/lib/utils"; import { getRequestContext } from "@cloudflare/next-on-pages"; @@ -48,7 +47,7 @@ export default async function EventsView({ params }: { params: SearchParams }) { }, }, }, - where: and(eventSearchQuery, dateComparison), + where: and(eventSearchQuery, dateComparison, eq(events.isHidden, false)), orderBy: events.start, }) .then((events) => { diff --git a/apps/web/src/components/events/id/EventDetails.tsx b/apps/web/src/components/events/id/EventDetails.tsx index 09df76ef..d9e3109f 100644 --- a/apps/web/src/components/events/id/EventDetails.tsx +++ b/apps/web/src/components/events/id/EventDetails.tsx @@ -1,21 +1,18 @@ import { getEventDetails } from "@/lib/queries/events"; import PageError from "../../shared/PageError"; import EventImage from "../shared/EventImage"; -import { headers } from "next/headers"; import { TWENTY_FOUR_HOURS, ONE_HOUR_IN_MILLISECONDS } from "@/lib/constants"; import c from "config"; import { getClientTimeZone, getUTCDate, - isEventCurrentlyHappening, } from "@/lib/utils"; -import { differenceInHours, isAfter } from "date-fns"; +import { isAfter, isWithinInterval } from "date-fns"; import { formatInTimeZone } from "date-fns-tz"; import { EVENT_DATE_FORMAT_STRING, EVENT_TIME_FORMAT_STRING, } from "@/lib/constants/events"; -import EventDetailsLiveIndicator from "../shared/EventDetailsLiveIndicator"; import EventCategories from "../EventCategories"; import { BellRing, @@ -66,14 +63,13 @@ export default async function EventDetails({ if (!event) { return ; } - const { start, end, checkinStart, checkinEnd } = event; + const { start, end, } = event; const currentDateUTC = getUTCDate(); const isEventPassed = isAfter(currentDateUTC, end); - const isEventHappening = isEventCurrentlyHappening( - currentDateUTC, - start, - end, - ); + const isEventHappening = isWithinInterval(currentDateUTC, { + start: start, + end: end, + }); const startTime = formatInTimeZone( start, @@ -97,15 +93,6 @@ export default async function EventDetails({ const checkInUrl = `/events/${event.id}/checkin`; - const isCheckinAvailable = - checkinStart <= currentDateUTC && currentDateUTC <= checkinEnd; - - const checkInMessage = isCheckinAvailable - ? "Ready to check-in? Click here!" - : isEventPassed - ? "Check-in is closed" - : `Check-in starts on ${formatInTimeZone(start, clientTimeZone, `${EVENT_TIME_FORMAT_STRING} @${EVENT_DATE_FORMAT_STRING}`)}`; - const eventCalendarLink = { title: event.name, description: event.description, @@ -114,18 +101,6 @@ export default async function EventDetails({ location: event.location, }; - const detailsProps = { - event, - startTime, - startDate: startDateFormatted, - formattedEventDuration, - checkInUrl, - checkInMessage, - eventCalendarLink, - isEventPassed, - isCheckinAvailable, - isEventHappening, - }; const { thumbnailUrl, location, description, points } = event; const width = 500; @@ -183,16 +158,16 @@ export default async function EventDetails({
-

{event.location}

+

{location}

- {event.points} + {points} {" "} - pt{event.points != 1 ? "s" : ""} + pt{points != 1 ? "s" : ""}

@@ -263,7 +238,7 @@ export default async function EventDetails({ href={`/api/ics-calendar?event_id=${id}`} target="_blank" className="flex w-auto justify-between gap-3 rounded-md px-3 py-2 text-primary-foreground md:max-w-[7.5rem] lg:max-w-none" - download={`event_${event.id}.ics`} + download={`event_${id}.ics`} > ; - } const userEventData = await getUserDataAndCheckin(eventID, clerkId); if (!userEventData) { @@ -52,9 +47,11 @@ export default async function EventCheckin({ return ; } - const isCheckinAvailable = - event.checkinStart <= currentDateUTC && - currentDateUTC <= event.checkinEnd; + const isCheckinAvailable = isWithinInterval(currentDateUTC, { + start: event.checkinStart, + end: event.checkinEnd, + }); + if (!isCheckinAvailable) { return ( - ); -} diff --git a/apps/web/src/lib/utils.ts b/apps/web/src/lib/utils.ts index c7a6d4ae..eafc1d6f 100644 --- a/apps/web/src/lib/utils.ts +++ b/apps/web/src/lib/utils.ts @@ -43,22 +43,6 @@ export function getUTCDate() { return new Date(currentDate.toUTCString()); } -export function isEventCurrentlyHappening( - currentDateUTC: Date, - eventStart: Date, - eventEnd: Date, -) { - return currentDateUTC >= eventStart && currentDateUTC <= eventEnd; -} - -export function isEventCheckinAllowed( - currentDateUTC: Date, - checkinStart: Date, - checkinEnd: Date, -) { - return currentDateUTC >= checkinStart && currentDateUTC <= checkinEnd; -} - export function formatBlobUrl(blobUrl: string) { const end = blobUrl.split("/").at(-1); if (!end) return blobUrl; From 7e3e0ed4bbc628760227f1bdc1889e8bb1dff5d2 Mon Sep 17 00:00:00 2001 From: Christian Walker Date: Mon, 7 Apr 2025 00:11:49 -0500 Subject: [PATCH 02/11] fix checkin logic to make a check --- apps/web/src/actions/checkin.ts | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/apps/web/src/actions/checkin.ts b/apps/web/src/actions/checkin.ts index 5e4edf1b..ef6945a1 100644 --- a/apps/web/src/actions/checkin.ts +++ b/apps/web/src/actions/checkin.ts @@ -6,14 +6,38 @@ import { UNIQUE_KEY_CONSTRAINT_VIOLATION_CODE } from "@/lib/constants/"; import { checkInUserClient, checkInUserList } from "@/lib/queries/checkins"; import { adminCheckinSchema, universityIDSplitter } from "db/zod"; import { CheckinResult } from "@/lib/types/events"; -import { revalidatePath } from "next/cache"; import { headers } from "next/headers"; +import { getEventById } from "@/lib/queries/events"; +import { returnValidationErrors } from "next-safe-action"; +import z from "zod" +import { isWithinInterval } from "date-fns"; const { ALREADY_CHECKED_IN, SUCCESS, FAILED, SOME_FAILED } = CheckinResult; export const checkInUserAction = userAction .schema(userCheckinSchemaFormified) .action(async ({ parsedInput }) => { + const { eventID } = parsedInput; + const event = await getEventById(eventID); + if (!event) { + returnValidationErrors(z.null(),{ + _errors: ["Event does not exist"], + }) + } + + const currentDateUTC = new Date(); + const isCheckinAvailable = isWithinInterval(currentDateUTC, { + start: event.checkinStart, + end: event.checkinEnd, + }); + if (!isCheckinAvailable) { + returnValidationErrors(z.null(),{ + _errors: [ + `Check-in not available until ${event.checkinStart.toLocaleString()}`, + ], + }) + } + try { await checkInUserClient(parsedInput); } catch (e) { From 88bdba19dd9ebb2c50f3565f88077e83270be097 Mon Sep 17 00:00:00 2001 From: Christian Walker Date: Mon, 7 Apr 2025 00:11:58 -0500 Subject: [PATCH 03/11] updates edit event form --- .../dash/admin/events/EditEventForm.tsx | 26 +++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/apps/web/src/components/dash/admin/events/EditEventForm.tsx b/apps/web/src/components/dash/admin/events/EditEventForm.tsx index 2264e5b9..1c15027d 100644 --- a/apps/web/src/components/dash/admin/events/EditEventForm.tsx +++ b/apps/web/src/components/dash/admin/events/EditEventForm.tsx @@ -29,8 +29,7 @@ import { } from "@/components/ui/alert-dialog"; import { Switch } from "@/components/ui/switch"; import { useState, useEffect } from "react"; -import { cn } from "@/lib/utils"; -import { format } from "date-fns"; +import { isAfter,addHours, isBefore } from "date-fns"; import { getLocalTimeZone, parseAbsolute } from "@internationalized/date"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; @@ -126,6 +125,29 @@ export default function EditEventForm({ return true; } + const eventStartTime = form.watch("start"); + const eventEndTime = form.watch("end"); + const checkinStartTime = form.watch("checkinStart"); + const checkinEndTime = form.watch("checkinEnd"); + + useEffect(() => { + if (isAfter(eventStartTime, eventEndTime)) { + form.setValue("end", addHours(eventStartTime, 1)); + } + }, [eventStartTime]); + + useEffect(() => { + if (isAfter(checkinStartTime, checkinEndTime)) { + form.setValue("checkinEnd", addHours(checkinStartTime, 1)); + } + }, [checkinStartTime]); + + useEffect(() => { + if (isBefore(checkinEndTime, eventEndTime)) { + form.setValue("checkinEnd", eventEndTime); + } + }, [eventEndTime]); + useEffect(() => { if (Object.keys(form.formState.errors).length > 0) { console.log("Errors: ", form.formState.errors); From 289c21ec1b329e52d0a72eae878cec67610b2d90 Mon Sep 17 00:00:00 2001 From: Christian Walker Date: Mon, 7 Apr 2025 00:19:45 -0500 Subject: [PATCH 04/11] updates checkin logic --- apps/web/src/actions/checkin.ts | 25 +++++++++------ .../events/id/checkin/EventCheckin.tsx | 2 +- .../events/id/checkin/EventCheckinForm.tsx | 32 +++++++++++++++++-- apps/web/src/lib/types/events.ts | 2 ++ 4 files changed, 48 insertions(+), 13 deletions(-) diff --git a/apps/web/src/actions/checkin.ts b/apps/web/src/actions/checkin.ts index ef6945a1..c6df9c5a 100644 --- a/apps/web/src/actions/checkin.ts +++ b/apps/web/src/actions/checkin.ts @@ -9,10 +9,17 @@ import { CheckinResult } from "@/lib/types/events"; import { headers } from "next/headers"; import { getEventById } from "@/lib/queries/events"; import { returnValidationErrors } from "next-safe-action"; -import z from "zod" +import z from "zod"; import { isWithinInterval } from "date-fns"; -const { ALREADY_CHECKED_IN, SUCCESS, FAILED, SOME_FAILED } = CheckinResult; +const { + ALREADY_CHECKED_IN, + SUCCESS, + FAILED, + SOME_FAILED, + EVENT_NOT_FOUND, + CHECKIN_NOT_AVAILABLE, +} = CheckinResult; export const checkInUserAction = userAction .schema(userCheckinSchemaFormified) @@ -20,9 +27,9 @@ export const checkInUserAction = userAction const { eventID } = parsedInput; const event = await getEventById(eventID); if (!event) { - returnValidationErrors(z.null(),{ - _errors: ["Event does not exist"], - }) + returnValidationErrors(z.null(), { + _errors: [EVENT_NOT_FOUND], + }); } const currentDateUTC = new Date(); @@ -31,11 +38,9 @@ export const checkInUserAction = userAction end: event.checkinEnd, }); if (!isCheckinAvailable) { - returnValidationErrors(z.null(),{ - _errors: [ - `Check-in not available until ${event.checkinStart.toLocaleString()}`, - ], - }) + returnValidationErrors(z.null(), { + _errors: [CHECKIN_NOT_AVAILABLE], + }); } try { diff --git a/apps/web/src/components/events/id/checkin/EventCheckin.tsx b/apps/web/src/components/events/id/checkin/EventCheckin.tsx index b0707e3e..e7208896 100644 --- a/apps/web/src/components/events/id/checkin/EventCheckin.tsx +++ b/apps/web/src/components/events/id/checkin/EventCheckin.tsx @@ -51,7 +51,7 @@ export default async function EventCheckin({ start: event.checkinStart, end: event.checkinEnd, }); - + if (!isCheckinAvailable) { return ( { + console.log("Checkin success", data); toast.dismiss(); const success = data?.success; const code = data?.code; @@ -95,7 +97,33 @@ export default function EventCheckinForm({ }, onError: async ({ error: e }) => { toast.dismiss(); - if (e.validationErrors) { + if (e.validationErrors != null) { + if (e.validationErrors?._errors?.[0] === EVENT_NOT_FOUND) { + return toast.error( + `Event not found. Please check the event ID.`, + { + duration: Infinity, + cancel: { + label: "Close", + onClick: () => {}, + }, + }, + ); + } + if ( + e.validationErrors?._errors?.[0] === CHECKIN_NOT_AVAILABLE + ) { + return toast.error( + `Check-in is not available at this time.`, + { + duration: Infinity, + cancel: { + label: "Close", + onClick: () => {}, + }, + }, + ); + } toast.error(`Please check your input. ${e.validationErrors}`, { duration: Infinity, cancel: { diff --git a/apps/web/src/lib/types/events.ts b/apps/web/src/lib/types/events.ts index 14f43eca..1d55b12e 100644 --- a/apps/web/src/lib/types/events.ts +++ b/apps/web/src/lib/types/events.ts @@ -67,6 +67,8 @@ export enum CheckinResult { ALREADY_CHECKED_IN = "already_checked_in", SOME_FAILED = "some_failed", FAILED = "failed", + EVENT_NOT_FOUND = "event_not_found", + CHECKIN_NOT_AVAILABLE = "checkin_not_available", } export type iEvent = z.infer; From 1669b3d6f913405b69e5f56e2dc61869dc876f4c Mon Sep 17 00:00:00 2001 From: Christian Walker Date: Mon, 7 Apr 2025 00:19:54 -0500 Subject: [PATCH 05/11] updates edit form --- apps/web/src/components/dash/admin/events/EditEventForm.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/web/src/components/dash/admin/events/EditEventForm.tsx b/apps/web/src/components/dash/admin/events/EditEventForm.tsx index 1c15027d..970c91da 100644 --- a/apps/web/src/components/dash/admin/events/EditEventForm.tsx +++ b/apps/web/src/components/dash/admin/events/EditEventForm.tsx @@ -29,7 +29,7 @@ import { } from "@/components/ui/alert-dialog"; import { Switch } from "@/components/ui/switch"; import { useState, useEffect } from "react"; -import { isAfter,addHours, isBefore } from "date-fns"; +import { isAfter, addHours, isBefore } from "date-fns"; import { getLocalTimeZone, parseAbsolute } from "@internationalized/date"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; From 2148630d732996bf777e5e2701b7ba5096e9f50a Mon Sep 17 00:00:00 2001 From: Christian Walker Date: Mon, 7 Apr 2025 00:20:01 -0500 Subject: [PATCH 06/11] formatter --- .../src/components/events/EventsCardView.tsx | 24 +++++++++++-------- apps/web/src/components/events/EventsView.tsx | 6 ++++- .../src/components/events/id/EventDetails.tsx | 8 ++----- 3 files changed, 21 insertions(+), 17 deletions(-) diff --git a/apps/web/src/components/events/EventsCardView.tsx b/apps/web/src/components/events/EventsCardView.tsx index 093b1bc6..3316d2d2 100644 --- a/apps/web/src/components/events/EventsCardView.tsx +++ b/apps/web/src/components/events/EventsCardView.tsx @@ -1,7 +1,7 @@ import type { EventAndCategoriesType } from "@/lib/types/events"; import EventCardComponent from "./EventCardComponent"; import { ScrollArea } from "../ui/scroll-area"; -import {isAfter, isWithinInterval } from "date-fns"; +import { isAfter, isWithinInterval } from "date-fns"; export default function EventsCardView({ events, clientTimeZone, @@ -20,16 +20,20 @@ export default function EventsCardView({ key={event.id} event={event} isPast={isAfter(currentDateUTC, event.end)} - isEventCurrentlyHappening={isWithinInterval(currentDateUTC, { - start: event.start, - end: event.end, - } + isEventCurrentlyHappening={isWithinInterval( + currentDateUTC, + { + start: event.start, + end: event.end, + }, + )} + isEventCheckinAllowed={isWithinInterval( + currentDateUTC, + { + start: event.checkinStart, + end: event.checkinEnd, + }, )} - isEventCheckinAllowed={isWithinInterval(currentDateUTC,{ - start: event.checkinStart, - end: event.checkinEnd, - }, - )} clientTimezone={clientTimeZone} /> ))} diff --git a/apps/web/src/components/events/EventsView.tsx b/apps/web/src/components/events/EventsView.tsx index 49b3f162..dd94d924 100644 --- a/apps/web/src/components/events/EventsView.tsx +++ b/apps/web/src/components/events/EventsView.tsx @@ -47,7 +47,11 @@ export default async function EventsView({ params }: { params: SearchParams }) { }, }, }, - where: and(eventSearchQuery, dateComparison, eq(events.isHidden, false)), + where: and( + eventSearchQuery, + dateComparison, + eq(events.isHidden, false), + ), orderBy: events.start, }) .then((events) => { diff --git a/apps/web/src/components/events/id/EventDetails.tsx b/apps/web/src/components/events/id/EventDetails.tsx index d9e3109f..b7462c97 100644 --- a/apps/web/src/components/events/id/EventDetails.tsx +++ b/apps/web/src/components/events/id/EventDetails.tsx @@ -3,10 +3,7 @@ import PageError from "../../shared/PageError"; import EventImage from "../shared/EventImage"; import { TWENTY_FOUR_HOURS, ONE_HOUR_IN_MILLISECONDS } from "@/lib/constants"; import c from "config"; -import { - getClientTimeZone, - getUTCDate, -} from "@/lib/utils"; +import { getClientTimeZone, getUTCDate } from "@/lib/utils"; import { isAfter, isWithinInterval } from "date-fns"; import { formatInTimeZone } from "date-fns-tz"; import { @@ -63,7 +60,7 @@ export default async function EventDetails({ if (!event) { return ; } - const { start, end, } = event; + const { start, end } = event; const currentDateUTC = getUTCDate(); const isEventPassed = isAfter(currentDateUTC, end); const isEventHappening = isWithinInterval(currentDateUTC, { @@ -101,7 +98,6 @@ export default async function EventDetails({ location: event.location, }; - const { thumbnailUrl, location, description, points } = event; const width = 500; const height = 500; From 3b20f975596adab4bb07f0756278af48ccc8ba95 Mon Sep 17 00:00:00 2001 From: Christian Walker Date: Mon, 7 Apr 2025 00:40:04 -0500 Subject: [PATCH 07/11] updates edit and create event form --- .../dash/admin/events/EditEventForm.tsx | 1 + .../dash/admin/events/NewEventForm.tsx | 26 ++++++++++++++++++- 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/apps/web/src/components/dash/admin/events/EditEventForm.tsx b/apps/web/src/components/dash/admin/events/EditEventForm.tsx index 970c91da..446a5d3e 100644 --- a/apps/web/src/components/dash/admin/events/EditEventForm.tsx +++ b/apps/web/src/components/dash/admin/events/EditEventForm.tsx @@ -144,6 +144,7 @@ export default function EditEventForm({ useEffect(() => { if (isBefore(checkinEndTime, eventEndTime)) { + form.setValue("checkinStart",eventStartTime); form.setValue("checkinEnd", eventEndTime); } }, [eventEndTime]); diff --git a/apps/web/src/components/dash/admin/events/NewEventForm.tsx b/apps/web/src/components/dash/admin/events/NewEventForm.tsx index b30a31d9..173d0e20 100644 --- a/apps/web/src/components/dash/admin/events/NewEventForm.tsx +++ b/apps/web/src/components/dash/admin/events/NewEventForm.tsx @@ -45,7 +45,6 @@ import { useAction } from "next-safe-action/hooks"; import { put } from "@/lib/client/file-upload"; import { createEvent } from "@/actions/events/createNewEvent"; import { ONE_HOUR_IN_MILLISECONDS } from "@/lib/constants"; -import { bucketEventThumbnailBaseUrl } from "config"; import type { NewEventFormProps } from "@/lib/types/events"; import { Select, @@ -54,6 +53,7 @@ import { SelectTrigger, SelectValue, } from "@/components/ui/select"; +import { isAfter, isBefore, addHours } from "date-fns"; const formSchema = insertEventSchemaFormified; @@ -116,6 +116,30 @@ export default function NewEventForm({ return true; } + const eventStartTime = form.watch("start"); + const eventEndTime = form.watch("end"); + const checkinStartTime = form.watch("checkinStart"); + const checkinEndTime = form.watch("checkinEnd"); + + useEffect(() => { + if (isAfter(eventStartTime, eventEndTime)) { + form.setValue("end", addHours(eventStartTime, 1)); + } + }, [eventStartTime]); + + useEffect(() => { + if (isAfter(checkinStartTime, checkinEndTime) && hasDifferentCheckinTime) { + form.setValue("checkinEnd", addHours(checkinStartTime, 1)); + } + }, [checkinStartTime]); + + useEffect(() => { + if (isBefore(checkinEndTime, eventEndTime) && hasDifferentCheckinTime) { + form.setValue("checkinStart",eventStartTime); + form.setValue("checkinEnd", eventEndTime); + } + }, [eventEndTime]); + const { execute: runCreateEvent, status: actionStatus, From 70df586f22a6dce7c8010fc914ff2fde1e12129c Mon Sep 17 00:00:00 2001 From: Christian Walker Date: Mon, 7 Apr 2025 00:40:16 -0500 Subject: [PATCH 08/11] updates checkin feedback --- .../src/components/events/id/checkin/EventCheckin.tsx | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/apps/web/src/components/events/id/checkin/EventCheckin.tsx b/apps/web/src/components/events/id/checkin/EventCheckin.tsx index e7208896..4d9fe0bf 100644 --- a/apps/web/src/components/events/id/checkin/EventCheckin.tsx +++ b/apps/web/src/components/events/id/checkin/EventCheckin.tsx @@ -5,7 +5,7 @@ import EventCheckinForm from "./EventCheckinForm"; import { getClientTimeZone } from "@/lib/utils"; import { headers } from "next/headers"; import { formatInTimeZone } from "date-fns-tz"; -import { isWithinInterval } from "date-fns"; +import { isBefore, isWithinInterval } from "date-fns"; import { EVENT_TIME_FORMAT_STRING, EVENT_DATE_FORMAT_STRING, @@ -53,9 +53,14 @@ export default async function EventCheckin({ }); if (!isCheckinAvailable) { + const isDateBeforeCheckinStart = isBefore( + currentDateUTC, + event.checkinStart + ); + const errorMessage = isDateBeforeCheckinStart ? `Check-in does not start until ${formatInTimeZone(event.checkinStart, clientTimeZone, `${EVENT_TIME_FORMAT_STRING} @ ${EVENT_DATE_FORMAT_STRING}`)}` : `Check-in for this event ended on ${formatInTimeZone(event.checkinEnd, clientTimeZone, `${EVENT_TIME_FORMAT_STRING} @ ${EVENT_DATE_FORMAT_STRING}`)}`; return ( From 219ba17e9a08a86d6539ff67dbbc8e1480b49e37 Mon Sep 17 00:00:00 2001 From: Christian Walker Date: Mon, 7 Apr 2025 00:40:53 -0500 Subject: [PATCH 09/11] formatter --- .../dash/admin/events/EditEventForm.tsx | 2 +- .../dash/admin/events/NewEventForm.tsx | 47 ++++++++++--------- .../events/id/checkin/EventCheckin.tsx | 6 ++- 3 files changed, 30 insertions(+), 25 deletions(-) diff --git a/apps/web/src/components/dash/admin/events/EditEventForm.tsx b/apps/web/src/components/dash/admin/events/EditEventForm.tsx index 446a5d3e..7a8c81d4 100644 --- a/apps/web/src/components/dash/admin/events/EditEventForm.tsx +++ b/apps/web/src/components/dash/admin/events/EditEventForm.tsx @@ -144,7 +144,7 @@ export default function EditEventForm({ useEffect(() => { if (isBefore(checkinEndTime, eventEndTime)) { - form.setValue("checkinStart",eventStartTime); + form.setValue("checkinStart", eventStartTime); form.setValue("checkinEnd", eventEndTime); } }, [eventEndTime]); diff --git a/apps/web/src/components/dash/admin/events/NewEventForm.tsx b/apps/web/src/components/dash/admin/events/NewEventForm.tsx index 173d0e20..56f6d380 100644 --- a/apps/web/src/components/dash/admin/events/NewEventForm.tsx +++ b/apps/web/src/components/dash/admin/events/NewEventForm.tsx @@ -117,28 +117,31 @@ export default function NewEventForm({ } const eventStartTime = form.watch("start"); - const eventEndTime = form.watch("end"); - const checkinStartTime = form.watch("checkinStart"); - const checkinEndTime = form.watch("checkinEnd"); - - useEffect(() => { - if (isAfter(eventStartTime, eventEndTime)) { - form.setValue("end", addHours(eventStartTime, 1)); - } - }, [eventStartTime]); - - useEffect(() => { - if (isAfter(checkinStartTime, checkinEndTime) && hasDifferentCheckinTime) { - form.setValue("checkinEnd", addHours(checkinStartTime, 1)); - } - }, [checkinStartTime]); - - useEffect(() => { - if (isBefore(checkinEndTime, eventEndTime) && hasDifferentCheckinTime) { - form.setValue("checkinStart",eventStartTime); - form.setValue("checkinEnd", eventEndTime); - } - }, [eventEndTime]); + const eventEndTime = form.watch("end"); + const checkinStartTime = form.watch("checkinStart"); + const checkinEndTime = form.watch("checkinEnd"); + + useEffect(() => { + if (isAfter(eventStartTime, eventEndTime)) { + form.setValue("end", addHours(eventStartTime, 1)); + } + }, [eventStartTime]); + + useEffect(() => { + if ( + isAfter(checkinStartTime, checkinEndTime) && + hasDifferentCheckinTime + ) { + form.setValue("checkinEnd", addHours(checkinStartTime, 1)); + } + }, [checkinStartTime]); + + useEffect(() => { + if (isBefore(checkinEndTime, eventEndTime) && hasDifferentCheckinTime) { + form.setValue("checkinStart", eventStartTime); + form.setValue("checkinEnd", eventEndTime); + } + }, [eventEndTime]); const { execute: runCreateEvent, diff --git a/apps/web/src/components/events/id/checkin/EventCheckin.tsx b/apps/web/src/components/events/id/checkin/EventCheckin.tsx index 4d9fe0bf..832339d7 100644 --- a/apps/web/src/components/events/id/checkin/EventCheckin.tsx +++ b/apps/web/src/components/events/id/checkin/EventCheckin.tsx @@ -55,9 +55,11 @@ export default async function EventCheckin({ if (!isCheckinAvailable) { const isDateBeforeCheckinStart = isBefore( currentDateUTC, - event.checkinStart + event.checkinStart, ); - const errorMessage = isDateBeforeCheckinStart ? `Check-in does not start until ${formatInTimeZone(event.checkinStart, clientTimeZone, `${EVENT_TIME_FORMAT_STRING} @ ${EVENT_DATE_FORMAT_STRING}`)}` : `Check-in for this event ended on ${formatInTimeZone(event.checkinEnd, clientTimeZone, `${EVENT_TIME_FORMAT_STRING} @ ${EVENT_DATE_FORMAT_STRING}`)}`; + const errorMessage = isDateBeforeCheckinStart + ? `Check-in does not start until ${formatInTimeZone(event.checkinStart, clientTimeZone, `${EVENT_TIME_FORMAT_STRING} @ ${EVENT_DATE_FORMAT_STRING}`)}` + : `Check-in for this event ended on ${formatInTimeZone(event.checkinEnd, clientTimeZone, `${EVENT_TIME_FORMAT_STRING} @ ${EVENT_DATE_FORMAT_STRING}`)}`; return ( Date: Mon, 7 Apr 2025 01:21:56 -0500 Subject: [PATCH 10/11] update chart metrics --- .../components/dash/admin/overview/KeyMetrics.tsx | 11 ++++++++++- apps/web/src/lib/queries/charts.ts | 15 +++++++-------- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/apps/web/src/components/dash/admin/overview/KeyMetrics.tsx b/apps/web/src/components/dash/admin/overview/KeyMetrics.tsx index 9b8aec64..6c5ef9af 100644 --- a/apps/web/src/components/dash/admin/overview/KeyMetrics.tsx +++ b/apps/web/src/components/dash/admin/overview/KeyMetrics.tsx @@ -10,6 +10,7 @@ import { CheckCircleIcon, BarChart, ArrowUpIcon, + ArrowDownIcon, UsersIcon, TrendingUpIcon, } from "lucide-react"; @@ -117,7 +118,15 @@ export default async function KeyMetrics() {
{growthRate}%
- + { + growthRate > 0 ? ( + + ) : growthRate < 0 ? ( + + ) : ( + null + ) + }

vs last month diff --git a/apps/web/src/lib/queries/charts.ts b/apps/web/src/lib/queries/charts.ts index a1f59c07..a586883b 100644 --- a/apps/web/src/lib/queries/charts.ts +++ b/apps/web/src/lib/queries/charts.ts @@ -199,15 +199,14 @@ export async function getGrowthRate() { sql`${users.joinDate} >= date(datetime('now', '-1 month', 'start of month')) AND ${users.joinDate} < date(datetime('now', 'start of month'))`, ); - const currentMonthCount = currentMonthResult[0]?.count || 0; + const currentMonthCount = currentMonthResult[0]?.count || 1; const previousMonthCount = previousMonthResult[0]?.count || 1; // Avoid division by zero - - return parseFloat( - ( - ((currentMonthCount - previousMonthCount) / previousMonthCount) * - 100 - ).toFixed(1), - ); + + const growthRate = ( + ((currentMonthCount - previousMonthCount) / previousMonthCount) * + 100 + ).toFixed(1); + return parseFloat(growthRate); } // Get activity by day of week From 90680e270f16d9fd65c5bae4fb4f2c9d0f04ffa1 Mon Sep 17 00:00:00 2001 From: Christian Walker Date: Mon, 7 Apr 2025 14:16:17 -0500 Subject: [PATCH 11/11] formatter --- .../components/dash/admin/overview/KeyMetrics.tsx | 14 +++++--------- apps/web/src/lib/queries/charts.ts | 4 ++-- 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/apps/web/src/components/dash/admin/overview/KeyMetrics.tsx b/apps/web/src/components/dash/admin/overview/KeyMetrics.tsx index 6c5ef9af..360e5571 100644 --- a/apps/web/src/components/dash/admin/overview/KeyMetrics.tsx +++ b/apps/web/src/components/dash/admin/overview/KeyMetrics.tsx @@ -118,15 +118,11 @@ export default async function KeyMetrics() {

{growthRate}%
- { - growthRate > 0 ? ( - - ) : growthRate < 0 ? ( - - ) : ( - null - ) - } + {growthRate > 0 ? ( + + ) : growthRate < 0 ? ( + + ) : null}

vs last month diff --git a/apps/web/src/lib/queries/charts.ts b/apps/web/src/lib/queries/charts.ts index a586883b..b7b8a42f 100644 --- a/apps/web/src/lib/queries/charts.ts +++ b/apps/web/src/lib/queries/charts.ts @@ -199,9 +199,9 @@ export async function getGrowthRate() { sql`${users.joinDate} >= date(datetime('now', '-1 month', 'start of month')) AND ${users.joinDate} < date(datetime('now', 'start of month'))`, ); - const currentMonthCount = currentMonthResult[0]?.count || 1; + const currentMonthCount = currentMonthResult[0]?.count || 1; const previousMonthCount = previousMonthResult[0]?.count || 1; // Avoid division by zero - + const growthRate = ( ((currentMonthCount - previousMonthCount) / previousMonthCount) * 100