Merge pull request 'fix/117-toaster_button_on_event_creation' (#118)
Some checks failed
docker-build / docker (push) Waiting to run
tests / Tests (push) Waiting to run
container-scan / Container Scan (push) Has been cancelled

Reviewed-on: #118
Reviewed-by: Dominik <mail@dominikstahl.dev>
This commit is contained in:
Dominik 2025-06-30 10:17:15 +00:00
commit ed6174ad34
5 changed files with 161 additions and 151 deletions

View file

@ -40,14 +40,12 @@ export default function ShowEvent() {
if (isLoading || userLoading) { if (isLoading || userLoading) {
return ( return (
<div className='flex justify-center items-center h-screen'> <div className='flex justify-center items-center h-full'>Loading...</div>
Loading...
</div>
); );
} }
if (error || !eventData?.data?.event) { if (error || !eventData?.data?.event) {
return ( return (
<div className='flex justify-center items-center h-screen'> <div className='flex justify-center items-center h-full'>
Error loading event. Error loading event.
</div> </div>
); );
@ -70,167 +68,169 @@ export default function ShowEvent() {
}; };
return ( return (
<Card className='w-[80%] max-w-screen p-0 gap-0 max-xl:w-[95%] mx-auto'> <div className='flex items-center justify-center h-full'>
<CardHeader className='p-0 m-0 gap-0' /> <Card className='w-[80%] max-w-screen p-0 gap-0 max-xl:w-[95%] mx-auto'>
<CardHeader className='p-0 m-0 gap-0' />
<CardContent> <CardContent>
<div className='flex flex-col gap-5 w-full'> <div className='flex flex-col gap-5 w-full'>
<div className='grid grid-row-start:auto gap-4 sm:gap-8'> <div className='grid grid-row-start:auto gap-4 sm:gap-8'>
<div className='h-full mt-0 ml-2 mb-16 flex items-center justify-between max-sm:grid max-sm:grid-row-start:auto max-sm:mb-6 max-sm:mt-10 max-sm:ml-0'> <div className='h-full mt-0 ml-2 mb-16 flex items-center justify-between max-sm:grid max-sm:grid-row-start:auto max-sm:mb-6 max-sm:mt-10 max-sm:ml-0'>
<div className='w-[100px] max-sm:w-full max-sm:flex max-sm:justify-center'> <div className='w-[100px] max-sm:w-full max-sm:flex max-sm:justify-center'>
<Logo colorType='monochrome' logoType='submark' width={50} /> <Logo colorType='monochrome' logoType='submark' width={50} />
</div>
<div className='items-center ml-auto mr-auto max-sm:mb-6 max-sm:w-full max-sm:flex max-sm:justify-center'>
<h1 className='text-center'>
{event.title || 'Untitled Event'}
</h1>
</div>
<div className='w-0 sm:w-[100px]'></div>
</div> </div>
<div className='items-center ml-auto mr-auto max-sm:mb-6 max-sm:w-full max-sm:flex max-sm:justify-center'> <div className='grid grid-cols-4 gap-4 h-full w-full max-lg:grid-cols-2 max-sm:grid-cols-1'>
<h1 className='text-center'> <div>
{event.title || 'Untitled Event'} <Label className='text-[var(--color-neutral-300)] mb-2'>
</h1> start Time
</div>
<div className='w-0 sm:w-[100px]'></div>
</div>
<div className='grid grid-cols-4 gap-4 h-full w-full max-lg:grid-cols-2 max-sm:grid-cols-1'>
<div>
<Label className='text-[var(--color-neutral-300)] mb-2'>
start Time
</Label>
<Label size='large'>
{event.start_time
? `${formatDate(event.start_time)} ${formatTime(event.start_time)}`
: '-'}
</Label>
</div>
<div>
<Label className='text-[var(--color-neutral-300)] mb-2'>
end Time
</Label>
<Label size='large'>
{event.end_time
? `${formatDate(event.end_time)} ${formatTime(event.end_time)}`
: '-'}
</Label>
</div>
<div className='w-54'>
<Label className='text-[var(--color-neutral-300)] mb-2'>
Location
</Label>
<Label size='large'>{event.location || '-'}</Label>
</div>
<div className='flex flex-col gap-4'>
<div className='flex flex-row gap-2'>
<Label className='w-[70px] text-[var(--color-neutral-300)]'>
created:
</Label> </Label>
<Label> <Label size='large'>
{event.created_at ? formatDate(event.created_at) : '-'} {event.start_time
? `${formatDate(event.start_time)} ${formatTime(event.start_time)}`
: '-'}
</Label> </Label>
</div> </div>
<div className='flex flex-row gap-2'> <div>
<Label className='w-[70px] text-[var(--color-neutral-300)]'> <Label className='text-[var(--color-neutral-300)] mb-2'>
updated: end Time
</Label> </Label>
<Label> <Label size='large'>
{event.updated_at ? formatDate(event.updated_at) : '-'} {event.end_time
? `${formatDate(event.end_time)} ${formatTime(event.end_time)}`
: '-'}
</Label> </Label>
</div> </div>
</div> <div className='w-54'>
</div> <Label className='text-[var(--color-neutral-300)] mb-2'>
<div className='h-full w-full grid grid-cols-2 gap-4 max-sm:grid-cols-1'> Location
<div className='h-full w-full grid grid-flow-row gap-4 sm:gap-8'> </Label>
<div className='h-full w-full'> <Label size='large'>{event.location || '-'}</Label>
</div>
<div className='flex flex-col gap-4'>
<div className='flex flex-row gap-2'> <div className='flex flex-row gap-2'>
<Label className='text-[var(--color-neutral-300)]'> <Label className='w-[70px] text-[var(--color-neutral-300)]'>
Organiser: created:
</Label>
<Label>
{event.created_at ? formatDate(event.created_at) : '-'}
</Label>
</div>
<div className='flex flex-row gap-2'>
<Label className='w-[70px] text-[var(--color-neutral-300)]'>
updated:
</Label>
<Label>
{event.updated_at ? formatDate(event.updated_at) : '-'}
</Label> </Label>
<Label size='large'>{organiserName}</Label>
</div> </div>
</div> </div>
<div className='h-full w-full'> </div>
<div className='h-full w-full grid grid-cols-2 gap-4 max-sm:grid-cols-1'>
<div className='h-full w-full grid grid-flow-row gap-4 sm:gap-8'>
<div className='h-full w-full'>
<div className='flex flex-row gap-2'>
<Label className='text-[var(--color-neutral-300)]'>
Organiser:
</Label>
<Label size='large'>{organiserName}</Label>
</div>
</div>
<div className='h-full w-full'>
<Label className='text-[var(--color-neutral-300)] mb-2'>
Description
</Label>
<Label size='large'>{event.description || '-'}</Label>
</div>
</div>
<div className='h-full w-full mt-2'>
<Label className='text-[var(--color-neutral-300)] mb-2'> <Label className='text-[var(--color-neutral-300)] mb-2'>
Description Participants
</Label> </Label>{' '}
<Label size='large'>{event.description || '-'}</Label> <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) => (
<ParticipantListEntry key={user.user.id} {...user} />
))}
</div>
</div> </div>
</div> </div>
<div className='h-full w-full mt-2'>
<Label className='text-[var(--color-neutral-300)] mb-2'>
Participants
</Label>{' '}
<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) => (
<ParticipantListEntry key={user.user.id} {...user} />
))}
</div>
</div>
</div>
<div className='flex flex-row gap-2 justify-end mt-4 mb-6'> <div className='flex flex-row gap-2 justify-end mt-4 mb-6'>
<div className='w-[20%] grid max-sm:w-full'> <div className='w-[20%] grid max-sm:w-full'>
{session.data?.user?.id === event.organizer.id ? ( {session.data?.user?.id === event.organizer.id ? (
<Dialog <Dialog
open={deleteDialogOpen} open={deleteDialogOpen}
onOpenChange={setDeleteDialogOpen} onOpenChange={setDeleteDialogOpen}
> >
<DialogTrigger asChild> <DialogTrigger asChild>
<Button variant='destructive' className='w-full'> <Button variant='destructive' className='w-full'>
delete delete
</Button>
</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle>Delete Event</DialogTitle>
<DialogDescription>
Are you sure you want to delete the event &ldquo;
{event.title}&rdquo;? This action cannot be undone.
</DialogDescription>
</DialogHeader>
<DialogFooter>
<Button
variant='secondary'
onClick={() => setDeleteDialogOpen(false)}
>
Cancel
</Button> </Button>
<Button </DialogTrigger>
variant='muted' <DialogContent>
onClick={() => { <DialogHeader>
deleteEvent.mutate( <DialogTitle>Delete Event</DialogTitle>
{ eventID: event.id }, <DialogDescription>
{ Are you sure you want to delete the event &ldquo;
onSuccess: () => { {event.title}&rdquo;? This action cannot be undone.
router.push('/home'); </DialogDescription>
toast.custom((t) => ( </DialogHeader>
<ToastInner <DialogFooter>
toastId={t} <Button
title='Event deleted' variant='secondary'
description={event?.title} onClick={() => setDeleteDialogOpen(false)}
variant='success' >
/> Cancel
)); </Button>
<Button
variant='muted'
onClick={() => {
deleteEvent.mutate(
{ eventID: event.id },
{
onSuccess: () => {
router.push('/home');
toast.custom((t) => (
<ToastInner
toastId={t}
title='Event deleted'
description={event?.title}
variant='success'
/>
));
},
}, },
}, );
); setDeleteDialogOpen(false);
setDeleteDialogOpen(false); }}
}} >
> Delete
Delete </Button>
</Button> </DialogFooter>
</DialogFooter> </DialogContent>
</DialogContent> </Dialog>
</Dialog> ) : null}
) : null} </div>
</div> <div className='w-[20%] grid max-sm:w-full'>
<div className='w-[20%] grid max-sm:w-full'> {session.data?.user?.id === event.organizer.id ? (
{session.data?.user?.id === event.organizer.id ? ( <RedirectButton
<RedirectButton redirectUrl={`/events/edit/${eventID}`}
redirectUrl={`/events/edit/${eventID}`} buttonText='edit'
buttonText='edit' className='w-full'
className='w-full' />
/> ) : null}
) : null} </div>
</div> </div>
</div> </div>
</div> </div>
</div> </CardContent>
</CardContent> </Card>
</Card> </div>
); );
} }

View file

@ -4,7 +4,7 @@ import { Suspense } from 'react';
export default function NewEvent() { export default function NewEvent() {
return ( return (
<div className='flex flex-col items-center justify-center h-screen'> <div className='flex flex-col items-center justify-center h-full'>
<Card className='w-[80%] max-w-screen p-0 gap-0 max-xl:w-[95%] max-h-[90vh] overflow-auto'> <Card className='w-[80%] max-w-screen p-0 gap-0 max-xl:w-[95%] max-h-[90vh] overflow-auto'>
<CardHeader className='p-0 m-0 gap-0' /> <CardHeader className='p-0 m-0 gap-0' />

View file

@ -17,7 +17,7 @@ export default function Events() {
const events = eventsData?.data?.events || []; const events = eventsData?.data?.events || [];
return ( return (
<div className='relative h-screen flex flex-col items-center'> <div className='relative h-full flex flex-col items-center'>
{/* Heading */} {/* Heading */}
<h1 className='text-3xl font-bold mt-8 mb-4 text-center z-10'> <h1 className='text-3xl font-bold mt-8 mb-4 text-center z-10'>
My Events My Events

View file

@ -233,7 +233,7 @@ function CalendarWithUserEvents({
resourceTitleAccessor={(event) => event.title} resourceTitleAccessor={(event) => event.title}
startAccessor={(event) => event.start} startAccessor={(event) => event.start}
endAccessor={(event) => event.end} endAccessor={(event) => event.end}
selectable={sesstion.data?.user?.id === userId && !additionalEvents} selectable={sesstion.data?.user?.id === userId}
onEventDrop={(event) => { onEventDrop={(event) => {
const { start, end, event: droppedEvent } = event; const { start, end, event: droppedEvent } = event;
if (droppedEvent.type === 'blocked_private') return; if (droppedEvent.type === 'blocked_private') return;

View file

@ -51,7 +51,12 @@ const EventForm: React.FC<EventFormProps> = (props) => {
const startFromUrl = searchParams.get('start'); const startFromUrl = searchParams.get('start');
const endFromUrl = searchParams.get('end'); const endFromUrl = searchParams.get('end');
const { mutate: createEvent, status, isSuccess, error } = usePostApiEvent(); const {
mutateAsync: createEvent,
status,
isSuccess,
error,
} = usePostApiEvent();
const { data, isLoading, error: fetchError } = useGetApiUserMe(); const { data, isLoading, error: fetchError } = useGetApiUserMe();
const { data: eventData } = useGetApiEventEventID(props.eventId!, { const { data: eventData } = useGetApiEventEventID(props.eventId!, {
query: { enabled: props.type === 'edit' }, query: { enabled: props.type === 'edit' },
@ -150,8 +155,10 @@ const EventForm: React.FC<EventFormProps> = (props) => {
participants: selectedParticipants.map((u) => u.id), participants: selectedParticipants.map((u) => u.id),
}; };
let eventID: string | undefined;
if (props.type === 'edit' && props.eventId) { if (props.type === 'edit' && props.eventId) {
await patchEvent.mutateAsync({ const mutationResult = await patchEvent.mutateAsync({
eventID: props.eventId, eventID: props.eventId,
data: { data: {
title: data.title, title: data.title,
@ -162,9 +169,12 @@ const EventForm: React.FC<EventFormProps> = (props) => {
participants: data.participants, participants: data.participants,
}, },
}); });
eventID = mutationResult.data.event.id;
console.log('Updating event'); console.log('Updating event');
} else { } else {
console.log('Creating event'); console.log('Creating event');
const mutationResult = await createEvent({ data });
eventID = mutationResult.data.event.id;
createEvent({ data }); createEvent({ data });
} }
@ -173,7 +183,7 @@ const EventForm: React.FC<EventFormProps> = (props) => {
toastId={t} toastId={t}
title='Event saved' title='Event saved'
description={event?.title} description={event?.title}
onAction={() => router.push(`/events/${event?.id}`)} onAction={() => router.push(`/events/${eventID}`)}
variant='success' variant='success'
buttonText='show' buttonText='show'
/> />