fix(appointment): align request layer with real backend contract
- getAppointmentSlots uses doctor_uuid + date (was doctor_id, which the backend rejects with دکتر یافت نشد). - postAppointmentPayment posts to /api/v1/payment/appointment (was the nonexistent /api/v1/payment). - Remove getAppointmentNotAvailable: the not-available route does not exist (404); disabled dates come from the slots response. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,288 @@
|
||||
# بازنویسی صفحهی گرفتن نوبت (`/appointment/[doctorId]`) برای همخوانی با API واقعی
|
||||
|
||||
## پروژه
|
||||
|
||||
`nobat724_front` — سایت عمومی نوبتدهی. این کار **صرفاً frontend** است؛ backend (`clinicpro`) کامل و درست است و **تغییر نمیکند**. مشکل این است که کل فلوی نوبتگیری روی یک قرارداد API **خیالی/قدیمی** نوشته شده که با endpointهای واقعی `clinicpro` همخوان نیست. همهی endpointهای لازم از قبل در `clinicpro/docs/api/appointment.md` و `clinicpro/docs/api/payment.md` مستند و آمادهاند.
|
||||
|
||||
## زمینه
|
||||
|
||||
صفحهی `/appointment/[doctorId]` یک wizard چندمرحلهای است:
|
||||
|
||||
```
|
||||
step 0: انتخاب تاریخ + ساعت (Date) → step 1/2: لاگین OTP → step 3: تکمیل اطلاعات (Detail) → step 4: پرداخت (Paying) → step 5/6: success/failed
|
||||
```
|
||||
|
||||
این فلو در ظاهر کامل است ولی عملاً کار نمیکند چون **هر چهار فراخوانی اصلی API (اسلاتها، رزرو، پروفایل، پرداخت) با قرارداد واقعی backend مغایرت دارند** و علاوه بر آن صفحه از یک endpoint که اصلاً وجود ندارد (`appointment/not-available/{id}`) استفاده میکند.
|
||||
|
||||
## مشکل / هدف
|
||||
|
||||
صفحهی نوبتگیری را به API واقعی وصل کن: استخراج درست پاسخها، پارامترها و بدنههای درست، و مپکردن ساختار واقعی اسلات (`sessions[].slots[]`) به UI موجود. هدف این است که یک کاربر واقعی بتواند تاریخ/ساعت را ببیند، اسلات انتخاب کند، نوبت رزرو کند و به درگاه پرداخت برود.
|
||||
|
||||
این کار باید **مرحلهبهمرحله** انجام شود (یک قابلیت در هر مرحله: پیادهسازی → build → تأیید → commit).
|
||||
|
||||
## قرارداد واقعی Backend (تأییدشده با curl روی `https://clinic-pro.ddev.site`)
|
||||
|
||||
### ۱. اسلاتها — `GET /api/v1/appointment-slots?doctor_uuid={uuid}&date={Y-m-d}` (PUBLIC)
|
||||
|
||||
- پارامتر `doctor_uuid` (UUID) است، **نه** `doctor_id`. فراخوانی با `doctor_id` خطای `ERR_VALIDATION_002` («دکتر یافت نشد») میدهد.
|
||||
- پاسخ:
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"data": {
|
||||
"doctor_uuid": "...",
|
||||
"date": "2026-06-20",
|
||||
"sessions": [
|
||||
{
|
||||
"start_time": "09:00",
|
||||
"end_time": "13:00",
|
||||
"slots": [
|
||||
{ "start": 1781933400, "end": 1781934600, "start_time": "09:00", "end_time": "09:20", "location_id": 2581, "is_available": true }
|
||||
]
|
||||
},
|
||||
{ "start_time": "15:00", "end_time": "17:00", "slots": [ ... ] }
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
> هیچ کلید `morning`/`evening`/`hours_morning`/`hours_afternoon` وجود ندارد. اسلات کلید `time`/`status` ندارد؛ بهجایش `start_time` (رشتهی HH:MM)، `is_available` (boolean)، و `start`/`end` (Unix timestamp) دارد. شیفتها در آرایهی `sessions` هستند (نه دو دستهی ثابت صبح/عصر).
|
||||
|
||||
### ۲. رزرو نوبت — `POST /api/v1/appointment` (AUTH)
|
||||
|
||||
بدنه:
|
||||
|
||||
```json
|
||||
{ "doctor_uuid": "...", "slot_start": 1781933400, "slot_end": 1781934600, "note": "" }
|
||||
```
|
||||
|
||||
- `doctor_uuid` (نه `doctor_id`)، `slot_start`/`slot_end` بهصورت Unix timestamp (همان `start`/`end` اسلات)، `note` اختیاری (نه `info`، نه شیء `slot`).
|
||||
- پاسخ `201`: `{ success, data: { uuid, status: "pending", price, ... } }` — شناسهی نوبت `data.uuid` است (UUID)، **نه** `data.id`.
|
||||
|
||||
### ۳. پرداخت — `POST /api/v1/payment/appointment` (AUTH، باید مالک نوبت باشد)
|
||||
|
||||
بدنه:
|
||||
|
||||
```json
|
||||
{ "appointment_uuid": "...", "gateway": "mellat", "frontend_address": "https://.../payment/result" }
|
||||
```
|
||||
|
||||
- مسیر `payment/appointment` است، **نه** `payment`. `gateway` فقط `"mellat"` یا `"sep"`. فیلدهای `payment_method`/`bundle`/`entity_reference_id` وجود ندارند.
|
||||
- پاسخ `200`: `{ success, data: { payment_uuid, redirect_url, order_id } }` — برای ریدایرکت از `data.redirect_url` استفاده کن (نه ساختن دستی URL).
|
||||
|
||||
### ۴. پروفایل کاربر — `GET /api/v1/user-profile/{uuid}` (AUTH)
|
||||
|
||||
پاسخ `{ success, data: {...} }`.
|
||||
|
||||
### ۵. interceptor مهم (`services/api.js`)
|
||||
|
||||
```js
|
||||
api.interceptors.response.use((response) => response.data, ...)
|
||||
```
|
||||
|
||||
همهی `request.*` **یکبار** پاسخ را باز میکنند و **بدنهی HTTP** (`{ success, data }`) را برمیگردانند. پس دادهی واقعی همیشه در `result.data` است. (نکته: تابع server-side `fetchReq` در `lib/req.js` هم `response.data` را برمیگرداند؛ ولی صفحهی نوبت با `axiosInstance.get(...)` مستقیم کار میکند که باز نمیکند → آنجا `.data` لازم است.)
|
||||
|
||||
> هشدار double-nesting: پاسخ `GET /api/v1/doctor/{uuid}` سهلایه است (`{ success, data: { data: {...} } }`). در `axiosInstance` خام یعنی `res.data.data.data`. (این الگو قبلاً در `app/doctor/[slug]/page.js` با `res.data?.data?.data` رفع شده — همانجا را مرجع بگیر.)
|
||||
|
||||
## فایلهای مرتبط
|
||||
|
||||
| فایل | نقش | مشکل |
|
||||
|------|-----|------|
|
||||
| `app/appointment/[doctorId]/page.js` | server: doctor + disabledDates | `doctor = doctorRes.data` (باید `?.data?.data`)؛ فراخوانی endpoint ناموجود `appointment/not-available/{id}` |
|
||||
| `services/response.js` | لایهی `request.*` | `getAppointment` با `doctor_id`؛ `postAppointment`/`postPayment`/`getPayment` با مسیر/بدنهی غلط؛ `getAppointmentNotAvailable` به route ناموجود |
|
||||
| `app/component/date/dateTime/index.js` | fetch اسلاتها + آدرس | `getAppointment(doctor.id, date)`؛ خواندن `res.morning`/`res.evening`؛ `res.address` |
|
||||
| `app/component/date/dateTime/hours/List.js` | grid اسلاتها | `appo[value ? "evening" : "morning"]`، `item.time`، `item.status` — هیچکدام در API نیست |
|
||||
| `app/component/date/dateTime/SendAppo.js` | دکمهی «تایید نوبت» | فقط `setSelectedSlot(hour)` — وابسته به شکل `hour` |
|
||||
| `components/appointment/Content.js` (در `components/appointment/index.js`) | fetch پروفایل کاربر | خواندن `res.uuid`/`res.name` (باید `res.data.*`) |
|
||||
| `components/appointment/detail/SubmitData.js` | PATCH/POST پروفایل + POST نوبت | بدنهی نوبت غلط؛ خواندن `appointmentResponse.id` (باید `data.uuid`) |
|
||||
| `components/appointment/paying/index.js` | POST پرداخت + ریدایرکت | بدنه/مسیر غلط؛ خواندن `response.uuid`؛ ساختن دستی URL درگاه |
|
||||
| `clinicpro/docs/api/appointment.md` | قرارداد اسلات/رزرو | مرجع — تغییر نمیکند |
|
||||
| `clinicpro/docs/api/payment.md` | قرارداد پرداخت | مرجع — تغییر نمیکند |
|
||||
|
||||
## وضعیت فعلی (کد واقعی مشکلدار)
|
||||
|
||||
### `app/appointment/[doctorId]/page.js`
|
||||
|
||||
```js
|
||||
const doctorRes = await axiosInstance.get(`${API_URL}/api/v1/doctor/${doctorId}`);
|
||||
doctor = doctorRes.data; // ❌ باید doctorRes.data?.data?.data
|
||||
|
||||
if (doctor && doctor.id) { // ❌ doctor.id همیشه undefined
|
||||
const disabledDatesRes = await axiosInstance.get(
|
||||
`${API_URL}/api/v1/appointment/not-available/${doctor.id}` // ❌ route وجود ندارد (404)
|
||||
);
|
||||
disabledDates = disabledDatesRes.data?.data || [];
|
||||
}
|
||||
```
|
||||
|
||||
### `services/response.js`
|
||||
|
||||
```js
|
||||
getAppointmentNotAvailable: (doctor_id) =>
|
||||
api.get(`api/v1/appointment/not-available/${doctor_id}`, removeTokenHead), // ❌ route ناموجود
|
||||
getAppointment: (doctor_id, date) =>
|
||||
api.get(`api/v1/appointment-slots?date=${date}&doctor_id=${doctor_id}`, removeTokenHead), // ❌ doctor_id
|
||||
postAppointment: (data) => api.post(`api/v1/appointment`, data, { requireAuth: true }),
|
||||
postPayment: (data) => api.post(`api/v1/payment`, data, { requireAuth: true }), // ❌ مسیر payment/appointment
|
||||
getPayment: (uuid) => api.get(`api/v1/payment/${uuid}`, { requireAuth: true }),
|
||||
```
|
||||
|
||||
### `app/component/date/dateTime/index.js`
|
||||
|
||||
```js
|
||||
request.getAppointment(doctor.id, date).then((res) => {
|
||||
setAppo(res); // ❌ res، نه res.data
|
||||
const hasAvailableMorning = res.morning?.some(s => s.status === "available"); // ❌ morning/status نیست
|
||||
const hasAvailableEvening = res.evening?.some(s => s.status === "available");
|
||||
...
|
||||
});
|
||||
// آدرس:
|
||||
request.getDoctorAddress(hour.location_id).then((res) => setLocationAddress(res.address)); // ❌ res.data.address
|
||||
```
|
||||
|
||||
### `app/component/date/dateTime/hours/List.js`
|
||||
|
||||
```js
|
||||
const list = appo && appo[value ? "evening" : "morning"]; // ❌ کلید وجود ندارد
|
||||
// ...
|
||||
disabled={item.status !== "available"} // ❌ is_available
|
||||
{item.time} // ❌ start_time
|
||||
```
|
||||
|
||||
### `components/appointment/detail/SubmitData.js`
|
||||
|
||||
```js
|
||||
const appointmentPayload = {
|
||||
doctor_id: doctor.id, // ❌ doctor_uuid
|
||||
slot: { // ❌ backend شیء slot نمیخواهد
|
||||
time: selectedSlot.time, status: selectedSlot.status,
|
||||
start_time_timestamp: selectedSlot.start_time_timestamp,
|
||||
end_time_timestamp: selectedSlot.end_time_timestamp,
|
||||
duration_per_patient: selectedSlot.duration_per_patient,
|
||||
location_id: selectedSlot.location_id
|
||||
},
|
||||
info: "" // ❌ note
|
||||
};
|
||||
const appointmentResponse = await request.postAppointment(appointmentPayload);
|
||||
if (appointmentResponse?.id) setAppointmentId(appointmentResponse.id); // ❌ data.uuid
|
||||
```
|
||||
|
||||
### `components/appointment/paying/index.js`
|
||||
|
||||
```js
|
||||
const paymentPayload = {
|
||||
payment_method: selectedBank, // ❌ gateway
|
||||
bundle: "appointment", // ❌ حذف
|
||||
entity_reference_id: appointmentId // ❌ appointment_uuid
|
||||
};
|
||||
const response = await request.postPayment(paymentPayload);
|
||||
if (response?.uuid) { // ❌ data.redirect_url
|
||||
const paymentUrl = `${process.env.NEXT_PUBLIC_API_URL}/payment/${response.uuid}`; // ❌ از redirect_url استفاده کن
|
||||
window.location.href = paymentUrl;
|
||||
}
|
||||
```
|
||||
|
||||
### `components/appointment/index.js` (خواندن پروفایل)
|
||||
|
||||
```js
|
||||
const res = await request.getUserProfile(parsedData.uuid);
|
||||
if (res) {
|
||||
const newData = { uuid: res.uuid, ... national_code: { value: res.national_code ... } }; // ❌ res.data.*
|
||||
}
|
||||
```
|
||||
|
||||
## وظایف
|
||||
|
||||
اجرای مرحلهبهمرحله؛ بعد از هر قابلیت `npm run build` و سپس commit جدا.
|
||||
|
||||
### ۱. اصلاح لایهی `request.*` در `services/response.js`
|
||||
|
||||
- `getAppointment` را با `doctor_uuid` بازنویسی کن (صفحه با `[doctorId]` کار میکند که همان uuid است):
|
||||
|
||||
```js
|
||||
getAppointmentSlots: (doctor_uuid, date) =>
|
||||
api.get(`api/v1/appointment-slots?doctor_uuid=${doctor_uuid}&date=${date}`, removeTokenHead),
|
||||
```
|
||||
|
||||
- `postAppointment` بدنهاش از caller میآید (در وظیفه ۴ اصلاح میشود) — تغییری در امضای تابع لازم نیست.
|
||||
- پرداخت را به مسیر و نام درست ببر:
|
||||
|
||||
```js
|
||||
postAppointmentPayment: (data) =>
|
||||
api.post(`api/v1/payment/appointment`, data, { requireAuth: true }),
|
||||
```
|
||||
|
||||
- `getAppointmentNotAvailable` و تابع/route ناموجود `not-available` را حذف کن (در وظیفه ۲ مصرفش هم حذف میشود).
|
||||
- اسمهای قدیمی (`getAppointment`, `postPayment`) را اگر جای دیگری مصرف نمیشوند حذف کن؛ اگر مصرف میشوند، همهی callerها را به نسخهی جدید مهاجرت بده. (با grep بررسی کن.)
|
||||
|
||||
### ۲. اصلاح `app/appointment/[doctorId]/page.js`
|
||||
|
||||
- استخراج درست doctor: `doctor = doctorRes.data?.data?.data;`
|
||||
- منطق `disabledDates` و فراخوانی `appointment/not-available/{id}` را **حذف کن** (route وجود ندارد). prop `disabledDates` را یا حذف کن یا `[]` بفرست تا کامپوننتهای پاییندستی نشکنند. تاریخهای غیرفعال در همان پاسخ `appointment-slots` (نبودِ session/اسلات available) منعکس میشود؛ منطق غیرفعالسازی روز را به آن واگذار کن.
|
||||
- `disabledDates` در `Time`/`SelectDatePicker` مصرف میشود — بررسی کن با آرایهی خالی رفتار درستی دارد (همهی روزها قابلانتخاب) و crash نمیکند.
|
||||
|
||||
### ۳. مپکردن ساختار واقعی اسلات به UI — `dateTime/index.js` + `hours/List.js`
|
||||
|
||||
- در `dateTime/index.js`: `request.getAppointmentSlots(doctor.uuid, date)` را صدا بزن (نه `doctor.id`؛ پس از وظیفه ۲، `doctor` شیء واقعی است و `uuid` دارد).
|
||||
- پاسخ در `res.data` است (interceptor). یک adapter بنویس که `data.sessions[]` را به ساختاری که UI میخواهد تبدیل کند. **توهمسازی صبح/عصر نکن**؛ یا مستقیم روی `sessions` رندر کن، یا اگر میخواهی UI تبدار صبح/عصر را نگه داری، sessionها را بر اساس `start_time < "12:00"` به صبح/عصر تقسیم کن و این تصمیم را در adapter مستندِ کوچک بگذار.
|
||||
- در `List.js`: بهجای `item.time` از `item.start_time`، بهجای `item.status !== "available"` از `!item.is_available`، و بهجای کلید `morning`/`evening` از خروجی adapter استفاده کن.
|
||||
- `setSelectedSlot(hour)` در `SendAppo` باید شیئی نگه دارد که `start` و `end` (Unix) و `location_id` دارد — همان آبجکت اسلات از API. مطمئن شو این فیلدها تا `SubmitData` میرسند.
|
||||
- بخش آدرس: `request.getDoctorAddress(hour.location_id)` پاسخش `res.data` است — `setLocationAddress(res.data?.address)`. (شکل واقعی `getDoctorAddress` را با یک فراخوانی تأیید کن.)
|
||||
|
||||
### ۴. اصلاح ساخت نوبت — `components/appointment/detail/SubmitData.js`
|
||||
|
||||
- بدنهی درست:
|
||||
|
||||
```js
|
||||
const appointmentPayload = {
|
||||
doctor_uuid: doctor.uuid,
|
||||
slot_start: selectedSlot.start,
|
||||
slot_end: selectedSlot.end,
|
||||
note: "",
|
||||
};
|
||||
const res = await request.postAppointment(appointmentPayload);
|
||||
const appointmentUuid = res?.data?.uuid;
|
||||
if (appointmentUuid) setAppointmentId(appointmentUuid); // نام state را appointmentUuid نگهدار یا همان appointmentId با مقدار uuid
|
||||
```
|
||||
|
||||
- خطای `409` (اسلات قبلاً رزرو شده، `ERR_CONFLICT_001`) را به پیام فارسی مناسب map کن و کاربر را به مرحلهی انتخاب ساعت برگردان.
|
||||
- بخش PATCH/POST پروفایل قبل از رزرو دستنخورده میماند مگر اینکه شکل پاسخ را بشکند — فقط مطمئن شو با interceptor (`res.data`) همخوان است.
|
||||
|
||||
### ۵. اصلاح پرداخت — `components/appointment/paying/index.js`
|
||||
|
||||
- بدنه و مسیر درست:
|
||||
|
||||
```js
|
||||
const paymentPayload = {
|
||||
appointment_uuid: appointmentId, // همان uuid نوبت
|
||||
gateway: selectedBank, // فقط "mellat" یا "sep"
|
||||
frontend_address: `${window.location.origin}/payment/result`,
|
||||
};
|
||||
const res = await request.postAppointmentPayment(paymentPayload);
|
||||
const redirectUrl = res?.data?.redirect_url;
|
||||
if (redirectUrl) {
|
||||
window.location.href = redirectUrl; // از redirect_url خود backend استفاده کن
|
||||
} else {
|
||||
setStep((prev) => prev + 1);
|
||||
}
|
||||
```
|
||||
|
||||
- لیست بانکها (`banks`) را با `gateway`های واقعی همخوان کن: `{ id: "mellat", title: "بانک ملت" }`، `{ id: "sep", title: "سامان (سپ)" }`. مقدار `id` باید دقیقاً `mellat`/`sep` باشد.
|
||||
- مبلغ hard-code شدهی «10،000 تومان» را یا از `price` پاسخ نوبت (`data.price`، ریال) بگیر و با جداکنندهی فارسی به ریال/تومان نمایش بده، یا اگر در این مرحله در دسترس نیست، متن مبلغ ثابت را حذف کن (توهمسازی مبلغ ممنوع). `price` در پاسخ `POST /api/v1/appointment` هست — میتوان آن را تا این مرحله پاس داد.
|
||||
|
||||
### ۶. اصلاح خواندن پروفایل — `components/appointment/index.js`
|
||||
|
||||
- در هر دو `useEffect`، `const res = await request.getUserProfile(parsedData.uuid)` پاسخش `{ success, data }` است → از `res.data` بخوان: `res.data.uuid`, `res.data.national_code`, `res.data.name`, ... . منطق 404 (پروفایل ناموجود → فیلدها قابلویرایش) حفظ شود.
|
||||
|
||||
## نکات مهم
|
||||
|
||||
- **هیچ تغییری در backend لازم نیست.** اگر به endpoint غایبی برخوردی، **متوقف شو و بپرس** (cross-repo) — دادهی جعلی یا route حدسی جایگزین نکن. مشخصاً `appointment/not-available` وجود ندارد و نباید بازسازی شود.
|
||||
- **interceptor (`services/api.js`):** همهی `request.*` بدنهی `{ success, data }` را برمیگردانند → داده در `result.data`. صفحهی server-side با `axiosInstance` خام، doctor را سهلایه میگیرد (`res.data.data.data`).
|
||||
- **slug = uuid:** پارامتر route `[doctorId]` در عمل uuid پزشک است؛ همان را به `doctor_uuid` بده، نه `doctor.id` عددی.
|
||||
- **timestampها Unix هستند:** `slot.start`/`slot.end` مستقیم بهعنوان `slot_start`/`slot_end` میروند؛ تبدیل اضافه نکن.
|
||||
- **adapter جدا:** برای اسلاتها یک تابع map کوچک بنویس (`sessions[]` → ساختار UI) تا کامپوننت نمایشی کمتغییر بماند و دیف کوچک شود.
|
||||
- **Auth:** رزرو و پرداخت `requireAuth` میخواهند؛ در 401، `api.js` خودکار logout/redirect میکند — این رفتار را حفظ کن. فلوی OTP (step 1/2) دستنخورده میماند.
|
||||
- **Multi-domain/RTL/Jalali:** تاریخها شمسی، مبالغ ریال با جداکنندهی فارسی، `matchedCity` موجود حفظ شود.
|
||||
- **تست:** بعد از هر قابلیت `npm run build` (ESLint در این پروژه setup نشده؛ build خود type-check را انجام میدهد). در صورت امکان فلو را با یک پزشک واقعی (`4a0594b1-008b-478a-a593-259b95d8c2dd`) و تاریخ آینده دستی تست کن: اسلاتها باید لود شوند. سپس commit با پیام توصیفی برای همان قابلیت.
|
||||
- **عدم رگرسیون:** `getAppointment`/`postPayment` قدیمی ممکن است جای دیگری مصرف شوند؛ قبل از حذف/تغییر امضا، با `grep -rn "getAppointment\|postPayment\|getAppointmentNotAvailable" app components services` همهی callerها را پیدا و مهاجرت بده.
|
||||
@@ -51,8 +51,6 @@ export const request = {
|
||||
Authorization: "",
|
||||
},
|
||||
}),
|
||||
getAppointmentNotAvailable: (doctor_id) =>
|
||||
api.get(`api/v1/appointment/not-available/${doctor_id}`, removeTokenHead),
|
||||
getAppointmentWeeklySchedule: (uuid) =>
|
||||
api.get(`api/v1/appointment-settings/weekly-schedule/${uuid}`),
|
||||
postAppointmentWeeklySchedule: () =>
|
||||
@@ -61,14 +59,15 @@ export const request = {
|
||||
api.patch(`api/v1/appointment-settings/weekly-schedule/${uuid}`),
|
||||
deleteAppointmentWeeklySchedule: (uuid) =>
|
||||
api.delete(`api/v1/appointment-settings/weekly-schedule/${uuid}`),
|
||||
getAppointment: (doctor_id, date) =>
|
||||
getAppointmentSlots: (doctor_uuid, date) =>
|
||||
api.get(
|
||||
`api/v1/appointment-slots?date=${date}&doctor_id=${doctor_id}`,
|
||||
`api/v1/appointment-slots?doctor_uuid=${doctor_uuid}&date=${date}`,
|
||||
removeTokenHead
|
||||
),
|
||||
postAppointment: (data) => api.post(`api/v1/appointment`, data, { requireAuth: true }),
|
||||
getMyAppointments: (userId, params) => api.get(`api/v1/appointment/my-appointments/${userId}`, { params, requireAuth: true }),
|
||||
postPayment: (data) => api.post(`api/v1/payment`, data, { requireAuth: true }),
|
||||
postAppointmentPayment: (data) =>
|
||||
api.post(`api/v1/payment/appointment`, data, { requireAuth: true }),
|
||||
getPayment: (uuid) => api.get(`api/v1/payment/${uuid}`, { requireAuth: true }),
|
||||
getMyPayments: (userId, params) => api.get(`api/v1/payment/my-payments/${userId}`, { params, requireAuth: true }),
|
||||
postDoctor: (data) => api.post("api/v1/doctor", data),
|
||||
|
||||
Reference in New Issue
Block a user