"use client";
import { signOut } from "@/app/login/actions";
import { ColorModeSync } from "@/components/theme/color-mode-sync";
import type { ColorMode } from "@/lib/color-mode";
import {
Button,
Card,
CardContent,
Typography,
} from "poyraz-ui/atoms";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuLabel,
DropdownMenuSeparator,
DropdownMenuTrigger,
Tooltip,
TooltipContent,
TooltipProvider,
TooltipTrigger,
toast,
} from "poyraz-ui/molecules";
import {
SidebarContent,
SidebarFooter,
SidebarGroup,
SidebarGroupLabel,
SidebarHeader,
SidebarMenu,
SidebarMenuItem,
SidebarPanel,
SidebarProvider,
SidebarTrigger,
SidebarUserProfile,
useSidebar,
} from "poyraz-ui/organisms";
import { ChevronUp, LogOut, Settings } from "lucide-react";
import type { LucideIcon } from "lucide-react";
import Image from "next/image";
import Link from "next/link";
import { usePathname, useRouter } from "next/navigation";
import { useTransition } from "react";
export type AppShellNavItem = {
title: string;
href?: string;
icon?: LucideIcon;
};
export type AppShellNavGroup = {
title: string;
items: AppShellNavItem[];
};
export type AppShellBranding = {
applicationName: string;
organizationName: string | null;
lightLogoUrl: string | null;
darkLogoUrl: string | null;
};
type ShellUser = {
email: string;
displayName: string;
shortName: string;
avatarUrl: string | null;
};
type AppShellProps = {
branding: AppShellBranding;
children: React.ReactNode;
homeHref: string;
labels?: AppShellLabels;
navGroups: AppShellNavGroup[];
settingsHref: string;
user: ShellUser;
progress?: number;
colorMode?: ColorMode;
};
export type AppShellLabels = {
skipToContent: string;
homeAriaLabel: string;
mobileMenuAriaLabel: string;
mobileMenuTooltip: string;
logoAlt: string;
progressTitle: string;
progressValue: string;
progressAriaLabel: string;
accountMenuAriaLabel: string;
settings: string;
signOut: string;
signingOut: string;
signOutError: string;
};
export function AppShell({
branding,
children,
homeHref,
labels = defaultAppShellLabels,
navGroups,
settingsHref,
user,
progress,
colorMode,
}: AppShellProps) {
const pathname = usePathname();
const sidebarProps = { branding, homeHref, labels, navGroups, pathname, progress, settingsHref, user };
return (
{colorMode ? : null}
);
}
const defaultAppShellLabels: AppShellLabels = {
skipToContent: "Ana içeriğe geç",
homeAriaLabel: "Ana sayfa",
mobileMenuAriaLabel: "Ana menüyü aç veya kapat",
mobileMenuTooltip: "Menü",
logoAlt: "Logo",
progressTitle: "Proje ilerlemesi",
progressValue: "%{progress} tamamlandı",
progressAriaLabel: "Proje ilerlemesi",
accountMenuAriaLabel: "{name} için hesap menüsünü aç",
settings: "Ayarlar",
signOut: "Çıkış yap",
signingOut: "Çıkış yapılıyor",
signOutError: "Çıkış yapılamadı. Lütfen tekrar deneyin.",
};
type SidebarCompositionProps = {
branding: AppShellBranding;
homeHref: string;
labels: AppShellLabels;
navGroups: AppShellNavGroup[];
pathname: string;
progress?: number;
settingsHref: string;
user: ShellUser;
};
function DesktopSidebar(props: SidebarCompositionProps) {
return (
);
}
function MobileSidebar(props: SidebarCompositionProps) {
return (
{props.labels.mobileMenuTooltip}
);
}
function SidebarComposition({
branding,
homeHref,
labels,
navGroups,
pathname,
progress,
settingsHref,
user,
}: SidebarCompositionProps) {
return (
<>
{typeof progress === "number" ? : null}
>
);
}
function SidebarNavigation({
homeHref,
navGroups,
pathname,
}: Pick) {
const { setMobileOpen, variant } = useSidebar();
return navGroups.map((group) => (
{group.title}
{group.items.map((item) => {
const active =
item.href === homeHref
? pathname === homeHref
: item.href
? pathname === item.href || pathname.startsWith(`${item.href}/`)
: false;
const Icon = item.icon;
return (
: undefined}
onClick={() => {
if (variant === "floating") setMobileOpen(false);
}}
>
{item.title}
);
})}
));
}
function WorkspaceLogo({
branding,
compact = false,
}: {
branding: AppShellBranding;
compact?: boolean;
}) {
const lightLogoUrl = branding.lightLogoUrl ?? branding.darkLogoUrl ?? "/logo/blackLogoLong.png";
const darkLogoUrl = branding.darkLogoUrl ?? branding.lightLogoUrl ?? "/logo/lightLogoLong.png";
const imageClassName = compact
? "max-h-8 w-auto max-w-full object-contain"
: "max-h-12 w-auto max-w-full object-contain";
return (
);
}
function ProgressSummary({ labels, progress }: { labels: AppShellLabels; progress: number }) {
const normalizedProgress = Math.max(0, Math.min(100, progress));
const progressValue = labels.progressValue.replace("{progress}", String(normalizedProgress));
return (
{labels.progressTitle}
);
}
function AccountMenu({ labels, user, settingsHref }: { labels: AppShellLabels; user: ShellUser; settingsHref: string }) {
const router = useRouter();
const [isSigningOut, startSignOutTransition] = useTransition();
function handleSignOut() {
startSignOutTransition(async () => {
try {
const result = await signOut();
router.replace(result.redirectTo);
router.refresh();
} catch {
toast.error(labels.signOutError);
}
});
}
return (
{user.displayName}
{user.email}
{labels.settings}
);
}