# محدودسازی صفحات بیمه (قیمت‌گذاری و مطالبات) به خرید پلن اشتراکی

## پروژه

`clinicpro` (admin frontend + UI ادمینِ پلن)

## زمینه

پنل ادمین یک سیستم feature-gating اشتراکی **از قبل دارد** که کار می‌کند:
- `assets/admin/hooks/useSubscription.ts` → `GET /api/v1/subscription/my` را می‌خواند و `hasFeature(key)` می‌دهد (از `subscription.plan.features`).
- `assets/admin/components/ui/FeatureGate.tsx` → اگر feature فعال نباشد، به‌جای محتوا یک قفل + دکمه‌ی «مشاهده/ارتقاء پنل اشتراکی» نشان می‌دهد.
- `Sidebar.tsx` → آیتم‌های منو با `feature: "..."` در صورت نبودِ feature مخفی می‌شوند (`!hasFeature(feature)`).

دو صفحه با همین الگو **درست محدود شده‌اند**: `ClinicServicesPage` با `<FeatureGate feature="services">` و `SmsWalletPage` با `<FeatureGate feature="sms_panel">`.

## مشکل / هدف

صفحات **«قیمت‌گذاری بیمه» (`/admin/insurance-pricing`)** و **«مطالبات بیمه» (`/admin/claims`)** به‌تازگی اضافه شده‌اند ولی **هیچ محدودسازی اشتراکی ندارند** — نه در سطح صفحه و نه در منو:

- `InsurancePricingPage.tsx` و `ClaimsPage.tsx` در `<FeatureGate>` پیچیده **نشده‌اند** → باز کردن مستقیم URL، صفحه را بدون اشتراک نمایش می‌دهد.
- در `Sidebar.tsx` لینک این دو صفحه برخلاف `my-patients` **کلید `feature:` ندارند** → همیشه در منو دیده می‌شوند (در حالی‌که `my-patients` با `feature: "patient_records"` مخفی می‌شود).

هدف: این دو صفحه فقط برای دارندگانِ پلن اشتراکی فعال که feature **`insurance`** را دارند باز باشند (کلید جدید، طبق تصمیم کاربر). دقیقاً مثل `services` / `sms_panel`.

## فایل‌های مرتبط

| فایل | نقش |
|------|-----|
| `assets/admin/pages/InsurancePricingPage.tsx` | باید در `<FeatureGate feature="insurance">` پیچیده شود |
| `assets/admin/pages/ClaimsPage.tsx` | باید در `<FeatureGate feature="insurance">` پیچیده شود |
| `assets/admin/components/layout/Sidebar.tsx` | افزودن `feature: "insurance"` به لینک هر دو صفحه (دو نقش: doctor و clinic) |
| `assets/admin/pages/AdminSubscriptionPage.tsx` | افزودن `insurance` به `FEATURE_LABELS` + `planSchema.features` تا ادمین بتواند این feature را روی پلن‌ها فعال کند |
| `assets/admin/components/ui/FeatureGate.tsx` / `hooks/useSubscription.ts` | فقط مصرف؛ تغییر نمی‌کنند |

## وضعیت فعلی

### الگوی درستِ موجود (برای تقلید)

```tsx
// assets/admin/pages/SmsWalletPage.tsx (انتها)
return (
  <FeatureGate feature="sms_panel">
    ...
  </FeatureGate>
);
```

### صفحات محافظت‌نشده

```tsx
// assets/admin/pages/InsurancePricingPage.tsx — هیچ گاردی ندارد
export default function InsurancePricingPage() {
  return (
    <div className="fade-in">
      <PageHeader title="بیمه و قیمت‌گذاری" description="..." />
      <FreeVisitPrice />
      <TenantInsuranceContracts />
    </div>
  );
}
```

```tsx
// assets/admin/pages/ClaimsPage.tsx — return اصلی بدون FeatureGate
export default function ClaimsPage() {
  // ... useQuery / useMutation ...
  return ( /* جدول مطالبات + بدهی بیمه */ );
}
```

### Sidebar — لینک‌ها بدون feature

```tsx
// assets/admin/components/layout/Sidebar.tsx (نقش doctor و مشابهش در clinic)
{ to: "/admin/my-patients",       icon: FolderOpenIcon,  label: "پرونده بیماران", feature: "patient_records" },
{ to: "/admin/insurance-pricing", icon: ShieldCheckIcon, label: "قیمت‌گذاری بیمه" },   // ← feature ندارد
{ to: "/admin/claims",            icon: DocumentTextIcon, label: "مطالبات بیمه" },      // ← feature ندارد
```

### AdminSubscriptionPage — featureهای هاردکد (فقط ۳ تا)

```tsx
// assets/admin/pages/AdminSubscriptionPage.tsx
const FEATURE_LABELS: Record<string, string> = {
  patient_records: 'پرونده بیمار',
  services:        'سرویس‌ها',
  sms_panel:       'پنل پیامک',
};

const planSchema = z.object({
  ...
  features: z.object({
    patient_records: z.boolean(),
    services:        z.boolean(),
    sms_panel:       z.boolean(),
  }),
  ...
});
```

## وظایف

### ۱. پیچیدن دو صفحه در FeatureGate

`InsurancePricingPage` و `ClaimsPage` را عیناً مثل `SmsWalletPage`/`ClinicServicesPage` در `<FeatureGate feature="insurance">` بپیچ:

```tsx
// InsurancePricingPage.tsx
import FeatureGate from '../components/ui/FeatureGate';

export default function InsurancePricingPage() {
  return (
    <FeatureGate feature="insurance">
      <div className="fade-in">
        <PageHeader title="بیمه و قیمت‌گذاری" description="..." />
        <FreeVisitPrice />
        <TenantInsuranceContracts />
      </div>
    </FeatureGate>
  );
}
```

برای `ClaimsPage` کل JSX داخل `return ( ... )` را در `<FeatureGate feature="insurance">...</FeatureGate>` بگذار. (اگر pageدارای چند `return` شرطی است، فقط return نهاییِ محتوا را بپیچ؛ مراقب باش hookها بالای FeatureGate صدا زده شوند تا ترتیب hookها نشکند.)

### ۲. افزودن feature به لینک‌های Sidebar

به لینک‌های `insurance-pricing` و `claims` در **هر دو** بخش نقش (doctor و clinic) کلید `feature: "insurance"` اضافه کن تا وقتی پلن این feature را ندارد، از منو مخفی شوند (همان رفتار `my-patients`).

### ۳. افزودن `insurance` به UI ادمینِ پلن

تا ادمین بتواند feature `insurance` را روی پلن‌ها روشن/خاموش کند:

```tsx
// AdminSubscriptionPage.tsx
const FEATURE_LABELS: Record<string, string> = {
  patient_records: 'پرونده بیمار',
  services:        'سرویس‌ها',
  sms_panel:       'پنل پیامک',
  insurance:       'بیمه و مطالبات',
};
```
و `planSchema.features` و `defaultValues` و `openEditPlan` را طوری اصلاح کن که `insurance` را هم شامل شود. (بهترین کار: featureها را از روی کلیدهای `FEATURE_LABELS` بساز تا دیگر هاردکد نباشد و افزودن feature بعدی فقط map را تغییر دهد.)

## نکات مهم

- backend نیازی به تغییر ندارد: `SubscriptionPlan.features` یک json آزاد است و `hasFeature($key)` هر کلیدی را می‌خواند؛ پلن‌های موجود به‌صورت پیش‌فرض `insurance` ندارند (یعنی `false`) و ادمین آن را روی پلن دلخواه فعال می‌کند. پس **migration لازم نیست** و قرارداد API تغییر نمی‌کند → docs نیاز به‌روزرسانی ندارد.
- این محدودسازی فقط برای نقش‌هایی که `useSubscription` فعال دارد عمل می‌کند (`doctor` / `clinic` / `secretary`). برای `admin` و `representation` صفحات بیمه در منوی آن‌ها نیست؛ کاری لازم نیست.
- ترتیب hookها: FeatureGate نباید باعث شود hookهای صفحه به‌صورت شرطی صدا زده شوند. در `ClaimsPage` همه‌ی `useQuery`/`useMutation`/`useState` بالای `return` می‌مانند و فقط JSX خروجی wrap می‌شود.
- بعد از تغییرات: `ddev exec yarn dev` و `ddev exec npx tsc --noEmit --project tsconfig.json` برای چک تایپ.
- گاردهای نقش (`RoleRoute`) را دست نزن — درست‌اند؛ این پرامپت فقط لایه‌ی feature اشتراکی را روی دو صفحه‌ی بیمه اضافه می‌کند.
