@zeniai/client-epic-state 5.0.65 → 5.0.66-beta0ND

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 (42) hide show
  1. package/lib/commonStateTypes/cacheOverrideFetchReducer.d.ts +17 -0
  2. package/lib/commonStateTypes/cacheOverrideFetchReducer.js +20 -0
  3. package/lib/commonStateTypes/pusherActions.d.ts +11 -0
  4. package/lib/commonStateTypes/pusherActions.js +6 -0
  5. package/lib/entity/chargeCard/chargeCardReducer.d.ts +19 -2
  6. package/lib/entity/chargeCard/chargeCardReducer.js +35 -2
  7. package/lib/entity/chargeCardTransaction/chargeCardTransactionReducer.d.ts +14 -1
  8. package/lib/entity/chargeCardTransaction/chargeCardTransactionReducer.js +36 -2
  9. package/lib/esm/commonStateTypes/cacheOverrideFetchReducer.js +16 -0
  10. package/lib/esm/commonStateTypes/pusherActions.js +3 -0
  11. package/lib/esm/entity/chargeCard/chargeCardReducer.js +34 -1
  12. package/lib/esm/entity/chargeCardTransaction/chargeCardTransactionReducer.js +35 -1
  13. package/lib/esm/index.js +5 -2
  14. package/lib/esm/view/spendManagement/chargeCards/cashbackDetail/cashbackDetailReducer.js +3 -2
  15. package/lib/esm/view/spendManagement/chargeCards/chargeCardConfig/chargeCardConfigReducer.js +3 -2
  16. package/lib/esm/view/spendManagement/chargeCards/chargeCardDetail/chargeCardDetailReducer.js +55 -18
  17. package/lib/esm/view/spendManagement/chargeCards/chargeCardDetail/fetchChargeCardDetailEpic.js +16 -2
  18. package/lib/esm/view/spendManagement/chargeCards/chargeCardDetail/fetchChargeCardDetailPageEpic.js +5 -4
  19. package/lib/esm/view/spendManagement/chargeCards/chargeCardList/chargeCardListReducer.js +28 -9
  20. package/lib/esm/view/spendManagement/chargeCards/chargeCardList/fetchChargeCardListPageEpic.js +9 -6
  21. package/lib/esm/view/spendManagement/chargeCards/chargeCardPaymentHistory/chargeCardPaymentHistoryReducer.js +3 -2
  22. package/lib/esm/view/spendManagement/chargeCards/chargeCardPaymentHistory/fetchChargeCardPaymentPageEpic.js +1 -1
  23. package/lib/esm/view/spendManagement/chargeCards/chargeCardRepaymentDetail/chargeCardRepaymentDetailReducer.js +7 -3
  24. package/lib/index.d.ts +6 -3
  25. package/lib/index.js +22 -11
  26. package/lib/view/spendManagement/chargeCards/cashbackDetail/cashbackDetailReducer.d.ts +3 -1
  27. package/lib/view/spendManagement/chargeCards/cashbackDetail/cashbackDetailReducer.js +3 -2
  28. package/lib/view/spendManagement/chargeCards/chargeCardConfig/chargeCardConfigReducer.d.ts +3 -1
  29. package/lib/view/spendManagement/chargeCards/chargeCardConfig/chargeCardConfigReducer.js +3 -2
  30. package/lib/view/spendManagement/chargeCards/chargeCardDetail/chargeCardDetailReducer.js +55 -18
  31. package/lib/view/spendManagement/chargeCards/chargeCardDetail/fetchChargeCardDetailEpic.js +16 -2
  32. package/lib/view/spendManagement/chargeCards/chargeCardDetail/fetchChargeCardDetailPageEpic.js +5 -4
  33. package/lib/view/spendManagement/chargeCards/chargeCardList/chargeCardListReducer.d.ts +18 -3
  34. package/lib/view/spendManagement/chargeCards/chargeCardList/chargeCardListReducer.js +29 -10
  35. package/lib/view/spendManagement/chargeCards/chargeCardList/fetchChargeCardListPageEpic.js +9 -6
  36. package/lib/view/spendManagement/chargeCards/chargeCardPaymentHistory/chargeCardPaymentHistoryReducer.d.ts +3 -1
  37. package/lib/view/spendManagement/chargeCards/chargeCardPaymentHistory/chargeCardPaymentHistoryReducer.js +3 -2
  38. package/lib/view/spendManagement/chargeCards/chargeCardPaymentHistory/fetchChargeCardPaymentPageEpic.js +1 -1
  39. package/lib/view/spendManagement/chargeCards/chargeCardRepaymentDetail/chargeCardRepaymentDetailReducer.d.ts +3 -1
  40. package/lib/view/spendManagement/chargeCards/chargeCardRepaymentDetail/chargeCardRepaymentDetailReducer.js +7 -3
  41. package/package.json +8 -3
  42. package/lib/tsconfig.typecheck.tsbuildinfo +0 -1
@@ -0,0 +1,17 @@
1
+ import { PayloadAction, Draft } from '@reduxjs/toolkit';
2
+ /**
3
+ * Factory for `fetchXxx` reducers that support Pusher-driven silent refresh.
4
+ * When `cacheOverride=true`, fetchState and error are left untouched so the
5
+ * UI doesn't flash a skeleton. When `false`, `applyTo` runs the normal
6
+ * 'In-Progress' transition.
7
+ */
8
+ export declare const createCacheOverrideFetchReducer: <TState>(applyTo: (draft: Draft<TState>) => void) => {
9
+ prepare: (cacheOverride?: boolean) => {
10
+ payload: {
11
+ cacheOverride: boolean;
12
+ };
13
+ };
14
+ reducer: (draft: Draft<TState>, action: PayloadAction<{
15
+ cacheOverride: boolean;
16
+ }>) => void;
17
+ };
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createCacheOverrideFetchReducer = void 0;
4
+ /**
5
+ * Factory for `fetchXxx` reducers that support Pusher-driven silent refresh.
6
+ * When `cacheOverride=true`, fetchState and error are left untouched so the
7
+ * UI doesn't flash a skeleton. When `false`, `applyTo` runs the normal
8
+ * 'In-Progress' transition.
9
+ */
10
+ const createCacheOverrideFetchReducer = (applyTo) => ({
11
+ reducer(draft, action) {
12
+ if (action.payload.cacheOverride !== true) {
13
+ applyTo(draft);
14
+ }
15
+ },
16
+ prepare(cacheOverride = false) {
17
+ return { payload: { cacheOverride } };
18
+ },
19
+ });
20
+ exports.createCacheOverrideFetchReducer = createCacheOverrideFetchReducer;
@@ -0,0 +1,11 @@
1
+ import { ID } from './common';
2
+ import { ChargeCardTransactionPayload } from '../entity/chargeCardTransaction/chargeCardTransactionPayload';
3
+ export declare const addChargeCardTransactionFromPusher: import("@reduxjs/toolkit").ActionCreatorWithPayload<{
4
+ cardId: ID;
5
+ transaction: ChargeCardTransactionPayload;
6
+ }, string>;
7
+ export declare const addDeclinedChargeCardTransactionFromPusher: import("@reduxjs/toolkit").ActionCreatorWithPayload<{
8
+ cardId: ID;
9
+ transaction: ChargeCardTransactionPayload;
10
+ declineReason?: string;
11
+ }, string>;
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.addDeclinedChargeCardTransactionFromPusher = exports.addChargeCardTransactionFromPusher = void 0;
4
+ const toolkit_1 = require("@reduxjs/toolkit");
5
+ exports.addChargeCardTransactionFromPusher = (0, toolkit_1.createAction)('chargeCardDetail/addChargeCardTransactionFromPusher');
6
+ exports.addDeclinedChargeCardTransactionFromPusher = (0, toolkit_1.createAction)('chargeCardDetail/addDeclinedChargeCardTransactionFromPusher');
@@ -1,9 +1,26 @@
1
- import { UpdateType } from '../../commonStateTypes/common';
1
+ import { ID, UpdateType } from '../../commonStateTypes/common';
2
2
  import { ChargeCardState } from './chargeCard';
3
3
  import { ChargeCardPayload } from './chargeCardPayload';
4
4
  export declare const initialState: ChargeCardState;
5
5
  export declare const updateChargeCards: import("@reduxjs/toolkit").ActionCreatorWithPreparedPayload<[chargeCards: ChargeCardPayload[], updateType?: UpdateType | undefined], ChargeCardPayload[], "chargeCard/updateChargeCards", never, {
6
6
  updateType: UpdateType;
7
- }>, updateChargeCard: import("@reduxjs/toolkit").ActionCreatorWithPayload<ChargeCardPayload, "chargeCard/updateChargeCard">, removeChargeCard: import("@reduxjs/toolkit").ActionCreatorWithPayload<string, "chargeCard/removeChargeCard">, clearAllChargeCards: import("@reduxjs/toolkit").ActionCreatorWithoutPayload<"chargeCard/clearAllChargeCards">;
7
+ }>, updateChargeCard: import("@reduxjs/toolkit").ActionCreatorWithPayload<ChargeCardPayload, "chargeCard/updateChargeCard">, updateChargeCardStatusFromPusher: import("@reduxjs/toolkit").ActionCreatorWithPayload<{
8
+ cardId: ID;
9
+ cardStatus: {
10
+ code: string;
11
+ name: string;
12
+ };
13
+ isLockedByAdmin: boolean | undefined;
14
+ }, "chargeCard/updateChargeCardStatusFromPusher">, updateChargeCardSpendingFromPusher: import("@reduxjs/toolkit").ActionCreatorWithPayload<{
15
+ cardId: ID;
16
+ currencyCode: string;
17
+ currencySymbol: string;
18
+ balance?: number;
19
+ dailyPurchaseSpends?: number;
20
+ dailyWithdrawals?: number;
21
+ hold?: number;
22
+ monthlyPurchaseSpends?: number;
23
+ monthlyWithdrawals?: number;
24
+ }, "chargeCard/updateChargeCardSpendingFromPusher">, removeChargeCard: import("@reduxjs/toolkit").ActionCreatorWithPayload<string, "chargeCard/removeChargeCard">, clearAllChargeCards: import("@reduxjs/toolkit").ActionCreatorWithoutPayload<"chargeCard/clearAllChargeCards">;
8
25
  declare const _default: import("redux").Reducer<ChargeCardState>;
9
26
  export default _default;
@@ -4,9 +4,11 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  var _a;
6
6
  Object.defineProperty(exports, "__esModule", { value: true });
7
- exports.clearAllChargeCards = exports.removeChargeCard = exports.updateChargeCard = exports.updateChargeCards = exports.initialState = void 0;
7
+ exports.clearAllChargeCards = exports.removeChargeCard = exports.updateChargeCardSpendingFromPusher = exports.updateChargeCardStatusFromPusher = exports.updateChargeCard = exports.updateChargeCards = exports.initialState = void 0;
8
8
  const toolkit_1 = require("@reduxjs/toolkit");
9
9
  const assignWith_1 = __importDefault(require("lodash/assignWith"));
10
+ const amount_1 = require("../../commonStateTypes/amount");
11
+ const chargeCard_1 = require("./chargeCard");
10
12
  const chargeCardPayload_1 = require("./chargeCardPayload");
11
13
  exports.initialState = {
12
14
  chargeCardByID: {},
@@ -42,6 +44,37 @@ const chargeCard = (0, toolkit_1.createSlice)({
42
44
  const latestChargeCard = (0, chargeCardPayload_1.mapChargeCardPayloadToChargeCard)(action.payload);
43
45
  draft.chargeCardByID[latestChargeCard.id] = latestChargeCard;
44
46
  },
47
+ updateChargeCardStatusFromPusher(draft, action) {
48
+ const { cardId, cardStatus, isLockedByAdmin } = action.payload;
49
+ const card = draft.chargeCardByID[cardId];
50
+ if (card != null) {
51
+ card.status = {
52
+ code: (0, chargeCard_1.toCardStatusCodeType)(cardStatus.code),
53
+ name: cardStatus.name,
54
+ };
55
+ if (isLockedByAdmin !== undefined) {
56
+ card.isLockedByAdmin = isLockedByAdmin;
57
+ }
58
+ }
59
+ },
60
+ updateChargeCardSpendingFromPusher(draft, action) {
61
+ const { cardId, currencyCode, currencySymbol } = action.payload;
62
+ const card = draft.chargeCardByID[cardId];
63
+ if (card == null) {
64
+ return;
65
+ }
66
+ const amt = (v) => v !== undefined ? (0, amount_1.toAmount)(v, currencyCode, currencySymbol) : undefined;
67
+ card.balance = amt(action.payload.balance) ?? card.balance;
68
+ card.hold = amt(action.payload.hold) ?? card.hold;
69
+ card.dailyPurchaseSpends =
70
+ amt(action.payload.dailyPurchaseSpends) ?? card.dailyPurchaseSpends;
71
+ card.monthlyPurchaseSpends =
72
+ amt(action.payload.monthlyPurchaseSpends) ?? card.monthlyPurchaseSpends;
73
+ card.dailyWithdrawals =
74
+ amt(action.payload.dailyWithdrawals) ?? card.dailyWithdrawals;
75
+ card.monthlyWithdrawals =
76
+ amt(action.payload.monthlyWithdrawals) ?? card.monthlyWithdrawals;
77
+ },
45
78
  removeChargeCard(draft, action) {
46
79
  delete draft.chargeCardByID[action.payload];
47
80
  },
@@ -50,5 +83,5 @@ const chargeCard = (0, toolkit_1.createSlice)({
50
83
  },
51
84
  },
52
85
  });
53
- _a = chargeCard.actions, exports.updateChargeCards = _a.updateChargeCards, exports.updateChargeCard = _a.updateChargeCard, exports.removeChargeCard = _a.removeChargeCard, exports.clearAllChargeCards = _a.clearAllChargeCards;
86
+ _a = chargeCard.actions, exports.updateChargeCards = _a.updateChargeCards, exports.updateChargeCard = _a.updateChargeCard, exports.updateChargeCardStatusFromPusher = _a.updateChargeCardStatusFromPusher, exports.updateChargeCardSpendingFromPusher = _a.updateChargeCardSpendingFromPusher, exports.removeChargeCard = _a.removeChargeCard, exports.clearAllChargeCards = _a.clearAllChargeCards;
54
87
  exports.default = chargeCard.reducer;
@@ -5,7 +5,20 @@ export declare const initialState: ChargeCardTransactionState;
5
5
  export declare const updateChargeCardTransactions: import("@reduxjs/toolkit").ActionCreatorWithPayload<ChargeCardTransactionPayload[], "chargeCardTransaction/updateChargeCardTransactions">, updateChargeCardTransaction: import("@reduxjs/toolkit").ActionCreatorWithPayload<ChargeCardTransactionPayload, "chargeCardTransaction/updateChargeCardTransaction">, updateChargeCardTransactionAttachments: import("@reduxjs/toolkit").ActionCreatorWithPayload<{
6
6
  data: TransactionReceiptsPayload;
7
7
  transactionId: ID;
8
- }, "chargeCardTransaction/updateChargeCardTransactionAttachments">, removeChargeCardTransaction: import("@reduxjs/toolkit").ActionCreatorWithPayload<string, "chargeCardTransaction/removeChargeCardTransaction">, removeChargeCardTransactionAttachmentByThirdPartyTransactionId: import("@reduxjs/toolkit").ActionCreatorWithPayload<{
8
+ }, "chargeCardTransaction/updateChargeCardTransactionAttachments">, updateChargeCardTransactionStatusFromPusher: import("@reduxjs/toolkit").ActionCreatorWithPayload<{
9
+ transactionId: ID;
10
+ transactionStatus: {
11
+ code: string;
12
+ name: string;
13
+ };
14
+ }, "chargeCardTransaction/updateChargeCardTransactionStatusFromPusher">, updateChargeCardTransactionFromPusher: import("@reduxjs/toolkit").ActionCreatorWithPayload<{
15
+ cardId: ID;
16
+ transaction: ChargeCardTransactionPayload;
17
+ }, "chargeCardTransaction/updateChargeCardTransactionFromPusher">, updateChargeCardTransactionReceiptFromPusher: import("@reduxjs/toolkit").ActionCreatorWithPayload<{
18
+ attachmentFilePaths: string[];
19
+ cardId: ID;
20
+ transactionId: ID;
21
+ }, "chargeCardTransaction/updateChargeCardTransactionReceiptFromPusher">, removeChargeCardTransaction: import("@reduxjs/toolkit").ActionCreatorWithPayload<string, "chargeCardTransaction/removeChargeCardTransaction">, removeChargeCardTransactionAttachmentByThirdPartyTransactionId: import("@reduxjs/toolkit").ActionCreatorWithPayload<{
9
22
  attachmentFileName: string;
10
23
  thirdPartyTransactionId: ID;
11
24
  }, "chargeCardTransaction/removeChargeCardTransactionAttachmentByThirdPartyTransactionId">, clearAllChargeCardTransactions: import("@reduxjs/toolkit").ActionCreatorWithoutPayload<"chargeCardTransaction/clearAllChargeCardTransactions">;
@@ -1,9 +1,11 @@
1
1
  "use strict";
2
2
  var _a;
3
3
  Object.defineProperty(exports, "__esModule", { value: true });
4
- exports.clearAllChargeCardTransactions = exports.removeChargeCardTransactionAttachmentByThirdPartyTransactionId = exports.removeChargeCardTransaction = exports.updateChargeCardTransactionAttachments = exports.updateChargeCardTransaction = exports.updateChargeCardTransactions = exports.initialState = void 0;
4
+ exports.clearAllChargeCardTransactions = exports.removeChargeCardTransactionAttachmentByThirdPartyTransactionId = exports.removeChargeCardTransaction = exports.updateChargeCardTransactionReceiptFromPusher = exports.updateChargeCardTransactionFromPusher = exports.updateChargeCardTransactionStatusFromPusher = exports.updateChargeCardTransactionAttachments = exports.updateChargeCardTransaction = exports.updateChargeCardTransactions = exports.initialState = void 0;
5
5
  const toolkit_1 = require("@reduxjs/toolkit");
6
+ const chargeCardTransaction_1 = require("./chargeCardTransaction");
6
7
  const chargeCardTransactionPayload_1 = require("./chargeCardTransactionPayload");
8
+ const pusherActions_1 = require("../../commonStateTypes/pusherActions");
7
9
  exports.initialState = {
8
10
  chargeCardTransactionById: {},
9
11
  };
@@ -50,10 +52,42 @@ const chargeCardTransaction = (0, toolkit_1.createSlice)({
50
52
  }
51
53
  }
52
54
  },
55
+ updateChargeCardTransactionStatusFromPusher(draft, action) {
56
+ const { transactionId, transactionStatus } = action.payload;
57
+ const transaction = draft.chargeCardTransactionById[transactionId];
58
+ if (transaction != null) {
59
+ transaction.transactionStatus = {
60
+ code: (0, chargeCardTransaction_1.toCardTransactionStatusCode)(transactionStatus.code),
61
+ name: transactionStatus.name,
62
+ };
63
+ }
64
+ },
65
+ updateChargeCardTransactionFromPusher(draft, action) {
66
+ const entity = (0, chargeCardTransactionPayload_1.toChargeCardTransaction)(action.payload.transaction);
67
+ draft.chargeCardTransactionById[entity.id] = entity;
68
+ },
69
+ updateChargeCardTransactionReceiptFromPusher(draft, action) {
70
+ const { transactionId, attachmentFilePaths } = action.payload;
71
+ const transaction = draft.chargeCardTransactionById[transactionId];
72
+ if (transaction != null) {
73
+ transaction.attachmentFilePaths = attachmentFilePaths;
74
+ }
75
+ },
53
76
  clearAllChargeCardTransactions(draft) {
54
77
  draft.chargeCardTransactionById = {};
55
78
  },
56
79
  },
80
+ extraReducers: (builder) => {
81
+ builder
82
+ .addCase(pusherActions_1.addChargeCardTransactionFromPusher, (draft, action) => {
83
+ const entity = (0, chargeCardTransactionPayload_1.toChargeCardTransaction)(action.payload.transaction);
84
+ draft.chargeCardTransactionById[entity.id] = entity;
85
+ })
86
+ .addCase(pusherActions_1.addDeclinedChargeCardTransactionFromPusher, (draft, action) => {
87
+ const entity = (0, chargeCardTransactionPayload_1.toChargeCardTransaction)(action.payload.transaction);
88
+ draft.chargeCardTransactionById[entity.id] = entity;
89
+ });
90
+ },
57
91
  });
58
- _a = chargeCardTransaction.actions, exports.updateChargeCardTransactions = _a.updateChargeCardTransactions, exports.updateChargeCardTransaction = _a.updateChargeCardTransaction, exports.updateChargeCardTransactionAttachments = _a.updateChargeCardTransactionAttachments, exports.removeChargeCardTransaction = _a.removeChargeCardTransaction, exports.removeChargeCardTransactionAttachmentByThirdPartyTransactionId = _a.removeChargeCardTransactionAttachmentByThirdPartyTransactionId, exports.clearAllChargeCardTransactions = _a.clearAllChargeCardTransactions;
92
+ _a = chargeCardTransaction.actions, exports.updateChargeCardTransactions = _a.updateChargeCardTransactions, exports.updateChargeCardTransaction = _a.updateChargeCardTransaction, exports.updateChargeCardTransactionAttachments = _a.updateChargeCardTransactionAttachments, exports.updateChargeCardTransactionStatusFromPusher = _a.updateChargeCardTransactionStatusFromPusher, exports.updateChargeCardTransactionFromPusher = _a.updateChargeCardTransactionFromPusher, exports.updateChargeCardTransactionReceiptFromPusher = _a.updateChargeCardTransactionReceiptFromPusher, exports.removeChargeCardTransaction = _a.removeChargeCardTransaction, exports.removeChargeCardTransactionAttachmentByThirdPartyTransactionId = _a.removeChargeCardTransactionAttachmentByThirdPartyTransactionId, exports.clearAllChargeCardTransactions = _a.clearAllChargeCardTransactions;
59
93
  exports.default = chargeCardTransaction.reducer;
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Factory for `fetchXxx` reducers that support Pusher-driven silent refresh.
3
+ * When `cacheOverride=true`, fetchState and error are left untouched so the
4
+ * UI doesn't flash a skeleton. When `false`, `applyTo` runs the normal
5
+ * 'In-Progress' transition.
6
+ */
7
+ export const createCacheOverrideFetchReducer = (applyTo) => ({
8
+ reducer(draft, action) {
9
+ if (action.payload.cacheOverride !== true) {
10
+ applyTo(draft);
11
+ }
12
+ },
13
+ prepare(cacheOverride = false) {
14
+ return { payload: { cacheOverride } };
15
+ },
16
+ });
@@ -0,0 +1,3 @@
1
+ import { createAction } from '@reduxjs/toolkit';
2
+ export const addChargeCardTransactionFromPusher = createAction('chargeCardDetail/addChargeCardTransactionFromPusher');
3
+ export const addDeclinedChargeCardTransactionFromPusher = createAction('chargeCardDetail/addDeclinedChargeCardTransactionFromPusher');
@@ -1,5 +1,7 @@
1
1
  import { createSlice } from '@reduxjs/toolkit';
2
2
  import assignWith from 'lodash/assignWith';
3
+ import { toAmount } from '../../commonStateTypes/amount';
4
+ import { toCardStatusCodeType } from './chargeCard';
3
5
  import { mapChargeCardPayloadToChargeCard, } from './chargeCardPayload';
4
6
  export const initialState = {
5
7
  chargeCardByID: {},
@@ -35,6 +37,37 @@ const chargeCard = createSlice({
35
37
  const latestChargeCard = mapChargeCardPayloadToChargeCard(action.payload);
36
38
  draft.chargeCardByID[latestChargeCard.id] = latestChargeCard;
37
39
  },
40
+ updateChargeCardStatusFromPusher(draft, action) {
41
+ const { cardId, cardStatus, isLockedByAdmin } = action.payload;
42
+ const card = draft.chargeCardByID[cardId];
43
+ if (card != null) {
44
+ card.status = {
45
+ code: toCardStatusCodeType(cardStatus.code),
46
+ name: cardStatus.name,
47
+ };
48
+ if (isLockedByAdmin !== undefined) {
49
+ card.isLockedByAdmin = isLockedByAdmin;
50
+ }
51
+ }
52
+ },
53
+ updateChargeCardSpendingFromPusher(draft, action) {
54
+ const { cardId, currencyCode, currencySymbol } = action.payload;
55
+ const card = draft.chargeCardByID[cardId];
56
+ if (card == null) {
57
+ return;
58
+ }
59
+ const amt = (v) => v !== undefined ? toAmount(v, currencyCode, currencySymbol) : undefined;
60
+ card.balance = amt(action.payload.balance) ?? card.balance;
61
+ card.hold = amt(action.payload.hold) ?? card.hold;
62
+ card.dailyPurchaseSpends =
63
+ amt(action.payload.dailyPurchaseSpends) ?? card.dailyPurchaseSpends;
64
+ card.monthlyPurchaseSpends =
65
+ amt(action.payload.monthlyPurchaseSpends) ?? card.monthlyPurchaseSpends;
66
+ card.dailyWithdrawals =
67
+ amt(action.payload.dailyWithdrawals) ?? card.dailyWithdrawals;
68
+ card.monthlyWithdrawals =
69
+ amt(action.payload.monthlyWithdrawals) ?? card.monthlyWithdrawals;
70
+ },
38
71
  removeChargeCard(draft, action) {
39
72
  delete draft.chargeCardByID[action.payload];
40
73
  },
@@ -43,5 +76,5 @@ const chargeCard = createSlice({
43
76
  },
44
77
  },
45
78
  });
46
- export const { updateChargeCards, updateChargeCard, removeChargeCard, clearAllChargeCards, } = chargeCard.actions;
79
+ export const { updateChargeCards, updateChargeCard, updateChargeCardStatusFromPusher, updateChargeCardSpendingFromPusher, removeChargeCard, clearAllChargeCards, } = chargeCard.actions;
47
80
  export default chargeCard.reducer;
@@ -1,5 +1,7 @@
1
1
  import { createSlice } from '@reduxjs/toolkit';
2
+ import { toCardTransactionStatusCode, } from './chargeCardTransaction';
2
3
  import { toChargeCardTransaction, } from './chargeCardTransactionPayload';
4
+ import { addChargeCardTransactionFromPusher, addDeclinedChargeCardTransactionFromPusher } from '../../commonStateTypes/pusherActions';
3
5
  export const initialState = {
4
6
  chargeCardTransactionById: {},
5
7
  };
@@ -46,10 +48,42 @@ const chargeCardTransaction = createSlice({
46
48
  }
47
49
  }
48
50
  },
51
+ updateChargeCardTransactionStatusFromPusher(draft, action) {
52
+ const { transactionId, transactionStatus } = action.payload;
53
+ const transaction = draft.chargeCardTransactionById[transactionId];
54
+ if (transaction != null) {
55
+ transaction.transactionStatus = {
56
+ code: toCardTransactionStatusCode(transactionStatus.code),
57
+ name: transactionStatus.name,
58
+ };
59
+ }
60
+ },
61
+ updateChargeCardTransactionFromPusher(draft, action) {
62
+ const entity = toChargeCardTransaction(action.payload.transaction);
63
+ draft.chargeCardTransactionById[entity.id] = entity;
64
+ },
65
+ updateChargeCardTransactionReceiptFromPusher(draft, action) {
66
+ const { transactionId, attachmentFilePaths } = action.payload;
67
+ const transaction = draft.chargeCardTransactionById[transactionId];
68
+ if (transaction != null) {
69
+ transaction.attachmentFilePaths = attachmentFilePaths;
70
+ }
71
+ },
49
72
  clearAllChargeCardTransactions(draft) {
50
73
  draft.chargeCardTransactionById = {};
51
74
  },
52
75
  },
76
+ extraReducers: (builder) => {
77
+ builder
78
+ .addCase(addChargeCardTransactionFromPusher, (draft, action) => {
79
+ const entity = toChargeCardTransaction(action.payload.transaction);
80
+ draft.chargeCardTransactionById[entity.id] = entity;
81
+ })
82
+ .addCase(addDeclinedChargeCardTransactionFromPusher, (draft, action) => {
83
+ const entity = toChargeCardTransaction(action.payload.transaction);
84
+ draft.chargeCardTransactionById[entity.id] = entity;
85
+ });
86
+ },
53
87
  });
54
- export const { updateChargeCardTransactions, updateChargeCardTransaction, updateChargeCardTransactionAttachments, removeChargeCardTransaction, removeChargeCardTransactionAttachmentByThirdPartyTransactionId, clearAllChargeCardTransactions, } = chargeCardTransaction.actions;
88
+ export const { updateChargeCardTransactions, updateChargeCardTransaction, updateChargeCardTransactionAttachments, updateChargeCardTransactionStatusFromPusher, updateChargeCardTransactionFromPusher, updateChargeCardTransactionReceiptFromPusher, removeChargeCardTransaction, removeChargeCardTransactionAttachmentByThirdPartyTransactionId, clearAllChargeCardTransactions, } = chargeCardTransaction.actions;
55
89
  export default chargeCardTransaction.reducer;
package/lib/esm/index.js CHANGED
@@ -37,6 +37,9 @@ import { toCardAddressType, toCardType, toCreditLimitFrequencyCodeType, toShippi
37
37
  import { getChargeCardById } from './entity/chargeCard/chargeCardSelector';
38
38
  import { attachmentFilePathToAttachment, } from './entity/chargeCardTransaction/chargeCardTransactionPayload';
39
39
  import { updateChargeCardTransactionAttachments } from './entity/chargeCardTransaction/chargeCardTransactionReducer';
40
+ import { updateChargeCardStatusFromPusher, updateChargeCardSpendingFromPusher, } from './entity/chargeCard/chargeCardReducer';
41
+ import { updateChargeCardTransactionStatusFromPusher, updateChargeCardTransactionFromPusher, updateChargeCardTransactionReceiptFromPusher, } from './entity/chargeCardTransaction/chargeCardTransactionReducer';
42
+ import { addChargeCardTransactionFromPusher, addDeclinedChargeCardTransactionFromPusher, } from './commonStateTypes/pusherActions';
40
43
  import { getControllersName, getFirstControllerEmail, getFirstControllerId, } from './entity/company/companyHelper';
41
44
  import { getCompanyByCompanyId, getCompanyInfoForAllCockpitCompaniesInState, getControllersForCompany, } from './entity/company/companySelector';
42
45
  import { ALL_ACCOUNTING_CONNECTION_CREATION_MODES, isCompanyEligibleForTreasury, } from './entity/company/companyStateTypes';
@@ -296,7 +299,7 @@ import { fetchChargeCardConfig } from './view/spendManagement/chargeCards/charge
296
299
  import { closeChargeCard, completeCVVActivationWait, completeDebitCardSetPinWait, fetchChargeCardDetail, fetchChargeCardDetailPage, fetchChargeCardTransactionAttachments, fetchChargeCardTransactionList, fetchChargeCardTransactionStatistics, fetchChargeCardsRecurringExpenses, fetchDepositAccountLimit, lockChargeCard, startCVVActivationWait, startDebitCardSetPinWait, unlockChargeCard, updateChargeCardDetail, updateChargeCardName, updateChargeCardSpendLimit, updateChargeCardSpendLimitSuccessOrFailure, updateChargeCardTransactionIsViewReceiptClicked, updateChargeCardTransactionReceiptsShowTickFetchStatus, updateChargeCardTransactionUploadReceiptsFetchStatus, updateDebitCardPinAttempt, updatePhysicalChargeCardAttempt, } from './view/spendManagement/chargeCards/chargeCardDetail/chargeCardDetailReducer';
297
300
  import { getChargeCardCVVActivateView, getChargeCardControlDetailView, getChargeCardDetailView, getChargeCardRecurringExpensesView, getChargeCardTransactionAttachmentView, getDebitCardSetPinView, getDepositAccountLimitFetchStateByDepositAccountId, } from './view/spendManagement/chargeCards/chargeCardDetail/chargeCardDetailSelector';
298
301
  import { toChargeCardSortKeyType, } from './view/spendManagement/chargeCards/chargeCardList/chargeCardList';
299
- import { closeChargeCards, fetchChargeCardList, fetchChargeCardListPage, fetchCreditAccount, fetchCreditAccountRepayment, fetchDebitCardSummary, lockChargeCards, resendCardInvite, revokeCardInvite, revokeChargeCardsInvite, unlockChargeCards, updateBulkActionCardIds, updateSearchText as updateChargeCardListSearchText, updateChargeCardListUIState, updateChargeCardsSpendLimit, updateRowActionCardId, } from './view/spendManagement/chargeCards/chargeCardList/chargeCardListReducer';
302
+ import { closeChargeCards, fetchChargeCardList, fetchChargeCardListPage, fetchCreditAccount, fetchCreditAccountRepayment, fetchDebitCardSummary, lockChargeCards, resendCardInvite, revokeCardInvite, revokeChargeCardsInvite, unlockChargeCards, updateBulkActionCardIds, updateSearchText as updateChargeCardListSearchText, updateChargeCardListUIState, updateChargeCardsSpendLimit, updateCreditAccountBalanceFromPusher, updateRowActionCardId, } from './view/spendManagement/chargeCards/chargeCardList/chargeCardListReducer';
300
303
  import { anyCardOnHold, getChargeCardBulkActionView, getChargeCardListView, getChargeCardRecurringExpensesByCardIds, getChargeCardRowActionView, getCreditAccountDetails, getDebitCardList, getDebitCardSummary, getDepositAccountListWithDebitCardIssued, getMyPendingActivationChargeCardListView, getMyRequestOnHoldChargeCardListWithShippingAddress, } from './view/spendManagement/chargeCards/chargeCardList/chargeCardListSelector';
301
304
  import { PAYMENT_HISTORY_FILTER_CATEGORIES, } from './view/spendManagement/chargeCards/chargeCardPaymentHistory/chargeCardPaymentHistory';
302
305
  import { getChargeCardPaymentHistoryDownloadReport, } from './view/spendManagement/chargeCards/chargeCardPaymentHistory/chargeCardPaymentHistoryDownloadSelector';
@@ -597,7 +600,7 @@ export { fetchUserRoleConfig, getUserRoleConfig };
597
600
  export { getCompanyHealthMetricConfig, fetchCompanyHealthMetricConfig, };
598
601
  export { updateCompaniesHealth, updateCompanyHealth, };
599
602
  export { clearCompanyHealthMetricView, fetchCompanyHealthMetricView, initializeCompanyHealthMetricViewLocalData, removeSelectedCompanyId, saveCompanyHealthMetricById, updateCompanyHealthMetricLocalStore, updateCompanyHealthMetricViewErrorStatus, updateCompanyHealthMetricViewSuccessStatus, updateCompanyHealthViewUIState, };
600
- export { updateChargeCardTransactionAttachments, attachmentFilePathToAttachment, isCompanyRunwayInfinite, getCompanyHealthMetricView, hasCompanyHealthMetricFormFieldChanged, companyHealthMetricDropDownOptions, getChargeCardBusinessVerificationDetails, fetchDebitCardSummary, fetchChargeCardList, fetchChargeCardListPage, fetchChargeCardConfig, fetchCreditAccount, fetchCreditAccountRepayment, getChargeCardListView, getMyPendingActivationChargeCardListView, getMyRequestOnHoldChargeCardListWithShippingAddress, clearChargeCardRepaymentDetail, fetchChargeCardRepaymentDetail, initiateChargeCardRepayment, updateChargeCardRepaymentLocalStore, getChargeCardRepaymentDetail, fetchChargeCardPaymentPage, fetchChargeCardPaymentHistory, updatePaymentHistoryDownloadUIState, updatePaymentHistoryFilters, updatePaymentHistorySearchText, updatePaymentHistoryUIState, getChargeCardPaymentHistoryDownloadReport, getChargeCardPaymentHistoryView, getPaymentHistorySourceAccountName, getPaymentStatusDisplayText, PAYMENT_HISTORY_FILTER_CATEGORIES, getCreditAccountDetails, fetchChargeCardDetailPage, fetchChargeCardDetail, fetchChargeCardTransactionStatistics, fetchDepositAccountLimit, getChargeCardDetailView, getChargeCardControlDetailView, getDepositAccountLimitFetchStateByDepositAccountId, getChargeCardTransactionAttachmentView, getDebitCardSetPinView, getChargeCardRecurringExpensesByCardIds, getChargeCardRecurringExpensesView, getChargeCardRowActionView, getChargeCardBulkActionView, getChargeCardCVVActivateView, fetchChargeCardTransactionList, fetchCashbackDetail, toChargeCardSortKeyType, getCashbackDetail, getZeniDateFromPeriod, toCreditLimitFrequencyCodeType, getDepositAccountListWithDebitCardIssued, getIssueChargeCardView, getChargeCardSetupViewDetails, fetchChargeCardStatementList, getChargeCardStatements, fetchChargeCardSetupView, enableChargeCardAutoPay, acceptChargeCardTerms, expressInterestInChargeCard, getDepositAccountLimitForChargeCardByDepositAccountId, toCardAddressType, toShippingAddressType, toCardType, issueChargeCards, fetchIssueCardPage, fetchDepositAccountListForCards, getDebitCardList, getDebitCardSummary, updateCustomAddressId, updateChargeCardsLocalStore, resetIssueChargeCardForm, updateBulkActionCardIds, updateChargeCardListSearchText, updateChargeCardListUIState, updateCashbackDetailUIState, updateChargeCardDetail, updatePhysicalChargeCardAttempt, lockChargeCard, unlockChargeCard, closeChargeCard, updateChargeCardName, getCardUserOnboardingView, initializeCardUserOnboardingLocalData, updateCardUserOnboardingLocalData, saveCardOnboardingUserDetails, updateChargeCardTransactionUploadReceiptsFetchStatus, completeDebitCardSetPinWait, startDebitCardSetPinWait, updateDebitCardPinAttempt, updateChargeCardTransactionReceiptsShowTickFetchStatus, updateChargeCardTransactionIsViewReceiptClicked, fetchChargeCardTransactionAttachments, completeCVVActivationWait, startCVVActivationWait, updateChargeCardSpendLimit, updateChargeCardSpendLimitSuccessOrFailure, resendCardInvite, revokeCardInvite, updateRowActionCardId, revokeChargeCardsInvite, lockChargeCards, unlockChargeCards, closeChargeCards, updateChargeCardsSpendLimit, fetchChargeCardsRecurringExpenses, startCardUserOnboardingActivationWait, completeCardUserOnboardingActivationWait, setFirstViewAfterActivation, setFirstViewCompleteAfterActivation, setCurrentDisplayedCardId, getChargeCardById, anyCardOnHold, };
603
+ export { updateChargeCardTransactionAttachments, updateChargeCardStatusFromPusher, updateChargeCardSpendingFromPusher, updateChargeCardTransactionStatusFromPusher, updateChargeCardTransactionFromPusher, updateChargeCardTransactionReceiptFromPusher, updateCreditAccountBalanceFromPusher, addChargeCardTransactionFromPusher, addDeclinedChargeCardTransactionFromPusher, attachmentFilePathToAttachment, isCompanyRunwayInfinite, getCompanyHealthMetricView, hasCompanyHealthMetricFormFieldChanged, companyHealthMetricDropDownOptions, getChargeCardBusinessVerificationDetails, fetchDebitCardSummary, fetchChargeCardList, fetchChargeCardListPage, fetchChargeCardConfig, fetchCreditAccount, fetchCreditAccountRepayment, getChargeCardListView, getMyPendingActivationChargeCardListView, getMyRequestOnHoldChargeCardListWithShippingAddress, clearChargeCardRepaymentDetail, fetchChargeCardRepaymentDetail, initiateChargeCardRepayment, updateChargeCardRepaymentLocalStore, getChargeCardRepaymentDetail, fetchChargeCardPaymentPage, fetchChargeCardPaymentHistory, updatePaymentHistoryDownloadUIState, updatePaymentHistoryFilters, updatePaymentHistorySearchText, updatePaymentHistoryUIState, getChargeCardPaymentHistoryDownloadReport, getChargeCardPaymentHistoryView, getPaymentHistorySourceAccountName, getPaymentStatusDisplayText, PAYMENT_HISTORY_FILTER_CATEGORIES, getCreditAccountDetails, fetchChargeCardDetailPage, fetchChargeCardDetail, fetchChargeCardTransactionStatistics, fetchDepositAccountLimit, getChargeCardDetailView, getChargeCardControlDetailView, getDepositAccountLimitFetchStateByDepositAccountId, getChargeCardTransactionAttachmentView, getDebitCardSetPinView, getChargeCardRecurringExpensesByCardIds, getChargeCardRecurringExpensesView, getChargeCardRowActionView, getChargeCardBulkActionView, getChargeCardCVVActivateView, fetchChargeCardTransactionList, fetchCashbackDetail, toChargeCardSortKeyType, getCashbackDetail, getZeniDateFromPeriod, toCreditLimitFrequencyCodeType, getDepositAccountListWithDebitCardIssued, getIssueChargeCardView, getChargeCardSetupViewDetails, fetchChargeCardStatementList, getChargeCardStatements, fetchChargeCardSetupView, enableChargeCardAutoPay, acceptChargeCardTerms, expressInterestInChargeCard, getDepositAccountLimitForChargeCardByDepositAccountId, toCardAddressType, toShippingAddressType, toCardType, issueChargeCards, fetchIssueCardPage, fetchDepositAccountListForCards, getDebitCardList, getDebitCardSummary, updateCustomAddressId, updateChargeCardsLocalStore, resetIssueChargeCardForm, updateBulkActionCardIds, updateChargeCardListSearchText, updateChargeCardListUIState, updateCashbackDetailUIState, updateChargeCardDetail, updatePhysicalChargeCardAttempt, lockChargeCard, unlockChargeCard, closeChargeCard, updateChargeCardName, getCardUserOnboardingView, initializeCardUserOnboardingLocalData, updateCardUserOnboardingLocalData, saveCardOnboardingUserDetails, updateChargeCardTransactionUploadReceiptsFetchStatus, completeDebitCardSetPinWait, startDebitCardSetPinWait, updateDebitCardPinAttempt, updateChargeCardTransactionReceiptsShowTickFetchStatus, updateChargeCardTransactionIsViewReceiptClicked, fetchChargeCardTransactionAttachments, completeCVVActivationWait, startCVVActivationWait, updateChargeCardSpendLimit, updateChargeCardSpendLimitSuccessOrFailure, resendCardInvite, revokeCardInvite, updateRowActionCardId, revokeChargeCardsInvite, lockChargeCards, unlockChargeCards, closeChargeCards, updateChargeCardsSpendLimit, fetchChargeCardsRecurringExpenses, startCardUserOnboardingActivationWait, completeCardUserOnboardingActivationWait, setFirstViewAfterActivation, setFirstViewCompleteAfterActivation, setCurrentDisplayedCardId, getChargeCardById, anyCardOnHold, };
601
604
  export { TIME_SERIES_DURATIONS, convertToTimeSeriesSelectionRange, toTimeSeriesDuration, fetchAggregatedReport, aggregatedReportView, };
602
605
  export { fetchApAging, getApAgingReport, updateApAgingUIState, };
603
606
  export { fetchApAgingDetail, getApAgingDetailForVendor, updateApAgingDetailUIState, };
@@ -1,6 +1,7 @@
1
1
  import { createSlice } from '@reduxjs/toolkit';
2
2
  import { mapCurrencyPayloadToCurrency } from '../../../../commonPayloadTypes/v2/viewAndReportPayloadv2';
3
3
  import { toAmount } from '../../../../commonStateTypes/amount';
4
+ import { createCacheOverrideFetchReducer } from '../../../../commonStateTypes/cacheOverrideFetchReducer';
4
5
  import { initialCashbackAnalytics, } from './cashbackDetailState';
5
6
  export const initialState = {
6
7
  fetchState: 'Not-Started',
@@ -27,10 +28,10 @@ const cashbackDetail = createSlice({
27
28
  name: 'cashbackDetail',
28
29
  initialState,
29
30
  reducers: {
30
- fetchCashbackDetail(draft) {
31
+ fetchCashbackDetail: createCacheOverrideFetchReducer((draft) => {
31
32
  draft.fetchState = 'In-Progress';
32
33
  draft.error = undefined;
33
- },
34
+ }),
34
35
  updateCashbackDetail(draft, action) {
35
36
  draft.cashbackByPeriod = toCashbackByPeriod(action.payload);
36
37
  draft.cashbackSummary = toCashbackSummary(action.payload);
@@ -1,5 +1,6 @@
1
1
  import { createSlice } from '@reduxjs/toolkit';
2
2
  import { toAmount } from '../../../../commonStateTypes/amount';
3
+ import { createCacheOverrideFetchReducer } from '../../../../commonStateTypes/cacheOverrideFetchReducer';
3
4
  import { toCreditLimitFrequencyCodeType } from '../../../../entity/chargeCard/chargeCard';
4
5
  import { toCreditTerm, toRePaymentInfo, } from './chargeCardConfigPayload';
5
6
  export const initialState = {
@@ -30,10 +31,10 @@ const chargeCardConfig = createSlice({
30
31
  name: 'chargeCardConfig',
31
32
  initialState,
32
33
  reducers: {
33
- fetchChargeCardConfig(draft) {
34
+ fetchChargeCardConfig: createCacheOverrideFetchReducer((draft) => {
34
35
  draft.fetchState = 'In-Progress';
35
36
  draft.error = undefined;
36
- },
37
+ }),
37
38
  updateChargeCardConfig(draft, action) {
38
39
  const { payload } = action;
39
40
  draft.creditLimitFrequency =
@@ -2,6 +2,7 @@ import { createSlice } from '@reduxjs/toolkit';
2
2
  import { mapSortOrderPayloadToSortOrder, } from '../../../../commonPayloadTypes/sortOrderPayload';
3
3
  import { toAttachment, } from '../../../../entity/transaction/payloadTypes/attachmentPayload';
4
4
  import { emptyChargeCardDetail, mapChargeCardTransactionStatisticsPayloadToChargeCardTransactionStatistics, toChargeCardTransactionSortKeyType, } from './chargeCardDetail';
5
+ import { addChargeCardTransactionFromPusher, addDeclinedChargeCardTransactionFromPusher, } from '../../../../commonStateTypes/pusherActions';
5
6
  export const initialState = {
6
7
  detailById: {},
7
8
  recurringExpensesByChargeCardId: {},
@@ -64,19 +65,30 @@ const chargeCardDetail = createSlice({
64
65
  },
65
66
  fetchChargeCardTransactionList: {
66
67
  reducer(draft, action) {
67
- const { chargeCardId, pageToken, pageTokenType } = action.payload;
68
+ const { chargeCardId, pageToken, pageTokenType, cacheOverride } = action.payload;
68
69
  const existingCardDetail = draft.detailById[chargeCardId] ?? emptyChargeCardDetail;
70
+ const existingUi = existingCardDetail.transactionList.uiState;
71
+ // cacheOverride=true (Pusher): preserve fetchState, error, and scroll
72
+ // to avoid skeleton flash. Normal fetches reset as before.
69
73
  draft.detailById[chargeCardId] = {
70
74
  ...existingCardDetail,
71
75
  transactionList: {
72
76
  ...existingCardDetail.transactionList,
73
- fetchState: 'In-Progress',
74
- error: undefined,
77
+ fetchState: cacheOverride
78
+ ? existingCardDetail.transactionList.fetchState
79
+ : 'In-Progress',
80
+ error: cacheOverride
81
+ ? existingCardDetail.transactionList.error
82
+ : undefined,
75
83
  uiState: {
76
- ...existingCardDetail.transactionList.uiState,
77
- scrollYOffset: existingCardDetail.transactionList.uiState.pageToken === null
78
- ? 0
79
- : existingCardDetail.transactionList.uiState.scrollYOffset,
84
+ ...existingUi,
85
+ // Preserve scroll on silent refresh so users aren't snapped
86
+ // away from their reading position.
87
+ scrollYOffset: cacheOverride
88
+ ? existingUi.scrollYOffset
89
+ : existingUi.pageToken === null
90
+ ? 0
91
+ : existingUi.scrollYOffset,
80
92
  pageToken: pageToken,
81
93
  pageTokenType: pageTokenType,
82
94
  },
@@ -93,18 +105,24 @@ const chargeCardDetail = createSlice({
93
105
  const { chargeCardId, data, cacheOverride } = action.payload;
94
106
  const existingCardDetail = draft.detailById[chargeCardId] ?? emptyChargeCardDetail;
95
107
  const newTransactionIds = data.transactions.map((tran) => tran.transaction_id);
108
+ const existingIds = existingCardDetail.transactionList.transactionIds;
109
+ // cacheOverride (Pusher): refresh page 1 but keep page 2+ IDs.
110
+ // Normal pagination: append new page, deduped.
111
+ const newIdSet = new Set(newTransactionIds);
112
+ const mergedTransactionIds = cacheOverride
113
+ ? [
114
+ ...newTransactionIds,
115
+ ...existingIds.filter((id) => !newIdSet.has(id)),
116
+ ]
117
+ : [
118
+ ...existingIds,
119
+ ...newTransactionIds.filter((id) => !existingIds.includes(id)),
120
+ ];
96
121
  draft.detailById[chargeCardId] = {
97
122
  ...existingCardDetail,
98
123
  transactionList: {
99
124
  ...existingCardDetail.transactionList,
100
- transactionIds: [
101
- ...new Set([
102
- ...(cacheOverride
103
- ? []
104
- : existingCardDetail.transactionList.transactionIds),
105
- ...newTransactionIds,
106
- ]),
107
- ],
125
+ transactionIds: mergedTransactionIds,
108
126
  fetchState: 'Completed',
109
127
  error: undefined,
110
128
  uiState: {
@@ -116,9 +134,12 @@ const chargeCardDetail = createSlice({
116
134
  limit: data.query.limit,
117
135
  pageToken: data.query.page_token,
118
136
  pageTokenType: data.query.page_token_type,
119
- scrollYOffset: existingCardDetail.transactionList.uiState.pageToken === null
120
- ? 0
121
- : existingCardDetail.transactionList.uiState.scrollYOffset,
137
+ // Preserve scroll on silent refresh; reset on user-triggered first page.
138
+ scrollYOffset: cacheOverride
139
+ ? existingCardDetail.transactionList.uiState.scrollYOffset
140
+ : existingCardDetail.transactionList.uiState.pageToken === null
141
+ ? 0
142
+ : existingCardDetail.transactionList.uiState.scrollYOffset,
122
143
  },
123
144
  },
124
145
  };
@@ -632,6 +653,22 @@ const chargeCardDetail = createSlice({
632
653
  Object.assign(draft, initialState);
633
654
  },
634
655
  },
656
+ extraReducers: (builder) => {
657
+ const prependTransaction = (draft, cardId, txId) => {
658
+ const detail = draft.detailById[cardId];
659
+ if (detail != null &&
660
+ !detail.transactionList.transactionIds.includes(txId)) {
661
+ detail.transactionList.transactionIds.unshift(txId);
662
+ }
663
+ };
664
+ builder
665
+ .addCase(addChargeCardTransactionFromPusher, (draft, action) => {
666
+ prependTransaction(draft, action.payload.cardId, action.payload.transaction.transaction_id);
667
+ })
668
+ .addCase(addDeclinedChargeCardTransactionFromPusher, (draft, action) => {
669
+ prependTransaction(draft, action.payload.cardId, action.payload.transaction.transaction_id);
670
+ });
671
+ },
635
672
  });
636
673
  export const { fetchChargeCardDetailPage, fetchChargeCardDetail, updateChargeCardDetailFetchState, fetchChargeCardTransactionList, updateChargeCardDetailUIState, updateChargeCardTransactionList, updateChargeCardTransactionUploadReceiptsFetchStatus, fetchChargeCardTransactionAttachments, updateChargeCardTransactionIsViewReceiptClicked, updateChargeCardTransactionAttachmentsFailure, updatePhysicalChargeCardAttemptSuccessOrFailure, updatePhysicalChargeCardAttempt, updateDebitCardPinAttempt, updateDebitCardPinAttemptSuccessOrFailure, updateChargeCardTransactionReceiptsShowTickFetchStatus, updateChargeCardTransactionAttachmentsInCardDetail, updateChargeCardTransactionListFailure, updateChargeCardDetail, startCVVActivationWait, completeCVVActivationWait, startDebitCardSetPinWait, completeDebitCardSetPinWait, updateChargeCardDetailUpdateStatus, updateChargeCardSpendLimit, updateChargeCardSpendLimitSuccessOrFailure, updateChargeCardName, updateChargeCardNameSuccessOrFailure, lockChargeCard, lockChargeCardSuccessOrFailure, unlockChargeCard, unlockChargeCardSuccessOrFailure, closeChargeCard, closeChargeCardSuccessOrFailure, fetchDepositAccountLimit, updateDepositAccountLimitFetchStatus, fetchChargeCardTransactionStatistics, updateChargeCardTransactionStatistics, updateChargeCardTransactionStatisticsFetchState, fetchChargeCardsRecurringExpenses, updateChargeCardsRecurringExpenses, updateChargeCardsRecurringExpensesFetchState, sendOtpCardHolder, resendOtpCardHolder, sendOtpCardHolderSuccess, sendOtpCardHolderFailure, verifyOtpCardHolder, verifyOtpCardHolderSuccess, verifyOtpCardHolderFailure, clearChargeCardDetail, } = chargeCardDetail.actions;
637
674
  export default chargeCardDetail.reducer;
@@ -13,13 +13,24 @@ export const fetchChargeCardDetailEpic = (actions$, state$, zeniAPI) => actions$
13
13
  const chargeCardAction = [];
14
14
  const state = state$.value;
15
15
  const chargeCardDetail = recordGet(state.chargeCardDetailState.detailById, chargeCardId, undefined);
16
+ // Skip if a user-triggered fetch is already in-flight (not applicable
17
+ // to cacheOverride/Pusher refreshes, which always proceed).
16
18
  if (cacheOverride === true ||
17
19
  chargeCardDetail == null ||
18
20
  chargeCardDetail.fetchState !== 'In-Progress') {
21
+ // Silent refresh: preserve fetchState to avoid skeleton flash.
22
+ // Discriminate via fetchState (not null-check) because the reducer
23
+ // always creates an entry before the epic runs.
24
+ const isSilentRefresh = cacheOverride === true &&
25
+ chargeCardDetail != null &&
26
+ chargeCardDetail.fetchState !== 'Not-Started';
19
27
  chargeCardAction.push(updateChargeCardDetailFetchState({
20
28
  chargeCardId,
21
- isRefreshingViewInBackground: cacheOverride,
22
- fetchState: 'In-Progress',
29
+ isRefreshingViewInBackground: isSilentRefresh,
30
+ fetchState: isSilentRefresh
31
+ ? chargeCardDetail.fetchState
32
+ : 'In-Progress',
33
+ error: isSilentRefresh ? chargeCardDetail.error : undefined,
23
34
  }));
24
35
  const query = {
25
36
  is_include_card_activation_events: true,
@@ -37,6 +48,8 @@ export const fetchChargeCardDetailEpic = (actions$, state$, zeniAPI) => actions$
37
48
  }));
38
49
  }
39
50
  else {
51
+ // Surface errors even on silent refresh so the user
52
+ // knows data is stale (follow-up: consider toast instead).
40
53
  return of(updateChargeCardDetailFetchState({
41
54
  chargeCardId,
42
55
  fetchState: 'Error',
@@ -45,6 +58,7 @@ export const fetchChargeCardDetailEpic = (actions$, state$, zeniAPI) => actions$
45
58
  }));
46
59
  }
47
60
  }), catchError((error) => {
61
+ // Surface network failures even on silent refresh.
48
62
  return of(updateChargeCardDetailFetchState({
49
63
  chargeCardId,
50
64
  fetchState: 'Error',