@zeniai/client-epic-state 4.19.37-betaVR17 → 4.19.37-betaVR19

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.
@@ -1,5 +1,6 @@
1
+ import orderBy from 'lodash/orderBy';
1
2
  import { concat, of } from 'rxjs';
2
- import { catchError, filter, mergeMap } from 'rxjs/operators';
3
+ import { catchError, exhaustMap, filter } from 'rxjs/operators';
3
4
  import { toMonthYearPeriodId } from '../../../../commonStateTypes/timePeriod';
4
5
  import { getCurrentTenant } from '../../../../entity/tenant/tenantSelector';
5
6
  import { createZeniAPIStatus } from '../../../../responsePayload';
@@ -7,7 +8,9 @@ import { isBatchListStatusCompleted } from '../../payload/missingReceiptsPayload
7
8
  import { fetchMoreBatchDetails, fetchMoreBatchDetailsComplete, fetchMoreBatchDetailsFailure, } from '../../reducers/missingReceiptsViewReducer';
8
9
  import { fetchBatchDetailsByIds } from './fetchMultipleBatchDetailsEpic';
9
10
  const MORE_BATCH_PAGE_SIZE = 4;
10
- export const fetchMoreBatchDetailsEpic = (actions$, state$, zeniAPI) => actions$.pipe(filter(fetchMoreBatchDetails.match), mergeMap(() => {
11
+ export const fetchMoreBatchDetailsEpic = (actions$, state$, zeniAPI) => actions$.pipe(filter(fetchMoreBatchDetails.match),
12
+ /** One page at a time — avoids duplicate loads if IO + scroll fallback both fire. */
13
+ exhaustMap(() => {
11
14
  const state = state$.value;
12
15
  const { expenseAutomationViewState: { selectedPeriodByTenantId }, expenseAutomationMissingReceiptsViewState: { bulkUpload }, } = state;
13
16
  const currentTenant = getCurrentTenant(state);
@@ -18,11 +21,10 @@ export const fetchMoreBatchDetailsEpic = (actions$, state$, zeniAPI) => actions$
18
21
  const periodId = toMonthYearPeriodId(selectedPeriod);
19
22
  const batchList = bulkUpload.batchListByPeriod[periodId] ?? [];
20
23
  const failedIds = new Set(bulkUpload.failedBatchDetailIds);
21
- const unfetchedBatchIds = batchList
22
- .filter((batch) => isBatchListStatusCompleted(batch.status) &&
24
+ const unfetchedBatches = batchList.filter((batch) => isBatchListStatusCompleted(batch.status) &&
23
25
  bulkUpload.batchDetailsById[batch.batchId] == null &&
24
- !failedIds.has(batch.batchId))
25
- .map((batch) => batch.batchId);
26
+ !failedIds.has(batch.batchId));
27
+ const unfetchedBatchIds = orderBy(unfetchedBatches, (b) => new Date(b.createdAt).valueOf(), 'asc').map((batch) => batch.batchId);
26
28
  if (unfetchedBatchIds.length === 0) {
27
29
  return of(fetchMoreBatchDetailsComplete());
28
30
  }
@@ -1,3 +1,4 @@
1
+ import orderBy from 'lodash/orderBy';
1
2
  import { EMPTY, concat, from, of } from 'rxjs';
2
3
  import { catchError, filter, mergeMap } from 'rxjs/operators';
3
4
  import { updateTransactions } from '../../../../entity/transaction/transactionReducer';
@@ -9,7 +10,6 @@ export function fetchBatchDetailsByIds(batchIds, zeniAPI) {
9
10
  if (batchIds.length === 0) {
10
11
  return EMPTY;
11
12
  }
12
- console.log('fetchBatchDetailsByIds', batchIds);
13
13
  return from(batchIds).pipe(mergeMap((batchId) => zeniAPI
14
14
  .getJSON(`${zeniAPI.apiEndPoints.communicationAgentMicroServiceBaseUrl}/1.0/batches/${batchId}`)
15
15
  .pipe(mergeMap((response) => {
@@ -32,10 +32,10 @@ export function fetchBatchDetailsByIds(batchIds, zeniAPI) {
32
32
  export const fetchMultipleBatchDetailsEpic = (actions$, state$, zeniAPI) => actions$.pipe(filter(fetchBulkUploadBatchesSuccess.match), mergeMap((action) => {
33
33
  const batchList = action.payload.batchList;
34
34
  const { batchDetailsById } = state$.value.expenseAutomationMissingReceiptsViewState.bulkUpload;
35
- const completedBatchIds = batchList
36
- .filter((batch) => isBatchListStatusCompleted(batch.status) &&
37
- batchDetailsById[batch.batchId] == null)
38
- .map((batch) => batch.batchId);
35
+ /** Oldest first — matches primary-batch selection in missingReceiptsSelector (chronological). */
36
+ const completedBatchesMissingDetails = batchList.filter((batch) => isBatchListStatusCompleted(batch.status) &&
37
+ batchDetailsById[batch.batchId] == null);
38
+ const completedBatchIds = orderBy(completedBatchesMissingDetails, (b) => new Date(b.createdAt).valueOf(), 'asc').map((batch) => batch.batchId);
39
39
  const batchIdsToFetch = completedBatchIds.slice(0, INITIAL_BATCH_PAGE_SIZE);
40
40
  if (batchIdsToFetch.length === 0) {
41
41
  return EMPTY;
@@ -205,12 +205,25 @@ const expenseAutomationMissingReceiptsView = createSlice({
205
205
  storeBatchDetails(draft, action) {
206
206
  const details = action.payload;
207
207
  draft.bulkUpload.batchDetailsById[details.batchId] = details;
208
+ /**
209
+ * Multi-batch fetch paths use `storeBatchDetails` (not `fetchBulkUploadBatchDetailsSuccess`).
210
+ * Without this, `phase` stays `matching` after upload forever and the Unmatched tab keeps
211
+ * showing the skeleton (`bulkUploadPhase === 'matching'` in web-components).
212
+ */
213
+ if (draft.bulkUpload.phase === 'matching' &&
214
+ draft.bulkUpload.currentBatchId === details.batchId) {
215
+ draft.bulkUpload.phase = 'completed';
216
+ }
208
217
  },
209
218
  batchDetailFetchFailed(draft, action) {
210
219
  const { batchId } = action.payload;
211
220
  if (!draft.bulkUpload.failedBatchDetailIds.includes(batchId)) {
212
221
  draft.bulkUpload.failedBatchDetailIds.push(batchId);
213
222
  }
223
+ if (draft.bulkUpload.phase === 'matching' &&
224
+ draft.bulkUpload.currentBatchId === batchId) {
225
+ draft.bulkUpload.phase = 'completed';
226
+ }
214
227
  },
215
228
  setInitialBatchDetailsLoading(draft) {
216
229
  draft.bulkUpload.batchDetailsPaginationState = {
@@ -229,6 +242,15 @@ const expenseAutomationMissingReceiptsView = createSlice({
229
242
  fetchState: 'Completed',
230
243
  error: undefined,
231
244
  };
245
+ const currentId = draft.bulkUpload.currentBatchId;
246
+ const currentDetails = currentId != null
247
+ ? draft.bulkUpload.batchDetailsById[currentId]
248
+ : undefined;
249
+ if (draft.bulkUpload.phase === 'matching' &&
250
+ currentId != null &&
251
+ currentDetails?.status === 'completed') {
252
+ draft.bulkUpload.phase = 'completed';
253
+ }
232
254
  },
233
255
  fetchMoreBatchDetailsFailure(draft, action) {
234
256
  draft.bulkUpload.batchDetailsPaginationState = {
@@ -60,9 +60,9 @@ export function getExpenseAutomationMissingReceiptsView(state) {
60
60
  const batchListChronological = orderBy(batchList, (b) => new Date(b.createdAt).valueOf(), 'asc');
61
61
  /**
62
62
  * Primary "Unmatched" batch = first completed batch in chronological order, preferring the
63
- * first batch that still has un_matched/no_match work when any completed batch has such work
64
- * (so a newer fully-matched batch does not hide older unmatched receipts). If an earlier batch
65
- * in that order has no details yet (still loading), we return undefined until it resolves.
63
+ * first batch that still has un_matched/no_match work when any completed batch has such work.
64
+ * Batches without details yet: wait if the list row still reports unmatched work; otherwise skip
65
+ * so we do not block the whole tab while older rows are not fetched yet.
66
66
  */
67
67
  const primaryBatchIdFromDetailsOrder = getPrimaryBatchIdFromBatchListOrder(batchListChronological, bulkUpload.batchDetailsById, bulkUpload.failedBatchDetailIds);
68
68
  /** During upload/matching, the in-flight batch may not appear in batchList yet — prefer currentBatchId. */
@@ -115,9 +115,13 @@ export function getExpenseAutomationMissingReceiptsView(state) {
115
115
  }
116
116
  : { total: 0, processed: 0, percentage: 0 };
117
117
  const batchListFetchState = bulkUpload.batchListFetchState;
118
+ /**
119
+ * When primary batch is not resolved yet, still aggregate unmatched files from every batch
120
+ * that has details loaded (otherwise past is empty and receipts vanish from the UI).
121
+ */
118
122
  const pastBatches = unmatchedSectionBatchId != null
119
123
  ? batchList.filter((b) => b.batchId !== unmatchedSectionBatchId)
120
- : [];
124
+ : batchList;
121
125
  const pastUnmatchedFiles = pastBatches.flatMap((b) => {
122
126
  const details = bulkUpload.batchDetailsById[b.batchId];
123
127
  if (details == null) {
@@ -189,10 +193,18 @@ export function getExpenseAutomationMissingReceiptsView(state) {
189
193
  function batchDetailsHasUnmatchedWork(details) {
190
194
  return details.files.some((f) => f.status === 'un_matched' || f.status === 'no_match');
191
195
  }
196
+ /** List row summary before batch details load — aligns with unmatched / possible-match work. */
197
+ function batchListItemHasUnmatchedWork(batch) {
198
+ return batch.noMatchCount > 0 || batch.possibleMatchesCount > 0;
199
+ }
192
200
  /**
193
201
  * `batchList` must be in chronological order (oldest first). Picks the primary batch for the
194
- * top "Unmatched" section. Skips failed detail fetches. Stops at the first batch with no details
195
- * yet (still loading) so we do not choose a later batch until earlier chronological rows resolve.
202
+ * top "Unmatched" section. Skips failed detail fetches.
203
+ *
204
+ * If details are not loaded for an older batch but the list row reports no unmatched work, we
205
+ * skip that batch so newer batches with loaded details can be primary (avoids an empty tab when
206
+ * the first fetch page only loaded newer batches). If the list reports unmatched work but details
207
+ * are still loading, we wait (undefined) so primary order stays correct once details arrive.
196
208
  */
197
209
  function getPrimaryBatchIdFromBatchListOrder(batchListChronological, batchDetailsById, failedBatchDetailIds) {
198
210
  const failedIds = new Set(failedBatchDetailIds);
@@ -201,9 +213,12 @@ function getPrimaryBatchIdFromBatchListOrder(batchListChronological, batchDetail
201
213
  return false;
202
214
  }
203
215
  const d = batchDetailsById[b.batchId];
204
- return (d != null &&
216
+ if (d != null &&
205
217
  d.status === 'completed' &&
206
- batchDetailsHasUnmatchedWork(d));
218
+ batchDetailsHasUnmatchedWork(d)) {
219
+ return true;
220
+ }
221
+ return d == null && batchListItemHasUnmatchedWork(b);
207
222
  });
208
223
  for (const batch of batchListChronological) {
209
224
  if (failedIds.has(batch.batchId)) {
@@ -211,7 +226,10 @@ function getPrimaryBatchIdFromBatchListOrder(batchListChronological, batchDetail
211
226
  }
212
227
  const details = batchDetailsById[batch.batchId];
213
228
  if (details == null) {
214
- return undefined;
229
+ if (batchListItemHasUnmatchedWork(batch)) {
230
+ return undefined;
231
+ }
232
+ continue;
215
233
  }
216
234
  if (details.status !== 'completed') {
217
235
  continue;
@@ -1,6 +1,10 @@
1
1
  "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
2
5
  Object.defineProperty(exports, "__esModule", { value: true });
3
6
  exports.fetchMoreBatchDetailsEpic = void 0;
7
+ const orderBy_1 = __importDefault(require("lodash/orderBy"));
4
8
  const rxjs_1 = require("rxjs");
5
9
  const operators_1 = require("rxjs/operators");
6
10
  const timePeriod_1 = require("../../../../commonStateTypes/timePeriod");
@@ -10,7 +14,9 @@ const missingReceiptsPayload_1 = require("../../payload/missingReceiptsPayload")
10
14
  const missingReceiptsViewReducer_1 = require("../../reducers/missingReceiptsViewReducer");
11
15
  const fetchMultipleBatchDetailsEpic_1 = require("./fetchMultipleBatchDetailsEpic");
12
16
  const MORE_BATCH_PAGE_SIZE = 4;
13
- const fetchMoreBatchDetailsEpic = (actions$, state$, zeniAPI) => actions$.pipe((0, operators_1.filter)(missingReceiptsViewReducer_1.fetchMoreBatchDetails.match), (0, operators_1.mergeMap)(() => {
17
+ const fetchMoreBatchDetailsEpic = (actions$, state$, zeniAPI) => actions$.pipe((0, operators_1.filter)(missingReceiptsViewReducer_1.fetchMoreBatchDetails.match),
18
+ /** One page at a time — avoids duplicate loads if IO + scroll fallback both fire. */
19
+ (0, operators_1.exhaustMap)(() => {
14
20
  const state = state$.value;
15
21
  const { expenseAutomationViewState: { selectedPeriodByTenantId }, expenseAutomationMissingReceiptsViewState: { bulkUpload }, } = state;
16
22
  const currentTenant = (0, tenantSelector_1.getCurrentTenant)(state);
@@ -21,11 +27,10 @@ const fetchMoreBatchDetailsEpic = (actions$, state$, zeniAPI) => actions$.pipe((
21
27
  const periodId = (0, timePeriod_1.toMonthYearPeriodId)(selectedPeriod);
22
28
  const batchList = bulkUpload.batchListByPeriod[periodId] ?? [];
23
29
  const failedIds = new Set(bulkUpload.failedBatchDetailIds);
24
- const unfetchedBatchIds = batchList
25
- .filter((batch) => (0, missingReceiptsPayload_1.isBatchListStatusCompleted)(batch.status) &&
30
+ const unfetchedBatches = batchList.filter((batch) => (0, missingReceiptsPayload_1.isBatchListStatusCompleted)(batch.status) &&
26
31
  bulkUpload.batchDetailsById[batch.batchId] == null &&
27
- !failedIds.has(batch.batchId))
28
- .map((batch) => batch.batchId);
32
+ !failedIds.has(batch.batchId));
33
+ const unfetchedBatchIds = (0, orderBy_1.default)(unfetchedBatches, (b) => new Date(b.createdAt).valueOf(), 'asc').map((batch) => batch.batchId);
29
34
  if (unfetchedBatchIds.length === 0) {
30
35
  return (0, rxjs_1.of)((0, missingReceiptsViewReducer_1.fetchMoreBatchDetailsComplete)());
31
36
  }
@@ -1,7 +1,11 @@
1
1
  "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
2
5
  Object.defineProperty(exports, "__esModule", { value: true });
3
6
  exports.fetchMultipleBatchDetailsEpic = void 0;
4
7
  exports.fetchBatchDetailsByIds = fetchBatchDetailsByIds;
8
+ const orderBy_1 = __importDefault(require("lodash/orderBy"));
5
9
  const rxjs_1 = require("rxjs");
6
10
  const operators_1 = require("rxjs/operators");
7
11
  const transactionReducer_1 = require("../../../../entity/transaction/transactionReducer");
@@ -13,7 +17,6 @@ function fetchBatchDetailsByIds(batchIds, zeniAPI) {
13
17
  if (batchIds.length === 0) {
14
18
  return rxjs_1.EMPTY;
15
19
  }
16
- console.log('fetchBatchDetailsByIds', batchIds);
17
20
  return (0, rxjs_1.from)(batchIds).pipe((0, operators_1.mergeMap)((batchId) => zeniAPI
18
21
  .getJSON(`${zeniAPI.apiEndPoints.communicationAgentMicroServiceBaseUrl}/1.0/batches/${batchId}`)
19
22
  .pipe((0, operators_1.mergeMap)((response) => {
@@ -36,10 +39,10 @@ function fetchBatchDetailsByIds(batchIds, zeniAPI) {
36
39
  const fetchMultipleBatchDetailsEpic = (actions$, state$, zeniAPI) => actions$.pipe((0, operators_1.filter)(missingReceiptsViewReducer_1.fetchBulkUploadBatchesSuccess.match), (0, operators_1.mergeMap)((action) => {
37
40
  const batchList = action.payload.batchList;
38
41
  const { batchDetailsById } = state$.value.expenseAutomationMissingReceiptsViewState.bulkUpload;
39
- const completedBatchIds = batchList
40
- .filter((batch) => (0, missingReceiptsPayload_1.isBatchListStatusCompleted)(batch.status) &&
41
- batchDetailsById[batch.batchId] == null)
42
- .map((batch) => batch.batchId);
42
+ /** Oldest first — matches primary-batch selection in missingReceiptsSelector (chronological). */
43
+ const completedBatchesMissingDetails = batchList.filter((batch) => (0, missingReceiptsPayload_1.isBatchListStatusCompleted)(batch.status) &&
44
+ batchDetailsById[batch.batchId] == null);
45
+ const completedBatchIds = (0, orderBy_1.default)(completedBatchesMissingDetails, (b) => new Date(b.createdAt).valueOf(), 'asc').map((batch) => batch.batchId);
43
46
  const batchIdsToFetch = completedBatchIds.slice(0, INITIAL_BATCH_PAGE_SIZE);
44
47
  if (batchIdsToFetch.length === 0) {
45
48
  return rxjs_1.EMPTY;
@@ -210,12 +210,25 @@ const expenseAutomationMissingReceiptsView = (0, toolkit_1.createSlice)({
210
210
  storeBatchDetails(draft, action) {
211
211
  const details = action.payload;
212
212
  draft.bulkUpload.batchDetailsById[details.batchId] = details;
213
+ /**
214
+ * Multi-batch fetch paths use `storeBatchDetails` (not `fetchBulkUploadBatchDetailsSuccess`).
215
+ * Without this, `phase` stays `matching` after upload forever and the Unmatched tab keeps
216
+ * showing the skeleton (`bulkUploadPhase === 'matching'` in web-components).
217
+ */
218
+ if (draft.bulkUpload.phase === 'matching' &&
219
+ draft.bulkUpload.currentBatchId === details.batchId) {
220
+ draft.bulkUpload.phase = 'completed';
221
+ }
213
222
  },
214
223
  batchDetailFetchFailed(draft, action) {
215
224
  const { batchId } = action.payload;
216
225
  if (!draft.bulkUpload.failedBatchDetailIds.includes(batchId)) {
217
226
  draft.bulkUpload.failedBatchDetailIds.push(batchId);
218
227
  }
228
+ if (draft.bulkUpload.phase === 'matching' &&
229
+ draft.bulkUpload.currentBatchId === batchId) {
230
+ draft.bulkUpload.phase = 'completed';
231
+ }
219
232
  },
220
233
  setInitialBatchDetailsLoading(draft) {
221
234
  draft.bulkUpload.batchDetailsPaginationState = {
@@ -234,6 +247,15 @@ const expenseAutomationMissingReceiptsView = (0, toolkit_1.createSlice)({
234
247
  fetchState: 'Completed',
235
248
  error: undefined,
236
249
  };
250
+ const currentId = draft.bulkUpload.currentBatchId;
251
+ const currentDetails = currentId != null
252
+ ? draft.bulkUpload.batchDetailsById[currentId]
253
+ : undefined;
254
+ if (draft.bulkUpload.phase === 'matching' &&
255
+ currentId != null &&
256
+ currentDetails?.status === 'completed') {
257
+ draft.bulkUpload.phase = 'completed';
258
+ }
237
259
  },
238
260
  fetchMoreBatchDetailsFailure(draft, action) {
239
261
  draft.bulkUpload.batchDetailsPaginationState = {
@@ -66,9 +66,9 @@ function getExpenseAutomationMissingReceiptsView(state) {
66
66
  const batchListChronological = (0, orderBy_1.default)(batchList, (b) => new Date(b.createdAt).valueOf(), 'asc');
67
67
  /**
68
68
  * Primary "Unmatched" batch = first completed batch in chronological order, preferring the
69
- * first batch that still has un_matched/no_match work when any completed batch has such work
70
- * (so a newer fully-matched batch does not hide older unmatched receipts). If an earlier batch
71
- * in that order has no details yet (still loading), we return undefined until it resolves.
69
+ * first batch that still has un_matched/no_match work when any completed batch has such work.
70
+ * Batches without details yet: wait if the list row still reports unmatched work; otherwise skip
71
+ * so we do not block the whole tab while older rows are not fetched yet.
72
72
  */
73
73
  const primaryBatchIdFromDetailsOrder = getPrimaryBatchIdFromBatchListOrder(batchListChronological, bulkUpload.batchDetailsById, bulkUpload.failedBatchDetailIds);
74
74
  /** During upload/matching, the in-flight batch may not appear in batchList yet — prefer currentBatchId. */
@@ -121,9 +121,13 @@ function getExpenseAutomationMissingReceiptsView(state) {
121
121
  }
122
122
  : { total: 0, processed: 0, percentage: 0 };
123
123
  const batchListFetchState = bulkUpload.batchListFetchState;
124
+ /**
125
+ * When primary batch is not resolved yet, still aggregate unmatched files from every batch
126
+ * that has details loaded (otherwise past is empty and receipts vanish from the UI).
127
+ */
124
128
  const pastBatches = unmatchedSectionBatchId != null
125
129
  ? batchList.filter((b) => b.batchId !== unmatchedSectionBatchId)
126
- : [];
130
+ : batchList;
127
131
  const pastUnmatchedFiles = pastBatches.flatMap((b) => {
128
132
  const details = bulkUpload.batchDetailsById[b.batchId];
129
133
  if (details == null) {
@@ -195,10 +199,18 @@ function getExpenseAutomationMissingReceiptsView(state) {
195
199
  function batchDetailsHasUnmatchedWork(details) {
196
200
  return details.files.some((f) => f.status === 'un_matched' || f.status === 'no_match');
197
201
  }
202
+ /** List row summary before batch details load — aligns with unmatched / possible-match work. */
203
+ function batchListItemHasUnmatchedWork(batch) {
204
+ return batch.noMatchCount > 0 || batch.possibleMatchesCount > 0;
205
+ }
198
206
  /**
199
207
  * `batchList` must be in chronological order (oldest first). Picks the primary batch for the
200
- * top "Unmatched" section. Skips failed detail fetches. Stops at the first batch with no details
201
- * yet (still loading) so we do not choose a later batch until earlier chronological rows resolve.
208
+ * top "Unmatched" section. Skips failed detail fetches.
209
+ *
210
+ * If details are not loaded for an older batch but the list row reports no unmatched work, we
211
+ * skip that batch so newer batches with loaded details can be primary (avoids an empty tab when
212
+ * the first fetch page only loaded newer batches). If the list reports unmatched work but details
213
+ * are still loading, we wait (undefined) so primary order stays correct once details arrive.
202
214
  */
203
215
  function getPrimaryBatchIdFromBatchListOrder(batchListChronological, batchDetailsById, failedBatchDetailIds) {
204
216
  const failedIds = new Set(failedBatchDetailIds);
@@ -207,9 +219,12 @@ function getPrimaryBatchIdFromBatchListOrder(batchListChronological, batchDetail
207
219
  return false;
208
220
  }
209
221
  const d = batchDetailsById[b.batchId];
210
- return (d != null &&
222
+ if (d != null &&
211
223
  d.status === 'completed' &&
212
- batchDetailsHasUnmatchedWork(d));
224
+ batchDetailsHasUnmatchedWork(d)) {
225
+ return true;
226
+ }
227
+ return d == null && batchListItemHasUnmatchedWork(b);
213
228
  });
214
229
  for (const batch of batchListChronological) {
215
230
  if (failedIds.has(batch.batchId)) {
@@ -217,7 +232,10 @@ function getPrimaryBatchIdFromBatchListOrder(batchListChronological, batchDetail
217
232
  }
218
233
  const details = batchDetailsById[batch.batchId];
219
234
  if (details == null) {
220
- return undefined;
235
+ if (batchListItemHasUnmatchedWork(batch)) {
236
+ return undefined;
237
+ }
238
+ continue;
221
239
  }
222
240
  if (details.status !== 'completed') {
223
241
  continue;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zeniai/client-epic-state",
3
- "version": "4.19.37-betaVR17",
3
+ "version": "4.19.37-betaVR19",
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",