fix(appointment): correct payment flow and account-info prefill
- Booking response is double-nested: read appointment uuid/expires_at from res.data.data so the payment countdown and gateway redirect actually fire. - Payment result page (/payment/[uuid]): unwrap res.data.data, use real backend fields (amount_rials, gateway, created_at, type) and statuses (pending/success/failed/canceled/refunded); the "pay" button now re-initiates via postAppointmentPayment instead of building a URL on the API origin. - Add /payment/result interstitial that reads payment_uuid from the gateway callback and forwards to /payment/[uuid]. - Prefill account info correctly in the booking form: name from profile.label, insurances from *_id, gender as string, national_code editable unless approved. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,127 @@
|
||||
# رفع جریان پرداخت و اطلاعات حساب در نوبتگیری آنلاین
|
||||
|
||||
## پروژه
|
||||
|
||||
`nobat724_front` (سایت عمومی).
|
||||
|
||||
> این مشکل **کاملاً frontend** است. بکاند `clinicpro` همهی endpointهای لازم را دارد و درست کار میکند: `POST /api/v1/appointment` (با `expires_at`)، `GET /api/v1/payment/config` (`test_mode`)، `POST /api/v1/payment/appointment` (`redirect_url` — در حالت تست از `MockGateway`)، `POST|GET /api/v1/payment/callback/{gateway}` (که نوبت را confirm و به `frontend_address` ریدایرکت میکند)، و `GET /api/v1/payment/{uuid}` (وضعیت پرداخت). نیازی به تغییر بکاند نیست. مرجع قرارداد: `clinicpro/docs/api/payment.md` و `docs/api/appointment.md`.
|
||||
|
||||
## زمینه
|
||||
|
||||
در فرایند نوبتگیری آنلاین (`/appointment/[doctorId]`) سه مشکل گزارش شده: (۱) اطلاعات حساب کاربری بهدرستی در فیلدها ست نمیشود، (۲) شمارندهی زمان پرداخت کار نمیکند، (۳) درگاه پرداخت تست کار نمیکند. ریشهی هر سه، **اشتباه در خواندن شکل پاسخ بکاند** در سمت frontend است — مخصوصاً پاسخهای double-nested بکاند.
|
||||
|
||||
یادآوری معماری پاسخ بکاند: `BaseController::success(['data' => X])` تولید میکند `{ success, data: { data: X } }`. interceptor در `services/api.js` یک بار `response.data` را برمیگرداند، پس مقدار واقعی در **`res.data.data`** است (نه `res.data`).
|
||||
|
||||
## مشکل / هدف
|
||||
|
||||
۱. **شمارنده + appointmentId**: پس از `POST /appointment`، فرانت `res.data.uuid` و `res.data.expires_at` را میخواند، اما چون پاسخ double-nested است اینها `undefined` میشوند → `appointmentId` خالی (پرداخت کار نمیکند) و `expiresAt` خالی (شمارنده روی مقدار ثابت `PAYMENT_TTL` میماند و واقعی نیست).
|
||||
۲. **درگاه تست**: درگاه تست خودِ بکاند است (`MockGateway`؛ وقتی `payment_test_mode=1`). فرانت باید: `redirect_url` بازگشتی از `POST /payment/appointment` را باز کند (که به callback بکاند میرود، نوبت را confirm میکند و به `frontend_address` با `?payment_uuid=...&status=...` برمیگردد). مشکل: `frontend_address` فعلی به `/payment/result` اشاره دارد که **route وجود ندارد**؛ صفحهی واقعی `/payment/[uuid]` است و callback `payment_uuid` را برمیگرداند.
|
||||
۳. **صفحهی نتیجهی پرداخت** (`/payment/[uuid]`): پاسخ `GET /payment/{uuid}` را بهاشتباه میخواند (`setPayment(response)` بهجای `response.data.data`) و statusها اشتباهاند (`completed`/`canceled` بهجای `success`/`failed`).
|
||||
۴. **اطلاعات حساب کاربری**: در `buildProfileData` کلیدها اصلاح شد (`label`→نام، `basic_insurance_id`، `gender` رشته، `national_code_approved`)؛ این وظیفه تثبیت/تأیید آن است.
|
||||
|
||||
## فایلهای مرتبط
|
||||
|
||||
| فایل | نقش |
|
||||
|------|-----|
|
||||
| `components/appointment/detail/SubmitData.js` | پس از `postAppointment`، `appointmentId`/`expiresAt` را ست میکند — **double-nest باگ** |
|
||||
| `components/appointment/paying/index.js` | شمارنده (`expiresAt` prop)، `getPaymentConfig`، `postAppointmentPayment` (`redirect_url`)، `frontend_address` |
|
||||
| `app/payment/[uuid]/page.js` | صفحهی نتیجهی پرداخت — مصرف `getPayment` با شکل اشتباه + statusهای اشتباه |
|
||||
| `services/response.js` | `getPayment`، `postAppointmentPayment`، `getPaymentConfig` (urlها درستاند) |
|
||||
| `components/appointment/index.js` | `buildProfileData` — اطلاعات حساب (وظیفه ۴، عمدتاً انجامشده) |
|
||||
|
||||
## وضعیت فعلی (کد واقعی)
|
||||
|
||||
### باگ ۱ — SubmitData: خواندن نتیجهی نوبت
|
||||
```js
|
||||
const res = await request.postAppointment(appointmentPayload);
|
||||
const appointmentUuid = res?.data?.uuid; // ❌ undefined — باید res.data.data.uuid
|
||||
if (appointmentUuid) {
|
||||
setAppointmentId(appointmentUuid);
|
||||
setAppointmentExpiresAt?.(res?.data?.expires_at ?? null); // ❌ undefined
|
||||
}
|
||||
```
|
||||
بکاند `POST /appointment` پاسخ میدهد: `{ success, data: { data: { uuid, slot_start, slot_end, expires_at, status, ... } } }`.
|
||||
|
||||
### باگ ۲ — paying: frontend_address و config
|
||||
```js
|
||||
const res = await request.postAppointmentPayment({
|
||||
appointment_uuid: appointmentId,
|
||||
gateway: testMode ? "mellat" : selectedBank,
|
||||
frontend_address: `${window.location.origin}/payment/result`, // ❌ route وجود ندارد
|
||||
});
|
||||
const redirectUrl = res?.data?.redirect_url; // ❌ باید res.data.data.redirect_url
|
||||
```
|
||||
- `getPaymentConfig` نیز: `res?.data?.test_mode` خوانده میشود ولی پاسخ `{ success, data: { test_mode } }` است (config با `success([...])` بدون nest اضافه ساخته شده؛ یعنی `res.data.test_mode` درست است — **این یکی را تأیید کن**، چون `config()` از `$this->success([...])` مستقیم استفاده میکند نه `['data'=>...]`).
|
||||
- callback بکاند به `frontend_address` با `?payment_uuid=<uuid>&status=<status>` برمیگردد.
|
||||
|
||||
### باگ ۳ — payment/[uuid]/page.js
|
||||
```js
|
||||
const response = await request.getPayment(params.uuid);
|
||||
setPayment(response); // ❌ باید response.data.data
|
||||
// ...
|
||||
const statusMap = { pending:..., completed:..., failed:..., canceled:... }; // ❌ بکاند: pending|success|failed|refunded
|
||||
```
|
||||
بکاند `GET /payment/{uuid}` → `{ success, data: { data: { uuid, order_id, amount_rials, status, gateway, type, reference_id, appointment_uuid, created_at } } }`. statusهای واقعی: `pending`, `success`, `failed`, `refunded`. مبلغ در `amount_rials` (ریال) است.
|
||||
|
||||
## وظایف
|
||||
|
||||
### ۱. رفع double-nest در SubmitData (شمارنده + appointmentId)
|
||||
در `components/appointment/detail/SubmitData.js`:
|
||||
```js
|
||||
const res = await request.postAppointment(appointmentPayload);
|
||||
const appt = res?.data?.data; // unwrap درست
|
||||
const appointmentUuid = appt?.uuid;
|
||||
if (appointmentUuid) {
|
||||
setAppointmentId(appointmentUuid);
|
||||
setAppointmentExpiresAt?.(appt?.expires_at ?? null);
|
||||
}
|
||||
```
|
||||
> نکته: `expires_at` بکاند Unix ثانیه است؛ `paying/index.js` همان را در `computeLeft` با `expiresAt * 1000` به میلیثانیه تبدیل میکند — درست است؛ فقط باید مقدار واقعی برسد.
|
||||
|
||||
### ۲. اصلاح frontend_address و redirect_url در paying
|
||||
در `components/appointment/paying/index.js`، تابع `handlePayment`:
|
||||
- `frontend_address` را به مسیر معتبری بده که نتیجه را نشان میدهد. چون callback `?payment_uuid=...&status=...` را به همان آدرس append میکند و صفحهی نتیجه `/payment/[uuid]` است، یک **route نتیجه** لازم است که `payment_uuid` را از query بخواند و کاربر را به نتیجه ببرد. دو گزینه:
|
||||
- **الف (ساده):** `frontend_address` را روی `${window.location.origin}/payment/result` بگذار و یک صفحهی سبک `app/payment/result/page.js` بساز که `payment_uuid` و `status` را از `searchParams` میخواند و به `/payment/${payment_uuid}` ریدایرکت (یا مستقیم وضعیت را نشان) میدهد. (پیشنهادی)
|
||||
- **ب:** اگر صفحهی `[uuid]` را نتیجهی نهایی میگیری، میتوان مستقیم آن را هدف frontend_address نکرد چون uuid را callback append نمیکند (فقط `payment_uuid`)؛ پس گزینه الف تمیزتر است.
|
||||
- `redirect_url` را از `res?.data?.data?.redirect_url` بخوان (double-nest):
|
||||
```js
|
||||
const res = await request.postAppointmentPayment({
|
||||
appointment_uuid: appointmentId,
|
||||
gateway: testMode ? "mellat" : selectedBank,
|
||||
frontend_address: `${window.location.origin}/payment/result`,
|
||||
});
|
||||
const redirectUrl = res?.data?.data?.redirect_url;
|
||||
if (redirectUrl) window.location.href = redirectUrl;
|
||||
```
|
||||
> در حالت تست، بکاند `MockGateway` یک `redirect_url` میدهد که مستقیم به callback بکاند میرود (`/api/v1/payment/callback/mock?...&mock=1&ResCode=0`) و خودِ بکاند نوبت را confirm و به `frontend_address` برمیگرداند. پس «درگاه تست» کاملاً سمت بکاند است و response واقعی میدهد — فرانت فقط `redirect_url` را باز میکند. **هیچ شبیهسازی پرداخت سمت فرانت اضافه نکن.**
|
||||
|
||||
### ۳. تأیید getPaymentConfig
|
||||
`config()` بکاند از `$this->success(['test_mode' => ...])` استفاده میکند → پاسخ `{ success, data: { test_mode } }`. پس `res?.data?.test_mode` در `paying/index.js` **درست** است. فقط تأیید کن این مقدار را درست میخواند و دکمه بر اساسش «پرداخت آزمایشی»/درگاه را نشان میدهد.
|
||||
|
||||
### ۴. اصلاح صفحهی نتیجه `app/payment/[uuid]/page.js`
|
||||
```js
|
||||
const response = await request.getPayment(params.uuid);
|
||||
setPayment(response?.data?.data ?? null); // unwrap درست
|
||||
```
|
||||
- statusها را با مقادیر واقعی بکاند هماهنگ کن: `pending` (در انتظار)، `success` (پرداخت موفق)، `failed` (ناموفق)، `refunded` (مسترد). برچسب/رنگ هر کدام.
|
||||
- مبلغ از `payment.amount_rials` است (ریال) — برای نمایش تومان `/10`.
|
||||
- روش پرداخت از `payment.gateway` (`mellat`/`sep`/`mock`).
|
||||
- تاریخ از `payment.created_at` (Unix ثانیه).
|
||||
|
||||
### ۵. صفحهی واسط نتیجه (اگر گزینه الف انتخاب شد)
|
||||
`app/payment/result/page.js` بساز:
|
||||
- `payment_uuid` و `status` را از `useSearchParams` بخوان.
|
||||
- اگر `payment_uuid` بود → `router.replace('/payment/' + payment_uuid)`؛ در غیر این صورت پیام خطا.
|
||||
- این صفحه فقط یک واسط ریدایرکت سبک است (با لودینگ).
|
||||
|
||||
### ۶. تثبیت اطلاعات حساب کاربری (انجامشده — تأیید)
|
||||
در `components/appointment/index.js` تابع `buildProfileData` قبلاً اصلاح شده: `name` از `profile.label`، `basic_insurance`/`supplementary_insurance` از `*_id` بهصورت `{id}`، `gender` رشتهی `profile.gender`، و `national_code.isEdit = !profile.national_code_approved`. تأیید کن این فیلدها در فرم (`detail/Form.js`) درست نمایش داده میشوند و در `SubmitData` درست ارسال میشوند (که سازگار است). اگر چیزی جا مانده اصلاح کن.
|
||||
|
||||
## نکات مهم
|
||||
|
||||
- **بکاند تغییر نمیکند.** همهی endpointها موجود و درستاند؛ فقط مصرف frontend اصلاح میشود.
|
||||
- پاسخهای `appointment` و `payment/{uuid}` و `payment/appointment` همگی **double-nested** اند (`res.data.data`)؛ ولی `payment/config` نیست (`res.data.test_mode`). به این تفاوت دقت کن.
|
||||
- شمارنده باید از `expires_at` واقعیِ بکاند (Unix ثانیه) تغذیه شود؛ منطق فعلی `computeLeft` درست است، فقط ورودیاش باید برسد.
|
||||
- پرداخت تست = درگاه تست بکاند (`MockGateway`)؛ فرانت فقط `redirect_url` را باز میکند و نتیجه را از callback/صفحهی نتیجه میگیرد. شبیهسازی فرانت ممنوع.
|
||||
- App Router؛ صفحهی نتیجه `"use client"` (به `useSearchParams`/`useParams` نیاز دارد). RTL، فونت Vazir، MUI v5.
|
||||
- بعد از تغییر: `npm run build` بدون خطا؛ جریان را end-to-end تست کن (نوبت → شمارنده فعال → پرداخت آزمایشی → callback → صفحهی نتیجه با وضعیت `success`).
|
||||
+38
-33
@@ -12,6 +12,27 @@ export default function PaymentDetailsPage() {
|
||||
const [payment, setPayment] = useState(null);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [error, setError] = useState(null);
|
||||
const [paying, setPaying] = useState(false);
|
||||
|
||||
const handleRetryPayment = async () => {
|
||||
if (!payment?.appointment_uuid) return;
|
||||
setPaying(true);
|
||||
try {
|
||||
const res = await request.postAppointmentPayment({
|
||||
appointment_uuid: payment.appointment_uuid,
|
||||
gateway: payment.gateway || "mellat",
|
||||
frontend_address: `${window.location.origin}/payment/result`,
|
||||
});
|
||||
const redirectUrl = res?.data?.redirect_url;
|
||||
if (redirectUrl) {
|
||||
window.location.href = redirectUrl;
|
||||
} else {
|
||||
setPaying(false);
|
||||
}
|
||||
} catch {
|
||||
setPaying(false);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
// بررسی لاگین بودن کاربر
|
||||
@@ -25,7 +46,7 @@ export default function PaymentDetailsPage() {
|
||||
try {
|
||||
setLoading(true);
|
||||
const response = await request.getPayment(params.uuid);
|
||||
setPayment(response);
|
||||
setPayment(response?.data?.data ?? null);
|
||||
} catch (err) {
|
||||
setError("خطا در دریافت اطلاعات پرداخت");
|
||||
console.error("Payment fetch error:", err);
|
||||
@@ -42,9 +63,9 @@ export default function PaymentDetailsPage() {
|
||||
const getStatusLabel = (status) => {
|
||||
const statusMap = {
|
||||
pending: "در انتظار پرداخت",
|
||||
completed: "پرداخت موفق",
|
||||
success: "پرداخت موفق",
|
||||
failed: "پرداخت ناموفق",
|
||||
canceled: "لغو شده",
|
||||
refunded: "مسترد شده",
|
||||
};
|
||||
return statusMap[status] || status;
|
||||
};
|
||||
@@ -52,9 +73,9 @@ export default function PaymentDetailsPage() {
|
||||
const getStatusColor = (status) => {
|
||||
const colorMap = {
|
||||
pending: "text-yellow-600 bg-yellow-50",
|
||||
completed: "text-green-600 bg-green-50",
|
||||
success: "text-green-600 bg-green-50",
|
||||
failed: "text-red-600 bg-red-50",
|
||||
canceled: "text-gray-600 bg-gray-50",
|
||||
refunded: "text-gray-600 bg-gray-50",
|
||||
};
|
||||
return colorMap[status] || "text-gray-600 bg-gray-50";
|
||||
};
|
||||
@@ -62,7 +83,8 @@ export default function PaymentDetailsPage() {
|
||||
const getPaymentMethodLabel = (method) => {
|
||||
const methodMap = {
|
||||
mellat: "بانک ملت",
|
||||
saman: "سامان کیش",
|
||||
sep: "سامان (سپ)",
|
||||
mock: "درگاه آزمایشی",
|
||||
};
|
||||
return methodMap[method] || method;
|
||||
};
|
||||
@@ -78,8 +100,8 @@ export default function PaymentDetailsPage() {
|
||||
}).format(date);
|
||||
};
|
||||
|
||||
const formatAmount = (amount) => {
|
||||
return new Intl.NumberFormat("fa-IR").format(parseInt(amount));
|
||||
const formatAmount = (rials) => {
|
||||
return new Intl.NumberFormat("fa-IR").format(Math.round(parseInt(rials) / 10));
|
||||
};
|
||||
|
||||
if (loading) {
|
||||
@@ -136,7 +158,7 @@ export default function PaymentDetailsPage() {
|
||||
<div className="flex justify-between items-center py-3 border-b border-gray-100">
|
||||
<span className="text-[#616161] font-medium">مبلغ:</span>
|
||||
<span className="text-[#3B3B3B] font-bold text-lg">
|
||||
{formatAmount(payment.amount)} تومان
|
||||
{formatAmount(payment.amount_rials)} تومان
|
||||
</span>
|
||||
</div>
|
||||
|
||||
@@ -144,7 +166,7 @@ export default function PaymentDetailsPage() {
|
||||
<div className="flex justify-between items-center py-3 border-b border-gray-100">
|
||||
<span className="text-[#616161] font-medium">روش پرداخت:</span>
|
||||
<span className="text-[#3B3B3B] font-bold">
|
||||
{getPaymentMethodLabel(payment.payment_method)}
|
||||
{getPaymentMethodLabel(payment.gateway)}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
@@ -170,17 +192,7 @@ export default function PaymentDetailsPage() {
|
||||
<div className="flex justify-between items-center py-3 border-b border-gray-100">
|
||||
<span className="text-[#616161] font-medium">تاریخ ایجاد:</span>
|
||||
<span className="text-[#3B3B3B]">
|
||||
{formatDate(payment.created)}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{/* تاریخ آخرین تغییر */}
|
||||
<div className="flex justify-between items-center py-3 border-b border-gray-100">
|
||||
<span className="text-[#616161] font-medium">
|
||||
آخرین بروزرسانی:
|
||||
</span>
|
||||
<span className="text-[#3B3B3B]">
|
||||
{formatDate(payment.changed)}
|
||||
{formatDate(payment.created_at)}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
@@ -188,7 +200,7 @@ export default function PaymentDetailsPage() {
|
||||
<div className="flex justify-between items-center py-3">
|
||||
<span className="text-[#616161] font-medium">نوع سرویس:</span>
|
||||
<span className="text-[#3B3B3B] font-bold">
|
||||
{payment.bundle === "appointment" ? "رزرو نوبت" : payment.bundle}
|
||||
{payment.type === "appointment" ? "رزرو نوبت" : payment.type}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -198,18 +210,11 @@ export default function PaymentDetailsPage() {
|
||||
{payment.status === "pending" ? (
|
||||
<>
|
||||
<button
|
||||
onClick={() => {
|
||||
try {
|
||||
const apiOrigin = new URL(process.env.NEXT_PUBLIC_API_URL).origin;
|
||||
const paymentUrl = new URL(`/payment/${payment.uuid}`, apiOrigin);
|
||||
if (paymentUrl.origin === apiOrigin) {
|
||||
window.location.href = paymentUrl.href;
|
||||
}
|
||||
} catch {}
|
||||
}}
|
||||
className="flex-1 bg-[#5559CE] hover:bg-[#4448b3] text-white font-bold py-3 px-6 rounded-lg transition-colors"
|
||||
onClick={handleRetryPayment}
|
||||
disabled={paying || !payment.appointment_uuid}
|
||||
className="flex-1 bg-[#5559CE] hover:bg-[#4448b3] disabled:opacity-60 text-white font-bold py-3 px-6 rounded-lg transition-colors"
|
||||
>
|
||||
پرداخت
|
||||
{paying ? "در حال انتقال به درگاه..." : "پرداخت"}
|
||||
</button>
|
||||
<button
|
||||
onClick={() => window.location.reload()}
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
"use client";
|
||||
|
||||
import { Suspense, useEffect } from "react";
|
||||
import { useRouter, useSearchParams } from "next/navigation";
|
||||
import Layout from "@/components/layout";
|
||||
|
||||
function PaymentResultRedirect() {
|
||||
const router = useRouter();
|
||||
const searchParams = useSearchParams();
|
||||
|
||||
useEffect(() => {
|
||||
const paymentUuid = searchParams.get("payment_uuid");
|
||||
if (paymentUuid) {
|
||||
router.replace(`/payment/${paymentUuid}`);
|
||||
} else {
|
||||
router.replace("/dashboard?sidebar=2");
|
||||
}
|
||||
}, [searchParams, router]);
|
||||
|
||||
return (
|
||||
<div className="flex items-center justify-center min-h-screen">
|
||||
<div className="flex flex-col items-center gap-4">
|
||||
<div className="w-12 h-12 border-4 border-[#5559CE] border-t-transparent rounded-full animate-spin"></div>
|
||||
<p className="text-[#3B3B3B] text-[16px]">در حال انتقال به نتیجهی پرداخت...</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default function PaymentResultPage() {
|
||||
return (
|
||||
<Layout>
|
||||
<Suspense fallback={null}>
|
||||
<PaymentResultRedirect />
|
||||
</Suspense>
|
||||
</Layout>
|
||||
);
|
||||
}
|
||||
@@ -125,10 +125,11 @@ function SubmitData({ setStep, data, prevData, setErrors, doctor, isForAnother,
|
||||
};
|
||||
|
||||
const res = await request.postAppointment(appointmentPayload);
|
||||
const appointmentUuid = res?.data?.uuid;
|
||||
const appointment = res?.data?.data;
|
||||
const appointmentUuid = appointment?.uuid;
|
||||
if (appointmentUuid) {
|
||||
setAppointmentId(appointmentUuid);
|
||||
setAppointmentExpiresAt?.(res?.data?.expires_at ?? null);
|
||||
setAppointmentExpiresAt?.(appointment?.expires_at ?? null);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -23,19 +23,22 @@ function buildProfileData(profile, phone) {
|
||||
phone: { value: phone, isEdit: false },
|
||||
national_code: {
|
||||
value: profile.national_code || "",
|
||||
isEdit: profile.national_code ? false : true,
|
||||
isEdit: !profile.national_code_approved,
|
||||
},
|
||||
name: { value: profile.name || "", isEdit: true },
|
||||
name: { value: profile.label || "", isEdit: true },
|
||||
family: { value: profile.family || "", isEdit: true },
|
||||
gender: {
|
||||
value: profile.gender
|
||||
? { id: profile.gender, title: profile.gender === "male" ? "مرد" : "زن" }
|
||||
gender: { value: profile.gender || "", isEdit: true },
|
||||
insurance_id: { value: profile.insurance_id || "", isEdit: true },
|
||||
basic_insurance: {
|
||||
value: profile.basic_insurance_id ? { id: profile.basic_insurance_id } : "",
|
||||
isEdit: true,
|
||||
},
|
||||
supplementary_insurance: {
|
||||
value: profile.supplementary_insurance_id
|
||||
? { id: profile.supplementary_insurance_id }
|
||||
: "",
|
||||
isEdit: true,
|
||||
},
|
||||
insurance_id: { value: profile.insurance_id || "", isEdit: true },
|
||||
basic_insurance: { value: profile.basic_insurance, isEdit: true },
|
||||
supplementary_insurance: { value: profile.supplementary_insurance, isEdit: true },
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user