@zeniai/client-epic-state 5.0.83-betaRR3 → 5.0.83-betaRR5

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 (79) hide show
  1. package/lib/entity/aiCfo/aiCfoPayload.d.ts +1 -4
  2. package/lib/entity/aiCfo/aiCfoReducer.js +3 -11
  3. package/lib/entity/aiCfo/aiCfoState.d.ts +0 -19
  4. package/lib/entity/aiCfo/aiCfoState.js +1 -8
  5. package/lib/entity/cardPolicy/policyRecommendationFromUploadEpic.d.ts +3 -2
  6. package/lib/entity/cardPolicy/policyRecommendationFromUploadEpic.js +3 -2
  7. package/lib/epic.d.ts +14 -12
  8. package/lib/epic.js +14 -12
  9. package/lib/esm/entity/aiCfo/aiCfoReducer.js +4 -12
  10. package/lib/esm/entity/aiCfo/aiCfoState.js +0 -7
  11. package/lib/esm/entity/cardPolicy/policyRecommendationFromUploadEpic.js +4 -3
  12. package/lib/esm/epic.js +14 -12
  13. package/lib/esm/index.js +14 -3
  14. package/lib/esm/view/spendManagement/chargeCards/cardPolicy/createCardPolicy/applyAiCardPolicyFormDraftUpdate.js +328 -0
  15. package/lib/esm/view/spendManagement/chargeCards/cardPolicy/createCardPolicy/applyExtractedPolicyToAiCardPolicyDraft.js +120 -0
  16. package/lib/esm/view/spendManagement/chargeCards/cardPolicy/createCardPolicy/applyExtractedPolicyToDraftEpic.js +60 -0
  17. package/lib/esm/view/spendManagement/chargeCards/cardPolicy/createCardPolicy/applyExtractedPolicyToManualCardPolicyDraft.js +118 -0
  18. package/lib/esm/view/spendManagement/chargeCards/cardPolicy/createCardPolicy/applyUploadPlanToAiCardPolicyDraft.js +33 -0
  19. package/lib/esm/view/spendManagement/chargeCards/cardPolicy/createCardPolicy/buildAiCardPolicyFormDraftSeed.js +385 -0
  20. package/lib/esm/view/spendManagement/chargeCards/cardPolicy/createCardPolicy/buildManualCardPolicyFormDraftSeed.js +34 -0
  21. package/lib/esm/view/spendManagement/chargeCards/cardPolicy/createCardPolicy/cardPolicyChipIds.js +33 -0
  22. package/lib/esm/view/spendManagement/chargeCards/cardPolicy/createCardPolicy/cardPolicyFormDraftTypes.js +17 -0
  23. package/lib/esm/view/spendManagement/chargeCards/cardPolicy/createCardPolicy/cardPolicyRequestParts.js +144 -0
  24. package/lib/esm/view/spendManagement/chargeCards/cardPolicy/createCardPolicy/createCardPolicyReducer.js +137 -1
  25. package/lib/esm/view/spendManagement/chargeCards/cardPolicy/createCardPolicy/createCardPolicySelector.js +18 -0
  26. package/lib/esm/view/spendManagement/chargeCards/cardPolicy/createCardPolicy/deriveAiPolicyReviewRowsFromInputs.js +148 -0
  27. package/lib/esm/view/spendManagement/chargeCards/cardPolicy/createCardPolicy/seedAiCardPolicyFormDraftEpic.js +112 -0
  28. package/lib/esm/view/spendManagement/chargeCards/cardPolicy/createCardPolicy/toBulkCardPolicyTemplateRequestsFromDraft.js +101 -0
  29. package/lib/esm/view/spendManagement/chargeCards/cardPolicy/createCardPolicy/toCardPolicyTemplateRequestFromDraft.js +71 -0
  30. package/lib/esm/view/spendManagement/chargeCards/cardPolicy/createCardPolicy/toManualCardPolicyTemplateRequestFromDraft.js +34 -0
  31. package/lib/esm/view/spendManagement/chargeCards/issueChargeCard/applyAiCardCreationFormDraftUpdate.js +0 -1
  32. package/lib/esm/view/spendManagement/chargeCards/issueChargeCard/buildAiCardCreationFormDraftSeed.js +13 -6
  33. package/lib/esm/view/spendManagement/chargeCards/issueChargeCard/deriveAiCardRowsFromTeams.js +1 -3
  34. package/lib/esm/view/spendManagement/chargeCards/issueChargeCard/toIssueChargeCardLocalDataFromDraft.js +0 -5
  35. package/lib/index.d.ts +20 -4
  36. package/lib/index.js +45 -4
  37. package/lib/view/spendManagement/chargeCards/cardPolicy/createCardPolicy/applyAiCardPolicyFormDraftUpdate.d.ts +38 -0
  38. package/lib/view/spendManagement/chargeCards/cardPolicy/createCardPolicy/applyAiCardPolicyFormDraftUpdate.js +333 -0
  39. package/lib/view/spendManagement/chargeCards/cardPolicy/createCardPolicy/applyExtractedPolicyToAiCardPolicyDraft.d.ts +25 -0
  40. package/lib/view/spendManagement/chargeCards/cardPolicy/createCardPolicy/applyExtractedPolicyToAiCardPolicyDraft.js +124 -0
  41. package/lib/view/spendManagement/chargeCards/cardPolicy/createCardPolicy/applyExtractedPolicyToDraftEpic.d.ts +28 -0
  42. package/lib/view/spendManagement/chargeCards/cardPolicy/createCardPolicy/applyExtractedPolicyToDraftEpic.js +64 -0
  43. package/lib/view/spendManagement/chargeCards/cardPolicy/createCardPolicy/applyExtractedPolicyToManualCardPolicyDraft.d.ts +17 -0
  44. package/lib/view/spendManagement/chargeCards/cardPolicy/createCardPolicy/applyExtractedPolicyToManualCardPolicyDraft.js +122 -0
  45. package/lib/view/spendManagement/chargeCards/cardPolicy/createCardPolicy/applyUploadPlanToAiCardPolicyDraft.d.ts +23 -0
  46. package/lib/view/spendManagement/chargeCards/cardPolicy/createCardPolicy/applyUploadPlanToAiCardPolicyDraft.js +37 -0
  47. package/lib/view/spendManagement/chargeCards/cardPolicy/createCardPolicy/buildAiCardPolicyFormDraftSeed.d.ts +38 -0
  48. package/lib/view/spendManagement/chargeCards/cardPolicy/createCardPolicy/buildAiCardPolicyFormDraftSeed.js +391 -0
  49. package/lib/view/spendManagement/chargeCards/cardPolicy/createCardPolicy/buildManualCardPolicyFormDraftSeed.d.ts +11 -0
  50. package/lib/view/spendManagement/chargeCards/cardPolicy/createCardPolicy/buildManualCardPolicyFormDraftSeed.js +38 -0
  51. package/lib/view/spendManagement/chargeCards/cardPolicy/createCardPolicy/cardPolicyChipIds.d.ts +24 -0
  52. package/lib/view/spendManagement/chargeCards/cardPolicy/createCardPolicy/cardPolicyChipIds.js +40 -0
  53. package/lib/view/spendManagement/chargeCards/cardPolicy/createCardPolicy/cardPolicyFormDraftTypes.d.ts +253 -0
  54. package/lib/view/spendManagement/chargeCards/cardPolicy/createCardPolicy/cardPolicyFormDraftTypes.js +21 -0
  55. package/lib/view/spendManagement/chargeCards/cardPolicy/createCardPolicy/cardPolicyRequestParts.d.ts +66 -0
  56. package/lib/view/spendManagement/chargeCards/cardPolicy/createCardPolicy/cardPolicyRequestParts.js +151 -0
  57. package/lib/view/spendManagement/chargeCards/cardPolicy/createCardPolicy/createCardPolicyReducer.d.ts +40 -1
  58. package/lib/view/spendManagement/chargeCards/cardPolicy/createCardPolicy/createCardPolicyReducer.js +138 -2
  59. package/lib/view/spendManagement/chargeCards/cardPolicy/createCardPolicy/createCardPolicySelector.d.ts +15 -0
  60. package/lib/view/spendManagement/chargeCards/cardPolicy/createCardPolicy/createCardPolicySelector.js +20 -0
  61. package/lib/view/spendManagement/chargeCards/cardPolicy/createCardPolicy/createCardPolicyState.d.ts +28 -0
  62. package/lib/view/spendManagement/chargeCards/cardPolicy/createCardPolicy/deriveAiPolicyReviewRowsFromInputs.d.ts +30 -0
  63. package/lib/view/spendManagement/chargeCards/cardPolicy/createCardPolicy/deriveAiPolicyReviewRowsFromInputs.js +152 -0
  64. package/lib/view/spendManagement/chargeCards/cardPolicy/createCardPolicy/seedAiCardPolicyFormDraftEpic.d.ts +26 -0
  65. package/lib/view/spendManagement/chargeCards/cardPolicy/createCardPolicy/seedAiCardPolicyFormDraftEpic.js +116 -0
  66. package/lib/view/spendManagement/chargeCards/cardPolicy/createCardPolicy/toBulkCardPolicyTemplateRequestsFromDraft.d.ts +35 -0
  67. package/lib/view/spendManagement/chargeCards/cardPolicy/createCardPolicy/toBulkCardPolicyTemplateRequestsFromDraft.js +105 -0
  68. package/lib/view/spendManagement/chargeCards/cardPolicy/createCardPolicy/toCardPolicyTemplateRequestFromDraft.d.ts +23 -0
  69. package/lib/view/spendManagement/chargeCards/cardPolicy/createCardPolicy/toCardPolicyTemplateRequestFromDraft.js +75 -0
  70. package/lib/view/spendManagement/chargeCards/cardPolicy/createCardPolicy/toManualCardPolicyTemplateRequestFromDraft.d.ts +15 -0
  71. package/lib/view/spendManagement/chargeCards/cardPolicy/createCardPolicy/toManualCardPolicyTemplateRequestFromDraft.js +38 -0
  72. package/lib/view/spendManagement/chargeCards/issueChargeCard/aiCardCreationFormDraftTypes.d.ts +3 -6
  73. package/lib/view/spendManagement/chargeCards/issueChargeCard/applyAiCardCreationFormDraftUpdate.js +0 -1
  74. package/lib/view/spendManagement/chargeCards/issueChargeCard/buildAiCardCreationFormDraftSeed.d.ts +6 -3
  75. package/lib/view/spendManagement/chargeCards/issueChargeCard/buildAiCardCreationFormDraftSeed.js +13 -6
  76. package/lib/view/spendManagement/chargeCards/issueChargeCard/deriveAiCardRowsFromTeams.d.ts +1 -4
  77. package/lib/view/spendManagement/chargeCards/issueChargeCard/deriveAiCardRowsFromTeams.js +1 -3
  78. package/lib/view/spendManagement/chargeCards/issueChargeCard/toIssueChargeCardLocalDataFromDraft.js +0 -5
  79. package/package.json +1 -1
@@ -0,0 +1,391 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.buildUploadReviewRows = exports.buildAiCardPolicyFormDraftSeed = exports.buildEmptyLimitRows = void 0;
4
+ const cardPolicyChipIds_1 = require("./cardPolicyChipIds");
5
+ const cardPolicyFormDraftTypes_1 = require("./cardPolicyFormDraftTypes");
6
+ const EMPTY_ALLOW_BLOCK = {
7
+ mode: 'allow',
8
+ allowItems: [],
9
+ blockItems: [],
10
+ };
11
+ const EMPTY_FORM_VALUES = {
12
+ vendorPolicy: EMPTY_ALLOW_BLOCK,
13
+ categoryPolicy: EMPTY_ALLOW_BLOCK,
14
+ cardSelections: [],
15
+ limits: [],
16
+ policiesReview: [],
17
+ };
18
+ const buildEmptyLimitRows = () => [
19
+ { id: cardPolicyFormDraftTypes_1.CARD_POLICY_LIMIT_ROW_ID_TRANSACTION, isEnabled: false },
20
+ { id: cardPolicyFormDraftTypes_1.CARD_POLICY_LIMIT_ROW_ID_REQUIRE_RECEIPT, isEnabled: false },
21
+ ];
22
+ exports.buildEmptyLimitRows = buildEmptyLimitRows;
23
+ /**
24
+ * Build the initial `CardPolicyFormDraft` + companion seed context for
25
+ * a fresh AI CFO card-policy session. Used by the
26
+ * `seedAiCardPolicyFormDraft` reducer.
27
+ *
28
+ * - `auto` (1-step review): chip groups are built eagerly from each
29
+ * `draftPolicies[i]` since there's no live form to derive from.
30
+ * - `guided` (5-step wizard): Steps 1–4 seeded from `draftPolicies[0]`,
31
+ * Step 5 seeded with one identity-only row per `draftPolicies[i]`;
32
+ * chip groups are re-derived on every `applyAiCardPolicyFormDraftUpdate`.
33
+ * - `upload` (3-step): pre-recommendation returns an empty scaffold;
34
+ * post-recommendation, Step 5 review rows + their chip groups are
35
+ * derived from `wizardPlan.step5Review.draftPolicies`.
36
+ */
37
+ const buildAiCardPolicyFormDraftSeed = ({ initialData, cardsMasterList = [], categorySearchOptions, suggestedAllowMerchants, suggestedBlockMerchants, suggestedAllowCategories, suggestedBlockCategories, }) => {
38
+ const suggestedPoliciesSeed = buildSuggestedPoliciesSeed(initialData);
39
+ const wizardPlan = 'wizardPlan' in initialData ? initialData.wizardPlan : undefined;
40
+ const source = initialData.policyKind === 'upload' ? initialData.source : undefined;
41
+ const context = {
42
+ policyKind: initialData.policyKind,
43
+ cardsMasterList,
44
+ categorySearchOptions: categorySearchOptions ?? [],
45
+ suggestedAllowMerchants,
46
+ suggestedBlockMerchants,
47
+ suggestedAllowCategories,
48
+ suggestedBlockCategories,
49
+ suggestedPoliciesSeed,
50
+ wizardPlan,
51
+ source,
52
+ };
53
+ const draft = buildDraftFromInitialData({
54
+ initialData,
55
+ cardsMasterList,
56
+ categorySearchOptions,
57
+ suggestedAllowMerchants,
58
+ suggestedBlockMerchants,
59
+ suggestedAllowCategories,
60
+ suggestedBlockCategories,
61
+ });
62
+ return { draft, context };
63
+ };
64
+ exports.buildAiCardPolicyFormDraftSeed = buildAiCardPolicyFormDraftSeed;
65
+ const buildDraftFromInitialData = ({ initialData, cardsMasterList, categorySearchOptions, suggestedAllowMerchants, suggestedBlockMerchants, suggestedAllowCategories, suggestedBlockCategories, }) => {
66
+ const vendorAllowSeed = merchantsToChips(suggestedAllowMerchants);
67
+ const vendorBlockSeed = merchantsToChips(suggestedBlockMerchants);
68
+ const categoryAllowSeed = categoriesToChips(suggestedAllowCategories);
69
+ const categoryBlockSeed = categoriesToChips(suggestedBlockCategories);
70
+ if (initialData.policyKind === 'auto') {
71
+ const autoDraftPolicies = initialData.wizardPlan?.step5Review?.draftPolicies ?? [];
72
+ return {
73
+ ...EMPTY_FORM_VALUES,
74
+ policyKind: 'auto',
75
+ policiesReview: buildAutoReviewRows(autoDraftPolicies, cardsMasterList, categorySearchOptions),
76
+ };
77
+ }
78
+ if (initialData.policyKind === 'upload') {
79
+ const uploadDraftPolicies = initialData.wizardPlan?.step5Review?.draftPolicies;
80
+ if (uploadDraftPolicies == null) {
81
+ return {
82
+ ...EMPTY_FORM_VALUES,
83
+ policyKind: 'upload',
84
+ cardSelections: cardsMasterList.map((row) => ({
85
+ ...row,
86
+ isChecked: false,
87
+ })),
88
+ limits: (0, exports.buildEmptyLimitRows)(),
89
+ };
90
+ }
91
+ return {
92
+ ...EMPTY_FORM_VALUES,
93
+ policyKind: 'upload',
94
+ cardSelections: cardsMasterList.map((row) => ({
95
+ ...row,
96
+ isChecked: false,
97
+ })),
98
+ limits: (0, exports.buildEmptyLimitRows)(),
99
+ policiesReview: (0, exports.buildUploadReviewRows)(uploadDraftPolicies, cardsMasterList, categorySearchOptions),
100
+ };
101
+ }
102
+ // Guided
103
+ const draftPolicies = initialData.wizardPlan?.step5Review?.draftPolicies ?? [];
104
+ const primary = draftPolicies[0];
105
+ if (primary == null) {
106
+ return {
107
+ policyKind: 'guided',
108
+ vendorPolicy: buildAllowBlockFromSeeds(vendorAllowSeed, vendorBlockSeed),
109
+ categoryPolicy: buildAllowBlockFromSeeds(categoryAllowSeed, categoryBlockSeed),
110
+ cardSelections: cardsMasterList.map((row) => ({
111
+ ...row,
112
+ isChecked: false,
113
+ })),
114
+ limits: (0, exports.buildEmptyLimitRows)(),
115
+ policiesReview: [],
116
+ };
117
+ }
118
+ const mccCodeToCategory = buildMccCodeToCategoryMap(categorySearchOptions);
119
+ const vendorMode = inferAllowBlockMode(primary.allowedEntity.merchantNames.length, primary.blockedEntity.merchantNames.length);
120
+ const aiVendorAllow = draftMerchantsToChips(primary.allowedEntity.merchantNames);
121
+ const aiVendorBlock = draftMerchantsToChips(primary.blockedEntity.merchantNames);
122
+ const vendorPolicy = {
123
+ mode: vendorMode,
124
+ allowItems: mergeAiAndSeedChips(aiVendorAllow, vendorAllowSeed),
125
+ blockItems: mergeAiAndSeedChips(aiVendorBlock, vendorBlockSeed),
126
+ };
127
+ const categoryMode = inferAllowBlockMode(primary.allowedEntity.categoryCodes.length, primary.blockedEntity.categoryCodes.length);
128
+ const aiCategoryAllow = draftCategoryCodesToChips(primary.allowedEntity.categoryCodes, mccCodeToCategory);
129
+ const aiCategoryBlock = draftCategoryCodesToChips(primary.blockedEntity.categoryCodes, mccCodeToCategory);
130
+ const categoryPolicy = {
131
+ mode: categoryMode,
132
+ allowItems: mergeAiAndSeedChips(aiCategoryAllow, categoryAllowSeed),
133
+ blockItems: mergeAiAndSeedChips(aiCategoryBlock, categoryBlockSeed),
134
+ };
135
+ const cardSelections = cardsMasterList.map((row) => ({
136
+ ...row,
137
+ isChecked: primary.applyToCards.includes(row.id),
138
+ }));
139
+ const limits = [
140
+ {
141
+ id: cardPolicyFormDraftTypes_1.CARD_POLICY_LIMIT_ROW_ID_TRANSACTION,
142
+ isEnabled: primary.spendLimits.transaction > 0,
143
+ amount: primary.spendLimits.transaction > 0
144
+ ? primary.spendLimits.transaction
145
+ : undefined,
146
+ },
147
+ {
148
+ id: cardPolicyFormDraftTypes_1.CARD_POLICY_LIMIT_ROW_ID_REQUIRE_RECEIPT,
149
+ isEnabled: primary.requiredReceiptThreshold > 0,
150
+ amount: primary.requiredReceiptThreshold > 0
151
+ ? primary.requiredReceiptThreshold
152
+ : undefined,
153
+ },
154
+ ];
155
+ return {
156
+ policyKind: 'guided',
157
+ vendorPolicy,
158
+ categoryPolicy,
159
+ cardSelections,
160
+ limits,
161
+ policiesReview: draftPolicies.map((p) => ({
162
+ id: p.id,
163
+ isChecked: true,
164
+ name: p.name,
165
+ chipGroups: [],
166
+ })),
167
+ };
168
+ };
169
+ const buildSuggestedPoliciesSeed = (initialData) => (initialData.wizardPlan?.step5Review?.draftPolicies ?? []).map((draft) => ({
170
+ id: draft.id,
171
+ name: draft.name,
172
+ isChecked: true,
173
+ }));
174
+ const merchantsToChips = (names) => (names ?? []).map((name) => (0, cardPolicyChipIds_1.toVendorChipFieldValue)(name, false));
175
+ const categoriesToChips = (categories) => (categories ?? []).map((category) => (0, cardPolicyChipIds_1.toMccCategoryChipFieldValue)(category, false));
176
+ const buildAllowBlockFromSeeds = (allowItems, blockItems) => {
177
+ if (allowItems.length === 0 && blockItems.length === 0) {
178
+ return EMPTY_ALLOW_BLOCK;
179
+ }
180
+ return { mode: 'allow', allowItems, blockItems };
181
+ };
182
+ const buildMccCodeToCategoryMap = (categories) => {
183
+ const map = new Map();
184
+ for (const category of categories ?? []) {
185
+ for (const code of category.mccCodes) {
186
+ if (!map.has(code)) {
187
+ map.set(code, category);
188
+ }
189
+ }
190
+ }
191
+ return map;
192
+ };
193
+ const buildOwnerSummaries = (cardIds, cardsMasterList) => {
194
+ const cardsById = new Map(cardsMasterList.map((card) => [card.id, card]));
195
+ const summaries = new Map();
196
+ for (const cardId of cardIds) {
197
+ const card = cardsById.get(cardId);
198
+ if (card == null) {
199
+ continue;
200
+ }
201
+ const existing = summaries.get(card.owner.userId);
202
+ if (existing != null) {
203
+ existing.cardIds.push(cardId);
204
+ continue;
205
+ }
206
+ summaries.set(card.owner.userId, {
207
+ userId: card.owner.userId,
208
+ displayName: card.owner.displayName,
209
+ cardIds: [cardId],
210
+ });
211
+ }
212
+ return Array.from(summaries.values());
213
+ };
214
+ const buildAutoReviewChipGroupsForDraft = (draft, cardsMasterList, mccCodeToCategory) => {
215
+ const groups = [];
216
+ if (draft.allowedEntity.merchantNames.length > 0) {
217
+ groups.push({
218
+ id: 'allowed-vendors',
219
+ label: 'Allowed Vendors',
220
+ chips: draft.allowedEntity.merchantNames.map((name) => ({
221
+ id: (0, cardPolicyChipIds_1.buildVendorChipId)(name),
222
+ label: name,
223
+ chipKind: 'positive',
224
+ isSelected: true,
225
+ })),
226
+ });
227
+ }
228
+ if (draft.blockedEntity.merchantNames.length > 0) {
229
+ groups.push({
230
+ id: 'blocked-vendors',
231
+ label: 'Blocked Vendors',
232
+ chips: draft.blockedEntity.merchantNames.map((name) => ({
233
+ id: (0, cardPolicyChipIds_1.buildVendorChipId)(name),
234
+ label: name,
235
+ chipKind: 'negative',
236
+ isSelected: true,
237
+ })),
238
+ });
239
+ }
240
+ if (draft.allowedEntity.categoryCodes.length > 0) {
241
+ groups.push({
242
+ id: 'allowed-categories',
243
+ label: 'Allowed Categories',
244
+ chips: draft.allowedEntity.categoryCodes.map((code) => {
245
+ const category = mccCodeToCategory.get(code);
246
+ const label = category != null ? `${category.name} (${code})` : code;
247
+ return {
248
+ id: code,
249
+ label,
250
+ chipKind: 'positive',
251
+ isSelected: true,
252
+ optionalCode: code,
253
+ };
254
+ }),
255
+ });
256
+ }
257
+ if (draft.blockedEntity.categoryCodes.length > 0) {
258
+ groups.push({
259
+ id: 'restricted-categories',
260
+ label: 'Restricted Categories',
261
+ chips: draft.blockedEntity.categoryCodes.map((code) => {
262
+ const category = mccCodeToCategory.get(code);
263
+ const label = category != null ? `${category.name} (${code})` : code;
264
+ return {
265
+ id: code,
266
+ label,
267
+ chipKind: 'negative',
268
+ isSelected: true,
269
+ optionalCode: code,
270
+ };
271
+ }),
272
+ });
273
+ }
274
+ if (draft.applyToCards.length > 0) {
275
+ const owners = buildOwnerSummaries(draft.applyToCards, cardsMasterList);
276
+ if (owners.length > 0) {
277
+ groups.push({
278
+ id: 'applied-to-cards',
279
+ label: 'Applied to Cards',
280
+ chips: owners.map((owner) => ({
281
+ id: owner.userId,
282
+ label: owner.displayName,
283
+ chipKind: 'avatar',
284
+ cardIds: owner.cardIds,
285
+ isSelected: true,
286
+ })),
287
+ });
288
+ }
289
+ }
290
+ return groups;
291
+ };
292
+ const buildAutoReviewRows = (draftPolicies, cardsMasterList, categorySearchOptions) => {
293
+ const mccCodeToCategory = buildMccCodeToCategoryMap(categorySearchOptions);
294
+ return draftPolicies.map((draft) => ({
295
+ id: draft.id,
296
+ isChecked: true,
297
+ name: draft.name,
298
+ chipGroups: buildAutoReviewChipGroupsForDraft(draft, cardsMasterList, mccCodeToCategory),
299
+ }));
300
+ };
301
+ /**
302
+ * Upload-only "Limits" chip group carrying the draft's
303
+ * `spend_limits.transaction` and `required_receipt_threshold`. Each
304
+ * chip stashes its numeric value on `optionalCode` so the bulk-submit
305
+ * builder can recover it without re-parsing the label.
306
+ */
307
+ const buildUploadLimitsChipGroup = (draft) => {
308
+ const transactionEnabled = draft.spendLimits.transaction > 0;
309
+ const receiptEnabled = draft.requiredReceiptThreshold > 0;
310
+ return {
311
+ id: 'limits',
312
+ label: 'Limits',
313
+ kind: 'limits',
314
+ chips: [
315
+ {
316
+ id: 'limit-transaction',
317
+ label: 'Transaction Limit',
318
+ helperText: 'Maximum amount per single transaction',
319
+ placeholder: '$0',
320
+ chipKind: 'positive',
321
+ isSelected: transactionEnabled,
322
+ optionalCode: transactionEnabled
323
+ ? String(draft.spendLimits.transaction)
324
+ : undefined,
325
+ },
326
+ {
327
+ id: 'limit-receipt',
328
+ label: 'Require Receipt',
329
+ helperText: 'Require a receipt above this amount',
330
+ placeholder: '$0',
331
+ chipKind: 'positive',
332
+ isSelected: receiptEnabled,
333
+ optionalCode: receiptEnabled
334
+ ? String(draft.requiredReceiptThreshold)
335
+ : undefined,
336
+ },
337
+ ],
338
+ };
339
+ };
340
+ const buildUploadReviewRows = (draftPolicies, cardsMasterList, categorySearchOptions) => {
341
+ const mccCodeToCategory = buildMccCodeToCategoryMap(categorySearchOptions);
342
+ return draftPolicies.map((draft) => {
343
+ const chipGroups = buildAutoReviewChipGroupsForDraft(draft, cardsMasterList, mccCodeToCategory);
344
+ chipGroups.push(buildUploadLimitsChipGroup(draft));
345
+ return {
346
+ id: draft.id,
347
+ isChecked: true,
348
+ name: draft.name,
349
+ chipGroups,
350
+ };
351
+ });
352
+ };
353
+ exports.buildUploadReviewRows = buildUploadReviewRows;
354
+ /**
355
+ * Infer the AllowBlock mode for a draft policy field. The BE doesn't
356
+ * tell the FE which radio to pre-select; mirrors the rule used by
357
+ * `applyExtractedPolicyTo*FormValues`:
358
+ *
359
+ * - allow side has any value → `"allow"`
360
+ * - block side has any value → `"block"`
361
+ * - both empty → `"allow"` (default)
362
+ * - both populated → `"allow"` (user can flip the radio to reveal block).
363
+ */
364
+ const inferAllowBlockMode = (allowCount, blockCount) => {
365
+ if (allowCount > 0) {
366
+ return 'allow';
367
+ }
368
+ if (blockCount > 0) {
369
+ return 'block';
370
+ }
371
+ return 'allow';
372
+ };
373
+ const draftMerchantsToChips = (names) => names.map((name) => (0, cardPolicyChipIds_1.toVendorChipFieldValue)(name, true));
374
+ const draftCategoryCodesToChips = (codes, mccCodeToCategory) => codes.map((code) => {
375
+ const category = mccCodeToCategory.get(code);
376
+ if (category != null) {
377
+ return (0, cardPolicyChipIds_1.toMccCategoryChipFieldValue)(category, true);
378
+ }
379
+ return {
380
+ id: code,
381
+ label: code,
382
+ isSelected: true,
383
+ optionalCode: code,
384
+ optionalCodes: [code],
385
+ };
386
+ });
387
+ const mergeAiAndSeedChips = (aiChips, seedChips) => {
388
+ const seenIds = new Set(aiChips.map((chip) => chip.id));
389
+ const extraSeeds = seedChips.filter((chip) => !seenIds.has(chip.id));
390
+ return [...aiChips, ...extraSeeds];
391
+ };
@@ -0,0 +1,11 @@
1
+ import { CardPolicyCardSelectionRow, CardPolicyCreateFormDraft, CardPolicyDefaultSeedSuggestions } from './cardPolicyFormDraftTypes';
2
+ export interface BuildManualCardPolicyFormDraftSeedArgs extends CardPolicyDefaultSeedSuggestions {
3
+ cardsMasterList?: CardPolicyCardSelectionRow[];
4
+ }
5
+ /**
6
+ * Build the initial `CardPolicyCreateFormDraft` for a fresh manual
7
+ * create-page session. Mirrors the AI guided seed minus the wizard
8
+ * plan: every BE-suggested chip lands `isSelected: false` so the user
9
+ * has to opt each suggestion onto the policy explicitly.
10
+ */
11
+ export declare const buildManualCardPolicyFormDraftSeed: ({ cardsMasterList, suggestedAllowMerchants, suggestedBlockMerchants, suggestedAllowCategories, suggestedBlockCategories, }: BuildManualCardPolicyFormDraftSeedArgs) => CardPolicyCreateFormDraft;
@@ -0,0 +1,38 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.buildManualCardPolicyFormDraftSeed = void 0;
4
+ const buildAiCardPolicyFormDraftSeed_1 = require("./buildAiCardPolicyFormDraftSeed");
5
+ const cardPolicyChipIds_1 = require("./cardPolicyChipIds");
6
+ const EMPTY_ALLOW_BLOCK = {
7
+ mode: 'allow',
8
+ allowItems: [],
9
+ blockItems: [],
10
+ };
11
+ /**
12
+ * Build the initial `CardPolicyCreateFormDraft` for a fresh manual
13
+ * create-page session. Mirrors the AI guided seed minus the wizard
14
+ * plan: every BE-suggested chip lands `isSelected: false` so the user
15
+ * has to opt each suggestion onto the policy explicitly.
16
+ */
17
+ const buildManualCardPolicyFormDraftSeed = ({ cardsMasterList = [], suggestedAllowMerchants, suggestedBlockMerchants, suggestedAllowCategories, suggestedBlockCategories, }) => {
18
+ const vendorAllow = (suggestedAllowMerchants ?? []).map((name) => (0, cardPolicyChipIds_1.toVendorChipFieldValue)(name, false));
19
+ const vendorBlock = (suggestedBlockMerchants ?? []).map((name) => (0, cardPolicyChipIds_1.toVendorChipFieldValue)(name, false));
20
+ const categoryAllow = (suggestedAllowCategories ?? []).map((category) => (0, cardPolicyChipIds_1.toMccCategoryChipFieldValue)(category, false));
21
+ const categoryBlock = (suggestedBlockCategories ?? []).map((category) => (0, cardPolicyChipIds_1.toMccCategoryChipFieldValue)(category, false));
22
+ const vendorPolicy = vendorAllow.length === 0 && vendorBlock.length === 0
23
+ ? EMPTY_ALLOW_BLOCK
24
+ : { mode: 'allow', allowItems: vendorAllow, blockItems: vendorBlock };
25
+ const categoryPolicy = categoryAllow.length === 0 && categoryBlock.length === 0
26
+ ? EMPTY_ALLOW_BLOCK
27
+ : { mode: 'allow', allowItems: categoryAllow, blockItems: categoryBlock };
28
+ return {
29
+ name: '',
30
+ description: '',
31
+ mode: 'strict',
32
+ vendorPolicy,
33
+ categoryPolicy,
34
+ cardSelections: cardsMasterList.map((row) => ({ ...row, isChecked: false })),
35
+ limits: (0, buildAiCardPolicyFormDraftSeed_1.buildEmptyLimitRows)(),
36
+ };
37
+ };
38
+ exports.buildManualCardPolicyFormDraftSeed = buildManualCardPolicyFormDraftSeed;
@@ -0,0 +1,24 @@
1
+ import type { CardPolicyChipFieldValue, MccCategoryLike } from './cardPolicyFormDraftTypes';
2
+ /**
3
+ * Centralized chip-id derivation so seeds, search-dropdown rows,
4
+ * saved-template recoveries, and the dedupe logic in
5
+ * `AllowBlockChipPicker.handleAddItem` all key off the **same** id for
6
+ * the same logical entity.
7
+ *
8
+ * The dedupe path is content-blind (`existing.id === option.id`): if
9
+ * the id strings don't match, the picker treats the option as a new
10
+ * chip and appends a duplicate. Every producer of chip values for the
11
+ * card-policy flow MUST funnel through these helpers.
12
+ *
13
+ * - Vendors: `vendor-${name.trim().toLowerCase()}`. Two vendors that
14
+ * share an identical display name collapse into one chip.
15
+ * - MCC categories: `mcc-${name}`. Matches the legacy
16
+ * `toCategoryChipOption` convention so the saved-template loader
17
+ * keeps recovering chips by id.
18
+ */
19
+ export declare const VENDOR_CHIP_ID_PREFIX = "vendor-";
20
+ export declare const MCC_CHIP_ID_PREFIX = "mcc-";
21
+ export declare const buildVendorChipId: (name: string) => string;
22
+ export declare const buildMccCategoryChipId: (name: string) => string;
23
+ export declare const toVendorChipFieldValue: (name: string, isSelected: boolean) => CardPolicyChipFieldValue;
24
+ export declare const toMccCategoryChipFieldValue: (category: MccCategoryLike, isSelected: boolean) => CardPolicyChipFieldValue;
@@ -0,0 +1,40 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.toMccCategoryChipFieldValue = exports.toVendorChipFieldValue = exports.buildMccCategoryChipId = exports.buildVendorChipId = exports.MCC_CHIP_ID_PREFIX = exports.VENDOR_CHIP_ID_PREFIX = void 0;
4
+ /**
5
+ * Centralized chip-id derivation so seeds, search-dropdown rows,
6
+ * saved-template recoveries, and the dedupe logic in
7
+ * `AllowBlockChipPicker.handleAddItem` all key off the **same** id for
8
+ * the same logical entity.
9
+ *
10
+ * The dedupe path is content-blind (`existing.id === option.id`): if
11
+ * the id strings don't match, the picker treats the option as a new
12
+ * chip and appends a duplicate. Every producer of chip values for the
13
+ * card-policy flow MUST funnel through these helpers.
14
+ *
15
+ * - Vendors: `vendor-${name.trim().toLowerCase()}`. Two vendors that
16
+ * share an identical display name collapse into one chip.
17
+ * - MCC categories: `mcc-${name}`. Matches the legacy
18
+ * `toCategoryChipOption` convention so the saved-template loader
19
+ * keeps recovering chips by id.
20
+ */
21
+ exports.VENDOR_CHIP_ID_PREFIX = 'vendor-';
22
+ exports.MCC_CHIP_ID_PREFIX = 'mcc-';
23
+ const buildVendorChipId = (name) => `${exports.VENDOR_CHIP_ID_PREFIX}${name.trim().toLowerCase()}`;
24
+ exports.buildVendorChipId = buildVendorChipId;
25
+ const buildMccCategoryChipId = (name) => `${exports.MCC_CHIP_ID_PREFIX}${name}`;
26
+ exports.buildMccCategoryChipId = buildMccCategoryChipId;
27
+ const toVendorChipFieldValue = (name, isSelected) => ({
28
+ id: (0, exports.buildVendorChipId)(name),
29
+ label: name,
30
+ isSelected,
31
+ });
32
+ exports.toVendorChipFieldValue = toVendorChipFieldValue;
33
+ const toMccCategoryChipFieldValue = (category, isSelected) => ({
34
+ id: (0, exports.buildMccCategoryChipId)(category.name),
35
+ label: category.name,
36
+ isSelected,
37
+ optionalCode: category.mccCodes[0],
38
+ optionalCodes: [...category.mccCodes],
39
+ });
40
+ exports.toMccCategoryChipFieldValue = toMccCategoryChipFieldValue;