From dc432f08f956ca3ded4013ad33e8a4ea54300d32 Mon Sep 17 00:00:00 2001 From: zoe2276 Date: Fri, 17 Jul 2026 19:39:57 -0500 Subject: [PATCH 01/21] addition of sidebar entry for events page --- src/app/admin/layout/Sidebar.tsx | 13 ++++++++- src/app/admin/panels/events/page.tsx | 40 ++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 1 deletion(-) create mode 100644 src/app/admin/panels/events/page.tsx diff --git a/src/app/admin/layout/Sidebar.tsx b/src/app/admin/layout/Sidebar.tsx index 224684b9..0466ee4c 100644 --- a/src/app/admin/layout/Sidebar.tsx +++ b/src/app/admin/layout/Sidebar.tsx @@ -5,7 +5,7 @@ import { cn } from '@/util' import Link from 'next/link' import { usePathname } from 'next/navigation' import { FaUsers, FaUserShield, FaUserTag, FaDonate } from 'react-icons/fa' -import { FaClipboardUser, FaDollarSign } from 'react-icons/fa6' +import { FaClipboardUser, FaDollarSign, FaCalendarDays } from 'react-icons/fa6' import { FiChevronLeft } from 'react-icons/fi' import type { IconType } from 'react-icons/lib' import { useLocalStorage } from 'usehooks-ts' @@ -17,6 +17,7 @@ interface SidebarProps { positionCount?: number roleCount?: number permissionCount?: number + eventCount?: number } export default function Sidebar({ @@ -26,6 +27,7 @@ export default function Sidebar({ positionCount, roleCount, permissionCount, + eventCount, }: SidebarProps) { const [open, setOpen] = useLocalStorage('pv.admin-nav-open', true) @@ -84,6 +86,7 @@ export default function Sidebar({ count={permissionCount} open={open} /> + + + - - + + ) } diff --git a/src/app/admin/panels/events/page.module.css b/src/app/admin/panels/events/page.module.css index 57a66af1..8c129a90 100644 --- a/src/app/admin/panels/events/page.module.css +++ b/src/app/admin/panels/events/page.module.css @@ -1,4 +1,4 @@ -:root:not(.listItem) { +.root { --s-unknown-brd: slategrey; --s-unknown-col: rgb(from var(--s-unknown-brd) r g b / 0.8); --s-unknown-bg: rgb(from var(--s-unknown-brd) r g b / 0.1); @@ -18,6 +18,9 @@ --s-cancelled-brd: #a52c20; --s-cancelled-col: rgb(from var(--s-cancelled-brd) r g b / 0.8); --s-cancelled-bg: rgb(from var(--s-cancelled-brd) r g b / 0.1); + + display: inherit; + flex: inherit; } .listItem { @@ -38,15 +41,15 @@ &::before { content: ''; position: absolute; - height: 100%; - width: 0.5rem; + height: 98%; + width: 0.85rem; left: 0.25rem; - top: 0; + top: 1%; border-left-width: 0.375rem; border-left-style: solid; - border-top-left-radius: 0.5rem; - border-bottom-left-radius: 0.5rem; + border-top-left-radius: 1rem; + border-bottom-left-radius: 1rem; } &.unknown::before { @@ -106,7 +109,6 @@ height: calc(100dvh - 100px); flex: 1; overflow-y: auto; - padding-block: 1rem; } .emptyState { @@ -128,6 +130,7 @@ position: sticky; top: 0; z-index: 20; + padding-block: 1rem; background: linear-gradient( to bottom, @@ -231,24 +234,45 @@ .detailsCreatedByContainer, .attendeeMeta { display: flex; + flex-flow: row wrap; + justify-content: center; align-items: center; - gap: 0.5rem; + column-gap: 0.5rem; } -@keyframes spin { - 0% { - transform: rotate(-360deg); +.attendeeListItem { + border-radius: 1rem; + overflow: hidden; + + & > .selectedAttendee > div, + & > div { + border-radius: 0; + margin: 0; } } -@keyframes recol { - 0% { - background-color: #0ea5e9; - } - 50% { - background-color: white; - } - 100% { - background-color: #a52c20; - } +.attendeeContainer { + display: flex; + justify-content: space-between; + align-items: center; + width: 100%; +} + +.attendeeCount { + display: inline; + font-size: 1rem; + font-weight: 400; +} + +.attendeeCardRedirectButton { + border-radius: 0.75rem; + + font-size: 0.75rem; + font-weight: 600; + padding: 0.75rem; +} + +.attendeeCardRedirectIcon { + flex-basis: 2rem; + aspect-ratio: 1 / 1; } diff --git a/src/app/admin/panels/events/page.tsx b/src/app/admin/panels/events/page.tsx index d177932a..e4b0fce4 100644 --- a/src/app/admin/panels/events/page.tsx +++ b/src/app/admin/panels/events/page.tsx @@ -19,15 +19,13 @@ import { zDiscordEvent, DiscordEventStatus, zDiscordEventAttendee, - zDiscordUser, - DiscordUser, } from '@/contracts/data' import { zDiscordEventDetailsResponse } from '@/contracts/responses' import { dateService } from '@/services' import { useFetch, usePaginatedSearch } from '@/util/hooks' import { keepPreviousData, skipToken, useQuery } from '@tanstack/react-query' import Image from 'next/image' -import { useSearchParams } from 'next/navigation' +import { redirect, useSearchParams } from 'next/navigation' import { useState } from 'react' import { FaUsers } from 'react-icons/fa6' import z from 'zod' @@ -102,6 +100,7 @@ export default function Page() { if (event.id === selectedEventId) return if (!loadingEvent) setLoadingEvent(true) setSelectedEventId(event.id) + redirect(`/admin/panels/events?eventId=${event.id}`) } const getStatusName = (status: DiscordEventStatus | null) => @@ -148,7 +147,7 @@ export default function Page() { } return ( - <> +
- + + Attendees + {eventQuery.data?.event.attendees + .length !== 0 && ( + + {` (${ + eventQuery.data?.event + .attendees.length + })`} + + )} + + } + subtitle={ + eventQuery.data?.event.attendees.length.toString() ?? + '' + } + > { } @@ -341,6 +362,6 @@ export default function Page() { )}
- + ) } diff --git a/src/app/admin/panels/members/page.tsx b/src/app/admin/panels/members/page.tsx index 400a6f6e..87fd7cfc 100644 --- a/src/app/admin/panels/members/page.tsx +++ b/src/app/admin/panels/members/page.tsx @@ -38,6 +38,7 @@ import { useQuery, useQueryClient, } from '@tanstack/react-query' +import { useSearchParams } from 'next/navigation' import { useCallback, useMemo, useState } from 'react' import { FaUsers, FaUserTag } from 'react-icons/fa' import { FaClipboardUser, FaDollarSign, FaAddressCard } from 'react-icons/fa6' @@ -55,8 +56,11 @@ const tabs: TabSpec[] = [ export default function Page() { const queryClient = useQueryClient() const { ready, onGet, onPatch, onPost } = useFetch() - - const [selectedId, setSelectedId] = useState(null) + const navParams = useSearchParams() + const navVal = navParams.get('id') + const [selectedId, setSelectedId] = useState( + navVal ? +navVal : null + ) const [selectedHistory, setSelectedHistory] = useState | null>(null) diff --git a/src/components/common/CollapsibleSection.tsx b/src/components/common/collapsible_section/CollapsibleSection.tsx similarity index 78% rename from src/components/common/CollapsibleSection.tsx rename to src/components/common/collapsible_section/CollapsibleSection.tsx index 6e81d6c1..fe42460c 100644 --- a/src/components/common/CollapsibleSection.tsx +++ b/src/components/common/collapsible_section/CollapsibleSection.tsx @@ -1,13 +1,13 @@ 'use client' -import styles from './CollapsibleSection.module.css' +import styles from './collapsibleSection.module.css' import { cn } from '@/util' import { useState } from 'react' import { FiChevronDown, FiChevronLeft } from 'react-icons/fi' export interface CollapsibleSectionProps { children?: React.ReactNode - title?: string + title?: string | React.ReactNode subtitle?: string initialOpenState?: boolean subGroup?: boolean @@ -26,20 +26,24 @@ export function CollapsibleSection({
{title && (
-

- {title} + {typeof title === 'string' ? ( +

{title}

+ ) : ( + <>{title} + )} - +
{subtitle &&

{subtitle}

} )} diff --git a/src/components/common/CollapsibleSection.module.css b/src/components/common/collapsible_section/collapsibleSection.module.css similarity index 63% rename from src/components/common/CollapsibleSection.module.css rename to src/components/common/collapsible_section/collapsibleSection.module.css index 53060855..79ae26d1 100644 --- a/src/components/common/CollapsibleSection.module.css +++ b/src/components/common/collapsible_section/collapsibleSection.module.css @@ -1,13 +1,20 @@ .header { + display: flex; + flex-direction: column; margin-top: 1rem; margin-bottom: 1rem; } .title { position: relative; + display: flex; + justify-content: space-between; + align-items: center; + margin: 1rem 0; + font-size: 1.25rem; - line-height: 1.75rem; font-weight: 600; + line-height: 1.75rem; } .titleSub { @@ -15,23 +22,23 @@ } .toggle { - position: absolute; - right: 0; - top: 0; display: flex; - width: 2rem; - height: 2rem; - cursor: pointer; - align-items: center; justify-content: center; - border-radius: 9999px; - border: 2px solid rgb(229, 231, 235); + align-items: center; + width: 2rem; + aspect-ratio: 1 / 1; + color: rgb(156, 163, 175); - background: transparent; -} -.toggle:hover { - color: rgb(107, 114, 128); + border-color: rgb(229, 231, 235); + border-width: 2px; + border-radius: 9999px; + + cursor: pointer; + + &:hover { + color: rgb(107, 114, 128); + } } .subtitle { diff --git a/src/components/common/forms/FormGroup.tsx b/src/components/common/forms/FormGroup.tsx index 02a1ef4b..782c82de 100644 --- a/src/components/common/forms/FormGroup.tsx +++ b/src/components/common/forms/FormGroup.tsx @@ -1,7 +1,7 @@ import { DynamicFormFieldProps } from './FormField' import styles from './FormGroup.module.css' import { CollapsibleSection } from '@/components/common' -import React from 'react' +import React, { ReactNode } from 'react' /** Properties for the FormGroup component. */ export interface FormGroupProps { @@ -13,8 +13,8 @@ export interface FormGroupProps { */ id?: string - /** The group's title, displayed as a heading above the fields. */ - title: string + /** The group's title, displayed as a heading (or custom component) above the fields. */ + title: string | ReactNode /** Optional subtitle displayed under the group's title. */ subtitle?: string @@ -25,7 +25,7 @@ export interface FormGroupProps { /**Whether the group is meant to wrap other form groups or not */ wrapper?: boolean - /**Wheter the group is a sub group of a bigger */ + /**Whether the group is a sub group of a bigger group */ subGroup?: boolean /** diff --git a/src/components/common/index.ts b/src/components/common/index.ts index ba23b311..6b2f1820 100644 --- a/src/components/common/index.ts +++ b/src/components/common/index.ts @@ -4,7 +4,7 @@ import { Message } from './twitter_card_element/Card' export { Button, Logo, Message } -export * from './CollapsibleSection' +export * from './collapsible_section/CollapsibleSection' export * from './DiscordAvatar' export * from './ImageWithFallback' export * from './loading_spinner/LoadingSpinner' diff --git a/src/components/common/loading_spinner/loadingSpinner.module.css b/src/components/common/loading_spinner/loadingSpinner.module.css index b2171571..ad4c8fd5 100644 --- a/src/components/common/loading_spinner/loadingSpinner.module.css +++ b/src/components/common/loading_spinner/loadingSpinner.module.css @@ -26,3 +26,21 @@ spin 777ms linear infinite, recol 777ms linear infinite alternate; } + +@keyframes spin { + 0% { + transform: rotate(-360deg); + } +} + +@keyframes recol { + 0% { + background-color: #0ea5e9; + } + 50% { + background-color: white; + } + 100% { + background-color: #a52c20; + } +} From 8218d8d1e0dd20795e0524f3c00c261afd823ed1 Mon Sep 17 00:00:00 2001 From: zoe2276 Date: Wed, 29 Jul 2026 19:16:59 +0000 Subject: [PATCH 04/21] prettier said it was ugly so i consoled it to make it feel better --- src/contracts/data/DiscordEventStatus.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/contracts/data/DiscordEventStatus.ts b/src/contracts/data/DiscordEventStatus.ts index 4aa21576..022a8aef 100644 --- a/src/contracts/data/DiscordEventStatus.ts +++ b/src/contracts/data/DiscordEventStatus.ts @@ -1,10 +1,10 @@ -import z from 'zod'; +import z from 'zod' export enum DiscordEventStatus { - Scheduled = 1, - Active = 2, - Completed = 3, - Cancelled = 4, + Scheduled = 1, + Active = 2, + Completed = 3, + Cancelled = 4, } -export const zDiscordEventStatus = z.enum(DiscordEventStatus); +export const zDiscordEventStatus = z.enum(DiscordEventStatus) From 48a5838f43d80b40686baedc21a8ff535ad332b4 Mon Sep 17 00:00:00 2001 From: zoe2276 Date: Wed, 29 Jul 2026 19:43:24 +0000 Subject: [PATCH 05/21] style fixes after merge --- .../common/collapsible_section/collapsibleSection.module.css | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/components/common/collapsible_section/collapsibleSection.module.css b/src/components/common/collapsible_section/collapsibleSection.module.css index 79ae26d1..c1e48907 100644 --- a/src/components/common/collapsible_section/collapsibleSection.module.css +++ b/src/components/common/collapsible_section/collapsibleSection.module.css @@ -1,6 +1,7 @@ .header { display: flex; flex-direction: column; + gap: 0.25rem; margin-top: 1rem; margin-bottom: 1rem; } @@ -10,7 +11,6 @@ display: flex; justify-content: space-between; align-items: center; - margin: 1rem 0; font-size: 1.25rem; font-weight: 600; @@ -42,7 +42,6 @@ } .subtitle { - margin-top: 0.25rem; font-size: 0.875rem; line-height: 1.25rem; color: rgb(107, 114, 128); From 91031dc5e4d58b56679ad2fe7e29ed01d797f12c Mon Sep 17 00:00:00 2001 From: zoe2276 Date: Wed, 29 Jul 2026 20:56:15 +0000 Subject: [PATCH 06/21] *unintelligible* --- src/app/admin/panels/events/page.tsx | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/app/admin/panels/events/page.tsx b/src/app/admin/panels/events/page.tsx index e4b0fce4..40de37fd 100644 --- a/src/app/admin/panels/events/page.tsx +++ b/src/app/admin/panels/events/page.tsx @@ -344,10 +344,6 @@ export default function Page() { )} } - subtitle={ - eventQuery.data?.event.attendees.length.toString() ?? - '' - } > { Date: Wed, 29 Jul 2026 21:17:16 +0000 Subject: [PATCH 07/21] *screams of unimaginable pain* --- src/app/admin/panels/events/page.module.css | 2 -- src/app/admin/panels/events/page.tsx | 21 ++++++++++----------- 2 files changed, 10 insertions(+), 13 deletions(-) diff --git a/src/app/admin/panels/events/page.module.css b/src/app/admin/panels/events/page.module.css index 8c129a90..400c7aa9 100644 --- a/src/app/admin/panels/events/page.module.css +++ b/src/app/admin/panels/events/page.module.css @@ -234,8 +234,6 @@ .detailsCreatedByContainer, .attendeeMeta { display: flex; - flex-flow: row wrap; - justify-content: center; align-items: center; column-gap: 0.5rem; } diff --git a/src/app/admin/panels/events/page.tsx b/src/app/admin/panels/events/page.tsx index 40de37fd..e2218b2f 100644 --- a/src/app/admin/panels/events/page.tsx +++ b/src/app/admin/panels/events/page.tsx @@ -24,6 +24,7 @@ import { zDiscordEventDetailsResponse } from '@/contracts/responses' import { dateService } from '@/services' import { useFetch, usePaginatedSearch } from '@/util/hooks' import { keepPreviousData, skipToken, useQuery } from '@tanstack/react-query' +import cx from 'classnames' import Image from 'next/image' import { redirect, useSearchParams } from 'next/navigation' import { useState } from 'react' @@ -112,8 +113,6 @@ export default function Page() { 'Cancelled', ][status ?? 0] - const cn = (classes: string[]) => classes.join(' ') - const renderEvent = (event: DiscordEvent) => { return (
{event.name} @@ -217,14 +216,14 @@ export default function Page() {
{getStatusName( eventQuery.data.event.status @@ -249,14 +248,14 @@ export default function Page() { />
{getStatusName( From 190bf641666e583f8157785e44ec3756793a4f43 Mon Sep 17 00:00:00 2001 From: zoe2276 Date: Wed, 29 Jul 2026 23:34:07 +0000 Subject: [PATCH 08/21] added recurring tags --- src/app/admin/panels/events/page.module.css | 11 +++++++++- src/app/admin/panels/events/page.tsx | 23 ++++++++++++++++++++- 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/src/app/admin/panels/events/page.module.css b/src/app/admin/panels/events/page.module.css index 400c7aa9..4bd2ad05 100644 --- a/src/app/admin/panels/events/page.module.css +++ b/src/app/admin/panels/events/page.module.css @@ -149,6 +149,14 @@ border-radius: 1rem; } +.detailsEventDecorationContainer { + display: flex; + flex-flow: row wrap; + justify-content: start; + align-items: center; + gap: 0.375rem; +} + .statusPill { border-radius: 9999px; font-size: 0.75rem; @@ -157,7 +165,8 @@ padding: 0.28rem 0.65rem; text-transform: uppercase; - &.unknown { + &.unknown, + &.recurrent { border: 1px solid var(--s-unknown-brd); background: var(--s-unknown-bg); color: var(--s-unknown-col); diff --git a/src/app/admin/panels/events/page.tsx b/src/app/admin/panels/events/page.tsx index e2218b2f..47d0c24b 100644 --- a/src/app/admin/panels/events/page.tsx +++ b/src/app/admin/panels/events/page.tsx @@ -214,7 +214,11 @@ export default function Page() {
-
+
+ {eventQuery.data.event.recurrent && ( + + Recurring + + )}
@@ -264,6 +278,13 @@ export default function Page() {
+ + + {eventQuery.data.event.recurrent + ? 'Yes' + : 'No'} + +
Date: Wed, 29 Jul 2026 23:34:29 +0000 Subject: [PATCH 09/21] adjusted header card opacity to feel more deliberate --- src/app/admin/panels/members/page.module.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/admin/panels/members/page.module.css b/src/app/admin/panels/members/page.module.css index b3127e56..db1bbbf5 100644 --- a/src/app/admin/panels/members/page.module.css +++ b/src/app/admin/panels/members/page.module.css @@ -81,7 +81,7 @@ padding-bottom: 0.9rem; padding-inline: 1rem; border: 1px solid rgba(255, 255, 255, 0.72); - background: rgba(255, 255, 255, 0.84); + background: rgba(255, 255, 255, 0.66); backdrop-filter: blur(16px) saturate(145%); -webkit-backdrop-filter: blur(16px) saturate(145%); From a35003741b0c8b0b3fe4e6ceac00771ff3f2af0a Mon Sep 17 00:00:00 2001 From: zoe2276 Date: Fri, 31 Jul 2026 20:17:04 +0000 Subject: [PATCH 10/21] ~CollapsibleSection: logic extraction --- .../common/collapsible_section/CollapsibleSection.tsx | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/components/common/collapsible_section/CollapsibleSection.tsx b/src/components/common/collapsible_section/CollapsibleSection.tsx index fe42460c..c408a2f5 100644 --- a/src/components/common/collapsible_section/CollapsibleSection.tsx +++ b/src/components/common/collapsible_section/CollapsibleSection.tsx @@ -22,6 +22,8 @@ export function CollapsibleSection({ }: CollapsibleSectionProps) { const [isOpen, setIsOpen] = useState(initialOpenState) + const toRender = typeof title === 'string' ?

{title}

: <>{title} + return (
{title && ( @@ -32,11 +34,7 @@ export function CollapsibleSection({ subGroup && styles.titleSub )} > - {typeof title === 'string' ? ( -

{title}

- ) : ( - <>{title} - )} + {toRender}