diff --git a/apps/web/src/app/admin/events/new/page.tsx b/apps/web/src/app/admin/events/new/page.tsx
index 6a11aa99..0050480d 100644
--- a/apps/web/src/app/admin/events/new/page.tsx
+++ b/apps/web/src/app/admin/events/new/page.tsx
@@ -1,4 +1,4 @@
-import NewEventForm from "@/components/admin/events/NewEventForm";
+import NewEventForm from "@/components/events/admin/NewEventForm";
export default function Page() {
const defaultDate = new Date();
diff --git a/apps/web/src/app/admin/events/page.tsx b/apps/web/src/app/admin/events/page.tsx
index 2a9d0ae1..980d2fcf 100644
--- a/apps/web/src/app/admin/events/page.tsx
+++ b/apps/web/src/app/admin/events/page.tsx
@@ -1,12 +1,11 @@
-import { db } from "db";
-import { DataTable } from "@/components/admin/events/EventDataTable";
-import { columns } from "@/components/admin/events/EventColumns";
+import { EventDataTable } from "@/components/events/shared/EventDataTable";
+import { columns } from "@/components/events/shared/EventColumns";
import { Button } from "@/components/shadcn/ui/button";
import { PlusCircle } from "lucide-react";
import Link from "next/link";
-
+import { getAllEvents } from "db/functions";
export default async function Page() {
- const events = await db.query.events.findMany();
+ const events = await getAllEvents();
return (
@@ -17,7 +16,7 @@ export default async function Page() {
Events
- {events.length} Event{events.length != 1 ? "s" : ""}
+ {events.length} Event{events.length != 1 && "s"}
@@ -30,7 +29,7 @@ export default async function Page() {
-
+
);
}
diff --git a/apps/web/src/app/api/admin/events/create/route.ts b/apps/web/src/app/api/admin/events/create/route.ts
index bfb68f73..372cf7de 100644
--- a/apps/web/src/app/api/admin/events/create/route.ts
+++ b/apps/web/src/app/api/admin/events/create/route.ts
@@ -9,6 +9,7 @@ import { z } from "zod";
import superjson from "superjson";
import c from "config";
+// Make this a server action
export async function POST(req: Request) {
const { userId } = auth();
@@ -25,9 +26,8 @@ export async function POST(req: Request) {
return new Response("Unauthorized", { status: 401 });
}
- // console.log(await req.json());
const body = superjson.parse(await req.text());
- const parsedBody = newEventValidator.safeParse(body);
+ const parsedBody = newEventFormSchema.safeParse(body);
if (!parsedBody.success) {
return new Response("Malformed request body.", { status: 400 });
diff --git a/apps/web/src/app/dash/layout.tsx b/apps/web/src/app/dash/layout.tsx
index c784403d..15d16e71 100644
--- a/apps/web/src/app/dash/layout.tsx
+++ b/apps/web/src/app/dash/layout.tsx
@@ -45,12 +45,15 @@ export default async function DashLayout({ children }: DashLayoutProps) {
@@ -81,7 +84,9 @@ export default async function DashLayout({ children }: DashLayoutProps) {
-
+
{Object.entries(c.dashPaths.dash).map(([name, path]) => (
diff --git a/apps/web/src/app/dash/schedule/page.tsx b/apps/web/src/app/dash/schedule/page.tsx
index 3650b296..1d9b20fc 100644
--- a/apps/web/src/app/dash/schedule/page.tsx
+++ b/apps/web/src/app/dash/schedule/page.tsx
@@ -1,21 +1,11 @@
-import c from "config";
-import Day from "@/components/schedule/Day";
-import { db } from "db";
-import { format, compareAsc } from "date-fns";
-import { type ReactNode } from "react";
-import { formatInTimeZone } from "date-fns-tz";
-import { redirect } from "next/navigation";
-
-export default async function Page() {
- const events = await db.query.events.findMany();
-
+import { Suspense } from "react";
+import UserScheduleView from "@/components/schedule/UserScheduleView";
+import Loading from "@/components/shared/Loading";
+export default function Page() {
return (
-
-
- Bug with Scheduling was found. Fix Coming soon!
-
- - Christian
-
+
}>
+
+
);
}
diff --git a/apps/web/src/app/schedule/[id]/page.tsx b/apps/web/src/app/schedule/[id]/page.tsx
index dc45b9c6..c5c1ad74 100644
--- a/apps/web/src/app/schedule/[id]/page.tsx
+++ b/apps/web/src/app/schedule/[id]/page.tsx
@@ -2,7 +2,7 @@ import { db } from "db";
import { eq } from "db/drizzle";
import { events } from "db/schema";
import FullScreenMessage from "@/components/shared/FullScreenMessage";
-import EventFull from "@/components/schedule/EventFull";
+import EventDetails from "@/components/events/admin/EventDetails";
import Navbar from "@/components/shared/Navbar";
export default async function Page({ params }: { params: { id: string } }) {
@@ -33,7 +33,7 @@ export default async function Page({ params }: { params: { id: string } }) {
return (
<>
-
+
>
);
}
diff --git a/apps/web/src/components/schedule/EventFull.tsx b/apps/web/src/components/events/admin/EventDetails.tsx
similarity index 72%
rename from apps/web/src/components/schedule/EventFull.tsx
rename to apps/web/src/components/events/admin/EventDetails.tsx
index 922fcded..298d7a17 100644
--- a/apps/web/src/components/schedule/EventFull.tsx
+++ b/apps/web/src/components/events/admin/EventDetails.tsx
@@ -1,15 +1,17 @@
-import { events } from "db/schema";
-import { InferModel } from "db/drizzle";
import c from "config";
import { Badge } from "@/components/shadcn/ui/badge";
import Balancer from "react-wrap-balancer";
import { formatInTimeZone } from "date-fns-tz";
+import { getClientTimeZone } from "@/lib/utils/client/shared";
+import { EventType } from "@/lib/types/events";
+import { headers } from "next/headers";
+import { VERCEL_IP_TIMEZONE_HEADER_KEY } from "@/lib/constants";
+
+export default function EventDetails({ event }: { event: EventType }) {
+ const userTimeZoneHeaderKey = headers().get(VERCEL_IP_TIMEZONE_HEADER_KEY);
+
+ const userTimeZone = getClientTimeZone(userTimeZoneHeaderKey);
-export default function EventFull({
- event,
-}: {
- event: InferModel
;
-}) {
return (
{`${formatInTimeZone(
event.startTime,
- c.hackathonTimezone,
+ userTimeZone,
"EEEE MMMM do",
)}, ${formatInTimeZone(
event.startTime,
- c.hackathonTimezone,
+ userTimeZone,
"h:mm a",
- )} - ${formatInTimeZone(event.endTime, c.hackathonTimezone, "h:mm a")}`}
+ )} - ${formatInTimeZone(event.endTime, userTimeZone, "h:mm a")}`}
diff --git a/apps/web/src/components/admin/events/NewEventForm.tsx b/apps/web/src/components/events/admin/NewEventForm.tsx
similarity index 70%
rename from apps/web/src/components/admin/events/NewEventForm.tsx
rename to apps/web/src/components/events/admin/NewEventForm.tsx
index e20a7bed..d43ea847 100644
--- a/apps/web/src/components/admin/events/NewEventForm.tsx
+++ b/apps/web/src/components/events/admin/NewEventForm.tsx
@@ -25,45 +25,43 @@ import { Textarea } from "@/components/shadcn/ui/textarea";
import c from "config";
import { DateTimePicker } from "@/components/shadcn/ui/date-time-picker/date-time-picker";
import { parseAbsolute, getLocalTimeZone } from "@internationalized/date";
-import { newEventValidator } from "@/validators/shared/newEvent";
import { zpostSafe } from "@/lib/utils/client/zfetch";
import { BasicRedirValidator } from "@/validators/shared/basicRedir";
import { useState } from "react";
-import { Shell } from "lucide-react";
+import { LoaderPinwheel } from "lucide-react";
import { useRouter } from "next/navigation";
-
-interface NewEventFormProps {
- defaultDate: Date;
-}
-
-const formSchema = newEventValidator.merge(
- z.object({
- type: z.enum(Object.keys(c.eventTypes) as any),
- }),
-);
+import { ONE_HOUR_IN_MILLISECONDS } from "@/lib/constants";
+import { NewEventFormProps } from "@/lib/types/events";
+import { newEventFormSchema } from "@/validators/event";
+import { useAction } from "next-safe-action/hook";
+import { eventType } from "@/lib/utils/shared/types";
+import { useEffect } from "react";
+import { ThreeCircles } from "react-loader-spinner";
export default function NewEventForm({ defaultDate }: NewEventFormProps) {
const [loading, setLoading] = useState(false);
const router = useRouter();
- const form = useForm>({
- resolver: zodResolver(formSchema),
+ const userLocalTimeZone = getLocalTimeZone();
+
+ const form = useForm>({
+ resolver: zodResolver(newEventFormSchema),
defaultValues: {
title: "",
description: "",
type: "" as any,
host: "",
startTime: defaultDate,
- endTime: defaultDate,
+ endTime: new Date(defaultDate.getTime() + ONE_HOUR_IN_MILLISECONDS),
},
});
- async function onSubmit(values: z.infer) {
+ async function onSubmit(values: z.infer) {
setLoading(true);
const res = await zpostSafe({
url: "/api/admin/events/create",
body: values,
superReq: true,
- vReq: formSchema,
+ vReq: newEventFormSchema,
vRes: BasicRedirValidator,
});
setLoading(false);
@@ -91,8 +89,7 @@ export default function NewEventForm({ defaultDate }: NewEventFormProps) {
- Generally its best to keep this short and
- consise
+ Keep title short and concise
@@ -105,10 +102,7 @@ export default function NewEventForm({ defaultDate }: NewEventFormProps) {
Description
-
+
@@ -178,18 +172,27 @@ export default function NewEventForm({ defaultDate }: NewEventFormProps) {
!!field.value
? parseAbsolute(
field.value.toISOString(),
- getLocalTimeZone(),
+ userLocalTimeZone,
)
: null
}
onChange={(date) => {
- field.onChange(
- !!date
- ? date.toDate(
- getLocalTimeZone(),
- )
- : null,
- );
+ const newDate = !!date
+ ? date.toDate(userLocalTimeZone)
+ : null;
+ field.onChange(newDate);
+ const isEventStartBeforeEnd =
+ newDate &&
+ newDate > form.getValues("endTime");
+ if (isEventStartBeforeEnd) {
+ form.setValue(
+ "endTime",
+ new Date(
+ newDate.getTime() +
+ ONE_HOUR_IN_MILLISECONDS,
+ ),
+ );
+ }
}}
shouldCloseOnSelect={false}
granularity={"minute"}
@@ -210,18 +213,28 @@ export default function NewEventForm({ defaultDate }: NewEventFormProps) {
!!field.value
? parseAbsolute(
field.value.toISOString(),
- getLocalTimeZone(),
+ userLocalTimeZone,
)
: null
}
onChange={(date) => {
- field.onChange(
- !!date
- ? date.toDate(
- getLocalTimeZone(),
- )
- : null,
- );
+ const newDate = !!date
+ ? date.toDate(userLocalTimeZone)
+ : null;
+ field.onChange(newDate);
+ const isEventEndBeforeStart =
+ newDate &&
+ newDate <
+ form.getValues("startTime");
+ if (isEventEndBeforeStart) {
+ form.setValue(
+ "startTime",
+ new Date(
+ newDate.getTime() -
+ ONE_HOUR_IN_MILLISECONDS,
+ ),
+ );
+ }
}}
shouldCloseOnSelect={false}
granularity={"minute"}
@@ -234,7 +247,16 @@ export default function NewEventForm({ defaultDate }: NewEventFormProps) {
{loading ? (
- Creating Event
+ Creating Event{" "}
+
) : (
diff --git a/apps/web/src/components/admin/events/EventColumns.tsx b/apps/web/src/components/events/shared/EventColumns.tsx
similarity index 90%
rename from apps/web/src/components/admin/events/EventColumns.tsx
rename to apps/web/src/components/events/shared/EventColumns.tsx
index c1dcea8b..de821c59 100644
--- a/apps/web/src/components/admin/events/EventColumns.tsx
+++ b/apps/web/src/components/events/shared/EventColumns.tsx
@@ -1,13 +1,11 @@
"use client";
import { ColumnDef } from "@tanstack/react-table";
-import { z } from "zod";
-import { createSelectSchema } from "drizzle-zod";
-import { events } from "db/schema";
import Link from "next/link";
import { Button } from "@/components/shadcn/ui/button";
import { Badge } from "@/components/shadcn/ui/badge";
import c from "config";
+import { eventTableValidatorType } from "@/lib/types/events";
const eventValidator = createSelectSchema(events);
@@ -42,7 +40,7 @@ export const columns: ColumnDef[] = [
accessorKey: "startTime",
header: "Start",
cell: ({ row }) => (
-
+
{new Date(row.original.startTime).toLocaleDateString() + " "}
{new Date(row.original.startTime).toLocaleTimeString("en-US", {
hour: "2-digit",
@@ -55,7 +53,7 @@ export const columns: ColumnDef[] = [
accessorKey: "endTime",
header: "End",
cell: ({ row }) => (
-
+
{new Date(row.original.endTime).toLocaleDateString() + " "}
{new Date(row.original.endTime).toLocaleTimeString("en-US", {
hour: "2-digit",
diff --git a/apps/web/src/components/admin/events/EventDataTable.tsx b/apps/web/src/components/events/shared/EventDataTable.tsx
similarity index 93%
rename from apps/web/src/components/admin/events/EventDataTable.tsx
rename to apps/web/src/components/events/shared/EventDataTable.tsx
index 0af4a9dc..30295da7 100644
--- a/apps/web/src/components/admin/events/EventDataTable.tsx
+++ b/apps/web/src/components/events/shared/EventDataTable.tsx
@@ -16,15 +16,12 @@ import {
TableRow,
} from "@/components/shadcn/ui/table";
-import { useCallback } from "react";
-import { useRouter } from "next/navigation";
-
interface DataTableProps {
columns: ColumnDef[];
data: TData[];
}
-export function DataTable({
+export function EventDataTable({
columns,
data,
}: DataTableProps) {
diff --git a/apps/web/src/components/registration/RegisterForm.tsx b/apps/web/src/components/registration/RegisterForm.tsx
index f0962f77..07ebe78a 100644
--- a/apps/web/src/components/registration/RegisterForm.tsx
+++ b/apps/web/src/components/registration/RegisterForm.tsx
@@ -51,7 +51,7 @@ import { FileRejection, useDropzone } from "react-dropzone";
import { put, type PutBlobResult } from "@vercel/blob";
import { Tag, TagInput } from "@/components/shadcn/ui/tag/tag-input";
import CreatingRegistration from "./CreatingRegistration";
-
+import { bucketResumeBaseUploadUrl } from "config";
interface RegisterFormProps {
defaultEmail: string;
}
@@ -94,6 +94,10 @@ export default function RegisterForm({ defaultEmail }: RegisterFormProps) {
},
});
+ const { isSubmitSuccessful, isSubmitted, errors } = form.formState;
+
+ const hasErrors = !isSubmitSuccessful && isSubmitted;
+
const [uploadedFile, setUploadedFile] = useState(null);
const [skills, setSkills] = useState([]);
const [isLoading, setIsLoading] = useState(false);
@@ -110,7 +114,6 @@ export default function RegisterForm({ defaultEmail }: RegisterFormProps) {
async function onSubmit(data: z.infer) {
setIsLoading(true);
- console.log("Submision Clicked");
if (!userId || !isLoaded) {
setIsLoading(false);
return alert(
@@ -131,7 +134,7 @@ export default function RegisterForm({ defaultEmail }: RegisterFormProps) {
let resume: string = c.noResumeProvidedURL;
if (uploadedFile) {
- const fileLocation = `${c.hackathonName}/resume/${uploadedFile.name}`;
+ const fileLocation = `${bucketResumeBaseUploadUrl}/${uploadedFile.name}`;
const newBlob = await put(fileLocation, uploadedFile, {
access: "public",
handleBlobUploadUrl: "/api/upload/resume/register",
@@ -179,10 +182,6 @@ export default function RegisterForm({ defaultEmail }: RegisterFormProps) {
);
}
if (acceptedFiles.length > 0) {
- console.log(
- `Got accepted file! The length of the array is ${acceptedFiles.length}.`,
- );
- console.log(acceptedFiles[0]);
setUploadedFile(acceptedFiles[0]);
}
},
@@ -552,10 +551,6 @@ export default function RegisterForm({ defaultEmail }: RegisterFormProps) {
onSelect={(
value,
) => {
- console.log(
- "value changed to: ",
- value,
- );
form.setValue(
"university",
value,
@@ -1212,6 +1207,12 @@ export default function RegisterForm({ defaultEmail }: RegisterFormProps) {
/>
+ {hasErrors && (
+
+ Something doesn't look right. Please check your
+ inputs.
+
+ )}
diff --git a/apps/web/src/components/schedule/Day.tsx b/apps/web/src/components/schedule/Day.tsx
index 22a5d4db..b2641fe1 100644
--- a/apps/web/src/components/schedule/Day.tsx
+++ b/apps/web/src/components/schedule/Day.tsx
@@ -1,71 +1,45 @@
-import { events } from "db/schema";
-import { InferModel } from "db/drizzle";
import { format, compareAsc } from "date-fns";
+import { EventType } from "@/lib/types/events";
import { Badge } from "@/components/shadcn/ui/badge";
import c from "config";
-import Link from "next/link";
-import { formatInTimeZone } from "date-fns-tz";
-
+import { headers } from "next/headers";
+import { getClientTimeZone } from "@/lib/utils/client/shared";
+import EventItem from "./EventItem";
+import { VERCEL_IP_TIMEZONE_HEADER_KEY } from "@/lib/constants";
interface DayProps {
title: string;
subtitle: string;
- events: InferModel[];
-}
-
-interface EventItemProps {
- event: InferModel;
+ events: EventType[];
}
export default function Day({ title, subtitle, events }: DayProps) {
- let dup = structuredClone(events);
- dup.sort((a, b) => compareAsc(a.startTime, b.startTime));
+ const userTimeZoneHeaderKey = headers().get(VERCEL_IP_TIMEZONE_HEADER_KEY);
+
+ const userTimeZone = getClientTimeZone(userTimeZoneHeaderKey);
+
return (
-
+
{title}
-
{subtitle}
-
- {dup.map((event) => (
-
- ))}
-
-
- );
-}
-
-function EventItem({ event }: EventItemProps) {
- return (
-
-
-
-
{event.title}
-
-
)[
- event.type
- ] || c.eventTypes.Other,
- }}
- >
- {event.type}
-
+
{subtitle}
+
+ {events.length > 0 ? (
+ events.map((event) => (
+
+ ))
+ ) : (
+
+
+ No events scheduled at this time.
+
-
-
-
{`${formatInTimeZone(
- event.startTime,
- c.hackathonTimezone,
- "h:mm a",
- )} - ${formatInTimeZone(event.endTime, c.hackathonTimezone, "h:mm a")}`}
-
+ )}
-
+
);
}
diff --git a/apps/web/src/components/schedule/EventItem.tsx b/apps/web/src/components/schedule/EventItem.tsx
new file mode 100644
index 00000000..6fbdb7a0
--- /dev/null
+++ b/apps/web/src/components/schedule/EventItem.tsx
@@ -0,0 +1,59 @@
+import { EventType } from "@/lib/types/events";
+import Link from "next/link";
+import { Badge } from "../shadcn/ui/badge";
+import { formatInTimeZone } from "date-fns-tz";
+import c from "config";
+
+export default function EventItem({
+ event,
+ userTimeZone,
+}: {
+ event: EventType;
+ userTimeZone: string;
+}) {
+ const startTimeFormatted = formatInTimeZone(
+ event.startTime,
+ userTimeZone,
+ "EEEE, hh:mm a",
+ {
+ useAdditionalDayOfYearTokens: true,
+ },
+ );
+
+ const endTimeFormatted = formatInTimeZone(
+ event.endTime,
+ userTimeZone,
+ "h:mm a",
+ );
+
+ const href = `/schedule/${event.id}`;
+
+ const eventTypeColor =
+ (c.eventTypes as Record
)[event.type] ||
+ c.eventTypes.Other;
+
+ return (
+
+
+
+
+
{`${startTimeFormatted} - ${endTimeFormatted}`}
+
+
+
+ );
+}
diff --git a/apps/web/src/components/schedule/UserScheduleView.tsx b/apps/web/src/components/schedule/UserScheduleView.tsx
new file mode 100644
index 00000000..84abd624
--- /dev/null
+++ b/apps/web/src/components/schedule/UserScheduleView.tsx
@@ -0,0 +1,17 @@
+import { getAllEvents } from "db/functions";
+import Day from "@/components/schedule/Day";
+import c from "config";
+export default async function UserScheduleView() {
+ const events = await getAllEvents();
+
+ // Idea for later: we use tabs to sort our data by day
+ return (
+
+
+
+ );
+}
diff --git a/apps/web/src/components/shared/Loading.tsx b/apps/web/src/components/shared/Loading.tsx
index daa91c76..b3ef21c3 100644
--- a/apps/web/src/components/shared/Loading.tsx
+++ b/apps/web/src/components/shared/Loading.tsx
@@ -1,10 +1,16 @@
import { cn } from "@/lib/utils/client/cn";
import { Loader2 } from "lucide-react";
-
interface LoadingProps {
className?: string;
}
export default function Loading({ className }: LoadingProps) {
- return ;
+ return (
+
+
+ Loading. Please wait.
+
+
+
+ );
}
diff --git a/apps/web/src/components/shared/ThreeCirclesLoader.tsx b/apps/web/src/components/shared/ThreeCirclesLoader.tsx
new file mode 100644
index 00000000..beaaf67a
--- /dev/null
+++ b/apps/web/src/components/shared/ThreeCirclesLoader.tsx
@@ -0,0 +1,16 @@
+"use client";
+import { ThreeCircles } from "react-loader-spinner";
+
+export default function ThreeCirclesLoader() {
+ return (
+
+ );
+}
diff --git a/apps/web/src/lib/constants/index.ts b/apps/web/src/lib/constants/index.ts
new file mode 100644
index 00000000..b239662a
--- /dev/null
+++ b/apps/web/src/lib/constants/index.ts
@@ -0,0 +1,2 @@
+export const ONE_HOUR_IN_MILLISECONDS = 3600000;
+export const VERCEL_IP_TIMEZONE_HEADER_KEY = "x-vercel-ip-timezone";
diff --git a/apps/web/src/lib/types/events.ts b/apps/web/src/lib/types/events.ts
new file mode 100644
index 00000000..7ef29a03
--- /dev/null
+++ b/apps/web/src/lib/types/events.ts
@@ -0,0 +1,20 @@
+import { events } from "db/schema";
+import z from "zod";
+import { eventDataTableValidator } from "@/validators/event";
+import type { InferSelectModel, InferInsertModel } from "db";
+
+export interface eventInsertType extends InferInsertModel {}
+export interface EventType extends InferSelectModel {}
+
+export type eventTableValidatorType = Pick<
+ z.infer,
+ "title" | "startTime" | "endTime" | "id" | "type"
+>;
+
+export interface NewEventFormProps {
+ defaultDate: Date;
+}
+
+export interface getAllEventsOptions {
+ ascending?: boolean;
+}
diff --git a/apps/web/src/lib/types/index.ts b/apps/web/src/lib/types/index.ts
new file mode 100644
index 00000000..1784004f
--- /dev/null
+++ b/apps/web/src/lib/types/index.ts
@@ -0,0 +1 @@
+export * from "./events";
diff --git a/apps/web/src/lib/utils/client/shared.ts b/apps/web/src/lib/utils/client/shared.ts
new file mode 100644
index 00000000..5f5f516f
--- /dev/null
+++ b/apps/web/src/lib/utils/client/shared.ts
@@ -0,0 +1,3 @@
+export function getClientTimeZone(vercelIPTimeZone: string | null) {
+ return vercelIPTimeZone ?? Intl.DateTimeFormat().resolvedOptions().timeZone;
+}
diff --git a/apps/web/src/validators/event.ts b/apps/web/src/validators/event.ts
new file mode 100644
index 00000000..ce5dbc53
--- /dev/null
+++ b/apps/web/src/validators/event.ts
@@ -0,0 +1,19 @@
+import { createInsertSchema } from "drizzle-zod";
+import { events } from "db/schema";
+import { createSelectSchema } from "drizzle-zod";
+import z from "zod";
+import c from "config";
+
+export const newEventFormSchema = createInsertSchema(events, {
+ title: z.string().min(1),
+ description: z.string().min(1),
+ startTime: z.date(),
+ endTime: z.date(),
+ host: z.string().optional(),
+ type: z.enum(Object.keys(c.eventTypes) as any),
+}).refine(({ startTime, endTime }) => startTime < endTime, {
+ message: "Start time must be before end time",
+ path: ["startTime"],
+});
+
+export const eventDataTableValidator = createSelectSchema(events);
diff --git a/apps/web/src/validators/shared/RegisterForm.ts b/apps/web/src/validators/shared/RegisterForm.ts
index dce90912..dcd9594b 100644
--- a/apps/web/src/validators/shared/RegisterForm.ts
+++ b/apps/web/src/validators/shared/RegisterForm.ts
@@ -80,6 +80,7 @@ export const RegisterFormValidator = z.object({
z.literal("Sophomore", defaultPrettyError),
z.literal("Junior", defaultPrettyError),
z.literal("Senior", defaultPrettyError),
+ z.literal("Recent Grad", defaultPrettyError),
z.literal("Other", defaultPrettyError),
]),
hackathonsAttended: z
diff --git a/apps/web/src/validators/shared/newEvent.ts b/apps/web/src/validators/shared/newEvent.ts
deleted file mode 100644
index 6838c294..00000000
--- a/apps/web/src/validators/shared/newEvent.ts
+++ /dev/null
@@ -1,4 +0,0 @@
-import { createInsertSchema } from "drizzle-zod";
-import { events } from "db/schema";
-
-export const newEventValidator = createInsertSchema(events);
diff --git a/packages/config/hackkit.config.ts b/packages/config/hackkit.config.ts
index f0ce489c..8f87c101 100644
--- a/packages/config/hackkit.config.ts
+++ b/packages/config/hackkit.config.ts
@@ -1,6 +1,5 @@
-export const defaultTheme = "dark";
-
-export default {
+const defaultTheme = "dark";
+const c = {
hackathonName: "HackKit",
itteration: "I",
siteUrl: "https://rowdyhacks.org", // Do not have a trailing slash
@@ -125,6 +124,7 @@ export default {
foreground: "#ffffff",
checked: false,
},
+ // Why is the checked set to a color?
mlh: {
title: "MLH",
color: "#ffffff",
@@ -152,9 +152,11 @@ export default {
},
} as const;
+const bucketResumeBaseUploadUrl = `${c.hackathonName}/${c.itteration}/resume`;
+
// Its important that this is kept in sync with the database schema.
-export const perms = [
+const perms = [
"hacker",
"volunteer",
"mentor",
@@ -165,7 +167,7 @@ export const perms = [
// These are routes (pages) which do not require a account / authentication. They are used in the authMiddleware in middleware.ts. Be careful which routes you add here!
-export const publicRoutes = [
+const publicRoutes = [
"/",
/^\/schedule(\/.*)?$/,
/^\/@/,
@@ -176,7 +178,7 @@ export const publicRoutes = [
// Generally it is reccomended to put your primary audience's university at the top of this list.
-export const schools = [
+const schools = [
"The University of Texas at San Antonio",
"Texas A&M University - San Antonio",
"American Heritage School",
@@ -591,7 +593,9 @@ export const schools = [
"Other",
] as const;
-export const majors = [
+const majors = [
+ "Computer Science",
+ "Cyber Security",
"Accounting",
"Accounting Technician",
"Actuarial Science",
@@ -625,13 +629,11 @@ export const majors = [
"Computer & Information Sciences, General",
"Computer Engineering",
"Computer Networking/Telecommunications",
- "Computer Science",
"Computer Software & Media Applications",
"Computer System Administration",
"Construction Engineering/Management",
"Creative Writing",
"Criminology",
- "Cyber Security",
"Data Management Technology",
"Dental Assisting",
"Design & Visual Communications, General",
@@ -704,3 +706,13 @@ export const majors = [
"Webpage Design",
"Other",
] as const;
+
+export default c;
+export {
+ defaultTheme,
+ bucketResumeBaseUploadUrl,
+ perms,
+ publicRoutes,
+ schools,
+ majors,
+};
diff --git a/packages/db/functions/events.ts b/packages/db/functions/events.ts
new file mode 100644
index 00000000..71f7a56a
--- /dev/null
+++ b/packages/db/functions/events.ts
@@ -0,0 +1,26 @@
+import { db, asc, desc } from "..";
+import {
+ eventInsertType,
+ getAllEventsOptions,
+} from "../../../apps/web/src/lib/types/events";
+import { events } from "../schema";
+
+export function createNewEvent(event: eventInsertType) {
+ return db
+ .insert(events)
+ .values({
+ ...event,
+ })
+ .returning({
+ eventID: events.id,
+ });
+}
+
+export function getAllEvents(options?: getAllEventsOptions) {
+ const orderByClause = options?.ascending
+ ? [asc(events.startTime)]
+ : [desc(events.startTime)];
+ return db.query.events.findMany({
+ orderBy: orderByClause,
+ });
+}
diff --git a/packages/db/functions/index.ts b/packages/db/functions/index.ts
new file mode 100644
index 00000000..1784004f
--- /dev/null
+++ b/packages/db/functions/index.ts
@@ -0,0 +1 @@
+export * from "./events";
diff --git a/packages/db/schema.ts b/packages/db/schema.ts
index 945c5403..5a9d535d 100644
--- a/packages/db/schema.ts
+++ b/packages/db/schema.ts
@@ -155,6 +155,10 @@ export const events = pgTable("events", {
title: varchar("name", { length: 255 }).notNull(),
startTime: timestamp("start_time").notNull(),
endTime: timestamp("end_time").notNull(),
+ // checkinStartTime: timestamp("checkin_start_time").notNull(),
+ // checkinEndTime: timestamp("checkin_end_time").notNull(),
+ // location: varchar("location", { length: 255 }).notNull(),
+ // points: integer("points").notNull().default(0),
description: text("description").notNull(),
type: varchar("type", { length: 50 }).notNull(),
host: varchar("host", { length: 255 }),