import { useState, type ReactNode } from "react"; import { Navigate } from "react-router-dom"; import { CalendarDays, CreditCard, Globe, IdCardLanyard, UsersRound, type LucideIcon } from "lucide-react"; import { useAuthServiceContext } from "../../../../services/AuthService"; import { useBillingContext } from "../../../../services/BillingContext"; import { isUnderClosure, usePracticeClosure, usePracticeClosureService } from "../../../../services/PracticeClosureService"; import { Checkbox } from "../../../../components/ui/checkbox"; import { Input } from "../../../../components/ui/input"; import { Card } from "../../../../components/ui/card"; import { resolveHeaderBranding } from "../../../../components/PortalFrameHeader/headerBranding"; import { CLOSURE_CARD, NOTICE_TONE, counted, formatBillingDate, sameName } from "./closureText"; import { practiceTimeZoneOf } from "../../../../utils/practiceTimezone"; import PracticeClosureStatus from "./PracticeClosureStatus"; import "./PracticeClosure.css"; // The rest of the app learned at sign-in that the practice was closed, so reopening starts it afresh. const reloadApp = () => { window.location.hash = "#/dashboard/home"; window.location.reload(); }; const UNCONFIRMED = "Closing could not be confirmed. Reload this page to see where it stands before trying again."; const REFUSALS: Record = { "name-mismatch": "The name typed does not match this practice.", conflict: "This practice changed while you were closing it. Try again.", "not-the-owner": "Only the owner can close this practice.", }; // One consequence, on the shared card (a panel: it opens nothing, so it takes no hover): the icon at the left, the title and its sentence beside it. const Effect = ({ icon: Icon, title, children }: { icon: LucideIcon; title: string; children: ReactNode }) => (
  • {title} {children}
  • ); type Surface = "closure" | "account"; const ClosureConfirmation = ({ surface }: { surface: Surface }) => { const { currentOrganization } = useAuthServiceContext(); const billing = useBillingContext(); const organizationId = currentOrganization?.id; const { view, reload } = usePracticeClosure(organizationId); const { closePractice } = usePracticeClosureService(); const [typed, setTyped] = useState(""); const [acknowledged, setAcknowledged] = useState(false); const [count, setCount] = useState(); const [submitting, setSubmitting] = useState(false); const [notice, setNotice] = useState(); const [reopened, setReopened] = useState(); const read = typeof view === "string" ? undefined : view; const practiceName = read?.preview?.practiceName ?? currentOrganization?.name ?? "This practice"; const timeZone = practiceTimeZoneOf(currentOrganization); if (view === "checking") return

    Checking…

    ; // The account while closed is the Owner's recovery view; an open practice has its normal account. if (surface === "account" && !reopened) { if (read && !isUnderClosure(read)) return ; if (view === "denied" || read?.isOwner === false) { return ( <>

    Practice account

    Only the practice owner can see its account while it is closed.
    ); } if (!read) { return (
    This practice's account could not be read.
    ); } } if (view === "denied") { return (
    You do not have access to this practice's closure.
    ); } if (reopened && read && !isUnderClosure(read)) { return (
    {reopened}
    ); } // After signing in to a closed practice this is the screen that still works, so it serves every state. if (read && isUnderClosure(read)) { return (
    { setReopened(notice); reload(); }} onChanged={reload} />
    ); } if (read?.isOwner === false) { return (
    Only the practice owner can close this practice.
    ); } const preview = read?.preview; if (!preview) { return (
    Whether this practice can be closed could not be checked.
    ); } const name = preview.practiceName; const cancelling = count ?? preview.futureAppointments; const ready = sameName(typed, name) && acknowledged && !submitting; const agencyPays = billing.subscriptionPayer === "contractor"; const freePlan = billing.billingMode === "free_basic"; const paidThrough = preview.paidThrough !== undefined ? preview.paidThrough : (billing.subscription?.paidThrough ?? billing.subscription?.nextChargeAt); const staffTitle = typeof preview.staffCount === "number" ? `${counted(preview.staffCount, "person loses", "people lose")} this workspace` : "Everyone who works here loses this workspace"; const patientTitle = typeof preview.patientCount === "number" ? `${counted(preview.patientCount, "patient keeps", "patients keep")} everything` : "Patients keep everything"; const periodEnd = paidThrough ? `The current paid period runs through ${formatBillingDate(paidThrough, timeZone)}` : "The current paid period runs to its end"; const planTitle = freePlan ? "There is no paid plan to stop" : agencyPays ? "The subscription your contractor pays for will not renew" : "Your subscription will not renew"; const planText = freePlan ? "Practice access and bookings stop now, and nothing is charged while the practice is closed." : `Practice access and bookings stop now. ${periodEnd}; ${agencyPays ? "your contractor" : "you"} will not be charged` + " for another period while the practice stays closed."; const close = async () => { if (!organizationId) return; setSubmitting(true); setNotice(undefined); try { const outcome = await closePractice(organizationId, typed, cancelling); if (outcome.status === 200 || outcome.status === 202 || outcome.code === "job-not-started") { reload(); } else if (outcome.code === "count-changed" && typeof outcome.count === "number") { setCount(outcome.count); setAcknowledged(false); setNotice(`The number of future appointments has changed to ${outcome.count.toLocaleString()}. Review it and confirm again.`); } else { const refusal = REFUSALS[outcome.code ?? ""] ?? (outcome.status === 403 ? REFUSALS["not-the-owner"] : undefined); setNotice(refusal ?? UNCONFIRMED); // An answer this page cannot place may still have closed the practice; the closure read says which. if (!refusal) reload(); } } catch { setNotice(UNCONFIRMED); reload(); } finally { setSubmitting(false); } }; return (

    Close {name}

    Only you can do this. You are the owner.

    {/* One description, so the bold lead stays in the notice's one text run. */} Closing archives this practice. Nothing is deleted. Records, messages and invoices are preserved. You can reopen the practice, but cancelled appointments are not restored.

    What happens the moment you close it

      We try to email patients who have an address. After closing, this page counts anyone a notice could not reach the way they chose. Reopening does not bring these appointments back. Their own accounts and their own records are untouched. Anyone who works at another practice on Akashic keeps that. A record belongs to the patient, not to a practice. They lose nothing at all. Both say the practice is closed rather than failing quietly. Enquiries already in the front desk's inbox are kept. {planText}

    To close it

    setTyped(event.target.value)} />

    Enter the exact name and acknowledge the appointment cancellations to enable closing.

    setAcknowledged(value === true)} />
    {notice && (
    {notice}
    )}
    ); }; // A practice switch starts the confirmation over; nothing typed for one practice carries to another. const PracticeClosurePage = ({ surface = "closure" }: { surface?: Surface }) => { const { currentOrganization } = useAuthServiceContext(); return ; }; export default PracticeClosurePage;