feat(events): refactor event and participant list entries to use schema validation
Some checks failed
container-scan / Container Scan (pull_request) Failing after 4m21s
docker-build / docker (pull_request) Failing after 6m5s

This commit is contained in:
micha 2025-06-25 19:11:38 +02:00
parent d9129f3f93
commit 018f94e69d
5 changed files with 24 additions and 35 deletions

View file

@ -1,7 +1,6 @@
'use client'; 'use client';
import React from 'react'; import React from 'react';
import { usePathname } from 'next/navigation';
import Logo from '@/components/misc/logo'; import Logo from '@/components/misc/logo';
import { ThemePicker } from '@/components/misc/theme-picker'; import { ThemePicker } from '@/components/misc/theme-picker';
import { Card, CardContent, CardHeader } from '@/components/ui/card'; import { Card, CardContent, CardHeader } from '@/components/ui/card';
@ -12,12 +11,10 @@ import { RedirectButton } from '@/components/buttons/redirect-button';
import { useSession } from 'next-auth/react'; import { useSession } from 'next-auth/react';
import ParticipantListEntry from '@/components/custom-ui/participant-list-entry'; import ParticipantListEntry from '@/components/custom-ui/participant-list-entry';
export default function ShowEvent() { export default function ShowEvent({ params }: { params: { eventId: string } }) {
const session = useSession(); const session = useSession();
const pathname = usePathname();
// Extract eventId from URL like /events/[eventId] const eventId = params.eventId;
const eventId = pathname.split('/').pop() || '';
// Fetch event data // Fetch event data
const { data: eventData, isLoading, error } = useGetApiEventEventID(eventId); const { data: eventData, isLoading, error } = useGetApiEventEventID(eventId);
@ -145,11 +142,7 @@ export default function ShowEvent() {
</Label>{' '} </Label>{' '}
<div className='grid grid-cols-1 mt-3 sm:max-h-60 sm:grid-cols-2 sm:overflow-y-auto sm:mb-0'> <div className='grid grid-cols-1 mt-3 sm:max-h-60 sm:grid-cols-2 sm:overflow-y-auto sm:mb-0'>
{event.participants?.map((user) => ( {event.participants?.map((user) => (
<ParticipantListEntry <ParticipantListEntry key={user.user.id} {...user} />
key={user.user.id}
participant={user.user.name}
imageSrc={user.user.image}
></ParticipantListEntry>
))} ))}
</div> </div>
</div> </div>

View file

@ -35,11 +35,9 @@ export default function Events() {
events.map((event) => ( events.map((event) => (
<EventListEntry <EventListEntry
key={event.id} key={event.id}
title={event.title} {...event}
id={event.id} created_at={new Date(event.created_at)}
start_time={event.start_time} updated_at={new Date(event.updated_at)}
end_time={event.end_time}
location={event.location}
/> />
)) ))
) : ( ) : (

View file

@ -2,14 +2,10 @@ import { Card } from '@/components/ui/card';
import Logo from '@/components/misc/logo'; import Logo from '@/components/misc/logo';
import { Label } from '@/components/ui/label'; import { Label } from '@/components/ui/label';
import Link from 'next/link'; import Link from 'next/link';
import zod from 'zod/v4';
import { EventSchema } from '@/app/api/event/validation';
type EventListEntryProps = { type EventListEntryProps = zod.output<typeof EventSchema>;
title: string;
id: string;
start_time: string;
end_time: string;
location: string | null | undefined;
};
export default function EventListEntry({ export default function EventListEntry({
title, title,

View file

@ -3,26 +3,24 @@ import Image from 'next/image';
import { user_default_dark } from '@/assets/usericon/default/defaultusericon-export'; import { user_default_dark } from '@/assets/usericon/default/defaultusericon-export';
import { user_default_light } from '@/assets/usericon/default/defaultusericon-export'; import { user_default_light } from '@/assets/usericon/default/defaultusericon-export';
import { useTheme } from 'next-themes'; import { useTheme } from 'next-themes';
import zod from 'zod/v4';
import { ParticipantSchema } from '@/app/api/event/[eventID]/participant/validation';
type ParticipantListEntryProps = { type ParticipantListEntryProps = zod.output<typeof ParticipantSchema>;
participant: string;
imageSrc?: string | null;
};
export default function ParticipantListEntry({ export default function ParticipantListEntry({
participant, user,
imageSrc,
}: ParticipantListEntryProps) { }: ParticipantListEntryProps) {
const { resolvedTheme } = useTheme(); const { resolvedTheme } = useTheme();
const defaultImage = const defaultImage =
resolvedTheme === 'dark' ? user_default_dark : user_default_light; resolvedTheme === 'dark' ? user_default_dark : user_default_light;
const finalImageSrc = imageSrc ?? defaultImage; const finalImageSrc = user.image ?? defaultImage;
return ( return (
<div className='flex items-center gap-2 py-1 ml-5'> <div className='flex items-center gap-2 py-1 ml-5'>
<Image src={finalImageSrc} alt='Avatar' width={30} height={30} /> <Image src={finalImageSrc} alt='Avatar' width={30} height={30} />
<span>{participant}</span> <span>{user.name}</span>
</div> </div>
); );
} }

View file

@ -19,10 +19,10 @@ import ParticipantListEntry from '../custom-ui/participant-list-entry';
import { useSearchParams } from 'next/navigation'; import { useSearchParams } from 'next/navigation';
interface User { import zod from 'zod/v4';
id: string; import { PublicUserSchema } from '@/app/api/user/validation';
name: string;
} type User = zod.output<typeof PublicUserSchema>;
interface EventFormProps { interface EventFormProps {
type: 'create' | 'edit'; type: 'create' | 'edit';
@ -305,7 +305,11 @@ const EventForm: React.FC<EventFormProps> = (props) => {
/> />
<div className='grid grid-cols-1 mt-3 sm:max-h-60 sm:grid-cols-2 sm:overflow-y-auto sm:mb-0'> <div className='grid grid-cols-1 mt-3 sm:max-h-60 sm:grid-cols-2 sm:overflow-y-auto sm:mb-0'>
{selectedParticipants.map((user) => ( {selectedParticipants.map((user) => (
<ParticipantListEntry key={user.id} participant={user.name} /> <ParticipantListEntry
key={user.id}
user={user}
status='PENDING'
/>
))} ))}
</div> </div>
</div> </div>