From 9912ae06ca5ba660609c4ab3673de47c9e9d8a33 Mon Sep 17 00:00:00 2001 From: hamed <15238-genius.ha@users.noreply.drupalcode.org> Date: Mon, 15 Jun 2026 18:25:11 +0330 Subject: [PATCH] feat(api): surface backend error messages globally via toast MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Show the backend's Persian error (errors[0].message, e.g. rate-limit 'درخواست‌های زیاد') as a toast for any failed request.* call, from the axios response interceptor — so failures are no longer silent. 401 still logs out/redirects without a toast; callers can opt out with config.skipErrorToast. Drop now-redundant per-caller alerts/toasts in the booking submit, payment, and OTP userinfo paths. Co-Authored-By: Claude Opus 4.8 --- components/appointment/detail/SubmitData.js | 1 - components/appointment/paying/index.js | 1 - .../register/verificationPage/SendReq.js | 1 - services/api.js | 36 +++++++++++++------ 4 files changed, 26 insertions(+), 13 deletions(-) diff --git a/components/appointment/detail/SubmitData.js b/components/appointment/detail/SubmitData.js index 4bd4977..18fa0cf 100644 --- a/components/appointment/detail/SubmitData.js +++ b/components/appointment/detail/SubmitData.js @@ -127,7 +127,6 @@ function SubmitData({ setStep, data, prevData, setErrors, doctor, isForAnother, } catch (error) { setLoading(false); if (error?.response?.status === 409) { - alert("این زمان همین لحظه توسط کاربر دیگری رزرو شد. لطفاً ساعت دیگری انتخاب کنید."); setStep(0); return; } diff --git a/components/appointment/paying/index.js b/components/appointment/paying/index.js index 069ab04..33b0189 100644 --- a/components/appointment/paying/index.js +++ b/components/appointment/paying/index.js @@ -63,7 +63,6 @@ function Paying({ setStep, appointmentId, expiresAt, doctor, selectedSlot, selec } } catch (error) { console.error("Payment error:", error); - alert("خطا در پرداخت"); setLoading(false); } }; diff --git a/components/register/verificationPage/SendReq.js b/components/register/verificationPage/SendReq.js index e24e4aa..8c43688 100644 --- a/components/register/verificationPage/SendReq.js +++ b/components/register/verificationPage/SendReq.js @@ -103,7 +103,6 @@ function SendReq({ .catch(() => { setLoading(false); setIsError(true); - toast.error("دریافت اطلاعات کاربر ناموفق بود. دوباره تلاش کنید."); }); }; diff --git a/services/api.js b/services/api.js index 56928fb..1028394 100644 --- a/services/api.js +++ b/services/api.js @@ -1,5 +1,17 @@ import axios from "axios"; import Cookies from "js-cookie"; +import { toast } from "react-toastify"; + +function extractErrorMessage(error) { + const errors = error?.response?.data?.errors; + if (Array.isArray(errors) && errors.length > 0 && errors[0]?.message) { + return errors[0].message; + } + if (error?.response?.data?.message) { + return error.response.data.message; + } + return "خطایی رخ داد. لطفاً دوباره تلاش کنید."; +} const BASE_URL = process.env.NEXT_PUBLIC_API_URL; @@ -33,16 +45,20 @@ api.interceptors.response.use( return response.data; }, (error) => { - if (error?.response?.status === 401 && typeof window !== "undefined") { - const hostname = window.location.hostname; - const domain = hostname.includes("localhost") - ? undefined - : `.${hostname.split(".").slice(-2).join(".")}`; - const opts = { path: "/", ...(domain && { domain }) }; - ["access_token", "refresh_token", "uuid", "userInfo"].forEach((key) => { - Cookies.remove(key, opts); - }); - window.location.href = "/login"; + if (typeof window !== "undefined") { + if (error?.response?.status === 401) { + const hostname = window.location.hostname; + const domain = hostname.includes("localhost") + ? undefined + : `.${hostname.split(".").slice(-2).join(".")}`; + const opts = { path: "/", ...(domain && { domain }) }; + ["access_token", "refresh_token", "uuid", "userInfo"].forEach((key) => { + Cookies.remove(key, opts); + }); + window.location.href = "/login"; + } else if (!error?.config?.skipErrorToast) { + toast.error(extractErrorMessage(error)); + } } return Promise.reject(error); }