The backend now answers 503 with code MAINTENANCE_MODE while maintenance is on. Without this change a visitor got a red error toast over a broken page client-side, and a silently empty page server-side, because fetchReq discards the status and returns null on any failure. - lib/maintenance.js detects the state by BOTH status 503 and the error code; a bare 503 can come from a reverse proxy and is not maintenance - The axios interceptor checks it before the 401 branch, so a maintenance response never triggers the refresh-token path or logs the user out - fetchReq redirects to /maintenance, with a silentMaintenance opt-out used by getStateInfo: that one runs inside generateMetadata and while rendering the maintenance page itself, where a redirect is either ineffective or loops - redirect() works by throwing, so the try/catch blocks in the doctors, clinics and specialties pages now rethrow NEXT_REDIRECT instead of swallowing it - clinicApi.js handles 503 too; it previously rendered maintenance as a clinic with zero doctors - The page reuses the existing 404 design and is marked noindex Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
58 lines
1.9 KiB
JavaScript
58 lines
1.9 KiB
JavaScript
// src/services/clinicApi.js
|
|
import { redirect } from "next/navigation";
|
|
|
|
import {
|
|
MAINTENANCE_CODE,
|
|
MAINTENANCE_PATH,
|
|
isNextRedirectError,
|
|
} from "@/lib/maintenance";
|
|
|
|
export async function getClinicDoctors(slug, params = {}) {
|
|
try {
|
|
const baseUrl = process.env.NEXT_PUBLIC_API_URL;
|
|
if (!baseUrl) throw new Error("❌ NEXT_PUBLIC_API_URL is not defined");
|
|
if (!slug) throw new Error("❌ slug is missing");
|
|
|
|
const query = new URLSearchParams(params).toString();
|
|
const finalUrl = `${baseUrl}/api/v1/clinic/doctor-list/${slug}?${query}`;
|
|
|
|
const response = await fetch(finalUrl, { method: "GET" });
|
|
|
|
// بدون این، حالت تعمیرات بهصورت «کلینیک بدون پزشک» رندر میشود که گمراهکننده است.
|
|
if (response.status === 503) {
|
|
const body = await response.json().catch(() => null);
|
|
if (body?.errors?.[0]?.code === MAINTENANCE_CODE) {
|
|
redirect(MAINTENANCE_PATH);
|
|
}
|
|
}
|
|
|
|
if (!response.ok) {
|
|
const text = await response.text();
|
|
throw new Error(`HTTP ${response.status}: ${text}`);
|
|
}
|
|
|
|
const json = await response.json();
|
|
|
|
// پاسخ دو لایه nested است: آرایهی پزشکان در json.data.data و صفحهبندی در json.data.meta
|
|
const doctors = json?.data?.data || [];
|
|
const meta = json?.data?.meta;
|
|
|
|
// ✅ خروجی همیشه ساختار ثابت دارد
|
|
return {
|
|
data: doctors,
|
|
page: meta
|
|
? { total_pages: meta.totalPages, current: meta.currentPage }
|
|
: { total_pages: 1, current: 1 },
|
|
};
|
|
} catch (error) {
|
|
if (isNextRedirectError(error)) throw error;
|
|
console.error("❌ خطا در دریافت دکترهای کلینیک:", error);
|
|
|
|
// ✅ ساختار خروجی در حالت خطا هم مثل حالت عادی
|
|
return {
|
|
data: [],
|
|
page: { total_pages: 1, current: 1 },
|
|
};
|
|
}
|
|
}
|