From 3d026b68ee3ebb5240dbb4dea383bb212a0c9140 Mon Sep 17 00:00:00 2001 From: Millian Lamiaux Date: Tue, 17 Mar 2026 11:45:29 +0100 Subject: [PATCH] feat: implement beautiful toast notifications with Sonner - Install sonner package for toast notifications - Add Toaster component to root layout with dark theme styling - Replace all alert() calls with toast.success() and toast.error() - Add descriptive messages for success states - Toast notifications match the app's dark theme design --- admin-web/app/layout.tsx | 12 ++++++++++++ admin-web/app/media/page.tsx | 5 +++-- admin-web/app/trainers/page.tsx | 6 +++++- admin-web/app/workouts/page.tsx | 6 +++++- admin-web/components/workout-form.tsx | 3 ++- admin-web/package-lock.json | 11 +++++++++++ admin-web/package.json | 1 + 7 files changed, 39 insertions(+), 5 deletions(-) diff --git a/admin-web/app/layout.tsx b/admin-web/app/layout.tsx index 16f07f3..142a77d 100644 --- a/admin-web/app/layout.tsx +++ b/admin-web/app/layout.tsx @@ -2,6 +2,7 @@ import type { Metadata } from "next"; import { Geist } from "next/font/google"; import "./globals.css"; import { Sidebar } from "@/components/sidebar"; +import { Toaster } from "sonner"; const geistSans = Geist({ variable: "--font-geist-sans", @@ -27,6 +28,17 @@ export default function RootLayout({ {children} + ); diff --git a/admin-web/app/media/page.tsx b/admin-web/app/media/page.tsx index 8ae1398..0ef62fb 100644 --- a/admin-web/app/media/page.tsx +++ b/admin-web/app/media/page.tsx @@ -6,6 +6,7 @@ import { Button } from "@/components/ui/button"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; import { Upload, Film, Image as ImageIcon, User, Loader2 } from "lucide-react"; +import { toast } from "sonner"; const BUCKETS = [ { id: "videos", label: "Videos", icon: Film, types: "video/*" }, @@ -34,10 +35,10 @@ export default function MediaPage() { if (uploadError) throw uploadError; - alert("File uploaded successfully!"); + toast.success("File uploaded successfully!"); } catch (error) { console.error("Upload failed:", error); - alert("Upload failed: " + (error instanceof Error ? error.message : "Unknown error")); + toast.error("Upload failed: " + (error instanceof Error ? error.message : "Unknown error")); } finally { setUploading(false); if (fileInputRef.current) { diff --git a/admin-web/app/trainers/page.tsx b/admin-web/app/trainers/page.tsx index cfcd537..1eec42e 100644 --- a/admin-web/app/trainers/page.tsx +++ b/admin-web/app/trainers/page.tsx @@ -6,6 +6,7 @@ import { Button } from "@/components/ui/button"; import { Card, CardContent } from "@/components/ui/card"; import { Plus, Trash2, Edit, Loader2, Users, AlertCircle } from "lucide-react"; import Link from "next/link"; +import { toast } from "sonner"; import type { Database } from "@/lib/supabase"; type Trainer = Database["public"]["Tables"]["trainers"]["Row"]; @@ -56,9 +57,12 @@ export default function TrainersPage() { const { error } = await supabase.from("trainers").delete().eq("id", id); if (error) throw error; setTrainers(trainers.filter((t) => t.id !== id)); + toast.success("Trainer deleted", { + description: "The trainer has been removed successfully." + }); } catch (error) { console.error("Failed to delete trainer:", error); - alert("Failed to delete trainer"); + toast.error("Failed to delete trainer"); } finally { setDeletingId(null); } diff --git a/admin-web/app/workouts/page.tsx b/admin-web/app/workouts/page.tsx index 26b6932..2a493b4 100644 --- a/admin-web/app/workouts/page.tsx +++ b/admin-web/app/workouts/page.tsx @@ -16,6 +16,7 @@ import { TableRow, } from "@/components/ui/table"; import { Plus, Trash2, Edit, Loader2, Eye } from "lucide-react"; +import { toast } from "sonner"; import type { Database } from "@/lib/supabase"; type Workout = Database["public"]["Tables"]["workouts"]["Row"]; @@ -54,9 +55,12 @@ export default function WorkoutsPage() { const { error } = await supabase.from("workouts").delete().eq("id", id); if (error) throw error; setWorkouts(workouts.filter((w) => w.id !== id)); + toast.success("Workout deleted", { + description: "The workout has been removed successfully." + }); } catch (error) { console.error("Failed to delete workout:", error); - alert("Failed to delete workout"); + toast.error("Failed to delete workout"); } finally { setDeletingId(null); } diff --git a/admin-web/components/workout-form.tsx b/admin-web/components/workout-form.tsx index 8edeee0..417eb55 100644 --- a/admin-web/components/workout-form.tsx +++ b/admin-web/components/workout-form.tsx @@ -16,6 +16,7 @@ import { TagInput } from "@/components/tag-input" import { ExerciseList, Exercise } from "@/components/exercise-list" import { MediaUpload } from "@/components/media-upload" import { moveFilesFromTempToWorkout } from "@/lib/storage" +import { toast } from "sonner" import type { Database } from "@/lib/supabase" type Workout = Database["public"]["Tables"]["workouts"]["Row"] @@ -215,7 +216,7 @@ export default function WorkoutForm({ initialData, mode = "create" }: WorkoutFor router.push(`/workouts/${result.data.id}`) } catch (err) { console.error("Failed to save workout:", err) - alert("Failed to save workout. Please try again.") + toast.error("Failed to save workout. Please try again.") } finally { setIsLoading(false) } diff --git a/admin-web/package-lock.json b/admin-web/package-lock.json index 3cd33ec..6feefc9 100644 --- a/admin-web/package-lock.json +++ b/admin-web/package-lock.json @@ -16,6 +16,7 @@ "radix-ui": "^1.4.3", "react": "19.2.3", "react-dom": "19.2.3", + "sonner": "^2.0.7", "tailwind-merge": "^3.5.0" }, "devDependencies": { @@ -12066,6 +12067,16 @@ "dev": true, "license": "MIT" }, + "node_modules/sonner": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/sonner/-/sonner-2.0.7.tgz", + "integrity": "sha512-W6ZN4p58k8aDKA4XPcx2hpIQXBRAgyiWVkYhT7CvK6D3iAu7xjvVyhQHg2/iaKJZ1XVJ4r7XuwGL+WGEK37i9w==", + "license": "MIT", + "peerDependencies": { + "react": "^18.0.0 || ^19.0.0 || ^19.0.0-rc", + "react-dom": "^18.0.0 || ^19.0.0 || ^19.0.0-rc" + } + }, "node_modules/source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", diff --git a/admin-web/package.json b/admin-web/package.json index a48ecc6..4919669 100644 --- a/admin-web/package.json +++ b/admin-web/package.json @@ -20,6 +20,7 @@ "radix-ui": "^1.4.3", "react": "19.2.3", "react-dom": "19.2.3", + "sonner": "^2.0.7", "tailwind-merge": "^3.5.0" }, "devDependencies": {