From 173fb99aed957fd8b9b47455a1cb5b6cf4115c34 Mon Sep 17 00:00:00 2001
From: Mohamed Bassem <me@mbassem.com>
Date: Sun, 28 Dec 2025 08:32:32 +0000
Subject: refactor: migrate toasts to sonner

---
 apps/web/components/ui/sonner.tsx | 71 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 71 insertions(+)
 create mode 100644 apps/web/components/ui/sonner.tsx

(limited to 'apps/web/components/ui/sonner.tsx')

diff --git a/apps/web/components/ui/sonner.tsx b/apps/web/components/ui/sonner.tsx
new file mode 100644
index 00000000..d281f4ae
--- /dev/null
+++ b/apps/web/components/ui/sonner.tsx
@@ -0,0 +1,71 @@
+"use client";
+
+import {
+  CircleCheck,
+  Info,
+  LoaderCircle,
+  OctagonX,
+  TriangleAlert,
+} from "lucide-react";
+import { useTheme } from "next-themes";
+import { Toaster as Sonner, toast } from "sonner";
+
+type ToasterProps = React.ComponentProps<typeof Sonner>;
+
+const Toaster = ({ ...props }: ToasterProps) => {
+  const { theme = "system" } = useTheme();
+
+  return (
+    <Sonner
+      theme={theme as ToasterProps["theme"]}
+      className="toaster group"
+      icons={{
+        success: <CircleCheck className="h-4 w-4" />,
+        info: <Info className="h-4 w-4" />,
+        warning: <TriangleAlert className="h-4 w-4" />,
+        error: <OctagonX className="h-4 w-4" />,
+        loading: <LoaderCircle className="h-4 w-4 animate-spin" />,
+      }}
+      toastOptions={{
+        classNames: {
+          toast:
+            "group toast group-[.toaster]:bg-background group-[.toaster]:text-foreground group-[.toaster]:border-border group-[.toaster]:shadow-lg",
+          description: "group-[.toast]:text-muted-foreground",
+          actionButton:
+            "group-[.toast]:bg-primary group-[.toast]:text-primary-foreground",
+          cancelButton:
+            "group-[.toast]:bg-muted group-[.toast]:text-muted-foreground",
+        },
+      }}
+      {...props}
+    />
+  );
+};
+
+/**
+ * Compat layer for migrating from old toaster to sonner
+ * @deprecated Use sonner's natie toast instead
+ */
+const legacyToast = ({
+  title,
+  description,
+  variant,
+}: {
+  title?: React.ReactNode;
+  description?: React.ReactNode;
+  variant?: "destructive" | "default";
+}) => {
+  let toastTitle = title;
+  let toastDescription: React.ReactNode | undefined = description;
+  if (!title) {
+    toastTitle = description;
+    toastDescription = undefined;
+  }
+  if (variant === "destructive") {
+    toast.error(toastTitle, { description: toastDescription });
+  } else {
+    toast(toastTitle, { description: toastDescription });
+  }
+};
+
+export { Toaster, legacyToast as toast };
-- 
cgit v1.2.3-70-g09d2

