TorbatYar/frontend/modules/loyalty/features/membership/members.tsx
Mortezakoohjani 625275e55b feat(healthcare): add backend service and finalize frontend build
Add the Healthcare platform backend (phases 13.0–13.7) with Alembic migration revision fix, production deploy script, validation reports, shared UI exports, and loyalty list page client directives so Next.js build succeeds.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-27 11:38:31 +03:30

95 lines
3.3 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"use client";
import Link from "next/link";
import { z } from "zod";
import { Button } from "@/components/ds";
import { loyaltyApi } from "@/modules/loyalty/services/loyalty-api";
import { createLoyaltyListPage } from "@/modules/loyalty/components/LoyaltyListCrudPage";
import { LoyaltyStatusChip } from "@/modules/loyalty/design-system";
import type { Member } from "@/modules/loyalty/types";
const createSchema = z.object({
program_id: z.string().uuid(),
display_name: z.string().min(1),
membership_number: z.string().optional(),
email: z.string().email().optional().or(z.literal("")),
mobile: z.string().optional(),
status: z
.enum(["pending", "active", "frozen", "cancelled", "expired", "transferred"])
.default("pending"),
enroll: z.coerce.boolean().default(false),
});
const editSchema = z.object({
display_name: z.string().min(1).optional(),
email: z.string().optional(),
mobile: z.string().optional(),
status: z
.enum(["pending", "active", "frozen", "cancelled", "expired", "transferred"])
.optional(),
version: z.coerce.number().optional(),
});
export default createLoyaltyListPage<Member>({
title: "اعضا",
description: "فهرست اعضای برنامه وفاداری — ایجاد، ویرایش و حذف نرم.",
breadcrumb: "اعضا",
resourceKey: "members",
createSchema,
editSchema,
createDefaults: {
program_id: "",
display_name: "",
membership_number: "",
email: "",
mobile: "",
status: "pending",
enroll: false,
},
fields: [
{ name: "program_id", label: "شناسه برنامه", required: true, createOnly: true },
{ name: "display_name", label: "نام نمایشی", required: true },
{ name: "membership_number", label: "شماره عضویت", createOnly: true },
{ name: "email", label: "ایمیل", type: "email" },
{ name: "mobile", label: "موبایل", type: "tel" },
{
name: "status",
label: "وضعیت",
type: "select",
editOnly: true,
options: [
{ value: "pending", label: "در انتظار" },
{ value: "active", label: "فعال" },
{ value: "frozen", label: "مسدود" },
{ value: "cancelled", label: "لغو" },
{ value: "expired", label: "منقضی" },
{ value: "transferred", label: "منتقل" },
],
},
],
columns: [
{ key: "membership_number", header: "شماره" },
{ key: "display_name", header: "نام" },
{ key: "email", header: "ایمیل" },
{ key: "mobile", header: "موبایل" },
{
key: "status",
header: "وضعیت",
render: (r) => <LoyaltyStatusChip status={r.status} domain="member" />,
},
],
list: (tid) => loyaltyApi.members.list(tid, { page: 1, page_size: 500 }),
create: (tid, d) => loyaltyApi.members.create(tid, d),
update: (tid, id, d) => loyaltyApi.members.update(tid, id, d),
remove: (tid, id) => loyaltyApi.members.delete(tid, id),
filterDeleted: true,
exportColumns: ["membership_number", "display_name", "email", "mobile", "status", "program_id"],
extraActions: (row) => (
<Link href={`/loyalty/engage/customer-profile?memberId=${row.id}`}>
<Button variant="ghost" size="sm">
پروفایل
</Button>
</Link>
),
});