diff --git a/src/app/(dashboard)/dashboard-shell.tsx b/src/app/(dashboard)/dashboard-shell.tsx new file mode 100644 index 0000000..66a3bf5 --- /dev/null +++ b/src/app/(dashboard)/dashboard-shell.tsx @@ -0,0 +1,93 @@ +"use client"; + +import React from "react"; + +import { AppSidebar } from "@/components/app-sidebar"; +import { SiteHeader } from "@/components/site-header"; +import { SiteFooter } from "@/components/site-footer"; +import { SidebarProvider, SidebarInset } from "@/components/ui/sidebar"; +import { ThemeCustomizer, ThemeCustomizerTrigger } from "@/components/theme-customizer"; +import { useSidebarConfig } from "@/hooks/use-sidebar-config"; + +export type ShellUser = { + id: string; + name: string; + email: string; +}; + +export type ShellCompany = { + id: string; + name: string; +}; + +export function DashboardShell({ + user, + company, + children, +}: { + user: ShellUser; + company: ShellCompany; + children: React.ReactNode; +}) { + const [themeCustomizerOpen, setThemeCustomizerOpen] = React.useState(false); + const { config } = useSidebarConfig(); + + return ( + + {config.side === "left" ? ( + <> + + + +
+
+
{children}
+
+
+ +
+ + ) : ( + <> + + +
+
+
{children}
+
+
+ +
+ + + )} + + setThemeCustomizerOpen(true)} /> + +
+ ); +} diff --git a/src/app/(dashboard)/layout.tsx b/src/app/(dashboard)/layout.tsx index b6dbb7c..f324a0f 100644 --- a/src/app/(dashboard)/layout.tsx +++ b/src/app/(dashboard)/layout.tsx @@ -1,78 +1,29 @@ -"use client"; +import { redirect } from "next/navigation"; -import React from "react"; -import { AppSidebar } from "@/components/app-sidebar"; -import { SiteHeader } from "@/components/site-header"; -import { SiteFooter } from "@/components/site-footer"; -import { SidebarProvider, SidebarInset } from "@/components/ui/sidebar"; -import { ThemeCustomizer, ThemeCustomizerTrigger } from "@/components/theme-customizer"; -import { UpgradeToProButton } from "@/components/upgrade-to-pro-button"; -import { useSidebarConfig } from "@/hooks/use-sidebar-config"; +import { getActiveContext } from "@/lib/appwrite/active-context"; +import { DashboardShell } from "./dashboard-shell"; -export default function DashboardLayout({ +export default async function DashboardLayout({ children, }: { children: React.ReactNode; }) { - const [themeCustomizerOpen, setThemeCustomizerOpen] = React.useState(false); - const { config } = useSidebarConfig(); + const ctx = await getActiveContext(); + if (!ctx) redirect("/onboarding"); + + const company = { + id: ctx.tenantId, + name: ctx.settings?.companyName ?? "Çalışma alanı", + }; + const user = { + id: ctx.user.id, + name: ctx.user.name || ctx.user.email, + email: ctx.user.email, + }; return ( - - {config.side === "left" ? ( - <> - - - -
-
-
- {children} -
-
-
- -
- - ) : ( - <> - - -
-
-
- {children} -
-
-
- -
- - - )} - - {/* Theme Customizer */} - setThemeCustomizerOpen(true)} /> - - -
+ + {children} + ); } diff --git a/src/components/app-sidebar.tsx b/src/components/app-sidebar.tsx index 902c755..47242a9 100644 --- a/src/components/app-sidebar.tsx +++ b/src/components/app-sidebar.tsx @@ -1,27 +1,24 @@ -"use client" +"use client"; -import * as React from "react" +import * as React from "react"; import { - LayoutPanelLeft, - LayoutDashboard, - Mail, - CheckSquare, - MessageCircle, + Briefcase, Calendar, - Shield, - AlertTriangle, - Settings, - HelpCircle, + CheckSquare, CreditCard, - LayoutTemplate, + FileText, + LayoutDashboard, + Package, + Receipt, + Settings, Users, -} from "lucide-react" -import Link from "next/link" -import { Logo } from "@/components/logo" -import { SidebarNotification } from "@/components/sidebar-notification" + Wallet, +} from "lucide-react"; +import Link from "next/link"; -import { NavMain } from "@/components/nav-main" -import { NavUser } from "@/components/nav-user" +import { Logo } from "@/components/logo"; +import { NavMain } from "@/components/nav-main"; +import { NavUser } from "@/components/nav-user"; import { Sidebar, SidebarContent, @@ -30,186 +27,106 @@ import { SidebarMenu, SidebarMenuButton, SidebarMenuItem, -} from "@/components/ui/sidebar" +} from "@/components/ui/sidebar"; -const data = { - user: { - name: "ShadcnStore", - email: "store@example.com", - avatar: "", +import type { ShellCompany, ShellUser } from "@/app/(dashboard)/dashboard-shell"; + +const navGroups = [ + { + label: "Genel", + items: [ + { + title: "Genel bakış", + url: "/dashboard", + icon: LayoutDashboard, + }, + ], }, - navGroups: [ - { - label: "Dashboards", - items: [ - { - title: "Dashboard 1", - url: "/dashboard", - icon: LayoutDashboard, - }, - { - title: "Dashboard 2", - url: "/dashboard-2", - icon: LayoutPanelLeft, - }, - ], - }, - { - label: "Apps", - items: [ - { - title: "Mail", - url: "/mail", - icon: Mail, - }, - { - title: "Tasks", - url: "/tasks", - icon: CheckSquare, - }, - { - title: "Chat", - url: "/chat", - icon: MessageCircle, - }, - { - title: "Calendar", - url: "/calendar", - icon: Calendar, - }, - { - title: "Users", - url: "/users", - icon: Users, - }, - ], - }, - { - label: "Pages", - items: [ - { - title: "Landing", - url: "/landing", - target: "_blank", - icon: LayoutTemplate, - }, - { - title: "Auth Pages", - url: "#", - icon: Shield, - items: [ - { - title: "Sign In 1", - url: "/sign-in", - }, - { - title: "Sign In 2", - url: "/sign-in-2", - }, - { - title: "Sign In 3", - url: "/sign-in-3", - }, - { - title: "Sign Up 1", - url: "/sign-up", - }, - { - title: "Sign Up 2", - url: "/sign-up-2", - }, - { - title: "Sign Up 3", - url: "/sign-up-3", - }, - { - title: "Forgot Password 1", - url: "/forgot-password", - }, - { - title: "Forgot Password 2", - url: "/forgot-password-2", - }, - { - title: "Forgot Password 3", - url: "/forgot-password-3", - } - ], - }, - { - title: "Errors", - url: "#", - icon: AlertTriangle, - items: [ - { - title: "Unauthorized", - url: "/errors/unauthorized", - }, - { - title: "Forbidden", - url: "/errors/forbidden", - }, - { - title: "Not Found", - url: "/errors/not-found", - }, - { - title: "Internal Server Error", - url: "/errors/internal-server-error", - }, - { - title: "Under Maintenance", - url: "/errors/under-maintenance", - }, - ], - }, - { - title: "Settings", - url: "#", - icon: Settings, - items: [ - { - title: "User Settings", - url: "/settings/user", - }, - { - title: "Account Settings", - url: "/settings/account", - }, - { - title: "Plans & Billing", - url: "/settings/billing", - }, - { - title: "Appearance", - url: "/settings/appearance", - }, - { - title: "Notifications", - url: "/settings/notifications", - }, - { - title: "Connections", - url: "/settings/connections", - }, - ], - }, - { - title: "FAQs", - url: "/faqs", - icon: HelpCircle, - }, - { - title: "Pricing", - url: "/pricing", - icon: CreditCard, - }, - ], - }, - ], -} + { + label: "İşletme", + items: [ + { + title: "Müşteriler", + url: "/customers", + icon: Users, + }, + { + title: "Hizmetler", + url: "/services", + icon: Briefcase, + }, + { + title: "Yazılımlarımız", + url: "/software", + icon: Package, + }, + ], + }, + { + label: "Operasyon", + items: [ + { + title: "Takvim", + url: "/calendar", + icon: Calendar, + }, + { + title: "Görevler", + url: "/tasks", + icon: CheckSquare, + }, + ], + }, + { + label: "Finans", + items: [ + { + title: "Gelir / Gider", + url: "/finance", + icon: Wallet, + }, + { + title: "Faturalar", + url: "/invoices", + icon: Receipt, + }, + ], + }, + { + label: "Hesap", + items: [ + { + title: "Çalışma alanı", + url: "/settings/workspace", + icon: Settings, + items: [ + { title: "Şirket bilgileri", url: "/settings/workspace" }, + { title: "Ekip üyeleri", url: "/settings/members" }, + { title: "Faturalama", url: "/settings/billing" }, + ], + }, + { + title: "Profil", + url: "/settings/account", + icon: FileText, + }, + { + title: "Plan", + url: "/pricing", + icon: CreditCard, + }, + ], + }, +]; -export function AppSidebar({ ...props }: React.ComponentProps) { +export function AppSidebar({ + user, + company, + ...props +}: React.ComponentProps & { + user: ShellUser; + company: ShellCompany; +}) { return ( @@ -217,12 +134,12 @@ export function AppSidebar({ ...props }: React.ComponentProps) { -
- +
+
- ShadcnStore - Admin Dashboard + İşletmem + {company.name}
@@ -230,14 +147,13 @@ export function AppSidebar({ ...props }: React.ComponentProps) { - {data.navGroups.map((group) => ( + {navGroups.map((group) => ( ))} - - + - ) + ); } diff --git a/src/components/layouts/base-layout.tsx b/src/components/layouts/base-layout.tsx deleted file mode 100644 index 4d42209..0000000 --- a/src/components/layouts/base-layout.tsx +++ /dev/null @@ -1,105 +0,0 @@ -"use client" - -import * as React from "react" -import { AppSidebar } from "@/components/app-sidebar" -import { SiteHeader } from "@/components/site-header" -import { SiteFooter } from "@/components/site-footer" -import { ThemeCustomizer, ThemeCustomizerTrigger } from "@/components/theme-customizer" -import { UpgradeToProButton } from "@/components/upgrade-to-pro-button" -import { useSidebarConfig } from "@/hooks/use-sidebar-config" -import { - SidebarInset, - SidebarProvider, -} from "@/components/ui/sidebar" - -interface BaseLayoutProps { - children: React.ReactNode - title?: string - description?: string -} - -export function BaseLayout({ children, title, description }: BaseLayoutProps) { - const [themeCustomizerOpen, setThemeCustomizerOpen] = React.useState(false) - const { config } = useSidebarConfig() - - return ( - - {config.side === "left" ? ( - <> - - - -
-
-
- {title && ( -
-
-

{title}

- {description && ( -

{description}

- )} -
-
- )} - {children} -
-
-
- -
- - ) : ( - <> - - -
-
-
- {title && ( -
-
-

{title}

- {description && ( -

{description}

- )} -
-
- )} - {children} -
-
-
- -
- - - )} - - {/* Theme Customizer */} - setThemeCustomizerOpen(true)} /> - - -
- ) -} diff --git a/src/components/nav-user.tsx b/src/components/nav-user.tsx index 7be4dae..e3e7ccf 100644 --- a/src/components/nav-user.tsx +++ b/src/components/nav-user.tsx @@ -1,15 +1,15 @@ -"use client" +"use client"; +import { useTransition } from "react"; import { + BellDot, + CircleUser, CreditCard, EllipsisVertical, LogOut, - BellDot, - CircleUser, -} from "lucide-react" -import Link from "next/link" +} from "lucide-react"; +import Link from "next/link"; -import { Logo } from "@/components/logo" import { DropdownMenu, DropdownMenuContent, @@ -18,24 +18,33 @@ import { DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger, -} from "@/components/ui/dropdown-menu" +} from "@/components/ui/dropdown-menu"; import { SidebarMenu, SidebarMenuButton, SidebarMenuItem, useSidebar, -} from "@/components/ui/sidebar" +} from "@/components/ui/sidebar"; +import { signOutAction } from "@/lib/appwrite/auth-actions"; + +function initials(name: string) { + const parts = name.trim().split(/\s+/).slice(0, 2); + return parts.map((p) => p[0]?.toUpperCase() ?? "").join("") || "?"; +} export function NavUser({ user, }: { - user: { - name: string - email: string - avatar: string - } + user: { name: string; email: string }; }) { - const { isMobile } = useSidebar() + const { isMobile } = useSidebar(); + const [isPending, startTransition] = useTransition(); + + const handleSignOut = () => { + startTransition(async () => { + await signOutAction(); + }); + }; return ( @@ -46,14 +55,12 @@ export function NavUser({ size="lg" className="data-[state=open]:bg-sidebar-accent data-[state=open]:text-sidebar-accent-foreground cursor-pointer" > -
- < Logo size={28} /> +
+ {initials(user.name)}
{user.name} - - {user.email} - + {user.email}
@@ -66,14 +73,12 @@ export function NavUser({ >
-
- < Logo size={28} /> +
+ {initials(user.name)}
{user.name} - - {user.email} - + {user.email}
@@ -82,32 +87,34 @@ export function NavUser({ - Account + Profil - Billing + Plan & Faturalama - Notifications + Bildirimler - - - - Log out - + + + {isPending ? "Çıkış yapılıyor..." : "Çıkış yap"} - ) + ); } diff --git a/src/components/site-header.tsx b/src/components/site-header.tsx index e0a3362..f8e8ddb 100644 --- a/src/components/site-header.tsx +++ b/src/components/site-header.tsx @@ -1,26 +1,29 @@ -"use client" +"use client"; -import * as React from "react" -import { Button } from "@/components/ui/button" -import { Separator } from "@/components/ui/separator" -import { SidebarTrigger } from "@/components/ui/sidebar" -import { CommandSearch, SearchTrigger } from "@/components/command-search" -import { ModeToggle } from "@/components/mode-toggle" +import * as React from "react"; +import { Building2 } from "lucide-react"; -export function SiteHeader() { - const [searchOpen, setSearchOpen] = React.useState(false) +import { CommandSearch, SearchTrigger } from "@/components/command-search"; +import { ModeToggle } from "@/components/mode-toggle"; +import { Separator } from "@/components/ui/separator"; +import { SidebarTrigger } from "@/components/ui/sidebar"; + +import type { ShellCompany } from "@/app/(dashboard)/dashboard-shell"; + +export function SiteHeader({ company }: { company?: ShellCompany }) { + const [searchOpen, setSearchOpen] = React.useState(false); React.useEffect(() => { const down = (e: KeyboardEvent) => { if (e.key === "k" && (e.metaKey || e.ctrlKey)) { - e.preventDefault() - setSearchOpen((open) => !open) + e.preventDefault(); + setSearchOpen((open) => !open); } - } + }; - document.addEventListener("keydown", down) - return () => document.removeEventListener("keydown", down) - }, []) + document.addEventListener("keydown", down); + return () => document.removeEventListener("keydown", down); + }, []); return ( <> @@ -31,45 +34,23 @@ export function SiteHeader() { orientation="vertical" className="mx-2 data-[orientation=vertical]:h-4" /> -
- setSearchOpen(true)} /> -
+ + {company && ( +
+ + {company.name} +
+ )} +
- - - +
+ setSearchOpen(true)} /> +
- ) + ); }