diff --git a/package.json b/package.json index b291e57..ad3de2a 100644 --- a/package.json +++ b/package.json @@ -51,6 +51,7 @@ "react-day-picker": "^9.7.0", "react-dom": "^19.0.0", "react-hook-form": "^7.56.4", + "sonner": "^2.0.5", "swagger-ui-react": "^5.24.1", "tailwind-merge": "^3.2.0", "zod": "^3.25.60" diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 201a730..c37fc2e 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -3,6 +3,7 @@ import { ThemeProvider } from '@/components/wrappers/theme-provider'; import type { Metadata } from 'next'; import './globals.css'; import { QueryProvider } from '@/components/query-provider'; +import { Toaster } from '@/components/ui/sonner'; export const metadata: Metadata = { title: 'MeetUp', @@ -58,6 +59,7 @@ export default function RootLayout({ > {children} + ); diff --git a/src/components/forms/event-form.tsx b/src/components/forms/event-form.tsx index 81e1717..8be2602 100644 --- a/src/components/forms/event-form.tsx +++ b/src/components/forms/event-form.tsx @@ -13,6 +13,8 @@ import { } from '@/generated/api/event/event'; import ParticipantListEntry from '@/components/custom-ui/participantListEntry'; import { useRouter } from 'next/navigation'; +import { toast } from 'sonner'; +import { CalendarCheck } from 'lucide-react'; interface EventFormProps { type: 'create' | 'edit'; @@ -129,9 +131,14 @@ const EventForm: React.FC = (props) => { console.log('Updating event with data:', data); } else { console.log('Creating event with data:', data); - createEvent({ data }); } + + toast('Event saved successfully', { + description: `Your event "${data.title}" has been saved.`, + icon: , + }); + router.back(); } diff --git a/src/components/misc/toast-inner.tsx b/src/components/misc/toast-inner.tsx new file mode 100644 index 0000000..74a7bf7 --- /dev/null +++ b/src/components/misc/toast-inner.tsx @@ -0,0 +1,146 @@ +/* +USAGE: + +import { toast } from 'sonner'; +import { ToastInner } from '@/components/misc/toast-inner'; + +import { Button } from '@/components/ui/button'; + + + + +*/ + +'use client'; + +import { toast } from 'sonner'; +import { X } from 'lucide-react'; +import React from 'react'; +import { Label } from '@/components/ui/label'; +import { Button } from '@/components/ui/button'; +import * as Icons from 'lucide-react'; + +interface ToastInnerProps { + title: string; + description?: string; + buttonText?: string; + onAction?: () => void; + toastId: string | number; + variant?: + | 'default' + | 'success' + | 'error' + | 'info' + | 'warning' + | 'notification'; + iconName?: keyof typeof Icons; +} + +const variantConfig = { + default: { + bgColor: 'bg-green-150', + defaultIcon: 'Info', + }, + success: { + bgColor: 'bg-green-200', + defaultIcon: 'CheckCircle', + }, + error: { + bgColor: 'bg-red-200', + defaultIcon: 'XCircle', + }, + info: { + bgColor: 'bg-blue-200', + defaultIcon: 'Info', + }, + warning: { + bgColor: 'bg-yellow-200', + defaultIcon: 'AlertTriangle', + }, + notification: { + bgColor: 'bg-neutral-150', + defaultIcon: 'BellRing', + }, +}; + +export const ToastInner: React.FC = ({ + title, + description, + buttonText, + onAction, + toastId, + variant = 'default', + iconName, +}) => { + const bgColor = variantConfig[variant].bgColor; + + // fallback to variant's default icon if iconName is not provided + const iconKey = (iconName || + variantConfig[variant].defaultIcon) as keyof typeof Icons; + const Icon = Icons[iconKey] as React.ComponentType; + + return ( +
+ {/* Close Button */} + + +
+ {/* Icon */} +
+ +
+ + {/* Text Content */} +
+
{title}
+ {description && } +
+ + {/* Action Button */} +
+ {onAction && buttonText && ( + + )} +
+
+
+ ); +}; diff --git a/src/components/ui/sonner.tsx b/src/components/ui/sonner.tsx new file mode 100644 index 0000000..9bfe21d --- /dev/null +++ b/src/components/ui/sonner.tsx @@ -0,0 +1,37 @@ +'use client'; + +import { useTheme } from 'next-themes'; +import { Toaster as Sonner, ToasterProps } from 'sonner'; + +const Toaster = ({ ...props }: ToasterProps) => { + const { theme = 'system' } = useTheme(); + + return ( + + ); +}; + +export { Toaster }; diff --git a/yarn.lock b/yarn.lock index b09b056..67406be 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6761,6 +6761,7 @@ __metadata: react-day-picker: "npm:^9.7.0" react-dom: "npm:^19.0.0" react-hook-form: "npm:^7.56.4" + sonner: "npm:^2.0.5" swagger-ui-react: "npm:^5.24.1" tailwind-merge: "npm:^3.2.0" tailwindcss: "npm:4.1.10" @@ -8661,6 +8662,16 @@ __metadata: languageName: node linkType: hard +"sonner@npm:^2.0.5": + version: 2.0.5 + resolution: "sonner@npm:2.0.5" + peerDependencies: + react: ^18.0.0 || ^19.0.0 || ^19.0.0-rc + react-dom: ^18.0.0 || ^19.0.0 || ^19.0.0-rc + checksum: 10c0/38ec98e2f5d7e086825307f737a90bdc8639182d184e002719c2368bf3a9259c340f41afda731716d2b78c40e5e3aa9165058375be42f6a93bda0876b9b433ba + languageName: node + linkType: hard + "source-map-js@npm:^1.0.2, source-map-js@npm:^1.2.1": version: 1.2.1 resolution: "source-map-js@npm:1.2.1"