Skip to content
Merged
Show file tree
Hide file tree
Changes from 63 commits
Commits
Show all changes
87 commits
Select commit Hold shift + click to select a range
6558d39
feat: make Panel collapsible
Isoscelestial Feb 5, 2026
a6303c6
feat: use new collapsing panel system for club listing officers panel…
Isoscelestial Feb 6, 2026
872436d
chore(panel): cleanup comments, more logical callback function callin…
Isoscelestial Feb 6, 2026
b68be2e
fix(panel): add slotClassNames prop to resolve inconsistent absolutel…
Isoscelestial Feb 6, 2026
4e11b04
add: transparent and conditionally transparent panels
Isoscelestial Feb 13, 2026
4e25efe
Merge branch 'feature/improved-panels' into feature/redesigned-events…
Isoscelestial Feb 14, 2026
b697be1
add(events): begin implementing redesigned events directory page
Isoscelestial Feb 14, 2026
4f2692e
feat(events): move events directory tab switcher to layout
Isoscelestial Feb 14, 2026
6216dcb
fix(events): tab switcher forgetting selected tab when page refreshed
Isoscelestial Feb 14, 2026
5c542fa
feat(events): begin implementing UI for events directory page body
Isoscelestial Feb 14, 2026
5cb9a9d
feat(events): add filter list for time and location filters; begin ad…
Isoscelestial Feb 15, 2026
b554667
fix(events): fix modal and layout styles
Isoscelestial Feb 15, 2026
6168fbf
feat(events): add custom date pickers
Isoscelestial Feb 15, 2026
7af9cd4
feat: temporarily modify events.byDateRange to also return club data
Isoscelestial Feb 18, 2026
12033e6
feat(events): add view options bar
Isoscelestial Feb 18, 2026
7804923
Merge pull request #636 from UTDNebula/develop
TyHil Feb 20, 2026
7b07f50
fix(events): stop clear button triggering exclusion on filter list
Isoscelestial Feb 21, 2026
153c521
feat(events): begin adding filter tags
Isoscelestial Feb 21, 2026
8131576
feat(events): begin adding event filter schema; add URL query params …
Isoscelestial Feb 23, 2026
95eaea4
feat(events): split panels into memoized components, add location inc…
Isoscelestial Mar 1, 2026
d581836
fix(events): unstable objects causing re-renders, missing location ex…
Isoscelestial Mar 1, 2026
d0e4d78
feat: useFilterFieldsMemo wrapper hook for useMemo
Isoscelestial Mar 1, 2026
43be82b
feat: add keybinds to toggle sidebar and change page
Isoscelestial Mar 1, 2026
82abfa0
feat(events): tags filter
Isoscelestial Mar 1, 2026
8c93823
feat(events): date filter
Isoscelestial Mar 1, 2026
8025dbe
fix: stabilize tags filter panel
Isoscelestial Mar 2, 2026
c805d27
fix: set param's custom dateStart and dateEnd if their state has a value
Isoscelestial Mar 2, 2026
ffce070
refactor: setParams function to easily set the URL search params, add…
Isoscelestial Mar 2, 2026
a774a06
feat(events): filters bar, improve useFilterFieldsMemo, use prop dril…
Isoscelestial Mar 9, 2026
fa7b687
refactor: type safe wrapper class for URLSearchParams with callback f…
Isoscelestial Mar 9, 2026
715a1c7
feat(events): fully functional filters bar
Isoscelestial Mar 9, 2026
48e548d
chore: lint and format
Isoscelestial Mar 9, 2026
fa5a9f2
feat(events): better mobile pagination input field
Isoscelestial Mar 11, 2026
2ef78d0
fix: /events tabs not set on navigate; FilterList exclusion visibilit…
Isoscelestial Mar 11, 2026
befc860
git ignore .vscode
Isoscelestial Mar 11, 2026
1c797cd
feat(events): view options
Isoscelestial Mar 13, 2026
d86b60f
fix(events): hotkey responsiveness, round date days, move sidebar but…
Isoscelestial Mar 17, 2026
6f39271
feat(events): clear all filters buttons
Isoscelestial Mar 17, 2026
ea83b1c
feat(events): search bar
Isoscelestial Mar 18, 2026
ddc15c9
feat(events): misc. style tweaks
Isoscelestial Mar 18, 2026
f27177a
Merge pull request #657 from UTDNebula/develop
AbhiramTadepalli Mar 19, 2026
2eb8e0e
fix(events): misc fixes and refactors
Isoscelestial Mar 23, 2026
a3436b3
feat(events): dirty state for filter chip
Isoscelestial Mar 24, 2026
21c3af1
feat(events): clear query field button, pagination on bottom of page
Isoscelestial Mar 30, 2026
f7672cd
feat(events): API query calls, begin rewriting findByFilters procedur…
Isoscelestial Mar 31, 2026
c7fff62
feat(events): sort by recency when viewing past events
Isoscelestial Mar 31, 2026
18ed6ef
fix(events): go to first page when filters change
Isoscelestial Mar 31, 2026
c3457bf
feat(events): pagination response
Isoscelestial Mar 31, 2026
bf1281e
feat(events): use SQL select rather than Drizzle query, implement tag…
Isoscelestial Apr 1, 2026
b616e36
feat(events): performance improvements, loading state, framer motion,…
Isoscelestial Apr 2, 2026
218b0ec
feat(events): use SwipeableDrawer instead of Modal for mobile filters…
Isoscelestial Apr 5, 2026
0ce8c81
feat(events): implement clubs filter, add placeholder for query and l…
Isoscelestial Apr 5, 2026
080942e
fix(events): default export for useStable, responsive event cards
Isoscelestial Apr 5, 2026
1e6b52f
fix(events): make event search bar work by adding schema index
Isoscelestial Apr 5, 2026
51c7c3d
feat(events): change view layout
Isoscelestial Apr 5, 2026
5d396e9
fix(events): don't refetch on mount if server fetched already, displa…
Isoscelestial Apr 5, 2026
a27ad9e
feat(events): add event count to header, comment out calendar feed su…
Isoscelestial Apr 5, 2026
dc39cc8
fix(events): improved error handling
Isoscelestial Apr 5, 2026
3b68782
feat(events): abstract setParams, create ParamSetter class, move rela…
Isoscelestial Apr 5, 2026
257e0fb
feat(events): change z index of sentry feedback button instead of hid…
Isoscelestial Apr 5, 2026
8dd2bf2
fix(events): use store instead of raising state, which caused infinit…
Isoscelestial Apr 6, 2026
e4e905b
chore: remove deprecated schemas from eventFilter.ts
Isoscelestial Apr 6, 2026
de2f0f9
feat(events): add snackbar when using a filter that requires being si…
Isoscelestial Apr 6, 2026
9337ecf
Merge branch 'develop' into feature/redesigned-events-directory
Isoscelestial Apr 6, 2026
5ecdbd2
fix: merge errors
Isoscelestial Apr 6, 2026
ba3d5ba
refactor: combine ClubTagEdit and ClubTagFilter
Isoscelestial Apr 6, 2026
d0fa490
refactor(events): improved querying for registered events and joined …
Isoscelestial Apr 6, 2026
d20fded
Merge branch 'develop'
BK2004 Apr 7, 2026
ec57a80
Merge pull request #679 from UTDNebula/develop
TyHil Apr 13, 2026
01cc573
refactor: use factory method for creating a ParamSetter
Isoscelestial Apr 23, 2026
5a783d0
Merge branch 'develop' into feature/redesigned-events-directory
Isoscelestial Apr 26, 2026
402c2ae
fix: drizzle migration
Isoscelestial Apr 26, 2026
cda5ccd
fix: error when setting state in render
Isoscelestial Apr 26, 2026
bb53570
refactor: make PageHeader component
Isoscelestial Apr 26, 2026
a0a76c0
feat: improve focus states and keyboard accessibility for EventCard
Isoscelestial Apr 26, 2026
b9c2bfd
fix: add back missing migration journal entry
Isoscelestial Apr 26, 2026
0427068
fix: fully add back missing migration
Isoscelestial Apr 26, 2026
050e70d
refactor: copy updated FilterChip and FilterList from UTD Trends
Isoscelestial Apr 26, 2026
c264009
refactor: more sensible file structure
Isoscelestial Apr 26, 2026
2f00c71
Merge branch 'feature/redesigned-events-directory' of https://github.…
BK2004 May 4, 2026
1431daf
resolve delete conflict
BK2004 May 4, 2026
e00cbf3
fix API distinctTags and topTags type mismatch in ClubTagAutocomplete
BK2004 May 4, 2026
218b65b
run format/lint
BK2004 May 4, 2026
4daadeb
fix: add back tag count to ClubTagAutocomplete
Isoscelestial May 4, 2026
90f1f42
feat: list view EventCard improvements
Isoscelestial May 4, 2026
c3c74c2
feat: open dropdown menu on mouse down instead
Isoscelestial May 4, 2026
5958a1b
refactor: use distinct schemas for URL params and filters, and use tr…
Isoscelestial May 5, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,4 @@ yarn-error.log*

.idea
.neon
.vscode
2 changes: 1 addition & 1 deletion src/app/admin/clubs/[slug]/events/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ export default async function Page({ params, searchParams }: Props) {
includePast,
currentTime: now,
}),
api.event.countByClubId({
api.event.count({
clubId: club.id,
includePast,
currentTime: now,
Expand Down
14 changes: 14 additions & 0 deletions src/app/events/(directory)/calendar/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
const Events = async () => {
return (
<main className="font-bold relative select-none h-72">
<h1 className="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 text-[200px] text-slate-200 dark:text-slate-800">
WIP
</h1>
<h2 className="absolute bottom-1/2 left-1/2 -translate-x-1/2 translate-y-20 text-3xl text-slate-800 dark:text-slate-200">
Coming soon!
</h2>
</main>
);
};

export default Events;
22 changes: 22 additions & 0 deletions src/app/events/(directory)/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { ReactNode } from 'react';
import EventsTitle from '@src/components/events/directory/EventsTitle';
import { EventHeader } from '@src/components/header/Header';

type EventDirectoryLayoutProps = {
children: ReactNode;
};

export default async function EventDirectoryLayout({
children,
}: EventDirectoryLayoutProps) {
return (
<>
<EventHeader />
<main className="mb-5 flex flex-col sm:px-4 max-w-6xl mx-auto">
{/* EventsTitle should be in layout.tsx so that it doesn't re-render between pages */}
<EventsTitle />
<div className="flex flex-col gap-y-4 max-sm:px-4">{children}</div>
</main>
</>
);
}
47 changes: 47 additions & 0 deletions src/app/events/(directory)/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { type Metadata } from 'next';
import { redirect } from 'next/navigation';
import EventsBody from '@src/components/events/directory/EventsBody';
import { api } from '@src/trpc/server';
import { eventFiltersSchema, EventParamsSchema } from '@src/utils/eventFilter';

export const metadata: Metadata = {
title: 'Events',
description: 'The place to find events at UTD.',
alternates: {
canonical: 'https://clubs.utdnebula.com/events',
},
openGraph: {
url: 'https://clubs.utdnebula.com/events',
description: 'The place to find events at UTD.',
},
};
const Events = async (props: { searchParams: Promise<EventParamsSchema> }) => {
const searchParams = await props.searchParams;
const parsed = eventFiltersSchema.parse(searchParams);

// Server-side query to avoid client-side fetching on load
const results = await Promise.allSettled([
api.event.findByFilters({ filters: parsed }),
api.event.count({ includePast: true }),
]);

const initialEvents =
results[0].status === 'fulfilled' ? results[0].value : undefined;
const count = results[1].status === 'fulfilled' ? results[1].value : 0;

// If error fetching events with current filters, clear all filters and reload page
if (
results[0].status === 'rejected' &&
Object.keys(searchParams).length > 0
) {
redirect('/events');
}

return (
<>
<EventsBody initialQueryData={initialEvents} total={count} />
</>
);
};

export default Events;
40 changes: 0 additions & 40 deletions src/app/events/EventsNone.tsx

This file was deleted.

63 changes: 0 additions & 63 deletions src/app/events/EventsTitle.tsx

This file was deleted.

47 changes: 0 additions & 47 deletions src/app/events/page.tsx

This file was deleted.

2 changes: 1 addition & 1 deletion src/app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ const inter = Inter({

const baiJamjuree = Bai_Jamjuree({
subsets: ['latin'],
weight: ['500', '700'],
weight: ['500', '600', '700'],
variable: '--font-display',
});

Expand Down
2 changes: 1 addition & 1 deletion src/app/manage/[slug]/events/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ export default async function Page({
currentTime: now,
});

const totalCount = await api.event.countByClubId({
const totalCount = await api.event.count({
clubId: club.id,
includePast,
currentTime: now,
Expand Down
26 changes: 14 additions & 12 deletions src/components/club/listing/ClubDetailsCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -109,18 +109,20 @@ export default function ClubDetailsCard({
}

return (
<Panel className="text-sm !gap-1" id={id} smallPadding heading="Details">
{items.length ? (
items.flatMap((item, index) => {
const row = [item];
if (index < items.length - 1) {
row.push(<Divider key={index} />);
}
return row;
})
) : (
<span className="text-slate-600 dark:text-slate-400">No details</span>
)}
<Panel className="text-sm" id={id} smallPadding heading="Details">
<div className="flex flex-col gap-1">
{items.length ? (
items.flatMap((item, index) => {
const row = [item];
if (index < items.length - 1) {
row.push(<Divider key={index} />);
}
return row;
})
) : (
<span className="text-slate-600 dark:text-slate-400">No details</span>
)}
</div>
</Panel>
);
}
51 changes: 28 additions & 23 deletions src/components/club/listing/OfficerList.tsx
Comment thread
TyHil marked this conversation as resolved.
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ export default function OfficerList({
// The height of the officer card at start should be the distance between officer's top and the right side's bottom
const targetHeight = rightBottom - officerTop; // will be negative in mobile -> sets truncation to true, but maxHeight is default 300px
const contentHeight = contentRef.current.scrollHeight + 80; // height of the full officer card + padding/header space
setMaxHeight(targetHeight > 300 ? targetHeight : 300); // at least 300px to show 2 officers
setMaxHeight(Math.max(targetHeight, 230)); // at least 230px to show 2 officers
setNeedsTruncation(contentHeight > targetHeight && officers.length > 0); // if no officers, no truncation -- just show error text
};

Expand All @@ -50,23 +50,25 @@ export default function OfficerList({
return () => observer.disconnect();
}, [officers, id]);

// dynamically determine css height in expanded or normal states
const containerStyle =
isExpanded || !needsTruncation
? { height: 'auto' }
: maxHeight
? { height: `${maxHeight}px` }
: { height: 'auto' };

return (
<Panel
className="text-sm"
slotClassNames={{ collapse: 'relative' }}
id={id}
smallPadding
heading="Officers"
style={containerStyle}
enableCollapsing={
needsTruncation
? {
toggleOnHeadingClick: true,
collapsedSize: maxHeight ?? undefined,
}
: false
}
collapse={needsTruncation && !isExpanded}
onCollapseClick={() => setIsExpanded((prev) => !prev)}
>
<div className="relative flex-1 min-h-0 overflow-hidden">
<div className="flex-1 min-h-0 overflow-hidden">
<div ref={contentRef} className="flex flex-col gap-4">
{officers.length > 0 ? (
officers.map((officer) => (
Expand All @@ -78,21 +80,24 @@ export default function OfficerList({
</span>
)}
</div>

{/* fade overlay only shows if content is taller than right side AND not expanded */}
{needsTruncation && !isExpanded && (
<div className="absolute bottom-0 left-0 w-full h-16 bg-gradient-to-t from-white dark:from-neutral-800 to-transparent pointer-events-none" />
)}
</div>

{needsTruncation && (
<div className="mt-2 pt-2 border-t border-slate-300 dark:border-slate-700 z-10">
<button
onClick={() => setIsExpanded(!isExpanded)}
className="w-full text-sm font-semibold text-royal dark:text-cornflower-300 hover:text-royalDark dark:hover:text-cornflower-400 underline decoration-transparent hover:decoration-inherit transition text-center"
>
{isExpanded ? 'Show less' : 'See all officers'}
</button>
<div
className={`${needsTruncation && !isExpanded ? 'absolute' : ''} bottom-0 left-0 w-full`}
>
{/* fade overlay only shows if content is taller than right side AND not expanded */}
{!isExpanded && (
<div className="h-16 bg-gradient-to-t from-white dark:from-neutral-800 to-transparent pointer-events-none" />
)}
<div className="bg-white dark:bg-neutral-800 pt-2 border-t border-slate-300 dark:border-slate-700 z-10">
<button
onClick={() => setIsExpanded(!isExpanded)}
className="w-full text-sm font-semibold text-royal dark:text-cornflower-300 hover:text-royalDark dark:hover:text-cornflower-400 underline decoration-transparent hover:decoration-inherit transition text-center"
>
{isExpanded ? 'Show less' : 'See all officers'}
</button>
</div>
</div>
)}
</Panel>
Expand Down
Loading
Loading