@zeniai/web-components 4.1.67-betaJK2 → 4.1.67-betaVR1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/dist/{SessionTimeoutPopup-BfhMt5Qq.cjs → SessionTimeoutPopup-BrRR0XU5.cjs} +15065 -14520
  2. package/dist/{SessionTimeoutPopup-DTK0o0og.js → SessionTimeoutPopup-DCorFAuC.js} +70935 -68946
  3. package/dist/appLocale.d.ts +115 -10
  4. package/dist/assets/interface/dnd-handle.svg +8 -0
  5. package/dist/assets/interface/flag.svg +4 -3
  6. package/dist/cockpit.cjs.js +11 -5
  7. package/dist/cockpit.esm.js +3940 -3927
  8. package/dist/components/common/zeniDatePicker/ZeniDatePickerField.d.ts +1 -2
  9. package/dist/components/commonSetUp/approval/AmountConditionRow.d.ts +21 -0
  10. package/dist/components/commonSetUp/approval/ApprovalRuleSection.d.ts +70 -3
  11. package/dist/components/commonSetUp/approval/ApprovalRuleSectionV1.d.ts +14 -0
  12. package/dist/components/commonSetUp/approval/ApprovalStageRow.d.ts +121 -0
  13. package/dist/components/commonSetUp/approval/ApprovalStagesSection.d.ts +66 -0
  14. package/dist/components/commonSetUp/approval/ConditionRow.d.ts +78 -0
  15. package/dist/components/commonSetUp/approval/DepartmentConditionRow.d.ts +22 -0
  16. package/dist/components/commonSetUp/approval/FallbackEngineBanner.d.ts +28 -0
  17. package/dist/components/commonSetUp/approval/FormSection.d.ts +26 -0
  18. package/dist/components/commonSetUp/approval/IgnoreOverlapModal.d.ts +22 -0
  19. package/dist/components/commonSetUp/approval/OperatorIsOrIsNotPicker.d.ts +23 -0
  20. package/dist/components/commonSetUp/approval/RuleOverlapBanner.d.ts +61 -0
  21. package/dist/components/commonSetUp/approval/RuleOverlapCard.d.ts +31 -0
  22. package/dist/components/commonSetUp/approval/Switch.d.ts +23 -0
  23. package/dist/components/commonSetUp/approval/VendorConditionRow.d.ts +27 -0
  24. package/dist/components/spendManagement/billPay/billPaySetUp/BillPayApprovalRuleDetailPage.d.ts +107 -12
  25. package/dist/components/spendManagement/billPay/billPaySetUp/BillPayApprovalRuleDetailPageV1.d.ts +37 -0
  26. package/dist/components/spendManagement/billPay/billPaySetUp/BillPayApprovalRulesPage.d.ts +18 -1
  27. package/dist/components/spendManagement/billPay/billPaySetUp/BillPayApprovalRulesPageV1.d.ts +10 -0
  28. package/dist/components/spendManagement/reimbursement/reimbursementSetUp/ReimbursementApprovalRuleDetailPage.d.ts +100 -12
  29. package/dist/components/spendManagement/reimbursement/reimbursementSetUp/ReimbursementApprovalRuleDetailPageV1.d.ts +37 -0
  30. package/dist/components/spendManagement/reimbursement/reimbursementSetUp/ReimbursementApprovalRulesPage.d.ts +16 -1
  31. package/dist/components/spendManagement/reimbursement/reimbursementSetUp/ReimbursementApprovalRulesPageV1.d.ts +10 -0
  32. package/dist/components/taskManagement/TaskDetailPage.d.ts +2 -6
  33. package/dist/components/taskManagement/TaskListRow.d.ts +2 -7
  34. package/dist/components/taskManagement/TaskListRowSmall.d.ts +1 -3
  35. package/dist/components/taskManagement/TaskManagementPage.d.ts +28 -4
  36. package/dist/components/taskManagement/taskManagementFormConstants.d.ts +0 -1
  37. package/dist/components/taskManagement/taskManagementHeaderItemsData.d.ts +0 -1
  38. package/dist/components/vendors/vendorList/VendorListTableRow.d.ts +1 -2
  39. package/dist/context/featureProvider/DynamicConfigNameConstants.d.ts +2 -0
  40. package/dist/context/featureProvider/useApprovalRulesV3Config.d.ts +31 -0
  41. package/dist/designSystem/ClickableRow.d.ts +11 -0
  42. package/dist/designSystem/clickableRowStyles.d.ts +32 -0
  43. package/dist/index.cjs.js +1 -1
  44. package/dist/index.d.ts +14 -0
  45. package/dist/index.esm.js +328 -321
  46. package/dist/strings/strings.d.ts +115 -10
  47. package/package.json +2 -2
  48. package/dist/components/taskManagement/SubtaskCreationForm.d.ts +0 -14
  49. package/dist/components/taskManagement/TaskDetailSubtaskForm.d.ts +0 -14
  50. package/dist/components/taskManagement/taskManagementTypes.d.ts +0 -33
  51. package/dist/components/taskManagement/taskManagementUtils.d.ts +0 -2
@@ -13,9 +13,8 @@ export interface Props {
13
13
  dateFormat?: string;
14
14
  inputStyles?: InputStyles;
15
15
  minDate?: ZeniDate;
16
- placeHolder?: JSX.Element;
17
16
  registerOptions?: RegisterOptions;
18
17
  style?: React.CSSProperties;
19
18
  }
20
- declare const ZeniDatePickerField: ({ name, defaultValue, registerOptions, dateFormat, style, inputStyles, minDate, placeHolder, }: Props) => import("react/jsx-runtime").JSX.Element;
19
+ declare const ZeniDatePickerField: ({ name, defaultValue, registerOptions, dateFormat, style, inputStyles, minDate, }: Props) => import("react/jsx-runtime").JSX.Element;
21
20
  export default ZeniDatePickerField;
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Form-state keys used by the amount-condition group.
3
+ *
4
+ * The row is a composite: a comparator picker + one or two amount inputs.
5
+ * All three pieces nest under the single form key `amountCriteria` so the
6
+ * connector can read `formData.amountCriteria` as a complete
7
+ * `AmountCriteria` value at save time.
8
+ */
9
+ export declare const AMOUNT_CRITERIA_FIELD = "amountCriteria";
10
+ export declare const AMOUNT_COMPARATOR_FIELD = "amountCriteria.comparator";
11
+ export declare const AMOUNT_MIN_FIELD = "amountCriteria.min.amount";
12
+ export declare const AMOUNT_MAX_FIELD = "amountCriteria.max.amount";
13
+ export interface AmountConditionRowProps {
14
+ /**
15
+ * Currency symbol surfaced as a placeholder prefix on every amount input.
16
+ * Defaults to `"$"` when the rule has no stored currency yet.
17
+ */
18
+ currencySymbol?: string;
19
+ }
20
+ export declare function AmountConditionRow({ currencySymbol, }: AmountConditionRowProps): import("react/jsx-runtime").JSX.Element;
21
+ export default AmountConditionRow;
@@ -1,14 +1,81 @@
1
1
  import { BillPayApprovalRuleWithUser, RemiApprovalRuleWithUser } from '@zeniai/client-epic-state';
2
+ /**
3
+ * The setup-approver view selectors alias the same underlying
4
+ * `ApprovalRuleWithUser` shape across bills and reimbursements.
5
+ */
6
+ export type ApprovalRuleWithUser = BillPayApprovalRuleWithUser | RemiApprovalRuleWithUser;
2
7
  export interface DialogAction {
3
8
  onCancelClick: () => void;
4
9
  onOkClick: (notes?: string) => void;
5
10
  }
6
- declare const ApprovalRuleSection: ({ showDeleteBtn, disableButtons, isLastSection, approvalRule, onEditRuleClick, onDeleteRuleClick, }: {
7
- approvalRule: BillPayApprovalRuleWithUser | RemiApprovalRuleWithUser;
11
+ /**
12
+ * react-dnd item shape carried while dragging a rule card. Carries
13
+ * the source rule's id so the drop target can issue an
14
+ * 'onReorder(sourceId, targetId)' callback to the parent on release.
15
+ */
16
+ export interface RuleDragItem {
17
+ ruleId: string;
18
+ }
19
+ /** react-dnd type discriminator for approval-rule cards. */
20
+ export declare const APPROVAL_RULE_DND_TYPE = "approval-rule";
21
+ export interface Props {
22
+ approvalRule: ApprovalRuleWithUser;
8
23
  isLastSection: boolean;
9
24
  showDeleteBtn: boolean;
25
+ /**
26
+ * Optional department-id → display-name map. In this codebase
27
+ * "department" maps to the Class entity (accounting class); the list
28
+ * page derives this from `state.classState`.
29
+ */
30
+ departmentNamesById?: Record<string, string>;
10
31
  disableButtons?: boolean;
32
+ /**
33
+ * Number rendered before the rule name (e.g. "1. Marketing vendor block").
34
+ * Defaults to `approvalRule.priority`.
35
+ */
36
+ positionNumber?: number;
37
+ /**
38
+ * Optional vendor-id → display-name map. The list page derives this
39
+ * from `state.contactState` (vendors are stored as contacts). Chips
40
+ * fall back to the raw ID when no entry is found.
41
+ */
42
+ vendorNamesById?: Record<string, string>;
11
43
  onDeleteRuleClick: (ruleId: string) => void;
12
44
  onEditRuleClick: (ruleId?: string) => void;
13
- }) => import("react/jsx-runtime").JSX.Element;
45
+ /**
46
+ * Called when the user drops THIS card (drop target) after dragging
47
+ * another rule onto it. Receives the source and target rule ids;
48
+ * the list page composes the new order and dispatches the reorder
49
+ * action. Optional — when omitted the card renders without a drag
50
+ * handle and is not draggable.
51
+ */
52
+ onReorderRules?: (dragRuleId: string, hoverRuleId: string) => void;
53
+ }
54
+ /**
55
+ * Approval rule list-page card per Approval Rules 3.0:
56
+ *
57
+ * ┌─────────────────────────────────────────────────────────┐
58
+ * │ 1. Marketing vendor block [Separation of Duties] ⋮│
59
+ * │ All marketing bills route through department lead │
60
+ * │ When: [Amount > $1,000] [Department is Sales & Mktg] │
61
+ * │ Then: 1. Require approval from Jordan Leo or Elena King │
62
+ * │ 2. Require approval from Matteo Ramsey │
63
+ * └─────────────────────────────────────────────────────────┘
64
+ *
65
+ * Accepts the entity-shape `ApprovalRuleWithUser` (steps have resolved
66
+ * User objects, criteria is the discriminated union). The parent
67
+ * provides optional `vendorNamesById` / `departmentNamesById` so chips
68
+ * render names instead of raw IDs.
69
+ *
70
+ * The kebab now opens an internal dropdown (Edit / Delete for V1; Pause
71
+ * and Activity to follow once their action wiring exists). Edit dispatches
72
+ * `onEditRuleClick(approvalRuleId)`; Delete opens the legacy delete-
73
+ * confirmation popup which then dispatches `onDeleteRuleClick(approvalRuleId)`.
74
+ *
75
+ * `showDeleteBtn` is accepted for backward compat with the existing list
76
+ * pages but no longer drives any UI — the kebab and its menu items are
77
+ * always rendered (subject to `disableButtons` for the in-flight pusher
78
+ * case). Once callers stop passing it, the prop can be removed.
79
+ */
80
+ declare const ApprovalRuleSection: ({ approvalRule, isLastSection, disableButtons, onDeleteRuleClick, onEditRuleClick, vendorNamesById, departmentNamesById, positionNumber, onReorderRules, }: Props) => import("react/jsx-runtime").JSX.Element;
14
81
  export default ApprovalRuleSection;
@@ -0,0 +1,14 @@
1
+ import { BillPayApprovalRuleWithUser, RemiApprovalRuleWithUser } from '@zeniai/client-epic-state';
2
+ export interface DialogAction {
3
+ onCancelClick: () => void;
4
+ onOkClick: (notes?: string) => void;
5
+ }
6
+ declare const ApprovalRuleSection: ({ showDeleteBtn, disableButtons, isLastSection, approvalRule, onEditRuleClick, onDeleteRuleClick, }: {
7
+ approvalRule: BillPayApprovalRuleWithUser | RemiApprovalRuleWithUser;
8
+ isLastSection: boolean;
9
+ showDeleteBtn: boolean;
10
+ disableButtons?: boolean;
11
+ onDeleteRuleClick: (ruleId: string) => void;
12
+ onEditRuleClick: (ruleId?: string) => void;
13
+ }) => import("react/jsx-runtime").JSX.Element;
14
+ export default ApprovalRuleSection;
@@ -0,0 +1,121 @@
1
+ import { ApprovalActionType, AttributeType, User } from '@zeniai/client-epic-state';
2
+ /**
3
+ * Approval Rules 3.0 — Set Approval Stages row.
4
+ *
5
+ * One stage in the rule's sequential approval pipeline, laid out as:
6
+ *
7
+ * [::] [N.] [Require | Notify] [Actor kind ▾] [Value picker] [🗑]
8
+ *
9
+ * Actor kind drives the value picker:
10
+ * - "specific_person" → user multi-select (renders avatars + "or"
11
+ * between names, via the existing `UserMultiSelectField`).
12
+ * - "role" → single-select of `Manager / Manager of Manager /
13
+ * Vendor Owner`, backed by `AttributeType` in `client-epic-state`.
14
+ *
15
+ * Form-state model — each row binds to a slot under `steps[N]`:
16
+ * - `steps[N].action` → 'require_approval' | 'send_notification'
17
+ * - `steps[N].actorKind` → 'specific_person' | 'role'
18
+ * - `steps[N].persons` → `{allUsers, allNonUsers, selectedUsers, selectedNonUsers}`
19
+ * (the UserMultiSelectField-native shape)
20
+ * - `steps[N].selectedRole` → AttributeType | undefined
21
+ *
22
+ * Both `persons` and `selectedRole` live on the slot at all times so
23
+ * the user can toggle actor kind without losing the data they entered
24
+ * for the other variant. The screen connector reads the relevant
25
+ * branch based on `actorKind` at save time and ignores the other.
26
+ *
27
+ * Drag handle is wired up to 'react-dnd' (HTML5 backend, configured
28
+ * by the enclosing ApprovalStagesSection's DndProvider). The handle
29
+ * is the drag source; the whole row is the drop target with the
30
+ * standard hover-middle gate so a drag past the row's vertical center
31
+ * triggers reorder. The parent owns the reorder via the
32
+ * 'onReorder(dragIndex, hoverIndex)' callback — the row never mutates
33
+ * form state directly. See ApprovalsActivity / RealTimeApprovalListItem
34
+ * for the canonical pattern this mirrors.
35
+ */
36
+ /**
37
+ * react-dnd item shape carried while dragging a stage row. Index is
38
+ * mutated in-place during hover (per the react-dnd reorder pattern)
39
+ * so subsequent hovers see the rebased index without re-querying the
40
+ * monitor.
41
+ */
42
+ export interface StageDragItem {
43
+ index: number;
44
+ }
45
+ /** react-dnd type discriminator for stage rows. */
46
+ export declare const STAGE_DND_TYPE = "approval-stage";
47
+ /** The two actor-kind variants the row's type dropdown surfaces. */
48
+ export type ApprovalStageActorKind = "specific_person" | "role";
49
+ /**
50
+ * Form-state shape for a single stage row. Lives on
51
+ * `FormData.steps[N]` in the BillPay and Reimbursement detail pages.
52
+ *
53
+ * `persons` and `selectedRole` both live on every stage so the user
54
+ * can toggle actor kind without losing data they entered for the
55
+ * other variant. The screen connector reads only the branch that
56
+ * matches `actorKind` at save time.
57
+ */
58
+ export interface ApprovalStageData {
59
+ /** Sequential index within the stage list. Re-numbered on add/remove. */
60
+ stageIndex: number;
61
+ /**
62
+ * Require / Notify segmented toggle binding. Bare string because
63
+ * the toggle uses a plain `Controller` (not `SingleSelectField`).
64
+ */
65
+ action?: ApprovalActionType;
66
+ /**
67
+ * Drives the value picker variant. Wrapped because the dropdown is
68
+ * `SingleSelectField`-driven (writes `{allOptions, selectedOption}`).
69
+ * Readers do `actorKind.selectedOption`.
70
+ */
71
+ actorKind?: {
72
+ allOptions: ApprovalStageActorKind[];
73
+ selectedOption?: ApprovalStageActorKind;
74
+ };
75
+ /**
76
+ * Bound when `actorKind.selectedOption === "specific_person"`.
77
+ * Shape matches `UserMultiSelectField`'s native value so the field
78
+ * can re-use existing avatar rendering and "or" join.
79
+ */
80
+ persons?: {
81
+ allNonUsers: any[];
82
+ allUsers: any[];
83
+ selectedNonUsers: any[];
84
+ selectedUsers: any[];
85
+ };
86
+ /**
87
+ * Bound when `actorKind.selectedOption === "role"`. Wrapped shape
88
+ * (same reason as actorKind). Readers do `selectedRole.selectedOption`.
89
+ */
90
+ selectedRole?: {
91
+ allOptions: AttributeType[];
92
+ selectedOption?: AttributeType;
93
+ };
94
+ }
95
+ export interface ApprovalStageRowProps {
96
+ /** Pool of users surfaced by the "Specific Person" multi-select. */
97
+ allUsers: User[];
98
+ /** When `false`, the trash icon is dimmed and inert. */
99
+ canRemove: boolean;
100
+ /**
101
+ * Base react-hook-form path for this row (e.g. `"steps.0"`). Inner
102
+ * controls suffix `.action`, `.actorKind`, `.persons`,
103
+ * `.selectedRole` as needed. The shape mirrors `ApprovalStageData`
104
+ * defined alongside the parent section.
105
+ */
106
+ fieldNameBase: string;
107
+ /** Zero-based index of this row within the parent's stage list. */
108
+ index: number;
109
+ /** Called when the user clicks the trash icon. */
110
+ onRemove: () => void;
111
+ /**
112
+ * Called continuously while the user drags one stage over another,
113
+ * once the cursor crosses the hover target's vertical midpoint.
114
+ * Optional — when omitted the row is rendered as inert (no drag
115
+ * handlers attached). The parent owns the reorder mutation; this
116
+ * callback receives the two indices to swap.
117
+ */
118
+ onReorder?: (dragIndex: number, hoverIndex: number) => void;
119
+ }
120
+ export declare function ApprovalStageRow({ index, fieldNameBase, allUsers, onRemove, canRemove, onReorder, }: ApprovalStageRowProps): import("react/jsx-runtime").JSX.Element;
121
+ export default ApprovalStageRow;
@@ -0,0 +1,66 @@
1
+ import { User } from '@zeniai/client-epic-state';
2
+ /**
3
+ * Approval Rules 3.0 — Set Approval Stages form section.
4
+ *
5
+ * Renders the third FormSection of the rule create/edit form. Holds:
6
+ *
7
+ * ┌────────────────────────────────────────────────────────────┐
8
+ * │ 1. [Require|Notify] [Specific Person ▾] [users…] [🗑] │
9
+ * │ 2. [Require|Notify] [Role ▾] [Manager ▾] [🗑] │
10
+ * │ Clear All ⊕ Add Approval Stage │
11
+ * │ ───────────────────────────────────────────────────────── │
12
+ * │ Separation of Duties ⏺ │
13
+ * │ Enabling separation of duties prevent ... │
14
+ * └────────────────────────────────────────────────────────────┘
15
+ *
16
+ * Stage rows are owned by `formData.steps`. The component reads the
17
+ * list length from form state via `useWatch` indirectly through the
18
+ * stagesValue prop, and lets the parent own the add / remove / clear
19
+ * actions (mirroring the ConditionRow pattern). The parent is also
20
+ * responsible for translating the form-data shape to canonical
21
+ * `Step[]` at save time in the screen connector.
22
+ *
23
+ * The Separation of Duties toggle sits inside the same FormSection
24
+ * card per product spec — SoD is a stage-modifier, so visually it
25
+ * belongs with the stages it modifies.
26
+ */
27
+ export interface ApprovalStagesSectionProps {
28
+ /**
29
+ * Pool of users surfaced inside the "Specific Person" multi-select
30
+ * on each row. Resolved by the parent — in production, this is the
31
+ * tenant's filtered approver list.
32
+ */
33
+ allUsers: User[];
34
+ /** Form-state key for the SoD boolean toggle. */
35
+ separationOfDutiesFieldName: string;
36
+ /**
37
+ * Stage 'fields' produced by 'useFieldArray' in the parent. Each
38
+ * carries a stable 'id' the section uses as the React key so React
39
+ * physically reorders DOM nodes on drag-drop — which in turn
40
+ * forces each row's 'index' / 'fieldNameBase' props to update and
41
+ * its Controllers to re-bind to the new form-state paths. Keying
42
+ * by index instead silently broke drag-and-drop because the
43
+ * positionally-keyed rows kept stale Controller bindings.
44
+ */
45
+ stageFields: ReadonlyArray<{
46
+ id: string;
47
+ }>;
48
+ /**
49
+ * Form-state key prefix for stage rows — typically `"steps"`. Each
50
+ * row's full path is `${stagesFieldName}.${index}`.
51
+ */
52
+ stagesFieldName: string;
53
+ onAddStage: () => void;
54
+ onClearAllStages: () => void;
55
+ onRemoveStage: (index: number) => void;
56
+ /**
57
+ * Called when the user drops a dragged stage row onto another row.
58
+ * The parent re-orders the form-state 'steps' array so the new
59
+ * order propagates to the save payload via the existing
60
+ * 'createSteps' iteration. Optional — when omitted the rows render
61
+ * without drag handlers attached (handle stays visible but inert).
62
+ */
63
+ onReorderStages?: (dragIndex: number, hoverIndex: number) => void;
64
+ }
65
+ export declare function ApprovalStagesSection({ allUsers, stageFields, stagesFieldName, separationOfDutiesFieldName, onAddStage, onClearAllStages, onRemoveStage, onReorderStages, }: ApprovalStagesSectionProps): import("react/jsx-runtime").JSX.Element;
66
+ export default ApprovalStagesSection;
@@ -0,0 +1,78 @@
1
+ import { ConditionType } from '@zeniai/client-epic-state';
2
+ /**
3
+ * `ConditionType` is re-exported here so existing import sites in
4
+ * `web-components` (BillPay + Reimbursement detail pages, stories)
5
+ * keep working unchanged. The canonical definition lives in
6
+ * `client-epic-state` (derived from `Criteria["type"]`) so the UI
7
+ * discriminator can't drift from the data model.
8
+ */
9
+ export type { ConditionType };
10
+ /**
11
+ * Approval Rules 3.0 — unified condition row.
12
+ *
13
+ * A single row in the Set Conditions section, laid out as one
14
+ * horizontal line:
15
+ *
16
+ * [ Type ▾ ] [ Operator/Comparator ] [ Value(s) ] [ 🗑 ]
17
+ *
18
+ * For Amount: operator slot holds the comparator dropdown
19
+ * (Greater than / Less than / Between), and the value slot is one
20
+ * number input (or two for "Between"). For Vendor / Department: the
21
+ * operator slot is a segmented `is` / `is not` toggle, and the value
22
+ * slot is a multi-select of vendor or department names.
23
+ *
24
+ * Form-state model — controls bind directly to the existing form
25
+ * paths used by the (now-deprecated for screen use) per-variant rows:
26
+ * - `amountCriteria.comparator`, `amountCriteria.min.amount`,
27
+ * `amountCriteria.max.amount`
28
+ * - `vendorCriteria.operator`, `vendorCriteria.selection`
29
+ * - `departmentCriteria.operator`, `departmentCriteria.selection`
30
+ *
31
+ * The "list of conditions" is a *visual* construct owned by the
32
+ * parent: it tracks the ordered list of active types and renders one
33
+ * ConditionRow per type. When a row is removed the parent clears the
34
+ * relevant form slot so the payload mapper drops the condition. The
35
+ * leading type dropdown is parent-controlled (not bound to
36
+ * react-hook-form) because that list is the source of truth.
37
+ *
38
+ * Per task #11 (clear-all UX): the Amount row is non-removable. Its
39
+ * trash icon is rendered but visually dimmed and disabled so the row
40
+ * keeps its horizontal alignment with removable rows.
41
+ *
42
+ * Visual polish (this iteration):
43
+ * 1. Each control sits inside a `ControlCard` styled wrapper that
44
+ * paints the design-system border + background so the raw
45
+ * react-select primitives don't expose their default UA outlines.
46
+ * 2. The `is` / `is_not` operator is a binary segmented toggle
47
+ * (built inline below) rather than a dropdown, matching the
48
+ * target design.
49
+ * 3. The multi-select primitive keeps its built-in
50
+ * focused → chips / blurred → comma-text rendering — changing
51
+ * that requires modifying the shared `MultiSelectField`, which
52
+ * every other consumer depends on. Flagged as a follow-up.
53
+ */
54
+ export interface ConditionRowProps {
55
+ availableTypes: readonly ConditionType[];
56
+ /** When `false`, the trash icon is dimmed and inert. */
57
+ canRemove: boolean;
58
+ index: number;
59
+ rowType: ConditionType;
60
+ /**
61
+ * Types currently used by *other* rows (i.e. excludes this row's own
62
+ * type). They are filtered out of the dropdown so the user can't
63
+ * create duplicates.
64
+ */
65
+ usedTypes: ReadonlySet<ConditionType>;
66
+ /** Department multi-select options + label lookup. */
67
+ allDepartmentIds?: string[];
68
+ /** Vendor multi-select options + label lookup. */
69
+ allVendorIds?: string[];
70
+ /** Forwarded to the amount value input when `rowType === "amount"`. */
71
+ currencySymbol?: string;
72
+ departmentNamesById?: Record<string, string>;
73
+ vendorNamesById?: Record<string, string>;
74
+ onRemove: () => void;
75
+ onTypeChange: (next: ConditionType) => void;
76
+ }
77
+ export declare function ConditionRow({ rowType, index, availableTypes, usedTypes, onTypeChange, onRemove, canRemove, currencySymbol, allVendorIds, vendorNamesById, allDepartmentIds, departmentNamesById, }: ConditionRowProps): import("react/jsx-runtime").JSX.Element;
78
+ export default ConditionRow;
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Form-state keys used by the department condition group.
3
+ *
4
+ * The form-side split (operator + selection multi-select) mirrors
5
+ * VendorConditionRow. The screen connector reads
6
+ * `selection.selectedOptions` and translates to the canonical
7
+ * `DepartmentCriteria.departmentIds` at save time.
8
+ */
9
+ export declare const DEPARTMENT_CRITERIA_FIELD = "departmentCriteria";
10
+ export declare const DEPARTMENT_OPERATOR_FIELD = "departmentCriteria.operator";
11
+ export declare const DEPARTMENT_SELECTION_FIELD = "departmentCriteria.selection";
12
+ export interface DepartmentConditionRowProps {
13
+ /**
14
+ * All department IDs the user can choose from. Display names are
15
+ * resolved via `departmentNamesById`. In this codebase "department"
16
+ * maps to the Class entity, so this is `classId` for each Class.
17
+ */
18
+ allDepartmentIds: string[];
19
+ departmentNamesById: Record<string, string>;
20
+ }
21
+ export declare function DepartmentConditionRow({ allDepartmentIds, departmentNamesById, }: DepartmentConditionRowProps): import("react/jsx-runtime").JSX.Element;
22
+ export default DepartmentConditionRow;
@@ -0,0 +1,28 @@
1
+ import { BillPayApprovalRuleWithUser, RemiApprovalRuleWithUser } from '@zeniai/client-epic-state';
2
+ /**
3
+ * Shared shape across the two product-specific selectors. Same alias used
4
+ * in ApprovalRuleSection.
5
+ */
6
+ export type ApprovalRuleWithUser = BillPayApprovalRuleWithUser | RemiApprovalRuleWithUser;
7
+ export interface FallbackEngineBannerProps {
8
+ /**
9
+ * The explicit fallback rule for this list, if the tenant has configured
10
+ * one (i.e. `approvalRule.isFallback === true`). When undefined, the
11
+ * banner renders a placeholder approver list derived from the default
12
+ * non-user actor labels. Final copy for the default case is still TBD;
13
+ * we use existing locale strings for now and swap when product confirms.
14
+ */
15
+ fallbackRule?: ApprovalRuleWithUser;
16
+ }
17
+ /**
18
+ * Top-of-list-page banner that surfaces which approvers will be requested
19
+ * when no other approval rule matches a bill / reimbursement.
20
+ *
21
+ * Per Rubal's feedback in the handoff call, the approver list is rendered
22
+ * as a flat "Vendor Owner or Manager or Admin" listing — replacing the
23
+ * old arrow-flow format. Both branches (explicit fallback rule vs.
24
+ * default trio) render through the same actor-list path so the styling
25
+ * stays consistent.
26
+ */
27
+ declare const FallbackEngineBanner: ({ fallbackRule }: FallbackEngineBannerProps) => import("react/jsx-runtime").JSX.Element;
28
+ export default FallbackEngineBanner;
@@ -0,0 +1,26 @@
1
+ import { ResponsiveSized } from '../../../context/windowSizeProvider';
2
+ /**
3
+ * A labelled section wrapper for the approval-rule create/edit form.
4
+ *
5
+ * Renders a bold heading + lighter subheading above a bordered card
6
+ * holding the section's controls. Used to break the form into
7
+ * "Add Rule", "Set Conditions", and "Set Approval Stages" groups so
8
+ * each chunk of the rule is visually separated.
9
+ */
10
+ /**
11
+ * Layout constants for the create / edit approval-rule form column.
12
+ *
13
+ * Exported so other components sharing the column (e.g. the overlap
14
+ * warning banner that sits above the FormSections) can match the same
15
+ * responsive width and stay in vertical alignment with the cards.
16
+ */
17
+ export declare const D: {
18
+ width: ResponsiveSized;
19
+ };
20
+ export interface FormSectionProps {
21
+ children: React.ReactNode;
22
+ heading: string;
23
+ subheading: string;
24
+ }
25
+ export declare function FormSection({ heading, subheading, children }: FormSectionProps): import("react/jsx-runtime").JSX.Element;
26
+ export default FormSection;
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Approval Rules 3.0 — "Proceed with overlapping rules?" confirmation.
3
+ *
4
+ * Mounted by the BillPay / Reimbursement detail page when the user
5
+ * clicks "Ignore & Proceed" in RuleOverlapBanner. Cancel returns to
6
+ * the form with no side effects (banner remains visible); Proceed
7
+ * dispatches the underlying save. This is the second-stage gate on
8
+ * top of the banner itself — once the user acknowledges the overlap,
9
+ * the rule is created / updated as-is.
10
+ *
11
+ * Thin wrapper over the shared ConfirmationPopup, kept as a named
12
+ * file so the wiring side reads naturally and so the copy lives in
13
+ * one place.
14
+ */
15
+ export interface IgnoreOverlapModalProps {
16
+ /** True while the underlying save dispatch is in flight. */
17
+ isLoading?: boolean;
18
+ onCancel: () => void;
19
+ onProceed: () => void;
20
+ }
21
+ declare const IgnoreOverlapModal: ({ onCancel, onProceed, isLoading, }: IgnoreOverlapModalProps) => import("react/jsx-runtime").JSX.Element;
22
+ export default IgnoreOverlapModal;
@@ -0,0 +1,23 @@
1
+ /**
2
+ * The `is` / `is_not` operator used by both vendor and department
3
+ * condition rows. Extracted so the option list, locale labels, and
4
+ * binding shape stay identical between rows.
5
+ */
6
+ export type IsOrIsNotOperator = "is" | "is_not";
7
+ export interface OperatorIsOrIsNotPickerProps {
8
+ /**
9
+ * The label rendered to the left of the picker (e.g. "Vendor"
10
+ * or "Department"). Each row chooses its own copy so the picker
11
+ * row reads naturally as "Vendor is …" / "Department is not …".
12
+ */
13
+ label: string;
14
+ /**
15
+ * Full react-hook-form path to the operator value. Typical values:
16
+ * - `vendorCriteria.operator`
17
+ * - `departmentCriteria.operator`
18
+ */
19
+ name: string;
20
+ defaultOperator?: IsOrIsNotOperator;
21
+ }
22
+ export declare function OperatorIsOrIsNotPicker({ label, name, defaultOperator, }: OperatorIsOrIsNotPickerProps): import("react/jsx-runtime").JSX.Element;
23
+ export default OperatorIsOrIsNotPicker;
@@ -0,0 +1,61 @@
1
+ import { RuleOverlap } from '@zeniai/client-epic-state';
2
+ import { ApprovalRuleWithUser } from './RuleOverlapCard';
3
+ /**
4
+ * Approval Rules 3.0 — frontend overlap warning surface.
5
+ *
6
+ * Sits above the Add Rule / detail form when 'detectRuleOverlap'
7
+ * returns a non-empty list. Outer width matches the form column
8
+ * (same 'FormSection.D.width' tuple) so the banner stacks cleanly
9
+ * above the first SectionCard.
10
+ *
11
+ * Structure (per design):
12
+ * ┌─[gold border]──────────────────────────────────────┐
13
+ * │ [warm warning fill — header only] │
14
+ * │ ⚠ Partial rule overlap detected │
15
+ * │ Conditions partially overlap with… │
16
+ * ├────────────────────────────────────────────────────┤
17
+ * │ [grey-5 surface — body] │
18
+ * │ ┌─ inner rule card ───────────────────────────┐ │
19
+ * │ │ Rule name [SoD][Set at Priority] │ │
20
+ * │ │ Description │ │
21
+ * │ │ When: [chip] [chip] │ │
22
+ * │ │ Then: 1. Require approval from … │ │
23
+ * │ └─────────────────────────────────────────────┘ │
24
+ * │ [Ignore & Proceed] [Edit] │
25
+ * └────────────────────────────────────────────────────┘
26
+ *
27
+ * Colors are explicit static tokens per the design (not theme-
28
+ * adaptive) — the warning surface stays warm-amber in both themes,
29
+ * the body stays light, the rule card stays white. See the styled
30
+ * components below for the token-by-token mapping.
31
+ *
32
+ * Action buttons sit at the bottom-right of the body. 'Ignore &
33
+ * Proceed' fires the parent's save flow as-is. 'Edit Existing Rule'
34
+ * navigates same-tab to the conflicting rule's detail page; when
35
+ * multiple overlaps are present we suppress this button because it
36
+ * has no unambiguous target — the user can pick a card via its own
37
+ * header context (TODO: multi-overlap design pass).
38
+ */
39
+ export interface RuleOverlapBannerProps {
40
+ overlaps: RuleOverlap<ApprovalRuleWithUser>[];
41
+ departmentNamesById?: Record<string, string>;
42
+ /**
43
+ * Disables both action buttons while the page is in an in-flight
44
+ * save (so the user can't double-fire or navigate away mid-write).
45
+ */
46
+ disableButtons?: boolean;
47
+ vendorNamesById?: Record<string, string>;
48
+ /**
49
+ * Called when the user clicks Edit Existing Rule. The parent's
50
+ * connector navigates same-tab to that rule's edit page. Only
51
+ * invoked when 'overlaps.length === 1'.
52
+ */
53
+ onEditExistingRule: (ruleId: string) => void;
54
+ /**
55
+ * Called when the user accepts the overlap and wants the save to
56
+ * proceed. The parent dispatches the underlying save here.
57
+ */
58
+ onIgnoreAndProceed: () => void;
59
+ }
60
+ declare const RuleOverlapBanner: ({ overlaps, vendorNamesById, departmentNamesById, onIgnoreAndProceed, onEditExistingRule, disableButtons, }: RuleOverlapBannerProps) => import("react/jsx-runtime").JSX.Element | null;
61
+ export default RuleOverlapBanner;
@@ -0,0 +1,31 @@
1
+ import { BillPayApprovalRuleWithUser, RemiApprovalRuleWithUser } from '@zeniai/client-epic-state';
2
+ /**
3
+ * Shared shape across the two product-specific selectors. Same alias
4
+ * used in ApprovalRuleSection / FallbackEngineBanner. We accept the
5
+ * full `WithUser` shape (not just a structural subset) because the
6
+ * card renders steps with resolved user names.
7
+ */
8
+ export type ApprovalRuleWithUser = BillPayApprovalRuleWithUser | RemiApprovalRuleWithUser;
9
+ /**
10
+ * Approval Rules 3.0 — per-rule overlap row inside RuleOverlapBanner.
11
+ *
12
+ * Renders the conflicting rule almost identically to the list-page
13
+ * card (ApprovalRuleSection): name + Priority pill + optional SoD
14
+ * pill on the right, description below, then 'When:' chips and
15
+ * 'Then:' step list. The kebab + edit/delete actions are intentionally
16
+ * omitted — the Edit Existing Rule CTA lives at the banner level and
17
+ * acts on the rule that this card represents.
18
+ *
19
+ * The chip / step rendering is duplicated from ApprovalRuleSection
20
+ * rather than extracted to a shared file: the two surfaces have
21
+ * different surrounding chrome and the helpers are small. If a third
22
+ * consumer ever needs them, extract at that point.
23
+ */
24
+ export interface RuleOverlapCardProps {
25
+ departmentNamesById: Record<string, string>;
26
+ rule: ApprovalRuleWithUser;
27
+ vendorNamesById: Record<string, string>;
28
+ dataTestId?: string;
29
+ }
30
+ declare const RuleOverlapCard: ({ rule, vendorNamesById, departmentNamesById, dataTestId, }: RuleOverlapCardProps) => import("react/jsx-runtime").JSX.Element;
31
+ export default RuleOverlapCard;
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Approval Rules 3.0 — boolean toggle primitive.
3
+ *
4
+ * Inline iOS-style switch built locally rather than pulling in a new
5
+ * dependency, because (a) the project does not export a Switch /
6
+ * Toggle field, and (b) the two current consumers (the Separation of
7
+ * Duties toggle inside Set Approval Stages, and the "Set as default
8
+ * fallback" toggle inside Add Rule) want the same shape.
9
+ *
10
+ * The control writes a bare boolean to form state under the supplied
11
+ * field name — no {allOptions, selectedOption} wrapping like the
12
+ * shared SingleSelectField. That matches the canonical shape of
13
+ * boolean form slots like isFallback and separationOfDuties so the
14
+ * screen connector reads them directly without normalisation.
15
+ */
16
+ export interface SwitchProps {
17
+ /** react-hook-form field path (e.g. "isFallback" or "separationOfDuties"). */
18
+ name: string;
19
+ /** Optional starting value. Defaults to false. */
20
+ defaultValue?: boolean;
21
+ }
22
+ export declare function Switch({ name, defaultValue }: SwitchProps): import("react/jsx-runtime").JSX.Element;
23
+ export default Switch;