feat(events): add deletion button and style toaster for light mode
This commit is contained in:
parent
8bbb7e4c85
commit
42e1b69720
7 changed files with 128 additions and 32 deletions
|
@ -1,25 +1,42 @@
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import React from 'react';
|
import React, { useState } from 'react';
|
||||||
import Logo from '@/components/misc/logo';
|
import Logo from '@/components/misc/logo';
|
||||||
import { ThemePicker } from '@/components/misc/theme-picker';
|
|
||||||
import { Card, CardContent, CardHeader } from '@/components/ui/card';
|
import { Card, CardContent, CardHeader } from '@/components/ui/card';
|
||||||
import { Label } from '@/components/ui/label';
|
import { Label } from '@/components/ui/label';
|
||||||
import { useGetApiEventEventID } from '@/generated/api/event/event';
|
import {
|
||||||
|
useDeleteApiEventEventID,
|
||||||
|
useGetApiEventEventID,
|
||||||
|
} from '@/generated/api/event/event';
|
||||||
import { useGetApiUserMe } from '@/generated/api/user/user';
|
import { useGetApiUserMe } from '@/generated/api/user/user';
|
||||||
import { RedirectButton } from '@/components/buttons/redirect-button';
|
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';
|
||||||
import { useParams } from 'next/navigation';
|
import { useParams, useRouter } from 'next/navigation';
|
||||||
|
import { Button } from '@/components/ui/button';
|
||||||
|
import { ToastInner } from '@/components/misc/toast-inner';
|
||||||
|
import { toast } from 'sonner';
|
||||||
|
import {
|
||||||
|
Dialog,
|
||||||
|
DialogContent,
|
||||||
|
DialogDescription,
|
||||||
|
DialogFooter,
|
||||||
|
DialogHeader,
|
||||||
|
DialogTitle,
|
||||||
|
DialogTrigger,
|
||||||
|
} from '@/components/ui/dialog';
|
||||||
|
|
||||||
export default function ShowEvent() {
|
export default function ShowEvent() {
|
||||||
const session = useSession();
|
const session = useSession();
|
||||||
|
const router = useRouter();
|
||||||
|
const [deleteDialogOpen, setDeleteDialogOpen] = useState(false);
|
||||||
|
|
||||||
const { eventId } = useParams<{ eventId: string }>();
|
const { eventID: eventID } = useParams<{ eventID: string }>();
|
||||||
|
|
||||||
// Fetch event data
|
// Fetch event data
|
||||||
const { data: eventData, isLoading, error } = useGetApiEventEventID(eventId);
|
const { data: eventData, isLoading, error } = useGetApiEventEventID(eventID);
|
||||||
const { data: userData, isLoading: userLoading } = useGetApiUserMe();
|
const { data: userData, isLoading: userLoading } = useGetApiUserMe();
|
||||||
|
const deleteEvent = useDeleteApiEventEventID();
|
||||||
|
|
||||||
if (isLoading || userLoading) {
|
if (isLoading || userLoading) {
|
||||||
return (
|
return (
|
||||||
|
@ -54,9 +71,6 @@ export default function ShowEvent() {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='flex flex-col items-center justify-center h-screen'>
|
<div className='flex flex-col items-center justify-center h-screen'>
|
||||||
<div className='absolute top-4 right-4'>
|
|
||||||
<ThemePicker />
|
|
||||||
</div>
|
|
||||||
<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' />
|
||||||
|
|
||||||
|
@ -150,10 +164,65 @@ export default function ShowEvent() {
|
||||||
</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'>
|
||||||
|
{session.data?.user?.id === event.organizer.id ? (
|
||||||
|
<Dialog
|
||||||
|
open={deleteDialogOpen}
|
||||||
|
onOpenChange={setDeleteDialogOpen}
|
||||||
|
>
|
||||||
|
<DialogTrigger asChild>
|
||||||
|
<Button variant='destructive' className='w-full'>
|
||||||
|
delete
|
||||||
|
</Button>
|
||||||
|
</DialogTrigger>
|
||||||
|
<DialogContent>
|
||||||
|
<DialogHeader>
|
||||||
|
<DialogTitle>Delete Event</DialogTitle>
|
||||||
|
<DialogDescription>
|
||||||
|
Are you sure you want to delete the event “
|
||||||
|
{event.title}”? This action cannot be undone.
|
||||||
|
</DialogDescription>
|
||||||
|
</DialogHeader>
|
||||||
|
<DialogFooter>
|
||||||
|
<Button
|
||||||
|
variant='secondary'
|
||||||
|
onClick={() => setDeleteDialogOpen(false)}
|
||||||
|
>
|
||||||
|
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);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Delete
|
||||||
|
</Button>
|
||||||
|
</DialogFooter>
|
||||||
|
</DialogContent>
|
||||||
|
</Dialog>
|
||||||
|
) : null}
|
||||||
|
</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'
|
||||||
/>
|
/>
|
|
@ -1,4 +1,3 @@
|
||||||
import { ThemePicker } from '@/components/misc/theme-picker';
|
|
||||||
import { Card, CardContent, CardHeader } from '@/components/ui/card';
|
import { Card, CardContent, CardHeader } from '@/components/ui/card';
|
||||||
import EventForm from '@/components/forms/event-form';
|
import EventForm from '@/components/forms/event-form';
|
||||||
import { Suspense } from 'react';
|
import { Suspense } from 'react';
|
||||||
|
@ -11,7 +10,6 @@ export default async function Page({
|
||||||
const eventID = (await params).eventID;
|
const eventID = (await params).eventID;
|
||||||
return (
|
return (
|
||||||
<div className='flex flex-col items-center justify-center h-screen'>
|
<div className='flex flex-col items-center justify-center h-screen'>
|
||||||
<div className='absolute top-4 right-4'>{<ThemePicker />}</div>
|
|
||||||
<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' />
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
|
|
||||||
import { RedirectButton } from '@/components/buttons/redirect-button';
|
import { RedirectButton } from '@/components/buttons/redirect-button';
|
||||||
import EventListEntry from '@/components/custom-ui/event-list-entry';
|
import EventListEntry from '@/components/custom-ui/event-list-entry';
|
||||||
import { ThemePicker } from '@/components/misc/theme-picker';
|
|
||||||
import { Label } from '@/components/ui/label';
|
import { Label } from '@/components/ui/label';
|
||||||
import { useGetApiEvent } from '@/generated/api/event/event';
|
import { useGetApiEvent } from '@/generated/api/event/event';
|
||||||
|
|
||||||
|
@ -19,10 +18,6 @@ export default function Events() {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='relative h-screen flex flex-col items-center'>
|
<div className='relative h-screen flex flex-col items-center'>
|
||||||
<div className='absolute top-4 right-4'>
|
|
||||||
<ThemePicker />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* 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
|
|
@ -50,11 +50,23 @@
|
||||||
--active-secondary: oklch(0.4254 0.133 272.15);
|
--active-secondary: oklch(0.4254 0.133 272.15);
|
||||||
--disabled-secondary: oklch(0.4937 0.1697 271.26 / 0.5);
|
--disabled-secondary: oklch(0.4937 0.1697 271.26 / 0.5);
|
||||||
|
|
||||||
|
--destructive: oklch(60.699% 0.20755 25.945);
|
||||||
|
--hover-destructive: oklch(60.699% 0.20755 25.945 / 0.8);
|
||||||
|
--active-destructive: oklch(50.329% 0.17084 25.842);
|
||||||
|
--disabled-destructive: oklch(60.699% 0.20755 25.945 / 0.4);
|
||||||
|
|
||||||
--muted: var(--color-neutral-700);
|
--muted: var(--color-neutral-700);
|
||||||
--hover-muted: var(--color-neutral-600);
|
--hover-muted: var(--color-neutral-600);
|
||||||
--active-muted: var(--color-neutral-400);
|
--active-muted: var(--color-neutral-400);
|
||||||
--disabled-muted: var(--color-neutral-400);
|
--disabled-muted: var(--color-neutral-400);
|
||||||
|
|
||||||
|
--toaster-default-bg: var(--color-neutral-150);
|
||||||
|
--toaster-success-bg: oklch(54.147% 0.09184 144.208);
|
||||||
|
--toaster-error-bg: oklch(52.841% 0.10236 27.274);
|
||||||
|
--toaster-info-bg: oklch(44.298% 0.05515 259.369);
|
||||||
|
--toaster-warning-bg: oklch(61.891% 0.07539 102.943);
|
||||||
|
--toaster-notification-bg: var(--color-neutral-150);
|
||||||
|
|
||||||
--card: var(--neutral-800);
|
--card: var(--neutral-800);
|
||||||
|
|
||||||
--sidebar-width-icon: 32px;
|
--sidebar-width-icon: 32px;
|
||||||
|
@ -81,8 +93,6 @@
|
||||||
|
|
||||||
--accent-foreground: oklch(0.21 0.034 264.665);
|
--accent-foreground: oklch(0.21 0.034 264.665);
|
||||||
|
|
||||||
--destructive: oklch(0.577 0.245 27.325);
|
|
||||||
|
|
||||||
--border: oklch(0.928 0.006 264.531);
|
--border: oklch(0.928 0.006 264.531);
|
||||||
|
|
||||||
--input: oklch(0.928 0.006 264.531);
|
--input: oklch(0.928 0.006 264.531);
|
||||||
|
@ -232,11 +242,23 @@ p {
|
||||||
--color-active-secondary: var(--active-secondary);
|
--color-active-secondary: var(--active-secondary);
|
||||||
--color-disabled-secondary: var(--disabled-secondary);
|
--color-disabled-secondary: var(--disabled-secondary);
|
||||||
|
|
||||||
|
--color-destructive: var(--destructive);
|
||||||
|
--color-hover-destructive: var(--hover-destructive);
|
||||||
|
--color-active-destructive: var(--active-destructive);
|
||||||
|
--color-disabled-destructive: var(--disabled-destructive);
|
||||||
|
|
||||||
--color-muted: var(--muted);
|
--color-muted: var(--muted);
|
||||||
--color-hover-muted: var(--hover-muted);
|
--color-hover-muted: var(--hover-muted);
|
||||||
--color-active-muted: var(--active-muted);
|
--color-active-muted: var(--active-muted);
|
||||||
--color-disabled-muted: var(--disabled-muted);
|
--color-disabled-muted: var(--disabled-muted);
|
||||||
|
|
||||||
|
--color-toaster-default-bg: var(--toaster-default-bg);
|
||||||
|
--color-toaster-success-bg: var(--toaster-success-bg);
|
||||||
|
--color-toaster-error-bg: var(--toaster-error-bg);
|
||||||
|
--color-toaster-info-bg: var(--toaster-info-bg);
|
||||||
|
--color-toaster-warning-bg: var(--toaster-warning-bg);
|
||||||
|
--color-toaster-notification-bg: var(--toaster-notification-bg);
|
||||||
|
|
||||||
/* Custom values */
|
/* Custom values */
|
||||||
|
|
||||||
--radius-sm: calc(var(--radius) - 4px);
|
--radius-sm: calc(var(--radius) - 4px);
|
||||||
|
@ -277,8 +299,6 @@ p {
|
||||||
|
|
||||||
--color-accent-foreground: var(--accent-foreground);
|
--color-accent-foreground: var(--accent-foreground);
|
||||||
|
|
||||||
--color-destructive: var(--destructive);
|
|
||||||
|
|
||||||
--color-border: var(--border);
|
--color-border: var(--border);
|
||||||
|
|
||||||
--color-input: var(--input);
|
--color-input: var(--input);
|
||||||
|
@ -354,11 +374,23 @@ p {
|
||||||
--active-secondary: oklch(0.4471 0.15 271.61);
|
--active-secondary: oklch(0.4471 0.15 271.61);
|
||||||
--disabled-secondary: oklch(0.6065 0.213 271.11 / 0.4);
|
--disabled-secondary: oklch(0.6065 0.213 271.11 / 0.4);
|
||||||
|
|
||||||
|
--destructive: oklch(0.58 0.2149 27.13);
|
||||||
|
--hover-destructive: oklch(0.58 0.2149 27.13 / 0.8);
|
||||||
|
--active-destructive: oklch(45.872% 0.16648 26.855);
|
||||||
|
--disabled-destructive: oklch(0.58 0.2149 27.13 / 0.4);
|
||||||
|
|
||||||
--muted: var(--color-neutral-650);
|
--muted: var(--color-neutral-650);
|
||||||
--hover-muted: var(--color-neutral-500);
|
--hover-muted: var(--color-neutral-500);
|
||||||
--active-muted: var(--color-neutral-400);
|
--active-muted: var(--color-neutral-400);
|
||||||
--disabled-muted: var(--color-neutral-400);
|
--disabled-muted: var(--color-neutral-400);
|
||||||
|
|
||||||
|
--toaster-default-bg: var(--color-neutral-150);
|
||||||
|
--toaster-success-bg: var(--color-green-200);
|
||||||
|
--toaster-error-bg: var(--color-red-200);
|
||||||
|
--toaster-info-bg: var(--color-blue-200);
|
||||||
|
--toaster-warning-bg: var(--color-yellow-200);
|
||||||
|
--toaster-notification-bg: var(--color-neutral-150);
|
||||||
|
|
||||||
--card: var(--neutral-750);
|
--card: var(--neutral-750);
|
||||||
|
|
||||||
/* ------------------- */
|
/* ------------------- */
|
||||||
|
@ -383,8 +415,6 @@ p {
|
||||||
|
|
||||||
--accent-foreground: oklch(0.985 0.002 247.839);
|
--accent-foreground: oklch(0.985 0.002 247.839);
|
||||||
|
|
||||||
--destructive: oklch(0.704 0.191 22.216);
|
|
||||||
|
|
||||||
--border: oklch(1 0 0 / 10%);
|
--border: oklch(1 0 0 / 10%);
|
||||||
|
|
||||||
--input: oklch(1 0 0 / 15%);
|
--input: oklch(1 0 0 / 15%);
|
||||||
|
|
|
@ -65,27 +65,27 @@ interface ToastInnerProps {
|
||||||
|
|
||||||
const variantConfig = {
|
const variantConfig = {
|
||||||
default: {
|
default: {
|
||||||
bgColor: 'bg-neutral-150',
|
bgColor: 'bg-toaster-default-bg',
|
||||||
defaultIcon: 'Info',
|
defaultIcon: 'Info',
|
||||||
},
|
},
|
||||||
success: {
|
success: {
|
||||||
bgColor: 'bg-green-200',
|
bgColor: 'bg-toaster-success-bg',
|
||||||
defaultIcon: 'CheckCircle',
|
defaultIcon: 'CheckCircle',
|
||||||
},
|
},
|
||||||
error: {
|
error: {
|
||||||
bgColor: 'bg-red-200',
|
bgColor: 'bg-toaster-error-bg',
|
||||||
defaultIcon: 'XCircle',
|
defaultIcon: 'XCircle',
|
||||||
},
|
},
|
||||||
info: {
|
info: {
|
||||||
bgColor: 'bg-blue-200',
|
bgColor: 'bg-toaster-info-bg',
|
||||||
defaultIcon: 'Info',
|
defaultIcon: 'Info',
|
||||||
},
|
},
|
||||||
warning: {
|
warning: {
|
||||||
bgColor: 'bg-yellow-200',
|
bgColor: 'bg-toaster-warning-bg',
|
||||||
defaultIcon: 'AlertTriangle',
|
defaultIcon: 'AlertTriangle',
|
||||||
},
|
},
|
||||||
notification: {
|
notification: {
|
||||||
bgColor: 'bg-neutral-150',
|
bgColor: 'bg-toaster-notification-bg',
|
||||||
defaultIcon: 'BellRing',
|
defaultIcon: 'BellRing',
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -127,14 +127,16 @@ export const ToastInner: React.FC<ToastInnerProps> = ({
|
||||||
>
|
>
|
||||||
{variant !== 'default' && (
|
{variant !== 'default' && (
|
||||||
<div className='flex items-center justify-center'>
|
<div className='flex items-center justify-center'>
|
||||||
<Icon size={40} />
|
<Icon className='text-text-alt' size={40} />
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Text Content */}
|
{/* Text Content */}
|
||||||
<div className='grid gap-1'>
|
<div className='grid gap-1'>
|
||||||
<h6>{title}</h6>
|
<h6 className='text-text-alt'>{title}</h6>
|
||||||
{description && <Label>{description}</Label>}
|
{description && (
|
||||||
|
<Label className='text-text-alt'>{description}</Label>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Action Button */}
|
{/* Action Button */}
|
||||||
|
|
|
@ -26,6 +26,8 @@ const buttonVariants = cva(
|
||||||
'border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50 w-32 justify-between font-normal',
|
'border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50 w-32 justify-between font-normal',
|
||||||
ghost:
|
ghost:
|
||||||
'hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50',
|
'hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50',
|
||||||
|
destructive:
|
||||||
|
'bg-destructive text-text shadow-xs hover:bg-hover-destructive active:bg-active-destructive disabled:bg-disabled-destructive',
|
||||||
},
|
},
|
||||||
size: {
|
size: {
|
||||||
default: 'h-9 px-4 py-2 has-[>svg]:px-3',
|
default: 'h-9 px-4 py-2 has-[>svg]:px-3',
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue