@zeniai/client-epic-state 5.0.83 → 5.0.84-beta24RJ

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 (131) hide show
  1. package/lib/common/aiCfo/aiCfoSuggestedQuestionsPageContext.d.ts +1 -1
  2. package/lib/entity/aiCfo/aiCfoPayload.d.ts +1 -140
  3. package/lib/entity/aiCfo/aiCfoReducer.d.ts +2 -23
  4. package/lib/entity/aiCfo/aiCfoReducer.js +4 -332
  5. package/lib/entity/aiCfo/aiCfoSelector.d.ts +1 -13
  6. package/lib/entity/aiCfo/aiCfoSelector.js +1 -28
  7. package/lib/entity/aiCfo/aiCfoState.d.ts +4 -225
  8. package/lib/entity/aiCfo/aiCfoState.js +1 -30
  9. package/lib/entity/jeSchedules/jeSchedulesPayload.d.ts +1 -0
  10. package/lib/entity/jeSchedules/jeSchedulesPayload.js +7 -0
  11. package/lib/entity/jeSchedules/jeSchedulesState.d.ts +1 -0
  12. package/lib/entity/jeSchedules/jeSchedulesTypes.d.ts +1 -1
  13. package/lib/entity/monthEndCloseChecks/monthEndCloseChecksState.d.ts +1 -1
  14. package/lib/entity/snackbar/snackbarTypes.d.ts +1 -1
  15. package/lib/entity/snackbar/snackbarTypes.js +0 -3
  16. package/lib/entity/tenant/clearAllEpic.d.ts +2 -6
  17. package/lib/entity/tenant/clearAllEpic.js +0 -8
  18. package/lib/epic.d.ts +1 -11
  19. package/lib/epic.js +1 -11
  20. package/lib/esm/entity/aiCfo/aiCfoReducer.js +4 -332
  21. package/lib/esm/entity/aiCfo/aiCfoSelector.js +1 -26
  22. package/lib/esm/entity/aiCfo/aiCfoState.js +0 -27
  23. package/lib/esm/entity/jeSchedules/jeSchedulesPayload.js +7 -0
  24. package/lib/esm/entity/snackbar/snackbarTypes.js +0 -3
  25. package/lib/esm/entity/tenant/clearAllEpic.js +0 -8
  26. package/lib/esm/epic.js +1 -11
  27. package/lib/esm/index.js +7 -22
  28. package/lib/esm/reducer.js +0 -12
  29. package/lib/esm/view/aiCfoView/aiCfoViewReducer.js +3 -6
  30. package/lib/esm/view/aiCfoView/epics/createSessionAndSubmitEpic.js +2 -5
  31. package/lib/esm/view/aiCfoView/epics/createSessionEpic.js +1 -2
  32. package/lib/esm/view/aiCfoView/epics/fetchSuggestedQuestionsEpic.js +2 -12
  33. package/lib/esm/view/spendManagement/chargeCards/chargeCardList/chargeCardListSelector.js +0 -25
  34. package/lib/esm/view/spendManagement/chargeCards/issueChargeCard/issueChargeCardEpic.js +2 -2
  35. package/lib/esm/view/spendManagement/chargeCards/issueChargeCard/issueChargeCardReducer.js +4 -16
  36. package/lib/esm/view/spendManagement/chargeCards/issueChargeCard/issueChargeCardSelector.js +0 -38
  37. package/lib/index.d.ts +7 -20
  38. package/lib/index.js +10 -125
  39. package/lib/reducer.d.ts +0 -12
  40. package/lib/reducer.js +0 -12
  41. package/lib/view/aiCfoView/aiCfoViewReducer.d.ts +2 -11
  42. package/lib/view/aiCfoView/aiCfoViewReducer.js +3 -6
  43. package/lib/view/aiCfoView/epics/createSessionAndSubmitEpic.js +2 -5
  44. package/lib/view/aiCfoView/epics/createSessionEpic.js +1 -2
  45. package/lib/view/aiCfoView/epics/fetchSuggestedQuestionsEpic.d.ts +1 -8
  46. package/lib/view/aiCfoView/epics/fetchSuggestedQuestionsEpic.js +2 -12
  47. package/lib/view/expenseAutomationView/helpers/transactionCategorizationLocalDataHelper.d.ts +1 -1
  48. package/lib/view/expenseAutomationView/types/reconciliationViewState.d.ts +1 -1
  49. package/lib/view/people/peopleTypes.d.ts +1 -1
  50. package/lib/view/scheduleView/scheduleListView/scheduleListTypes.d.ts +1 -1
  51. package/lib/view/spendManagement/chargeCards/chargeCardList/chargeCardList.d.ts +1 -1
  52. package/lib/view/spendManagement/chargeCards/chargeCardList/chargeCardListSelector.d.ts +0 -14
  53. package/lib/view/spendManagement/chargeCards/chargeCardList/chargeCardListSelector.js +1 -27
  54. package/lib/view/spendManagement/chargeCards/issueChargeCard/issueChargeCardEpic.d.ts +2 -2
  55. package/lib/view/spendManagement/chargeCards/issueChargeCard/issueChargeCardEpic.js +1 -1
  56. package/lib/view/spendManagement/chargeCards/issueChargeCard/issueChargeCardReducer.d.ts +1 -5
  57. package/lib/view/spendManagement/chargeCards/issueChargeCard/issueChargeCardReducer.js +5 -17
  58. package/lib/view/spendManagement/chargeCards/issueChargeCard/issueChargeCardSelector.d.ts +0 -27
  59. package/lib/view/spendManagement/chargeCards/issueChargeCard/issueChargeCardSelector.js +1 -43
  60. package/lib/view/spendManagement/chargeCards/issueChargeCard/issueChargeCardState.d.ts +0 -2
  61. package/lib/view/taskManager/taskListView/taskListReducer.d.ts +1 -1
  62. package/package.json +1 -1
  63. package/lib/entity/cardPolicy/cardPolicyPayload.d.ts +0 -277
  64. package/lib/entity/cardPolicy/cardPolicyPayload.js +0 -143
  65. package/lib/entity/cardPolicy/cardPolicyReducer.d.ts +0 -19
  66. package/lib/entity/cardPolicy/cardPolicyReducer.js +0 -265
  67. package/lib/entity/cardPolicy/cardPolicySelector.d.ts +0 -32
  68. package/lib/entity/cardPolicy/cardPolicySelector.js +0 -103
  69. package/lib/entity/cardPolicy/cardPolicyState.d.ts +0 -205
  70. package/lib/entity/cardPolicy/cardPolicyState.js +0 -14
  71. package/lib/entity/cardPolicy/extractPolicyDocumentEpic.d.ts +0 -18
  72. package/lib/entity/cardPolicy/extractPolicyDocumentEpic.js +0 -68
  73. package/lib/entity/cardPolicy/fetchCardPolicyVendorOptionsEpic.d.ts +0 -26
  74. package/lib/entity/cardPolicy/fetchCardPolicyVendorOptionsEpic.js +0 -47
  75. package/lib/entity/cardPolicy/policyDocumentExtractionToRecommendationBridgeEpic.d.ts +0 -25
  76. package/lib/entity/cardPolicy/policyDocumentExtractionToRecommendationBridgeEpic.js +0 -39
  77. package/lib/entity/cardPolicy/policyRecommendationFromUploadEpic.d.ts +0 -23
  78. package/lib/entity/cardPolicy/policyRecommendationFromUploadEpic.js +0 -111
  79. package/lib/esm/entity/cardPolicy/cardPolicyPayload.js +0 -130
  80. package/lib/esm/entity/cardPolicy/cardPolicyReducer.js +0 -261
  81. package/lib/esm/entity/cardPolicy/cardPolicySelector.js +0 -79
  82. package/lib/esm/entity/cardPolicy/cardPolicyState.js +0 -9
  83. package/lib/esm/entity/cardPolicy/extractPolicyDocumentEpic.js +0 -64
  84. package/lib/esm/entity/cardPolicy/fetchCardPolicyVendorOptionsEpic.js +0 -43
  85. package/lib/esm/entity/cardPolicy/policyDocumentExtractionToRecommendationBridgeEpic.js +0 -35
  86. package/lib/esm/entity/cardPolicy/policyRecommendationFromUploadEpic.js +0 -107
  87. package/lib/esm/view/spendManagement/chargeCards/cardPolicy/cardPolicyDetail/cardPolicyDetailReducer.js +0 -70
  88. package/lib/esm/view/spendManagement/chargeCards/cardPolicy/cardPolicyDetail/cardPolicyDetailSelector.js +0 -22
  89. package/lib/esm/view/spendManagement/chargeCards/cardPolicy/cardPolicyDetail/cardPolicyDetailState.js +0 -1
  90. package/lib/esm/view/spendManagement/chargeCards/cardPolicy/cardPolicyDetail/fetchCardPolicyDetailEpic.js +0 -56
  91. package/lib/esm/view/spendManagement/chargeCards/cardPolicy/cardPolicyDetail/updateCardPolicyEpic.js +0 -49
  92. package/lib/esm/view/spendManagement/chargeCards/cardPolicy/cardPolicyList/archiveCardPolicyEpic.js +0 -42
  93. package/lib/esm/view/spendManagement/chargeCards/cardPolicy/cardPolicyList/cardPolicyListReducer.js +0 -72
  94. package/lib/esm/view/spendManagement/chargeCards/cardPolicy/cardPolicyList/cardPolicyListSelector.js +0 -21
  95. package/lib/esm/view/spendManagement/chargeCards/cardPolicy/cardPolicyList/cardPolicyListState.js +0 -1
  96. package/lib/esm/view/spendManagement/chargeCards/cardPolicy/cardPolicyList/fetchCardPolicyListEpic.js +0 -56
  97. package/lib/esm/view/spendManagement/chargeCards/cardPolicy/createCardPolicy/createCardPolicyReducer.js +0 -62
  98. package/lib/esm/view/spendManagement/chargeCards/cardPolicy/createCardPolicy/createCardPolicySelector.js +0 -39
  99. package/lib/esm/view/spendManagement/chargeCards/cardPolicy/createCardPolicy/createCardPolicyState.js +0 -1
  100. package/lib/esm/view/spendManagement/chargeCards/cardPolicy/createCardPolicy/createCardPolicyTemplateEpic.js +0 -53
  101. package/lib/esm/view/spendManagement/chargeCards/cardPolicy/createCardPolicy/fetchCardPolicyMccCategoriesEpic.js +0 -25
  102. package/lib/view/spendManagement/chargeCards/cardPolicy/cardPolicyDetail/cardPolicyDetailReducer.d.ts +0 -14
  103. package/lib/view/spendManagement/chargeCards/cardPolicy/cardPolicyDetail/cardPolicyDetailReducer.js +0 -74
  104. package/lib/view/spendManagement/chargeCards/cardPolicy/cardPolicyDetail/cardPolicyDetailSelector.d.ts +0 -21
  105. package/lib/view/spendManagement/chargeCards/cardPolicy/cardPolicyDetail/cardPolicyDetailSelector.js +0 -28
  106. package/lib/view/spendManagement/chargeCards/cardPolicy/cardPolicyDetail/cardPolicyDetailState.d.ts +0 -25
  107. package/lib/view/spendManagement/chargeCards/cardPolicy/cardPolicyDetail/cardPolicyDetailState.js +0 -2
  108. package/lib/view/spendManagement/chargeCards/cardPolicy/cardPolicyDetail/fetchCardPolicyDetailEpic.d.ts +0 -19
  109. package/lib/view/spendManagement/chargeCards/cardPolicy/cardPolicyDetail/fetchCardPolicyDetailEpic.js +0 -60
  110. package/lib/view/spendManagement/chargeCards/cardPolicy/cardPolicyDetail/updateCardPolicyEpic.d.ts +0 -18
  111. package/lib/view/spendManagement/chargeCards/cardPolicy/cardPolicyDetail/updateCardPolicyEpic.js +0 -53
  112. package/lib/view/spendManagement/chargeCards/cardPolicy/cardPolicyList/archiveCardPolicyEpic.d.ts +0 -16
  113. package/lib/view/spendManagement/chargeCards/cardPolicy/cardPolicyList/archiveCardPolicyEpic.js +0 -46
  114. package/lib/view/spendManagement/chargeCards/cardPolicy/cardPolicyList/cardPolicyListReducer.d.ts +0 -15
  115. package/lib/view/spendManagement/chargeCards/cardPolicy/cardPolicyList/cardPolicyListReducer.js +0 -76
  116. package/lib/view/spendManagement/chargeCards/cardPolicy/cardPolicyList/cardPolicyListSelector.d.ts +0 -21
  117. package/lib/view/spendManagement/chargeCards/cardPolicy/cardPolicyList/cardPolicyListSelector.js +0 -27
  118. package/lib/view/spendManagement/chargeCards/cardPolicy/cardPolicyList/cardPolicyListState.d.ts +0 -19
  119. package/lib/view/spendManagement/chargeCards/cardPolicy/cardPolicyList/cardPolicyListState.js +0 -2
  120. package/lib/view/spendManagement/chargeCards/cardPolicy/cardPolicyList/fetchCardPolicyListEpic.d.ts +0 -19
  121. package/lib/view/spendManagement/chargeCards/cardPolicy/cardPolicyList/fetchCardPolicyListEpic.js +0 -60
  122. package/lib/view/spendManagement/chargeCards/cardPolicy/createCardPolicy/createCardPolicyReducer.d.ts +0 -13
  123. package/lib/view/spendManagement/chargeCards/cardPolicy/createCardPolicy/createCardPolicyReducer.js +0 -66
  124. package/lib/view/spendManagement/chargeCards/cardPolicy/createCardPolicy/createCardPolicySelector.d.ts +0 -32
  125. package/lib/view/spendManagement/chargeCards/cardPolicy/createCardPolicy/createCardPolicySelector.js +0 -46
  126. package/lib/view/spendManagement/chargeCards/cardPolicy/createCardPolicy/createCardPolicyState.d.ts +0 -45
  127. package/lib/view/spendManagement/chargeCards/cardPolicy/createCardPolicy/createCardPolicyState.js +0 -2
  128. package/lib/view/spendManagement/chargeCards/cardPolicy/createCardPolicy/createCardPolicyTemplateEpic.d.ts +0 -25
  129. package/lib/view/spendManagement/chargeCards/cardPolicy/createCardPolicy/createCardPolicyTemplateEpic.js +0 -57
  130. package/lib/view/spendManagement/chargeCards/cardPolicy/createCardPolicy/fetchCardPolicyMccCategoriesEpic.d.ts +0 -15
  131. package/lib/view/spendManagement/chargeCards/cardPolicy/createCardPolicy/fetchCardPolicyMccCategoriesEpic.js +0 -29
@@ -1,10 +1,9 @@
1
1
  import { createSlice } from '@reduxjs/toolkit';
2
2
  import { date as zeniDate } from '../../zeniDayJS';
3
- import { ALL_AI_CFO_ANSWER_RESPONSE_TYPES, CARDS_CREATION_DEFAULT_CARD_OPTION_ID, toAiCfoAnswerResponseType, toAiCfoAnswerResponseTypeStrict, toAiCfoAnswerStateType, toAiCfoVisualizationTypeStrict, toInteractiveFormTypeStrict, toMessageSender, toMessageType, toYFormatScaleStrict, toYFormatTypeStrict, toYFormatUnitStrict, } from './aiCfoState';
3
+ import { ALL_AI_CFO_ANSWER_RESPONSE_TYPES, toAiCfoAnswerResponseType, toAiCfoAnswerResponseTypeStrict, toAiCfoAnswerStateType, toAiCfoVisualizationTypeStrict, toMessageSender, toMessageType, toYFormatScaleStrict, toYFormatTypeStrict, toYFormatUnitStrict, } from './aiCfoState';
4
4
  export const initialAiCfoState = {
5
5
  aiCfoByChatSessionId: {},
6
6
  partialQuestionAnswers: {},
7
- syntheticAnswersByChatSessionId: {},
8
7
  };
9
8
  // Utility: Merge two arrays of Q&A pairs, combining responses for the same question
10
9
  function mergeQuestionAnswerPairs(existing, newQAs) {
@@ -136,216 +135,9 @@ export const toAiCfoVisualization = (visualization) => {
136
135
  if (visualization.type == null || visualization.data == null) {
137
136
  return undefined;
138
137
  }
139
- // Reject unknown viz types instead of silently defaulting to `table`.
140
- // The previous `?? 'table'` fallback funneled any non-strict-union
141
- // payload into `toAiCfoVisualizationData`, which is the table/chart
142
- // decoder and dereferences `data.values.map(...)`. Interactive-form
143
- // payloads (e.g. when the BE ships `type: <new_form_kind>` we don't
144
- // know about yet) carry no `values`, so that path threw during answer
145
- // upsert and broke rendering for the whole Q/A. Returning `undefined`
146
- // matches the existing "missing type / data" guard above — callers
147
- // already handle a no-visualization answer.
148
- const normalizedType = toAiCfoVisualizationTypeStrict(visualization.type);
149
- if (normalizedType == null) {
150
- return undefined;
151
- }
152
- return {
153
- type: normalizedType,
154
- data: normalizedType === 'interactive_form'
155
- ? toInteractiveFormVisualization(visualization.data)
156
- : toAiCfoVisualizationData(visualization.data),
157
- };
158
- };
159
- const toInteractiveFormVisualization = (data) => {
160
- // When `form_type` is missing / mistyped, fall back to a payload-shape
161
- // heuristic instead of blindly defaulting to `cards_creation`. A
162
- // `card_policy` payload always carries `mode: 'auto' | 'guided' |
163
- // 'upload'` (see `CardPolicyInitialDataPayload`); a `cards_creation`
164
- // payload carries `suggested_cards` and never that exact `mode` set.
165
- // Without this, a card-policy answer with a malformed `form_type`
166
- // would be decoded as cards_creation, surfacing the wrong interactive
167
- // form (and wrong submit path) in the UI.
168
- const formType = toInteractiveFormTypeStrict(data.form_type) ??
169
- inferInteractiveFormTypeFromPayload(data.payload);
170
- if (formType === 'card_policy') {
171
- return {
172
- formType: 'card_policy',
173
- payload: toCardPolicyInitialData(data.payload),
174
- };
175
- }
176
- return {
177
- formType: 'cards_creation',
178
- payload: toCardsCreationInitialData(data.payload),
179
- };
180
- };
181
- const inferInteractiveFormTypeFromPayload = (payload) => {
182
- if (payload != null && typeof payload === 'object' && 'mode' in payload) {
183
- const mode = payload.mode;
184
- if (mode === 'auto' || mode === 'guided' || mode === 'upload') {
185
- return 'card_policy';
186
- }
187
- }
188
- return 'cards_creation';
189
- };
190
- /**
191
- * Decode the unified `cards_creation` interactive-form payload into the FE
192
- * state shape. Both `review` and `create` modes ship the same envelope
193
- * (`{mode, suggested_cards[]}`); the only thing that varies is how the
194
- * common derivations are exposed:
195
- *
196
- * - `review` (2-step): `is_suggested: true` rows -> `teamRows`; the full
197
- * universe -> `cardNameOptions` (step-2 swap + step-1 "Add something
198
- * else" search).
199
- * - `create` (1-step): `is_suggested: true` rows -> `cardRows` pre-seeded
200
- * for the step-2 editable table (with `cardOptionId` defaulted to
201
- * `'virtual'`); the full universe -> `cardNameOptions` (step-2 swap).
202
- *
203
- * `cardOptions` (physical / virtual / subscription) is intentionally not
204
- * derived here — the wire never carries it. The component prop is fed
205
- * from `AI_CARD_CREATION_VIRTUAL_ONLY_CARD_OPTIONS` at render time. The
206
- * state field is preserved as `[]` for backward compatibility with
207
- * consumers that still narrow on it.
208
- */
209
- const toCardsCreationInitialData = (payload) => {
210
- const suggestedCards = payload.suggested_cards ?? [];
211
- const ordered = [...suggestedCards].sort((a, b) => KIND_RANK[a.card_type] - KIND_RANK[b.card_type]);
212
- const withUniqueIds = withSynthesizedIds(ordered);
213
- const suggestedOnly = withUniqueIds.filter(({ card }) => card.is_suggested);
214
- const cardNameOptions = withUniqueIds.map(({ card, uniqueId }) => ({
215
- id: uniqueId,
216
- kind: toCardKind(card.card_type),
217
- label: card.card_name,
218
- }));
219
- const suggestedOwnerUserIdByTeamId = Object.fromEntries(suggestedOnly.map(({ card, uniqueId }) => [
220
- uniqueId,
221
- normalizeOwnerId(card.owner_id),
222
- ]));
223
- const common = {
224
- cardNameOptions,
225
- cardOptions: [],
226
- suggestedOwnerUserIdByTeamId,
227
- };
228
- if (payload.mode === 'create') {
229
- return {
230
- ...common,
231
- mode: 'create',
232
- cardRows: suggestedOnly.map(({ card, uniqueId }) => ({
233
- cardKind: toCardKind(card.card_type),
234
- cardOptionId: CARDS_CREATION_DEFAULT_CARD_OPTION_ID,
235
- id: uniqueId,
236
- label: card.card_name,
237
- recommendedLimit: card.credit_limit > 0 ? card.credit_limit : undefined,
238
- suggestedOwnerUserId: normalizeOwnerId(card.owner_id),
239
- })),
240
- };
241
- }
242
138
  return {
243
- ...common,
244
- mode: 'review',
245
- teamRows: suggestedOnly.map(({ card, uniqueId }) => ({
246
- avgMonthlySpend: CURRENCY_FORMATTER.format(card.avg_spend),
247
- cardKind: toCardKind(card.card_type),
248
- id: uniqueId,
249
- label: card.card_name,
250
- recommendedLimit: CURRENCY_FORMATTER.format(card.credit_limit),
251
- recommendedLimitCadence: 'Monthly',
252
- })),
253
- };
254
- };
255
- const CURRENCY_FORMATTER = new Intl.NumberFormat('en-US', {
256
- style: 'currency',
257
- currency: 'USD',
258
- maximumFractionDigits: 0,
259
- });
260
- /**
261
- * Normalize the controller's `owner_id` into `string | undefined`. The
262
- * BE may emit either `null` or `""` to signal "no owner picked"; both
263
- * collapse to `undefined` so downstream resolvers don't try to look up
264
- * a user with an empty id.
265
- */
266
- const normalizeOwnerId = (ownerId) => ownerId != null && ownerId !== '' ? ownerId : undefined;
267
- const KIND_RANK = {
268
- vendor: 0,
269
- category: 1,
270
- department: 2,
271
- };
272
- const toCardKind = (cardType) => {
273
- if (cardType === 'department') {
274
- return 'class';
275
- }
276
- if (cardType === 'category') {
277
- return 'category';
278
- }
279
- return 'vendor';
280
- };
281
- /**
282
- * Stamp each suggested card with a stable unique id derived from its
283
- * `card_name_id`. If two cards in the same payload share the same
284
- * `card_name_id` (which happens in the current sample payload where
285
- * `card_name_id` is the literal `"vendor_uuid"`), fall back to a
286
- * synthesized id `${kind}__${card_name_id}__${index}` so RHF row keying
287
- * stays unique.
288
- */
289
- const withSynthesizedIds = (cards) => {
290
- const seen = new Set();
291
- return cards.map((card, index) => {
292
- const preferred = card.card_name_id;
293
- if (preferred != null && preferred !== '' && !seen.has(preferred)) {
294
- seen.add(preferred);
295
- return { card, uniqueId: preferred };
296
- }
297
- const synthesized = `${card.card_type}__${preferred ?? 'unknown'}__${index}`;
298
- seen.add(synthesized);
299
- return { card, uniqueId: synthesized };
300
- });
301
- };
302
- const toCardPolicyDraftPolicy = (payload, index) => ({
303
- id: `draft-${index}`,
304
- name: payload.name,
305
- description: payload.description ?? '',
306
- mode: payload.mode,
307
- allowedEntity: {
308
- categoryCodes: payload.allowed_entity?.category_codes ?? [],
309
- merchantNames: payload.allowed_entity?.merchant_names ?? [],
310
- },
311
- blockedEntity: {
312
- categoryCodes: payload.blocked_entity?.category_codes ?? [],
313
- merchantNames: payload.blocked_entity?.merchant_names ?? [],
314
- },
315
- applyToCards: payload.apply_to_cards ?? [],
316
- requiredReceiptThreshold: payload.required_receipt_threshold ?? 0,
317
- spendLimits: {
318
- transaction: payload.spend_limits?.transaction ?? 0,
319
- },
320
- });
321
- const toCardPolicyStep5Review = (payload) => ({
322
- draftPolicies: (payload.draft_policies ?? []).map(toCardPolicyDraftPolicy),
323
- groupingSource: payload.grouping_source ?? 'none',
324
- prompt: payload.prompt ?? '',
325
- });
326
- const toCardPolicyWizardPlan = (payload) => ({
327
- step5Review: toCardPolicyStep5Review(payload.step_5_review),
328
- });
329
- const toCardPolicyUploadSource = (payload) => ({
330
- confidenceScore: payload.confidence_score,
331
- fileName: payload.file_name,
332
- lowConfidenceFields: payload.low_confidence_fields ?? [],
333
- });
334
- const toCardPolicyInitialData = (payload) => {
335
- if (payload.mode === 'upload') {
336
- return {
337
- policyKind: 'upload',
338
- wizardPlan: payload.wizard_plan != null
339
- ? toCardPolicyWizardPlan(payload.wizard_plan)
340
- : undefined,
341
- source: payload.source != null
342
- ? toCardPolicyUploadSource(payload.source)
343
- : undefined,
344
- };
345
- }
346
- return {
347
- policyKind: payload.mode,
348
- wizardPlan: toCardPolicyWizardPlan(payload.wizard_plan),
139
+ type: toAiCfoVisualizationTypeStrict(visualization.type) ?? 'table',
140
+ data: toAiCfoVisualizationData(visualization.data),
349
141
  };
350
142
  };
351
143
  const toAiCfoVisualizationData = (data) => {
@@ -661,119 +453,9 @@ const aiCfo = createSlice({
661
453
  session.questionAnswers.push(qa);
662
454
  }
663
455
  },
664
- /**
665
- * Patch the `card_policy` interactive-form payload for a specific
666
- * answer in a chat session to merge in the wizard plan + upload
667
- * source metadata returned by
668
- * `POST /cards/1.0/ai-cfo/policy-recommendation-from-upload`.
669
- *
670
- * Dispatched by the recommendation epic after a successful response;
671
- * the wizard re-renders Steps 2 + 3 of the upload variant once the
672
- * payload becomes a populated `CardPolicyInitialData` with
673
- * `policyKind: "upload"` + `wizardPlan` + `source`.
674
- *
675
- * No-op when the target answer / chat session / form payload is
676
- * missing or isn't an upload-mode card-policy interactive form —
677
- * the bridge epic is best-effort and silently drops in edge cases
678
- * (e.g. the user closed the chat before recommendation returned).
679
- */
680
- updateAiCfoAnswerCardPolicyWizardPlan(draft, action) {
681
- const { answerId, chatSessionId, source, wizardPlan } = action.payload;
682
- const session = draft.aiCfoByChatSessionId[chatSessionId];
683
- if (session == null) {
684
- return;
685
- }
686
- const qa = session.questionAnswers.find((entry) => entry.questionAnswerId === answerId);
687
- if (qa == null) {
688
- return;
689
- }
690
- for (const response of Object.values(qa.responses)) {
691
- const visualization = response?.content.visualization;
692
- if (visualization == null ||
693
- visualization.type !== 'interactive_form') {
694
- continue;
695
- }
696
- const data = visualization.data;
697
- if (data.formType !== 'card_policy' ||
698
- data.payload.policyKind !== 'upload') {
699
- continue;
700
- }
701
- data.payload = {
702
- ...data.payload,
703
- wizardPlan,
704
- source: source ?? data.payload.source,
705
- };
706
- }
707
- },
708
- /**
709
- * Append a client-synthesized answer bubble to a chat session. Used by
710
- * the AI CFO cards/policy create flow to render a "Creating…" placeholder
711
- * in the drawer while the underlying mutation runs.
712
- *
713
- * The caller is responsible for generating a stable `id` (so the same
714
- * bubble can later be updated in place via `updateSyntheticAiCfoAnswer`
715
- * once the mutation completes) and a `createdAt` timestamp so the
716
- * renderer can interleave synthetic bubbles with streamed Q&A pairs in
717
- * chronological order.
718
- */
719
- appendSyntheticAiCfoAnswer(draft, action) {
720
- const { chatSessionId, id, kind, createdAt, entityIds, sourceQuestionAnswerId, } = action.payload;
721
- if (draft.syntheticAnswersByChatSessionId[chatSessionId] == null) {
722
- draft.syntheticAnswersByChatSessionId[chatSessionId] = [];
723
- }
724
- draft.syntheticAnswersByChatSessionId[chatSessionId].push({
725
- id,
726
- kind,
727
- entityIds: entityIds ?? [],
728
- createdAt,
729
- sourceQuestionAnswerId,
730
- });
731
- },
732
- /**
733
- * Update an existing synthetic answer bubble in place. Typically called
734
- * when the create mutation completes: the screen transitions the bubble
735
- * from `creating_*` to `created_*` and populates `entityIds` with the
736
- * newly created cards / policy templates.
737
- *
738
- * No-op when the target bubble is missing (e.g. the session was cleared
739
- * before the mutation returned).
740
- */
741
- updateSyntheticAiCfoAnswer(draft, action) {
742
- const { chatSessionId, id, kind, entityIds } = action.payload;
743
- const list = draft.syntheticAnswersByChatSessionId[chatSessionId];
744
- if (list == null) {
745
- return;
746
- }
747
- const entry = list.find((item) => item.id === id);
748
- if (entry == null) {
749
- return;
750
- }
751
- entry.kind = kind;
752
- if (entityIds != null) {
753
- entry.entityIds = entityIds;
754
- }
755
- },
756
- /**
757
- * Remove a single synthetic answer bubble (e.g. when the user manually
758
- * dismisses it or the mutation errors out and we want to fall back to
759
- * an inline error snackbar).
760
- */
761
- removeSyntheticAiCfoAnswer(draft, action) {
762
- const { chatSessionId, id } = action.payload;
763
- const list = draft.syntheticAnswersByChatSessionId[chatSessionId];
764
- if (list == null) {
765
- return;
766
- }
767
- draft.syntheticAnswersByChatSessionId[chatSessionId] = list.filter((item) => item.id !== id);
768
- },
769
- /** Clear every synthetic bubble for a session. */
770
- clearSyntheticAiCfoAnswers(draft, action) {
771
- delete draft.syntheticAnswersByChatSessionId[action.payload];
772
- },
773
456
  clearSession(draft, action) {
774
457
  const sessionId = action.payload;
775
458
  delete draft.aiCfoByChatSessionId[sessionId];
776
- delete draft.syntheticAnswersByChatSessionId[sessionId];
777
459
  // Clear partial Q&A if it belongs to the cleared session
778
460
  if (draft.partialQuestionAnswers?.[sessionId] != null) {
779
461
  draft.partialQuestionAnswers[sessionId] = undefined;
@@ -782,7 +464,6 @@ const aiCfo = createSlice({
782
464
  clearAiCfo(draft) {
783
465
  draft.aiCfoByChatSessionId = {};
784
466
  draft.partialQuestionAnswers = {};
785
- draft.syntheticAnswersByChatSessionId = {};
786
467
  },
787
468
  deleteQuestion(draft, action) {
788
469
  const { chatSessionId, questionAnswerId } = action.payload;
@@ -795,15 +476,6 @@ const aiCfo = createSlice({
795
476
  if (idx !== -1) {
796
477
  session.questionAnswers.splice(idx, 1);
797
478
  }
798
- // Also drop any synthetic bubbles whose `sourceQuestionAnswerId`
799
- // referenced the just-deleted Q/A. Without this, the chat would
800
- // keep rendering "Creating…" / "Created" tiles tied to a Q/A that
801
- // no longer exists (via `getSyntheticAiCfoAnswerByQuestionAnswerId`).
802
- const syntheticAnswers = draft.syntheticAnswersByChatSessionId[chatSessionId];
803
- if (syntheticAnswers != null) {
804
- draft.syntheticAnswersByChatSessionId[chatSessionId] =
805
- syntheticAnswers.filter((answer) => answer.sourceQuestionAnswerId !== questionAnswerId);
806
- }
807
479
  },
808
480
  },
809
481
  });
@@ -816,5 +488,5 @@ const toChatSession = (chatSessionPayload) => {
816
488
  createdAt: zeniDate(created_at),
817
489
  };
818
490
  };
819
- export const { setNewSession, clearSession, setSessions, setChatHistory, upsertAnswerPayload, upsertOrAddQuestionAnswerPayload, addQuestionPayload, clearAiCfo, deleteQuestion, updateAiCfoAnswerCardPolicyWizardPlan, appendSyntheticAiCfoAnswer, updateSyntheticAiCfoAnswer, removeSyntheticAiCfoAnswer, clearSyntheticAiCfoAnswers, } = aiCfo.actions;
491
+ export const { setNewSession, clearSession, setSessions, setChatHistory, upsertAnswerPayload, upsertOrAddQuestionAnswerPayload, addQuestionPayload, clearAiCfo, deleteQuestion, } = aiCfo.actions;
820
492
  export default aiCfo.reducer;
@@ -32,30 +32,5 @@ export function getAiCfoSelectorView(state) {
32
32
  : [],
33
33
  }))
34
34
  .sort((a, b) => b.chatSession.createdAt.valueOf() - a.chatSession.createdAt.valueOf());
35
- return {
36
- allSessionsWithOrderedQuestionAnswers,
37
- syntheticAnswersByChatSessionId: state.syntheticAnswersByChatSessionId ?? {},
38
- };
39
- }
40
- export function getSyntheticAiCfoAnswersForChatSession(state, chatSessionId) {
41
- const arr = state.syntheticAnswersByChatSessionId?.[chatSessionId] ?? [];
42
- return arr
43
- .slice()
44
- .sort((a, b) => a.createdAt.valueOf() - b.createdAt.valueOf());
45
- }
46
- /**
47
- * Look up the synthetic answer bubble (if any) whose source AI CFO Q/A
48
- * is `questionAnswerId`. Used by the in-place renderer to swap a Q/A's
49
- * answer bubble with the "Creating…" / "Created" tile.
50
- *
51
- * Returns `undefined` when no synthetic bubble has been dispatched for
52
- * the answer yet (i.e. the user hasn't submitted the interactive form),
53
- * or when the chat session has no synthetic entries at all.
54
- */
55
- export function getSyntheticAiCfoAnswerByQuestionAnswerId(state, chatSessionId, questionAnswerId) {
56
- const arr = state.syntheticAnswersByChatSessionId?.[chatSessionId];
57
- if (arr == null) {
58
- return undefined;
59
- }
60
- return arr.find((answer) => answer.sourceQuestionAnswerId === questionAnswerId);
35
+ return { allSessionsWithOrderedQuestionAnswers };
61
36
  }
@@ -7,14 +7,7 @@ export const ALL_AI_CFO_CHARTS_TYPES = [
7
7
  export const ALL_AI_CFO_VISUALIZATION_TYPES = [
8
8
  ...ALL_AI_CFO_CHARTS_TYPES,
9
9
  'table',
10
- 'interactive_form',
11
10
  ];
12
- export const ALL_INTERACTIVE_FORM_TYPES = [
13
- 'cards_creation',
14
- 'card_policy',
15
- ];
16
- export const toInteractiveFormType = (v) => stringToUnion(v, ALL_INTERACTIVE_FORM_TYPES);
17
- export const toInteractiveFormTypeStrict = (v) => stringToUnionStrict(v, ALL_INTERACTIVE_FORM_TYPES);
18
11
  export const toAiCfoVisualizationType = (v) => stringToUnion(v, ALL_AI_CFO_VISUALIZATION_TYPES);
19
12
  export const toAiCfoVisualizationTypeStrict = (v) => stringToUnionStrict(v, ALL_AI_CFO_VISUALIZATION_TYPES);
20
13
  export const toAiCfoChartType = (v) => stringToUnion(v, ALL_AI_CFO_CHARTS_TYPES);
@@ -59,29 +52,9 @@ export const toAiCfoAnswerStateType = (v) => stringToUnion(v, ALL_AI_CFO_ANSWER_
59
52
  export const toAiCfoAnswerResponseType = (v) => stringToUnion(v, ALL_AI_CFO_ANSWER_RESPONSE_TYPES);
60
53
  export const toAiCfoAnswerStateTypeStrict = (v) => stringToUnionStrict(v, ALL_AI_CFO_ANSWER_STATE_TYPES);
61
54
  export const toAiCfoAnswerResponseTypeStrict = (v) => stringToUnionStrict(v, ALL_AI_CFO_ANSWER_RESPONSE_TYPES);
62
- /**
63
- * Default `cardOptionId` (physical / virtual / subscription) assigned to
64
- * every seeded card row. The AI Card Creation flow currently issues virtual
65
- * credit cards only — this constant is kept in sync with
66
- * `AI_CARD_CREATION_VIRTUAL_ONLY_CARD_OPTIONS` in `zeni-web-app-ui`.
67
- */
68
- export const CARDS_CREATION_DEFAULT_CARD_OPTION_ID = 'virtual';
69
55
  const ALL_MESSAGE_SENDERS = ['user', 'agent'];
70
56
  const ALL_MESSAGE_TYPES = ['plain_text', 'json'];
71
57
  export const toMessageSender = (v) => stringToUnion(v, ALL_MESSAGE_SENDERS);
72
58
  export const toMessageType = (v) => stringToUnion(v, ALL_MESSAGE_TYPES);
73
59
  export const toMessageSenderStrict = (v) => stringToUnionStrict(v, ALL_MESSAGE_SENDERS);
74
60
  export const toMessageTypeStrict = (v) => stringToUnionStrict(v, ALL_MESSAGE_TYPES);
75
- /**
76
- * Discriminator for client-synthesized AI CFO answer bubbles. These are not
77
- * Q/A pairs streamed from the backend — they are pushed locally by the AI
78
- * CFO flow when it kicks off a cards or policy create from an interactive
79
- * form, so the drawer can render a "Creating…" placeholder and later a
80
- * "Created" success bubble while the corresponding mutation epic runs.
81
- */
82
- export const ALL_SYNTHETIC_AI_CFO_ANSWER_KINDS = [
83
- 'creating_cards',
84
- 'creating_policy',
85
- 'created_cards',
86
- 'created_policy',
87
- ];
@@ -145,42 +145,49 @@ function toJEScheduleAISummaries(payload) {
145
145
  result.debitAccount = {
146
146
  confidence: payload.debit_account.confidence,
147
147
  reasoning: payload.debit_account.reasoning,
148
+ cot: payload.debit_account.cot,
148
149
  };
149
150
  }
150
151
  if (payload.credit_account != null) {
151
152
  result.creditAccount = {
152
153
  confidence: payload.credit_account.confidence,
153
154
  reasoning: payload.credit_account.reasoning,
155
+ cot: payload.credit_account.cot,
154
156
  };
155
157
  }
156
158
  if (payload.debit_accounting_class != null) {
157
159
  result.debitClass = {
158
160
  confidence: payload.debit_accounting_class.confidence,
159
161
  reasoning: payload.debit_accounting_class.reasoning,
162
+ cot: payload.debit_accounting_class.cot,
160
163
  };
161
164
  }
162
165
  if (payload.credit_accounting_class != null) {
163
166
  result.creditClass = {
164
167
  confidence: payload.credit_accounting_class.confidence,
165
168
  reasoning: payload.credit_accounting_class.reasoning,
169
+ cot: payload.credit_accounting_class.cot,
166
170
  };
167
171
  }
168
172
  if (payload.period != null) {
169
173
  result.period = {
170
174
  confidence: payload.period.confidence,
171
175
  reasoning: payload.period.reasoning,
176
+ cot: payload.period.cot,
172
177
  };
173
178
  }
174
179
  if (payload.posting_date != null) {
175
180
  result.postingDate = {
176
181
  confidence: payload.posting_date.confidence,
177
182
  reasoning: payload.posting_date.reasoning,
183
+ cot: payload.posting_date.cot,
178
184
  };
179
185
  }
180
186
  if (payload.schedule_type != null) {
181
187
  result.scheduleType = {
182
188
  confidence: payload.schedule_type.confidence,
183
189
  reasoning: payload.schedule_type.reasoning,
190
+ cot: payload.schedule_type.cot,
184
191
  };
185
192
  }
186
193
  return Object.keys(result).length > 0 ? result : undefined;
@@ -95,9 +95,6 @@ const ALL_SNACKBAR_MESSAGE_SECTIONS = [
95
95
  'charge_card_receipt_upload',
96
96
  'charge_card_resend_invite',
97
97
  'charge_card_revoke_invite',
98
- 'card_policy_created',
99
- 'card_policy_updated',
100
- 'card_policy_deleted',
101
98
  'charge_card_update_limit',
102
99
  'charge_cards_update_limit',
103
100
  'close_charge_card',
@@ -97,9 +97,6 @@ import { clearInternationalWire } from '../../view/spendManagement/billPay/inter
97
97
  import { clearInternationalVerificationView } from '../../view/spendManagement/billPay/internationalWireVerification/internationalWireVerificationReducer';
98
98
  import { clearPreviousBills } from '../../view/spendManagement/billPay/previousBills/previousBillsReducer';
99
99
  import { clearWiseRedirectStatus } from '../../view/spendManagement/billPay/wiseRedirectView/wiseRedirectReducer';
100
- import { clearCardPolicyDetail } from '../../view/spendManagement/chargeCards/cardPolicy/cardPolicyDetail/cardPolicyDetailReducer';
101
- import { clearCardPolicyList } from '../../view/spendManagement/chargeCards/cardPolicy/cardPolicyList/cardPolicyListReducer';
102
- import { clearCreateCardPolicy } from '../../view/spendManagement/chargeCards/cardPolicy/createCardPolicy/createCardPolicyReducer';
103
100
  import { clearCardUserOnboarding } from '../../view/spendManagement/chargeCards/cardUserOnboarding/cardUserOnboardingReducer';
104
101
  import { clearCashbackDetail } from '../../view/spendManagement/chargeCards/cashbackDetail/cashbackDetailReducer';
105
102
  import { clearChargeCardConfig } from '../../view/spendManagement/chargeCards/chargeCardConfig/chargeCardConfigReducer';
@@ -171,7 +168,6 @@ import { clearAllBillTransactions } from '../billPay/billTransaction/billTransac
171
168
  import { clearContacts } from '../billPay/contact/contactReducer';
172
169
  import { clearAllRecurringBills } from '../billPay/recurringBills/recurringBillsReducer';
173
170
  import { clearAllCardPayments } from '../cardPayment/cardPaymentReducer';
174
- import { clearCardPolicy } from '../cardPolicy/cardPolicyReducer';
175
171
  import { clearAllChargeCards } from '../chargeCard/chargeCardReducer';
176
172
  import { clearAllChargeCardRepayments } from '../chargeCardRepayment/chargeCardRepaymentReducer';
177
173
  import { clearAllChargeCardTransactions } from '../chargeCardTransaction/chargeCardTransactionReducer';
@@ -248,8 +244,6 @@ export const clearAllEpic = (actions$) => actions$.pipe(filter(clearAll.match),
248
244
  clearBillPaySetupView(),
249
245
  clearCardBalance(),
250
246
  clearCardPaymentView(),
251
- clearCardPolicyDetail(),
252
- clearCardPolicyList(),
253
247
  clearCardUserOnboarding(),
254
248
  clearCashbackDetail(),
255
249
  clearCashBalance(),
@@ -269,7 +263,6 @@ export const clearAllEpic = (actions$) => actions$.pipe(filter(clearAll.match),
269
263
  clearCompanyMonthEndReportView(),
270
264
  clearCompanyTaskManagerView(),
271
265
  clearCompanyView(),
272
- clearCreateCardPolicy(),
273
266
  clearCreateTransferEntry(),
274
267
  clearAllCreditAgent(),
275
268
  clearCreditAgentView(),
@@ -431,7 +424,6 @@ export const clearAllEpic = (actions$) => actions$.pipe(filter(clearAll.match),
431
424
  clearAllVendorExpenseTrends(),
432
425
  clearAllVendors(),
433
426
  clearCannedResponses(),
434
- clearCardPolicy(),
435
427
  clearClassList(),
436
428
  clearContacts(),
437
429
  clearCountryList(),