"use client"; import Link from "next/link"; import { useQuery } from "@tanstack/react-query"; import { PageHeader, LoadingState, ErrorState, Badge, Card, CardContent, DataTable, EmptyState, } 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 { StatWidget, BeautyTablePage } from "@/modules/beauty/design-system"; export function BeautyPageLoader({ label = "در حال بارگذاری…" }: { label?: string }) { return ; } export function BeautyPageError({ error, onRetry, }: { error: unknown; onRetry?: () => void; }) { const message = error instanceof Error ? error.message : "خطا در دریافت داده‌ها"; return ; } export function useBeautyServiceMeta() { const healthQ = useQuery({ queryKey: ["beauty", "health"], queryFn: () => beautyBusinessApi.health(), }); const capsQ = useQuery({ queryKey: ["beauty", "capabilities"], queryFn: () => beautyBusinessApi.capabilities(), }); const metricsQ = useQuery({ queryKey: ["beauty", "metrics"], queryFn: () => beautyBusinessApi.metrics(), }); return { healthQ, capsQ, metricsQ }; } export function ServiceMetaBadges() { const { healthQ, capsQ } = useBeautyServiceMeta(); return (
{healthQ.data ? ( سرویس {healthQ.data.version} ) : null} {capsQ.data ? فاز {capsQ.data.phase} : null}
); } export function MetricsGrid() { const { metricsQ } = useBeautyServiceMeta(); if (metricsQ.isLoading) return null; if (!metricsQ.data) return null; return (

متریک‌های سرویس

{metricsQ.data.note ? (

{metricsQ.data.note}

) : null}
{Object.entries(metricsQ.data.metrics).map(([k, v]) => ( {k}: {String(v)} ))}
); } export function AggregateStatsRow({ stats, }: { stats: { label: string; value: string | number; hint?: string }[]; }) { return (
{stats.map((s) => ( ))}
); } export function ExternalProvidersByKind({ kind, title, description, accountingLink, }: { kind: "accounting" | "crm" | "communication" | "delivery" | "loyalty"; title: string; description: string; accountingLink?: boolean; }) { const { tenantId } = useTenantId(); const q = useQuery({ queryKey: ["beauty", tenantId, "external-providers", kind], queryFn: () => beautyBusinessApi.externalProviders.list(tenantId!), enabled: !!tenantId, select: (rows) => rows.filter((p) => p.provider_kind === kind), }); if (!tenantId || q.isLoading) return ; if (q.error) return q.refetch()} />; return ( {String(r.status)}, }, ]} rows={(q.data ?? []) as unknown as Record[]} empty={} actions={ accountingLink ? ( حسابداری تربت‌یار ) : undefined } /> ); } export function EntityListPage({ title, description, queryKey, queryFn, columns, renderCard, emptyTitle, }: { title: string; description?: string; queryKey: string[]; queryFn: (tenantId: string) => Promise; columns: { key: string; header: string; render?: (row: T) => React.ReactNode }[]; renderCard?: (row: T) => React.ReactNode; emptyTitle?: string; }) { const { tenantId } = useTenantId(); const q = useQuery({ queryKey, queryFn: () => queryFn(tenantId!), enabled: !!tenantId, }); if (!tenantId || q.isLoading) return ; if (q.error) return q.refetch()} />; const rows = q.data ?? []; return (
{renderCard ? (
{rows.map((r) => (
{renderCard(r)}
))}
) : ( ({ ...c, render: c.render ? (row) => c.render!(row as T) : undefined, }))} rows={rows as unknown as Record[]} empty={} /> )} {renderCard && rows.length === 0 ? : null}
); } export function AnalyticsPage({ title }: { title: string }) { const { tenantId } = useTenantId(); const { organizations, branches, customers, staff, services, isLoading } = useBeautyLookups(); const apptsQ = useQuery({ queryKey: ["beauty", tenantId, "analytics-appointments"], queryFn: () => beautyBusinessApi.appointments.list(tenantId!), enabled: !!tenantId, }); const { capsQ } = useBeautyServiceMeta(); if (!tenantId || isLoading || apptsQ.isLoading) return ; if (apptsQ.error) return apptsQ.refetch()} />; return (
); } export function MonitoringPage() { const { healthQ, capsQ, metricsQ } = useBeautyServiceMeta(); if (healthQ.isLoading || capsQ.isLoading) return ; const err = healthQ.error || capsQ.error || metricsQ.error; if (err) return healthQ.refetch()} />; return (

Health

{healthQ.data?.status}

{healthQ.data?.service} v{healthQ.data?.version}

Capabilities

فاز {capsQ.data?.phase}

{capsQ.data?.commercial_product}

Independence

{capsQ.data?.independence.integration_mode}

); } export function SettingsListPage({ title, description }: { title: string; description: string }) { const { tenantId } = useTenantId(); const q = useQuery({ queryKey: ["beauty", tenantId, "settings"], queryFn: () => beautyBusinessApi.settings.list(tenantId!), enabled: !!tenantId, }); if (!tenantId || q.isLoading) return ; if (q.error) return q.refetch()} />; return ( ( {JSON.stringify(r.value ?? {})} ), }, { key: "description", header: "توضیح", render: (r) => String(r.description ?? "—") }, ]} rows={(q.data ?? []) as unknown as Record[]} empty={} /> ); }