import { Checkbox } from '../ui/checkbox';
import { Heading } from '../ui/heading';
import { DismissibleAlert } from '../ui/dismissible-alert';
import {
AlertDialog,
AlertDialogAction,
AlertDialogCancel,
AlertDialogContent,
AlertDialogDescription,
AlertDialogFooter,
AlertDialogHeader,
AlertDialogTitle,
} from '../ui/alert-dialog';
import { CLINICIAN_SEAT_PERMITS, type ClinicianSeatCharge } from '../../utils/clinicianSeatCharge';
/**
* THE CLINICIAN SEAT CONTROL, AND THE CONFIRMATION THAT PRECEDES THE CHARGE.
*
* Extracted from `StaffWorkspacesPage` when the staff CREATION form gained the same control. It is
* shared rather than copied for one reason: **this control is the last thing somebody reads before a
* recurring charge starts.** Two copies of that sentence drift, and the copy that goes stale is the one
* a practice reads immediately before being billed - which is the defect this exists for, on
* the screen that had only one copy.
*
* THE PREREQUISITE IS THE PRACTITIONER WORKSPACE, and the dependency runs in that direction. A seat on
* somebody who is not a practitioner is what made a receptionist bookable for a consultation
* so the box is disabled until Practitioner is ticked and the refusal names the remedy in the same
* breath.
*
* A DISABLED CONTROL IS A HINT, NOT A GATE. Every caller must apply the same test at save time; this
* component renders the decision, it never enforces it.
*/
export interface ClinicianSeatFieldProps {
className?: string;
/** Is the box ticked in the draft? */
checked: boolean;
onCheckedChange: (checked: boolean) => void;
/** Has the Practitioner workspace been selected? The seat is meaningless without it. */
practitionerWorkspaceSelected: boolean;
/**
* Already saved as a clinician.
*
* IT NO LONGER LOCKS THE BOX. Turning a seat off has to cancel or move that clinician's booked
* patients first, and while no flow did that the off-switch was withheld and said to be withheld -
* which left a practice that granted a seat by mistake billed for it indefinitely, with no screen
* anywhere that could stop the charge. That flow exists now, so unticking is allowed and the CALLER
* decides what happens next.
*
* Always false on a creation form, where nothing has been saved and there is nothing to remove.
*/
savedEnabled?: boolean;
disabled?: boolean;
headingLevel?: 3 | 6;
}
export const ClinicianSeatField = ({
className = 'mt-4 pt-4 border-t border-border',
checked,
onCheckedChange,
practitionerWorkspaceSelected,
savedEnabled = false,
disabled = false,
headingLevel = 6,
}: ClinicianSeatFieldProps) => {
// A SAVED seat is unlockable now: it is the only route a practice has to stop paying for one. The
// Practitioner prerequisite still holds for GRANTING, which is the direction that made a
// receptionist bookable for a consultation.
const locked = disabled || (!savedEnabled && !practitionerWorkspaceSelected);
return (
Clinician seat
onCheckedChange(next === true)}
/>
{/* THE OFF-SWITCH EXISTS NOW, and the sentence that used to sit here said it did not.
Withholding it was defensible while nothing dealt with the booked patients; leaving it
withheld meant a practice that granted a seat by mistake was billed for it forever with
no screen that could stop the charge. Unticking opens a dialog that reads the clinician's
calendar first and will not save until those patients have somewhere to go. */}
{savedEnabled && (
Removing the seat makes them unbookable. Their booked patients have to be cancelled
or moved first; the next screen does that and explains any change to your bill.
)}
{/* Says WHY the box is disabled rather than leaving a dead control. */}
{!savedEnabled && !practitionerWorkspaceSelected && (
A clinician seat can only be given to somebody who has the Practitioner workspace.
Select the Practitioner workspace first.
)}
);
};
/**
* The money question, asked once, on the way ON.
*
* `open` is driven by the caller's pending-confirm state so the caller keeps control of what happens on
* accept - a creation form submits, an edit form saves. The SENTENCE is what is shared, and it is the
* whole point: it states the amount, or says plainly that we could not read it. Never an invented
* figure immediately before a charge.
*/
export interface ClinicianSeatConfirmDialogProps {
open: boolean;
onOpenChange: (open: boolean) => void;
seatCharge: ClinicianSeatCharge;
onConfirm: () => void;
}
export const ClinicianSeatConfirmDialog = ({
open,
onOpenChange,
seatCharge,
onConfirm,
}: ClinicianSeatConfirmDialogProps) => (
Enable this clinician?
{/* TWO FACTS, AND THE PERMISSION ONE COMES FIRST. An admin reading only about a
subscription line is not being told who just became bookable. */}
{CLINICIAN_SEAT_PERMITS}
{' '}
{seatCharge.headline}
Don't enable
{/* Three states, because there are three outcomes: nothing happens, a line
joins a bill, or a card is asked for. "Enable and add to my bill" in front
of a Stripe checkout says the money is settled when it is not. */}
{seatCharge.startsSubscription
? 'Continue to payment'
: seatCharge.chargeCents === 0 ? 'Enable clinician' : 'Enable and add to my bill'}
);
/**
* What somebody who may not add a clinician seat is told, where the seat control would have been.
*
* Spencer, 2026-09-16: when a person is not allowed to attach a paid clinician seat, say that only
* administrators can add one and to contact them. Leaving the control out silently let a practitioner be
* created without a seat and nobody know why. It says "paid" only when the seat is: the first clinician is
* free, and this screen claims only what is true.
*/
export const ClinicianSeatWithheldNote = ({
practitionerWorkspaceSelected,
free,
seated = false,
}: {
practitionerWorkspaceSelected: boolean;
free: boolean;
/** The person already holds a seat, so the missing authority is the one that removes it. */
seated?: boolean;
}) =>
seated ? (
Only administrators can remove a clinician seat. Please contact an administrator to remove it.
) : practitionerWorkspaceSelected ? (
{free ? 'Only administrators can add a clinician seat.' : 'Only administrators can add a new paid clinician seat.'}
{' '}Please contact an administrator to add one.
) : null;
export default ClinicianSeatField;