diff --git a/apps/web/src/actions/checkin.ts b/apps/web/src/actions/checkin.ts index 5e4edf1..c6df9c5 100644 --- a/apps/web/src/actions/checkin.ts +++ b/apps/web/src/actions/checkin.ts @@ -6,14 +6,43 @@ 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; +const { + ALREADY_CHECKED_IN, + SUCCESS, + FAILED, + SOME_FAILED, + EVENT_NOT_FOUND, + CHECKIN_NOT_AVAILABLE, +} = 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_NOT_FOUND], + }); + } + + const currentDateUTC = new Date(); + const isCheckinAvailable = isWithinInterval(currentDateUTC, { + start: event.checkinStart, + end: event.checkinEnd, + }); + if (!isCheckinAvailable) { + returnValidationErrors(z.null(), { + _errors: [CHECKIN_NOT_AVAILABLE], + }); + } + try { await checkInUserClient(parsedInput); } catch (e) { diff --git a/apps/web/src/components/dash/admin/events/EditEventForm.tsx b/apps/web/src/components/dash/admin/events/EditEventForm.tsx index 2264e5b..7a8c81d 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,30 @@ 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("checkinStart", eventStartTime); + form.setValue("checkinEnd", eventEndTime); + } + }, [eventEndTime]); + useEffect(() => { if (Object.keys(form.formState.errors).length > 0) { console.log("Errors: ", form.formState.errors); diff --git a/apps/web/src/components/dash/admin/events/NewEventForm.tsx b/apps/web/src/components/dash/admin/events/NewEventForm.tsx index b30a31d..56f6d38 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,33 @@ 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, diff --git a/apps/web/src/components/dash/admin/overview/KeyMetrics.tsx b/apps/web/src/components/dash/admin/overview/KeyMetrics.tsx index 9b8aec6..360e557 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,11 @@ export default async function KeyMetrics() {
vs last month
diff --git a/apps/web/src/components/events/EventsCardView.tsx b/apps/web/src/components/events/EventsCardView.tsx
index fe0922b..3316d2d 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,15 +20,19 @@ export default function EventsCardView({
key={event.id}
event={event}
isPast={isAfter(currentDateUTC, event.end)}
- isEventCurrentlyHappening={isEventCurrentlyHappening(
+ isEventCurrentlyHappening={isWithinInterval(
currentDateUTC,
- event.start,
- event.end,
+ {
+ start: event.start,
+ end: event.end,
+ },
)}
- isEventCheckinAllowed={isEventCheckinAllowed(
+ isEventCheckinAllowed={isWithinInterval(
currentDateUTC,
- event.checkinStart,
- event.checkinEnd,
+ {
+ 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 35dcf72..dd94d92 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,11 @@ 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 09df76e..b7462c9 100644
--- a/apps/web/src/components/events/id/EventDetails.tsx
+++ b/apps/web/src/components/events/id/EventDetails.tsx
@@ -1,21 +1,15 @@
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 { getClientTimeZone, getUTCDate } from "@/lib/utils";
+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 +60,13 @@ export default async function EventDetails({
if (!event) {
return
{event.location}
+{location}