/** * Full-screen access denied view. Used when the user is not allowed (no initData / not localhost) * or when API returns 403. Matches global-error and not-found layout: no extra chrome, one action. */ "use client"; import { useEffect } from "react"; import { getLang, translate } from "@/i18n/messages"; import { useAppStore } from "@/store/app-store"; import { triggerHapticLight } from "@/lib/telegram-haptic"; export interface AccessDeniedScreenProps { /** Optional detail from API 403 response, shown below the hint. */ serverDetail?: string | null; /** Primary button: reload (main page) or back/close (deep link). */ primaryAction: "reload" | "back"; /** Called when primaryAction is "back" (e.g. Back to calendar or Close). */ onBack?: () => void; /** When true and primaryAction is "back", button label is "Close" instead of "Back to calendar". */ openedFromPin?: boolean; } /** * Full-screen access denied: title, hint, optional server detail, single action button. * Calls setAppContentReady(true) on mount so Telegram receives ready(). */ export function AccessDeniedScreen({ serverDetail, primaryAction, onBack, openedFromPin = false, }: AccessDeniedScreenProps) { const lang = getLang(); const setAppContentReady = useAppStore((s) => s.setAppContentReady); useEffect(() => { setAppContentReady(true); }, [setAppContentReady]); const hasDetail = Boolean(serverDetail && String(serverDetail).trim()); const handleClick = () => { triggerHapticLight(); if (primaryAction === "reload") { if (typeof window !== "undefined") { window.location.reload(); } } else { onBack?.(); } }; const buttonLabel = primaryAction === "reload" ? translate(lang, "access_denied.reload") : openedFromPin ? translate(lang, "current_duty.close") : translate(lang, "current_duty.back"); return (
{translate(lang, "access_denied.hint")}
{hasDetail && ({serverDetail}
)}