Files
nobat724_front/.claude/prompt/payment-single-flow-frontend.md

6.2 KiB

entry پرداخت به‌صورت ریدایرکت خالص به Backend (بدون XHR) — سایت عمومی

پروژه

nobat724_front (سایت عمومی). cross-repo — پرامپت همتا (Backend، اول اجرا شود): clinicpro/.claude/prompt/payment-single-flow-consolidation.md.

زمینه

طبق معماری واحد پرداخت، سایت عمومی نباید هیچ API برای شروع پرداخت صدا بزند؛ فقط مرورگر را به Backend ریدایرکت کند. Backend یک entry ریدایرکتِ خالص دارد:

GET {API}/api/v1/payment/order/{appointmentUuid}?gateway=<name>&return=<frontend_return_url>

Backend این آدرس را می‌گیرد، سفارش را اعتبارسنجی می‌کند، Payment می‌سازد، به بانک وصل می‌شود و کاربر را به شاپرک می‌فرستد؛ در پایان به return (همان دامنهٔ مبدأ) با ?status=... برمی‌گردد.

وضعیت فعلی سایت: components/appointment/paying/index.js هنوز با XHR (request.postAppointmentPayment) پرداخت را شروع می‌کند و بعد به pay_url می‌رود. طبق نیاز جدید باید این XHR حذف شود و دکمهٔ پرداخت مستقیماً به payment/order/{uuid} ریدایرکت کند.

مشکل / هدف

حذف کامل فراخوانی API برای شروع پرداخت در سایت عمومی؛ دکمهٔ پرداخت = ریدایرکت مرورگر به GET {API}/api/v1/payment/order/{appointmentUuid}?gateway=...&return=.... انتخاب درگاه (در صورت چند درگاه) قبل از ریدایرکت انجام شود؛ اگر یک درگاه فعال باشد، خودکار.

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

فایل نقش
components/appointment/paying/index.js دکمهٔ پرداخت + انتخاب درگاه (از getPaymentConfig)
services/response.js getPaymentConfig (برای فهرست درگاه‌های فعال) — بدون تغییر
app/payment/result/page.js بازگشت از Backend با status — بدون تغییر
app/payment/[uuid]/page.js نمایش نتیجه — بدون تغییر

وضعیت فعلی

// components/appointment/paying/index.js
const handlePayment = async () => {
  if (!appointmentId) return;
  if (!testMode && !selectedBank) return;
  setLoading(true);
  try {
    const res = await request.postAppointmentPayment({          // ❌ XHR برای شروع پرداخت
      appointment_uuid: appointmentId,
      gateway: testMode ? "mellat" : selectedBank,
      frontend_address: `${window.location.origin}/payment/result`,
    });
    const payUrl = res?.data?.pay_url;
    if (payUrl) { window.location.href = payUrl; return; }
    throw new Error("pay_url missing");
  } catch (error) { alert("خطا در شروع پرداخت..."); setLoading(false); }
};

getPaymentConfig از قبل درگاه‌های فعال را در gateways می‌دهد و selectedBank/testMode ست می‌شوند (بدون تغییر می‌مانند).

وظایف

۱. تبدیل دکمهٔ پرداخت به ریدایرکتِ خالص (حذف XHR)

handlePayment را طوری بازنویسی کن که به‌جای XHR، مستقیماً مرورگر را به entry بک‌اند ببرد:

const handlePayment = () => {
  if (!appointmentId) return;
  const gateway = testMode ? "mellat" : selectedBank;
  if (!gateway) return; // باید یک درگاه انتخاب شده باشد
  setLoading(true);

  const apiBase = process.env.NEXT_PUBLIC_API_URL;
  const ret = encodeURIComponent(`${window.location.origin}/payment/result`);
  window.location.href =
    `${apiBase}/api/v1/payment/order/${appointmentId}` +
    `?gateway=${encodeURIComponent(gateway)}&return=${ret}`;
};
  • handlePayment دیگر async نیست و هیچ request.* صدا نمی‌زند.
  • NEXT_PUBLIC_API_URL همان base بک‌اند است (مثل بقیهٔ سایت).
  • appointmentId همان appointment_uuid است (capability؛ در URL می‌رود).

۲. حفظ انتخاب درگاه (مرحلهٔ ۲ نیاز)

  • getPaymentConfig و state gateways/selectedBank/testMode بدون تغییر بمانند؛ Select فقط وقتی چند درگاه فعال است نمایش داده شود.
  • اگر فقط یک درگاه فعال باشد، selectedBank از قبل روی همان ست است (پیش‌فرض gateways[0]), پس مرحله خودکار است.
  • دکمه وقتی !testMode && !selectedBank است disabled بماند (از قبل هست).

۳. پاک‌سازی

  • اگر request.postAppointmentPayment دیگر جای دیگری استفاده نمی‌شود، آن را از services/response.js حذف کن (بررسی با grep). اگر جای دیگری استفاده می‌شود، نگه‌دار.
  • app/payment/result/page.js و app/payment/[uuid]/page.js بدون تغییر (بازگشت با status را از قبل مدیریت می‌کنند).

نکات مهم

  • هیچ فراخوانی API برای شروع پرداخت نباید بماند — فقط ریدایرکت full-page به {API}/api/v1/payment/order/{uuid}. Backend همهٔ ارتباط با بانک را انجام می‌دهد.
  • بازگشت به دامنهٔ مبدأ: return=${window.location.origin}/payment/result تضمین می‌کند Backend بعد از پرداخت به همین دامنهٔ چند-شهری برگردد؛ Backend این آدرس را در برابر payment_allowed_frontend_hosts اعتبارسنجی می‌کند (host دامنه باید whitelist باشد).
  • انتخاب درگاه همچنان از GET /api/v1/payment/config (gateways فعال) است — درگاه هاردکد نکن.
  • App Router؛ paying یک client component است (use client). فونت/استایل موجود (MUI + Tailwind, RTL).
  • بعد از تغییر: npm run build. تست دستی: کلیک پرداخت → مرورگر به {API}/api/v1/payment/order/... می‌رود (نه XHR)، سپس شاپرک، سپس بازگشت به /payment/result?status=....