From 7f415680e6a112e543f8343f9016f772dadad16f Mon Sep 17 00:00:00 2001 From: Ethan Bickel Date: Thu, 8 Feb 2024 15:28:03 -0600 Subject: [PATCH 01/87] extract searchparam into new hook --- src/app/events/page.tsx | 55 ++----- src/components/events/EventSidebar.tsx | 199 +++---------------------- src/utils/paramSchemas.ts | 18 +++ src/utils/useSearch.ts | 55 +++++++ 4 files changed, 102 insertions(+), 225 deletions(-) create mode 100644 src/utils/paramSchemas.ts create mode 100644 src/utils/useSearch.ts diff --git a/src/app/events/page.tsx b/src/app/events/page.tsx index c852f94f..c0cf3303 100644 --- a/src/app/events/page.tsx +++ b/src/app/events/page.tsx @@ -1,13 +1,13 @@ import { EventHeader } from '@src/components/BaseHeader'; -import { type filterState } from '@src/components/events/EventSidebar'; import { api } from '@src/trpc/server'; import { type z } from 'zod'; import { type findByFilterSchema } from '@src/server/api/routers/event'; import EventView from './eventView'; import { type Metadata } from 'next'; +import { eventParamsSchema } from '@src/utils/paramSchemas'; function getStartTime( - filterState: filterState, + filterState: z.infer, ): z.infer['startTime'] { switch (filterState.filter) { case 'Upcoming Events': @@ -16,10 +16,6 @@ function getStartTime( return { type: 'distance', options: { days: -7 } }; case 'Last month events': return { type: 'distance', options: { days: -30 } }; - case 'pick': - return filterState.date - ? { type: 'range', options: filterState.date } - : { type: 'now' }; } } export const metadata: Metadata = { @@ -33,48 +29,21 @@ export const metadata: Metadata = { description: 'Get connected on campus.', }, }; -type searchPams = Partial< - Omit & { - date: string | string[] | undefined; - clubs: string | string[] | undefined; - view: 'list' | 'grid' | undefined; - } ->; -const Events = async ({ searchParams }: { searchParams: searchPams }) => { - const filters = { - filter: searchParams.filter ?? 'Upcoming Events', - date: - searchParams.filter === 'pick' - ? searchParams.date - ? Array.isArray(searchParams.date) - ? { - from: searchParams.date[0] - ? new Date(Number.parseInt(searchParams.date[0])) - : undefined, - to: searchParams.date[1] - ? new Date(Number.parseInt(searchParams.date[1])) - : undefined, - } - : { from: new Date(Number.parseInt(searchParams.date)) } - : undefined - : undefined, - clubs: searchParams.clubs - ? Array.isArray(searchParams.clubs) - ? searchParams.clubs - : [searchParams.clubs] - : [], - order: searchParams.order ?? 'soon', - types: searchParams.types ?? [], - }; +const Events = async ({ + searchParams, +}: { + searchParams: (typeof eventParamsSchema)['_input']; +}) => { + const parsed = eventParamsSchema.parse(searchParams); const { events } = await api.event.findByFilters.query({ - startTime: getStartTime(filters), - club: filters.clubs, - order: filters.order, + startTime: getStartTime(parsed), + club: parsed.clubs, + order: parsed.order, }); return (
- +
); }; diff --git a/src/components/events/EventSidebar.tsx b/src/components/events/EventSidebar.tsx index 3a807059..bfdec1b0 100644 --- a/src/components/events/EventSidebar.tsx +++ b/src/components/events/EventSidebar.tsx @@ -5,22 +5,9 @@ import { RadioGroupItem, } from '@radix-ui/react-radio-group'; import { EventClubSearchBar } from '../SearchBar'; -import { - Popover, - PopoverPortal, - PopoverTrigger, -} from '@radix-ui/react-popover'; -import DatePopover from './DatePopover'; -import { - useRouter, - useSearchParams, - usePathname, - type ReadonlyURLSearchParams, -} from 'next/navigation'; -import { type DateRange } from 'react-day-picker'; -import { type Dispatch, type SetStateAction, useEffect, useState } from 'react'; import { api } from '@src/trpc/react'; -import { format, isEqual } from 'date-fns'; +import useSearch from '@src/utils/useSearch'; +import { eventParamsSchema } from '@src/utils/paramSchemas'; export const filters = [ 'Upcoming Events', @@ -33,77 +20,15 @@ const order = [ 'shortest duration', 'longest duration', ] as const; -const types = ['In-Person', 'Virtual', 'Multi-Day', 'Hybrid'] as const; export type filterState = { - filter: (typeof filters)[number] | 'pick'; - date?: DateRange; + filter: (typeof filters)[number]; clubs: Array; order: (typeof order)[number]; - types: (typeof types)[number][]; }; -function createSearchParams( - oldSearchParams: URLSearchParams, - filters: filterState, -) { - const params = new URLSearchParams(oldSearchParams); - params.set('filter', filters.filter); - if (filters.filter == 'pick' && filters.date) { - if (filters.date.from) - params.set('date', filters.date.from.getTime().toString()); - if (filters.date.to) - params.append('date', filters.date.to.getTime().toString()); - } - params.set('order', filters.order); - params.delete('clubs'); - filters.clubs.forEach((val) => params.append('clubs', val)); - - return params.toString(); -} -function createFilterState(searchParams: ReadonlyURLSearchParams): filterState { - const filter = searchParams.get('filter') as filterState['filter'] | null; - const order = searchParams.get('order') as filterState['order'] | null; - const clubs = (searchParams.getAll('clubs') ?? []) as - | filterState['clubs'] - | null; - if (filter === 'pick') { - const dates = searchParams.getAll('date'); - return { - filter: filter, - date: { - from: dates[0] ? new Date(Number.parseInt(dates[0])) : undefined, - to: dates[1] ? new Date(Number.parseInt(dates[1])) : undefined, - }, - order: order ?? 'soon', - clubs: clubs ?? [], - types: [], - }; - } else { - return { - filter: filter ?? 'Upcoming Events', - order: order ?? 'soon', - clubs: clubs ?? [], - types: [], - }; - } -} - const EventSidebar = () => { - const searchParams = useSearchParams(); - const router = useRouter(); - const pathname = usePathname(); - const [filterState, setFilterState] = useState( - createFilterState(searchParams) ?? { - filter: 'Upcoming Events', - clubs: [], - order: 'soon', - types: [], - }, - ); - useEffect(() => { - router.push(pathname + '?' + createSearchParams(searchParams, filterState)); - router.refresh(); - }, [filterState, router, pathname, searchParams]); + const [filterState, setFilterState] = useSearch(eventParamsSchema); + return (
@@ -111,17 +36,7 @@ const EventSidebar = () => {
{ - setFilterState((old) => { - if (!old.clubs.includes(val)) { - return { - filter: old.filter, - clubs: [...old.clubs, val], - order: old.order, - types: old.types, - }; - } - return old; - }); + setFilterState({ clubs: [...filterState.clubs, val] }); }} />
@@ -129,7 +44,10 @@ const EventSidebar = () => { { + const temp = filterState.clubs.filter((c) => c !== value); + setFilterState({ clubs: temp }); + }} /> ))}
@@ -141,14 +59,8 @@ const EventSidebar = () => { className="space-y-2.5" value={filterState.filter} onValueChange={(value) => { - setFilterState((old) => { - return { - filter: value as (typeof filters)[number], - date: old.date, - clubs: old.clubs, - order: old.order, - types: old.types, - }; + setFilterState({ + filter: value as (typeof filters)[number], }); }} > @@ -168,49 +80,6 @@ const EventSidebar = () => {
))} - - - -
-
- -
-

- {filterState.date?.from - ? filterState.date.to - ? isEqual(filterState.date.from, filterState.date.to) - ? format(filterState.date.from, 'PPP') - : format(filterState.date.from, 'MMM do') + - ' - ' + - format(filterState.date.to, 'MMM do') - : format(filterState.date.from, 'PPP') - : 'Pick a date range'} -

-
-
- - {filterState.filter === 'pick' && ( - { - setFilterState((old) => { - return { - filter: 'pick', - clubs: old.clubs, - date: val, - order: old.order, - types: old.types, - }; - }); - }} - /> - )} - -
-
@@ -219,13 +88,8 @@ const EventSidebar = () => { className="flex flex-col space-y-2.5" value={filterState.order} onValueChange={(value) => { - setFilterState((old) => { - return { - filter: old.filter, - clubs: old.clubs, - order: value as (typeof order)[number], - types: old.types, - }; + setFilterState({ + order: value as (typeof order)[number], }); }} > @@ -247,37 +111,16 @@ const EventSidebar = () => { ))}
- {/* for future when we add event types */} -
-

Event Types

-
- {types.map((value) => ( -
- -
- ))} -
-
); }; export default EventSidebar; const SelectedClub = ({ clubId, - setFilterState, + removeClub, }: { clubId: string; - setFilterState: Dispatch>; + removeClub: () => void; }) => { const query = api.club.byId.useQuery({ id: clubId }); return ( @@ -290,15 +133,7 @@ const SelectedClub = ({ type="button" title="remove club" onClick={() => { - setFilterState((old) => { - const clubs = old.clubs.filter((val) => val != clubId); - return { - filter: old.filter, - clubs: clubs, - order: old.order, - types: old.types, - }; - }); + removeClub(); }} > X diff --git a/src/utils/paramSchemas.ts b/src/utils/paramSchemas.ts new file mode 100644 index 00000000..0e78b0a5 --- /dev/null +++ b/src/utils/paramSchemas.ts @@ -0,0 +1,18 @@ +import { z } from 'zod'; + +// schemas for parsing and transforming query params +// input types are all strings that should then be transformed and piped into a parse +export const eventParamsSchema = z.object({ + filter: z + .enum(['Upcoming Events', 'Last weeks events', 'Last month events']) + .default('Upcoming Events'), + clubs: z + .string() + .default('[]') + .transform((s) => JSON.parse(decodeURIComponent(s)) as string[]) + .pipe(z.string().array().default([])), + order: z + .enum(['soon', 'later', 'shortest duration', 'longest duration']) + .default('soon'), + view: z.enum(['list', 'grid']).default('list'), +}); diff --git a/src/utils/useSearch.ts b/src/utils/useSearch.ts new file mode 100644 index 00000000..b489ca62 --- /dev/null +++ b/src/utils/useSearch.ts @@ -0,0 +1,55 @@ +import { usePathname, useSearchParams } from 'next/navigation'; +import { useRouter } from 'next/navigation'; +import { useEffect, useReducer } from 'react'; +import { type z } from 'zod'; + +function EncodeParams< + // eslint-disable-next-line @typescript-eslint/no-explicit-any + T extends Record | Record>, +>(obj: T): string { + return Object.entries(obj) + .map((value) => + typeof value[1] === 'string' + ? `${value[0]}=${encodeURIComponent(value[1])}` + : `${value[0]}=${encodeURIComponent(JSON.stringify(value[1]))}`, + ) + .join('&'); +} +// eslint-disable-next-line @typescript-eslint/no-explicit-any +const useSearch = (schema: T) => { + const searchParams = useSearchParams(); + const router = useRouter(); + const pathname = usePathname(); + const [params, setParams] = useReducer( + (state: z.infer, action: Partial>) => { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + Object.entries(action).map((value: [keyof z.infer, any]) => { + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment + state[value[0]] = value[1]; + }); + return { ...state }; + }, + null, + () => { + const temp: Record = {}; + Object.keys(schema.shape).map((key) => { + temp[key] = searchParams.get(key) ?? undefined; + }); + return schema.parse(temp); + }, + ); + useEffect(() => { + const temp: Record = {}; + Object.keys(schema.shape).map((key) => { + temp[key] = searchParams.get(key) ?? undefined; + }); + const parsed = schema.parse(temp); + setParams(parsed); + }, [searchParams, schema]); + useEffect(() => { + const enc = EncodeParams(params); + router.push(`${pathname}?${enc}`); + }, [params, router, pathname]); + return [params, setParams] as const; +}; +export default useSearch; From ab6c89e3960e17e987d9cf2f5c8c33caa0fd4c8c Mon Sep 17 00:00:00 2001 From: Ethan Bickel Date: Thu, 8 Feb 2024 17:58:57 -0600 Subject: [PATCH 02/87] fix typing for searchParams encoder --- src/utils/useSearch.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/utils/useSearch.ts b/src/utils/useSearch.ts index b489ca62..0fccd81e 100644 --- a/src/utils/useSearch.ts +++ b/src/utils/useSearch.ts @@ -3,13 +3,15 @@ import { useRouter } from 'next/navigation'; import { useEffect, useReducer } from 'react'; import { type z } from 'zod'; -function EncodeParams< +export function EncodeParams< // eslint-disable-next-line @typescript-eslint/no-explicit-any - T extends Record | Record>, + T extends Record, >(obj: T): string { return Object.entries(obj) .map((value) => - typeof value[1] === 'string' + typeof value[1] === 'string' || + typeof value[1] === 'number' || + typeof value[1] === 'boolean' ? `${value[0]}=${encodeURIComponent(value[1])}` : `${value[0]}=${encodeURIComponent(JSON.stringify(value[1]))}`, ) From 600aadee4a2e61852526928af2ee2d8f7459db1c Mon Sep 17 00:00:00 2001 From: Ethan Bickel Date: Thu, 8 Feb 2024 18:01:02 -0600 Subject: [PATCH 03/87] make event view setting client side and optimistic from search params --- src/app/events/eventView.tsx | 48 +++++++++++++----------------------- src/app/events/page.tsx | 7 +++++- 2 files changed, 23 insertions(+), 32 deletions(-) diff --git a/src/app/events/eventView.tsx b/src/app/events/eventView.tsx index f0cf18a2..39d7ad40 100644 --- a/src/app/events/eventView.tsx +++ b/src/app/events/eventView.tsx @@ -1,60 +1,48 @@ -'use server'; -import { GridIcon, ListIcon } from '@src/icons/Icons'; -import EventCard from '@src/components/events/EventCard'; +'use client'; import EventSidebar from '@src/components/events/EventSidebar'; -import { type RouterOutputs } from '@src/trpc/shared'; -import Link from 'next/link'; +import { GridIcon, ListIcon } from '@src/icons/Icons'; +import { eventParamsSchema } from '@src/utils/paramSchemas'; +import useSearch from '@src/utils/useSearch'; +import { type ReactNode } from 'react'; type Props = { - events: RouterOutputs['event']['findByFilters']['events']; - params: Record; + children: ReactNode; }; -const EventView = ({ events, params }: Props) => { - const view = (params?.view ?? 'list') as 'list' | 'grid'; +const EventView = ({ children }: Props) => { + const [{ view }, setParams] = useSearch(eventParamsSchema); return (

Events

- setParams({ view: 'list' })} >

List view

- - +
@@ -67,9 +55,7 @@ const EventView = ({ events, params }: Props) => { : 'group flex flex-wrap gap-x-10 gap-y-7.5 pt-10' } > - {events.map((event) => { - return ; - })} + {children}
diff --git a/src/app/events/page.tsx b/src/app/events/page.tsx index c0cf3303..e745a139 100644 --- a/src/app/events/page.tsx +++ b/src/app/events/page.tsx @@ -5,6 +5,7 @@ import { type findByFilterSchema } from '@src/server/api/routers/event'; import EventView from './eventView'; import { type Metadata } from 'next'; import { eventParamsSchema } from '@src/utils/paramSchemas'; +import EventCard from '@src/components/events/EventCard'; function getStartTime( filterState: z.infer, @@ -43,7 +44,11 @@ const Events = async ({ return (
- + + {events.map((event) => { + return ; + })} +
); }; From c75c947dd02547cbd24eebec4f632bd89df01534 Mon Sep 17 00:00:00 2001 From: Ethan Bickel Date: Thu, 8 Feb 2024 18:14:15 -0600 Subject: [PATCH 04/87] fix: errors from malformated searchparams --- src/utils/paramSchemas.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/utils/paramSchemas.ts b/src/utils/paramSchemas.ts index 0e78b0a5..f2a13b0a 100644 --- a/src/utils/paramSchemas.ts +++ b/src/utils/paramSchemas.ts @@ -5,14 +5,14 @@ import { z } from 'zod'; export const eventParamsSchema = z.object({ filter: z .enum(['Upcoming Events', 'Last weeks events', 'Last month events']) - .default('Upcoming Events'), + .catch('Upcoming Events'), clubs: z .string() .default('[]') .transform((s) => JSON.parse(decodeURIComponent(s)) as string[]) - .pipe(z.string().array().default([])), + .pipe(z.string().array().catch([])), order: z .enum(['soon', 'later', 'shortest duration', 'longest duration']) .default('soon'), - view: z.enum(['list', 'grid']).default('list'), + view: z.enum(['list', 'grid']).catch('list'), }); From 897dc490f082236129b9be164ef59131987557c7 Mon Sep 17 00:00:00 2001 From: Ethan Bickel Date: Fri, 9 Feb 2024 17:05:03 -0600 Subject: [PATCH 05/87] clean up filters --- src/app/events/eventView.tsx | 2 +- src/app/events/page.tsx | 4 +- src/components/events/EventSidebar.tsx | 55 ++++++++++++++++++-------- src/utils/eventFilter.ts | 25 ++++++++++++ src/utils/paramSchemas.ts | 18 --------- 5 files changed, 68 insertions(+), 36 deletions(-) create mode 100644 src/utils/eventFilter.ts delete mode 100644 src/utils/paramSchemas.ts diff --git a/src/app/events/eventView.tsx b/src/app/events/eventView.tsx index 39d7ad40..2ff6feb5 100644 --- a/src/app/events/eventView.tsx +++ b/src/app/events/eventView.tsx @@ -1,7 +1,7 @@ 'use client'; import EventSidebar from '@src/components/events/EventSidebar'; import { GridIcon, ListIcon } from '@src/icons/Icons'; -import { eventParamsSchema } from '@src/utils/paramSchemas'; +import { eventParamsSchema } from '@src/utils/eventFilter'; import useSearch from '@src/utils/useSearch'; import { type ReactNode } from 'react'; type Props = { diff --git a/src/app/events/page.tsx b/src/app/events/page.tsx index e745a139..8b90e2f6 100644 --- a/src/app/events/page.tsx +++ b/src/app/events/page.tsx @@ -4,7 +4,7 @@ import { type z } from 'zod'; import { type findByFilterSchema } from '@src/server/api/routers/event'; import EventView from './eventView'; import { type Metadata } from 'next'; -import { eventParamsSchema } from '@src/utils/paramSchemas'; +import { eventParamsSchema } from '@src/utils/eventFilter'; import EventCard from '@src/components/events/EventCard'; function getStartTime( @@ -17,6 +17,8 @@ function getStartTime( return { type: 'distance', options: { days: -7 } }; case 'Last month events': return { type: 'distance', options: { days: -30 } }; + default: + return { type: 'now' }; } } export const metadata: Metadata = { diff --git a/src/components/events/EventSidebar.tsx b/src/components/events/EventSidebar.tsx index bfdec1b0..443dba9e 100644 --- a/src/components/events/EventSidebar.tsx +++ b/src/components/events/EventSidebar.tsx @@ -7,25 +7,13 @@ import { import { EventClubSearchBar } from '../SearchBar'; import { api } from '@src/trpc/react'; import useSearch from '@src/utils/useSearch'; -import { eventParamsSchema } from '@src/utils/paramSchemas'; +import { eventParamsSchema, order } from '@src/utils/eventFilter'; -export const filters = [ +export const basicFilters = [ 'Upcoming Events', 'Last weeks events', 'Last month events', ] as const; -const order = [ - 'soon', - 'later', - 'shortest duration', - 'longest duration', -] as const; -export type filterState = { - filter: (typeof filters)[number]; - clubs: Array; - order: (typeof order)[number]; -}; - const EventSidebar = () => { const [filterState, setFilterState] = useSearch(eventParamsSchema); @@ -60,11 +48,11 @@ const EventSidebar = () => { value={filterState.filter} onValueChange={(value) => { setFilterState({ - filter: value as (typeof filters)[number], + filter: value as (typeof basicFilters)[number], }); }} > - {filters.map((value) => ( + {basicFilters.map((value) => ( { ))} + +
+
+ +
+

+ {'Date'} +

+
+
+ {filterState.filter === 'Date' &&
On Date
} + +
+
+ +
+

+ Date Range +

+
+
+ {filterState.filter === 'Date Range' && ( + <> +
From
+
To
+ + )}
diff --git a/src/utils/eventFilter.ts b/src/utils/eventFilter.ts new file mode 100644 index 00000000..f1677c89 --- /dev/null +++ b/src/utils/eventFilter.ts @@ -0,0 +1,25 @@ +import { z } from 'zod'; +export const filters = [ + 'Upcoming Events', + 'Last weeks events', + 'Last month events', + 'Date', + 'Date Range', +] as const; +export const order = [ + 'soon', + 'later', + 'shortest duration', + 'longest duration', +] as const; +export const eventParamsSchema = z.object({ + filter: z.enum(filters).catch('Upcoming Events'), + clubs: z + .string() + .default('[]') + .transform((s) => JSON.parse(decodeURIComponent(s)) as string[]) + .pipe(z.string().array().catch([])), + order: z.enum(order).default('soon'), + view: z.enum(['list', 'grid']).catch('list'), + liked: z.boolean().catch(false), +}); diff --git a/src/utils/paramSchemas.ts b/src/utils/paramSchemas.ts deleted file mode 100644 index f2a13b0a..00000000 --- a/src/utils/paramSchemas.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { z } from 'zod'; - -// schemas for parsing and transforming query params -// input types are all strings that should then be transformed and piped into a parse -export const eventParamsSchema = z.object({ - filter: z - .enum(['Upcoming Events', 'Last weeks events', 'Last month events']) - .catch('Upcoming Events'), - clubs: z - .string() - .default('[]') - .transform((s) => JSON.parse(decodeURIComponent(s)) as string[]) - .pipe(z.string().array().catch([])), - order: z - .enum(['soon', 'later', 'shortest duration', 'longest duration']) - .default('soon'), - view: z.enum(['list', 'grid']).catch('list'), -}); From 1147b95b2cfec5850bb1b2e8b56f31697ae89de2 Mon Sep 17 00:00:00 2001 From: Ethan Bickel Date: Fri, 8 Mar 2024 16:18:25 -0600 Subject: [PATCH 06/87] add seperate schema for email contacts --- src/utils/formSchemas.ts | 34 ++++++++++++++++++++++++++-------- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/src/utils/formSchemas.ts b/src/utils/formSchemas.ts index 1348f308..d100bf15 100644 --- a/src/utils/formSchemas.ts +++ b/src/utils/formSchemas.ts @@ -1,6 +1,29 @@ -import { selectContact } from '@src/server/db/models'; import { z } from 'zod'; +const genericPlatformSchema = z.object({ + platform: z.enum([ + 'discord', + 'youtube', + 'twitch', + 'facebook', + 'twitter', + 'instagram', + 'website', + 'other', + ]), + clubId: z.string().optional(), + url: z.string().url(), +}); + +const emailSchema = z.object({ + platform: z.literal('email'), + url: z.string().email(), +}); +const contactSchema = z.discriminatedUnion('platform', [ + genericPlatformSchema, + emailSchema, +]); + export const createClubSchema = z.object({ name: z.string().min(3, 'Club name must be at least 3 characters long'), description: z.string().min(1, 'Description is required'), @@ -14,15 +37,10 @@ export const createClubSchema = z.object({ }) .array() .min(1), - contacts: selectContact - .omit({ clubId: true, url: true }) - .extend({ url: z.string().url() }) - .array(), + contacts: contactSchema.array(), }); export const editClubContactSchema = z.object({ - contacts: selectContact - .extend({ clubId: z.string().optional(), url: z.string().url() }) - .array(), + contacts: contactSchema.array(), }); export const editClubSchema = z.object({ From d92234bec4347e675552ce1287f8c7959f51b563 Mon Sep 17 00:00:00 2001 From: Ethan Bickel Date: Fri, 8 Mar 2024 19:54:36 -0600 Subject: [PATCH 07/87] add seperate Contact button option for emails --- src/components/ContactButtons.tsx | 35 ++++++++++++++++++++++++------- 1 file changed, 27 insertions(+), 8 deletions(-) diff --git a/src/components/ContactButtons.tsx b/src/components/ContactButtons.tsx index b961ca01..c8fce984 100644 --- a/src/components/ContactButtons.tsx +++ b/src/components/ContactButtons.tsx @@ -2,6 +2,19 @@ import type { SelectContact as Contacts } from '@src/server/db/models'; import { logo } from './ContactIcons'; import Link from 'next/link'; +const EmailButton = ({ item }: { item: Contacts }) => { + return ( + + ); +}; + type contentButtonProps = { contacts: Array; }; @@ -9,14 +22,20 @@ const ContactButtons = ({ contacts }: contentButtonProps) => { return (
{contacts.map((item) => ( - + <> + {item.platform === 'email' ? ( + + ) : ( + + )} + ))}
); From 5f2e01659ca44373850a0eda73007da8a4aba06f Mon Sep 17 00:00:00 2001 From: Ethan Bickel Date: Sat, 16 Mar 2024 19:06:11 -0500 Subject: [PATCH 08/87] update backend schema --- src/server/api/routers/club.ts | 31 ++++++++++++++----------------- src/utils/formSchemas.ts | 1 + 2 files changed, 15 insertions(+), 17 deletions(-) diff --git a/src/server/api/routers/club.ts b/src/server/api/routers/club.ts index ce62811e..727068e1 100644 --- a/src/server/api/routers/club.ts +++ b/src/server/api/routers/club.ts @@ -11,12 +11,12 @@ import { } from 'drizzle-orm'; import { createTRPCRouter, protectedProcedure, publicProcedure } from '../trpc'; import { z } from 'zod'; -import { selectContact } from '@src/server/db/models'; import { clubEditRouter } from './clubEdit'; import { userMetadataToClubs } from '@src/server/db/schema/users'; import { club } from '@src/server/db/schema/club'; import { contacts } from '@src/server/db/schema/contacts'; import { carousel } from '@src/server/db/schema/admin'; +import { createClubSchema as baseClubSchema } from '@src/utils/formSchemas'; const byNameSchema = z.object({ name: z.string().default(''), }); @@ -35,22 +35,19 @@ const allSchema = z.object({ limit: z.number().min(1).max(50).default(10), initialCursor: z.number().min(0).default(0), }); -const createClubSchema = z.object({ - name: z.string().min(3), - description: z.string().min(1), - officers: z - .object({ - id: z.string().min(1), - position: z.string().min(1), - president: z.boolean(), - }) - .array() - .min(1), - contacts: selectContact - .omit({ clubId: true, url: true }) - .extend({ url: z.string().url() }) - .array(), -}); +const createClubSchema = baseClubSchema + .omit({ clubId: true, officers: true }) + .extend({ + officers: z + .object({ + id: z.string().min(1), + position: z.string(), + president: z.boolean(), + }) + .array() + .min(1), + }); + export const clubRouter = createTRPCRouter({ edit: clubEditRouter, byName: publicProcedure.input(byNameSchema).query(async ({ input, ctx }) => { diff --git a/src/utils/formSchemas.ts b/src/utils/formSchemas.ts index d100bf15..df833524 100644 --- a/src/utils/formSchemas.ts +++ b/src/utils/formSchemas.ts @@ -17,6 +17,7 @@ const genericPlatformSchema = z.object({ const emailSchema = z.object({ platform: z.literal('email'), + clubId: z.string().optional(), url: z.string().email(), }); const contactSchema = z.discriminatedUnion('platform', [ From b2136e982f8c3a99d3195e7e6ea9d654a81a71ae Mon Sep 17 00:00:00 2001 From: Ethan Bickel Date: Fri, 22 Mar 2024 19:51:32 -0500 Subject: [PATCH 09/87] remove list and grid toggle --- src/app/events/eventView.tsx | 41 +++--------------------------------- 1 file changed, 3 insertions(+), 38 deletions(-) diff --git a/src/app/events/eventView.tsx b/src/app/events/eventView.tsx index 2ff6feb5..dbb558e1 100644 --- a/src/app/events/eventView.tsx +++ b/src/app/events/eventView.tsx @@ -1,59 +1,24 @@ 'use client'; import EventSidebar from '@src/components/events/EventSidebar'; -import { GridIcon, ListIcon } from '@src/icons/Icons'; -import { eventParamsSchema } from '@src/utils/eventFilter'; -import useSearch from '@src/utils/useSearch'; import { type ReactNode } from 'react'; type Props = { children: ReactNode; }; const EventView = ({ children }: Props) => { - const [{ view }, setParams] = useSearch(eventParamsSchema); - return (

Events

- - + date picker here
{children}
From ae8f6b98023b44fb65bec13ab0d60010069a548c Mon Sep 17 00:00:00 2001 From: Ethan Bickel Date: Mon, 1 Apr 2024 17:06:20 -0500 Subject: [PATCH 10/87] extract contact schemas to new file and create seperate schemas for better validation --- src/utils/contact.ts | 86 ++++++++++++++++++++++++++++++++++++++++ src/utils/formSchemas.ts | 29 ++------------ 2 files changed, 89 insertions(+), 26 deletions(-) create mode 100644 src/utils/contact.ts diff --git a/src/utils/contact.ts b/src/utils/contact.ts new file mode 100644 index 00000000..002a6c8a --- /dev/null +++ b/src/utils/contact.ts @@ -0,0 +1,86 @@ +import { z } from 'zod'; + +const emailSchema = z.object({ + platform: z.literal('email'), + clubId: z.string().optional(), + url: z.string().email('Must be a valid email'), +}); +const discordSchema = z.object({ + platform: z.literal('discord'), + clubId: z.string().optional(), + url: z + .string() + .url('Vaid url required') + .regex(/https:\/\/discord\.(gg|com)\/.+/, 'Must be a discord link'), +}); + +const youtubeSchema = z.object({ + platform: z.literal('youtube'), + clubId: z.string().optional(), + url: z + .string() + .url('Vaid url required') + .regex(/https:\/\/youtube\.(com)\/.+/, 'Must be a youtube link'), +}); + +const twitchSchema = z.object({ + platform: z.literal('twitch'), + clubId: z.string().optional(), + url: z + .string() + .url('Vaid url required') + .regex(/https:\/\/twitch\.(tv)\/.+/, 'Must be a twitch link'), +}); + +const facebookSchema = z.object({ + platform: z.literal('facebook'), + clubId: z.string().optional(), + url: z + .string() + .url('Vaid url required') + .regex(/https:\/\/facebook\.(com)\/.+/, 'Must be a facebook link'), +}); + +const twitterSchema = z.object({ + platform: z.literal('twitter'), + clubId: z.string().optional(), + url: z + .string() + .url('Vaid url required') + .regex(/https:\/\/(twitter|x)\.(com)\/.+/, 'Must be a twitter link'), +}); +const instagramSchema = z.object({ + platform: z.literal('instragram'), + clubId: z.string().optional(), + url: z + .string() + .url('Vaid url required') + .regex(/https:\/\/instagram\.(com)\/.+/, 'Must be a instagram link'), +}); + +const websiteSchema = z.object({ + platform: z.literal('website'), + clubId: z.string().optional(), + url: z + .string() + .url('Vaid url required') + .regex(/https?:\/\/.*\.?.+\..+\/.+/, 'Must be a valid website link'), +}); + +const otherSchema = z.object({ + platform: z.literal('other'), + clubId: z.string().optional(), + url: z.string().url('must be a valid url'), +}); + +export const contactSchema = z.discriminatedUnion('platform', [ + emailSchema, + discordSchema, + youtubeSchema, + twitchSchema, + facebookSchema, + twitterSchema, + instagramSchema, + websiteSchema, + otherSchema, +]); diff --git a/src/utils/formSchemas.ts b/src/utils/formSchemas.ts index 92f18e35..04b788b7 100644 --- a/src/utils/formSchemas.ts +++ b/src/utils/formSchemas.ts @@ -1,29 +1,5 @@ import { z } from 'zod'; - -const genericPlatformSchema = z.object({ - platform: z.enum([ - 'discord', - 'youtube', - 'twitch', - 'facebook', - 'twitter', - 'instagram', - 'website', - 'other', - ]), - clubId: z.string().optional(), - url: z.string().url(), -}); - -const emailSchema = z.object({ - platform: z.literal('email'), - clubId: z.string().optional(), - url: z.string().email(), -}); -const contactSchema = z.discriminatedUnion('platform', [ - genericPlatformSchema, - emailSchema, -]); +import { contactSchema } from './contact'; export const createClubSchema = z.object({ name: z.string().min(3, 'Club name must be at least 3 characters long'), @@ -67,4 +43,5 @@ export const feedbackFormSchema = z.object({ dislikes: z.string().default(''), features: z.string().default(''), submit_on: z.date().default(new Date()), -}) \ No newline at end of file +}); + From bb8200d09fcc6819ae0262a75d35838c62d0bd9b Mon Sep 17 00:00:00 2001 From: Ethan Bickel Date: Mon, 1 Apr 2024 17:51:51 -0500 Subject: [PATCH 11/87] fix edit contact form --- src/app/manage/[clubId]/edit/EditContactForm.tsx | 3 ++- src/utils/contact.ts | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/app/manage/[clubId]/edit/EditContactForm.tsx b/src/app/manage/[clubId]/edit/EditContactForm.tsx index dacce878..4d9edd15 100644 --- a/src/app/manage/[clubId]/edit/EditContactForm.tsx +++ b/src/app/manage/[clubId]/edit/EditContactForm.tsx @@ -4,6 +4,7 @@ import { zodResolver } from '@hookform/resolvers/zod'; import EditContactSelector from '@src/components/EditContactSelector'; import { type SelectClub, type SelectContact } from '@src/server/db/models'; import { api } from '@src/trpc/react'; +import { type contact } from '@src/utils/contact'; import { editClubContactSchema } from '@src/utils/formSchemas'; import { useRouter } from 'next/navigation'; import { useReducer } from 'react'; @@ -55,7 +56,7 @@ const deletedReducer = ( export default function EditContactForm({ club, }: { - club: SelectClub & { contacts: SelectContact[] }; + club: SelectClub & { contacts: contact[] }; }) { const { register, diff --git a/src/utils/contact.ts b/src/utils/contact.ts index 002a6c8a..659e1d7e 100644 --- a/src/utils/contact.ts +++ b/src/utils/contact.ts @@ -50,7 +50,7 @@ const twitterSchema = z.object({ .regex(/https:\/\/(twitter|x)\.(com)\/.+/, 'Must be a twitter link'), }); const instagramSchema = z.object({ - platform: z.literal('instragram'), + platform: z.literal('instagram'), clubId: z.string().optional(), url: z .string() @@ -84,3 +84,4 @@ export const contactSchema = z.discriminatedUnion('platform', [ websiteSchema, otherSchema, ]); +export type contact = z.infer; From 1022dbad15490ac32c325bdc841f630ea6c128db Mon Sep 17 00:00:00 2001 From: Ethan Bickel Date: Tue, 2 Apr 2024 22:15:09 -0500 Subject: [PATCH 12/87] update instagram regex --- src/utils/contact.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils/contact.ts b/src/utils/contact.ts index 659e1d7e..38e1dce0 100644 --- a/src/utils/contact.ts +++ b/src/utils/contact.ts @@ -55,7 +55,7 @@ const instagramSchema = z.object({ url: z .string() .url('Vaid url required') - .regex(/https:\/\/instagram\.(com)\/.+/, 'Must be a instagram link'), + .regex(/https:\/\/www\.instagram\.(com)\/.+/, 'Must be a instagram link'), }); const websiteSchema = z.object({ From f67e9fc072941fda2829084f22b2d886c49a923c Mon Sep 17 00:00:00 2001 From: Ethan Bickel Date: Wed, 3 Apr 2024 12:11:31 -0500 Subject: [PATCH 13/87] fix merge issue --- src/components/events/EventSidebar.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/components/events/EventSidebar.tsx b/src/components/events/EventSidebar.tsx index f102a661..543b46da 100644 --- a/src/components/events/EventSidebar.tsx +++ b/src/components/events/EventSidebar.tsx @@ -8,13 +8,15 @@ import { EventClubSearchBar } from '../SearchBar'; import { api } from '@src/trpc/react'; import useSearch from '@src/utils/useSearch'; import { eventParamsSchema, order } from '@src/utils/eventFilter'; +import { useState } from 'react'; +import { ExpandLess, ExpandMore } from '@src/icons/Icons'; export const basicFilters = [ 'Upcoming Events', 'Last weeks events', 'Last month events', ] as const; -const EventSidebar = () => { +const Filters = () => { const [filterState, setFilterState] = useSearch(eventParamsSchema); return ( From f78cd5b3d991e0539f865150c534ca94b280bc6f Mon Sep 17 00:00:00 2001 From: Ethan Bickel Date: Wed, 3 Apr 2024 12:12:13 -0500 Subject: [PATCH 14/87] rework date selector --- src/app/events/eventView.tsx | 5 +-- src/components/events/DateBrowser.tsx | 49 +++++++++++++++++++++++++++ src/components/events/DatePopover.tsx | 18 ---------- 3 files changed, 52 insertions(+), 20 deletions(-) create mode 100644 src/components/events/DateBrowser.tsx delete mode 100644 src/components/events/DatePopover.tsx diff --git a/src/app/events/eventView.tsx b/src/app/events/eventView.tsx index a1f49eb5..8e73a8b7 100644 --- a/src/app/events/eventView.tsx +++ b/src/app/events/eventView.tsx @@ -1,4 +1,5 @@ 'use client'; +import DateBrowser from '@src/components/events/DateBrowser'; import EventSidebar from '@src/components/events/EventSidebar'; import { type ReactNode } from 'react'; type Props = { @@ -11,10 +12,10 @@ const EventView = ({ children }: Props) => {

Events

- date picker here +
-
+
{ + const { inputProps, dayPickerProps, setSelected } = useInput({ + defaultSelected: new Date(), + }); + + return ( +
+ + + +
+ +
+
+ + + + + + +
+ +
+ ); +}; +export default DateBrowser; diff --git a/src/components/events/DatePopover.tsx b/src/components/events/DatePopover.tsx deleted file mode 100644 index d5a170f2..00000000 --- a/src/components/events/DatePopover.tsx +++ /dev/null @@ -1,18 +0,0 @@ -'use client'; -import { PopoverClose, PopoverContent } from '@radix-ui/react-popover'; -import { type Dispatch } from 'react'; -import { DayPicker, type DateRange } from 'react-day-picker'; -import 'react-day-picker/dist/style.css'; -type DatePickerPopoverProps = { - range: DateRange | undefined; - setRange: Dispatch; -}; -const DatePickerPopover = ({ range, setRange }: DatePickerPopoverProps) => { - return ( - - - - - ); -}; -export default DatePickerPopover; From 08d7dfb779145f12139a92155c15a509b0dbdc47 Mon Sep 17 00:00:00 2001 From: Ethan Bickel Date: Tue, 16 Apr 2024 15:28:26 -0500 Subject: [PATCH 15/87] rework eventFilter params --- src/app/events/page.tsx | 16 +------ src/components/events/EventSidebar.tsx | 64 -------------------------- src/server/api/routers/event.ts | 64 ++++++-------------------- src/utils/eventFilter.ts | 16 +++---- src/utils/useSearch.ts | 3 ++ 5 files changed, 24 insertions(+), 139 deletions(-) diff --git a/src/app/events/page.tsx b/src/app/events/page.tsx index 8b90e2f6..a9c5fc35 100644 --- a/src/app/events/page.tsx +++ b/src/app/events/page.tsx @@ -7,20 +7,6 @@ import { type Metadata } from 'next'; import { eventParamsSchema } from '@src/utils/eventFilter'; import EventCard from '@src/components/events/EventCard'; -function getStartTime( - filterState: z.infer, -): z.infer['startTime'] { - switch (filterState.filter) { - case 'Upcoming Events': - return { type: 'now' }; - case 'Last weeks events': - return { type: 'distance', options: { days: -7 } }; - case 'Last month events': - return { type: 'distance', options: { days: -30 } }; - default: - return { type: 'now' }; - } -} export const metadata: Metadata = { title: 'Events - Jupiter', description: 'Get connected on campus.', @@ -39,7 +25,7 @@ const Events = async ({ }) => { const parsed = eventParamsSchema.parse(searchParams); const { events } = await api.event.findByFilters.query({ - startTime: getStartTime(parsed), + date: parsed.date, club: parsed.clubs, order: parsed.order, }); diff --git a/src/components/events/EventSidebar.tsx b/src/components/events/EventSidebar.tsx index 543b46da..c25a87ed 100644 --- a/src/components/events/EventSidebar.tsx +++ b/src/components/events/EventSidebar.tsx @@ -43,70 +43,6 @@ const Filters = () => {
-
-

Filters

- { - setFilterState({ - filter: value as (typeof basicFilters)[number], - }); - }} - > - {basicFilters.map((value) => ( - -
-
- -
-

- {value} -

-
-
- ))} - -
-
- -
-

- {'Date'} -

-
-
- {filterState.filter === 'Date' &&
On Date
} - -
-
- -
-

- Date Range -

-
-
- {filterState.filter === 'Date Range' && ( - <> -
From
-
To
- - )} -
-

Arrange Events

((val) => isDateRange(val)), - }), - ]), + date: z.date(), order: z.enum(['soon', 'later', 'shortest duration', 'longest duration']), club: z.string().array(), }); @@ -110,43 +93,22 @@ export const eventRouter = createTRPCRouter({ findByFilters: publicProcedure .input(findByFilterSchema) .query(async ({ input, ctx }) => { - const startTime = - input.startTime.type === 'now' - ? new Date() - : input.startTime.type === 'distance' - ? add(new Date(), input.startTime.options) - : input.startTime.options.from ?? new Date(); - const endTime = - input.startTime.type === 'distance' - ? new Date() - : input.startTime.type === 'range' - ? input.startTime.options.to - ? add(input.startTime.options.to, { days: 1 }) - : add(startTime, { days: 1 }) - : undefined; + const startTime = startOfDay(input.date); + const endTime = add(startTime, { days: 1 }); const events = await ctx.db.query.events.findMany({ where: (event) => { const whereElements: Array | undefined> = []; - if (!endTime) { - whereElements.push( - or( - gte(event.startTime, startTime), + whereElements.push( + or( + between(event.startTime, startTime, endTime), + between(event.endTime, startTime, endTime), + and( + lte(event.startTime, startTime), gte(event.endTime, startTime), ), - ); - } else { - whereElements.push( - or( - between(event.startTime, startTime, endTime), - between(event.endTime, startTime, endTime), - and( - lte(event.startTime, startTime), - gte(event.endTime, startTime), - ), - and(lte(event.startTime, endTime), gte(event.endTime, endTime)), - ), - ); - } + and(lte(event.startTime, endTime), gte(event.endTime, endTime)), + ), + ); if (input.club.length !== 0) { whereElements.push(inArray(event.clubId, input.club)); diff --git a/src/utils/eventFilter.ts b/src/utils/eventFilter.ts index f1677c89..7eb256c7 100644 --- a/src/utils/eventFilter.ts +++ b/src/utils/eventFilter.ts @@ -1,11 +1,5 @@ +import { startOfToday, toDate } from 'date-fns'; import { z } from 'zod'; -export const filters = [ - 'Upcoming Events', - 'Last weeks events', - 'Last month events', - 'Date', - 'Date Range', -] as const; export const order = [ 'soon', 'later', @@ -13,13 +7,17 @@ export const order = [ 'longest duration', ] as const; export const eventParamsSchema = z.object({ - filter: z.enum(filters).catch('Upcoming Events'), + date: z + .string() + .transform((s) => toDate(Number.parseInt(s))) + .pipe(z.date().catch(startOfToday())), clubs: z .string() .default('[]') .transform((s) => JSON.parse(decodeURIComponent(s)) as string[]) .pipe(z.string().array().catch([])), order: z.enum(order).default('soon'), - view: z.enum(['list', 'grid']).catch('list'), liked: z.boolean().catch(false), }); + +export type eventParamsSchema = z.infer; diff --git a/src/utils/useSearch.ts b/src/utils/useSearch.ts index 0fccd81e..ac12d471 100644 --- a/src/utils/useSearch.ts +++ b/src/utils/useSearch.ts @@ -22,6 +22,8 @@ const useSearch = (schema: T) => { const searchParams = useSearchParams(); const router = useRouter(); const pathname = usePathname(); + + // parses params and typesafety mumbo jumbo, nextjs is trying it's hardest const [params, setParams] = useReducer( (state: z.infer, action: Partial>) => { // eslint-disable-next-line @typescript-eslint/no-explicit-any @@ -41,6 +43,7 @@ const useSearch = (schema: T) => { }, ); useEffect(() => { + // whenever the query params are updated, sync them const temp: Record = {}; Object.keys(schema.shape).map((key) => { temp[key] = searchParams.get(key) ?? undefined; From 8e1602009f30f267d88a497006879c55762b9208 Mon Sep 17 00:00:00 2001 From: Ethan Bickel Date: Tue, 16 Apr 2024 15:29:12 -0500 Subject: [PATCH 16/87] improve datebrowser buttons change events page header to support date browser better --- src/app/events/eventView.tsx | 4 ++-- src/components/events/DateBrowser.tsx | 19 ++++++++++++++++--- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/src/app/events/eventView.tsx b/src/app/events/eventView.tsx index 8e73a8b7..a6aa45e0 100644 --- a/src/app/events/eventView.tsx +++ b/src/app/events/eventView.tsx @@ -9,9 +9,9 @@ type Props = { const EventView = ({ children }: Props) => { return (
-
+

Events

-
+
diff --git a/src/components/events/DateBrowser.tsx b/src/components/events/DateBrowser.tsx index 254eb1ba..127419b3 100644 --- a/src/components/events/DateBrowser.tsx +++ b/src/components/events/DateBrowser.tsx @@ -1,3 +1,4 @@ +'use client'; import { DayPicker, useInput } from 'react-day-picker'; import { Popover, @@ -9,19 +10,28 @@ import { import 'react-day-picker/dist/style.css'; import { addDays, subDays } from 'date-fns'; +import { LeftArrowIcon, RightArrowIcon } from '@src/icons/Icons'; +import { useEffect } from 'react'; +import { eventParamsSchema } from '@src/utils/eventFilter'; +import useSearch from '@src/utils/useSearch'; const DateBrowser = () => { const { inputProps, dayPickerProps, setSelected } = useInput({ defaultSelected: new Date(), }); + const [filterState] = useSearch(eventParamsSchema); return ( -
+
@@ -40,8 +50,11 @@ const DateBrowser = () => { onClick={() => { setSelected(addDays(dayPickerProps.selected!, 1)); }} + aria-label="forward one day" > - forward +
+ +
); From 35302217e0926bb64e25bd4b2fa8c95d3d0aa94b Mon Sep 17 00:00:00 2001 From: Ethan Bickel Date: Tue, 16 Apr 2024 16:04:00 -0500 Subject: [PATCH 17/87] add server action to change date --- src/components/events/DateBrowser.tsx | 76 +++++++++++++++------------ src/utils/actions.ts | 21 ++++++++ src/utils/encodeParams.ts | 14 +++++ src/utils/useSearch.ts | 17 ++---- 4 files changed, 79 insertions(+), 49 deletions(-) create mode 100644 src/utils/actions.ts create mode 100644 src/utils/encodeParams.ts diff --git a/src/components/events/DateBrowser.tsx b/src/components/events/DateBrowser.tsx index 127419b3..10507d53 100644 --- a/src/components/events/DateBrowser.tsx +++ b/src/components/events/DateBrowser.tsx @@ -1,4 +1,5 @@ 'use client'; + import { DayPicker, useInput } from 'react-day-picker'; import { Popover, @@ -11,51 +12,56 @@ import { import 'react-day-picker/dist/style.css'; import { addDays, subDays } from 'date-fns'; import { LeftArrowIcon, RightArrowIcon } from '@src/icons/Icons'; -import { useEffect } from 'react'; import { eventParamsSchema } from '@src/utils/eventFilter'; import useSearch from '@src/utils/useSearch'; +import { eventTimeUpdate } from '@src/utils/actions'; const DateBrowser = () => { const { inputProps, dayPickerProps, setSelected } = useInput({ defaultSelected: new Date(), }); const [filterState] = useSearch(eventParamsSchema); + const changeDate = eventTimeUpdate.bind(null, filterState); return (
- - - -
- -
-
- - - - - - -
- + {/* eslint-disable-next-line @typescript-eslint/no-misused-promises */} +
+ + + + + + + + + + + + + +
); }; diff --git a/src/utils/actions.ts b/src/utils/actions.ts new file mode 100644 index 00000000..dcf3087a --- /dev/null +++ b/src/utils/actions.ts @@ -0,0 +1,21 @@ +'use server'; + +import { isDate } from 'util/types'; +import { type eventParamsSchema } from './eventFilter'; +import { redirect } from 'next/navigation'; +import { parse } from 'date-fns'; +import EncodeParams from './encodeParams'; + +export async function eventTimeUpdate( + queryParams: eventParamsSchema, + formData: FormData, +) { + const udate = formData.get('date'); + const date = parse(typeof udate === 'string' ? udate : '', 'PP', new Date()); + console.log(date); + if (date && isDate(date)) { + queryParams.date = date; + const newQuery = EncodeParams(queryParams); + redirect(`/events?${newQuery}`); + } +} diff --git a/src/utils/encodeParams.ts b/src/utils/encodeParams.ts new file mode 100644 index 00000000..816131f9 --- /dev/null +++ b/src/utils/encodeParams.ts @@ -0,0 +1,14 @@ +export default function EncodeParams< + // eslint-disable-next-line @typescript-eslint/no-explicit-any + T extends Record, +>(obj: T): string { + return Object.entries(obj) + .map((value) => + typeof value[1] === 'string' || + typeof value[1] === 'number' || + typeof value[1] === 'boolean' + ? `${value[0]}=${encodeURIComponent(value[1])}` + : `${value[0]}=${encodeURIComponent(JSON.stringify(value[1]))}`, + ) + .join('&'); +} diff --git a/src/utils/useSearch.ts b/src/utils/useSearch.ts index ac12d471..8de0266d 100644 --- a/src/utils/useSearch.ts +++ b/src/utils/useSearch.ts @@ -1,22 +1,11 @@ +'use client'; + import { usePathname, useSearchParams } from 'next/navigation'; import { useRouter } from 'next/navigation'; import { useEffect, useReducer } from 'react'; import { type z } from 'zod'; +import EncodeParams from './encodeParams'; -export function EncodeParams< - // eslint-disable-next-line @typescript-eslint/no-explicit-any - T extends Record, ->(obj: T): string { - return Object.entries(obj) - .map((value) => - typeof value[1] === 'string' || - typeof value[1] === 'number' || - typeof value[1] === 'boolean' - ? `${value[0]}=${encodeURIComponent(value[1])}` - : `${value[0]}=${encodeURIComponent(JSON.stringify(value[1]))}`, - ) - .join('&'); -} // eslint-disable-next-line @typescript-eslint/no-explicit-any const useSearch = (schema: T) => { const searchParams = useSearchParams(); From e8d78bf493df34689bac95acdd0beb1cbca4ac54 Mon Sep 17 00:00:00 2001 From: Ethan Bickel Date: Tue, 16 Apr 2024 16:12:55 -0500 Subject: [PATCH 18/87] make eventtimealert client side and dynamic --- src/components/events/EventCard.tsx | 6 +++++- src/components/events/EventTimeAlert.tsx | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/components/events/EventCard.tsx b/src/components/events/EventCard.tsx index 0f16625f..75008289 100644 --- a/src/components/events/EventCard.tsx +++ b/src/components/events/EventCard.tsx @@ -3,10 +3,14 @@ import { format, isSameDay } from 'date-fns'; import Image from 'next/image'; import Link from 'next/link'; import { MoreIcon } from '../../icons/Icons'; -import EventTimeAlert from './EventTimeAlert'; import { type RouterOutputs } from '@src/trpc/shared'; import EventLikeButton from '../EventLikeButton'; import { getServerAuthSession } from '@src/server/auth'; +import dynamic from 'next/dynamic'; + +const EventTimeAlert = dynamic(() => import('./EventTimeAlert'), { + ssr: false, +}); type EventCardProps = { event: RouterOutputs['event']['findByFilters']['events'][number]; diff --git a/src/components/events/EventTimeAlert.tsx b/src/components/events/EventTimeAlert.tsx index 69500b57..c027f020 100644 --- a/src/components/events/EventTimeAlert.tsx +++ b/src/components/events/EventTimeAlert.tsx @@ -1,4 +1,4 @@ -'use server'; +'use client'; import { type SelectEvent } from '@src/server/db/models'; import { differenceInDays, From 275c8b10d650441df8b605d91350ff9009065958 Mon Sep 17 00:00:00 2001 From: Ethan Bickel Date: Tue, 16 Apr 2024 17:12:45 -0500 Subject: [PATCH 19/87] update to next 14, no big changes fix: next config for next 14 --- next.config.mjs | 3 - package-lock.json | 470 ++++++++++++++++++++++++++++++++++------------ package.json | 12 +- 3 files changed, 352 insertions(+), 133 deletions(-) diff --git a/next.config.mjs b/next.config.mjs index c611029a..4a705781 100644 --- a/next.config.mjs +++ b/next.config.mjs @@ -13,9 +13,6 @@ const config = { 'jupiter.nlmc.workers.dev', ], }, - experimental: { - serverActions: true, - }, }; export default config; diff --git a/package-lock.json b/package-lock.json index 487c2f52..a4585255 100644 --- a/package-lock.json +++ b/package-lock.json @@ -27,12 +27,12 @@ "dotenv": "^16.0.3", "drizzle-orm": "^0.28.5", "drizzle-zod": "^0.5.1", - "next": "^13.5.4", + "next": "^14.2.1", "next-auth": "^4.23.0", "postgres": "^3.3.5", - "react": "18.2.0", + "react": "^18.2.0", "react-day-picker": "^8.9.1", - "react-dom": "18.2.0", + "react-dom": "^18.2.0", "react-hook-form": "^7.48.2", "superjson": "^1.13.1", "zod": "^3.22.4" @@ -44,8 +44,8 @@ "@types/eslint": "^8.44.2", "@types/jest": "^29.5.5", "@types/node": "^18.16.0", - "@types/react": "^18.2.20", - "@types/react-dom": "^18.2.7", + "@types/react": "^18.2.79", + "@types/react-dom": "^18.2.25", "@typescript-eslint/eslint-plugin": "^6.3.0", "@typescript-eslint/parser": "^6.3.0", "autoprefixer": "^10.4.14", @@ -54,7 +54,7 @@ "dotenv-cli": "^7.3.0", "drizzle-kit": "^0.19.13", "eslint": "^8.47.0", - "eslint-config-next": "^13.5.4", + "eslint-config-next": "^14.2.1", "eslint-config-prettier": "^8.5.0", "eslint-plugin-jsx-a11y": "^6.5.1", "eslint-plugin-react": "^7.29.4", @@ -1300,6 +1300,96 @@ "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", "dev": true }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@isaacs/cliui/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, "node_modules/@istanbuljs/load-nyc-config": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", @@ -1735,65 +1825,60 @@ } }, "node_modules/@next/env": { - "version": "13.5.6", - "resolved": "https://registry.npmjs.org/@next/env/-/env-13.5.6.tgz", - "integrity": "sha512-Yac/bV5sBGkkEXmAX5FWPS9Mmo2rthrOPRQQNfycJPkjUAUclomCPH7QFVCDQ4Mp2k2K1SSM6m0zrxYrOwtFQw==" + "version": "14.2.1", + "resolved": "https://registry.npmjs.org/@next/env/-/env-14.2.1.tgz", + "integrity": "sha512-qsHJle3GU3CmVx7pUoXcghX4sRN+vINkbLdH611T8ZlsP//grzqVW87BSUgOZeSAD4q7ZdZicdwNe/20U2janA==" }, "node_modules/@next/eslint-plugin-next": { - "version": "13.5.5", - "resolved": "https://registry.npmjs.org/@next/eslint-plugin-next/-/eslint-plugin-next-13.5.5.tgz", - "integrity": "sha512-S/32s4S+SCOpW58lHKdmILAAPRdnsSei7Y3L1oZSoe5Eh0QSlzbG1nYyIpnpwWgz3T7qe3imdq7cJ6Hf29epRA==", - "dev": true, - "dependencies": { - "glob": "7.1.7" - } - }, - "node_modules/@next/eslint-plugin-next/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "version": "14.2.1", + "resolved": "https://registry.npmjs.org/@next/eslint-plugin-next/-/eslint-plugin-next-14.2.1.tgz", + "integrity": "sha512-Fp+mthEBjkn8r9qd6o4JgxKp0IDEzW0VYHD8ZC05xS5/lFNwHKuOdr2kVhWG7BQCO9L6eeepshM1Wbs2T+LgSg==", "dev": true, "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "glob": "10.3.10" } }, "node_modules/@next/eslint-plugin-next/node_modules/glob": { - "version": "7.1.7", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", - "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", + "version": "10.3.10", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz", + "integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==", "dev": true, "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "foreground-child": "^3.1.0", + "jackspeak": "^2.3.5", + "minimatch": "^9.0.1", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", + "path-scurry": "^1.10.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" }, "engines": { - "node": "*" + "node": ">=16 || 14 >=14.17" }, "funding": { "url": "https://github.com/sponsors/isaacs" } }, "node_modules/@next/eslint-plugin-next/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", + "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", "dev": true, "dependencies": { - "brace-expansion": "^1.1.7" + "brace-expansion": "^2.0.1" }, "engines": { - "node": "*" + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/@next/swc-darwin-arm64": { - "version": "13.5.6", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-13.5.6.tgz", - "integrity": "sha512-5nvXMzKtZfvcu4BhtV0KH1oGv4XEW+B+jOfmBdpFI3C7FrB/MfujRpWYSBBO64+qbW8pkZiSyQv9eiwnn5VIQA==", + "version": "14.2.1", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-14.2.1.tgz", + "integrity": "sha512-kGjnjcIJehEcd3rT/3NAATJQndAEELk0J9GmGMXHSC75TMnvpOhONcjNHbjtcWE5HUQnIHy5JVkatrnYm1QhVw==", "cpu": [ "arm64" ], @@ -1806,9 +1891,9 @@ } }, "node_modules/@next/swc-darwin-x64": { - "version": "13.5.6", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-13.5.6.tgz", - "integrity": "sha512-6cgBfxg98oOCSr4BckWjLLgiVwlL3vlLj8hXg2b+nDgm4bC/qVXXLfpLB9FHdoDu4057hzywbxKvmYGmi7yUzA==", + "version": "14.2.1", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-14.2.1.tgz", + "integrity": "sha512-dAdWndgdQi7BK2WSXrx4lae7mYcOYjbHJUhvOUnJjMNYrmYhxbbvJ2xElZpxNxdfA6zkqagIB9He2tQk+l16ew==", "cpu": [ "x64" ], @@ -1821,9 +1906,9 @@ } }, "node_modules/@next/swc-linux-arm64-gnu": { - "version": "13.5.6", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-13.5.6.tgz", - "integrity": "sha512-txagBbj1e1w47YQjcKgSU4rRVQ7uF29YpnlHV5xuVUsgCUf2FmyfJ3CPjZUvpIeXCJAoMCFAoGnbtX86BK7+sg==", + "version": "14.2.1", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.2.1.tgz", + "integrity": "sha512-2ZctfnyFOGvTkoD6L+DtQtO3BfFz4CapoHnyLTXkOxbZkVRgg3TQBUjTD/xKrO1QWeydeo8AWfZRg8539qNKrg==", "cpu": [ "arm64" ], @@ -1836,9 +1921,9 @@ } }, "node_modules/@next/swc-linux-arm64-musl": { - "version": "13.5.6", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-13.5.6.tgz", - "integrity": "sha512-cGd+H8amifT86ZldVJtAKDxUqeFyLWW+v2NlBULnLAdWsiuuN8TuhVBt8ZNpCqcAuoruoSWynvMWixTFcroq+Q==", + "version": "14.2.1", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.2.1.tgz", + "integrity": "sha512-jazZXctiaanemy4r+TPIpFP36t1mMwWCKMsmrTRVChRqE6putyAxZA4PDujx0SnfvZHosjdkx9xIq9BzBB5tWg==", "cpu": [ "arm64" ], @@ -1851,9 +1936,9 @@ } }, "node_modules/@next/swc-linux-x64-gnu": { - "version": "13.5.6", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-13.5.6.tgz", - "integrity": "sha512-Mc2b4xiIWKXIhBy2NBTwOxGD3nHLmq4keFk+d4/WL5fMsB8XdJRdtUlL87SqVCTSaf1BRuQQf1HvXZcy+rq3Nw==", + "version": "14.2.1", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.2.1.tgz", + "integrity": "sha512-VjCHWCjsAzQAAo8lkBOLEIkBZFdfW+Z18qcQ056kL4KpUYc8o59JhLDCBlhg+hINQRgzQ2UPGma2AURGOH0+Qg==", "cpu": [ "x64" ], @@ -1866,9 +1951,9 @@ } }, "node_modules/@next/swc-linux-x64-musl": { - "version": "13.5.6", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-13.5.6.tgz", - "integrity": "sha512-CFHvP9Qz98NruJiUnCe61O6GveKKHpJLloXbDSWRhqhkJdZD2zU5hG+gtVJR//tyW897izuHpM6Gtf6+sNgJPQ==", + "version": "14.2.1", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.2.1.tgz", + "integrity": "sha512-7HZKYKvAp4nAHiHIbY04finRqjeYvkITOGOurP1aLMexIFG/1+oCnqhGogBdc4lao/lkMW1c+AkwWSzSlLasqw==", "cpu": [ "x64" ], @@ -1881,9 +1966,9 @@ } }, "node_modules/@next/swc-win32-arm64-msvc": { - "version": "13.5.6", - "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-13.5.6.tgz", - "integrity": "sha512-aFv1ejfkbS7PUa1qVPwzDHjQWQtknzAZWGTKYIAaS4NMtBlk3VyA6AYn593pqNanlicewqyl2jUhQAaFV/qXsg==", + "version": "14.2.1", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.2.1.tgz", + "integrity": "sha512-YGHklaJ/Cj/F0Xd8jxgj2p8po4JTCi6H7Z3Yics3xJhm9CPIqtl8erlpK1CLv+HInDqEWfXilqatF8YsLxxA2Q==", "cpu": [ "arm64" ], @@ -1896,9 +1981,9 @@ } }, "node_modules/@next/swc-win32-ia32-msvc": { - "version": "13.5.6", - "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-13.5.6.tgz", - "integrity": "sha512-XqqpHgEIlBHvzwG8sp/JXMFkLAfGLqkbVsyN+/Ih1mR8INb6YCc2x/Mbwi6hsAgUnqQztz8cvEbHJUbSl7RHDg==", + "version": "14.2.1", + "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.2.1.tgz", + "integrity": "sha512-o+ISKOlvU/L43ZhtAAfCjwIfcwuZstiHVXq/BDsZwGqQE0h/81td95MPHliWCnFoikzWcYqh+hz54ZB2FIT8RA==", "cpu": [ "ia32" ], @@ -1911,9 +1996,9 @@ } }, "node_modules/@next/swc-win32-x64-msvc": { - "version": "13.5.6", - "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-13.5.6.tgz", - "integrity": "sha512-Cqfe1YmOS7k+5mGu92nl5ULkzpKuxJrP3+4AEuPmrpFZ3BHxTY3TnHmU1On3bFmFFs6FbTcdF58CCUProGpIGQ==", + "version": "14.2.1", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.2.1.tgz", + "integrity": "sha512-GmRoTiLcvCLifujlisknv4zu9/C4i9r0ktsA8E51EMqJL4bD4CpO7lDYr7SrUxCR0tS4RVcrqKmCak24T0ohaw==", "cpu": [ "x64" ], @@ -1968,6 +2053,16 @@ "url": "https://github.com/sponsors/panva" } }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, + "optional": true, + "engines": { + "node": ">=14" + } + }, "node_modules/@radix-ui/primitive": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.0.1.tgz", @@ -2677,11 +2772,17 @@ "@sinonjs/commons": "^3.0.0" } }, + "node_modules/@swc/counter": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz", + "integrity": "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==" + }, "node_modules/@swc/helpers": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.2.tgz", - "integrity": "sha512-E4KcWTpoLHqwPHLxidpOqQbcrZVgi0rsmmZXUle1jXmJfuIf/UWpczUJ7MZZ5tlxytgJXyp0w4PGkkeLiuIdZw==", + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.5.tgz", + "integrity": "sha512-KGYxvIOXcceOAbEk4bi/dVLEK9z8sZ0uBB3Il5b1rhfClSpcX0yfRO0KmTkqR2cnQDymwLB+25ZyMzICg/cm/A==", "dependencies": { + "@swc/counter": "^0.1.3", "tslib": "^2.4.0" } }, @@ -3021,31 +3122,24 @@ "devOptional": true }, "node_modules/@types/react": { - "version": "18.2.28", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.28.tgz", - "integrity": "sha512-ad4aa/RaaJS3hyGz0BGegdnSRXQBkd1CCYDCdNjBPg90UUpLgo+WlJqb9fMYUxtehmzF3PJaTWqRZjko6BRzBg==", + "version": "18.2.79", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.79.tgz", + "integrity": "sha512-RwGAGXPl9kSXwdNTafkOEuFrTBD5SA2B3iEB96xi8+xu5ddUa/cpvyVCSNn+asgLCTHkb5ZxN8gbuibYJi4s1w==", "devOptional": true, "dependencies": { "@types/prop-types": "*", - "@types/scheduler": "*", "csstype": "^3.0.2" } }, "node_modules/@types/react-dom": { - "version": "18.2.13", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.13.tgz", - "integrity": "sha512-eJIUv7rPP+EC45uNYp/ThhSpE16k22VJUknt5OLoH9tbXoi8bMhwLf5xRuWMywamNbWzhrSmU7IBJfPup1+3fw==", + "version": "18.2.25", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.25.tgz", + "integrity": "sha512-o/V48vf4MQh7juIKZU2QGDfli6p1+OOi5oXx36Hffpc9adsHeXjVp8rHuPkjd8VT8sOJ2Zp05HR7CdpGTIUFUA==", "devOptional": true, "dependencies": { "@types/react": "*" } }, - "node_modules/@types/scheduler": { - "version": "0.16.4", - "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.4.tgz", - "integrity": "sha512-2L9ifAGl7wmXwP4v3pN4p2FLhD0O1qsJpvKmNin5VA8+UvNVb447UDaAEV6UdrkA+m/Xs58U1RFps44x6TFsVQ==", - "devOptional": true - }, "node_modules/@types/semver": { "version": "7.5.3", "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.3.tgz", @@ -4024,9 +4118,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001549", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001549.tgz", - "integrity": "sha512-qRp48dPYSCYaP+KurZLhDYdVE+yEyht/3NlmcJgVQ2VMGt6JL36ndQ/7rgspdZsJuxDPFIo/OzBT2+GmIJ53BA==", + "version": "1.0.30001610", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001610.tgz", + "integrity": "sha512-QFutAY4NgaelojVMjY63o6XlZyORPaLfyMnsl3HgnWdJUcX6K0oaJymHjH8PT5Gk7sTm8rvC/c5COUQKXqmOMA==", "funding": [ { "type": "opencollective", @@ -5509,14 +5603,14 @@ } }, "node_modules/eslint-config-next": { - "version": "13.5.5", - "resolved": "https://registry.npmjs.org/eslint-config-next/-/eslint-config-next-13.5.5.tgz", - "integrity": "sha512-kQr/eevFyzeVt0yCKTchQp3MTIx8ZmBsAKLW+7bzmAXHcf2vvxIqAt2N/afb9SZpuXXhSb/8yrKQGVUVpYmafQ==", + "version": "14.2.1", + "resolved": "https://registry.npmjs.org/eslint-config-next/-/eslint-config-next-14.2.1.tgz", + "integrity": "sha512-BgD0kPCWMlqoItRf3xe9fG0MqwObKfVch+f2ccwDpZiCJA8ghkz2wrASH+bI6nLZzGcOJOpMm1v1Q1euhfpt4Q==", "dev": true, "dependencies": { - "@next/eslint-plugin-next": "13.5.5", + "@next/eslint-plugin-next": "14.2.1", "@rushstack/eslint-patch": "^1.3.3", - "@typescript-eslint/parser": "^5.4.2 || ^6.0.0", + "@typescript-eslint/parser": "^5.4.2 || ^6.0.0 || 7.0.0 - 7.2.0", "eslint-import-resolver-node": "^0.3.6", "eslint-import-resolver-typescript": "^3.5.2", "eslint-plugin-import": "^2.28.1", @@ -6281,6 +6375,34 @@ "is-callable": "^1.1.3" } }, + "node_modules/foreground-child": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", + "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.0", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/foreground-child/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/fraction.js": { "version": "4.3.7", "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz", @@ -6561,11 +6683,6 @@ "node": ">=10.13.0" } }, - "node_modules/glob-to-regexp": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", - "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==" - }, "node_modules/glob/node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -7609,6 +7726,24 @@ "set-function-name": "^2.0.1" } }, + "node_modules/jackspeak": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz", + "integrity": "sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==", + "dev": true, + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, "node_modules/jest": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest/-/jest-29.7.0.tgz", @@ -8911,6 +9046,15 @@ "node": ">= 6" } }, + "node_modules/minipass": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", + "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", + "dev": true, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, "node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -9024,37 +9168,38 @@ "dev": true }, "node_modules/next": { - "version": "13.5.6", - "resolved": "https://registry.npmjs.org/next/-/next-13.5.6.tgz", - "integrity": "sha512-Y2wTcTbO4WwEsVb4A8VSnOsG1I9ok+h74q0ZdxkwM3EODqrs4pasq7O0iUxbcS9VtWMicG7f3+HAj0r1+NtKSw==", + "version": "14.2.1", + "resolved": "https://registry.npmjs.org/next/-/next-14.2.1.tgz", + "integrity": "sha512-SF3TJnKdH43PMkCcErLPv+x/DY1YCklslk3ZmwaVoyUfDgHKexuKlf9sEfBQ69w+ue8jQ3msLb+hSj1T19hGag==", "dependencies": { - "@next/env": "13.5.6", - "@swc/helpers": "0.5.2", + "@next/env": "14.2.1", + "@swc/helpers": "0.5.5", "busboy": "1.6.0", - "caniuse-lite": "^1.0.30001406", + "caniuse-lite": "^1.0.30001579", + "graceful-fs": "^4.2.11", "postcss": "8.4.31", - "styled-jsx": "5.1.1", - "watchpack": "2.4.0" + "styled-jsx": "5.1.1" }, "bin": { "next": "dist/bin/next" }, "engines": { - "node": ">=16.14.0" + "node": ">=18.17.0" }, "optionalDependencies": { - "@next/swc-darwin-arm64": "13.5.6", - "@next/swc-darwin-x64": "13.5.6", - "@next/swc-linux-arm64-gnu": "13.5.6", - "@next/swc-linux-arm64-musl": "13.5.6", - "@next/swc-linux-x64-gnu": "13.5.6", - "@next/swc-linux-x64-musl": "13.5.6", - "@next/swc-win32-arm64-msvc": "13.5.6", - "@next/swc-win32-ia32-msvc": "13.5.6", - "@next/swc-win32-x64-msvc": "13.5.6" + "@next/swc-darwin-arm64": "14.2.1", + "@next/swc-darwin-x64": "14.2.1", + "@next/swc-linux-arm64-gnu": "14.2.1", + "@next/swc-linux-arm64-musl": "14.2.1", + "@next/swc-linux-x64-gnu": "14.2.1", + "@next/swc-linux-x64-musl": "14.2.1", + "@next/swc-win32-arm64-msvc": "14.2.1", + "@next/swc-win32-ia32-msvc": "14.2.1", + "@next/swc-win32-x64-msvc": "14.2.1" }, "peerDependencies": { "@opentelemetry/api": "^1.1.0", + "@playwright/test": "^1.41.2", "react": "^18.2.0", "react-dom": "^18.2.0", "sass": "^1.3.0" @@ -9063,6 +9208,9 @@ "@opentelemetry/api": { "optional": true }, + "@playwright/test": { + "optional": true + }, "sass": { "optional": true } @@ -9534,6 +9682,31 @@ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "dev": true }, + "node_modules/path-scurry": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.2.tgz", + "integrity": "sha512-7xTavNy5RQXnsjANvVvMkEjvloOinkAjv/Z6Ildz9v2RinZ4SBKTWFOVRbaF8p0vpHnyjV/UwNDdKuUv6M5qcA==", + "dev": true, + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-scurry/node_modules/lru-cache": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.0.tgz", + "integrity": "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==", + "dev": true, + "engines": { + "node": "14 || >=16.14" + } + }, "node_modules/path-type": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", @@ -10958,6 +11131,36 @@ "node": ">=8" } }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/string-width-cjs/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/string-width/node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", @@ -11050,6 +11253,19 @@ "node": ">=8" } }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/strip-bom": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", @@ -11886,18 +12102,6 @@ "makeerror": "1.0.12" } }, - "node_modules/watchpack": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", - "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==", - "dependencies": { - "glob-to-regexp": "^0.4.1", - "graceful-fs": "^4.1.2" - }, - "engines": { - "node": ">=10.13.0" - } - }, "node_modules/wcwidth": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", @@ -12030,6 +12234,24 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", diff --git a/package.json b/package.json index 8935df9a..8a7bb032 100644 --- a/package.json +++ b/package.json @@ -32,12 +32,12 @@ "dotenv": "^16.0.3", "drizzle-orm": "^0.28.5", "drizzle-zod": "^0.5.1", - "next": "^13.5.4", + "next": "^14.2.1", "next-auth": "^4.23.0", "postgres": "^3.3.5", - "react": "18.2.0", + "react": "^18.2.0", "react-day-picker": "^8.9.1", - "react-dom": "18.2.0", + "react-dom": "^18.2.0", "react-hook-form": "^7.48.2", "superjson": "^1.13.1", "zod": "^3.22.4" @@ -49,8 +49,8 @@ "@types/eslint": "^8.44.2", "@types/jest": "^29.5.5", "@types/node": "^18.16.0", - "@types/react": "^18.2.20", - "@types/react-dom": "^18.2.7", + "@types/react": "^18.2.79", + "@types/react-dom": "^18.2.25", "@typescript-eslint/eslint-plugin": "^6.3.0", "@typescript-eslint/parser": "^6.3.0", "autoprefixer": "^10.4.14", @@ -59,7 +59,7 @@ "dotenv-cli": "^7.3.0", "drizzle-kit": "^0.19.13", "eslint": "^8.47.0", - "eslint-config-next": "^13.5.4", + "eslint-config-next": "^14.2.1", "eslint-config-prettier": "^8.5.0", "eslint-plugin-jsx-a11y": "^6.5.1", "eslint-plugin-react": "^7.29.4", From 2cc3120e9ab489ca8e5ce68a0ef7430e6d2208a2 Mon Sep 17 00:00:00 2001 From: Ethan Bickel Date: Tue, 16 Apr 2024 18:11:17 -0500 Subject: [PATCH 20/87] searchParams drilling, might change --- src/app/events/eventView.tsx | 6 ++++-- src/app/events/page.tsx | 4 +--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/app/events/eventView.tsx b/src/app/events/eventView.tsx index a6aa45e0..5fa1ccbe 100644 --- a/src/app/events/eventView.tsx +++ b/src/app/events/eventView.tsx @@ -1,18 +1,20 @@ 'use client'; import DateBrowser from '@src/components/events/DateBrowser'; import EventSidebar from '@src/components/events/EventSidebar'; +import { type eventParamsSchema } from '@src/utils/eventFilter'; import { type ReactNode } from 'react'; type Props = { children: ReactNode; + searchParams: eventParamsSchema; }; -const EventView = ({ children }: Props) => { +const EventView = ({ children, searchParams }: Props) => { return (

Events

- +
diff --git a/src/app/events/page.tsx b/src/app/events/page.tsx index a9c5fc35..bd8dd975 100644 --- a/src/app/events/page.tsx +++ b/src/app/events/page.tsx @@ -1,7 +1,5 @@ import { EventHeader } from '@src/components/BaseHeader'; import { api } from '@src/trpc/server'; -import { type z } from 'zod'; -import { type findByFilterSchema } from '@src/server/api/routers/event'; import EventView from './eventView'; import { type Metadata } from 'next'; import { eventParamsSchema } from '@src/utils/eventFilter'; @@ -32,7 +30,7 @@ const Events = async ({ return (
- + {events.map((event) => { return ; })} From 366b4665307ff1e23f19bd814d19f1c55caa90e6 Mon Sep 17 00:00:00 2001 From: Ethan Bickel Date: Tue, 16 Apr 2024 18:12:17 -0500 Subject: [PATCH 21/87] move to server action for date change --- src/components/events/DateBrowser.tsx | 22 +++++++++------------- src/utils/actions.ts | 4 +++- src/utils/eventFilter.ts | 1 + 3 files changed, 13 insertions(+), 14 deletions(-) diff --git a/src/components/events/DateBrowser.tsx b/src/components/events/DateBrowser.tsx index 10507d53..9eee6747 100644 --- a/src/components/events/DateBrowser.tsx +++ b/src/components/events/DateBrowser.tsx @@ -1,5 +1,7 @@ 'use client'; +import 'react-day-picker/dist/style.css'; +import { LeftArrowIcon, RightArrowIcon } from '@src/icons/Icons'; import { DayPicker, useInput } from 'react-day-picker'; import { Popover, @@ -8,31 +10,25 @@ import { PopoverPortal, PopoverTrigger, } from '@radix-ui/react-popover'; - -import 'react-day-picker/dist/style.css'; import { addDays, subDays } from 'date-fns'; -import { LeftArrowIcon, RightArrowIcon } from '@src/icons/Icons'; -import { eventParamsSchema } from '@src/utils/eventFilter'; -import useSearch from '@src/utils/useSearch'; +import { type eventParamsSchema } from '@src/utils/eventFilter'; import { eventTimeUpdate } from '@src/utils/actions'; -const DateBrowser = () => { +const DateBrowser = ({ filterState }: { filterState: eventParamsSchema }) => { + const changeTime = eventTimeUpdate.bind(null, filterState); const { inputProps, dayPickerProps, setSelected } = useInput({ defaultSelected: new Date(), }); - const [filterState] = useSearch(eventParamsSchema); - const changeDate = eventTimeUpdate.bind(null, filterState); - return (
{/* eslint-disable-next-line @typescript-eslint/no-misused-promises */} -
+
- - - - - - - - - - - - - + + + + + + + + + + + + +
); }; diff --git a/src/components/events/EventSidebar.tsx b/src/components/events/EventSidebar.tsx index 37078a67..66bfc203 100644 --- a/src/components/events/EventSidebar.tsx +++ b/src/components/events/EventSidebar.tsx @@ -7,82 +7,72 @@ import { import { EventClubSearchBar } from '../SearchBar'; import { api } from '@src/trpc/react'; import { type eventParamsSchema, order } from '@src/utils/eventFilter'; -import { useEffect, useRef, useState } from 'react'; +import { useState } from 'react'; import { ExpandLess, ExpandMore } from '@src/icons/Icons'; -import { eventFilterUpdate } from '@src/app/actions'; +import { type useSyncedSearchParamsDispatch } from '@src/utils/useSyncedSearchParams'; export const basicFilters = [ 'Upcoming Events', 'Last weeks events', 'Last month events', ] as const; -const Filters = ({ filterState }: { filterState: eventParamsSchema }) => { - const [clubs, setClubs] = useState(filterState.clubs); - const eventFilterChange = eventFilterUpdate.bind(null, filterState, clubs); - const formRef = useRef(null); - useEffect(() => { - if ( - !( - clubs.every((val) => filterState.clubs.includes(val)) && - filterState.clubs.every((val) => clubs.includes(val)) - ) - ) - formRef.current?.requestSubmit(); - }, [clubs]); - +type FilterProps = { + filterState: eventParamsSchema; + setParams: useSyncedSearchParamsDispatch; +}; +const Filters = ({ filterState, setParams }: FilterProps) => { return (
- {/* eslint-disable-next-line @typescript-eslint/no-misused-promises */} -
-
-

Search for Club

-
- { - setClubs([...clubs, val]); - }} - /> -
- {filterState.clubs.map((value) => ( - { - const temp = clubs.filter((c) => c !== value); - setClubs(temp); - }} - /> - ))} -
-
-
-
-

Arrange Events

- formRef.current?.requestSubmit()} - > - {order.map((value) => ( - +

Search for Club

+
+ { + setParams({ clubs: [...filterState.clubs, val] }); + }} + /> +
+ {filterState.clubs.map((value) => ( + -
-
- -
-

- {value} -

-
- + clubId={value} + removeClub={() => { + const temp = filterState.clubs.filter((c) => c !== value); + setParams({ clubs: temp }); + }} + /> ))} - +
- +
+
+

Arrange Events

+ { + setParams({ order: val }); + }} + > + {order.map((value) => ( + +
+
+ +
+

+ {value} +

+
+
+ ))} +
+
); }; @@ -113,7 +103,7 @@ const SelectedClub = ({
); }; -const EventSidebar = ({ filterState }: { filterState: eventParamsSchema }) => { +const EventSidebar = ({ filterState, setParams }: FilterProps) => { const [open, setOpen] = useState(true); return (
@@ -130,7 +120,7 @@ const EventSidebar = ({ filterState }: { filterState: eventParamsSchema }) => { className="hidden overflow-clip data-[open=true]:contents sm:contents" >
- +
diff --git a/src/utils/useSyncedSearchParams.ts b/src/utils/useSyncedSearchParams.ts new file mode 100644 index 00000000..2e479e4f --- /dev/null +++ b/src/utils/useSyncedSearchParams.ts @@ -0,0 +1,21 @@ +import { useRouter } from 'next/navigation'; +import { useReducer } from 'react'; +import EncodeParams from './encodeParams'; + +// not sure about the name, but basically makes updates to searchparams not overwrite themselves +const useSyncedSearchParams = >( + searchParams: T, + route: string, +) => { + const router = useRouter(); + const [params, setParams] = useReducer((state: T, action: Partial) => { + const temp = { ...state, ...action }; + router.push(`${route}?${EncodeParams(temp)}`); + return temp; + }, searchParams); + return [params, setParams] as const; +}; +export default useSyncedSearchParams; + +export type useSyncedSearchParamsDispatch> = + ReturnType>[1]; From 3712df34b3c2738753e4388faf1aed8aa7493a52 Mon Sep 17 00:00:00 2001 From: Ethan Bickel Date: Wed, 24 Apr 2024 15:03:41 -0500 Subject: [PATCH 27/87] fix lint issues --- src/app/actions.ts | 31 -------------------------- src/app/events/eventView.tsx | 4 ++-- src/components/SearchBar.tsx | 2 ++ src/components/events/EventSidebar.tsx | 2 +- src/utils/useSyncedSearchParams.ts | 1 + 5 files changed, 6 insertions(+), 34 deletions(-) delete mode 100644 src/app/actions.ts diff --git a/src/app/actions.ts b/src/app/actions.ts deleted file mode 100644 index baab6d41..00000000 --- a/src/app/actions.ts +++ /dev/null @@ -1,31 +0,0 @@ -'use server'; -/* eslint-disable @typescript-eslint/require-await */ - -import { isDate } from 'util/types'; -import { redirect } from 'next/navigation'; -import { parse } from 'date-fns'; -import { z } from 'zod'; -import { type eventParamsSchema, order } from '@src/utils/eventFilter'; -import EncodeParams from '@src/utils/encodeParams'; - -const FilterSchema = z.object({ - clubs: z.string().array(), - order: z.enum(order), -}); - -export async function eventFilterUpdate( - queryParams: eventParamsSchema, - clubs: string[], - formData: FormData, -) { - const parsed = FilterSchema.safeParse({ - clubs: clubs, - order: formData.get('order'), - }); - if (parsed.success) { - queryParams.clubs = parsed.data.clubs; - queryParams.order = parsed.data.order; - const newQuery = EncodeParams(queryParams); - redirect(`/events?${newQuery}`); - } -} diff --git a/src/app/events/eventView.tsx b/src/app/events/eventView.tsx index e7799454..e589e1da 100644 --- a/src/app/events/eventView.tsx +++ b/src/app/events/eventView.tsx @@ -16,11 +16,11 @@ const EventView = ({ children, searchParams }: Props) => {

Events

- +
- +
{ const [search, setSearch] = useState(''); const [res, setRes] = useState([]); + const utils = api.useUtils(); const clubQuery = api.club.byName.useQuery( { name: search }, { @@ -152,6 +153,7 @@ export const EventClubSearchBar = ({ addClub }: EventClubSearchBarProps) => { value={search} searchResults={res} onClick={(club) => { + void utils.club.byId.prefetch({ id: club.id }); addClub(club.id); setSearch(''); }} diff --git a/src/components/events/EventSidebar.tsx b/src/components/events/EventSidebar.tsx index 66bfc203..b5936453 100644 --- a/src/components/events/EventSidebar.tsx +++ b/src/components/events/EventSidebar.tsx @@ -24,7 +24,7 @@ const Filters = ({ filterState, setParams }: FilterProps) => { return (
-

Search for Club

+

Filter by Clubs

{ diff --git a/src/utils/useSyncedSearchParams.ts b/src/utils/useSyncedSearchParams.ts index 2e479e4f..1ae3c109 100644 --- a/src/utils/useSyncedSearchParams.ts +++ b/src/utils/useSyncedSearchParams.ts @@ -1,3 +1,4 @@ +'use client'; import { useRouter } from 'next/navigation'; import { useReducer } from 'react'; import EncodeParams from './encodeParams'; From 4829159e8dac41fa002f88ec62a2828734b7a8cf Mon Sep 17 00:00:00 2001 From: Ethan Bickel Date: Tue, 27 Aug 2024 13:14:47 -0500 Subject: [PATCH 28/87] remove sidebar and improve styling for mobile other css --- src/app/events/eventView.tsx | 16 +++++++++------- src/components/events/DateBrowser.tsx | 2 +- src/styles/globals.css | 6 ++++++ 3 files changed, 16 insertions(+), 8 deletions(-) diff --git a/src/app/events/eventView.tsx b/src/app/events/eventView.tsx index e589e1da..49493e86 100644 --- a/src/app/events/eventView.tsx +++ b/src/app/events/eventView.tsx @@ -1,6 +1,5 @@ 'use client'; import DateBrowser from '@src/components/events/DateBrowser'; -import EventSidebar from '@src/components/events/EventSidebar'; import { type eventParamsSchema } from '@src/utils/eventFilter'; import useSyncedSearchParams from '@src/utils/useSyncedSearchParams'; import { type ReactNode } from 'react'; @@ -13,17 +12,20 @@ const EventView = ({ children, searchParams }: Props) => { const [params, setParams] = useSyncedSearchParams(searchParams, '/events'); return (
-
-

Events

-
+
+

+ Events +

+
-
- +
{children}
diff --git a/src/components/events/DateBrowser.tsx b/src/components/events/DateBrowser.tsx index 9f468c3c..952dcabb 100644 --- a/src/components/events/DateBrowser.tsx +++ b/src/components/events/DateBrowser.tsx @@ -28,7 +28,7 @@ const DateBrowser = ({ filterState, setParams }: DateBrowserProps) => { } }, [dayPickerProps.selected]); return ( -
+
{/* eslint-disable-next-line @typescript-eslint/no-misused-promises */} -
- ); -}; -const EventSidebar = ({ filterState, setParams }: FilterProps) => { - const [open, setOpen] = useState(true); - return ( -
- -
-
- -
-
-
- ); -}; -export default EventSidebar; From b54d335094961b4addcb361a088600a09483ddd1 Mon Sep 17 00:00:00 2001 From: Ethan Bickel Date: Tue, 27 Aug 2024 13:45:37 -0500 Subject: [PATCH 31/87] add CODEOWNERS --- CODEOWNERS | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 CODEOWNERS diff --git a/CODEOWNERS b/CODEOWNERS new file mode 100644 index 00000000..6074e0fd --- /dev/null +++ b/CODEOWNERS @@ -0,0 +1,3 @@ +# for now project lead should signoff on any prs +# current project lead: Ethan Bickel +* @nl32 From 986b9c053b3ce326eb28db5aa2709e84c2a8b3f5 Mon Sep 17 00:00:00 2001 From: Ethan Bickel Date: Tue, 27 Aug 2024 13:50:51 -0500 Subject: [PATCH 32/87] add engineering head --- CODEOWNERS | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/CODEOWNERS b/CODEOWNERS index 6074e0fd..ac762077 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -1,3 +1,2 @@ -# for now project lead should signoff on any prs -# current project lead: Ethan Bickel -* @nl32 +# for now project lead or engineering head should signoff on any prs +* @nl32 @KennethImphean From 23801ba507030a1ac26d2a31c855e93327a2b75f Mon Sep 17 00:00:00 2001 From: Ethan Bickel Date: Tue, 3 Sep 2024 12:44:55 -0500 Subject: [PATCH 33/87] switch tag query to use new tag view --- src/server/api/routers/club.ts | 14 +++++--------- src/server/db/schema/club.ts | 14 +++++++++++++- src/server/db/tagView.sql | 6 ++++++ 3 files changed, 24 insertions(+), 10 deletions(-) create mode 100644 src/server/db/tagView.sql diff --git a/src/server/api/routers/club.ts b/src/server/api/routers/club.ts index ce62811e..ee13dbdb 100644 --- a/src/server/api/routers/club.ts +++ b/src/server/api/routers/club.ts @@ -14,7 +14,7 @@ import { z } from 'zod'; import { selectContact } from '@src/server/db/models'; import { clubEditRouter } from './clubEdit'; import { userMetadataToClubs } from '@src/server/db/schema/users'; -import { club } from '@src/server/db/schema/club'; +import { club, usedTags } from '@src/server/db/schema/club'; import { contacts } from '@src/server/db/schema/contacts'; import { carousel } from '@src/server/db/schema/admin'; const byNameSchema = z.object({ @@ -119,14 +119,10 @@ export const clubRouter = createTRPCRouter({ }), distinctTags: publicProcedure.query(async ({ ctx }) => { try { - const tags = await ctx.db.selectDistinct({ tags: club.tags }).from(club); - const tagSet = new Set(['All']); - tags.forEach((club) => { - club.tags.forEach((tag) => { - tagSet.add(tag); - }); - }); - return Array.from(tagSet); + const tags = (await ctx.db.select().from(usedTags)).map( + (obj) => obj.tags, + ); + return tags; } catch (e) { console.error(e); return []; diff --git a/src/server/db/schema/club.ts b/src/server/db/schema/club.ts index a717e9ef..52f632c4 100644 --- a/src/server/db/schema/club.ts +++ b/src/server/db/schema/club.ts @@ -1,5 +1,12 @@ import { relations, sql } from 'drizzle-orm'; -import { boolean, pgEnum, pgTable, text } from 'drizzle-orm/pg-core'; +import { + boolean, + integer, + pgEnum, + pgTable, + pgView, + text, +} from 'drizzle-orm/pg-core'; import { events } from './events'; import { userMetadataToClubs } from './users'; import { contacts } from './contacts'; @@ -35,3 +42,8 @@ export const clubRelations = relations(club, ({ many }) => ({ userMetadataToClubs: many(userMetadataToClubs), carousel: many(carousel), })); + +export const usedTags = pgView('used_tags', { + tags: text('tags').notNull(), + count: integer('count').notNull(), +}).existing(); diff --git a/src/server/db/tagView.sql b/src/server/db/tagView.sql new file mode 100644 index 00000000..88f626ee --- /dev/null +++ b/src/server/db/tagView.sql @@ -0,0 +1,6 @@ +select distinct UNNEST(tags) as tags, +count(tags) +from +club +group by unnest(tags) +order by count desc From 525cf97261c2ea4181b457720f0f6d2518efa52b Mon Sep 17 00:00:00 2001 From: Ethan Bickel Date: Tue, 3 Sep 2024 12:49:58 -0500 Subject: [PATCH 34/87] update read me to have new database setup instructions --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index a8df8cb9..bc92abb4 100644 --- a/README.md +++ b/README.md @@ -105,6 +105,10 @@ $$; Currently, drizzle does not automatically create enums for you. You will have to create them manually. This [link](https://orm.drizzle.team/docs/column-types/pg#enum) should give you a good idea of how to create enums in postgres.
+
+Tag View + there is a sql query in `src/server/db/tagView.sql` that you need to run in order for tags to work properly. +
Once you have added the `DATABASE_URL` to your `.env` file, and have all the necessary extensions as well as enums, you will need to run the following commands to create the tables in your database. From 38442d70466b5f3d8dfa33da21afa4586c064994 Mon Sep 17 00:00:00 2001 From: Ethan Bickel Date: Tue, 3 Sep 2024 14:06:54 -0500 Subject: [PATCH 35/87] Update README.md move line break for database setup sections --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index bc92abb4..207103db 100644 --- a/README.md +++ b/README.md @@ -104,11 +104,11 @@ $$; Currently, drizzle does not automatically create enums for you. You will have to create them manually. This [link](https://orm.drizzle.team/docs/column-types/pg#enum) should give you a good idea of how to create enums in postgres. -
+
Tag View there is a sql query in `src/server/db/tagView.sql` that you need to run in order for tags to work properly. -
+
Once you have added the `DATABASE_URL` to your `.env` file, and have all the necessary extensions as well as enums, you will need to run the following commands to create the tables in your database. From fad65913dcd353a7531bc44b9f722b26caea1084 Mon Sep 17 00:00:00 2001 From: BK2004 Date: Sun, 8 Sep 2024 12:43:08 -0500 Subject: [PATCH 36/87] event picture select grayed out; select start and end time by date only --- .../[clubId]/create/CreateEventForm.tsx | 4 +- src/app/manage/[clubId]/create/TimeSelect.tsx | 55 +++---------------- 2 files changed, 12 insertions(+), 47 deletions(-) diff --git a/src/app/manage/[clubId]/create/CreateEventForm.tsx b/src/app/manage/[clubId]/create/CreateEventForm.tsx index 70168b22..28542274 100644 --- a/src/app/manage/[clubId]/create/CreateEventForm.tsx +++ b/src/app/manage/[clubId]/create/CreateEventForm.tsx @@ -24,6 +24,8 @@ const CreateEventForm = ({ clubId, officerClubs }: { clubId: string, officerClub resolver: zodResolver(createEventSchema), defaultValues: { clubId: clubId, + startTime: new Date(Date.now()), + endTime: new Date(Date.now()), }, mode: "onSubmit", }); @@ -89,7 +91,7 @@ const CreateEventForm = ({ clubId, officerClubs }: { clubId: string, officerClub

Event Picture

Drag or choose file to upload

-
+

JPEG, PNG, or SVG

diff --git a/src/app/manage/[clubId]/create/TimeSelect.tsx b/src/app/manage/[clubId]/create/TimeSelect.tsx index 05ea7d24..820a6770 100644 --- a/src/app/manage/[clubId]/create/TimeSelect.tsx +++ b/src/app/manage/[clubId]/create/TimeSelect.tsx @@ -16,69 +16,32 @@ interface Props { } 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'))) { + if ((new Date(watchStartTime) > new Date(getValues('endTime')))) { setValue('endTime', watchStartTime); } - }, [setValue, getValues, watchStartTime, multiDay, numHours]) + }, [setValue, getValues, watchStartTime]) 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()} + min={watchStartTime?.toString()} className="outline-none w-full block p-2 text-xs rounded-md text-[#7D8FB3]" />
- : -
- - -
- }
); } From 57d094569769c56b0008b0f323f0ee8d12d4a209 Mon Sep 17 00:00:00 2001 From: BK2004 Date: Sun, 8 Sep 2024 12:52:00 -0500 Subject: [PATCH 37/87] end time defaults to start time when empty in TimeSelect --- src/app/manage/[clubId]/create/CreateEventForm.tsx | 2 -- src/app/manage/[clubId]/create/TimeSelect.tsx | 4 +++- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/app/manage/[clubId]/create/CreateEventForm.tsx b/src/app/manage/[clubId]/create/CreateEventForm.tsx index 28542274..d2117976 100644 --- a/src/app/manage/[clubId]/create/CreateEventForm.tsx +++ b/src/app/manage/[clubId]/create/CreateEventForm.tsx @@ -24,8 +24,6 @@ const CreateEventForm = ({ clubId, officerClubs }: { clubId: string, officerClub resolver: zodResolver(createEventSchema), defaultValues: { clubId: clubId, - startTime: new Date(Date.now()), - endTime: new Date(Date.now()), }, mode: "onSubmit", }); diff --git a/src/app/manage/[clubId]/create/TimeSelect.tsx b/src/app/manage/[clubId]/create/TimeSelect.tsx index 820a6770..af30988a 100644 --- a/src/app/manage/[clubId]/create/TimeSelect.tsx +++ b/src/app/manage/[clubId]/create/TimeSelect.tsx @@ -18,7 +18,9 @@ interface Props { const TimeSelect = ({ register, setValue, getValues, watchStartTime }: Props) => { useEffect(() => { // If start time is after end time, set end time to start time - if ((new Date(watchStartTime) > new Date(getValues('endTime')))) { + console.log(getValues("endTime")); + if ((new Date(watchStartTime) > new Date(getValues('endTime'))) + || (watchStartTime !== undefined && getValues('endTime').toString() === "")) { setValue('endTime', watchStartTime); } }, [setValue, getValues, watchStartTime]) From 5962921bd7c674c52c91e092fe0299161a51ea18 Mon Sep 17 00:00:00 2001 From: BK2004 Date: Sun, 8 Sep 2024 13:10:48 -0500 Subject: [PATCH 38/87] Create API route returns event id; successful event creation redirects to event page; added protection against create event spam while redirecting --- src/app/manage/[clubId]/create/CreateEventForm.tsx | 8 ++++++-- src/server/api/routers/event.ts | 4 +++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/app/manage/[clubId]/create/CreateEventForm.tsx b/src/app/manage/[clubId]/create/CreateEventForm.tsx index d2117976..95da69d6 100644 --- a/src/app/manage/[clubId]/create/CreateEventForm.tsx +++ b/src/app/manage/[clubId]/create/CreateEventForm.tsx @@ -29,6 +29,7 @@ const CreateEventForm = ({ clubId, officerClubs }: { clubId: string, officerClub }); const router = useRouter(); const [watchDescription, watchStartTime] = watch(['description', 'startTime']); + const [redirecting, setRedirecting] = useState(false); const [eventPreview, setEventPreview] = useState({ name: "", clubId, @@ -65,11 +66,14 @@ const CreateEventForm = ({ clubId, officerClubs }: { clubId: string, officerClub }, [router, watch, officerClubs]); const createMutation = api.event.create.useMutation({ - onSuccess: () => { location.reload(); } + onSuccess: (data) => { if (data) { + setRedirecting(true); + router.push(`/event/${data}`); + } } }) const onSubmit = handleSubmit((data: z.infer) => { - if (!createMutation.isPending) { + if (!createMutation.isPending && !redirecting) { createMutation.mutate(data); } }); diff --git a/src/server/api/routers/event.ts b/src/server/api/routers/event.ts index e883f40e..454af6e4 100644 --- a/src/server/api/routers/event.ts +++ b/src/server/api/routers/event.ts @@ -262,7 +262,9 @@ 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; From 518ef41b8079430b9d6b55c20d12024112dfc3e6 Mon Sep 17 00:00:00 2001 From: BK2004 Date: Sun, 8 Sep 2024 13:12:24 -0500 Subject: [PATCH 39/87] remove unused dependency --- src/app/manage/[clubId]/create/TimeSelect.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/manage/[clubId]/create/TimeSelect.tsx b/src/app/manage/[clubId]/create/TimeSelect.tsx index af30988a..b446831a 100644 --- a/src/app/manage/[clubId]/create/TimeSelect.tsx +++ b/src/app/manage/[clubId]/create/TimeSelect.tsx @@ -1,5 +1,5 @@ 'use client' -import { useEffect, useState } from "react"; +import { useEffect } from "react"; import type { UseFormRegister, UseFormSetValue, From 7fd2d73e3fb50fa93cad68d0c00a538a4cd1fa60 Mon Sep 17 00:00:00 2001 From: Ethan Bickel Date: Tue, 10 Sep 2024 13:42:33 -0500 Subject: [PATCH 40/87] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 207103db..d547e0a1 100644 --- a/README.md +++ b/README.md @@ -108,6 +108,7 @@ Currently, drizzle does not automatically create enums for you. You will have to
Tag View there is a sql query in `src/server/db/tagView.sql` that you need to run in order for tags to work properly. + This query sets up a view that queries the different tags from clubs and orders them by how many clubs have those tags in descending order.

Once you have added the `DATABASE_URL` to your `.env` file, and have all the necessary extensions as well as enums, you will need to run the following commands to create the tables in your database. From d91f446a4d783c196d5207b0880fab8567f7cfe6 Mon Sep 17 00:00:00 2001 From: BK2004 Date: Thu, 19 Sep 2024 20:12:34 -0500 Subject: [PATCH 41/87] start time updates end time to start time + one hour if needed; grayed out create event button while processing --- .../[clubId]/create/CreateEventForm.tsx | 24 ++++--- src/app/manage/[clubId]/create/TimeSelect.tsx | 63 ++++++++++++------- 2 files changed, 57 insertions(+), 30 deletions(-) diff --git a/src/app/manage/[clubId]/create/CreateEventForm.tsx b/src/app/manage/[clubId]/create/CreateEventForm.tsx index 95da69d6..b257eedb 100644 --- a/src/app/manage/[clubId]/create/CreateEventForm.tsx +++ b/src/app/manage/[clubId]/create/CreateEventForm.tsx @@ -20,6 +20,7 @@ const CreateEventForm = ({ clubId, officerClubs }: { clubId: string, officerClub watch, setValue, getValues, + control, } = useForm>({ resolver: zodResolver(createEventSchema), defaultValues: { @@ -29,7 +30,7 @@ const CreateEventForm = ({ clubId, officerClubs }: { clubId: string, officerClub }); const router = useRouter(); const [watchDescription, watchStartTime] = watch(['description', 'startTime']); - const [redirecting, setRedirecting] = useState(false); + const [loading, setLoading] = useState(false); const [eventPreview, setEventPreview] = useState({ name: "", clubId, @@ -53,8 +54,8 @@ const CreateEventForm = ({ clubId, officerClubs }: { clubId: string, officerClub 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), + 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, }); } @@ -67,13 +68,16 @@ const CreateEventForm = ({ clubId, officerClubs }: { clubId: string, officerClub const createMutation = api.event.create.useMutation({ onSuccess: (data) => { if (data) { - setRedirecting(true); router.push(`/event/${data}`); - } } + } }, + onError: (e) => { + setLoading(false); + } }) const onSubmit = handleSubmit((data: z.infer) => { - if (!createMutation.isPending && !redirecting) { + if (!createMutation.isPending && !loading) { + setLoading(true); createMutation.mutate(data); } }); @@ -122,8 +126,12 @@ const CreateEventForm = ({ clubId, officerClubs }: { clubId: string, officerClub placeholder="Event description" />
- - + +

Preview

diff --git a/src/app/manage/[clubId]/create/TimeSelect.tsx b/src/app/manage/[clubId]/create/TimeSelect.tsx index b446831a..9674b2aa 100644 --- a/src/app/manage/[clubId]/create/TimeSelect.tsx +++ b/src/app/manage/[clubId]/create/TimeSelect.tsx @@ -1,48 +1,67 @@ 'use client' -import { useEffect } from "react"; import type { UseFormRegister, 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, + control: Control>, } -const TimeSelect = ({ register, setValue, getValues, watchStartTime }: Props) => { - useEffect(() => { - // If start time is after end time, set end time to start time - console.log(getValues("endTime")); - if ((new Date(watchStartTime) > new Date(getValues('endTime'))) - || (watchStartTime !== undefined && getValues('endTime').toString() === "")) { - setValue('endTime', watchStartTime); - } - }, [setValue, getValues, watchStartTime]) - +const TimeSelect = ({ setValue, getValues, watchStartTime, control }: Props) => { return (<>

Duration

- + ( + { + if (!getValues("endTime") || new Date(e.currentTarget.value) > getValues("endTime")) { + // Add 1 hr to new start time + setValue("endTime", new Date(new Date(e.currentTarget.value).getTime() + 60 * 60 * 1000)); + } + onChange(new Date(e.currentTarget.value)); + }} + className="outline-none w-full block p-2 text-xs rounded-md text-[#7D8FB3]" /> + )} + rules={{ + required: true, + }} />
- { 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]" - /> + ( + onChange(new Date(e.currentTarget.value))} + className="outline-none w-full block p-2 text-xs rounded-md text-[#7D8FB3]" /> + )} + rules={{ + required: true, + }} />
); From 8c41e9a3085bb13e63761f5dc7acde1c62dd8d9c Mon Sep 17 00:00:00 2001 From: BK2004 Date: Thu, 19 Sep 2024 20:14:38 -0500 Subject: [PATCH 42/87] fixed build errors --- src/app/manage/[clubId]/create/CreateEventForm.tsx | 2 +- src/app/manage/[clubId]/create/TimeSelect.tsx | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/app/manage/[clubId]/create/CreateEventForm.tsx b/src/app/manage/[clubId]/create/CreateEventForm.tsx index b257eedb..fb3fbf0e 100644 --- a/src/app/manage/[clubId]/create/CreateEventForm.tsx +++ b/src/app/manage/[clubId]/create/CreateEventForm.tsx @@ -70,7 +70,7 @@ const CreateEventForm = ({ clubId, officerClubs }: { clubId: string, officerClub onSuccess: (data) => { if (data) { router.push(`/event/${data}`); } }, - onError: (e) => { + onError: () => { setLoading(false); } }) diff --git a/src/app/manage/[clubId]/create/TimeSelect.tsx b/src/app/manage/[clubId]/create/TimeSelect.tsx index 9674b2aa..4e9f942a 100644 --- a/src/app/manage/[clubId]/create/TimeSelect.tsx +++ b/src/app/manage/[clubId]/create/TimeSelect.tsx @@ -1,6 +1,5 @@ 'use client' import type { - UseFormRegister, UseFormSetValue, UseFormGetValues, Control From 95d66591f0da45ef80793e32e65a6387e34d63fd Mon Sep 17 00:00:00 2001 From: Ethan Bickel Date: Mon, 30 Sep 2024 09:05:36 -0500 Subject: [PATCH 43/87] seperate different search bars each search bar is now it's own file --- .../edit/officers/EditOfficerForm.tsx | 2 +- src/components/BaseHeader.tsx | 3 +- src/components/OfficerSelector.tsx | 2 +- src/components/SearchBar.tsx | 198 ------------------ src/components/admin/AddOfficer.tsx | 2 +- src/components/admin/OrgSearch.tsx | 4 +- src/components/searchBar/ClubSearchBar.tsx | 26 +++ .../searchBar/DebouncedSearchBar.tsx | 69 ++++++ .../searchBar/EventClubSearchBar.tsx | 38 ++++ src/components/searchBar/EventSearchBar.tsx | 34 +++ src/components/searchBar/UserSearchBar.tsx | 42 ++++ src/components/searchBar/index.tsx | 20 ++ 12 files changed, 236 insertions(+), 204 deletions(-) delete mode 100644 src/components/SearchBar.tsx create mode 100644 src/components/searchBar/ClubSearchBar.tsx create mode 100644 src/components/searchBar/DebouncedSearchBar.tsx create mode 100644 src/components/searchBar/EventClubSearchBar.tsx create mode 100644 src/components/searchBar/EventSearchBar.tsx create mode 100644 src/components/searchBar/UserSearchBar.tsx create mode 100644 src/components/searchBar/index.tsx 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/components/BaseHeader.tsx b/src/components/BaseHeader.tsx index 93d0a874..ac43c322 100644 --- a/src/components/BaseHeader.tsx +++ b/src/components/BaseHeader.tsx @@ -1,7 +1,8 @@ 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 { api } from '@src/trpc/server'; diff --git a/src/components/OfficerSelector.tsx b/src/components/OfficerSelector.tsx index 230828fa..b40a7e57 100644 --- a/src/components/OfficerSelector.tsx +++ b/src/components/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 './searchBar/UserSearchBar'; type OfficerSelectorProps = { control: Control>; 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/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/OrgSearch.tsx b/src/components/admin/OrgSearch.tsx index 505a710f..9caf805d 100644 --- a/src/components/admin/OrgSearch.tsx +++ b/src/components/admin/OrgSearch.tsx @@ -2,7 +2,7 @@ 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 = { @@ -21,7 +21,7 @@ export default function OrgSearch({ setOrg }: Props) { setSearch(''); }; return ( - { + 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 ( + + ); +}; diff --git a/src/components/searchBar/DebouncedSearchBar.tsx b/src/components/searchBar/DebouncedSearchBar.tsx new file mode 100644 index 00000000..395f898c --- /dev/null +++ b/src/components/searchBar/DebouncedSearchBar.tsx @@ -0,0 +1,69 @@ +'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; +}; +export const DebouncedSearchBar = ({ + placeholder, + value, + setSearch, + searchResults, + onClick, +}: 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)} + /> + {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..afce98f5 --- /dev/null +++ b/src/components/searchBar/EventClubSearchBar.tsx @@ -0,0 +1,38 @@ +'use client'; +import { useState, useEffect } 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 [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(''); + }} + /> + ); +}; diff --git a/src/components/searchBar/EventSearchBar.tsx b/src/components/searchBar/EventSearchBar.tsx new file mode 100644 index 00000000..04adb555 --- /dev/null +++ b/src/components/searchBar/EventSearchBar.tsx @@ -0,0 +1,34 @@ +'use client'; +import { useState, useEffect } 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 [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}`); + }} + /> + ); +}; diff --git a/src/components/searchBar/UserSearchBar.tsx b/src/components/searchBar/UserSearchBar.tsx new file mode 100644 index 00000000..487d4f40 --- /dev/null +++ b/src/components/searchBar/UserSearchBar.tsx @@ -0,0 +1,42 @@ +'use client'; +import { type SelectUserMetadata } from '@src/server/db/models'; +import { api } from '@src/trpc/react'; +import { useState, useEffect } from 'react'; +import { DebouncedSearchBar } from './DebouncedSearchBar'; + +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/searchBar/index.tsx b/src/components/searchBar/index.tsx new file mode 100644 index 00000000..2fbe4389 --- /dev/null +++ b/src/components/searchBar/index.tsx @@ -0,0 +1,20 @@ +import { SearchIcon } from '@src/icons/Icons'; +import { ComponentProps } from 'react'; + +type SearchBarProps = Omit, 'type'>; + +export const SearchBar = (props: SearchBarProps) => { + return ( +
+ + + + +
+ ); +}; +export default SearchBar; From 322ec200a462fa3082451c2100eedede313c1029 Mon Sep 17 00:00:00 2001 From: Ethan Bickel Date: Mon, 30 Sep 2024 09:08:32 -0500 Subject: [PATCH 44/87] relocate EventLikeButton --- src/components/events/EventCard.tsx | 2 +- src/components/{ => events}/EventLikeButton.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename src/components/{ => events}/EventLikeButton.tsx (94%) diff --git a/src/components/events/EventCard.tsx b/src/components/events/EventCard.tsx index 75008289..091256fa 100644 --- a/src/components/events/EventCard.tsx +++ b/src/components/events/EventCard.tsx @@ -4,7 +4,7 @@ import Image from 'next/image'; import Link from 'next/link'; import { MoreIcon } from '../../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..a22b05a4 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 '../../icons/Icons'; import { api } from '@src/trpc/react'; import { useRouter } from 'next/navigation'; From 2d31a147db18bd54beb18dc8a56ed4bf6958ac8c Mon Sep 17 00:00:00 2001 From: Ethan Bickel Date: Mon, 30 Sep 2024 09:14:50 -0500 Subject: [PATCH 45/87] relocate sidebar/nav to own folder --- src/app/layout.tsx | 2 +- src/components/BaseHeader.tsx | 2 +- src/components/{ => nav}/MobileNav.tsx | 0 src/components/{ => nav}/NavMenu.tsx | 0 src/components/{ => nav}/Sidebar.tsx | 0 src/components/{ => nav}/SidebarItems.tsx | 2 +- 6 files changed, 3 insertions(+), 3 deletions(-) rename src/components/{ => nav}/MobileNav.tsx (100%) rename src/components/{ => nav}/NavMenu.tsx (100%) rename src/components/{ => nav}/Sidebar.tsx (100%) rename src/components/{ => nav}/SidebarItems.tsx (97%) 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/components/BaseHeader.tsx b/src/components/BaseHeader.tsx index ac43c322..1d8e0c48 100644 --- a/src/components/BaseHeader.tsx +++ b/src/components/BaseHeader.tsx @@ -4,7 +4,7 @@ import { getServerAuthSession } from '@src/server/auth'; 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/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..fdf1cc89 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 '../../icons/Icons'; const SidebarItems: FC<{ cat: allCats[number] }> = ({ cat }) => { const Icon = IconMap[cat]; From 07661b41feedd4d477847a72568604346cd63487 Mon Sep 17 00:00:00 2001 From: Ethan Bickel Date: Mon, 30 Sep 2024 10:25:18 -0500 Subject: [PATCH 46/87] relocate ClubSelector --- src/components/{ => settings}/ClubSelector.tsx | 0 src/components/settings/FormCard.tsx | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename src/components/{ => settings}/ClubSelector.tsx (100%) 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'; From 1b34d4caf4d4dd965d77a495b9b179d4b9247596 Mon Sep 17 00:00:00 2001 From: Ethan Bickel Date: Mon, 30 Sep 2024 11:01:26 -0500 Subject: [PATCH 47/87] relocate ProviderButtons since it's only used for sign in --- src/{components => app/auth}/ProviderButtons.tsx | 0 src/app/auth/page.tsx | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename src/{components => app/auth}/ProviderButtons.tsx (100%) diff --git a/src/components/ProviderButtons.tsx b/src/app/auth/ProviderButtons.tsx similarity index 100% rename from src/components/ProviderButtons.tsx rename to src/app/auth/ProviderButtons.tsx diff --git a/src/app/auth/page.tsx b/src/app/auth/page.tsx index 72370832..02bdf246 100644 --- a/src/app/auth/page.tsx +++ b/src/app/auth/page.tsx @@ -1,4 +1,4 @@ -import ProviderButton from '@src/components/ProviderButtons'; +import ProviderButton from '@src/app/auth/ProviderButtons'; import { getServerAuthSession } from '@src/server/auth'; import { getProviders } from 'next-auth/react'; import { redirect } from 'next/navigation'; From bd87f3066f876f9187d4e12e161e735fc799f1f9 Mon Sep 17 00:00:00 2001 From: Ethan Bickel Date: Mon, 30 Sep 2024 11:02:22 -0500 Subject: [PATCH 48/87] relocate directory components and rename DirectoryOrgs --- src/app/page.tsx | 4 ++-- src/components/{DirectoryOrgs.tsx => club/ClubCard.tsx} | 8 ++++---- .../{ => club/directory}/InfiniteScrollGrid.tsx | 6 +++--- src/components/{ => club/directory}/OrgDirectoryGrid.tsx | 4 ++-- src/components/{ => club/directory}/TagFilter.tsx | 0 src/components/{ => club/listing}/ContactButtons.tsx | 2 +- src/components/{ => club/listing}/OrgHeader.tsx | 0 src/components/{ => club/listing}/OrgInfoSegment.tsx | 0 src/components/{ => club/listing}/OrgUpcomingEvents.tsx | 0 9 files changed, 12 insertions(+), 12 deletions(-) rename src/components/{DirectoryOrgs.tsx => club/ClubCard.tsx} (91%) rename src/components/{ => club/directory}/InfiniteScrollGrid.tsx (92%) rename src/components/{ => club/directory}/OrgDirectoryGrid.tsx (90%) rename src/components/{ => club/directory}/TagFilter.tsx (100%) rename src/components/{ => club/listing}/ContactButtons.tsx (94%) rename src/components/{ => club/listing}/OrgHeader.tsx (100%) rename src/components/{ => club/listing}/OrgInfoSegment.tsx (100%) rename src/components/{ => club/listing}/OrgUpcomingEvents.tsx (100%) diff --git a/src/app/page.tsx b/src/app/page.tsx index 34978715..c482e4fc 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 TagFilter from '../components/club/directory/TagFilter'; +import OrgDirectoryGrid from '../components/club/directory/OrgDirectoryGrid'; import type { Metadata } from 'next'; import { api } from '@src/trpc/server'; diff --git a/src/components/DirectoryOrgs.tsx b/src/components/club/ClubCard.tsx similarity index 91% rename from src/components/DirectoryOrgs.tsx rename to src/components/club/ClubCard.tsx index 882b0410..9624db0b 100644 --- a/src/components/DirectoryOrgs.tsx +++ b/src/components/club/ClubCard.tsx @@ -1,13 +1,13 @@ import { type FC } from 'react'; import Image from 'next/image'; import type { SelectClub as Club } from '@src/server/db/models'; -import JoinButton from './JoinButton'; +import JoinButton from '../JoinButton'; import Link from 'next/link'; 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/InfiniteScrollGrid.tsx b/src/components/club/directory/InfiniteScrollGrid.tsx similarity index 92% rename from src/components/InfiniteScrollGrid.tsx rename to src/components/club/directory/InfiniteScrollGrid.tsx index 2a3e6189..1be06703 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 DirectoryOrgs, { ClubCardSkeleton } from '../ClubCard'; type Props = { session: Session | null; @@ -67,11 +67,11 @@ export default function InfiniteScrollGrid({ session, tag }: Props) { }), ) : Array.from({ length: 4 }, (_, index) => ( - + ))} {isFetchingNextPage && Array.from({ length: 4 }, (_, index) => ( - + ))} ); diff --git a/src/components/OrgDirectoryGrid.tsx b/src/components/club/directory/OrgDirectoryGrid.tsx similarity index 90% rename from src/components/OrgDirectoryGrid.tsx rename to src/components/club/directory/OrgDirectoryGrid.tsx index c3be3c13..cdb4d0af 100644 --- a/src/components/OrgDirectoryGrid.tsx +++ b/src/components/club/directory/OrgDirectoryGrid.tsx @@ -1,9 +1,9 @@ import { type FC } from 'react'; -import DirectoryOrgs from './DirectoryOrgs'; +import DirectoryOrgs from '../ClubCard'; import { api } from '@src/trpc/server'; import { getServerAuthSession } from '@src/server/auth'; import InfiniteScrollGrid from './InfiniteScrollGrid'; -import ScrollTop from './ScrollTop'; +import ScrollTop from '../../ScrollTop'; interface Props { tag?: string; 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/ContactButtons.tsx b/src/components/club/listing/ContactButtons.tsx similarity index 94% rename from src/components/ContactButtons.tsx rename to src/components/club/listing/ContactButtons.tsx index b961ca01..b526a45c 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 '../../ContactIcons'; import Link from 'next/link'; type contentButtonProps = { diff --git a/src/components/OrgHeader.tsx b/src/components/club/listing/OrgHeader.tsx similarity index 100% rename from src/components/OrgHeader.tsx rename to src/components/club/listing/OrgHeader.tsx diff --git a/src/components/OrgInfoSegment.tsx b/src/components/club/listing/OrgInfoSegment.tsx similarity index 100% rename from src/components/OrgInfoSegment.tsx rename to src/components/club/listing/OrgInfoSegment.tsx diff --git a/src/components/OrgUpcomingEvents.tsx b/src/components/club/listing/OrgUpcomingEvents.tsx similarity index 100% rename from src/components/OrgUpcomingEvents.tsx rename to src/components/club/listing/OrgUpcomingEvents.tsx From 0d00a1ea95a2ce56f0737c66d48e113ce1ff3584 Mon Sep 17 00:00:00 2001 From: Ethan Bickel Date: Mon, 30 Sep 2024 11:15:23 -0500 Subject: [PATCH 49/87] colocate create club components --- .../directory/create}/CreateContactSelector.tsx | 2 +- src/{components => app/directory/create}/OfficerSelector.tsx | 2 +- src/app/directory/create/createForm.tsx | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) rename src/{components => app/directory/create}/CreateContactSelector.tsx (99%) rename src/{components => app/directory/create}/OfficerSelector.tsx (97%) 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..5d5f7071 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/components/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 b40a7e57..06b9ccf0 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/UserSearchBar'; +import { UserSearchBar } from '../../../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'; From ac93254a75185bbe5b3ae4c6a50ec6377761a73c Mon Sep 17 00:00:00 2001 From: Ethan Bickel Date: Mon, 30 Sep 2024 11:15:50 -0500 Subject: [PATCH 50/87] relocate JoinButton for ClubCard --- src/components/club/ClubCard.tsx | 2 +- src/components/{ => club}/JoinButton.tsx | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename src/components/{ => club}/JoinButton.tsx (100%) diff --git a/src/components/club/ClubCard.tsx b/src/components/club/ClubCard.tsx index 9624db0b..3fa4755f 100644 --- a/src/components/club/ClubCard.tsx +++ b/src/components/club/ClubCard.tsx @@ -1,7 +1,7 @@ import { type FC } from 'react'; import Image from 'next/image'; import type { SelectClub as Club } from '@src/server/db/models'; -import JoinButton from '../JoinButton'; +import JoinButton from './JoinButton'; import Link from 'next/link'; import { type Session } from 'next-auth'; 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 From c1cdb46fb1289abb013eb05eb066fb92cf22fe07 Mon Sep 17 00:00:00 2001 From: Ethan Bickel Date: Mon, 30 Sep 2024 11:16:14 -0500 Subject: [PATCH 51/87] colocate RegisterButton for event page --- src/{components => app/event/[id]}/RegisterButton.tsx | 0 src/app/event/[id]/page.tsx | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename src/{components => app/event/[id]}/RegisterButton.tsx (100%) 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..87e9455e 100644 --- a/src/app/event/[id]/page.tsx +++ b/src/app/event/[id]/page.tsx @@ -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 } }; From a1d3016ba96a5cc0c4557ddfe294148ad9105620 Mon Sep 17 00:00:00 2001 From: Ethan Bickel Date: Mon, 30 Sep 2024 11:19:30 -0500 Subject: [PATCH 52/87] relocate carousel and return to top with other directory components squash --- src/app/page.tsx | 2 +- src/components/{ => club/directory}/Carousel.tsx | 2 +- src/components/club/directory/OrgDirectoryGrid.tsx | 2 +- src/components/{ => club/directory}/ScrollTop.tsx | 0 4 files changed, 3 insertions(+), 3 deletions(-) rename src/components/{ => club/directory}/Carousel.tsx (98%) rename src/components/{ => club/directory}/ScrollTop.tsx (100%) diff --git a/src/app/page.tsx b/src/app/page.tsx index c482e4fc..db3754f6 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -1,5 +1,5 @@ import Header from '../components/BaseHeader'; -import Carousel from '../components/Carousel'; +import Carousel from '../components/club/directory/Carousel'; import TagFilter from '../components/club/directory/TagFilter'; import OrgDirectoryGrid from '../components/club/directory/OrgDirectoryGrid'; import type { Metadata } from 'next'; 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..3edb1159 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 '../../../icons/Icons'; import Link from 'next/link'; import { type SelectClub } from '@src/server/db/models'; diff --git a/src/components/club/directory/OrgDirectoryGrid.tsx b/src/components/club/directory/OrgDirectoryGrid.tsx index cdb4d0af..8a84de19 100644 --- a/src/components/club/directory/OrgDirectoryGrid.tsx +++ b/src/components/club/directory/OrgDirectoryGrid.tsx @@ -3,7 +3,7 @@ import DirectoryOrgs from '../ClubCard'; import { api } from '@src/trpc/server'; import { getServerAuthSession } from '@src/server/auth'; import InfiniteScrollGrid from './InfiniteScrollGrid'; -import ScrollTop from '../../ScrollTop'; +import ScrollTop from './ScrollTop'; interface Props { tag?: string; 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 From de580ead61f8c5920a5d3b87b78314abef4000fd Mon Sep 17 00:00:00 2001 From: Ethan Bickel Date: Mon, 30 Sep 2024 11:21:53 -0500 Subject: [PATCH 53/87] relocate contact editor with contact edit form --- src/app/manage/[clubId]/edit/EditContactForm.tsx | 2 +- .../manage/[clubId]/edit}/EditContactSelector.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename src/{components => app/manage/[clubId]/edit}/EditContactSelector.tsx (99%) 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..8bd2d1d4 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/components/ContactIcons'; import { type modifyDeletedAction } from '@src/app/manage/[clubId]/edit/EditContactForm'; import { type editClubContactSchema } from '@src/utils/formSchemas'; From a5014a88d264f5b38b7a59ce671acd88de4d7939 Mon Sep 17 00:00:00 2001 From: Ethan Bickel Date: Mon, 30 Sep 2024 11:28:53 -0500 Subject: [PATCH 54/87] relocate header components and back button fix back button imports --- src/app/about/page.tsx | 2 +- src/app/community/page.tsx | 2 +- src/app/directory/[id]/page.tsx | 2 +- src/app/directory/create/page.tsx | 2 +- src/app/event/[id]/page.tsx | 2 +- src/app/events/page.tsx | 2 +- src/app/feedback/page.tsx | 2 +- .../manage/[clubId]/(dashboard)/layout.tsx | 6 +-- src/app/manage/[clubId]/create/page.tsx | 54 ++++++++++--------- .../manage/[clubId]/edit/officers/page.tsx | 6 +-- src/app/manage/[clubId]/edit/page.tsx | 6 +-- src/app/manage/page.tsx | 2 +- src/app/page.tsx | 2 +- src/app/settings/page.tsx | 2 +- src/components/BlueBackButton.tsx | 20 ------- src/components/NotFound.tsx | 2 +- src/components/backButton.tsx | 16 ++++++ src/components/{ => header}/BaseHeader.tsx | 6 +-- .../{ => header}/ProfileDropDown.tsx | 0 src/components/{ => header}/signInButton.tsx | 0 20 files changed, 67 insertions(+), 69 deletions(-) delete mode 100644 src/components/BlueBackButton.tsx rename src/components/{ => header}/BaseHeader.tsx (88%) rename src/components/{ => header}/ProfileDropDown.tsx (100%) rename src/components/{ => header}/signInButton.tsx (100%) 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/community/page.tsx b/src/app/community/page.tsx index c3fb56cf..497350aa 100644 --- a/src/app/community/page.tsx +++ b/src/app/community/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 { type Metadata } from 'next'; import Image from 'next/image'; diff --git a/src/app/directory/[id]/page.tsx b/src/app/directory/[id]/page.tsx index 51de93ad..e42b484b 100644 --- a/src/app/directory/[id]/page.tsx +++ b/src/app/directory/[id]/page.tsx @@ -1,4 +1,4 @@ -import Header from '@src/components/BaseHeader'; +import Header from '@src/components/header/BaseHeader'; import OrgHeader from '@src/components/OrgHeader'; import OrgInfoSegment from '@src/components/OrgInfoSegment'; import OrgUpcomingEvents from '@src/components/OrgUpcomingEvents'; 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/app/event/[id]/page.tsx b/src/app/event/[id]/page.tsx index 87e9455e..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'; 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/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/page.tsx b/src/app/manage/[clubId]/create/page.tsx index 95765a0e..03745126 100644 --- a/src/app/manage/[clubId]/create/page.tsx +++ b/src/app/manage/[clubId]/create/page.tsx @@ -1,30 +1,32 @@ -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; - return (
-
-
- -
- -
) -} -export default Page; \ No newline at end of file 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 db3754f6..058b8025 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -1,4 +1,4 @@ -import Header from '../components/BaseHeader'; +import Header from '../components/header/BaseHeader'; import Carousel from '../components/club/directory/Carousel'; import TagFilter from '../components/club/directory/TagFilter'; import OrgDirectoryGrid from '../components/club/directory/OrgDirectoryGrid'; 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/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/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 1d8e0c48..1a72a5f9 100644 --- a/src/components/BaseHeader.tsx +++ b/src/components/header/BaseHeader.tsx @@ -1,10 +1,10 @@ import type { ReactNode } from 'react'; import { ProfileDropDown } from './ProfileDropDown'; import { getServerAuthSession } from '@src/server/auth'; -import { ClubSearchBar } from './searchBar/ClubSearchBar'; -import { EventSearchBar } from './searchBar/EventSearchBar'; +import { ClubSearchBar } from '../searchBar/ClubSearchBar'; +import { EventSearchBar } from '../searchBar/EventSearchBar'; import SignInButton from './signInButton'; -import MobileNav from './nav/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 From cc338dbb745bd9e301c414793359a47e0d006f15 Mon Sep 17 00:00:00 2001 From: Ethan Bickel Date: Mon, 30 Sep 2024 11:31:57 -0500 Subject: [PATCH 55/87] move ContactIcons to icons folder --- src/app/directory/create/CreateContactSelector.tsx | 2 +- src/app/manage/[clubId]/edit/EditContactSelector.tsx | 2 +- src/components/club/listing/ContactButtons.tsx | 2 +- src/{components => icons}/ContactIcons.tsx | 0 4 files changed, 3 insertions(+), 3 deletions(-) rename src/{components => icons}/ContactIcons.tsx (100%) diff --git a/src/app/directory/create/CreateContactSelector.tsx b/src/app/directory/create/CreateContactSelector.tsx index 5d5f7071..2d0735c5 100644 --- a/src/app/directory/create/CreateContactSelector.tsx +++ b/src/app/directory/create/CreateContactSelector.tsx @@ -16,7 +16,7 @@ import { Website, Youtube, type logoProps, -} from '@src/components/ContactIcons'; +} from '@src/icons/ContactIcons'; import { type Control, type UseFormRegister, diff --git a/src/app/manage/[clubId]/edit/EditContactSelector.tsx b/src/app/manage/[clubId]/edit/EditContactSelector.tsx index 8bd2d1d4..3e03c38b 100644 --- a/src/app/manage/[clubId]/edit/EditContactSelector.tsx +++ b/src/app/manage/[clubId]/edit/EditContactSelector.tsx @@ -23,7 +23,7 @@ import { Website, Youtube, type logoProps, -} from '@src/components/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/components/club/listing/ContactButtons.tsx b/src/components/club/listing/ContactButtons.tsx index b526a45c..ea255f59 100644 --- a/src/components/club/listing/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/ContactIcons.tsx b/src/icons/ContactIcons.tsx similarity index 100% rename from src/components/ContactIcons.tsx rename to src/icons/ContactIcons.tsx From 1a8928e92eab7c027d0df589558c0b78b07104f3 Mon Sep 17 00:00:00 2001 From: Ethan Bickel Date: Mon, 30 Sep 2024 11:49:01 -0500 Subject: [PATCH 56/87] fix broken imports --- src/app/directory/[id]/page.tsx | 6 +++--- src/components/club/listing/OrgHeader.tsx | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/app/directory/[id]/page.tsx b/src/app/directory/[id]/page.tsx index e42b484b..cb03e51e 100644 --- a/src/app/directory/[id]/page.tsx +++ b/src/app/directory/[id]/page.tsx @@ -1,7 +1,7 @@ import Header from '@src/components/header/BaseHeader'; -import OrgHeader from '@src/components/OrgHeader'; -import OrgInfoSegment from '@src/components/OrgInfoSegment'; -import OrgUpcomingEvents from '@src/components/OrgUpcomingEvents'; +import OrgHeader from '@src/components/club/listing/OrgHeader'; +import OrgInfoSegment from '@src/components/club/listing/OrgInfoSegment'; +import OrgUpcomingEvents from '@src/components/club/listing/OrgUpcomingEvents'; import { api } from '@src/trpc/server'; import { db } from '@src/server/db'; import { eq } from 'drizzle-orm'; diff --git a/src/components/club/listing/OrgHeader.tsx b/src/components/club/listing/OrgHeader.tsx index 4b17dcb0..5dc99217 100644 --- a/src/components/club/listing/OrgHeader.tsx +++ b/src/components/club/listing/OrgHeader.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'; From 06564901b17fe119d94529b0b1f889853d52e240 Mon Sep 17 00:00:00 2001 From: Ethan Bickel Date: Mon, 30 Sep 2024 19:28:55 -0500 Subject: [PATCH 57/87] rename orgs to clubs in all locations --- src/app/admin/carousel/add/page.tsx | 6 +-- src/app/admin/{orgs => clubs}/[id]/page.tsx | 8 ++-- src/app/admin/{orgs => clubs}/page.tsx | 6 +-- src/app/admin/page.tsx | 4 +- src/app/directory/[id]/page.tsx | 16 +++---- src/app/directory/create/OfficerSelector.tsx | 2 +- src/app/page.tsx | 4 +- .../admin/{AddOrg.tsx => AddClub.tsx} | 42 +++++++++---------- src/components/admin/ApprovedClub.tsx | 23 ++++++++++ src/components/admin/ApprovedOrg.tsx | 23 ---------- src/components/admin/CarouselCards.tsx | 2 +- ...angeOrgStatus.tsx => ChangeClubStatus.tsx} | 12 +++--- ...OrgDescription.tsx => ClubDescription.tsx} | 2 +- .../admin/{OrgSearch.tsx => ClubSearch.tsx} | 6 +-- .../admin/{OrgTable.tsx => ClubTable.tsx} | 4 +- ...OtherOrgStatus.tsx => OtherClubStatus.tsx} | 14 +++---- ...irectoryGrid.tsx => ClubDirectoryGrid.tsx} | 8 ++-- .../club/directory/InfiniteScrollGrid.tsx | 16 +++---- .../listing/{OrgHeader.tsx => ClubHeader.tsx} | 4 +- ...OrgInfoSegment.tsx => ClubInfoSegment.tsx} | 4 +- ...omingEvents.tsx => ClubUpcomingEvents.tsx} | 4 +- src/server/api/routers/admin.ts | 20 ++++----- 22 files changed, 113 insertions(+), 117 deletions(-) rename src/app/admin/{orgs => clubs}/[id]/page.tsx (72%) rename src/app/admin/{orgs => clubs}/page.tsx (51%) rename src/components/admin/{AddOrg.tsx => AddClub.tsx} (72%) create mode 100644 src/components/admin/ApprovedClub.tsx delete mode 100644 src/components/admin/ApprovedOrg.tsx rename src/components/admin/{ChangeOrgStatus.tsx => ChangeClubStatus.tsx} (78%) rename src/components/admin/{OrgDescription.tsx => ClubDescription.tsx} (96%) rename src/components/admin/{OrgSearch.tsx => ClubSearch.tsx} (79%) rename src/components/admin/{OrgTable.tsx => ClubTable.tsx} (98%) rename src/components/admin/{OtherOrgStatus.tsx => OtherClubStatus.tsx} (78%) rename src/components/club/directory/{OrgDirectoryGrid.tsx => ClubDirectoryGrid.tsx} (75%) rename src/components/club/listing/{OrgHeader.tsx => ClubHeader.tsx} (96%) rename src/components/club/listing/{OrgInfoSegment.tsx => ClubInfoSegment.tsx} (98%) rename src/components/club/listing/{OrgUpcomingEvents.tsx => ClubUpcomingEvents.tsx} (93%) 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/app/directory/create/OfficerSelector.tsx b/src/app/directory/create/OfficerSelector.tsx index 06b9ccf0..05c07ef5 100644 --- a/src/app/directory/create/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 '../../../components/searchBar/UserSearchBar'; +import { UserSearchBar } from '@src/components/searchBar/UserSearchBar'; type OfficerSelectorProps = { control: Control>; diff --git a/src/app/page.tsx b/src/app/page.tsx index 058b8025..97531516 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -1,7 +1,7 @@ import Header from '../components/header/BaseHeader'; import Carousel from '../components/club/directory/Carousel'; import TagFilter from '../components/club/directory/TagFilter'; -import OrgDirectoryGrid from '../components/club/directory/OrgDirectoryGrid'; +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/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/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 79% rename from src/components/admin/OrgSearch.tsx rename to src/components/admin/ClubSearch.tsx index 9caf805d..0c14d02d 100644 --- a/src/components/admin/OrgSearch.tsx +++ b/src/components/admin/ClubSearch.tsx @@ -6,10 +6,10 @@ 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,7 +17,7 @@ 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 ( diff --git a/src/components/admin/OrgTable.tsx b/src/components/admin/ClubTable.tsx similarity index 98% rename from src/components/admin/OrgTable.tsx rename to src/components/admin/ClubTable.tsx index c94fd9e7..8123e162 100644 --- a/src/components/admin/OrgTable.tsx +++ b/src/components/admin/ClubTable.tsx @@ -18,11 +18,11 @@ import { useRouter } from 'next/navigation'; import { type Club, fuzzyFilter } from '@src/utils/table'; import StatusFilter from './StatusFilter'; -export default function OrgTable({ clubs }: { clubs: Club[] }) { +export default function ClubTable({ clubs }: { clubs: Club[] }) { const router = useRouter(); const parentRef = useRef(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/club/directory/OrgDirectoryGrid.tsx b/src/components/club/directory/ClubDirectoryGrid.tsx similarity index 75% rename from src/components/club/directory/OrgDirectoryGrid.tsx rename to src/components/club/directory/ClubDirectoryGrid.tsx index 8a84de19..8c6a99ab 100644 --- a/src/components/club/directory/OrgDirectoryGrid.tsx +++ b/src/components/club/directory/ClubDirectoryGrid.tsx @@ -1,5 +1,5 @@ import { type FC } from 'react'; -import DirectoryOrgs from '../ClubCard'; +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/club/directory/InfiniteScrollGrid.tsx b/src/components/club/directory/InfiniteScrollGrid.tsx index 1be06703..259ab9b8 100644 --- a/src/components/club/directory/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, { ClubCardSkeleton } from '../ClubCard'; +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,14 +54,10 @@ export default function InfiniteScrollGrid({ session, tag }: Props) { clubIndex === page.clubs.length - 1; return (
- +
); }), diff --git a/src/components/club/listing/OrgHeader.tsx b/src/components/club/listing/ClubHeader.tsx similarity index 96% rename from src/components/club/listing/OrgHeader.tsx rename to src/components/club/listing/ClubHeader.tsx index 5dc99217..fcbb26dc 100644 --- a/src/components/club/listing/OrgHeader.tsx +++ b/src/components/club/listing/ClubHeader.tsx @@ -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/club/listing/OrgInfoSegment.tsx b/src/components/club/listing/ClubInfoSegment.tsx similarity index 98% rename from src/components/club/listing/OrgInfoSegment.tsx rename to src/components/club/listing/ClubInfoSegment.tsx index 2e2e3b9a..d1fe1fc7 100644 --- a/src/components/club/listing/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/club/listing/OrgUpcomingEvents.tsx b/src/components/club/listing/ClubUpcomingEvents.tsx similarity index 93% rename from src/components/club/listing/OrgUpcomingEvents.tsx rename to src/components/club/listing/ClubUpcomingEvents.tsx index 9232c1a3..7672f8a8 100644 --- a/src/components/club/listing/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/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)); }), }); From a46cb7a862d8ec357e99d32b78a4987f94c2fbe1 Mon Sep 17 00:00:00 2001 From: Ethan Bickel Date: Mon, 30 Sep 2024 19:30:58 -0500 Subject: [PATCH 58/87] fix relative icon imports --- src/components/club/directory/Carousel.tsx | 2 +- src/components/events/EventCard.tsx | 2 +- src/components/events/EventLikeButton.tsx | 2 +- src/components/nav/SidebarItems.tsx | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/components/club/directory/Carousel.tsx b/src/components/club/directory/Carousel.tsx index 3edb1159..74a04aff 100644 --- a/src/components/club/directory/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/events/EventCard.tsx b/src/components/events/EventCard.tsx index 091256fa..1eb41bc5 100644 --- a/src/components/events/EventCard.tsx +++ b/src/components/events/EventCard.tsx @@ -2,7 +2,7 @@ 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 { getServerAuthSession } from '@src/server/auth'; diff --git a/src/components/events/EventLikeButton.tsx b/src/components/events/EventLikeButton.tsx index a22b05a4..5257e59d 100644 --- a/src/components/events/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/nav/SidebarItems.tsx b/src/components/nav/SidebarItems.tsx index fdf1cc89..d13c5cdb 100644 --- a/src/components/nav/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]; From 3a422c11163fe13b74ae2c6ef23a1bcd9801625f Mon Sep 17 00:00:00 2001 From: Ethan Bickel Date: Tue, 1 Oct 2024 14:45:23 -0500 Subject: [PATCH 59/87] add submit functionality to search bar --- .../searchBar/DebouncedSearchBar.tsx | 6 +++ src/components/searchBar/index.tsx | 37 +++++++++++++++++-- 2 files changed, 39 insertions(+), 4 deletions(-) diff --git a/src/components/searchBar/DebouncedSearchBar.tsx b/src/components/searchBar/DebouncedSearchBar.tsx index 395f898c..1fe89774 100644 --- a/src/components/searchBar/DebouncedSearchBar.tsx +++ b/src/components/searchBar/DebouncedSearchBar.tsx @@ -18,6 +18,8 @@ export type DebouncedSearchBarProps = { setSearch: Dispatch>; searchResults?: Array; onClick?: (input: T) => void; + submitButton?: boolean; + submitLogic?: () => void; }; export const DebouncedSearchBar = ({ placeholder, @@ -25,6 +27,8 @@ export const DebouncedSearchBar = ({ setSearch, searchResults, onClick, + submitButton, + submitLogic, }: DebouncedSearchBarProps) => { const [input, setInput] = useState(value ?? ''); const [focused, setFocused] = useState(false); @@ -48,6 +52,8 @@ export const DebouncedSearchBar = ({ onChange={handleSearch} onFocus={() => setFocused(true)} onBlur={() => setTimeout(() => setFocused(false), 300)} + submitButton={submitButton} + submitLogic={submitLogic} /> {input && focused && searchResults && searchResults.length > 0 && (
diff --git a/src/components/searchBar/index.tsx b/src/components/searchBar/index.tsx index 2fbe4389..cd90c59f 100644 --- a/src/components/searchBar/index.tsx +++ b/src/components/searchBar/index.tsx @@ -1,9 +1,14 @@ -import { SearchIcon } from '@src/icons/Icons'; -import { ComponentProps } from 'react'; +import { RightArrowIcon, SearchIcon } from '@src/icons/Icons'; +import { type ComponentProps } from 'react'; -type SearchBarProps = Omit, 'type'>; +type SearchBarProps = Omit, 'type'> & { + submitButton?: boolean; + submitLogic?: () => void; +}; export const SearchBar = (props: SearchBarProps) => { + const submitButton = props.submitButton; + const submitLogic = props.submitLogic; return (
@@ -12,8 +17,32 @@ export const SearchBar = (props: SearchBarProps) => { { + console.log('howdy from submit'); + }} + onKeyDown={(e) => { + if (e.key === 'Enter' && submitLogic) { + submitLogic(); + } + }} /> + {submitButton && ( + + )}
); }; From 31df6a1c689cc49e397bcd0ab44ba606b484f97b Mon Sep 17 00:00:00 2001 From: Connor Harris Date: Tue, 1 Oct 2024 15:42:55 -0500 Subject: [PATCH 60/87] detailed commit message (oopsie) --- src/app/clubSearch/page.tsx | 22 ++++++++++++++++ src/components/ClubSearchComponent.tsx | 35 ++++++++++++++++++++++++++ src/components/SearchBar.tsx | 9 +++++++ src/server/api/routers/club.ts | 9 +++++++ 4 files changed, 75 insertions(+) create mode 100644 src/app/clubSearch/page.tsx create mode 100644 src/components/ClubSearchComponent.tsx diff --git a/src/app/clubSearch/page.tsx b/src/app/clubSearch/page.tsx new file mode 100644 index 00000000..080ec094 --- /dev/null +++ b/src/app/clubSearch/page.tsx @@ -0,0 +1,22 @@ +import Header from '@src/components/BaseHeader'; +import { ClubSearchComponent } from '@src/components/ClubSearchComponent'; + +type Params = { + searchParams: { [key: string]: string | undefined }; +}; + +const clubSearch = async (props: Params) => { + const { searchParams } = props; + const userSearch = searchParams['search'] || ''; + + return ( +
+
+
+ +
+
+ ); +}; + +export default clubSearch; diff --git a/src/components/ClubSearchComponent.tsx b/src/components/ClubSearchComponent.tsx new file mode 100644 index 00000000..0e0b113a --- /dev/null +++ b/src/components/ClubSearchComponent.tsx @@ -0,0 +1,35 @@ +'use client'; +import { api } from '@src/trpc/react'; +import DirectoryOrgs from './DirectoryOrgs'; +import type { SelectClub as Club } from '@src/server/db/models'; // Assuming you use this type +import { type Session } from 'next-auth'; + +interface ClubSearchComponentProps { + userSearch: string; + session: Session | null; +} + +export const ClubSearchComponent = ({ + userSearch, + session, +}: ClubSearchComponentProps) => { + const { data } = api.club.byNameNoLimit.useQuery( + { name: userSearch }, + { enabled: !!userSearch }, + ); + + if (!data) { + return

; + } + if (data.length === 0) { + return

No results found for "{userSearch}".

; + } + + return ( +
+ {data.map((club: Club, index: number) => ( + + ))} +
+ ); +}; \ No newline at end of file diff --git a/src/components/SearchBar.tsx b/src/components/SearchBar.tsx index fb219eb2..85be4083 100644 --- a/src/components/SearchBar.tsx +++ b/src/components/SearchBar.tsx @@ -25,6 +25,7 @@ type SearchBarProps = { setSearch: Dispatch>; searchResults?: Array; onClick?: (input: T) => void; + handleKeyDown?: (e: React.KeyboardEvent) => void; }; export const SearchBar = ({ @@ -33,6 +34,7 @@ export const SearchBar = ({ setSearch, searchResults, onClick, + handleKeyDown, }: SearchBarProps) => { const [input, setInput] = useState(value ?? ''); const [focused, setFocused] = useState(false); @@ -62,6 +64,7 @@ export const SearchBar = ({ onChange={handleSearch} onFocus={() => setFocused(true)} onBlur={() => setTimeout(() => setFocused(false), 300)} + onKeyDown={handleKeyDown} /> {input && focused && searchResults && searchResults.length > 0 && (
@@ -92,12 +95,18 @@ export const ClubSearchBar = () => { const onClickSearchResult = (club: Club) => { router.push(`/directory/${club.id}`); }; + const handleKeyDown = (e: React.KeyboardEvent) => { + if (e.key === 'Enter') { + router.push(`/clubSearch?search=${encodeURIComponent(search)}`); + } + }; return ( ); }; diff --git a/src/server/api/routers/club.ts b/src/server/api/routers/club.ts index ee13dbdb..8154451c 100644 --- a/src/server/api/routers/club.ts +++ b/src/server/api/routers/club.ts @@ -64,6 +64,15 @@ export const clubRouter = createTRPCRouter({ return clubs.slice(0, 5); }), + byNameNoLimit: publicProcedure.input(byNameSchema).query(async ({ input, ctx }) => { + const { name } = input; + const clubs = await ctx.db.query.club.findMany({ + where: (club) => + and(ilike(club.name, `%${name}%`), eq(club.approved, 'approved')), + }); + + return clubs; + }), byId: publicProcedure.input(byIdSchema).query(async ({ input, ctx }) => { const { id } = input; try { From ea1284e41366750ec8a365a09de38885ca8fe63b Mon Sep 17 00:00:00 2001 From: Ethan Bickel Date: Tue, 1 Oct 2024 16:13:33 -0500 Subject: [PATCH 61/87] implement submits to current searchbars --- src/components/searchBar/ClubSearchBar.tsx | 6 +++++ .../searchBar/EventClubSearchBar.tsx | 27 ++++++++++--------- src/components/searchBar/EventSearchBar.tsx | 22 ++++++++------- src/components/searchBar/UserSearchBar.tsx | 27 +++++++++---------- 4 files changed, 45 insertions(+), 37 deletions(-) diff --git a/src/components/searchBar/ClubSearchBar.tsx b/src/components/searchBar/ClubSearchBar.tsx index 7523c719..6e2ffa8d 100644 --- a/src/components/searchBar/ClubSearchBar.tsx +++ b/src/components/searchBar/ClubSearchBar.tsx @@ -21,6 +21,12 @@ export const ClubSearchBar = () => { setSearch={setSearch} searchResults={data || []} onClick={onClickSearchResult} + submitButton + submitLogic={() => { + if (data && data[0]) { + onClickSearchResult(data[0]); + } + }} /> ); }; diff --git a/src/components/searchBar/EventClubSearchBar.tsx b/src/components/searchBar/EventClubSearchBar.tsx index afce98f5..0c65a28f 100644 --- a/src/components/searchBar/EventClubSearchBar.tsx +++ b/src/components/searchBar/EventClubSearchBar.tsx @@ -1,5 +1,5 @@ 'use client'; -import { useState, useEffect } from 'react'; +import { useState } from 'react'; import type { SelectClub as Club } from '@src/server/db/models'; import { api } from '@src/trpc/react'; import { DebouncedSearchBar } from './DebouncedSearchBar'; @@ -9,29 +9,30 @@ type EventClubSearchBarProps = { }; export const EventClubSearchBar = ({ addClub }: EventClubSearchBarProps) => { const [search, setSearch] = useState(''); - const [res, setRes] = useState([]); const utils = api.useUtils(); - const clubQuery = api.club.byName.useQuery( + const { data } = api.club.byName.useQuery( { name: search }, { enabled: !!search, }, ); - useEffect(() => { - if (clubQuery.data) { - setRes(clubQuery.data); - } - }, [clubQuery.data]); + const submit = (club: Club) => { + void utils.club.byId.prefetch({ id: club.id }); + addClub(club.id); + setSearch(''); + }; return ( { - void utils.club.byId.prefetch({ id: club.id }); - addClub(club.id); - setSearch(''); + searchResults={data || []} + onClick={submit} + submitButton + submitLogic={() => { + if (data && data[0]) { + submit(data[0]); + } }} /> ); diff --git a/src/components/searchBar/EventSearchBar.tsx b/src/components/searchBar/EventSearchBar.tsx index 04adb555..7e32cd98 100644 --- a/src/components/searchBar/EventSearchBar.tsx +++ b/src/components/searchBar/EventSearchBar.tsx @@ -1,5 +1,5 @@ 'use client'; -import { useState, useEffect } from 'react'; +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'; @@ -8,26 +8,28 @@ import { DebouncedSearchBar } from './DebouncedSearchBar'; export const EventSearchBar = () => { const router = useRouter(); const [search, setSearch] = useState(''); - const [res, setRes] = useState([]); - const eventQuery = api.event.byName.useQuery( + const { data } = api.event.byName.useQuery( { name: search, sortByDate: true, }, { enabled: !!search }, ); - useEffect(() => { - if (eventQuery.data) setRes(eventQuery.data); - }, [eventQuery.data]); - + const onClickSearchResult = (event: Event) => { + router.push(`/event/${event.id}`); + }; return ( { - router.push(`/event/${event.id}`); + searchResults={data || []} + onClick={onClickSearchResult} + submitButton + submitLogic={() => { + if (data && data[0]) { + onClickSearchResult(data[0]); + } }} /> ); diff --git a/src/components/searchBar/UserSearchBar.tsx b/src/components/searchBar/UserSearchBar.tsx index 487d4f40..94fad809 100644 --- a/src/components/searchBar/UserSearchBar.tsx +++ b/src/components/searchBar/UserSearchBar.tsx @@ -1,42 +1,41 @@ 'use client'; -import { type SelectUserMetadata } from '@src/server/db/models'; import { api } from '@src/trpc/react'; -import { useState, useEffect } from 'react'; +import { useState } from 'react'; import { DebouncedSearchBar } from './DebouncedSearchBar'; 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) => { + const formattedData = userQuery.isSuccess + ? userQuery.data.map((val) => { return { name: val.firstName + ' ' + val.lastName, ...val }; - }); - setRes(newData); - } - }, [userQuery.data]); + }) + : []; 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(''); + } + }} /> ); }; From 1cabb03efe5baa80585bb3e52447495407647dfb Mon Sep 17 00:00:00 2001 From: Connor Harris Date: Tue, 1 Oct 2024 16:57:43 -0500 Subject: [PATCH 62/87] added session stuff --- src/app/clubSearch/page.tsx | 4 +++- src/components/ClubSearchComponent.tsx | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/app/clubSearch/page.tsx b/src/app/clubSearch/page.tsx index 080ec094..3f79726e 100644 --- a/src/app/clubSearch/page.tsx +++ b/src/app/clubSearch/page.tsx @@ -1,5 +1,6 @@ import Header from '@src/components/BaseHeader'; import { ClubSearchComponent } from '@src/components/ClubSearchComponent'; +import { getServerAuthSession } from '@src/server/auth'; type Params = { searchParams: { [key: string]: string | undefined }; @@ -8,12 +9,13 @@ type Params = { const clubSearch = async (props: Params) => { const { searchParams } = props; const userSearch = searchParams['search'] || ''; + const session = await getServerAuthSession(); return (
- +
); diff --git a/src/components/ClubSearchComponent.tsx b/src/components/ClubSearchComponent.tsx index 0e0b113a..ad6084a0 100644 --- a/src/components/ClubSearchComponent.tsx +++ b/src/components/ClubSearchComponent.tsx @@ -1,7 +1,7 @@ 'use client'; import { api } from '@src/trpc/react'; import DirectoryOrgs from './DirectoryOrgs'; -import type { SelectClub as Club } from '@src/server/db/models'; // Assuming you use this type +import type { SelectClub as Club } from '@src/server/db/models'; import { type Session } from 'next-auth'; interface ClubSearchComponentProps { From a1690d72126b5c2ede56887dffe7953f0373efc5 Mon Sep 17 00:00:00 2001 From: Connor Harris Date: Tue, 1 Oct 2024 17:42:40 -0500 Subject: [PATCH 63/87] make vercel stop yelling at me hopefully --- src/components/ClubSearchComponent.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/ClubSearchComponent.tsx b/src/components/ClubSearchComponent.tsx index ad6084a0..eb0198a8 100644 --- a/src/components/ClubSearchComponent.tsx +++ b/src/components/ClubSearchComponent.tsx @@ -22,12 +22,12 @@ export const ClubSearchComponent = ({ return

; } if (data.length === 0) { - return

No results found for "{userSearch}".

; + return

No results found

; } return (
- {data.map((club: Club, index: number) => ( + {data.map((club: Club) => ( ))}
From 2a65541f7223fb7156cd4d364d29e5b781ac63e3 Mon Sep 17 00:00:00 2001 From: Ninad-S <144244166+Ninad-S@users.noreply.github.com> Date: Tue, 1 Oct 2024 17:53:04 -0500 Subject: [PATCH 64/87] Updated the about page --- src/app/about/page.tsx | 86 +++++++++++++++++++++++++++--------------- 1 file changed, 56 insertions(+), 30 deletions(-) diff --git a/src/app/about/page.tsx b/src/app/about/page.tsx index 2a0e1b80..af774c62 100644 --- a/src/app/about/page.tsx +++ b/src/app/about/page.tsx @@ -1,4 +1,4 @@ -import Header from '@src/components/header/BaseHeader'; +import Header from '@src/components/BaseHeader'; import type { Metadata } from 'next'; export const metadata: Metadata = { @@ -14,40 +14,48 @@ export const metadata: Metadata = { }; const About = () => { + const teamMembers = [ + { name: "Ethan Bickel", position: "Project Lead" }, + { name: "Braeden Kotko", position: "Engineer" }, + { name: "Connor Harris", position: "Engineer" }, + { name: "Jonathan Le", position: "Engineer" }, + { name: "Alex Vazquez", position: "Engineer" }, + { name: "Ishaan Gupta", position: "Engineer" }, + { name: "Ritvik Thota", position: "Engineer" } + + ]; + const recruits= [ + { name: "Jordan Joelson", position: "Engineer" }, + { name: "Mansi Cherukupally", position: "Engineer" }, + { name: "Aryav Rastogi", position: "Engineer" }, + { name: "Sreevasan Siasubramanian", position: "Engineer" }, + { name: "Ninad Sudarsanam", position: "Engineer" }, + { name: "Shivesh Gupta", position: "Engineer" }, + { name: "Natalia Sekulic", position: "Engineer" }, + { name: "Mamoun Elmamoun", position: "Engineer" }, + { name: "Chloe Alzaga", position: "Engineer" }, + { name: "Joshua Perez", position: "Engineer" }, + { name: "Ankith Ganji", position: "Engineer" }, + { name: "Valeria Gallardo", position: "Designer" }, + { name: "Waseef Kabir", position: "Designer" }, + { name: "Ved Mahant", position: "Designer" } + ]; return (
-

- About us -

+

- Project Jupiter + About Jupiter

-

Our Goal

+

- Jupiter is a user-friendly platform that can be utilized by students - to seamlessly join school clubs. This tool allows students to browse - through the list of available clubs, their activities, and - objectives, all in one place. Students can easily sign up for clubs - that interest them and receive real-time updates on events, - meetings, and other activities organized by the clubs. The platform - also enables club leaders to manage and promote their clubs more - efficiently, keeping members informed about important details and - facilitating communication between members. -
-
- Jupiter comes with several features that make it an ideal tool for - school club management. For instance, the platform provides a - comprehensive dashboard that enables club leaders to track - attendance, monitor club performance, and collect feedback from - members. The tool also integrates with the school's social - media pages and website, making it easy for students to discover - clubs that match their interests. With Jupiter, students can easily - find and join clubs, and club leaders can manage their clubs more - effectively, leading to more successful and fulfilling club - experiences for everyone involved. + Jupiter is a platform being developed by nebula labs in order to help students find organizations and events on and around campus. + + Jupiter let's you track organizations you're interested in, find new organizations, and keep up to date on events you want to attend. + + For organizations we offer a better way to keep your info up to date, and for people well suited for your organization to find out about you and your events.

@@ -55,18 +63,36 @@ const About = () => { Our Team
- {Array.from({ length: 8 }).map((_, key) => ( + {teamMembers.map((member, key) => (

- Name + {member.name}

-

Position

+

{member.position}

))}
+
+

+ Recruits +

+
+ {recruits.map((member, key) => ( +
+

+ {member.name} +

+

{member.position}

+
+ ))} +
+
From 3ccdaa962b6367381e3a304c1b43cc4e9508f753 Mon Sep 17 00:00:00 2001 From: MamounE1 Date: Tue, 1 Oct 2024 18:03:37 -0500 Subject: [PATCH 65/87] make event countdown work --- src/components/events/EventTimeAlert.tsx | 45 +++++++++++++++++++----- 1 file changed, 36 insertions(+), 9 deletions(-) diff --git a/src/components/events/EventTimeAlert.tsx b/src/components/events/EventTimeAlert.tsx index c027f020..a0eee0fe 100644 --- a/src/components/events/EventTimeAlert.tsx +++ b/src/components/events/EventTimeAlert.tsx @@ -10,6 +10,7 @@ import { type ReactNode } from 'react'; type EventTimeAlertProps = { event: SelectEvent; }; + type BaseProps = { children: ReactNode; className?: string }; const Base = ({ children, className }: BaseProps) => { return ( @@ -22,19 +23,43 @@ const Base = ({ children, className }: BaseProps) => {
); }; -const EventTimeAlert = ({ event }: EventTimeAlertProps) => { - const now = new Date(); + +import React, {useState, useEffect} from 'react'; + +const EventTimeAlert = ({ event }: EventTimeAlertProps) => +{ + const [now, setNow] = useState(new Date()); + + useEffect(() => { + const intervalId = setInterval(() => + { + setNow (new Date()); + }, 1000); + + return () => clearInterval(intervalId); + + }, []); + const start = event.startTime; const hourDiff = differenceInHours(start, now); - if (event.startTime.getTime() < Date.now()) { - if (event.endTime.getTime() < Date.now()) { + + if (event.startTime.getTime() < Date.now()) + { + if (event.endTime.getTime() < Date.now()) + { return over :(; - } else { + } + else + { return NOW; } - } else { - if (differenceInDays(start, now) < 1) { - if (hourDiff < 1) { + } + else + { + if (differenceInDays(start, now) < 1) + { + if (hourDiff < 1) + { return ( {differenceInMinutes(start, now)} minutes @@ -45,7 +70,9 @@ const EventTimeAlert = ({ event }: EventTimeAlertProps) => { } else { return {hourDiff} hours; } - } else { + } + else + { return ( {differenceInDays(start, now)} days ); From 14cef9abebd78db60968c5a1d6367d1f6b2fb209 Mon Sep 17 00:00:00 2001 From: Ethan Bickel Date: Thu, 3 Oct 2024 13:30:55 -0500 Subject: [PATCH 66/87] remove debug statement and reword logic --- src/components/searchBar/index.tsx | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/components/searchBar/index.tsx b/src/components/searchBar/index.tsx index cd90c59f..228aeb96 100644 --- a/src/components/searchBar/index.tsx +++ b/src/components/searchBar/index.tsx @@ -18,11 +18,8 @@ export const SearchBar = (props: SearchBarProps) => { {...props} type="text" className={`h-10 w-full rounded-full border pl-10 ${submitButton ? 'pr-[38px]' : 'pr-3'} focus:outline-none ${props.className}`} - onSubmit={() => { - console.log('howdy from submit'); - }} onKeyDown={(e) => { - if (e.key === 'Enter' && submitLogic) { + if (e.key === 'Enter' && typeof submitLogic !== 'undefined') { submitLogic(); } }} From 674959dbadba850707d1f527ad7f05e435f8be33 Mon Sep 17 00:00:00 2001 From: Ethan Bickel Date: Thu, 3 Oct 2024 13:40:44 -0500 Subject: [PATCH 67/87] move prettier config to modules and add typing --- .prettierrc.js | 9 --------- .prettierrc.mjs | 16 ++++++++++++++++ 2 files changed, 16 insertions(+), 9 deletions(-) delete mode 100644 .prettierrc.js create mode 100644 .prettierrc.mjs 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; From c3a1532e7cb98f3a2e2685aec085aa177239ef3e Mon Sep 17 00:00:00 2001 From: Ethan Bickel Date: Thu, 3 Oct 2024 14:41:23 -0500 Subject: [PATCH 68/87] fix formatting check --- .github/workflows/prettierCheck.yml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/.github/workflows/prettierCheck.yml b/.github/workflows/prettierCheck.yml index e642ea75..09538a2f 100644 --- a/.github/workflows/prettierCheck.yml +++ b/.github/workflows/prettierCheck.yml @@ -16,9 +16,11 @@ jobs: npm i --no-save prettier prettier-plugin-tailwindcss mv package.json.bak package.json - name: Run prettier + id: prettier + continue-on-error: true run: | - files=`npx prettier . -l` || st=$? && st=$? - echo status=`echo $st`>>"$GITHUB_ENV" - echo files=`echo $files`>> "$GITHUB_ENV" + echo "files=${npx prettier . -l}">> "$GITHUB_ENV" - name: generate errors/summary run: .github/workflows/generateCheck.sh + env: + status: ${{ success() && 0 || 1 }} From 2b3468a1c91c3fd8443df9ab275bc25ad693d40d Mon Sep 17 00:00:00 2001 From: Ethan Bickel Date: Thu, 3 Oct 2024 14:46:50 -0500 Subject: [PATCH 69/87] fix status check --- .github/workflows/prettierCheck.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/prettierCheck.yml b/.github/workflows/prettierCheck.yml index 09538a2f..d875a5e8 100644 --- a/.github/workflows/prettierCheck.yml +++ b/.github/workflows/prettierCheck.yml @@ -23,4 +23,4 @@ jobs: - name: generate errors/summary run: .github/workflows/generateCheck.sh env: - status: ${{ success() && 0 || 1 }} + status: ${{ steps.prettier.outcome == 'success' && 0 || 1 }} From 37b81f7e0835535d1db297d61cbd73dd20516585 Mon Sep 17 00:00:00 2001 From: Ethan Bickel Date: Thu, 3 Oct 2024 14:50:17 -0500 Subject: [PATCH 70/87] fix substitution --- .github/workflows/prettierCheck.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/prettierCheck.yml b/.github/workflows/prettierCheck.yml index d875a5e8..11982147 100644 --- a/.github/workflows/prettierCheck.yml +++ b/.github/workflows/prettierCheck.yml @@ -19,7 +19,7 @@ jobs: id: prettier continue-on-error: true run: | - echo "files=${npx prettier . -l}">> "$GITHUB_ENV" + echo files=`npx prettier . -l` >> "$GITHUB_ENV" - name: generate errors/summary run: .github/workflows/generateCheck.sh env: From 4b1b9837b620b3cb55997b2bc37e63a840b78f09 Mon Sep 17 00:00:00 2001 From: Ethan Bickel Date: Thu, 3 Oct 2024 15:08:44 -0500 Subject: [PATCH 71/87] simplify install --- .github/workflows/prettierCheck.yml | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/.github/workflows/prettierCheck.yml b/.github/workflows/prettierCheck.yml index 11982147..ea76a9ad 100644 --- a/.github/workflows/prettierCheck.yml +++ b/.github/workflows/prettierCheck.yml @@ -11,15 +11,11 @@ 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 id: prettier continue-on-error: true - run: | - echo files=`npx prettier . -l` >> "$GITHUB_ENV" + run: echo files=`npx prettier . -l` >> "$GITHUB_ENV" - name: generate errors/summary run: .github/workflows/generateCheck.sh env: From 8fdeb9d79a2f5ac9b1f33edf6d844f4aa5965a1b Mon Sep 17 00:00:00 2001 From: Ethan Bickel Date: Thu, 3 Oct 2024 15:14:02 -0500 Subject: [PATCH 72/87] formatting fixes --- .../[clubId]/create/CreateEventForm.tsx | 331 ++++++++++-------- .../[clubId]/create/EventCardPreview.tsx | 110 +++--- src/app/manage/[clubId]/create/TimeSelect.tsx | 177 ++++++---- src/app/manage/[clubId]/create/page.tsx | 1 - src/server/api/routers/event.ts | 7 +- src/utils/formSchemas.ts | 2 +- 6 files changed, 366 insertions(+), 262 deletions(-) diff --git a/src/app/manage/[clubId]/create/CreateEventForm.tsx b/src/app/manage/[clubId]/create/CreateEventForm.tsx index fb3fbf0e..bd09638c 100644 --- a/src/app/manage/[clubId]/create/CreateEventForm.tsx +++ b/src/app/manage/[clubId]/create/CreateEventForm.tsx @@ -1,142 +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, - 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({ - 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: (data) => { if (data) { - router.push(`/event/${data}`); - } }, - onError: () => { - setLoading(false); - } - }) + 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 && !loading) { - setLoading(true); - createMutation.mutate(data); - } - }); + const onSubmit = handleSubmit((data: z.infer) => { + if (!createMutation.isPending && !loading) { + setLoading(true); + createMutation.mutate(data); + } + }); - return (
void onSubmit(e)} className="w-full flex flex-row flex-wrap justify-start gap-10 overflow-x-clip text-[#4D5E80] pb-4"> -
-
- Create Club Event for -
- -
-
-
-

Event Picture

-

Drag or choose file to upload

-
- -

JPEG, PNG, or SVG

-
-
-
-

Event Details

-
- - -
-
- - -
-
-
- -

{watchDescription && watchDescription.length} of 1000 Characters used

-
-