193 lines
5.4 KiB
TypeScript
193 lines
5.4 KiB
TypeScript
"use client";
|
|
|
|
|
|
import { cn } from "@/lib/utils";
|
|
import {
|
|
Dialog,
|
|
DialogContent,
|
|
DialogTrigger,
|
|
} from "@/app/_components/ui/dialog";
|
|
import { ScrollArea } from "@/app/_components/ui/scroll-area";
|
|
import { Separator } from "@/app/_components/ui/separator";
|
|
import {
|
|
Avatar,
|
|
AvatarFallback,
|
|
AvatarImage,
|
|
} from "@/app/_components/ui/avatar";
|
|
import {
|
|
IconBell,
|
|
IconFingerprint,
|
|
IconLock,
|
|
IconPlugConnected,
|
|
IconSettings,
|
|
IconUser,
|
|
IconUsers,
|
|
IconWorld,
|
|
} from "@tabler/icons-react";
|
|
import type { User } from "@/src/models/users/users.model";
|
|
import { ProfileSettings } from "./profile-settings";
|
|
import { DialogTitle } from "@radix-ui/react-dialog";
|
|
import { useState } from "react";
|
|
|
|
interface SettingsDialogProps {
|
|
user: User | null;
|
|
trigger: React.ReactNode;
|
|
defaultTab?: string;
|
|
open?: boolean;
|
|
onOpenChange?: (open: boolean) => void;
|
|
}
|
|
|
|
interface SettingsTab {
|
|
id: string;
|
|
icon: typeof IconUser;
|
|
title: string;
|
|
content: React.ReactNode;
|
|
}
|
|
|
|
interface SettingsSection {
|
|
title: string;
|
|
tabs: SettingsTab[];
|
|
}
|
|
|
|
export function SettingsDialog({
|
|
user,
|
|
trigger,
|
|
defaultTab = "account",
|
|
open,
|
|
onOpenChange,
|
|
}: SettingsDialogProps) {
|
|
const [selectedTab, setSelectedTab] = useState(defaultTab);
|
|
|
|
// Get user display name
|
|
const preferredName = user?.profile?.first_name || "";
|
|
const userEmail = user?.email || "";
|
|
const displayName = preferredName || userEmail?.split("@")[0] || "User";
|
|
const userAvatar = user?.profile?.avatar || "";
|
|
|
|
const sections: SettingsSection[] = [
|
|
{
|
|
title: "Account",
|
|
tabs: [
|
|
{
|
|
id: "account",
|
|
icon: IconUser,
|
|
title: "My Account",
|
|
content: <ProfileSettings user={user} />,
|
|
},
|
|
{
|
|
id: "preferences",
|
|
icon: IconSettings,
|
|
title: "Preferences",
|
|
content: <div>Preferences content</div>,
|
|
},
|
|
{
|
|
id: "notifications",
|
|
icon: IconBell,
|
|
title: "Notifications",
|
|
content: <div>Notifications content</div>,
|
|
},
|
|
{
|
|
id: "connections",
|
|
icon: IconPlugConnected,
|
|
title: "Connections",
|
|
content: <div>Connections content</div>,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
title: "Workspace",
|
|
tabs: [
|
|
{
|
|
id: "general",
|
|
icon: IconWorld,
|
|
title: "General",
|
|
content: <div>General content</div>,
|
|
},
|
|
{
|
|
id: "members",
|
|
icon: IconUsers,
|
|
title: "Members",
|
|
content: <div>Members content</div>,
|
|
},
|
|
{
|
|
id: "security",
|
|
icon: IconLock,
|
|
title: "Security",
|
|
content: <div>Security content</div>,
|
|
},
|
|
{
|
|
id: "identity",
|
|
icon: IconFingerprint,
|
|
title: "Identity",
|
|
content: <div>Identity content</div>,
|
|
},
|
|
],
|
|
},
|
|
];
|
|
|
|
const currentTab = sections
|
|
.flatMap((section) => section.tabs)
|
|
.find((tab) => tab.id === selectedTab);
|
|
|
|
return (
|
|
<Dialog open={open} onOpenChange={onOpenChange}>
|
|
<DialogTitle></DialogTitle>
|
|
<DialogTrigger asChild>{trigger}</DialogTrigger>
|
|
<DialogContent className="max-w-[1200px] gap-0 p-0">
|
|
<div className="grid h-[600px] grid-cols-[250px,1fr]">
|
|
{/* Sidebar */}
|
|
<div className="border-r bg-muted/50">
|
|
<ScrollArea className="h-[600px]">
|
|
<div className="p-2">
|
|
<div className="flex items-center gap-2 px-3 py-2">
|
|
<Avatar className="h-8 w-8">
|
|
<AvatarImage src={userAvatar} alt={displayName} />
|
|
<AvatarFallback>
|
|
{displayName[0].toUpperCase()}
|
|
</AvatarFallback>
|
|
</Avatar>
|
|
<span className="text-sm font-medium">{displayName}</span>
|
|
</div>
|
|
{sections.map((section, index) => (
|
|
<div key={section.title} className="py-2">
|
|
<div className="px-3 py-2">
|
|
<h3 className="text-sm font-medium text-muted-foreground">
|
|
{section.title}
|
|
</h3>
|
|
</div>
|
|
<div className="space-y-1">
|
|
{section.tabs.map((tab) => (
|
|
<button
|
|
key={tab.id}
|
|
onClick={() => setSelectedTab(tab.id)}
|
|
className={cn(
|
|
"flex w-full items-center gap-2 rounded-lg px-3 py-2 text-sm font-medium",
|
|
tab.id === selectedTab
|
|
? "bg-accent text-accent-foreground"
|
|
: "text-muted-foreground hover:bg-accent hover:text-accent-foreground"
|
|
)}
|
|
>
|
|
<tab.icon className="h-4 w-4" />
|
|
{tab.title}
|
|
</button>
|
|
))}
|
|
</div>
|
|
{index < sections.length - 1 && (
|
|
<Separator className="mx-3 my-2" />
|
|
)}
|
|
</div>
|
|
))}
|
|
</div>
|
|
</ScrollArea>
|
|
</div>
|
|
|
|
{/* Content */}
|
|
<div className="flex flex-col">
|
|
<div className="flex-1">{currentTab?.content}</div>
|
|
</div>
|
|
</div>
|
|
</DialogContent>
|
|
</Dialog>
|
|
);
|
|
}
|