diff --git a/.github/workflows/generateCheck.sh b/.github/workflows/generateCheck.sh
index 0f98e9cb..8d1ba0b0 100755
--- a/.github/workflows/generateCheck.sh
+++ b/.github/workflows/generateCheck.sh
@@ -1,14 +1,14 @@
-if [ $status == 0 ]; then
- echo "## Formatting Check passed 🥳" >>$GITHUB_STEP_SUMMARY
- echo "All files are formatted correctly" >>$GITHUB_STEP_SUMMARY
- exit 0
+if [ $status == 'success' ]; then
+ echo "## Formatting Check passed 🥳" >>$GITHUB_STEP_SUMMARY
+ echo "All files are formatted correctly" >>$GITHUB_STEP_SUMMARY
+ exit 0
else
- echo "## Formatting Check Failed 😅" >>$GITHUB_STEP_SUMMARY
- echo "Please run prettier using \`npx prettier . --write\` in order to format your code" >>$GITHUB_STEP_SUMMARY
- echo "### Files with bad formatting:" >>$GITHUB_STEP_SUMMARY
- for file in $files; do
- echo "- $file" >>$GITHUB_STEP_SUMMARY
- echo "::error file=$file::$file not formatted correctly"
- done
- exit 1
+ echo "## Formatting Check Failed 😅" >>$GITHUB_STEP_SUMMARY
+ echo "Please run prettier using \`npx prettier . --write\` in order to format your code" >>$GITHUB_STEP_SUMMARY
+ echo "### Files with bad formatting:" >>$GITHUB_STEP_SUMMARY
+ for file in $files; do
+ echo "- $file" >>$GITHUB_STEP_SUMMARY
+ echo "::error file=$file::$file not formatted correctly"
+ done
+ exit 1
fi
diff --git a/.github/workflows/prettierCheck.yml b/.github/workflows/prettierCheck.yml
index e642ea75..7ebc8f6b 100644
--- a/.github/workflows/prettierCheck.yml
+++ b/.github/workflows/prettierCheck.yml
@@ -11,14 +11,12 @@ jobs:
node-version: 18
cache: 'npm'
- name: Run npm install
- run: |
- mv package.json package.json.bak
- npm i --no-save prettier prettier-plugin-tailwindcss
- mv package.json.bak package.json
+ run: npm ci
- name: Run prettier
- run: |
- files=`npx prettier . -l` || st=$? && st=$?
- echo status=`echo $st`>>"$GITHUB_ENV"
- echo files=`echo $files`>> "$GITHUB_ENV"
+ id: prettier
+ continue-on-error: true
+ run: echo files=`npx prettier . -l` >> "$GITHUB_ENV"
- name: generate errors/summary
run: .github/workflows/generateCheck.sh
+ env:
+ status: ${{ steps.prettier.outcome }}
diff --git a/.prettierrc.js b/.prettierrc.js
deleted file mode 100644
index 08a34d3b..00000000
--- a/.prettierrc.js
+++ /dev/null
@@ -1,9 +0,0 @@
-module.exports = {
- printWidth: 80,
- semi: true,
- singleQuote: true,
- tabWidth: 2,
- trailingComma: 'all',
- useTabs: false,
- plugins: ['prettier-plugin-tailwindcss'],
-};
diff --git a/.prettierrc.mjs b/.prettierrc.mjs
new file mode 100644
index 00000000..b7128a21
--- /dev/null
+++ b/.prettierrc.mjs
@@ -0,0 +1,16 @@
+/**
+ * @see https://prettier.io/docs/en/configuration.html
+ * @type {import("prettier").Config}
+ */
+const config = {
+ printWidth: 80,
+ semi: true,
+ singleQuote: true,
+ tabWidth: 2,
+ trailingComma: 'all',
+ useTabs: false,
+ bracketSameLine: false,
+ plugins: ['prettier-plugin-tailwindcss'],
+};
+
+export default config;
diff --git a/src/app/about/page.tsx b/src/app/about/page.tsx
index 44259a53..2a0e1b80 100644
--- a/src/app/about/page.tsx
+++ b/src/app/about/page.tsx
@@ -1,4 +1,4 @@
-import Header from '@src/components/BaseHeader';
+import Header from '@src/components/header/BaseHeader';
import type { Metadata } from 'next';
export const metadata: Metadata = {
diff --git a/src/app/admin/carousel/add/page.tsx b/src/app/admin/carousel/add/page.tsx
index f609d74c..3da1d6ea 100644
--- a/src/app/admin/carousel/add/page.tsx
+++ b/src/app/admin/carousel/add/page.tsx
@@ -1,12 +1,12 @@
-import AddOrg from '@src/components/admin/AddOrg';
+import AddClub from '@src/components/admin/AddClub';
export default function Page() {
return (
- Add Orgs to Carousel
+ Add Clubs to Carousel
-
+
);
}
diff --git a/src/app/admin/orgs/[id]/page.tsx b/src/app/admin/clubs/[id]/page.tsx
similarity index 72%
rename from src/app/admin/orgs/[id]/page.tsx
rename to src/app/admin/clubs/[id]/page.tsx
index f6bba3fc..06626949 100644
--- a/src/app/admin/orgs/[id]/page.tsx
+++ b/src/app/admin/clubs/[id]/page.tsx
@@ -1,5 +1,5 @@
-import ApprovedOrg from '@src/components/admin/ApprovedOrg';
-import OtherOrgStatus from '@src/components/admin/OtherOrgStatus';
+import ApprovedClub from '@src/components/admin/ApprovedClub';
+import OtherClubStatus from '@src/components/admin/OtherClubStatus';
import { db } from '@src/server/db';
import { eq } from 'drizzle-orm';
import { notFound } from 'next/navigation';
@@ -16,9 +16,9 @@ export default async function Page({ params: { id } }: Props) {
{org.name}
{org.approved === 'approved' ? (
-
+
) : (
-
+
)}
);
diff --git a/src/app/admin/orgs/page.tsx b/src/app/admin/clubs/page.tsx
similarity index 51%
rename from src/app/admin/orgs/page.tsx
rename to src/app/admin/clubs/page.tsx
index d2fc79b8..c6558454 100644
--- a/src/app/admin/orgs/page.tsx
+++ b/src/app/admin/clubs/page.tsx
@@ -1,11 +1,11 @@
-import OrgTable from '@src/components/admin/OrgTable';
+import ClubTable from '@src/components/admin/ClubTable';
import { api } from '@src/trpc/server';
export default async function Page() {
- const clubs = await api.admin.allOrgs();
+ const clubs = await api.admin.allClubs();
return (
-
+
);
}
diff --git a/src/app/admin/page.tsx b/src/app/admin/page.tsx
index ba693fa0..372a0741 100644
--- a/src/app/admin/page.tsx
+++ b/src/app/admin/page.tsx
@@ -8,10 +8,10 @@ export default function Page() {
- Manage Orgs
+ Manage Clubs
{
+const ClubPage = async ({ params }: { params: { id: string } }) => {
const club = await api.club.getDirectoryInfo({ id: params.id });
if (!club) return
;
@@ -16,15 +16,15 @@ const OrganizationPage = async ({ params }: { params: { id: string } }) => {
-
-
-
+
+
+
);
};
-export default OrganizationPage;
+export default ClubPage;
export async function generateMetadata({
params,
diff --git a/src/components/CreateContactSelector.tsx b/src/app/directory/create/CreateContactSelector.tsx
similarity index 99%
rename from src/components/CreateContactSelector.tsx
rename to src/app/directory/create/CreateContactSelector.tsx
index cfd09ed7..2d0735c5 100644
--- a/src/components/CreateContactSelector.tsx
+++ b/src/app/directory/create/CreateContactSelector.tsx
@@ -16,7 +16,7 @@ import {
Website,
Youtube,
type logoProps,
-} from './ContactIcons';
+} from '@src/icons/ContactIcons';
import {
type Control,
type UseFormRegister,
diff --git a/src/components/OfficerSelector.tsx b/src/app/directory/create/OfficerSelector.tsx
similarity index 97%
rename from src/components/OfficerSelector.tsx
rename to src/app/directory/create/OfficerSelector.tsx
index 230828fa..05c07ef5 100644
--- a/src/components/OfficerSelector.tsx
+++ b/src/app/directory/create/OfficerSelector.tsx
@@ -7,7 +7,7 @@ import {
type FieldErrors,
} from 'react-hook-form';
import { type z } from 'zod';
-import { UserSearchBar } from './SearchBar';
+import { UserSearchBar } from '@src/components/searchBar/UserSearchBar';
type OfficerSelectorProps = {
control: Control
>;
diff --git a/src/app/directory/create/createForm.tsx b/src/app/directory/create/createForm.tsx
index b9342196..e9c89543 100644
--- a/src/app/directory/create/createForm.tsx
+++ b/src/app/directory/create/createForm.tsx
@@ -1,8 +1,8 @@
'use client';
/* eslint-disable @typescript-eslint/no-misused-promises */
import { zodResolver } from '@hookform/resolvers/zod';
-import ContactSelector from '@src/components/CreateContactSelector';
-import OfficerSelector from '@src/components/OfficerSelector';
+import ContactSelector from '@src/app/directory/create/CreateContactSelector';
+import OfficerSelector from '@src/app/directory/create/OfficerSelector';
import { api } from '@src/trpc/react';
import { createClubSchema } from '@src/utils/formSchemas';
import { useRouter } from 'next/navigation';
diff --git a/src/app/directory/create/page.tsx b/src/app/directory/create/page.tsx
index da5b2791..819bc121 100644
--- a/src/app/directory/create/page.tsx
+++ b/src/app/directory/create/page.tsx
@@ -1,4 +1,4 @@
-import Header from '@src/components/BaseHeader';
+import Header from '@src/components/header/BaseHeader';
import CreateClubForm from './createForm';
import { getServerAuthSession } from '@src/server/auth';
import { redirect } from 'next/navigation';
diff --git a/src/components/RegisterButton.tsx b/src/app/event/[id]/RegisterButton.tsx
similarity index 100%
rename from src/components/RegisterButton.tsx
rename to src/app/event/[id]/RegisterButton.tsx
diff --git a/src/app/event/[id]/page.tsx b/src/app/event/[id]/page.tsx
index 405c6452..9943eb68 100644
--- a/src/app/event/[id]/page.tsx
+++ b/src/app/event/[id]/page.tsx
@@ -1,4 +1,4 @@
-import { EventHeader } from '@src/components/BaseHeader';
+import { EventHeader } from '@src/components/header/BaseHeader';
import { db } from '@src/server/db';
import { and, eq } from 'drizzle-orm';
import { type Metadata } from 'next';
@@ -8,7 +8,7 @@ import Image from 'next/image';
import CountdownTimer from './CountdownTimer';
import Link from 'next/link';
import { getServerAuthSession } from '@src/server/auth';
-import RegisterButton from '@src/components/RegisterButton';
+import RegisterButton from '@src/app/event/[id]/RegisterButton';
type Params = { params: { id: string } };
diff --git a/src/app/events/page.tsx b/src/app/events/page.tsx
index 8036676e..79bc45dd 100644
--- a/src/app/events/page.tsx
+++ b/src/app/events/page.tsx
@@ -1,4 +1,4 @@
-import { EventHeader } from '@src/components/BaseHeader';
+import { EventHeader } from '@src/components/header/BaseHeader';
import { api } from '@src/trpc/server';
import EventView from './eventView';
import { type Metadata } from 'next';
diff --git a/src/app/feedback/page.tsx b/src/app/feedback/page.tsx
index 38feaa5d..069ed2f9 100644
--- a/src/app/feedback/page.tsx
+++ b/src/app/feedback/page.tsx
@@ -1,5 +1,5 @@
import React from 'react';
-import Header from '@src/components/BaseHeader';
+import Header from '@src/components/header/BaseHeader';
import { type Metadata } from 'next';
import Form from '@src/app/feedback/Form';
diff --git a/src/app/layout.tsx b/src/app/layout.tsx
index 504ac436..4a14d4fb 100644
--- a/src/app/layout.tsx
+++ b/src/app/layout.tsx
@@ -4,7 +4,7 @@ import { Inter } from 'next/font/google';
import { headers } from 'next/headers';
import { TRPCReactProvider } from '@src/trpc/react';
-import Sidebar from '@src/components/Sidebar';
+import Sidebar from '@src/components/nav/Sidebar';
import { type Metadata } from 'next';
import { Analytics } from '@vercel/analytics/react';
diff --git a/src/app/manage/[clubId]/(dashboard)/layout.tsx b/src/app/manage/[clubId]/(dashboard)/layout.tsx
index 6879ec2b..478e2375 100644
--- a/src/app/manage/[clubId]/(dashboard)/layout.tsx
+++ b/src/app/manage/[clubId]/(dashboard)/layout.tsx
@@ -1,5 +1,5 @@
-import Header from '@src/components/BaseHeader';
-import BackButton from '@src/components/BlueBackButton';
+import Header from '@src/components/header/BaseHeader';
+import { BlueBackButton } from '@src/components/backButton';
import { getServerAuthSession } from '@src/server/auth';
import { api } from '@src/trpc/server';
import { signInRoute } from '@src/utils/redirect';
@@ -30,7 +30,7 @@ const Layout = async ({
-
+
{club.name}
diff --git a/src/app/manage/[clubId]/create/CreateEventForm.tsx b/src/app/manage/[clubId]/create/CreateEventForm.tsx
index 70168b22..bd09638c 100644
--- a/src/app/manage/[clubId]/create/CreateEventForm.tsx
+++ b/src/app/manage/[clubId]/create/CreateEventForm.tsx
@@ -1,130 +1,199 @@
-'use client'
+'use client';
-import { useEffect, useState } from "react";
-import { type SelectClub } from "@src/server/db/models";
-import { createEventSchema } from "@src/utils/formSchemas";
-import { useForm } from "react-hook-form";
-import { api } from "@src/trpc/react";
-import { type z } from "zod";
-import { zodResolver } from "@hookform/resolvers/zod";
-import { useRouter } from "next/navigation";
-import { UploadIcon } from "@src/icons/Icons";
-import EventCardPreview from "./EventCardPreview";
-import TimeSelect from "./TimeSelect";
-import { type RouterOutputs } from "@src/trpc/shared";
+import { useEffect, useState } from 'react';
+import { type SelectClub } from '@src/server/db/models';
+import { createEventSchema } from '@src/utils/formSchemas';
+import { useForm } from 'react-hook-form';
+import { api } from '@src/trpc/react';
+import { type z } from 'zod';
+import { zodResolver } from '@hookform/resolvers/zod';
+import { useRouter } from 'next/navigation';
+import { UploadIcon } from '@src/icons/Icons';
+import EventCardPreview from './EventCardPreview';
+import TimeSelect from './TimeSelect';
+import { type RouterOutputs } from '@src/trpc/shared';
-const CreateEventForm = ({ clubId, officerClubs }: { clubId: string, officerClubs: SelectClub[]}) => {
- const {
- register,
- handleSubmit,
- watch,
- setValue,
- getValues,
- } = useForm
>({
- resolver: zodResolver(createEventSchema),
- defaultValues: {
- clubId: clubId,
- },
- mode: "onSubmit",
- });
- const router = useRouter();
- const [watchDescription, watchStartTime] = watch(['description', 'startTime']);
- const [eventPreview, setEventPreview] = useState({
- name: "",
- clubId,
- description: "",
- location: "",
- liked: false,
- id: "",
- startTime: new Date(Date.now()),
- endTime: new Date(Date.now()),
- club: officerClubs.filter((v) => v.id == clubId)[0]!,
- });
- useEffect(() => {
- const subscription = watch((data, info) => {
- const { name, clubId, description, location, startTime, endTime } = data;
- const club = officerClubs.find((val) => val.id == data.clubId);
- if (club) {
- setEventPreview({
- name: name || "",
- clubId: clubId || "",
- description: description || "",
- location: location || "",
- liked: false,
- id: "",
- startTime: startTime?.toString() === "" || startTime == undefined ? new Date(Date.now()) : new Date(startTime),
- endTime: endTime?.toString() === "" || endTime?.toString() == "Invalid Date" || !endTime ? new Date(Date.now()) : new Date(endTime),
- club,
- });
- }
- if (info.name == "clubId") {
- router.replace(`/manage/${data.clubId}/create`);
- }
- });
- return () => subscription.unsubscribe();
- }, [router, watch, officerClubs]);
+const CreateEventForm = ({
+ clubId,
+ officerClubs,
+}: {
+ clubId: string;
+ officerClubs: SelectClub[];
+}) => {
+ const { register, handleSubmit, watch, setValue, getValues, control } =
+ useForm>({
+ resolver: zodResolver(createEventSchema),
+ defaultValues: {
+ clubId: clubId,
+ },
+ mode: 'onSubmit',
+ });
+ const router = useRouter();
+ const [watchDescription, watchStartTime] = watch([
+ 'description',
+ 'startTime',
+ ]);
+ const [loading, setLoading] = useState(false);
+ const [eventPreview, setEventPreview] = useState<
+ RouterOutputs['event']['findByFilters']['events'][number]
+ >({
+ name: '',
+ clubId,
+ description: '',
+ location: '',
+ liked: false,
+ id: '',
+ startTime: new Date(Date.now()),
+ endTime: new Date(Date.now()),
+ club: officerClubs.filter((v) => v.id == clubId)[0]!,
+ });
+ useEffect(() => {
+ const subscription = watch((data, info) => {
+ const { name, clubId, description, location, startTime, endTime } = data;
+ const club = officerClubs.find((val) => val.id == data.clubId);
+ if (club) {
+ setEventPreview({
+ name: name || '',
+ clubId: clubId || '',
+ description: description || '',
+ location: location || '',
+ liked: false,
+ id: '',
+ startTime:
+ startTime?.toString() === '' || startTime === undefined
+ ? new Date(Date.now())
+ : new Date(startTime),
+ endTime:
+ endTime?.toString() === '' ||
+ endTime?.toString() === 'Invalid Date' ||
+ !endTime
+ ? new Date(Date.now())
+ : new Date(endTime),
+ club,
+ });
+ }
+ if (info.name == 'clubId') {
+ router.replace(`/manage/${data.clubId}/create`);
+ }
+ });
+ return () => subscription.unsubscribe();
+ }, [router, watch, officerClubs]);
- const createMutation = api.event.create.useMutation({
- onSuccess: () => { location.reload(); }
- })
+ const createMutation = api.event.create.useMutation({
+ onSuccess: (data) => {
+ if (data) {
+ router.push(`/event/${data}`);
+ }
+ },
+ onError: () => {
+ setLoading(false);
+ },
+ });
- const onSubmit = handleSubmit((data: z.infer) => {
- if (!createMutation.isPending) {
- createMutation.mutate(data);
- }
- });
+ const onSubmit = handleSubmit((data: z.infer) => {
+ if (!createMutation.isPending && !loading) {
+ setLoading(true);
+ createMutation.mutate(data);
+ }
+ });
- return ()
-}
-export default CreateEventForm;
\ No newline at end of file
+ return (
+
+ );
+};
+export default CreateEventForm;
diff --git a/src/app/manage/[clubId]/create/EventCardPreview.tsx b/src/app/manage/[clubId]/create/EventCardPreview.tsx
index df3f462b..4e9fa614 100644
--- a/src/app/manage/[clubId]/create/EventCardPreview.tsx
+++ b/src/app/manage/[clubId]/create/EventCardPreview.tsx
@@ -1,64 +1,60 @@
-import EventTimeAlert from "@src/components/events/EventTimeAlert";
-import { MoreIcon, PlusIcon } from "@src/icons/Icons";
-import type { RouterOutputs } from "@src/trpc/shared"
+import EventTimeAlert from '@src/components/events/EventTimeAlert';
+import { MoreIcon, PlusIcon } from '@src/icons/Icons';
+import type { RouterOutputs } from '@src/trpc/shared';
import { format, isSameDay } from 'date-fns';
import Image from 'next/image';
interface Props {
- event: RouterOutputs['event']['findByFilters']['events'][number],
+ event: RouterOutputs['event']['findByFilters']['events'][number];
}
const EventCardPreview = ({ event }: Props) => {
- return (
-
-
-
-
-
{event.name}
-
-
- {event.club.name}
-
-
-
- {format(event.startTime, 'E, MMM d, p')}
- {isSameDay(event.startTime, event.endTime) ? (
- <> - {format(event.endTime, 'p')}>
- ) : (
- <>
- {' '}
- -
- {format(event.endTime, 'E, MMM d, p')}
- >
- )}
-
-
-
-
-
-
-
- );
-}
-export default EventCardPreview
\ No newline at end of file
+ return (
+
+
+
+
+
{event.name}
+
+
{event.club.name}
+
+
+ {format(event.startTime, 'E, MMM d, p')}
+ {isSameDay(event.startTime, event.endTime) ? (
+ <> - {format(event.endTime, 'p')}>
+ ) : (
+ <>
+ {' '}
+ -
+ {format(event.endTime, 'E, MMM d, p')}
+ >
+ )}
+
+
+
+
+
+
+
+ );
+};
+export default EventCardPreview;
diff --git a/src/app/manage/[clubId]/create/TimeSelect.tsx b/src/app/manage/[clubId]/create/TimeSelect.tsx
index 05ea7d24..4aeb93c7 100644
--- a/src/app/manage/[clubId]/create/TimeSelect.tsx
+++ b/src/app/manage/[clubId]/create/TimeSelect.tsx
@@ -1,85 +1,117 @@
-'use client'
-import { useEffect, useState } from "react";
-import type {
- UseFormRegister,
- UseFormSetValue,
- UseFormGetValues,
-} from "react-hook-form";
-import type { createEventSchema } from "@src/utils/formSchemas";
-import type { z } from "zod";
+'use client';
+import type {
+ UseFormSetValue,
+ UseFormGetValues,
+ Control,
+} from 'react-hook-form';
+import { Controller } from 'react-hook-form';
+import type { createEventSchema } from '@src/utils/formSchemas';
+import type { z } from 'zod';
interface Props {
- register: UseFormRegister>,
- setValue: UseFormSetValue>,
- getValues: UseFormGetValues>,
- watchStartTime: Date,
+ setValue: UseFormSetValue>;
+ getValues: UseFormGetValues>;
+ watchStartTime: Date;
+ control: Control>;
}
-const TimeSelect = ({ register, setValue, getValues, watchStartTime }: Props) => {
- const [multiDay, setMultiDay] = useState(false);
- const [numHours, setNumHours] = useState(2);
-
- useEffect(() => {
- // If not multi-day, set end time to start time + numHours
- if (!multiDay && watchStartTime !== undefined) {
- const date = new Date(watchStartTime);
- date.setHours(date.getHours() + numHours);
- setValue("endTime", date);
- }
-
- // If start time is after end time, set end time to start time
- if (new Date(watchStartTime) > new Date(getValues('endTime'))) {
- setValue('endTime', watchStartTime);
- }
- }, [setValue, getValues, watchStartTime, multiDay, numHours])
-
- return (<>
-
-
-
Multi-Day Event
-
Does the event last longer than one day?
-
-
-
-
{
- // If switching to multiDay, clear endTime
- if (!multiDay) {
- setValue('endTime', new Date(NaN));
- }
- setMultiDay(!multiDay);
- }} >
-
{multiDay ? "Yes" : "No"}
-
-
-
-
-
-
Duration
-
-
-
- { multiDay ?
-
-
- { if (new Date(e.currentTarget.value) < new Date(watchStartTime)) setValue('endTime', watchStartTime); }}
- min={watchStartTime?.toString()}
- className="outline-none w-full block p-2 text-xs rounded-md text-[#7D8FB3]"
- />
-
- :
-
-
-
-
- }
-
- >);
-}
-export default TimeSelect;
\ No newline at end of file
+const TimeSelect = ({
+ setValue,
+ getValues,
+ watchStartTime,
+ control,
+}: Props) => {
+ return (
+ <>
+
+ >
+ );
+};
+export default TimeSelect;
diff --git a/src/app/manage/[clubId]/create/page.tsx b/src/app/manage/[clubId]/create/page.tsx
index 95765a0e..fe239b4d 100644
--- a/src/app/manage/[clubId]/create/page.tsx
+++ b/src/app/manage/[clubId]/create/page.tsx
@@ -1,30 +1,31 @@
-import Header from "@src/components/BaseHeader";
-import { getServerAuthSession } from "@src/server/auth";
-import { api } from "@src/trpc/server";
-import { signInRoute } from "@src/utils/redirect";
-import { redirect, notFound } from "next/navigation";
-import CreateEventForm from "./CreateEventForm";
+import Header from '@src/components/header/BaseHeader';
+import { getServerAuthSession } from '@src/server/auth';
+import { api } from '@src/trpc/server';
+import { signInRoute } from '@src/utils/redirect';
+import { redirect, notFound } from 'next/navigation';
+import CreateEventForm from './CreateEventForm';
const Page = async ({ params }: { params: { clubId: string } }) => {
- const session = await getServerAuthSession();
- if (!session) {
- redirect(signInRoute(`manage/${params.clubId}/create`));
- }
+ const session = await getServerAuthSession();
+ if (!session) {
+ redirect(signInRoute(`manage/${params.clubId}/create`));
+ }
- const officerClubs = await api.club.getOfficerClubs();
- const currentClub = officerClubs.filter(val => {
- return val.id == params.clubId
- })[0];
- if (!currentClub) {
- notFound();
- }
+ const officerClubs = await api.club.getOfficerClubs();
+ const currentClub = officerClubs.filter((val) => {
+ return val.id == params.clubId;
+ })[0];
+ if (!currentClub) {
+ notFound();
+ }
- return (
-
-
-
-
-
- )
-}
-export default Page;
\ No newline at end of file
+ return (
+
+
+
+
+
+
+ );
+};
+export default Page;
diff --git a/src/app/manage/[clubId]/edit/EditContactForm.tsx b/src/app/manage/[clubId]/edit/EditContactForm.tsx
index 87a7dade..1b8df4f4 100644
--- a/src/app/manage/[clubId]/edit/EditContactForm.tsx
+++ b/src/app/manage/[clubId]/edit/EditContactForm.tsx
@@ -1,7 +1,7 @@
/* eslint-disable @typescript-eslint/no-misused-promises */
'use client';
import { zodResolver } from '@hookform/resolvers/zod';
-import EditContactSelector from '@src/components/EditContactSelector';
+import EditContactSelector from '@src/app/manage/[clubId]/edit/EditContactSelector';
import { type SelectClub, type SelectContact } from '@src/server/db/models';
import { api } from '@src/trpc/react';
import { editClubContactSchema } from '@src/utils/formSchemas';
diff --git a/src/components/EditContactSelector.tsx b/src/app/manage/[clubId]/edit/EditContactSelector.tsx
similarity index 99%
rename from src/components/EditContactSelector.tsx
rename to src/app/manage/[clubId]/edit/EditContactSelector.tsx
index 70583365..3e03c38b 100644
--- a/src/components/EditContactSelector.tsx
+++ b/src/app/manage/[clubId]/edit/EditContactSelector.tsx
@@ -23,7 +23,7 @@ import {
Website,
Youtube,
type logoProps,
-} from './ContactIcons';
+} from '@src/icons/ContactIcons';
import { type modifyDeletedAction } from '@src/app/manage/[clubId]/edit/EditContactForm';
import { type editClubContactSchema } from '@src/utils/formSchemas';
diff --git a/src/app/manage/[clubId]/edit/officers/EditOfficerForm.tsx b/src/app/manage/[clubId]/edit/officers/EditOfficerForm.tsx
index bf18ee28..f0f027d7 100644
--- a/src/app/manage/[clubId]/edit/officers/EditOfficerForm.tsx
+++ b/src/app/manage/[clubId]/edit/officers/EditOfficerForm.tsx
@@ -1,7 +1,7 @@
/* eslint-disable @typescript-eslint/no-misused-promises */
'use client';
import { zodResolver } from '@hookform/resolvers/zod';
-import { UserSearchBar } from '@src/components/SearchBar';
+import { UserSearchBar } from '@src/components/searchBar/UserSearchBar';
import { api } from '@src/trpc/react';
import { editOfficerSchema } from '@src/utils/formSchemas';
import { useRouter } from 'next/navigation';
diff --git a/src/app/manage/[clubId]/edit/officers/page.tsx b/src/app/manage/[clubId]/edit/officers/page.tsx
index 42718ded..df7955dd 100644
--- a/src/app/manage/[clubId]/edit/officers/page.tsx
+++ b/src/app/manage/[clubId]/edit/officers/page.tsx
@@ -1,5 +1,5 @@
-import Header from '@src/components/BaseHeader';
-import BackButton from '@src/components/BlueBackButton';
+import Header from '@src/components/header/BaseHeader';
+import { BlueBackButton } from '@src/components/backButton';
import EditOfficerForm from './EditOfficerForm';
import { api } from '@src/trpc/server';
import { getServerAuthSession } from '@src/server/auth';
@@ -28,7 +28,7 @@ export default async function Page({
-
+
Edit club officers
diff --git a/src/app/manage/[clubId]/edit/page.tsx b/src/app/manage/[clubId]/edit/page.tsx
index e52b7619..7ee9f734 100644
--- a/src/app/manage/[clubId]/edit/page.tsx
+++ b/src/app/manage/[clubId]/edit/page.tsx
@@ -1,9 +1,9 @@
import { api } from '@src/trpc/server';
import EditClubForm from './EditClubForm';
-import Header from '@src/components/BaseHeader';
+import Header from '@src/components/header/BaseHeader';
import { notFound } from 'next/navigation';
import EditContactForm from './EditContactForm';
-import BackButton from '@src/components/BlueBackButton';
+import { BlueBackButton } from '@src/components/backButton';
export default async function Page({
params: { clubId },
@@ -17,7 +17,7 @@ export default async function Page({
-
+
diff --git a/src/app/manage/page.tsx b/src/app/manage/page.tsx
index d0e33298..a52474d1 100644
--- a/src/app/manage/page.tsx
+++ b/src/app/manage/page.tsx
@@ -1,4 +1,4 @@
-import Header from '@src/components/BaseHeader';
+import Header from '@src/components/header/BaseHeader';
import { getServerAuthSession } from '@src/server/auth';
import { api } from '@src/trpc/server';
import ClubCard from './ClubCard';
diff --git a/src/app/page.tsx b/src/app/page.tsx
index 34978715..97531516 100644
--- a/src/app/page.tsx
+++ b/src/app/page.tsx
@@ -1,7 +1,7 @@
-import Header from '../components/BaseHeader';
-import Carousel from '../components/Carousel';
-import TagFilter from '../components/TagFilter';
-import OrgDirectoryGrid from '../components/OrgDirectoryGrid';
+import Header from '../components/header/BaseHeader';
+import Carousel from '../components/club/directory/Carousel';
+import TagFilter from '../components/club/directory/TagFilter';
+import ClubDirectoryGrid from '../components/club/directory/ClubDirectoryGrid';
import type { Metadata } from 'next';
import { api } from '@src/trpc/server';
@@ -33,7 +33,7 @@ const Home = async (props: Params) => {
-
+
);
diff --git a/src/app/settings/page.tsx b/src/app/settings/page.tsx
index 17ea96ba..b7e1eade 100644
--- a/src/app/settings/page.tsx
+++ b/src/app/settings/page.tsx
@@ -2,7 +2,7 @@ import { getServerAuthSession } from '@src/server/auth';
import SettingsForm from '@src/components/settings/SettingsForm';
import { type Metadata } from 'next';
import { redirect } from 'next/navigation';
-import Header from '@src/components/BaseHeader';
+import Header from '@src/components/header/BaseHeader';
import { signInRoute } from '@src/utils/redirect';
export const metadata: Metadata = {
title: 'Settings - Jupiter',
diff --git a/src/components/BlueBackButton.tsx b/src/components/BlueBackButton.tsx
deleted file mode 100644
index c44be100..00000000
--- a/src/components/BlueBackButton.tsx
+++ /dev/null
@@ -1,20 +0,0 @@
-'use client';
-
-import { useRouter } from 'next/navigation';
-import { LeftArrowIcon } from '../icons/Icons';
-
-const BackButton = () => {
- const router = useRouter();
- return (
-
-
-
- );
-};
-export default BackButton;
diff --git a/src/components/NotFound.tsx b/src/components/NotFound.tsx
index 61041e98..4e93365f 100644
--- a/src/components/NotFound.tsx
+++ b/src/components/NotFound.tsx
@@ -1,4 +1,4 @@
-import Header from '@src/components/BaseHeader';
+import Header from '@src/components/header/BaseHeader';
import React from 'react';
import { type FC } from 'react';
diff --git a/src/components/SearchBar.tsx b/src/components/SearchBar.tsx
deleted file mode 100644
index fb219eb2..00000000
--- a/src/components/SearchBar.tsx
+++ /dev/null
@@ -1,198 +0,0 @@
-'use client';
-import {
- type Dispatch,
- type SetStateAction,
- useState,
- type ChangeEvent,
- useEffect,
-} from 'react';
-import { SearchIcon } from '../icons/Icons';
-import { useRouter } from 'next/navigation';
-import type {
- SelectClub as Club,
- SelectUserMetadata,
-} from '@src/server/db/models';
-import { api } from '@src/trpc/react';
-import type { SelectEvent as Event } from '@src/server/db/models';
-
-type SearchElement = {
- id: string;
- name: string;
-};
-type SearchBarProps = {
- placeholder: string;
- value?: string;
- setSearch: Dispatch>;
- searchResults?: Array;
- onClick?: (input: T) => void;
-};
-
-export const SearchBar = ({
- placeholder,
- value,
- setSearch,
- searchResults,
- onClick,
-}: SearchBarProps) => {
- const [input, setInput] = useState(value ?? '');
- const [focused, setFocused] = useState(false);
- const handleSearch = (e: ChangeEvent) => {
- setInput(e.target.value);
- };
- useEffect(() => {
- const handler = setTimeout(() => {
- setSearch(input);
- }, 300);
- return () => {
- clearTimeout(handler);
- };
- }, [input, setSearch]);
-
- return (
-
-
-
-
-
-
setFocused(true)}
- onBlur={() => setTimeout(() => setFocused(false), 300)}
- />
- {input && focused && searchResults && searchResults.length > 0 && (
-
- {searchResults.map((item) => (
-
- ))}
-
- )}
-
-
- );
-};
-
-export const ClubSearchBar = () => {
- const router = useRouter();
- const [search, setSearch] = useState('');
- const { data } = api.club.byName.useQuery(
- { name: search },
- { enabled: !!search },
- );
- const onClickSearchResult = (club: Club) => {
- router.push(`/directory/${club.id}`);
- };
- return (
-
- );
-};
-export const EventSearchBar = () => {
- const router = useRouter();
- const [search, setSearch] = useState('');
- const [res, setRes] = useState([]);
-
- const eventQuery = api.event.byName.useQuery(
- {
- name: search,
- sortByDate: true,
- },
- { enabled: !!search },
- );
- useEffect(() => {
- if (eventQuery.data) setRes(eventQuery.data);
- }, [eventQuery.data]);
-
- return (
- {
- router.push(`/event/${event.id}`);
- }}
- />
- );
-};
-type EventClubSearchBarProps = {
- addClub: (value: string) => void;
-};
-export const EventClubSearchBar = ({ addClub }: EventClubSearchBarProps) => {
- const [search, setSearch] = useState('');
- const [res, setRes] = useState([]);
- const utils = api.useUtils();
- const clubQuery = api.club.byName.useQuery(
- { name: search },
- {
- enabled: !!search,
- },
- );
- useEffect(() => {
- if (clubQuery.data) {
- setRes(clubQuery.data);
- }
- }, [clubQuery.data]);
- return (
- {
- void utils.club.byId.prefetch({ id: club.id });
- addClub(club.id);
- setSearch('');
- }}
- />
- );
-};
-type UserSearchBarProps = {
- passUser: (user: { id: string; name: string }) => void;
-};
-type User = {
- name: string;
-} & SelectUserMetadata;
-export const UserSearchBar = ({ passUser }: UserSearchBarProps) => {
- const [search, setSearch] = useState('');
- const [res, setRes] = useState([]);
- const userQuery = api.userMetadata.searchByName.useQuery(
- { name: search },
- {
- enabled: !!search,
- },
- );
- useEffect(() => {
- if (userQuery.data) {
- const newData = userQuery.data.map((val) => {
- return { name: val.firstName + ' ' + val.lastName, ...val };
- });
- setRes(newData);
- }
- }, [userQuery.data]);
- return (
- {
- passUser({ id: user.id, name: user.name });
- setSearch('');
- }}
- />
- );
-};
diff --git a/src/components/admin/AddOrg.tsx b/src/components/admin/AddClub.tsx
similarity index 72%
rename from src/components/admin/AddOrg.tsx
rename to src/components/admin/AddClub.tsx
index 80429406..c287c40e 100644
--- a/src/components/admin/AddOrg.tsx
+++ b/src/components/admin/AddClub.tsx
@@ -2,26 +2,26 @@
import { useState } from 'react';
import { DayPicker, type DateRange } from 'react-day-picker';
-import OrgSearch from './OrgSearch';
+import ClubSearch from './ClubSearch';
import 'react-day-picker/dist/style.css';
import { api } from '@src/trpc/react';
import { useRouter } from 'next/navigation';
-type AddOrg = {
+type AddClub = {
range: DateRange;
orgId: string | null;
name: string | null;
};
-export default function AddOrg() {
- const [addOrg, setAddOrg] = useState({
+export default function AddClub() {
+ const [addClub, setAddClub] = useState({
range: { from: undefined, to: undefined },
orgId: null,
name: null,
});
const router = useRouter();
const utils = api.useContext();
- const { mutate } = api.admin.addOrgCarousel.useMutation({
+ const { mutate } = api.admin.addClubCarousel.useMutation({
onSuccess: async () => {
await utils.admin.upcomingCarousels.invalidate();
await utils.club.getCarousel.invalidate();
@@ -32,21 +32,21 @@ export default function AddOrg() {
});
function onClick() {
- if (!addOrg.orgId || !addOrg.range.from || !addOrg.range.to) return;
+ if (!addClub.orgId || !addClub.range.from || !addClub.range.to) return;
mutate({
- orgId: addOrg.orgId,
- range: addOrg.range,
+ orgId: addClub.orgId,
+ range: addClub.range,
});
}
- function setOrg({ id, name }: { id: string; name: string }) {
- setAddOrg({ ...addOrg, orgId: id, name });
+ function setClub({ id, name }: { id: string; name: string }) {
+ setAddClub({ ...addClub, orgId: id, name });
}
function setRange(range: DateRange | undefined) {
- setAddOrg({
- ...addOrg,
+ setAddClub({
+ ...addClub,
range: {
from: range?.from ? range.from : undefined,
to: range?.to ? range.to : undefined,
@@ -58,18 +58,18 @@ export default function AddOrg() {
-
- {addOrg.name && (
+
+ {addClub.name && (
- Adding {addOrg.name}
+ Adding {addClub.name}
)}
- {addOrg.range.from && addOrg.range.to && (
+ {addClub.range.from && addClub.range.to && (
From:
- {addOrg.range.from.toLocaleDateString(undefined, {
+ {addClub.range.from.toLocaleDateString(undefined, {
dateStyle: 'long',
})}
@@ -77,7 +77,7 @@ export default function AddOrg() {
To:
- {addOrg.range.to.toLocaleDateString(undefined, {
+ {addClub.range.to.toLocaleDateString(undefined, {
dateStyle: 'long',
})}
@@ -87,7 +87,7 @@ export default function AddOrg() {
- Add Org
+ Add Club
);
diff --git a/src/components/admin/AddOfficer.tsx b/src/components/admin/AddOfficer.tsx
index f4125260..3545811f 100644
--- a/src/components/admin/AddOfficer.tsx
+++ b/src/components/admin/AddOfficer.tsx
@@ -1,7 +1,7 @@
'use client';
import { api } from '@src/trpc/react';
-import { UserSearchBar } from '../SearchBar';
+import { UserSearchBar } from '../searchBar/UserSearchBar';
import { useRouter } from 'next/navigation';
import { useState } from 'react';
diff --git a/src/components/admin/ApprovedClub.tsx b/src/components/admin/ApprovedClub.tsx
new file mode 100644
index 00000000..b9a99aca
--- /dev/null
+++ b/src/components/admin/ApprovedClub.tsx
@@ -0,0 +1,23 @@
+import { type SelectClub } from '@src/server/db/models';
+import AddOfficer from './AddOfficer';
+import OfficerTable from './OfficerTable';
+import ClubDescription from './ClubDescription';
+import { api } from '@src/trpc/server';
+import ChangeClubStatus from './ChangeClubStatus';
+
+type Props = { club: SelectClub };
+export default async function AcceptedClub({ club: club }: Props) {
+ const officers = await api.club.getOfficers({ id: club.id });
+
+ return (
+ <>
+
Officers
+
+
+
+ >
+ );
+}
diff --git a/src/components/admin/ApprovedOrg.tsx b/src/components/admin/ApprovedOrg.tsx
deleted file mode 100644
index e4592d52..00000000
--- a/src/components/admin/ApprovedOrg.tsx
+++ /dev/null
@@ -1,23 +0,0 @@
-import { type SelectClub } from '@src/server/db/models';
-import AddOfficer from './AddOfficer';
-import OfficerTable from './OfficerTable';
-import OrgDescription from './OrgDescription';
-import { api } from '@src/trpc/server';
-import ChangeOrgStatus from './ChangeOrgStatus';
-
-type Props = { org: SelectClub };
-export default async function AcceptedOrg({ org }: Props) {
- const officers = await api.club.getOfficers({ id: org.id });
-
- return (
- <>
-
Officers
-
-
-
- >
- );
-}
diff --git a/src/components/admin/CarouselCards.tsx b/src/components/admin/CarouselCards.tsx
index af851e05..061b34a3 100644
--- a/src/components/admin/CarouselCards.tsx
+++ b/src/components/admin/CarouselCards.tsx
@@ -11,7 +11,7 @@ type Props = {
export default function CarouselCard({ item }: Props) {
const router = useRouter();
- const { mutate } = api.admin.removeOrgCarousel.useMutation({
+ const { mutate } = api.admin.removeClubCarousel.useMutation({
onSuccess: () => router.refresh(),
});
return (
diff --git a/src/components/admin/ChangeOrgStatus.tsx b/src/components/admin/ChangeClubStatus.tsx
similarity index 78%
rename from src/components/admin/ChangeOrgStatus.tsx
rename to src/components/admin/ChangeClubStatus.tsx
index 878e6cda..f79ee174 100644
--- a/src/components/admin/ChangeOrgStatus.tsx
+++ b/src/components/admin/ChangeClubStatus.tsx
@@ -4,27 +4,27 @@ import { api } from '@src/trpc/react';
import { useRouter } from 'next/navigation';
import { useState } from 'react';
-type Props = { status: 'approved' | 'pending' | 'rejected'; orgId: string };
+type Props = { status: 'approved' | 'pending' | 'rejected'; clubId: string };
-export default function ChangeOrgStatus({ status: initial, orgId }: Props) {
+export default function ChangeClubStatus({ status: initial, clubId }: Props) {
const router = useRouter();
const [status, setStatus] = useState
(initial);
- const { mutate } = api.admin.changeOrgStatus.useMutation({
+ const { mutate } = api.admin.changeClubStatus.useMutation({
onSuccess: () => router.refresh(),
});
function onChange(e: React.ChangeEvent) {
switch (e.target.value) {
case 'approved':
- mutate({ orgId, status: 'approved' });
+ mutate({ clubId: clubId, status: 'approved' });
setStatus('approved');
break;
case 'pending':
- mutate({ orgId, status: 'pending' });
+ mutate({ clubId: clubId, status: 'pending' });
setStatus('pending');
break;
case 'rejected':
- mutate({ orgId, status: 'rejected' });
+ mutate({ clubId: clubId, status: 'rejected' });
setStatus('rejected');
break;
}
diff --git a/src/components/admin/OrgDescription.tsx b/src/components/admin/ClubDescription.tsx
similarity index 96%
rename from src/components/admin/OrgDescription.tsx
rename to src/components/admin/ClubDescription.tsx
index b9b7900b..aec25d82 100644
--- a/src/components/admin/OrgDescription.tsx
+++ b/src/components/admin/ClubDescription.tsx
@@ -6,7 +6,7 @@ import { type SelectClub } from '@src/server/db/models';
type Props = {
club: SelectClub;
};
-export default function OrgDescription({ club }: Props) {
+export default function ClubDescription({ club }: Props) {
return (
diff --git a/src/components/admin/OrgSearch.tsx b/src/components/admin/ClubSearch.tsx
similarity index 67%
rename from src/components/admin/OrgSearch.tsx
rename to src/components/admin/ClubSearch.tsx
index 505a710f..0c14d02d 100644
--- a/src/components/admin/OrgSearch.tsx
+++ b/src/components/admin/ClubSearch.tsx
@@ -2,14 +2,14 @@
import { api } from '@src/trpc/react';
import { useState } from 'react';
-import { SearchBar } from '../SearchBar';
+import { DebouncedSearchBar } from '../searchBar/DebouncedSearchBar';
import { type SelectClub } from '@src/server/db/models';
type Props = {
- setOrg: ({ id, name }: { id: string; name: string }) => void;
+ setClub: ({ id, name }: { id: string; name: string }) => void;
};
-export default function OrgSearch({ setOrg }: Props) {
+export default function ClubSearch({ setClub }: Props) {
const [search, setSearch] = useState('');
const { data } = api.club.byName.useQuery(
{ name: search },
@@ -17,11 +17,11 @@ export default function OrgSearch({ setOrg }: Props) {
);
const onClickSearchResult = (club: SelectClub) => {
- setOrg({ id: club.id, name: club.name });
+ setClub({ id: club.id, name: club.name });
setSearch('');
};
return (
- (null);
const [columnFilters, setColumnFilters] = useState([]);
- const { mutate } = api.admin.deleteOrg.useMutation({
+ const { mutate } = api.admin.deleteClub.useMutation({
onSuccess: () => router.refresh(),
});
diff --git a/src/components/admin/OtherOrgStatus.tsx b/src/components/admin/OtherClubStatus.tsx
similarity index 78%
rename from src/components/admin/OtherOrgStatus.tsx
rename to src/components/admin/OtherClubStatus.tsx
index f62c8e5f..cc4ecd59 100644
--- a/src/components/admin/OtherOrgStatus.tsx
+++ b/src/components/admin/OtherClubStatus.tsx
@@ -1,14 +1,14 @@
import { db } from '@src/server/db';
import { type SelectClub } from '@src/server/db/models';
import { and, eq } from 'drizzle-orm';
-import ChangeOrgStatus from './ChangeOrgStatus';
+import ChangeClubStatus from './ChangeClubStatus';
-type Props = { org: SelectClub };
+type Props = { club: SelectClub };
-export default async function PendingOrg({ org }: Props) {
+export default async function PendingClub({ club }: Props) {
const president = await db.query.userMetadataToClubs.findFirst({
where: (umtc) =>
- and(eq(umtc.clubId, org.id), eq(umtc.memberType, 'President')),
+ and(eq(umtc.clubId, club.id), eq(umtc.memberType, 'President')),
with: { userMetadata: true },
});
@@ -18,7 +18,7 @@ export default async function PendingOrg({ org }: Props) {
return (
- {org.description.split('\n').map((line, i) => (
+ {club.description.split('\n').map((line, i) => (
{line}
@@ -26,7 +26,7 @@ export default async function PendingOrg({ org }: Props) {
Tags:
- {org.tags.map((tag) => (
+ {club.tags.map((tag) => (
-
+
);
}
diff --git a/src/components/backButton.tsx b/src/components/backButton.tsx
index ff2c044c..483ea7ac 100644
--- a/src/components/backButton.tsx
+++ b/src/components/backButton.tsx
@@ -1,6 +1,7 @@
'use client';
import { useRouter } from 'next/navigation';
+import { LeftArrowIcon } from '../icons/Icons';
const BackButton = () => {
const router = useRouter();
@@ -29,4 +30,19 @@ const BackButton = () => {
);
};
+export const BlueBackButton = () => {
+ const router = useRouter();
+ return (
+
+
+
+ );
+};
+
export default BackButton;
diff --git a/src/components/DirectoryOrgs.tsx b/src/components/club/ClubCard.tsx
similarity index 93%
rename from src/components/DirectoryOrgs.tsx
rename to src/components/club/ClubCard.tsx
index 882b0410..3fa4755f 100644
--- a/src/components/DirectoryOrgs.tsx
+++ b/src/components/club/ClubCard.tsx
@@ -7,7 +7,7 @@ import { type Session } from 'next-auth';
type Props = { club: Club; session: Session | null; priority: boolean };
-const OrgDirectoryCards: FC
= ({ club, session, priority }) => {
+const ClubCard: FC = ({ club, session, priority }) => {
const desc =
club.description.length > 50
? club.description.slice(0, 150) + '...'
@@ -45,7 +45,7 @@ const OrgDirectoryCards: FC = ({ club, session, priority }) => {
);
};
-export const OrgDirectoryCardSkeleton: FC = () => {
+export const ClubCardSkeleton: FC = () => {
return (
@@ -59,4 +59,4 @@ export const OrgDirectoryCardSkeleton: FC = () => {
);
};
-export default OrgDirectoryCards;
+export default ClubCard;
diff --git a/src/components/JoinButton.tsx b/src/components/club/JoinButton.tsx
similarity index 100%
rename from src/components/JoinButton.tsx
rename to src/components/club/JoinButton.tsx
diff --git a/src/components/Carousel.tsx b/src/components/club/directory/Carousel.tsx
similarity index 98%
rename from src/components/Carousel.tsx
rename to src/components/club/directory/Carousel.tsx
index 71e9c429..74a04aff 100644
--- a/src/components/Carousel.tsx
+++ b/src/components/club/directory/Carousel.tsx
@@ -1,7 +1,7 @@
'use client';
import Image from 'next/image';
import { useState, type TouchEventHandler } from 'react';
-import { LeftArrowIcon, RightArrowIcon } from '../icons/Icons';
+import { LeftArrowIcon, RightArrowIcon } from '@src/icons/Icons';
import Link from 'next/link';
import { type SelectClub } from '@src/server/db/models';
diff --git a/src/components/OrgDirectoryGrid.tsx b/src/components/club/directory/ClubDirectoryGrid.tsx
similarity index 75%
rename from src/components/OrgDirectoryGrid.tsx
rename to src/components/club/directory/ClubDirectoryGrid.tsx
index c3be3c13..8c6a99ab 100644
--- a/src/components/OrgDirectoryGrid.tsx
+++ b/src/components/club/directory/ClubDirectoryGrid.tsx
@@ -1,5 +1,5 @@
import { type FC } from 'react';
-import DirectoryOrgs from './DirectoryOrgs';
+import ClubCard from '../ClubCard';
import { api } from '@src/trpc/server';
import { getServerAuthSession } from '@src/server/auth';
import InfiniteScrollGrid from './InfiniteScrollGrid';
@@ -9,14 +9,14 @@ interface Props {
tag?: string;
}
-const OrgDirectoryGrid: FC
= async ({ tag }) => {
+const ClubDirectoryGrid: FC = async ({ tag }) => {
const { clubs } = await api.club.all({ tag, limit: 9 });
const session = await getServerAuthSession();
return (
{clubs.map((club) => (
-
+
))}
{clubs.length === 9 &&
}
@@ -24,4 +24,4 @@ const OrgDirectoryGrid: FC
= async ({ tag }) => {
);
};
-export default OrgDirectoryGrid;
+export default ClubDirectoryGrid;
diff --git a/src/components/InfiniteScrollGrid.tsx b/src/components/club/directory/InfiniteScrollGrid.tsx
similarity index 75%
rename from src/components/InfiniteScrollGrid.tsx
rename to src/components/club/directory/InfiniteScrollGrid.tsx
index 2a3e6189..259ab9b8 100644
--- a/src/components/InfiniteScrollGrid.tsx
+++ b/src/components/club/directory/InfiniteScrollGrid.tsx
@@ -2,7 +2,7 @@
import { api } from '@src/trpc/react';
import { type Session } from 'next-auth';
import { useEffect, useRef } from 'react';
-import DirectoryOrgs, { OrgDirectoryCardSkeleton } from './DirectoryOrgs';
+import ClubCard, { ClubCardSkeleton } from '../ClubCard';
type Props = {
session: Session | null;
@@ -21,7 +21,7 @@ export default function InfiniteScrollGrid({ session, tag }: Props) {
);
const observer = useRef();
- const lastOrgElementRef = useRef(null);
+ const lastClubElementRef = useRef(null);
useEffect(() => {
if (isLoading || isFetchingNextPage) return;
@@ -35,8 +35,8 @@ export default function InfiniteScrollGrid({ session, tag }: Props) {
}
});
- if (lastOrgElementRef.current) {
- observer.current.observe(lastOrgElementRef.current);
+ if (lastClubElementRef.current) {
+ observer.current.observe(lastClubElementRef.current);
}
return () => {
@@ -54,24 +54,20 @@ export default function InfiniteScrollGrid({ session, tag }: Props) {
clubIndex === page.clubs.length - 1;
return (
-
+
);
}),
)
: Array.from({ length: 4 }, (_, index) => (
-
+
))}
{isFetchingNextPage &&
Array.from({ length: 4 }, (_, index) => (
-
+
))}
>
);
diff --git a/src/components/ScrollTop.tsx b/src/components/club/directory/ScrollTop.tsx
similarity index 100%
rename from src/components/ScrollTop.tsx
rename to src/components/club/directory/ScrollTop.tsx
diff --git a/src/components/TagFilter.tsx b/src/components/club/directory/TagFilter.tsx
similarity index 100%
rename from src/components/TagFilter.tsx
rename to src/components/club/directory/TagFilter.tsx
diff --git a/src/components/OrgHeader.tsx b/src/components/club/listing/ClubHeader.tsx
similarity index 95%
rename from src/components/OrgHeader.tsx
rename to src/components/club/listing/ClubHeader.tsx
index 4b17dcb0..fcbb26dc 100644
--- a/src/components/OrgHeader.tsx
+++ b/src/components/club/listing/ClubHeader.tsx
@@ -4,7 +4,7 @@ import type {
SelectClub,
SelectContact as Contacts,
} from '@src/server/db/models';
-import JoinButton from './JoinButton';
+import JoinButton from '../JoinButton';
import { getServerAuthSession } from '@src/server/auth';
import Link from 'next/link';
import { api } from '@src/trpc/server';
@@ -13,7 +13,7 @@ type Club = SelectClub & {
contacts?: Contacts[];
tags: string[];
};
-const OrgHeader = async ({ club }: { club: Club }) => {
+const ClubHeader = async ({ club }: { club: Club }) => {
const session = await getServerAuthSession();
const memberType = await api.club.memberType({ id: club.id });
return (
@@ -83,4 +83,4 @@ const OrgHeader = async ({ club }: { club: Club }) => {
);
};
-export default OrgHeader;
+export default ClubHeader;
diff --git a/src/components/OrgInfoSegment.tsx b/src/components/club/listing/ClubInfoSegment.tsx
similarity index 98%
rename from src/components/OrgInfoSegment.tsx
rename to src/components/club/listing/ClubInfoSegment.tsx
index 2e2e3b9a..d1fe1fc7 100644
--- a/src/components/OrgInfoSegment.tsx
+++ b/src/components/club/listing/ClubInfoSegment.tsx
@@ -3,7 +3,7 @@ import { type FC } from 'react';
import { type RouterOutputs } from '@src/trpc/shared';
import { api } from '@src/trpc/server';
-const OrgInfoSegment: FC<{
+const ClubInfoSegment: FC<{
club: NonNullable;
}> = async ({ club }) => {
const isActive = await api.club.isActive({ id: club.id });
@@ -87,4 +87,4 @@ const OrgInfoSegment: FC<{
);
};
-export default OrgInfoSegment;
+export default ClubInfoSegment;
diff --git a/src/components/OrgUpcomingEvents.tsx b/src/components/club/listing/ClubUpcomingEvents.tsx
similarity index 93%
rename from src/components/OrgUpcomingEvents.tsx
rename to src/components/club/listing/ClubUpcomingEvents.tsx
index 9232c1a3..7672f8a8 100644
--- a/src/components/OrgUpcomingEvents.tsx
+++ b/src/components/club/listing/ClubUpcomingEvents.tsx
@@ -4,7 +4,7 @@ import { type FC } from 'react';
const MAX_DESCRIPTION_LENGTH = 150;
-const OrgUpcomingEvents: FC<{ clubId: string }> = async ({ clubId }) => {
+const ClubUpcomingEvents: FC<{ clubId: string }> = async ({ clubId }) => {
const cur_time = new Date();
const data = await api.event.byClubId({
@@ -51,4 +51,4 @@ const OrgUpcomingEvents: FC<{ clubId: string }> = async ({ clubId }) => {
);
};
-export default OrgUpcomingEvents;
+export default ClubUpcomingEvents;
diff --git a/src/components/ContactButtons.tsx b/src/components/club/listing/ContactButtons.tsx
similarity index 93%
rename from src/components/ContactButtons.tsx
rename to src/components/club/listing/ContactButtons.tsx
index b961ca01..ea255f59 100644
--- a/src/components/ContactButtons.tsx
+++ b/src/components/club/listing/ContactButtons.tsx
@@ -1,5 +1,5 @@
import type { SelectContact as Contacts } from '@src/server/db/models';
-import { logo } from './ContactIcons';
+import { logo } from '@src/icons/ContactIcons';
import Link from 'next/link';
type contentButtonProps = {
diff --git a/src/components/events/EventCard.tsx b/src/components/events/EventCard.tsx
index 75008289..1eb41bc5 100644
--- a/src/components/events/EventCard.tsx
+++ b/src/components/events/EventCard.tsx
@@ -2,9 +2,9 @@
import { format, isSameDay } from 'date-fns';
import Image from 'next/image';
import Link from 'next/link';
-import { MoreIcon } from '../../icons/Icons';
+import { MoreIcon } from '@src/icons/Icons';
import { type RouterOutputs } from '@src/trpc/shared';
-import EventLikeButton from '../EventLikeButton';
+import EventLikeButton from './EventLikeButton';
import { getServerAuthSession } from '@src/server/auth';
import dynamic from 'next/dynamic';
diff --git a/src/components/EventLikeButton.tsx b/src/components/events/EventLikeButton.tsx
similarity index 94%
rename from src/components/EventLikeButton.tsx
rename to src/components/events/EventLikeButton.tsx
index 59588782..5257e59d 100644
--- a/src/components/EventLikeButton.tsx
+++ b/src/components/events/EventLikeButton.tsx
@@ -1,6 +1,6 @@
'use client';
/* eslint-disable @typescript-eslint/no-misused-promises */
-import { CheckIcon, PlusIcon } from '../icons/Icons';
+import { CheckIcon, PlusIcon } from '@src/icons/Icons';
import { api } from '@src/trpc/react';
import { useRouter } from 'next/navigation';
diff --git a/src/components/BaseHeader.tsx b/src/components/header/BaseHeader.tsx
similarity index 88%
rename from src/components/BaseHeader.tsx
rename to src/components/header/BaseHeader.tsx
index 93d0a874..1a72a5f9 100644
--- a/src/components/BaseHeader.tsx
+++ b/src/components/header/BaseHeader.tsx
@@ -1,9 +1,10 @@
import type { ReactNode } from 'react';
import { ProfileDropDown } from './ProfileDropDown';
import { getServerAuthSession } from '@src/server/auth';
-import { ClubSearchBar, EventSearchBar } from './SearchBar';
+import { ClubSearchBar } from '../searchBar/ClubSearchBar';
+import { EventSearchBar } from '../searchBar/EventSearchBar';
import SignInButton from './signInButton';
-import MobileNav from './MobileNav';
+import MobileNav from '../nav/MobileNav';
import { api } from '@src/trpc/server';
export const BaseHeader = async ({ children }: { children: ReactNode }) => {
diff --git a/src/components/ProfileDropDown.tsx b/src/components/header/ProfileDropDown.tsx
similarity index 100%
rename from src/components/ProfileDropDown.tsx
rename to src/components/header/ProfileDropDown.tsx
diff --git a/src/components/signInButton.tsx b/src/components/header/signInButton.tsx
similarity index 100%
rename from src/components/signInButton.tsx
rename to src/components/header/signInButton.tsx
diff --git a/src/components/MobileNav.tsx b/src/components/nav/MobileNav.tsx
similarity index 100%
rename from src/components/MobileNav.tsx
rename to src/components/nav/MobileNav.tsx
diff --git a/src/components/NavMenu.tsx b/src/components/nav/NavMenu.tsx
similarity index 100%
rename from src/components/NavMenu.tsx
rename to src/components/nav/NavMenu.tsx
diff --git a/src/components/Sidebar.tsx b/src/components/nav/Sidebar.tsx
similarity index 100%
rename from src/components/Sidebar.tsx
rename to src/components/nav/Sidebar.tsx
diff --git a/src/components/SidebarItems.tsx b/src/components/nav/SidebarItems.tsx
similarity index 97%
rename from src/components/SidebarItems.tsx
rename to src/components/nav/SidebarItems.tsx
index 1adaefda..d13c5cdb 100644
--- a/src/components/SidebarItems.tsx
+++ b/src/components/nav/SidebarItems.tsx
@@ -2,7 +2,7 @@
import { type FC, useState } from 'react';
import { useRouter, usePathname } from 'next/navigation';
import { IconMap, type allCats, routeMap } from '@src/constants/categories';
-import { RightChevron } from '../icons/Icons';
+import { RightChevron } from '@src/icons/Icons';
const SidebarItems: FC<{ cat: allCats[number] }> = ({ cat }) => {
const Icon = IconMap[cat];
diff --git a/src/components/searchBar/ClubSearchBar.tsx b/src/components/searchBar/ClubSearchBar.tsx
new file mode 100644
index 00000000..6e2ffa8d
--- /dev/null
+++ b/src/components/searchBar/ClubSearchBar.tsx
@@ -0,0 +1,32 @@
+'use client';
+import { useState } from 'react';
+import { useRouter } from 'next/navigation';
+import type { SelectClub as Club } from '@src/server/db/models';
+import { api } from '@src/trpc/react';
+import { DebouncedSearchBar } from './DebouncedSearchBar';
+
+export const ClubSearchBar = () => {
+ const router = useRouter();
+ const [search, setSearch] = useState('');
+ const { data } = api.club.byName.useQuery(
+ { name: search },
+ { enabled: !!search },
+ );
+ const onClickSearchResult = (club: Club) => {
+ router.push(`/directory/${club.id}`);
+ };
+ return (
+ {
+ if (data && data[0]) {
+ onClickSearchResult(data[0]);
+ }
+ }}
+ />
+ );
+};
diff --git a/src/components/searchBar/DebouncedSearchBar.tsx b/src/components/searchBar/DebouncedSearchBar.tsx
new file mode 100644
index 00000000..1fe89774
--- /dev/null
+++ b/src/components/searchBar/DebouncedSearchBar.tsx
@@ -0,0 +1,75 @@
+'use client';
+import {
+ useState,
+ type ChangeEvent,
+ useEffect,
+ type Dispatch,
+ type SetStateAction,
+} from 'react';
+import { SearchBar } from '.';
+
+export type SearchElement = {
+ id: string;
+ name: string;
+};
+export type DebouncedSearchBarProps = {
+ placeholder: string;
+ value?: string;
+ setSearch: Dispatch>;
+ searchResults?: Array;
+ onClick?: (input: T) => void;
+ submitButton?: boolean;
+ submitLogic?: () => void;
+};
+export const DebouncedSearchBar = ({
+ placeholder,
+ value,
+ setSearch,
+ searchResults,
+ onClick,
+ submitButton,
+ submitLogic,
+}: DebouncedSearchBarProps) => {
+ const [input, setInput] = useState(value ?? '');
+ const [focused, setFocused] = useState(false);
+ const handleSearch = (e: ChangeEvent) => {
+ setInput(e.target.value);
+ };
+ useEffect(() => {
+ const handler = setTimeout(() => {
+ setSearch(input);
+ }, 300);
+ return () => {
+ clearTimeout(handler);
+ };
+ }, [input, setSearch]);
+
+ return (
+
+
setFocused(true)}
+ onBlur={() => setTimeout(() => setFocused(false), 300)}
+ submitButton={submitButton}
+ submitLogic={submitLogic}
+ />
+ {input && focused && searchResults && searchResults.length > 0 && (
+
+ {searchResults.map((item) => (
+
+ ))}
+
+ )}
+
+ );
+};
+export default DebouncedSearchBar;
diff --git a/src/components/searchBar/EventClubSearchBar.tsx b/src/components/searchBar/EventClubSearchBar.tsx
new file mode 100644
index 00000000..0c65a28f
--- /dev/null
+++ b/src/components/searchBar/EventClubSearchBar.tsx
@@ -0,0 +1,39 @@
+'use client';
+import { useState } from 'react';
+import type { SelectClub as Club } from '@src/server/db/models';
+import { api } from '@src/trpc/react';
+import { DebouncedSearchBar } from './DebouncedSearchBar';
+
+type EventClubSearchBarProps = {
+ addClub: (value: string) => void;
+};
+export const EventClubSearchBar = ({ addClub }: EventClubSearchBarProps) => {
+ const [search, setSearch] = useState('');
+ const utils = api.useUtils();
+ const { data } = api.club.byName.useQuery(
+ { name: search },
+ {
+ enabled: !!search,
+ },
+ );
+ const submit = (club: Club) => {
+ void utils.club.byId.prefetch({ id: club.id });
+ addClub(club.id);
+ setSearch('');
+ };
+ return (
+ {
+ if (data && data[0]) {
+ submit(data[0]);
+ }
+ }}
+ />
+ );
+};
diff --git a/src/components/searchBar/EventSearchBar.tsx b/src/components/searchBar/EventSearchBar.tsx
new file mode 100644
index 00000000..7e32cd98
--- /dev/null
+++ b/src/components/searchBar/EventSearchBar.tsx
@@ -0,0 +1,36 @@
+'use client';
+import { useState } from 'react';
+import { useRouter } from 'next/navigation';
+import { api } from '@src/trpc/react';
+import type { SelectEvent as Event } from '@src/server/db/models';
+import { DebouncedSearchBar } from './DebouncedSearchBar';
+
+export const EventSearchBar = () => {
+ const router = useRouter();
+ const [search, setSearch] = useState('');
+
+ const { data } = api.event.byName.useQuery(
+ {
+ name: search,
+ sortByDate: true,
+ },
+ { enabled: !!search },
+ );
+ const onClickSearchResult = (event: Event) => {
+ router.push(`/event/${event.id}`);
+ };
+ return (
+ {
+ if (data && data[0]) {
+ onClickSearchResult(data[0]);
+ }
+ }}
+ />
+ );
+};
diff --git a/src/components/searchBar/UserSearchBar.tsx b/src/components/searchBar/UserSearchBar.tsx
new file mode 100644
index 00000000..94fad809
--- /dev/null
+++ b/src/components/searchBar/UserSearchBar.tsx
@@ -0,0 +1,41 @@
+'use client';
+import { api } from '@src/trpc/react';
+import { useState } from 'react';
+import { DebouncedSearchBar } from './DebouncedSearchBar';
+
+type UserSearchBarProps = {
+ passUser: (user: { id: string; name: string }) => void;
+};
+export const UserSearchBar = ({ passUser }: UserSearchBarProps) => {
+ const [search, setSearch] = useState('');
+ const userQuery = api.userMetadata.searchByName.useQuery(
+ { name: search },
+ {
+ enabled: !!search,
+ },
+ );
+ const formattedData = userQuery.isSuccess
+ ? userQuery.data.map((val) => {
+ return { name: val.firstName + ' ' + val.lastName, ...val };
+ })
+ : [];
+ return (
+ {
+ passUser({ id: user.id, name: user.name });
+ setSearch('');
+ }}
+ submitLogic={() => {
+ if (formattedData && formattedData[0]) {
+ const user = formattedData[0];
+ passUser({ id: user.id, name: user.name });
+ setSearch('');
+ }
+ }}
+ />
+ );
+};
diff --git a/src/components/searchBar/index.tsx b/src/components/searchBar/index.tsx
new file mode 100644
index 00000000..228aeb96
--- /dev/null
+++ b/src/components/searchBar/index.tsx
@@ -0,0 +1,46 @@
+import { RightArrowIcon, SearchIcon } from '@src/icons/Icons';
+import { type ComponentProps } from 'react';
+
+type SearchBarProps = Omit, 'type'> & {
+ submitButton?: boolean;
+ submitLogic?: () => void;
+};
+
+export const SearchBar = (props: SearchBarProps) => {
+ const submitButton = props.submitButton;
+ const submitLogic = props.submitLogic;
+ return (
+
+
+
+
+ {
+ if (e.key === 'Enter' && typeof submitLogic !== 'undefined') {
+ submitLogic();
+ }
+ }}
+ />
+ {submitButton && (
+
+ )}
+
+ );
+};
+export default SearchBar;
diff --git a/src/components/ClubSelector.tsx b/src/components/settings/ClubSelector.tsx
similarity index 100%
rename from src/components/ClubSelector.tsx
rename to src/components/settings/ClubSelector.tsx
diff --git a/src/components/settings/FormCard.tsx b/src/components/settings/FormCard.tsx
index 70749e16..c3744de1 100644
--- a/src/components/settings/FormCard.tsx
+++ b/src/components/settings/FormCard.tsx
@@ -7,7 +7,7 @@ import SettingsInput from './SettingsInput';
import { useForm } from 'react-hook-form';
import { z } from 'zod';
import { zodResolver } from '@hookform/resolvers/zod';
-import ClubSelector from '@src/components/ClubSelector';
+import ClubSelector from '@src/components/settings/ClubSelector';
import { api } from '@src/trpc/react';
import DeleteButton from './DeleteButton';
import { useRouter } from 'next/navigation';
diff --git a/src/components/ContactIcons.tsx b/src/icons/ContactIcons.tsx
similarity index 100%
rename from src/components/ContactIcons.tsx
rename to src/icons/ContactIcons.tsx
diff --git a/src/server/api/routers/admin.ts b/src/server/api/routers/admin.ts
index 2e398bad..86eac7b1 100644
--- a/src/server/api/routers/admin.ts
+++ b/src/server/api/routers/admin.ts
@@ -25,13 +25,13 @@ const carouselSchema = z.object({
range: z.custom((val) => isDateRange(val)),
});
-const changeOrgStatusSchema = z.object({
- orgId: z.string(),
+const changeClubStatusSchema = z.object({
+ clubId: z.string(),
status: z.enum(['approved', 'pending', 'rejected']),
});
export const adminRouter = createTRPCRouter({
- allOrgs: adminProcedure.query(async ({ ctx }) => {
+ allClubs: adminProcedure.query(async ({ ctx }) => {
const orgs = await ctx.db.query.club.findMany({
columns: {
id: true,
@@ -44,7 +44,7 @@ export const adminRouter = createTRPCRouter({
});
return orgs;
}),
- deleteOrg: adminProcedure
+ deleteClub: adminProcedure
.input(deleteSchema)
.mutation(async ({ ctx, input }) => {
await ctx.db.delete(club).where(eq(club.id, input.id));
@@ -103,13 +103,13 @@ export const adminRouter = createTRPCRouter({
return carousels;
}),
- addOrgCarousel: adminProcedure
+ addClubCarousel: adminProcedure
.input(carouselSchema)
.mutation(async ({ ctx, input }) => {
if (!input.range.from || !input.range.to)
throw new Error('Invalid date range');
- // Check if there is already a carousel for this org
+ // Check if there is already a carousel for this club
const exists = await ctx.db.query.carousel.findFirst({
where: (carousel) => eq(carousel.orgId, input.orgId),
});
@@ -130,17 +130,17 @@ export const adminRouter = createTRPCRouter({
endTime: input.range.to,
});
}),
- removeOrgCarousel: adminProcedure
+ removeClubCarousel: adminProcedure
.input(deleteSchema)
.mutation(async ({ ctx, input }) => {
await ctx.db.delete(carousel).where(eq(carousel.orgId, input.id));
}),
- changeOrgStatus: adminProcedure
- .input(changeOrgStatusSchema)
+ changeClubStatus: adminProcedure
+ .input(changeClubStatusSchema)
.mutation(async ({ ctx, input }) => {
await ctx.db
.update(club)
.set({ approved: input.status })
- .where(eq(club.id, input.orgId));
+ .where(eq(club.id, input.clubId));
}),
});
diff --git a/src/server/api/routers/event.ts b/src/server/api/routers/event.ts
index e883f40e..895c5f26 100644
--- a/src/server/api/routers/event.ts
+++ b/src/server/api/routers/event.ts
@@ -262,7 +262,12 @@ export const eventRouter = createTRPCRouter({
throw new TRPCError({ code: 'UNAUTHORIZED' });
}
- await ctx.db.insert(events).values({ ...input });
+ const res = await ctx.db
+ .insert(events)
+ .values({ ...input })
+ .returning({ id: events.id });
+ if (res.length == 0) throw 'Failed to add event';
+ return res[0]?.id;
}),
byName: publicProcedure.input(byNameSchema).query(async ({ input, ctx }) => {
const { name, sortByDate } = input;
diff --git a/src/utils/formSchemas.ts b/src/utils/formSchemas.ts
index e03a7d32..3df635cd 100644
--- a/src/utils/formSchemas.ts
+++ b/src/utils/formSchemas.ts
@@ -49,7 +49,7 @@ export const createEventSchema = z.object({
description: z.string().max(1000),
startTime: z.coerce.date(),
endTime: z.coerce.date(),
-})
+});
export const feedbackFormSchema = z.object({
rating: z.number().min(1).max(10),