"use client"; import { BanIcon, CheckCircle2Icon } from "lucide-react"; import { useEffect, useMemo, useState } from "react"; import { type CustomerFormSavePayload } from "@/components/customer-form"; import { DashboardCrudPage, createDashboardStatusColumn, createDashboardStatusToggleAction, type DashboardCrudColumn, type DashboardCrudFilter, } from "@/components/dashboard/crud"; import { type ComboboxOption } from "@/components/option-combobox"; import { fetchCompanies, type AdminCompany } from "@/lib/api/company"; import { deleteCustomer, fetchCustomers, saveCustomerProfile, updateCustomerStatus, type AdminCustomer, } from "@/lib/api/customer"; import { Gender, Status } from "@/lib/generated/enums"; import { useI18n } from "@/i18n/provider"; import { EditDialog } from "./_components/edit"; type TFunction = (key: string, values?: Record) => string; function getGenderText(gender: number, t: TFunction) { if (gender === Gender.Male) return t("customerForm.genderMale"); if (gender === Gender.Female) return t("customerForm.genderFemale"); return t("customerForm.genderUnknown"); } export default function DashboardCustomersPage() { const t = useI18n(); const [companyOptions, setCompanyOptions] = useState([ { value: "0", label: t("customer.allCompanies") }, ]); const [companyNameMap, setCompanyNameMap] = useState>( {}, ); const listStatusOptions = useMemo( () => [ { value: "all", label: t("status.all") }, { value: String(Status.Ok), label: t("status.ok") }, { value: String(Status.Disabled), label: t("status.disabled") }, ], [t], ); const genderOptions = useMemo( () => [ { value: "all", label: t("customer.allGenders") }, { value: String(Gender.Unknown), label: t("customerForm.genderUnknown") }, { value: String(Gender.Male), label: t("customerForm.genderMale") }, { value: String(Gender.Female), label: t("customerForm.genderFemale") }, ], [t], ); useEffect(() => { async function loadCompanies() { try { const data = await fetchCompanies({ status: 0, page: 1, limit: 500 }); setCompanyOptions([ { value: "0", label: t("customer.allCompanies") }, ...data.results.map((item) => ({ value: String(item.id), label: item.name, })), ]); const map: Record = {}; data.results.forEach((item: AdminCompany) => { map[item.id] = item.name; }); setCompanyNameMap(map); } catch { // Company names are optional display enrichment for this list. } } void loadCompanies(); }, [t]); const filters = useMemo( () => [ { name: "keyword", label: t("customer.columnName"), placeholder: t("customer.keywordPlaceholder"), defaultValue: "", trim: true, className: "w-full sm:w-72", }, { name: "gender", label: t("customer.columnGender"), type: "select", defaultValue: "all", allValue: "all", valueType: "number", options: genderOptions, className: "w-full sm:w-36", }, { name: "companyId", label: t("customer.columnCompany"), type: "select", defaultValue: "0", allValue: "0", valueType: "number", options: companyOptions, className: "w-full sm:w-56", }, { name: "status", label: t("customer.columnStatus"), type: "select", defaultValue: "all", allValue: "all", valueType: "number", options: listStatusOptions, className: "w-full sm:w-36", }, ], [companyOptions, genderOptions, listStatusOptions, t], ); const columns = useMemo[]>( () => [ { key: "id", label: "ID", className: "w-20", render: (item) => item.id, }, { key: "name", label: t("customer.columnName"), render: (item) => {item.name}, }, { key: "gender", label: t("customer.columnGender"), className: "w-20", render: (item) => ( {getGenderText(item.gender, t)} ), }, { key: "company", label: t("customer.columnCompany"), render: (item) => ( {item.companyId > 0 ? (companyNameMap[item.companyId] ?? String(item.companyId)) : "-"} ), }, { key: "mobile", label: t("customer.columnMobile"), render: (item) => ( {item.primaryMobile || "-"} ), }, { key: "email", label: t("customer.columnEmail"), render: (item) => ( {item.primaryEmail || "-"} ), }, createDashboardStatusColumn({ label: t("customer.columnStatus"), className: "w-24", getStatus: (item) => item.status, getLabel: (status) => status === Status.Ok ? t("status.ok") : t("status.disabled"), getBadgeVariant: (status) => status === Status.Ok ? "default" : "secondary", }), ], [companyNameMap, t], ); return ( filters={filters} columns={columns} fetchList={(query) => fetchCustomers({ keyword: typeof query.keyword === "string" ? query.keyword : undefined, status: typeof query.status === "number" ? query.status : undefined, gender: typeof query.gender === "number" ? query.gender : undefined, companyId: typeof query.companyId === "number" ? query.companyId : undefined, page: Number(query.page), limit: Number(query.limit), }) } getItemId={(item) => item.id} createItem={saveCustomerProfile} updateItem={(_item, payload) => saveCustomerProfile(payload)} deleteItem={(item) => deleteCustomer(item.id)} canDelete={(item) => item.status !== Status.Deleted} rowActions={[ createDashboardStatusToggleAction({ icon: (item) => item.status === Status.Ok ? : , label: (item) => item.status === Status.Ok ? t("customer.disable") : t("customer.enable"), disabled: (item) => item.status === Status.Deleted, getNextStatus: (item) => item.status === Status.Ok ? Status.Disabled : Status.Ok, updateStatus: (item, nextStatus) => updateCustomerStatus(item.id, nextStatus), successMessage: (item, nextStatus) => t(nextStatus === Status.Ok ? "customer.enabled" : "customer.disabled", { name: item.name, }), errorMessage: t("customer.statusUpdateFailed"), }), ]} renderEditDialog={({ open, saving, itemId, onOpenChange, onSubmit }) => ( )} labels={{ refresh: t("customer.refresh"), create: t("customer.new"), query: t("customer.query"), loading: t("customer.loading"), empty: t("customer.empty"), actions: t("customer.columnActions"), edit: t("customer.edit"), delete: t("customer.delete"), processing: t("customer.processing"), moreActions: (item) => t("customer.moreActions", { name: item.name }), loadFailed: t("customer.loadFailed"), saveFailed: t("customer.saveFailed"), deleteFailed: t("customer.deleteFailed"), created: (payload) => t("customer.created", { name: payload.name }), updated: (item) => t("customer.updated", { name: item.name }), deleted: (item) => t("customer.deleted", { name: item.name }), }} /> ); }