"use client"; import { useMemo, useState, type ReactNode } from "react"; import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; import { toast } from "sonner"; import { Eye, Pencil, Plus, Trash2 } from "lucide-react"; import { PageHeader, Button, Dialog, Input, Textarea, DataTable, EmptyState, LoadingState, ErrorState, ConfirmDialog, TableToolbar, Select, Pagination, Tabs, JalaliDateText, } from "@/components/ds"; import { DetailDrawer, Timeline, PermissionDeniedState, type TimelineItem, } from "@/src/shared/ui"; import { useDebouncedValue, useSavedFilters } from "@/src/shared/hooks"; import { useTenantId } from "@/hooks/useTenantId"; import { BeautyBusinessApiError } from "@/modules/beauty/services/beauty-business-api"; import { useBeautyPermissions } from "@/modules/beauty/hooks/useBeautyPermissions"; import { BeautyStatusChip } from "@/modules/beauty/design-system"; import { OrganizationSelect, BranchSelect, StaffSelect, CustomerSelect, ServiceSelect, CategorySelect, RoomSelect, } from "@/modules/beauty/components/BeautyComboboxes"; import { lifecycleStatusOptions } from "@/modules/beauty/constants/labels"; export type FieldType = | "text" | "textarea" | "number" | "datetime-local" | "select" | "organization" | "branch" | "staff" | "customer" | "service" | "category" | "room"; export type FieldDef = { name: string; label: string; type?: FieldType; required?: boolean; placeholder?: string; options?: { value: string; label: string }[]; table?: boolean | ((mode: "create" | "edit") => boolean); form?: boolean | ((mode: "create" | "edit") => boolean); render?: (row: Record) => ReactNode; }; export type FilterDef = { id: string; label: string; options: { value: string; label: string }[]; }; export type WorkflowActionDef = { id: string; label: string; variant?: "default" | "outline" | "danger"; confirmTitle?: string; confirmDescription?: string; visible?: (row: Record) => boolean; run: (row: Record, tenantId: string) => Promise; }; export type ListParams = { search?: string; status?: string; page?: number; pageSize?: number; [key: string]: string | number | undefined; }; export type ResourceConfig = { storageKey: string; title: string; description?: string; viewPermission?: string; managePermission?: string; queryKey: string[]; listFn: (tenantId: string, params: ListParams) => Promise; createFn?: (tenantId: string, body: Record) => Promise; updateFn?: (tenantId: string, id: string, body: Record) => Promise; deleteFn?: (tenantId: string, id: string) => Promise; fields: FieldDef[]; filters?: FilterDef[]; workflowActions?: WorkflowActionDef[]; auditEntityType?: string; auditFn?: ( tenantId: string, entityType: string, entityId: string ) => Promise<{ id: string; action: string; message: string | null; created_at: string }[]>; defaultStatusFilter?: string; pageSize?: number; createLabel?: string; mapCreateBody?: (values: Record) => Record; mapUpdateBody?: (values: Record, row: Record) => Record; listParams?: (filters: Record) => ListParams; cardTitleKey?: string; }; function fieldVisible(f: FieldDef, mode: "create" | "edit", kind: "table" | "form") { const flag = kind === "table" ? f.table : f.form; if (flag === undefined) return kind === "table" ? f.name !== "version" : true; if (typeof flag === "function") return flag(mode); return flag; } function emptyValues(fields: FieldDef[]) { return Object.fromEntries(fields.map((f) => [f.name, ""])); } function rowToValues(row: Record, fields: FieldDef[]) { const out: Record = {}; for (const f of fields) { const v = row[f.name]; if (f.type === "datetime-local" && v) { const d = new Date(String(v)); out[f.name] = Number.isNaN(d.getTime()) ? "" : d.toISOString().slice(0, 16); } else { out[f.name] = v === null || v === undefined ? "" : String(v); } } return out; } function FieldInput({ field, value, onChange, organizationId, }: { field: FieldDef; value: string; onChange: (v: string) => void; organizationId?: string; }) { const type = field.type ?? "text"; if (type === "organization") return ; if (type === "branch") return ( ); if (type === "staff") return ; if (type === "customer") return ; if (type === "service") return ; if (type === "category") return ; if (type === "room") return ( ); if (type === "textarea") return (