Move business logic out of App Router into module packages, add boundary validation scripts, and keep all routes as thin re-exports without changing URLs or API behavior. Co-authored-by: Cursor <cursoragent@cursor.com>
165 lines
5.2 KiB
TypeScript
165 lines
5.2 KiB
TypeScript
"use client";
|
|
|
|
import { useQuery } from "@tanstack/react-query";
|
|
import { PageHeader, EmptyState, Badge, DataTable } from "@/components/ds";
|
|
import { beautyBusinessApi } from "@/modules/beauty/services/beauty-business-api";
|
|
import { useTenantId } from "@/hooks/useTenantId";
|
|
import { useBeautyLookups } from "@/modules/beauty/hooks/useBeautyLookups";
|
|
import { CenterCard, CustomerCard, StaffCard } from "@/modules/beauty/design-system";
|
|
import {
|
|
AggregateStatsRow,
|
|
AnalyticsPage,
|
|
BeautyPageError,
|
|
BeautyPageLoader,
|
|
MonitoringPage,
|
|
ServiceMetaBadges,
|
|
SettingsListPage,
|
|
} from "./shared";
|
|
|
|
export function AdminDashboard() {
|
|
const { tenantId } = useTenantId();
|
|
const { organizations, branches, customers, staff, isLoading } = useBeautyLookups();
|
|
|
|
if (!tenantId || isLoading) return <BeautyPageLoader />;
|
|
|
|
return (
|
|
<div>
|
|
<PageHeader
|
|
title="داشبورد مدیر سیستم"
|
|
description="مدیریت tenant و گزارش."
|
|
actions={<ServiceMetaBadges />}
|
|
/>
|
|
<AggregateStatsRow
|
|
stats={[
|
|
{ label: "سازمانها", value: organizations.length },
|
|
{ label: "شعب", value: branches.length },
|
|
{ label: "مشتریان", value: customers.length },
|
|
{ label: "پرسنل", value: staff.length },
|
|
]}
|
|
/>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
export function AdminOrganizations() {
|
|
const { organizations, isLoading } = useBeautyLookups();
|
|
if (isLoading) return <BeautyPageLoader />;
|
|
|
|
return (
|
|
<div>
|
|
<PageHeader title="سازمانها" description="organizations API." />
|
|
<div className="mt-6 grid gap-4 sm:grid-cols-2 lg:grid-cols-3">
|
|
{organizations.map((o) => (
|
|
<CenterCard key={o.id} org={o} href="/beauty/admin/organizations" />
|
|
))}
|
|
</div>
|
|
{organizations.length === 0 ? <EmptyState title="سازمانی ثبت نشده" /> : null}
|
|
</div>
|
|
);
|
|
}
|
|
|
|
export function AdminBranches() {
|
|
const { tenantId } = useTenantId();
|
|
const q = useQuery({
|
|
queryKey: ["beauty", tenantId, "admin-branches"],
|
|
queryFn: () => beautyBusinessApi.branches.list(tenantId!),
|
|
enabled: !!tenantId,
|
|
});
|
|
|
|
if (!tenantId || q.isLoading) return <BeautyPageLoader />;
|
|
if (q.error) return <BeautyPageError error={q.error} onRetry={() => q.refetch()} />;
|
|
|
|
return (
|
|
<div>
|
|
<PageHeader title="شعب" description="branches API." />
|
|
<DataTable
|
|
columns={[
|
|
{ key: "code", header: "کد" },
|
|
{ key: "name", header: "نام" },
|
|
{
|
|
key: "status",
|
|
header: "وضعیت",
|
|
render: (r) => <Badge tone={r.status === "active" ? "success" : "default"}>{String(r.status)}</Badge>,
|
|
},
|
|
]}
|
|
rows={(q.data ?? []) as unknown as Record<string, unknown>[]}
|
|
empty={<EmptyState title="شعبهای ثبت نشده" />}
|
|
/>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
export function AdminStaff() {
|
|
const { staff, isLoading } = useBeautyLookups();
|
|
if (isLoading) return <BeautyPageLoader />;
|
|
|
|
return (
|
|
<div>
|
|
<PageHeader title="پرسنل" description="staff API." />
|
|
<div className="mt-6 grid gap-4 sm:grid-cols-2">
|
|
{staff.map((s) => (
|
|
<StaffCard key={s.id} staff={s} />
|
|
))}
|
|
</div>
|
|
{staff.length === 0 ? <EmptyState title="پرسنلی ثبت نشده" /> : null}
|
|
</div>
|
|
);
|
|
}
|
|
|
|
export function AdminCustomers() {
|
|
const { customers, isLoading } = useBeautyLookups();
|
|
if (isLoading) return <BeautyPageLoader />;
|
|
|
|
return (
|
|
<div>
|
|
<PageHeader title="مشتریان" description="customers API." />
|
|
<div className="mt-6 grid gap-4 sm:grid-cols-2">
|
|
{customers.map((c) => (
|
|
<CustomerCard key={c.id} customer={c} />
|
|
))}
|
|
</div>
|
|
{customers.length === 0 ? <EmptyState title="مشتری ثبت نشده" /> : null}
|
|
</div>
|
|
);
|
|
}
|
|
|
|
export function AdminPermissions() {
|
|
const { tenantId } = useTenantId();
|
|
const q = useQuery({
|
|
queryKey: ["beauty", tenantId, "admin-permissions"],
|
|
queryFn: () => beautyBusinessApi.permissions.catalog(tenantId!),
|
|
enabled: !!tenantId,
|
|
});
|
|
|
|
if (!tenantId || q.isLoading) return <BeautyPageLoader />;
|
|
if (q.error) return <BeautyPageError error={q.error} onRetry={() => q.refetch()} />;
|
|
|
|
return (
|
|
<div>
|
|
<PageHeader title="دسترسیها" description="permissions catalog API." />
|
|
<p className="mb-4 text-sm text-[var(--muted)]">prefix: {q.data?.prefix}</p>
|
|
<DataTable
|
|
columns={[{ key: "permission", header: "دسترسی" }]}
|
|
rows={(q.data?.permissions ?? []).map((p) => ({ permission: p })) as Record<string, unknown>[]}
|
|
empty={<EmptyState title="دسترسیای ثبت نشده" />}
|
|
/>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
export function AdminReports() {
|
|
return <AnalyticsPage title="گزارش مدیر" />;
|
|
}
|
|
|
|
export function AdminAnalytics() {
|
|
return <AnalyticsPage title="آنالیتیکس مدیر" />;
|
|
}
|
|
|
|
export function AdminMonitoring() {
|
|
return <MonitoringPage />;
|
|
}
|
|
|
|
export function AdminSettings() {
|
|
return <SettingsListPage title="تنظیمات مدیر" description="settings API." />;
|
|
}
|