Adds accounting-service PATCH/archive, fiscal helpers, COA templates and setup status, plus SuperApp Accounting UI (DS, scoreboard, masters, vouchers, ledger, ops modules) with session refresh and HTTPS public API URLs. Co-authored-by: Cursor <cursoragent@cursor.com>
165 lines
6.6 KiB
TypeScript
165 lines
6.6 KiB
TypeScript
"use client";
|
||
|
||
import Link from "next/link";
|
||
import { usePathname } from "next/navigation";
|
||
import {
|
||
LayoutDashboard,
|
||
BookOpen,
|
||
CalendarRange,
|
||
Coins,
|
||
Landmark,
|
||
FolderKanban,
|
||
FileText,
|
||
Wallet,
|
||
Users,
|
||
Building2,
|
||
Briefcase,
|
||
FileBarChart2,
|
||
ShieldCheck,
|
||
Settings,
|
||
Moon,
|
||
Sun,
|
||
ChevronRight,
|
||
Scale,
|
||
Wrench,
|
||
Truck,
|
||
Plus,
|
||
MoreHorizontal,
|
||
} from "lucide-react";
|
||
import { cn } from "@/lib/utils";
|
||
import { useColorMode } from "@/components/providers/ColorModeProvider";
|
||
import { Button } from "@/components/ds";
|
||
|
||
const NAV = [
|
||
{ href: "/accounting", label: "داشبورد", icon: LayoutDashboard },
|
||
{ href: "/accounting/chart-of-accounts", label: "دفتر حسابها", icon: BookOpen },
|
||
{ href: "/accounting/fiscal", label: "سال و دوره مالی", icon: CalendarRange },
|
||
{ href: "/accounting/currencies", label: "ارزها", icon: Coins },
|
||
{ href: "/accounting/cost-centers", label: "مراکز هزینه", icon: Landmark },
|
||
{ href: "/accounting/projects", label: "پروژهها", icon: FolderKanban },
|
||
{ href: "/accounting/vouchers", label: "اسناد و ثبت", icon: FileText },
|
||
{ href: "/accounting/ledger", label: "دفتر کل", icon: Scale },
|
||
{ href: "/accounting/treasury", label: "خزانه", icon: Wallet },
|
||
{ href: "/accounting/customers", label: "مشتریان", icon: Users },
|
||
{ href: "/accounting/suppliers", label: "تأمینکنندگان", icon: Truck },
|
||
{ href: "/accounting/assets", label: "داراییها", icon: Building2 },
|
||
{ href: "/accounting/payroll", label: "حقوق و دستمزد", icon: Briefcase },
|
||
{ href: "/accounting/reports", label: "گزارشها", icon: FileBarChart2 },
|
||
{ href: "/accounting/audit", label: "حسابرسی", icon: ShieldCheck },
|
||
{ href: "/accounting/setup", label: "راهاندازی", icon: Wrench },
|
||
{ href: "/accounting/settings", label: "تنظیمات", icon: Settings },
|
||
];
|
||
|
||
const MOBILE_PRIMARY = [
|
||
{ href: "/accounting", label: "داشبورد", icon: LayoutDashboard },
|
||
{ href: "/accounting/vouchers", label: "اسناد", icon: FileText },
|
||
{ href: "/accounting/chart-of-accounts", label: "حسابها", icon: BookOpen },
|
||
{ href: "/accounting/treasury", label: "خزانه", icon: Wallet },
|
||
{ href: "/accounting/setup", label: "بیشتر", icon: MoreHorizontal },
|
||
];
|
||
|
||
function isActive(pathname: string, href: string) {
|
||
if (href === "/accounting") return pathname === "/accounting";
|
||
return pathname === href || pathname.startsWith(`${href}/`);
|
||
}
|
||
|
||
export function AccountingShell({ children }: { children: React.ReactNode }) {
|
||
const pathname = usePathname();
|
||
const { mode, toggle } = useColorMode();
|
||
|
||
return (
|
||
<div className="flex min-h-[calc(100vh-4rem)] bg-[var(--canvas)]">
|
||
<aside className="sticky top-16 hidden h-[calc(100vh-4rem)] w-64 shrink-0 overflow-y-auto border-l border-[var(--border)] bg-[var(--surface)] p-4 lg:block">
|
||
<div className="mb-4 flex items-center justify-between px-2">
|
||
<div>
|
||
<p className="text-xs text-[var(--muted)]">ماژول</p>
|
||
<p className="font-semibold text-secondary">حسابداری</p>
|
||
</div>
|
||
<Button type="button" variant="ghost" size="icon" onClick={toggle} aria-label="تغییر تم">
|
||
{mode === "dark" ? <Sun className="h-4 w-4" /> : <Moon className="h-4 w-4" />}
|
||
</Button>
|
||
</div>
|
||
<nav className="space-y-0.5">
|
||
{NAV.map((item) => {
|
||
const active = isActive(pathname, item.href);
|
||
const Icon = item.icon;
|
||
return (
|
||
<Link
|
||
key={item.href}
|
||
href={item.href}
|
||
className={cn(
|
||
"flex items-center gap-3 rounded-xl px-3 py-2.5 text-sm font-medium transition-colors",
|
||
active
|
||
? "bg-primary text-white shadow-sm"
|
||
: "text-[var(--muted)] hover:bg-[var(--surface-muted)] hover:text-secondary"
|
||
)}
|
||
>
|
||
<Icon className="h-4 w-4 shrink-0" />
|
||
{item.label}
|
||
</Link>
|
||
);
|
||
})}
|
||
</nav>
|
||
<Link
|
||
href="/dashboard"
|
||
className="mt-6 flex items-center gap-2 px-3 text-xs text-[var(--muted)] hover:text-secondary"
|
||
>
|
||
<ChevronRight className="h-3.5 w-3.5" />
|
||
بازگشت به workspace
|
||
</Link>
|
||
</aside>
|
||
|
||
<div className="relative min-w-0 flex-1 pb-20 lg:pb-0">
|
||
<div className="hidden gap-2 overflow-x-auto border-b border-[var(--border)] bg-[var(--surface)] px-3 py-2 md:flex lg:hidden">
|
||
{NAV.map((item) => {
|
||
const active = isActive(pathname, item.href);
|
||
return (
|
||
<Link
|
||
key={item.href}
|
||
href={item.href}
|
||
className={cn(
|
||
"whitespace-nowrap rounded-lg px-3 py-1.5 text-xs font-medium",
|
||
active ? "bg-primary text-white" : "text-[var(--muted)] hover:bg-[var(--surface-muted)]"
|
||
)}
|
||
>
|
||
{item.label}
|
||
</Link>
|
||
);
|
||
})}
|
||
</div>
|
||
|
||
<div className="mx-auto max-w-7xl px-4 py-6 sm:px-6">{children}</div>
|
||
|
||
<nav className="fixed inset-x-0 bottom-0 z-40 border-t border-[var(--border)] bg-[var(--surface)]/95 backdrop-blur md:hidden">
|
||
<div className="mx-auto flex max-w-lg items-stretch justify-around gap-1 px-2 py-1.5 pe-16">
|
||
{MOBILE_PRIMARY.map((item) => {
|
||
const active = isActive(pathname, item.href);
|
||
const Icon = item.icon;
|
||
return (
|
||
<Link
|
||
key={item.href}
|
||
href={item.href}
|
||
className={cn(
|
||
"flex min-w-0 flex-1 flex-col items-center gap-0.5 rounded-lg px-1 py-1.5 text-[10px] font-medium",
|
||
active ? "text-primary" : "text-[var(--muted)]"
|
||
)}
|
||
>
|
||
<Icon className="h-5 w-5 shrink-0" />
|
||
<span className="truncate">{item.label}</span>
|
||
</Link>
|
||
);
|
||
})}
|
||
</div>
|
||
<Link
|
||
href="/accounting/vouchers/new"
|
||
className="absolute bottom-3 left-3 flex h-12 w-12 items-center justify-center rounded-full bg-primary text-white shadow-lg"
|
||
aria-label="سند جدید"
|
||
>
|
||
<Plus className="h-6 w-6" />
|
||
</Link>
|
||
</nav>
|
||
</div>
|
||
</div>
|
||
);
|
||
}
|