Files
clinicpro/.claude/prompt/payment-test-mode-ui.md
T

178 lines
7.8 KiB
Markdown
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.
# نمایش درگاه تست در رابط کاربری هنگام فعال بودن حالت آزمایشی
## زمینه
سیستم پرداخت یک حالت آزمایشی (`payment_test_mode`) دارد که در `SiteConfig` ذخیره می‌شود. وقتی این حالت فعال است، backend در `resolveGateway()` (هر دو `PaymentController` و `SmsWalletController`) بجای درگاه واقعی، درگاه `MockGateway` را به‌کار می‌برد و پول واقعی کسر نمی‌شود.
**مشکل:** Frontend هیچ اطلاعی از حالت تست ندارد. کاربر در `SmsWalletPage` و `SubscriptionPage` انتخاب درگاه می‌بیند (ملت / سپ)، حتی وقتی backend همه را به Mock هدایت می‌کند. این گیج‌کننده است.
**هدف:** وقتی `payment_test_mode = '1'` است:
- انتخاب‌کننده درگاه واقعی پنهان شود
- بجای آن یک نوار زرد/نارنجی نمایش داده شود: «درگاه آزمایشی فعال است — پول واقعی کسر نخواهد شد»
---
## مشکل / هدف
دو صفحه frontend نیاز به تغییر دارند:
1. `SmsWalletPage.tsx` — modal شارژ کیف پول پیامک
2. `SubscriptionPage.tsx` — modal خرید اشتراک
همچنین یک endpoint عمومی (برای همه کاربران احراز هویت شده) باید ساخته شود چون `GET /api/v1/admin/settings` فقط برای `ROLE_ADMIN` است.
---
## فایل‌های مرتبط
| فایل | نقش |
|------|-----|
| `src/Config/Controller/SiteConfigController.php` | endpoint تنظیمات — فعلاً فقط ROLE_ADMIN |
| `src/Config/Repository/SiteConfigRepository.php` | خواندن `payment_test_mode` |
| `src/Payment/Controller/PaymentController.php` | `resolveGateway()` — backend قبلاً درست است |
| `assets/admin/pages/SmsWalletPage.tsx` | modal شارژ — نمایش‌دهنده انتخاب‌کننده درگاه |
| `assets/admin/pages/SubscriptionPage.tsx` | modal اشتراک — نمایش‌دهنده انتخاب‌کننده درگاه |
---
## وضعیت فعلی
### Backend — endpoint تنظیمات فقط ادمین است
```php
// src/Config/Controller/SiteConfigController.php
#[IsGranted('ROLE_ADMIN')]
class SiteConfigController extends BaseController
{
#[Route('/api/v1/admin/settings', methods: ['GET'])]
public function get(): JsonResponse
{
return $this->success($this->configRepo->getAll());
}
}
```
### Frontend — SmsWalletPage modal (خط ۳۴۸–۳۷۳)
```tsx
// همیشه دو گزینه mellat و sep نمایش می‌دهد
{(['mellat', 'sep'] as const).map((gw) => (
<div key={gw} onClick={() => setGateway(gw)} ...>
<div>{gw === 'mellat' ? 'ملت' : 'سپ'}</div>
...
</div>
))}
```
### Frontend — SubscriptionPage modal (خط ۳۰۷–۳۲۷)
```tsx
// همیشه دو گزینه mellat و sep نمایش می‌دهد
{(['mellat', 'sep'] as const).map((gw) => (
<button key={gw} onClick={() => setSelectedGateway(gw)} ...>
<CreditCardIcon ... />
{GATEWAY_LABELS[gw]}
</button>
))}
```
---
## وظایف
### ۱. Backend — endpoint عمومی `GET /api/v1/payment/config`
در `src/Payment/Controller/PaymentController.php` یک متد جدید اضافه کن:
```php
#[Route('/api/v1/payment/config', methods: ['GET'])]
public function config(): JsonResponse
{
return $this->success([
'test_mode' => $this->configRepo->get('payment_test_mode') === '1',
]);
}
```
- **Permission:** `IS_AUTHENTICATED_FULLY` (کلاس `PaymentController` قبلاً این را دارد)
- **مهم:** هرگز credential های درگاه (terminal_id، password، ...) را expose نکن
- پاسخ فقط یک boolean کافی است
- مستندات را در `docs/api/payment.md` اضافه کن
### ۲. Frontend — hook برای خواندن حالت تست
در `assets/admin/pages/SmsWalletPage.tsx` و `assets/admin/pages/SubscriptionPage.tsx`، یک `useQuery` برای خواندن config اضافه کن:
```tsx
const { data: paymentConfigData } = useQuery<ApiResponse<{ test_mode: boolean }>>({
queryKey: ['payment-config'],
queryFn: () => api.get('/api/v1/payment/config'),
staleTime: 5 * 60 * 1000, // 5 دقیقه cache
});
const isTestMode = paymentConfigData?.data?.test_mode ?? false;
```
### ۳. Frontend — SmsWalletPage: پنهان کردن انتخاب‌کننده درگاه در حالت تست
در modal شارژ (`SmsWalletPage.tsx`)، قسمت «انتخاب درگاه پرداخت» را با شرط جایگزین کن:
```tsx
{isTestMode ? (
<div style={{
background: '#fef9c3',
border: '1px solid #fbbf24',
borderRadius: 10,
padding: '12px 16px',
display: 'flex', alignItems: 'center', gap: 10,
}}>
<span style={{ fontSize: 18 }}>⚠️</span>
<div>
<div style={{ fontWeight: 700, fontSize: 13.5, color: '#92400e' }}>
درگاه آزمایشی فعال است
</div>
<div style={{ fontSize: 12, color: '#b45309', marginTop: 2 }}>
پول واقعی کسر نخواهد شد این تراکنش آزمایشی است
</div>
</div>
</div>
) : (
// کد فعلی انتخاب درگاه (mellat / sep)
<div>...</div>
)}
```
همچنین در mutation، وقتی `isTestMode` است، مقدار `gateway` را به `'mock'` تنظیم کن (یا هر رشته‌ای — backend به هر حال Mock را استفاده می‌کند، ولی باید یک مقدار ارسال کنیم).
### ۴. Frontend — SubscriptionPage: پنهان کردن انتخاب‌کننده درگاه در حالت تست
همان pattern را در `SubscriptionPage.tsx` در قسمت «انتخاب درگاه پرداخت» داخل modal اعمال کن.
همچنین در دکمه پرداخت زیر modal، متن را در حالت تست تغییر بده:
```tsx
{isTestMode
? `پرداخت آزمایشی ${formatRial(purchaseTarget.period.price_rials)}`
: `پرداخت ${formatRial(purchaseTarget.period.price_rials)}`
}
```
---
## نکات مهم
- **Backend قبلاً درست است:** `resolveGateway()` در هر دو `PaymentController` و `SmsWalletController` حالت تست را بررسی می‌کند. فقط UI نیاز به تغییر دارد.
- **Security:** endpoint جدید فقط یک boolean برمی‌گرداند — هیچ اطلاعات حساسی expose نمی‌شود.
- **قرارداد API:** پاسخ باید `{ success: true, data: { test_mode: boolean } }` باشد. در frontend: `data?.data?.test_mode`.
- **در حالت تست:** state انتخاب درگاه (`gateway` / `selectedGateway`) بی‌تأثیر است چون backend آن را نادیده می‌گیرد — ولی باید یک مقدار ارسال شود (از مقدار default `'mellat'` استفاده کن).
- **Stale time:** این تنظیم خیلی نادر تغییر می‌کند، 5 دقیقه staleTime کافی است.
- **Routing ترتیب:** مطمئن شو route `/api/v1/payment/config` قبل از `/api/v1/payment/{uuid}` تعریف شده تا با UUID conflict نکند. در Symfony اگر method‌ها مختلف است مشکلی نیست ولی اگر هر دو GET هستند، route خاص‌تر باید اول باشد.
---
## ترتیب اجرا
1. Backend: اضافه کردن `config()` به `PaymentController`
2. تست route: `ddev exec php bin/console debug:router | grep payment`
3. Cache: `ddev exec php bin/console cache:clear`
4. Frontend: `SmsWalletPage.tsx` — اضافه کردن query و شرط حالت تست
5. Frontend: `SubscriptionPage.tsx` — همان تغییر
6. Build: `ddev exec yarn dev`
7. TypeScript check: `ddev exec npx tsc --noEmit --project tsconfig.json 2>&1 | head -20`
8. مستندات: `docs/api/payment.md`