import { ApprovalActionType, AttributeType, User } from '@zeniai/client-epic-state'; /** * Approval Rules 3.0 — Set Approval Stages row. * * One stage in the rule's sequential approval pipeline, laid out as: * * [::] [N.] [Require | Notify] [Actor kind ▾] [Value picker] [🗑] * * Actor kind drives the value picker: * - "specific_person" → user multi-select (renders avatars + "or" * between names, via the existing `UserMultiSelectField`). * - "role" → single-select of `Manager / Manager of Manager / * Vendor Owner`, backed by `AttributeType` in `client-epic-state`. * * Form-state model — each row binds to a slot under `steps[N]`: * - `steps[N].action` → 'require_approval' | 'send_notification' * - `steps[N].actorKind` → 'specific_person' | 'role' * - `steps[N].persons` → `{allUsers, allNonUsers, selectedUsers, selectedNonUsers}` * (the UserMultiSelectField-native shape) * - `steps[N].selectedRole` → AttributeType | undefined * * Both `persons` and `selectedRole` live on the slot at all times so * the user can toggle actor kind without losing the data they entered * for the other variant. The screen connector reads the relevant * branch based on `actorKind` at save time and ignores the other. * * Drag handle is wired up to 'react-dnd' (HTML5 backend, configured * by the enclosing ApprovalStagesSection's DndProvider). The handle * is the drag source; the whole row is the drop target with the * standard hover-middle gate so a drag past the row's vertical center * triggers reorder. The parent owns the reorder via the * 'onReorder(dragIndex, hoverIndex)' callback — the row never mutates * form state directly. See ApprovalsActivity / RealTimeApprovalListItem * for the canonical pattern this mirrors. */ /** * react-dnd item shape carried while dragging a stage row. Index is * mutated in-place during hover (per the react-dnd reorder pattern) * so subsequent hovers see the rebased index without re-querying the * monitor. */ export interface StageDragItem { index: number; } /** react-dnd type discriminator for stage rows. */ export declare const STAGE_DND_TYPE = "approval-stage"; /** The two actor-kind variants the row's type dropdown surfaces. */ export type ApprovalStageActorKind = "specific_person" | "role"; /** * Form-state shape for a single stage row. Lives on * `FormData.steps[N]` in the BillPay and Reimbursement detail pages. * * `persons` and `selectedRole` both live on every stage so the user * can toggle actor kind without losing data they entered for the * other variant. The screen connector reads only the branch that * matches `actorKind` at save time. */ export interface ApprovalStageData { /** Sequential index within the stage list. Re-numbered on add/remove. */ stageIndex: number; /** * Require / Notify segmented toggle binding. Bare string because * the toggle uses a plain `Controller` (not `SingleSelectField`). */ action?: ApprovalActionType; /** * Drives the value picker variant. Wrapped because the dropdown is * `SingleSelectField`-driven (writes `{allOptions, selectedOption}`). * Readers do `actorKind.selectedOption`. */ actorKind?: { allOptions: ApprovalStageActorKind[]; selectedOption?: ApprovalStageActorKind; }; /** * Bound when `actorKind.selectedOption === "specific_person"`. * Shape matches `UserMultiSelectField`'s native value so the field * can re-use existing avatar rendering and "or" join. */ persons?: { allNonUsers: any[]; allUsers: any[]; selectedNonUsers: any[]; selectedUsers: any[]; }; /** * Bound when `actorKind.selectedOption === "role"`. Wrapped shape * (same reason as actorKind). Readers do `selectedRole.selectedOption`. */ selectedRole?: { allOptions: AttributeType[]; selectedOption?: AttributeType; }; } /** * Builds role dropdown options from API `allAttributes`. * Appends a saved role that is no longer in the allowed list so * existing rules still render their current selection. * * IMPORTANT: `allAttributes` must already be the API-filtered list * for the caller's context. For V3 remi rules the API is expected to * exclude `vendor_owner`; this function does not filter it itself. */ export declare function buildStageRoleOptions(allAttributes: AttributeType[] | undefined | null, selectedRole?: AttributeType): AttributeType[]; export interface ApprovalStageRowProps { /** Pool of users surfaced by the "Specific Person" multi-select. */ allUsers: User[]; /** When `false`, the trash icon is dimmed and inert. */ canRemove: boolean; /** * Base react-hook-form path for this row (e.g. `"steps.0"`). Inner * controls suffix `.action`, `.actorKind`, `.persons`, * `.selectedRole` as needed. The shape mirrors `ApprovalStageData` * defined alongside the parent section. */ fieldNameBase: string; /** Zero-based index of this row within the parent's stage list. */ index: number; /** * Roles the user can pick when actorKind === "role". Reimbursement * passes API `allAttributes`; Bill Pay omits this and keeps the * default list including vendor_owner. */ stageRoleOptions?: AttributeType[]; /** Called when the user clicks the trash icon. */ onRemove: () => void; /** * Called continuously while the user drags one stage over another, * once the cursor crosses the hover target's vertical midpoint. * Optional — when omitted the row is rendered as inert (no drag * handlers attached). The parent owns the reorder mutation; this * callback receives the two indices to swap. */ onReorder?: (dragIndex: number, hoverIndex: number) => void; } export declare function ApprovalStageRow({ index, fieldNameBase, allUsers, onRemove, canRemove, onReorder, stageRoleOptions, }: ApprovalStageRowProps): import("react/jsx-runtime").JSX.Element; export default ApprovalStageRow;