diff --git a/package.json b/package.json
index 0d65369..c6f03e8 100644
--- a/package.json
+++ b/package.json
@@ -9,6 +9,7 @@
"lint": "next lint"
},
"dependencies": {
+ "@radix-ui/react-alert-dialog": "^1.1.2",
"@radix-ui/react-avatar": "^1.1.1",
"@radix-ui/react-collapsible": "^1.1.1",
"@radix-ui/react-dialog": "^1.1.2",
@@ -25,7 +26,8 @@
"react": "^19.0.0",
"react-dom": "^19.0.0",
"tailwind-merge": "^2.5.5",
- "tailwindcss-animate": "^1.0.7"
+ "tailwindcss-animate": "^1.0.7",
+ "zustand": "^5.0.2"
},
"devDependencies": {
"typescript": "^5",
diff --git a/src/app/dashboard/layout.tsx b/src/app/dashboard/layout.tsx
index 3497e5a..aa09dac 100644
--- a/src/app/dashboard/layout.tsx
+++ b/src/app/dashboard/layout.tsx
@@ -14,6 +14,7 @@ import {
import { SessionProvider } from "next-auth/react";
import { AppSidebar } from "@/components/app-sidebar";
import { Separator } from "@/components/ui/separator";
+import ConfirmationDialog from "@/dialogs/ConfirmationDialog";
export default function DashboardLayout({
children,
@@ -44,6 +45,7 @@ export default function DashboardLayout({
{children}
+
);
diff --git a/src/components/nav-user.tsx b/src/components/nav-user.tsx
index 3be56fa..4df53ac 100644
--- a/src/components/nav-user.tsx
+++ b/src/components/nav-user.tsx
@@ -4,10 +4,9 @@ import {
Bell,
LogIn,
LogOut,
- Sparkles,
- BadgeCheck,
- CreditCard,
+ Settings,
ChevronsUpDown,
+ CircleUserRound,
} from "lucide-react";
import { useMemo } from "react";
import {
@@ -25,7 +24,8 @@ import {
DropdownMenuTrigger,
DropdownMenuSeparator,
} from "@/components/ui/dropdown-menu";
-import { useSession } from "next-auth/react";
+import useConfirmationStore from "@/store/confirmationStore";
+import { signIn, signOut, useSession } from "next-auth/react";
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
const UserAvatar = ({ src, alt }: { src: string; alt: string }) => (
@@ -46,6 +46,7 @@ export const NavUser = ({
}) => {
const { isMobile } = useSidebar();
const { data: session } = useSession();
+ const { openConfirmation } = useConfirmationStore();
const currentUser = useMemo(() => {
if (session?.user) {
@@ -104,28 +105,37 @@ export const NavUser = ({
-
- Upgrade to Pro
+
+ Profile
-
-
- Account
-
-
-
- Billing
-
Notifications
+
+
+ Settings
+
-
+ {
+ openConfirmation({
+ title: "Leaving Already?",
+ description: "Are you sure you want to say goodbye?",
+ cancelLabel: "Stay",
+ actionLabel: "Leave",
+ onCancel: () => {},
+ onAction: () => {
+ signOut();
+ },
+ });
+ }}
+ >
Log out
@@ -133,7 +143,7 @@ export const NavUser = ({
>
) : (
-
+ signIn()}>
Log in
diff --git a/src/components/ui/alert-dialog.tsx b/src/components/ui/alert-dialog.tsx
new file mode 100644
index 0000000..57760f2
--- /dev/null
+++ b/src/components/ui/alert-dialog.tsx
@@ -0,0 +1,141 @@
+"use client"
+
+import * as React from "react"
+import * as AlertDialogPrimitive from "@radix-ui/react-alert-dialog"
+
+import { cn } from "@/lib/utils"
+import { buttonVariants } from "@/components/ui/button"
+
+const AlertDialog = AlertDialogPrimitive.Root
+
+const AlertDialogTrigger = AlertDialogPrimitive.Trigger
+
+const AlertDialogPortal = AlertDialogPrimitive.Portal
+
+const AlertDialogOverlay = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+))
+AlertDialogOverlay.displayName = AlertDialogPrimitive.Overlay.displayName
+
+const AlertDialogContent = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+
+
+
+))
+AlertDialogContent.displayName = AlertDialogPrimitive.Content.displayName
+
+const AlertDialogHeader = ({
+ className,
+ ...props
+}: React.HTMLAttributes) => (
+
+)
+AlertDialogHeader.displayName = "AlertDialogHeader"
+
+const AlertDialogFooter = ({
+ className,
+ ...props
+}: React.HTMLAttributes) => (
+
+)
+AlertDialogFooter.displayName = "AlertDialogFooter"
+
+const AlertDialogTitle = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+))
+AlertDialogTitle.displayName = AlertDialogPrimitive.Title.displayName
+
+const AlertDialogDescription = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+))
+AlertDialogDescription.displayName =
+ AlertDialogPrimitive.Description.displayName
+
+const AlertDialogAction = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+))
+AlertDialogAction.displayName = AlertDialogPrimitive.Action.displayName
+
+const AlertDialogCancel = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+))
+AlertDialogCancel.displayName = AlertDialogPrimitive.Cancel.displayName
+
+export {
+ AlertDialog,
+ AlertDialogPortal,
+ AlertDialogOverlay,
+ AlertDialogTrigger,
+ AlertDialogContent,
+ AlertDialogHeader,
+ AlertDialogFooter,
+ AlertDialogTitle,
+ AlertDialogDescription,
+ AlertDialogAction,
+ AlertDialogCancel,
+}
diff --git a/src/dialogs/ConfirmationDialog.tsx b/src/dialogs/ConfirmationDialog.tsx
new file mode 100644
index 0000000..816009b
--- /dev/null
+++ b/src/dialogs/ConfirmationDialog.tsx
@@ -0,0 +1,48 @@
+"use client";
+
+import React from "react";
+import {
+ AlertDialog,
+ AlertDialogAction,
+ AlertDialogCancel,
+ AlertDialogContent,
+ AlertDialogDescription,
+ AlertDialogFooter,
+ AlertDialogHeader,
+ AlertDialogTitle,
+} from "@/components/ui/alert-dialog";
+import useConfirmationStore from "@/store/confirmationStore";
+
+const ConfirmationDialog = () => {
+ const {
+ open,
+ title,
+ description,
+ cancelLabel,
+ actionLabel,
+ onCancel,
+ onAction,
+ closeConfirmation,
+ } = useConfirmationStore();
+
+ return (
+
+
+
+ {title}
+ {description}
+
+
+
+ {cancelLabel}
+
+
+ {actionLabel}
+
+
+
+
+ );
+};
+
+export default ConfirmationDialog;
diff --git a/src/store/confirmationStore.ts b/src/store/confirmationStore.ts
new file mode 100644
index 0000000..2a75b47
--- /dev/null
+++ b/src/store/confirmationStore.ts
@@ -0,0 +1,64 @@
+import { create } from "zustand";
+
+interface ConfirmationState {
+ open: boolean;
+ title: string | null;
+ description: string | null;
+ cancelLabel: string | null;
+ actionLabel: string | null;
+ onCancel: () => void;
+ onAction: () => void;
+}
+
+interface ConfirmationActions {
+ openConfirmation: (data: {
+ title: string;
+ description: string;
+ cancelLabel: string;
+ actionLabel: string;
+ onCancel: () => void;
+ onAction: () => void;
+ }) => void;
+ closeConfirmation: () => void;
+}
+
+const useConfirmationStore = create(
+ (set) => ({
+ open: false,
+ title: null,
+ description: null,
+ cancelLabel: null,
+ actionLabel: null,
+ onCancel: () => {},
+ onAction: () => {},
+ openConfirmation: (data) =>
+ set(() => ({
+ open: true,
+ title: data.title,
+ description: data.description,
+ cancelLabel: data.cancelLabel,
+ actionLabel: data.actionLabel,
+ onCancel: data.onCancel,
+ onAction: data.onAction,
+ })),
+ closeConfirmation: () => {
+ set((state) => ({
+ ...state,
+ open: false,
+ }));
+ setTimeout(() => {
+ set((state) => ({
+ ...state,
+ title: null,
+ description: null,
+ cancelLabel: null,
+ actionLabel: null,
+ onCancel: () => {},
+ onAction: () => {},
+ }));
+ }, 100);
+ },
+ })
+);
+
+export default useConfirmationStore;