Files
hamedandClaude Fable 5 daf38c8631 feat(maintenance): show maintenance page when the API is in maintenance
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>
2026-07-19 22:01:45 +03:30

70 lines
2.7 KiB
JavaScript
Raw Permalink Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"use client";
import Image from "next/image";
import React, { useEffect, useState } from "react";
import { Button } from "@mui/material";
import { DEFAULT_MAINTENANCE_MESSAGE } from "@/lib/maintenance";
const RECHECK_INTERVAL_MS = 60_000;
function MaintenancePage() {
const [message, setMessage] = useState(DEFAULT_MAINTENANCE_MESSAGE);
// پیام واقعی را interceptor هنگام دریافت ۵۰۳ ذخیره کرده است.
useEffect(() => {
try {
const stored = sessionStorage.getItem("maintenance_message");
if (stored) setMessage(stored);
} catch { }
}, []);
// اگر تعمیرات تمام شد کاربر نباید تا رفرش دستی پشت این صفحه بماند.
useEffect(() => {
const timer = setInterval(async () => {
try {
const response = await fetch("/", { method: "HEAD", cache: "no-store" });
if (response.status !== 503) window.location.href = "/";
} catch { }
}, RECHECK_INTERVAL_MS);
return () => clearInterval(timer);
}, []);
return (
<div className="py-[105px] padding-responsive sm:py-[135px] md:py-[165px] lg:py-[201px] min-h-screen flex flex-col md:flex-row items-center justify-between gap-[50px]">
<div className="flex w-full md:w-fit flex-col justify-center items-center">
<Image
className=" flex md:hidden mt-[20px] w-[200px] sm:w-[270px] md:w-[340px] lg:w-[411px] h-[200px] sm:h-[270px] md:h-[340px] lg:h-[405px] "
src="/assets/images/notfound-cover.png"
alt="maintenance-cover"
height={405}
width={411}
/>
<p className="text-[#3B3B3B] text-[20px] sm:text-[24px] md:text-[28px] lg:text-[32px] font-bold mt-[24px] sm:mt-[30px] md:mt-[35px] lg:mt-[40px] mb-[12px] sm:mb-[16px] md:mb-[20px] lg:mb-[24px] text-center">
در حال بهروزرسانی سیستم
</p>
<p className="text-[#525252] text-[14px] md:text-[16px] font-normal text-center max-w-[520px]">
{message}
</p>
<Button
className="!h-[43px] md:!h-[45px] lg:!h-[46px] !mt-[20px] sm:!mt-[29px] md:!mt-[39px] lg:!mt-[48px] !px-[12px] !text-[#EFEFEF] !text-[14px] md:!text-[16px] !font-medium"
variant="contained"
onClick={() => { window.location.href = "/"; }}
>
تلاش مجدد
</Button>
</div>
<Image
className=" hidden md:flex w-[200px] sm:w-[270px] md:w-[340px] lg:w-[411px] h-[200px] sm:h-[270px] md:h-[340px] lg:h-[405px] "
src="/assets/images/notfound-cover.png"
alt="maintenance-cover"
height={405}
width={411}
/>
</div>
);
}
export default MaintenancePage;