import { HelpCircle } from 'lucide-react'; import { useTenant } from '../../services/TenantService.tsx'; import { leaveSandboxMode, reloadPage } from '../../environments/sandboxMode'; import { SandboxLandingNotice } from '../SandboxMode/SandboxLandingNotice'; import { useSandboxResetCountdown } from './sandboxResetCountdown'; import './SandboxBanner.css'; /** * THE SANDBOX BANNER - and the two things it must never do. * * IT READS NOTHING LOCAL. No build flag, no env var, no hostname, no prop. It renders the answer the * API gave and nothing else, because the whole security property of the sandbox is that the client is not * the thing that decides. See `TenantService` for why a token claim was rejected too. * * THREE STATES, AND THE THIRD IS THE ONE PEOPLE DELETE. * * sandbox say so, loudly and permanently * production say NOTHING - a banner on every real screen is noise that gets scrolled past, and * the absence of a sandbox banner is what production looks like * unknown say that we could not tell, and say it in a way that claims NEITHER * * THE THIRD STATE IS NOT DEFENSIVE CODING. Both wrong answers do harm and in opposite directions: a * production user shown a sandbox banner may treat real work as disposable; a sandbox user shown nothing * may treat test data as real. There is no safe default, so the honest state is its own state. * Collapsing `unknown` into either branch is the defect this card exists to prevent. */ export const SandboxBanner = () => { const { kind } = useTenant(); const resetsIn = useSandboxResetCountdown(kind === 'sandbox'); if (kind === 'production') return null; if (kind === 'sandbox') { return (
Sandbox ยท no live patient data Changes here stay here. {resetsIn && {resetsIn}}
); } /* * IT SAYS WHAT IT DOES NOT KNOW, rather than picking the safer-sounding half. "You may be in the * sandbox" would be a sandbox claim; saying nothing would be a production claim. Neither is true, and * a reader can act correctly on "we could not check" - by not relying on either assumption - in a way * they cannot act on a confident wrong answer. */ return (
We could not check whether this is your live practice or the sandbox. Treat anything you create here as real until it says otherwise.
); }; export default SandboxBanner;