@zeniai/client-epic-state 4.19.84-betaVR10 → 4.19.84-betaVR12

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 (26) hide show
  1. package/lib/esm/index.js +5 -2
  2. package/lib/esm/view/expenseAutomationView/bulkUploadTiming.js +5 -0
  3. package/lib/esm/view/expenseAutomationView/epics/missingReceipts/bulkUploadReceiptsEpic.js +4 -3
  4. package/lib/esm/view/expenseAutomationView/epics/missingReceipts/searchTransactionsForManualMatchEpic.js +5 -5
  5. package/lib/esm/view/expenseAutomationView/epics/missingReceipts/watchBulkUploadBatchStatusEpic.js +1 -1
  6. package/lib/esm/view/expenseAutomationView/payload/missingReceiptsPayload.js +14 -11
  7. package/lib/esm/view/expenseAutomationView/reducers/missingReceiptsViewReducer.js +21 -20
  8. package/lib/esm/view/expenseAutomationView/selectors/missingReceiptsSelector.js +57 -34
  9. package/lib/esm/view/expenseAutomationView/types/missingReceiptsViewState.js +30 -1
  10. package/lib/index.d.ts +3 -2
  11. package/lib/index.js +43 -32
  12. package/lib/tsconfig.typecheck.tsbuildinfo +1 -1
  13. package/lib/view/expenseAutomationView/bulkUploadTiming.d.ts +5 -0
  14. package/lib/view/expenseAutomationView/bulkUploadTiming.js +8 -0
  15. package/lib/view/expenseAutomationView/epics/missingReceipts/bulkUploadReceiptsEpic.d.ts +3 -0
  16. package/lib/view/expenseAutomationView/epics/missingReceipts/bulkUploadReceiptsEpic.js +2 -1
  17. package/lib/view/expenseAutomationView/epics/missingReceipts/searchTransactionsForManualMatchEpic.js +5 -5
  18. package/lib/view/expenseAutomationView/epics/missingReceipts/watchBulkUploadBatchStatusEpic.js +1 -1
  19. package/lib/view/expenseAutomationView/payload/missingReceiptsPayload.d.ts +1 -1
  20. package/lib/view/expenseAutomationView/payload/missingReceiptsPayload.js +14 -11
  21. package/lib/view/expenseAutomationView/reducers/missingReceiptsViewReducer.d.ts +7 -3
  22. package/lib/view/expenseAutomationView/reducers/missingReceiptsViewReducer.js +21 -20
  23. package/lib/view/expenseAutomationView/selectors/missingReceiptsSelector.js +57 -34
  24. package/lib/view/expenseAutomationView/types/missingReceiptsViewState.d.ts +20 -9
  25. package/lib/view/expenseAutomationView/types/missingReceiptsViewState.js +39 -2
  26. package/package.json +1 -1
@@ -0,0 +1,5 @@
1
+ /**
2
+ * After upload API success, hold the bar at 100% this long before transitioning to matching,
3
+ * so the fill animation can complete without an abrupt swap to the auto-matching banner.
4
+ */
5
+ export declare const BULK_UPLOAD_BAR_COMPLETE_HOLD_MS = 400;
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.BULK_UPLOAD_BAR_COMPLETE_HOLD_MS = void 0;
4
+ /**
5
+ * After upload API success, hold the bar at 100% this long before transitioning to matching,
6
+ * so the fill animation can complete without an abrupt swap to the auto-matching banner.
7
+ */
8
+ exports.BULK_UPLOAD_BAR_COMPLETE_HOLD_MS = 400;
@@ -12,4 +12,7 @@ export declare const bulkUploadReceiptsEpic: (actions$: ActionsObservable<Action
12
12
  error: import("../../../../responsePayload").ZeniAPIStatus;
13
13
  };
14
14
  type: "expenseAutomationMissingReceiptsView/bulkUploadReceiptsFailure";
15
+ } | {
16
+ payload: number;
17
+ type: "expenseAutomationMissingReceiptsView/updateBulkUploadProgress";
15
18
  }>;
@@ -4,6 +4,7 @@ exports.bulkUploadReceiptsEpic = void 0;
4
4
  const rxjs_1 = require("rxjs");
5
5
  const operators_1 = require("rxjs/operators");
6
6
  const responsePayload_1 = require("../../../../responsePayload");
7
+ const bulkUploadTiming_1 = require("../../bulkUploadTiming");
7
8
  const missingReceiptsViewReducer_1 = require("../../reducers/missingReceiptsViewReducer");
8
9
  const bulkUploadReceiptsEpic = (actions$, _state$, zeniAPI) => actions$.pipe((0, operators_1.filter)(missingReceiptsViewReducer_1.bulkUploadReceipts.match), (0, operators_1.mergeMap)((action) => {
9
10
  const { files } = action.payload;
@@ -21,7 +22,7 @@ const bulkUploadReceiptsEpic = (actions$, _state$, zeniAPI) => actions$.pipe((0,
21
22
  error: (0, responsePayload_1.createZeniAPIStatus)('Unexpected Error', 'Bulk upload succeeded but batch_id was missing or empty.'),
22
23
  }));
23
24
  }
24
- return (0, rxjs_1.of)((0, missingReceiptsViewReducer_1.bulkUploadReceiptsSuccess)({ batchId }));
25
+ return (0, rxjs_1.concat)((0, rxjs_1.of)((0, missingReceiptsViewReducer_1.updateBulkUploadProgress)(100)), (0, rxjs_1.timer)(bulkUploadTiming_1.BULK_UPLOAD_BAR_COMPLETE_HOLD_MS).pipe((0, operators_1.mergeMap)(() => (0, rxjs_1.of)((0, missingReceiptsViewReducer_1.bulkUploadReceiptsSuccess)({ batchId })))));
25
26
  }
26
27
  return (0, rxjs_1.of)((0, missingReceiptsViewReducer_1.bulkUploadReceiptsFailure)({ error: response.status }));
27
28
  }), (0, operators_1.catchError)((error) => (0, rxjs_1.of)((0, missingReceiptsViewReducer_1.bulkUploadReceiptsFailure)({
@@ -18,14 +18,14 @@ const transactionsViewState_1 = require("../../types/transactionsViewState");
18
18
  exports.MANUAL_TRANSACTION_SEARCH_AUTO_CATEGORIZED = false;
19
19
  const searchTransactionsForManualMatchEpic = (actions$, state$, zeniAPI) => {
20
20
  const searchActions$ = actions$.pipe((0, operators_1.filter)(missingReceiptsViewReducer_1.searchTransactionsForManualMatch.match));
21
- const pagination$ = searchActions$.pipe((0, operators_1.filter)((a) => a.payload.pageToken != null));
21
+ const pagination$ = searchActions$.pipe((0, operators_1.filter)((action) => action.payload.pageToken != null));
22
22
  /**
23
23
  * No API for empty or 1-char queries; immediate merge so switchMap cancels any in-flight HTTP.
24
24
  */
25
- const newSearchTooShortOrClear$ = searchActions$.pipe((0, operators_1.filter)((a) => a.payload.pageToken == null &&
26
- a.payload.query.trim().length < 2));
27
- const newSearchDebounced$ = searchActions$.pipe((0, operators_1.filter)((a) => a.payload.pageToken == null &&
28
- a.payload.query.trim().length >= 2), (0, operators_1.debounceTime)(300));
25
+ const newSearchTooShortOrClear$ = searchActions$.pipe((0, operators_1.filter)((action) => action.payload.pageToken == null &&
26
+ action.payload.query.trim().length < 2));
27
+ const newSearchDebounced$ = searchActions$.pipe((0, operators_1.filter)((action) => action.payload.pageToken == null &&
28
+ action.payload.query.trim().length >= 2), (0, operators_1.debounceTime)(300));
29
29
  return (0, rxjs_1.merge)(pagination$, newSearchTooShortOrClear$, newSearchDebounced$).pipe((0, operators_1.switchMap)((action) => {
30
30
  const { query, pageToken } = action.payload;
31
31
  if (pageToken == null &&
@@ -31,7 +31,7 @@ exports.pusherBatchStatusCompletionEpic = pusherBatchStatusCompletionEpic;
31
31
  const pollBulkUploadBatchStatusEpic = (actions$, _state$, zeniAPI) => actions$.pipe((0, operators_1.filter)(missingReceiptsViewReducer_1.bulkUploadReceiptsSuccess.match), (0, operators_1.mergeMap)((action) => {
32
32
  const { batchId } = action.payload;
33
33
  let pollErrorNotified = false;
34
- return (0, rxjs_1.timer)(FALLBACK_FIRST_DELAY_MS, FALLBACK_POLL_INTERVAL_MS).pipe((0, operators_1.takeUntil)((0, rxjs_1.merge)(actions$.pipe((0, operators_1.filter)(missingReceiptsViewReducer_1.clearBulkUpload.match)), actions$.pipe((0, operators_1.filter)(missingReceiptsViewReducer_1.pusherBatchStatusUpdate.match), (0, operators_1.filter)((a) => a.payload.batchId === batchId)), actions$.pipe((0, operators_1.filter)(missingReceiptsViewReducer_1.fetchBulkUploadBatchDetailsSuccess.match), (0, operators_1.filter)((a) => a.payload.batchId === batchId)))), (0, operators_1.switchMap)(() => zeniAPI
34
+ return (0, rxjs_1.timer)(FALLBACK_FIRST_DELAY_MS, FALLBACK_POLL_INTERVAL_MS).pipe((0, operators_1.takeUntil)((0, rxjs_1.merge)(actions$.pipe((0, operators_1.filter)(missingReceiptsViewReducer_1.clearBulkUpload.match)), actions$.pipe((0, operators_1.filter)(missingReceiptsViewReducer_1.pusherBatchStatusUpdate.match), (0, operators_1.filter)((action) => action.payload.batchId === batchId)), actions$.pipe((0, operators_1.filter)(missingReceiptsViewReducer_1.fetchBulkUploadBatchDetailsSuccess.match), (0, operators_1.filter)((action) => action.payload.batchId === batchId)))), (0, operators_1.switchMap)(() => zeniAPI
35
35
  .getJSON(`${zeniAPI.apiEndPoints.communicationAgentMicroServiceBaseUrl}/1.0/batches/${batchId}`)
36
36
  .pipe((0, operators_1.mergeMap)((response) => {
37
37
  /** Same batch-details URL; polls until `status` is completed (Pusher may win first). */
@@ -3,7 +3,7 @@ import { TransactionPayload } from '../../../entity/transaction/payloadTypes/tra
3
3
  import { SupportedTransactionPayload } from '../../../entity/transaction/transactionState';
4
4
  import { ZeniAPIResponse } from '../../../responsePayload';
5
5
  import type { MonthYearPeriodId } from '../../../commonStateTypes/timePeriod';
6
- import type { BatchDetails, BatchFile, BatchFileStatus, BatchListItem, BatchStatus, BatchSummary, ManualSearchResult } from '../types/missingReceiptsViewState';
6
+ import { type BatchDetails, type BatchFile, type BatchFileStatus, type BatchListItem, type BatchStatus, type BatchSummary, type ManualSearchResult } from '../types/missingReceiptsViewState';
7
7
  export interface MissingReceiptsQueryPayload {
8
8
  end_date: string;
9
9
  is_attachment_missing_only: boolean;
@@ -14,6 +14,7 @@ exports.toBatchListItem = toBatchListItem;
14
14
  exports.supportedTransactionPayloadToManualSearchResult = supportedTransactionPayloadToManualSearchResult;
15
15
  const urlPayload_1 = require("../../../commonPayloadTypes/urlPayload");
16
16
  const transactionPayload_1 = require("../../../entity/transaction/payloadTypes/transactionPayload");
17
+ const missingReceiptsViewState_1 = require("../types/missingReceiptsViewState");
17
18
  // -- Converter functions --
18
19
  /**
19
20
  * Maps batch-details API `files[].status` strings to canonical {@link BatchFileStatus}.
@@ -21,8 +22,8 @@ const transactionPayload_1 = require("../../../entity/transaction/payloadTypes/t
21
22
  * holds untyped status values.
22
23
  */
23
24
  function parseBatchFileStatus(raw) {
24
- const s = raw.trim().toLowerCase().replace(/-/g, '_');
25
- switch (s) {
25
+ const normalizedStatus = raw.trim().toLowerCase().replace(/-/g, '_');
26
+ switch (normalizedStatus) {
26
27
  case 'exact_match':
27
28
  case 'matched':
28
29
  return 'exact_match';
@@ -44,9 +45,9 @@ function parseBatchFileStatus(raw) {
44
45
  function toBatchFile(payload, filesEndPoint) {
45
46
  return {
46
47
  attachmentId: payload.attachment_id,
47
- candidates: payload.candidates?.map((c) => ({
48
- transactionId: c.transaction_id,
49
- matchScore: c.match_score,
48
+ candidates: payload.candidates?.map((candidate) => ({
49
+ transactionId: candidate.transaction_id,
50
+ matchScore: candidate.match_score,
50
51
  })),
51
52
  fileDownloadUrl: payload.file_id != null && filesEndPoint != null
52
53
  ? `${filesEndPoint}/1.0/files/${payload.file_id}?query=${encodeURIComponent(JSON.stringify({ download_file: true }))}`
@@ -54,9 +55,11 @@ function toBatchFile(payload, filesEndPoint) {
54
55
  fileId: payload.file_id,
55
56
  filePreviewUrl: payload.file_preview_url,
56
57
  filename: payload.filename,
57
- matchSource: payload.match_source,
58
+ matchSource: payload.match_source != null
59
+ ? (0, missingReceiptsViewState_1.toMatchSource)(payload.match_source)
60
+ : undefined,
58
61
  matchedTransactionId: payload.matched_transaction?.transaction_id,
59
- status: parseBatchFileStatus(payload.status),
62
+ status: (0, missingReceiptsViewState_1.toBatchFileStatus)(payload.status),
60
63
  };
61
64
  }
62
65
  function extractTransactionPayloadsFromBatchFiles(files) {
@@ -106,8 +109,8 @@ function toBatchDetails(payload, filesEndPoint) {
106
109
  return {
107
110
  batchId: payload.batch_id,
108
111
  createdAt: payload.created_at,
109
- files: payload.files.map((f) => toBatchFile(f, filesEndPoint)),
110
- status: payload.status,
112
+ files: payload.files.map((file) => toBatchFile(file, filesEndPoint)),
113
+ status: (0, missingReceiptsViewState_1.toBatchStatusValue)(payload.status),
111
114
  summary: toBatchSummary(payload.summary),
112
115
  };
113
116
  }
@@ -121,7 +124,7 @@ function isBatchListStatusCompleted(status) {
121
124
  * statuses for UI; only `completed` rows should trigger batch-details requests.
122
125
  */
123
126
  function filterBatchListItemsForBatchDetailsFetch(batches) {
124
- return batches.filter((b) => isBatchListStatusCompleted(b.status));
127
+ return batches.filter((batch) => isBatchListStatusCompleted(batch.status));
125
128
  }
126
129
  /**
127
130
  * Batch details API response `status` field — only completed payloads should be stored from
@@ -132,7 +135,7 @@ function isBatchDetailsApiStatusCompleted(status) {
132
135
  }
133
136
  function findBatchListItemForBatchId(batchListByPeriod, batchId) {
134
137
  for (const list of Object.values(batchListByPeriod)) {
135
- const found = list.find((b) => b.batchId === batchId);
138
+ const found = list.find((batch) => batch.batchId === batchId);
136
139
  if (found != null) {
137
140
  return found;
138
141
  }
@@ -10,6 +10,8 @@ import type { MonthYearPeriodId } from '../../../commonStateTypes/timePeriod';
10
10
  export declare const getCompletedTransactionsCacheKey: (periodId: MonthYearPeriodId, sortKey: BulkUploadSortKey, sortOrder: SortOrder, subTab: CompletedSubTab) => string;
11
11
  export declare const initialBulkUploadState: BulkUploadState;
12
12
  export declare const initialState: MissingReceiptsViewState;
13
+ /** Epic trigger only; batch-details fetch is handled in epics. */
14
+ export declare const fetchBulkUploadBatchDetails: import("@reduxjs/toolkit").ActionCreatorWithoutPayload<"expenseAutomationMissingReceiptsView/fetchBulkUploadBatchDetails">;
13
15
  export declare const fetchMissingReceipts: import("@reduxjs/toolkit").ActionCreatorWithPreparedPayload<[period: TimePeriod, minimumTransactionAmount: Amount, cacheOverride?: any, refreshViewInBackground?: any], {
14
16
  period: TimePeriod;
15
17
  minimumTransactionAmount: Amount;
@@ -38,9 +40,11 @@ export declare const fetchMissingReceipts: import("@reduxjs/toolkit").ActionCrea
38
40
  error: ZeniAPIStatus;
39
41
  }, "expenseAutomationMissingReceiptsView/bulkUploadReceiptsFailure">, pusherBatchStatusUpdate: import("@reduxjs/toolkit").ActionCreatorWithPayload<BatchStatus, "expenseAutomationMissingReceiptsView/pusherBatchStatusUpdate">, requestMissingReceiptsTabNavigation: import("@reduxjs/toolkit").ActionCreatorWithPayload<{
40
42
  tab: BulkUploadResultsTab;
41
- }, "expenseAutomationMissingReceiptsView/requestMissingReceiptsTabNavigation">, clearMissingReceiptsTabNavigation: import("@reduxjs/toolkit").ActionCreatorWithoutPayload<"expenseAutomationMissingReceiptsView/clearMissingReceiptsTabNavigation">, fetchBulkUploadBatchDetails: import("@reduxjs/toolkit").ActionCreatorWithoutPayload<"expenseAutomationMissingReceiptsView/fetchBulkUploadBatchDetails">, fetchBulkUploadBatchDetailsSuccess: import("@reduxjs/toolkit").ActionCreatorWithPayload<BatchDetails, "expenseAutomationMissingReceiptsView/fetchBulkUploadBatchDetailsSuccess">, fetchBulkUploadBatchDetailsFailure: import("@reduxjs/toolkit").ActionCreatorWithPayload<{
43
+ }, "expenseAutomationMissingReceiptsView/requestMissingReceiptsTabNavigation">, clearMissingReceiptsTabNavigation: import("@reduxjs/toolkit").ActionCreatorWithoutPayload<"expenseAutomationMissingReceiptsView/clearMissingReceiptsTabNavigation">, fetchBulkUploadBatchDetailsSuccess: import("@reduxjs/toolkit").ActionCreatorWithPayload<BatchDetails, "expenseAutomationMissingReceiptsView/fetchBulkUploadBatchDetailsSuccess">, fetchBulkUploadBatchDetailsFailure: import("@reduxjs/toolkit").ActionCreatorWithPreparedPayload<[payload: {
42
44
  error: ZeniAPIStatus;
43
- }, "expenseAutomationMissingReceiptsView/fetchBulkUploadBatchDetailsFailure">, storeBatchDetails: import("@reduxjs/toolkit").ActionCreatorWithPayload<BatchDetails, "expenseAutomationMissingReceiptsView/storeBatchDetails">, batchDetailFetchFailed: import("@reduxjs/toolkit").ActionCreatorWithPayload<{
45
+ }], {
46
+ error: ZeniAPIStatus;
47
+ }, "expenseAutomationMissingReceiptsView/fetchBulkUploadBatchDetailsFailure", never, never>, storeBatchDetails: import("@reduxjs/toolkit").ActionCreatorWithPayload<BatchDetails, "expenseAutomationMissingReceiptsView/storeBatchDetails">, batchDetailFetchFailed: import("@reduxjs/toolkit").ActionCreatorWithPayload<{
44
48
  batchId: ID;
45
49
  }, "expenseAutomationMissingReceiptsView/batchDetailFetchFailed">, setInitialBatchDetailsLoading: import("@reduxjs/toolkit").ActionCreatorWithoutPayload<"expenseAutomationMissingReceiptsView/setInitialBatchDetailsLoading">, fetchMoreBatchDetails: import("@reduxjs/toolkit").ActionCreatorWithoutPayload<"expenseAutomationMissingReceiptsView/fetchMoreBatchDetails">, fetchMoreBatchDetailsComplete: import("@reduxjs/toolkit").ActionCreatorWithoutPayload<"expenseAutomationMissingReceiptsView/fetchMoreBatchDetailsComplete">, fetchMoreBatchDetailsFailure: import("@reduxjs/toolkit").ActionCreatorWithPayload<{
46
50
  error: ZeniAPIStatus;
@@ -68,7 +72,7 @@ export declare const fetchMissingReceipts: import("@reduxjs/toolkit").ActionCrea
68
72
  transactionId: ID;
69
73
  }, "expenseAutomationMissingReceiptsView/confirmBulkUploadMatchSuccess">, confirmBulkUploadMatchFailure: import("@reduxjs/toolkit").ActionCreatorWithPayload<{
70
74
  error: ZeniAPIStatus;
71
- }, "expenseAutomationMissingReceiptsView/confirmBulkUploadMatchFailure">, setBulkUploadResultsTab: import("@reduxjs/toolkit").ActionCreatorWithPayload<BulkUploadResultsTab, "expenseAutomationMissingReceiptsView/setBulkUploadResultsTab">, setBulkUploadCompletedSubTab: import("@reduxjs/toolkit").ActionCreatorWithPayload<CompletedSubTab, "expenseAutomationMissingReceiptsView/setBulkUploadCompletedSubTab">, setBulkUploadSortConfig: import("@reduxjs/toolkit").ActionCreatorWithPayload<{
75
+ }, "expenseAutomationMissingReceiptsView/confirmBulkUploadMatchFailure">, setBulkUploadResultsTab: import("@reduxjs/toolkit").ActionCreatorWithPayload<"completed" | "unmatched", "expenseAutomationMissingReceiptsView/setBulkUploadResultsTab">, setBulkUploadCompletedSubTab: import("@reduxjs/toolkit").ActionCreatorWithPayload<"all" | "manual" | "ai_accountant", "expenseAutomationMissingReceiptsView/setBulkUploadCompletedSubTab">, setBulkUploadSortConfig: import("@reduxjs/toolkit").ActionCreatorWithPayload<{
72
76
  sortKey: BulkUploadSortKey;
73
77
  sortOrder: SortOrder;
74
78
  }, "expenseAutomationMissingReceiptsView/setBulkUploadSortConfig">, clearBulkUpload: import("@reduxjs/toolkit").ActionCreatorWithoutPayload<"expenseAutomationMissingReceiptsView/clearBulkUpload">, searchTransactionsForManualMatch: import("@reduxjs/toolkit").ActionCreatorWithPreparedPayload<[query: string, pageToken?: string | null | undefined], {
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  var _a;
3
3
  Object.defineProperty(exports, "__esModule", { value: true });
4
- exports.fetchCompletedTransactionsFailure = exports.fetchCompletedTransactionsSuccess = exports.fetchCompletedTransactions = exports.acknowledgeBulkUploadConfirmMatchComplete = exports.clearManualSearchResults = exports.searchTransactionsForManualMatchFailure = exports.searchTransactionsForManualMatchSuccess = exports.searchTransactionsForManualMatch = exports.clearBulkUpload = exports.setBulkUploadSortConfig = exports.setBulkUploadCompletedSubTab = exports.setBulkUploadResultsTab = exports.confirmBulkUploadMatchFailure = exports.confirmBulkUploadMatchSuccess = exports.confirmBulkUploadMatch = exports.fetchBulkUploadBatchesFailure = exports.fetchBulkUploadBatchesSuccess = exports.fetchBulkUploadBatches = exports.fetchMoreBatchDetailsFailure = exports.fetchMoreBatchDetailsComplete = exports.fetchMoreBatchDetails = exports.setInitialBatchDetailsLoading = exports.batchDetailFetchFailed = exports.storeBatchDetails = exports.fetchBulkUploadBatchDetailsFailure = exports.fetchBulkUploadBatchDetailsSuccess = exports.fetchBulkUploadBatchDetails = exports.clearMissingReceiptsTabNavigation = exports.requestMissingReceiptsTabNavigation = exports.pusherBatchStatusUpdate = exports.bulkUploadReceiptsFailure = exports.bulkUploadReceiptsSuccess = exports.updateBulkUploadProgress = exports.bulkUploadReceipts = exports.clearExpenseAutomationMissingReceiptsView = exports.markMissingReceiptAsDone = exports.updateMissingReceiptsUIState = exports.updateMissingReceiptUploadState = exports.uploadMissingReceiptSuccess = exports.fetchMissingReceiptsFailure = exports.fetchMissingReceiptsSuccess = exports.fetchMissingReceipts = exports.initialState = exports.initialBulkUploadState = exports.getCompletedTransactionsCacheKey = void 0;
4
+ exports.fetchCompletedTransactionsFailure = exports.fetchCompletedTransactionsSuccess = exports.fetchCompletedTransactions = exports.acknowledgeBulkUploadConfirmMatchComplete = exports.clearManualSearchResults = exports.searchTransactionsForManualMatchFailure = exports.searchTransactionsForManualMatchSuccess = exports.searchTransactionsForManualMatch = exports.clearBulkUpload = exports.setBulkUploadSortConfig = exports.setBulkUploadCompletedSubTab = exports.setBulkUploadResultsTab = exports.confirmBulkUploadMatchFailure = exports.confirmBulkUploadMatchSuccess = exports.confirmBulkUploadMatch = exports.fetchBulkUploadBatchesFailure = exports.fetchBulkUploadBatchesSuccess = exports.fetchBulkUploadBatches = exports.fetchMoreBatchDetailsFailure = exports.fetchMoreBatchDetailsComplete = exports.fetchMoreBatchDetails = exports.setInitialBatchDetailsLoading = exports.batchDetailFetchFailed = exports.storeBatchDetails = exports.fetchBulkUploadBatchDetailsFailure = exports.fetchBulkUploadBatchDetailsSuccess = exports.clearMissingReceiptsTabNavigation = exports.requestMissingReceiptsTabNavigation = exports.pusherBatchStatusUpdate = exports.bulkUploadReceiptsFailure = exports.bulkUploadReceiptsSuccess = exports.updateBulkUploadProgress = exports.bulkUploadReceipts = exports.clearExpenseAutomationMissingReceiptsView = exports.markMissingReceiptAsDone = exports.updateMissingReceiptsUIState = exports.updateMissingReceiptUploadState = exports.uploadMissingReceiptSuccess = exports.fetchMissingReceiptsFailure = exports.fetchMissingReceiptsSuccess = exports.fetchMissingReceipts = exports.fetchBulkUploadBatchDetails = exports.initialState = exports.initialBulkUploadState = exports.getCompletedTransactionsCacheKey = void 0;
5
5
  const toolkit_1 = require("@reduxjs/toolkit");
6
6
  const timePeriod_1 = require("../../../commonStateTypes/timePeriod");
7
7
  const missingReceiptsViewState_1 = require("../types/missingReceiptsViewState");
@@ -56,6 +56,8 @@ exports.initialState = {
56
56
  return this.fetchState == 'Completed';
57
57
  },
58
58
  };
59
+ /** Epic trigger only; batch-details fetch is handled in epics. */
60
+ exports.fetchBulkUploadBatchDetails = (0, toolkit_1.createAction)('expenseAutomationMissingReceiptsView/fetchBulkUploadBatchDetails');
59
61
  const expenseAutomationMissingReceiptsView = (0, toolkit_1.createSlice)({
60
62
  name: 'expenseAutomationMissingReceiptsView',
61
63
  initialState: exports.initialState,
@@ -159,8 +161,7 @@ const expenseAutomationMissingReceiptsView = (0, toolkit_1.createSlice)({
159
161
  },
160
162
  // -- Bulk Upload Actions --
161
163
  bulkUploadReceipts: {
162
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
163
- reducer(draft, _action) {
164
+ reducer(draft) {
164
165
  draft.bulkUpload.phase = 'uploading';
165
166
  draft.bulkUpload.uploadProgress = 0;
166
167
  draft.bulkUpload.uploadStatus = {
@@ -177,6 +178,7 @@ const expenseAutomationMissingReceiptsView = (0, toolkit_1.createSlice)({
177
178
  },
178
179
  bulkUploadReceiptsSuccess(draft, action) {
179
180
  draft.bulkUpload.currentBatchId = action.payload.batchId;
181
+ draft.bulkUpload.uploadProgress = 100;
180
182
  draft.bulkUpload.uploadStatus = {
181
183
  fetchState: 'Completed',
182
184
  error: undefined,
@@ -210,18 +212,18 @@ const expenseAutomationMissingReceiptsView = (0, toolkit_1.createSlice)({
210
212
  clearMissingReceiptsTabNavigation(draft) {
211
213
  draft.pendingMissingReceiptsTabNavigation = null;
212
214
  },
213
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
214
- fetchBulkUploadBatchDetails(_draft) {
215
- // trigger epic, no state change needed
216
- },
217
215
  fetchBulkUploadBatchDetailsSuccess(draft, action) {
218
216
  const details = action.payload;
219
217
  draft.bulkUpload.batchDetailsById[details.batchId] = details;
220
218
  draft.bulkUpload.phase = 'completed';
221
219
  },
222
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
223
- fetchBulkUploadBatchDetailsFailure(draft, _action) {
224
- draft.bulkUpload.phase = 'completed';
220
+ fetchBulkUploadBatchDetailsFailure: {
221
+ reducer(draft) {
222
+ draft.bulkUpload.phase = 'completed';
223
+ },
224
+ prepare(payload) {
225
+ return { payload };
226
+ },
225
227
  },
226
228
  storeBatchDetails(draft, action) {
227
229
  const details = action.payload;
@@ -252,8 +254,8 @@ const expenseAutomationMissingReceiptsView = (0, toolkit_1.createSlice)({
252
254
  error: undefined,
253
255
  };
254
256
  },
255
- fetchMoreBatchDetails(_draft) {
256
- _draft.bulkUpload.batchDetailsPaginationState = {
257
+ fetchMoreBatchDetails(draft) {
258
+ draft.bulkUpload.batchDetailsPaginationState = {
257
259
  fetchState: 'In-Progress',
258
260
  error: undefined,
259
261
  };
@@ -291,11 +293,11 @@ const expenseAutomationMissingReceiptsView = (0, toolkit_1.createSlice)({
291
293
  };
292
294
  },
293
295
  prepare(input) {
294
- const o = input ?? {};
296
+ const fetchOptions = input ?? {};
295
297
  return {
296
298
  payload: {
297
- cacheOverride: o.cacheOverride === true,
298
- invalidateBatchDetailsCache: o.invalidateBatchDetailsCache === true,
299
+ cacheOverride: fetchOptions.cacheOverride === true,
300
+ invalidateBatchDetailsCache: fetchOptions.invalidateBatchDetailsCache === true,
299
301
  },
300
302
  };
301
303
  },
@@ -329,8 +331,7 @@ const expenseAutomationMissingReceiptsView = (0, toolkit_1.createSlice)({
329
331
  };
330
332
  },
331
333
  confirmBulkUploadMatch: {
332
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
333
- reducer(draft, _action) {
334
+ reducer(draft) {
334
335
  draft.bulkUpload.confirmMatchStatus = {
335
336
  fetchState: 'In-Progress',
336
337
  error: undefined,
@@ -348,7 +349,7 @@ const expenseAutomationMissingReceiptsView = (0, toolkit_1.createSlice)({
348
349
  };
349
350
  const details = draft.bulkUpload.batchDetailsById[batchId];
350
351
  if (details != null) {
351
- const file = details.files.find((f) => f.attachmentId === attachmentId);
352
+ const file = details.files.find((batchFile) => batchFile.attachmentId === attachmentId);
352
353
  if (file != null) {
353
354
  const originalStatus = file.status;
354
355
  file.status = 'exact_match';
@@ -431,7 +432,7 @@ const expenseAutomationMissingReceiptsView = (0, toolkit_1.createSlice)({
431
432
  const { append, nextPageToken, results, totalCount } = action.payload;
432
433
  if (append) {
433
434
  const merged = [...draft.bulkUpload.manualSearch.results, ...results];
434
- const byId = new Map(merged.map((r) => [r.transactionId, r]));
435
+ const byId = new Map(merged.map((result) => [result.transactionId, result]));
435
436
  draft.bulkUpload.manualSearch.results = Array.from(byId.values());
436
437
  }
437
438
  else {
@@ -536,7 +537,7 @@ const expenseAutomationMissingReceiptsView = (0, toolkit_1.createSlice)({
536
537
  });
537
538
  _a = expenseAutomationMissingReceiptsView.actions, exports.fetchMissingReceipts = _a.fetchMissingReceipts, exports.fetchMissingReceiptsSuccess = _a.fetchMissingReceiptsSuccess, exports.fetchMissingReceiptsFailure = _a.fetchMissingReceiptsFailure, exports.uploadMissingReceiptSuccess = _a.uploadMissingReceiptSuccess, exports.updateMissingReceiptUploadState = _a.updateMissingReceiptUploadState, exports.updateMissingReceiptsUIState = _a.updateMissingReceiptsUIState, exports.markMissingReceiptAsDone = _a.markMissingReceiptAsDone, exports.clearExpenseAutomationMissingReceiptsView = _a.clearExpenseAutomationMissingReceiptsView,
538
539
  // Bulk Upload
539
- exports.bulkUploadReceipts = _a.bulkUploadReceipts, exports.updateBulkUploadProgress = _a.updateBulkUploadProgress, exports.bulkUploadReceiptsSuccess = _a.bulkUploadReceiptsSuccess, exports.bulkUploadReceiptsFailure = _a.bulkUploadReceiptsFailure, exports.pusherBatchStatusUpdate = _a.pusherBatchStatusUpdate, exports.requestMissingReceiptsTabNavigation = _a.requestMissingReceiptsTabNavigation, exports.clearMissingReceiptsTabNavigation = _a.clearMissingReceiptsTabNavigation, exports.fetchBulkUploadBatchDetails = _a.fetchBulkUploadBatchDetails, exports.fetchBulkUploadBatchDetailsSuccess = _a.fetchBulkUploadBatchDetailsSuccess, exports.fetchBulkUploadBatchDetailsFailure = _a.fetchBulkUploadBatchDetailsFailure, exports.storeBatchDetails = _a.storeBatchDetails, exports.batchDetailFetchFailed = _a.batchDetailFetchFailed, exports.setInitialBatchDetailsLoading = _a.setInitialBatchDetailsLoading, exports.fetchMoreBatchDetails = _a.fetchMoreBatchDetails, exports.fetchMoreBatchDetailsComplete = _a.fetchMoreBatchDetailsComplete, exports.fetchMoreBatchDetailsFailure = _a.fetchMoreBatchDetailsFailure, exports.fetchBulkUploadBatches = _a.fetchBulkUploadBatches, exports.fetchBulkUploadBatchesSuccess = _a.fetchBulkUploadBatchesSuccess, exports.fetchBulkUploadBatchesFailure = _a.fetchBulkUploadBatchesFailure, exports.confirmBulkUploadMatch = _a.confirmBulkUploadMatch, exports.confirmBulkUploadMatchSuccess = _a.confirmBulkUploadMatchSuccess, exports.confirmBulkUploadMatchFailure = _a.confirmBulkUploadMatchFailure, exports.setBulkUploadResultsTab = _a.setBulkUploadResultsTab, exports.setBulkUploadCompletedSubTab = _a.setBulkUploadCompletedSubTab, exports.setBulkUploadSortConfig = _a.setBulkUploadSortConfig, exports.clearBulkUpload = _a.clearBulkUpload, exports.searchTransactionsForManualMatch = _a.searchTransactionsForManualMatch, exports.searchTransactionsForManualMatchSuccess = _a.searchTransactionsForManualMatchSuccess, exports.searchTransactionsForManualMatchFailure = _a.searchTransactionsForManualMatchFailure, exports.clearManualSearchResults = _a.clearManualSearchResults, exports.acknowledgeBulkUploadConfirmMatchComplete = _a.acknowledgeBulkUploadConfirmMatchComplete,
540
+ exports.bulkUploadReceipts = _a.bulkUploadReceipts, exports.updateBulkUploadProgress = _a.updateBulkUploadProgress, exports.bulkUploadReceiptsSuccess = _a.bulkUploadReceiptsSuccess, exports.bulkUploadReceiptsFailure = _a.bulkUploadReceiptsFailure, exports.pusherBatchStatusUpdate = _a.pusherBatchStatusUpdate, exports.requestMissingReceiptsTabNavigation = _a.requestMissingReceiptsTabNavigation, exports.clearMissingReceiptsTabNavigation = _a.clearMissingReceiptsTabNavigation, exports.fetchBulkUploadBatchDetailsSuccess = _a.fetchBulkUploadBatchDetailsSuccess, exports.fetchBulkUploadBatchDetailsFailure = _a.fetchBulkUploadBatchDetailsFailure, exports.storeBatchDetails = _a.storeBatchDetails, exports.batchDetailFetchFailed = _a.batchDetailFetchFailed, exports.setInitialBatchDetailsLoading = _a.setInitialBatchDetailsLoading, exports.fetchMoreBatchDetails = _a.fetchMoreBatchDetails, exports.fetchMoreBatchDetailsComplete = _a.fetchMoreBatchDetailsComplete, exports.fetchMoreBatchDetailsFailure = _a.fetchMoreBatchDetailsFailure, exports.fetchBulkUploadBatches = _a.fetchBulkUploadBatches, exports.fetchBulkUploadBatchesSuccess = _a.fetchBulkUploadBatchesSuccess, exports.fetchBulkUploadBatchesFailure = _a.fetchBulkUploadBatchesFailure, exports.confirmBulkUploadMatch = _a.confirmBulkUploadMatch, exports.confirmBulkUploadMatchSuccess = _a.confirmBulkUploadMatchSuccess, exports.confirmBulkUploadMatchFailure = _a.confirmBulkUploadMatchFailure, exports.setBulkUploadResultsTab = _a.setBulkUploadResultsTab, exports.setBulkUploadCompletedSubTab = _a.setBulkUploadCompletedSubTab, exports.setBulkUploadSortConfig = _a.setBulkUploadSortConfig, exports.clearBulkUpload = _a.clearBulkUpload, exports.searchTransactionsForManualMatch = _a.searchTransactionsForManualMatch, exports.searchTransactionsForManualMatchSuccess = _a.searchTransactionsForManualMatchSuccess, exports.searchTransactionsForManualMatchFailure = _a.searchTransactionsForManualMatchFailure, exports.clearManualSearchResults = _a.clearManualSearchResults, exports.acknowledgeBulkUploadConfirmMatchComplete = _a.acknowledgeBulkUploadConfirmMatchComplete,
540
541
  // Completed Transactions
541
542
  exports.fetchCompletedTransactions = _a.fetchCompletedTransactions, exports.fetchCompletedTransactionsSuccess = _a.fetchCompletedTransactionsSuccess, exports.fetchCompletedTransactionsFailure = _a.fetchCompletedTransactionsFailure;
542
543
  exports.default = expenseAutomationMissingReceiptsView.reducer;
@@ -70,45 +70,68 @@ function getExpenseAutomationMissingReceiptsView(state) {
70
70
  * so we do not block the whole tab while other rows are not fetched yet.
71
71
  */
72
72
  const primaryBatchIdFromDetailsOrder = getPrimaryBatchIdFromBatchListOrder(batchList, bulkUpload.batchDetailsById, bulkUpload.failedBatchDetailIds);
73
- /** During upload/matching, the in-flight batch may not appear in batchList yet — prefer currentBatchId. */
74
- const unmatchedSectionBatchId = bulkUpload.phase === 'matching' || bulkUpload.phase === 'uploading'
75
- ? bulkUpload.currentBatchId ?? primaryBatchIdFromDetailsOrder
76
- : primaryBatchIdFromDetailsOrder;
77
- const completedBatchesInApiOrder = batchList.filter((b) => (0, missingReceiptsPayload_1.isBatchListStatusCompleted)(b.status));
73
+ /**
74
+ * During upload/matching, prefer `currentBatchId` only when it is not yet in the period
75
+ * `batchList` (true in-flight), or when its details are completed and include unmatched-tab work.
76
+ * Otherwise keep `primaryBatchIdFromDetailsOrder` so a new batch with no `possible_matches` /
77
+ * `no_match` rows yet does not vacate the primary column and push older batches into "past".
78
+ */
79
+ const unmatchedSectionBatchId = (() => {
80
+ const phase = bulkUpload.phase;
81
+ if (phase !== 'matching' && phase !== 'uploading') {
82
+ return primaryBatchIdFromDetailsOrder;
83
+ }
84
+ const currentId = bulkUpload.currentBatchId;
85
+ if (currentId == null) {
86
+ return primaryBatchIdFromDetailsOrder;
87
+ }
88
+ const currentInBatchList = batchList.some((b) => b.batchId === currentId);
89
+ if (!currentInBatchList) {
90
+ return currentId;
91
+ }
92
+ const currentDetails = bulkUpload.batchDetailsById[currentId];
93
+ if (currentDetails != null &&
94
+ currentDetails.status === 'completed' &&
95
+ batchDetailsHasUnmatchedWork(currentDetails)) {
96
+ return currentId;
97
+ }
98
+ return primaryBatchIdFromDetailsOrder;
99
+ })();
100
+ const completedBatchesInApiOrder = batchList.filter((batchListItem) => (0, missingReceiptsPayload_1.isBatchListStatusCompleted)(batchListItem.status));
78
101
  const currentBatchDetails = unmatchedSectionBatchId != null
79
102
  ? bulkUpload.batchDetailsById[unmatchedSectionBatchId]
80
103
  : undefined;
81
104
  const resolvedFiles = currentBatchDetails?.files.map((file) => resolveBatchFile(file, currentBatchDetails.batchId, transactionState));
82
105
  const failedIds = new Set(bulkUpload.failedBatchDetailIds);
83
- const hasMoreBatchDetails = completedBatchesInApiOrder.some((b) => bulkUpload.batchDetailsById[b.batchId] == null &&
84
- !failedIds.has(b.batchId));
106
+ const hasMoreBatchDetails = completedBatchesInApiOrder.some((batchListItem) => bulkUpload.batchDetailsById[batchListItem.batchId] == null &&
107
+ !failedIds.has(batchListItem.batchId));
85
108
  const getSortValue = (file) => {
86
- const t = file.matchedTransaction;
87
- if (t == null) {
109
+ const matchedTransaction = file.matchedTransaction;
110
+ if (matchedTransaction == null) {
88
111
  return null;
89
112
  }
90
113
  switch (bulkUpload.sortKey) {
91
114
  case 'vendor':
92
- return (t.vendorName ?? t.description)?.toLowerCase() ?? null;
115
+ return (matchedTransaction.vendorName ?? matchedTransaction.description)?.toLowerCase() ?? null;
93
116
  case 'category': {
94
- const line = t.lines?.[0];
117
+ const line = matchedTransaction.lines?.[0];
95
118
  return line?.account?.accountName?.toLowerCase() ?? null;
96
119
  }
97
120
  case 'class': {
98
- const line = t.lines?.[0];
121
+ const line = matchedTransaction.lines?.[0];
99
122
  return line?.class?.className?.toLowerCase() ?? null;
100
123
  }
101
124
  case 'date':
102
- return t.date.valueOf();
125
+ return matchedTransaction.date.valueOf();
103
126
  case 'amount':
104
- return t.amount.amount;
127
+ return matchedTransaction.amount.amount;
105
128
  default:
106
129
  return null;
107
130
  }
108
131
  };
109
132
  const bulkUploadSortDirection = bulkUpload.sortOrder === 'ascending' ? 'asc' : 'desc';
110
- const matchedFiles = (0, orderBy_1.default)(resolvedFiles?.filter((f) => f.status === 'exact_match') ?? [], getSortValue, bulkUploadSortDirection);
111
- const unmatchedFiles = (0, orderBy_1.default)(resolvedFiles?.filter((f) => (0, missingReceiptsViewState_1.isUnmatchedTabFileStatus)(f.status)) ?? [], getSortValue, bulkUploadSortDirection);
133
+ const matchedFiles = (0, orderBy_1.default)(resolvedFiles?.filter((resolvedFile) => resolvedFile.status === 'exact_match') ?? [], getSortValue, bulkUploadSortDirection);
134
+ const unmatchedFiles = (0, orderBy_1.default)(resolvedFiles?.filter((resolvedFile) => (0, missingReceiptsViewState_1.isUnmatchedTabFileStatus)(resolvedFile.status)) ?? [], getSortValue, bulkUploadSortDirection);
112
135
  const progress = currentBatchStatus != null
113
136
  ? {
114
137
  ...currentBatchStatus.progress,
@@ -125,16 +148,16 @@ function getExpenseAutomationMissingReceiptsView(state) {
125
148
  * that has details loaded (otherwise past is empty and receipts vanish from the UI).
126
149
  */
127
150
  const pastBatches = unmatchedSectionBatchId != null
128
- ? batchList.filter((b) => b.batchId !== unmatchedSectionBatchId)
151
+ ? batchList.filter((batchListItem) => batchListItem.batchId !== unmatchedSectionBatchId)
129
152
  : batchList;
130
- const pastUnmatchedFiles = pastBatches.flatMap((b) => {
131
- const details = bulkUpload.batchDetailsById[b.batchId];
153
+ const pastUnmatchedFiles = pastBatches.flatMap((pastBatch) => {
154
+ const details = bulkUpload.batchDetailsById[pastBatch.batchId];
132
155
  if (details == null) {
133
156
  return [];
134
157
  }
135
158
  return details.files
136
- .filter((f) => (0, missingReceiptsViewState_1.isUnmatchedTabFileStatus)(f.status))
137
- .map((f) => resolveBatchFile(f, b.batchId, transactionState));
159
+ .filter((batchFile) => (0, missingReceiptsViewState_1.isUnmatchedTabFileStatus)(batchFile.status))
160
+ .map((batchFile) => resolveBatchFile(batchFile, pastBatch.batchId, transactionState));
138
161
  });
139
162
  const completedTransactionsCacheKey = monthYearPeriodId != null
140
163
  ? (0, missingReceiptsViewReducer_1.getCompletedTransactionsCacheKey)(monthYearPeriodId, bulkUpload.sortKey, bulkUpload.sortOrder, bulkUpload.completedSubTab)
@@ -153,11 +176,11 @@ function getExpenseAutomationMissingReceiptsView(state) {
153
176
  summary: currentBatchDetails.summary,
154
177
  }
155
178
  : undefined;
156
- const manualSearchResults = bulkUpload.manualSearch.results.map((r) => {
157
- const t = (0, transactionSelector_1.getSupportedTransactionById)(transactionState, r.transactionId);
179
+ const manualSearchResults = bulkUpload.manualSearch.results.map((result) => {
180
+ const transaction = (0, transactionSelector_1.getSupportedTransactionById)(transactionState, result.transactionId);
158
181
  return {
159
- ...r,
160
- vendorLogo: r.vendorLogo ?? t?.logo?.href,
182
+ ...result,
183
+ vendorLogo: result.vendorLogo ?? transaction?.logo?.href,
161
184
  };
162
185
  });
163
186
  return {
@@ -207,7 +230,7 @@ function getExpenseAutomationMissingReceiptsView(state) {
207
230
  };
208
231
  }
209
232
  function batchDetailsHasUnmatchedWork(details) {
210
- return details.files.some((f) => (0, missingReceiptsViewState_1.isUnmatchedTabFileStatus)(f.status));
233
+ return details.files.some((file) => (0, missingReceiptsViewState_1.isUnmatchedTabFileStatus)(file.status));
211
234
  }
212
235
  /** List row summary before batch details load — aligns with unmatched / possible-match work. */
213
236
  function batchListItemHasUnmatchedWork(batch) {
@@ -224,17 +247,17 @@ function batchListItemHasUnmatchedWork(batch) {
224
247
  */
225
248
  function getPrimaryBatchIdFromBatchListOrder(batchListInPlatformOrder, batchDetailsById, failedBatchDetailIds) {
226
249
  const failedIds = new Set(failedBatchDetailIds);
227
- const anyCompletedBatchHasUnmatchedWork = batchListInPlatformOrder.some((b) => {
228
- if (failedIds.has(b.batchId)) {
250
+ const anyCompletedBatchHasUnmatchedWork = batchListInPlatformOrder.some((batch) => {
251
+ if (failedIds.has(batch.batchId)) {
229
252
  return false;
230
253
  }
231
- const d = batchDetailsById[b.batchId];
232
- if (d != null &&
233
- d.status === 'completed' &&
234
- batchDetailsHasUnmatchedWork(d)) {
254
+ const details = batchDetailsById[batch.batchId];
255
+ if (details != null &&
256
+ details.status === 'completed' &&
257
+ batchDetailsHasUnmatchedWork(details)) {
235
258
  return true;
236
259
  }
237
- return d == null && batchListItemHasUnmatchedWork(b);
260
+ return details == null && batchListItemHasUnmatchedWork(batch);
238
261
  });
239
262
  for (const batch of batchListInPlatformOrder) {
240
263
  if (failedIds.has(batch.batchId)) {
@@ -271,7 +294,7 @@ function resolveBatchFile(file, batchId, transactionState) {
271
294
  ? { transaction, matchScore: ref.matchScore }
272
295
  : undefined;
273
296
  })
274
- .filter((c) => c != null);
297
+ .filter((candidate) => candidate != null);
275
298
  return {
276
299
  attachmentId: file.attachmentId,
277
300
  batchId,
@@ -3,7 +3,6 @@ import { SortOrder } from '../../../commonStateTypes/selectorTypes/sortOrderType
3
3
  import { MonthYearPeriodId } from '../../../commonStateTypes/timePeriod';
4
4
  export declare const toMissingReceiptsSortKey: (v: string) => "date" | "amount" | "vendor" | "category" | "class";
5
5
  export type MissingReceiptsSortKey = ReturnType<typeof toMissingReceiptsSortKey>;
6
- export type BulkUploadSortKey = 'amount' | 'category' | 'class' | 'date' | 'vendor';
7
6
  export interface MissingReceiptsViewUIState {
8
7
  scrollPosition: {
9
8
  scrollTop: number;
@@ -18,15 +17,26 @@ export interface MissingReceiptsViewUIState {
18
17
  * Kept in sync with `ManualSearchInput` in web-components (fires search only when length ≥ this).
19
18
  */
20
19
  export declare const MIN_MANUAL_TRANSACTION_SEARCH_LENGTH = 2;
21
- export type BatchStatusValue = 'pending' | 'processing' | 'completed';
22
- export type BatchFileStatus = 'exact_match' | 'possible_matches' | 'no_match' | 'failed';
20
+ export declare const toBatchStatusValue: (v: string) => "pending" | "processing" | "completed";
21
+ export type BatchStatusValue = ReturnType<typeof toBatchStatusValue>;
22
+ /** Canonical batch file statuses (API ingress may use aliases; see `parseBatchFileStatus`). */
23
+ export declare const BATCH_FILE_STATUSES: readonly ["exact_match", "possible_matches", "no_match", "failed"];
24
+ export declare const toBatchFileStatus: (v: string) => "failed" | "exact_match" | "possible_matches" | "no_match";
25
+ export type BatchFileStatus = ReturnType<typeof toBatchFileStatus>;
23
26
  /** True for files that belong in the Unmatched tab (possible matches or no match). */
24
27
  export declare function isUnmatchedTabFileStatus(status: BatchFileStatus): boolean;
25
- export type BulkUploadPhase = 'idle' | 'uploading' | 'matching' | 'completed';
26
- export type BulkUploadResultsTab = 'completed' | 'unmatched';
27
- export type MissingReceiptsTab = 'missing' | BulkUploadResultsTab;
28
- export type CompletedSubTab = 'all' | 'ai_accountant' | 'manual';
29
- export type MatchSource = 'ai' | 'manual';
28
+ export declare const toBulkUploadPhase: (v: string) => "completed" | "idle" | "uploading" | "matching";
29
+ export type BulkUploadPhase = ReturnType<typeof toBulkUploadPhase>;
30
+ export declare const toBulkUploadResultsTab: (v: string) => "completed" | "unmatched";
31
+ export type BulkUploadResultsTab = ReturnType<typeof toBulkUploadResultsTab>;
32
+ export declare const toMissingReceiptsTab: (v: string) => "completed" | "unmatched" | "missing";
33
+ export type MissingReceiptsTab = ReturnType<typeof toMissingReceiptsTab>;
34
+ export declare const toCompletedSubTab: (v: string) => "all" | "manual" | "ai_accountant";
35
+ export type CompletedSubTab = ReturnType<typeof toCompletedSubTab>;
36
+ export declare const toMatchSource: (v: string) => "manual" | "ai";
37
+ export type MatchSource = ReturnType<typeof toMatchSource>;
38
+ export declare const toBulkUploadSortKey: (v: string) => "date" | "amount" | "vendor" | "category" | "class";
39
+ export type BulkUploadSortKey = ReturnType<typeof toBulkUploadSortKey>;
30
40
  export interface CandidateRef {
31
41
  matchScore: number;
32
42
  transactionId: ID;
@@ -106,7 +116,8 @@ export interface ManualSearchState {
106
116
  searchQuery: string;
107
117
  totalCount: number;
108
118
  }
109
- export type CompletedTransactionsMatchType = 'all' | 'ai_accountant' | 'manual';
119
+ /** Same union as {@link CompletedSubTab} — used for completed-transactions API `match_type`. */
120
+ export type CompletedTransactionsMatchType = CompletedSubTab;
110
121
  export interface CompletedTransactionsState {
111
122
  fetchState: FetchStateAndError;
112
123
  nextPageToken: string | null;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.MIN_MANUAL_TRANSACTION_SEARCH_LENGTH = exports.toMissingReceiptsSortKey = void 0;
3
+ exports.toBulkUploadSortKey = exports.toMatchSource = exports.toCompletedSubTab = exports.toMissingReceiptsTab = exports.toBulkUploadResultsTab = exports.toBulkUploadPhase = exports.toBatchFileStatus = exports.BATCH_FILE_STATUSES = exports.toBatchStatusValue = exports.MIN_MANUAL_TRANSACTION_SEARCH_LENGTH = exports.toMissingReceiptsSortKey = void 0;
4
4
  exports.isUnmatchedTabFileStatus = isUnmatchedTabFileStatus;
5
5
  const stringToUnion_1 = require("../../../commonStateTypes/stringToUnion");
6
6
  const MISSING_RECEIPTS_SORT_KEYS = [
@@ -18,7 +18,44 @@ exports.toMissingReceiptsSortKey = toMissingReceiptsSortKey;
18
18
  * Kept in sync with `ManualSearchInput` in web-components (fires search only when length ≥ this).
19
19
  */
20
20
  exports.MIN_MANUAL_TRANSACTION_SEARCH_LENGTH = 2;
21
+ const BATCH_STATUS_VALUES = ['pending', 'processing', 'completed'];
22
+ const toBatchStatusValue = (v) => (0, stringToUnion_1.stringToUnion)(v.trim().toLowerCase(), BATCH_STATUS_VALUES);
23
+ exports.toBatchStatusValue = toBatchStatusValue;
24
+ /** Canonical batch file statuses (API ingress may use aliases; see `parseBatchFileStatus`). */
25
+ exports.BATCH_FILE_STATUSES = [
26
+ 'exact_match',
27
+ 'possible_matches',
28
+ 'no_match',
29
+ 'failed',
30
+ ];
31
+ const toBatchFileStatus = (v) => (0, stringToUnion_1.stringToUnion)(v.trim().toLowerCase().replace(/-/g, '_'), exports.BATCH_FILE_STATUSES);
32
+ exports.toBatchFileStatus = toBatchFileStatus;
33
+ const UNMATCHED_TAB_FILE_STATUSES = ['possible_matches', 'no_match'];
21
34
  /** True for files that belong in the Unmatched tab (possible matches or no match). */
22
35
  function isUnmatchedTabFileStatus(status) {
23
- return status === 'possible_matches' || status === 'no_match';
36
+ return UNMATCHED_TAB_FILE_STATUSES.includes(status);
24
37
  }
38
+ const BULK_UPLOAD_PHASES = ['idle', 'uploading', 'matching', 'completed'];
39
+ const toBulkUploadPhase = (v) => (0, stringToUnion_1.stringToUnion)(v.trim().toLowerCase(), BULK_UPLOAD_PHASES);
40
+ exports.toBulkUploadPhase = toBulkUploadPhase;
41
+ const BULK_UPLOAD_RESULTS_TABS = ['completed', 'unmatched'];
42
+ const toBulkUploadResultsTab = (v) => (0, stringToUnion_1.stringToUnion)(v.trim().toLowerCase(), BULK_UPLOAD_RESULTS_TABS);
43
+ exports.toBulkUploadResultsTab = toBulkUploadResultsTab;
44
+ const MISSING_RECEIPTS_TABS = ['missing', 'completed', 'unmatched'];
45
+ const toMissingReceiptsTab = (v) => (0, stringToUnion_1.stringToUnion)(v.trim().toLowerCase(), MISSING_RECEIPTS_TABS);
46
+ exports.toMissingReceiptsTab = toMissingReceiptsTab;
47
+ const COMPLETED_SUB_TABS = ['all', 'ai_accountant', 'manual'];
48
+ const toCompletedSubTab = (v) => (0, stringToUnion_1.stringToUnion)(v.trim().toLowerCase(), COMPLETED_SUB_TABS);
49
+ exports.toCompletedSubTab = toCompletedSubTab;
50
+ const MATCH_SOURCES = ['ai', 'manual'];
51
+ const toMatchSource = (v) => (0, stringToUnion_1.stringToUnion)(v.trim().toLowerCase(), MATCH_SOURCES);
52
+ exports.toMatchSource = toMatchSource;
53
+ const BULK_UPLOAD_SORT_KEYS = [
54
+ 'amount',
55
+ 'category',
56
+ 'class',
57
+ 'date',
58
+ 'vendor',
59
+ ];
60
+ const toBulkUploadSortKey = (v) => (0, stringToUnion_1.stringToUnion)(v.trim().toLowerCase(), BULK_UPLOAD_SORT_KEYS);
61
+ exports.toBulkUploadSortKey = toBulkUploadSortKey;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zeniai/client-epic-state",
3
- "version": "4.19.84-betaVR10",
3
+ "version": "4.19.84-betaVR12",
4
4
  "description": "Shared module between Web & Mobile containing required abstractions for state management, async network communication. ",
5
5
  "main": "lib/index.js",
6
6
  "module": "lib/esm/index.js",