import { ReactNode } from "react"; /** One organization row — active or invited — rendered as a card in OrganizationDetails' grid. */ export type OrganizationItem = { /** Unique per card (React key); passed to every per-organization callback and matched against the `*OrgIds` spinner arrays. */ orgId: number; /** Card title; seeds the inline rename field, and renames are sent trimmed through `onEditOrganization`. */ company_name: string; /** Invited cards only: shown as a line with a globe icon; ignored on active cards. */ company_url?: string; /** 1 when this org is the user's default org. */ default: number; /** @deprecated Ignored; kept so existing callers still compile. Active vs. invited comes from which array the item is in. */ uiInvite?: number; /** Distinct from `default` above — only gates delete-protection, not the Default badge/set-default flow. */ defaultOrg: number; /** Shown as a tag on active cards; "Super Admin" is what `canRename` and `canDelete` default to allowing. */ roleName?: string; /** True when the current user owns this org; the app computes ownership. */ isOwner?: boolean; /** Overrides the role-name check for rename; omitted, defaults to roleName === "Super Admin". */ canRename?: boolean; /** Same default-if-omitted as canRename; defaultOrg === 1 still blocks delete regardless. */ canDelete?: boolean; /** * Why delete is unavailable for this organization, shown on the disabled * control. Falls back to `labels.protectedOrganization` when not supplied. */ deleteDisabledReason?: string; }; /** Local form state for CreateOrgModal — the shape onSubmit receives when the create form is confirmed. */ export type CreateOrgFormValues = { /** Organization name entered in the create form; required, and trimmed before submit. */ company_name: string; /** Address entered in the create form; required, and trimmed before submit. */ company_address: string; /** Trimmed phone; the built-in form requires it with at least 8 digits even though it is typed optional. */ phone?: string; /** @deprecated Dead — never populated by the built-in CreateOrgModal, no known consumer usage. */ default?: number; /** @deprecated Dead — never populated by the built-in CreateOrgModal, no known consumer usage. */ defaultOrg?: number; }; /** All copy in OrganizationDetails is overridable here; unset fields fall back to its built-in DEFAULT_LABELS. */ export type OrganizationDetailsLabels = { /** Header title, default "Hello, User!"; when `userName` is set, "User" is replaced by that name. */ greeting?: string; /** Header subtitle under the greeting. Default "Manage your organizations". */ manageSubtitle?: string; /** Not rendered by the current UI. */ organizationDetails?: string; /** Header button that opens the create modal. Default "Create New Organization". */ createNewOrganization?: string; /** Create modal title and the empty-state button. Default "Create Organization". */ createOrganization?: string; /** Heading of the active organizations section. Default "Active Organizations". */ activeOrganizations?: string; /** Heading of the invitations section. Default "Invited Organizations". */ invitedOrganizations?: string; /** Link on a non-default active card that calls `onSetDefault`. Default "Set as Default". */ setAsDefault?: string; /** Text beside the spinner while the card's id is in `switchingOrgIds`. Default "Setting...". */ settingDefault?: string; /** Badge on the card where `default` is 1. Default "Default". */ default?: string; /** Tag shown when `isOwner` is true. Default "Owner". */ owner?: string; /** Badge on invited cards. Default "Pending". */ pending?: string; /** Accept button on invited cards. Default "Accept". */ accept?: string; /** Accept button text while the id is in `respondingOrgIds`. Default "Accepting...". */ accepting?: string; /** Decline button on invited cards. Default "Decline". */ decline?: string; /** Accessible name of the delete icon, and its tooltip on an unprotected card. Default "Delete Organization". */ deleteOrganization?: string; /** Tooltip on a disabled delete icon when `deleteDisabledReason` is not set. Default "Protected organization". */ protectedOrganization?: string; /** Confirm button in the delete modal. Default "Delete". */ delete?: string; /** Accessible name and tooltip of the rename pencil. Default "Edit organization name". */ editOrganization?: string; /** Accessible name of the inline rename save button. Default "Save". */ save?: string; /** Not rendered by the current UI. */ saving?: string; /** Error shown when a rename is saved blank. Default "Organization name cannot be empty". */ emptyNameError?: string; /** Empty-state title when there are no active or invited organizations. Default "No organizations found". */ noOrganizationsTitle?: string; /** Empty-state description under the title. */ noOrganizationsDescription?: string; /** Create form field label. Default "Company Name". */ companyName?: string; /** Create form field label. Default "Company Address". */ companyAddress?: string; /** Create form field label. Default "Phone". */ phone?: string; /** Cancel button in the create and delete modals and the rename cancel button. Default "Cancel". */ cancel?: string; /** Submit button of the create form. Default "Submit". */ submit?: string; /** Create form error for an empty required field. Default "This field is required". */ requiredField?: string; /** Create form error for a phone with fewer than 8 digits. */ invalidPhone?: string; /** Delete modal title. Default "Confirm Deletion". */ confirmDeletion?: string; /** Delete modal body question. */ deleteConfirmText?: string; /** Not rendered by the built-in UI; put footer text in `footerSlot`. */ copyright?: string; /** Not rendered by the built-in UI; put footer links in `footerSlot`. */ termsOfService?: string; }; /** Payload for the public onCreateOrganization callback — company_address/phone optional here, unlike CreateOrgFormValues. */ export interface CreateOrganizationValues { /** Organization name, trimmed; required by the built-in form. */ company_name: string; /** Address, trimmed; the built-in form requires it. */ company_address?: string; /** Trimmed phone; the built-in form requires 8 or more digits. */ phone?: string; } /** Admin panel for the org list — rename/delete/create/invites/default; not a session switcher (see OrgSwitcher for picking the active org). */ export interface OrganizationDetailsProps { /** Organizations the user belongs to; each renders a card with rename, delete and set-default controls. */ activeOrganizations: OrganizationItem[]; /** Pending invitations; each renders a card with Accept and Decline buttons. */ invitedOrganizations: OrganizationItem[]; /** Replaces both sections with six skeleton cards while true. Defaults to false. */ isLoading?: boolean; /** Puts the create modal's submit button into its loading state. Defaults to false. */ isCreating?: boolean; /** orgIds currently switching to default (shows a spinner on that card) */ switchingOrgIds?: number[]; /** orgIds currently accepting/declining an invite (shows a spinner on that card) */ respondingOrgIds?: number[]; /** orgIds currently saving a renamed organization (shows a spinner on that card) */ editingOrgIds?: number[]; /** Greets the signed-in user in the header and names their avatar; no avatar renders without it. */ userName?: string; /** Avatar photo; initials from `userName` show when it is missing or fails to load. */ userAvatarUrl?: string; /** Not awaited internally despite the Promise signature — drive switchingOrgIds yourself. */ onSetDefault?: (orgId: number) => void | Promise; /** Same as onSetDefault — not awaited internally; respondingOrgIds is entirely consumer-managed. */ onAcceptInvite?: (orgId: number) => void | Promise; /** Fires with the invitation's orgId on Decline; the button has no built-in loading state. */ onDeclineInvite?: (orgId: number) => void | Promise; /** * Called once the built-in confirm modal is accepted. Never called when * `onDeleteRequest` is supplied — that app owns the whole delete. */ onDeleteOrganization?: (orgId: number) => void | Promise; /** * Called on trash-click *instead of* opening the built-in confirm modal, so * the app can run its own preview and confirmation. Supplying it suppresses * both the modal and `onDeleteOrganization`; omit it to keep the built-in flow. */ onDeleteRequest?: (orgId: number) => void | Promise; /** Rejecting/throwing here leaves the modal open with no built-in error UI — same for onDeleteOrganization/onEditOrganization; show your own toast. */ onCreateOrganization?: (values: CreateOrganizationValues) => void | Promise; /** Called when the user confirms a new name for an organization */ onEditOrganization?: (orgId: number, newName: string) => void | Promise; /** Back icon renders only when this is provided, not merely disabled when omitted. */ onBack?: () => void; /** Rendered below the sections, above the modals; use it for copyright or terms links. */ footerSlot?: ReactNode; /** Partial copy overrides; unset keys keep the English defaults. */ labels?: OrganizationDetailsLabels; } /** Props for the internal create-org modal; `labels` needs only the subset of OrganizationDetailsLabels it renders. */ export interface CreateOrgModalProps { isOpen: boolean; onClose: () => void; isLoading?: boolean; onSubmit: (values: CreateOrgFormValues) => void | Promise; labels: Required>; } /** Props for the internal delete-confirm modal; same narrowed-labels pattern as CreateOrgModalProps. */ export interface DeleteOrgModalProps { isOpen: boolean; onClose: () => void; isLoading?: boolean; onConfirm: () => void; labels: Required>; }