@zeniai/client-epic-state 5.1.55 → 5.1.57-betaDI0
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.
- package/lib/coreEpics.js +3 -2
- package/lib/entity/accountRecon/accountReconPayload.d.ts +1 -1
- package/lib/entity/accountRecon/accountReconReducer.js +15 -1
- package/lib/entity/chargeCard/chargeCard.d.ts +1 -1
- package/lib/entity/notificationRegistry/notificationRegistryPayload.d.ts +18 -0
- package/lib/entity/notificationRegistry/notificationRegistryPayload.js +28 -0
- package/lib/entity/notificationRegistry/notificationRegistryReducer.d.ts +6 -0
- package/lib/entity/notificationRegistry/notificationRegistryReducer.js +26 -0
- package/lib/entity/notificationRegistry/notificationRegistrySelector.d.ts +2 -0
- package/lib/entity/notificationRegistry/notificationRegistrySelector.js +10 -0
- package/lib/entity/notificationRegistry/notificationRegistryState.d.ts +31 -0
- package/lib/entity/notificationRegistry/notificationRegistryState.js +10 -0
- package/lib/entity/tenant/clearAllEpic.d.ts +3 -1
- package/lib/entity/tenant/clearAllEpic.js +4 -0
- package/lib/epic.d.ts +2 -1
- package/lib/epic.js +2 -1
- package/lib/esm/coreEpics.js +3 -2
- package/lib/esm/entity/accountRecon/accountReconReducer.js +15 -1
- package/lib/esm/entity/notificationRegistry/notificationRegistryPayload.js +24 -0
- package/lib/esm/entity/notificationRegistry/notificationRegistryReducer.js +22 -0
- package/lib/esm/entity/notificationRegistry/notificationRegistrySelector.js +6 -0
- package/lib/esm/entity/notificationRegistry/notificationRegistryState.js +5 -0
- package/lib/esm/entity/tenant/clearAllEpic.js +4 -0
- package/lib/esm/epic.js +2 -1
- package/lib/esm/index.js +6 -2
- package/lib/esm/reducer.js +6 -0
- package/lib/esm/view/expenseAutomationView/selectors/statementParseViewSelector.js +0 -224
- package/lib/esm/view/notificationPreferencesView/epics/saveNotificationPreferencesEpic.js +103 -0
- package/lib/esm/view/notificationPreferencesView/notificationPreferencesEndpoint.js +5 -0
- package/lib/esm/view/notificationPreferencesView/notificationPreferencesViewPayload.js +36 -0
- package/lib/esm/view/notificationPreferencesView/notificationPreferencesViewReducer.js +222 -0
- package/lib/esm/view/notificationPreferencesView/notificationPreferencesViewSelector.js +25 -0
- package/lib/esm/view/notificationPreferencesView/notificationPreferencesViewState.js +4 -0
- package/lib/esm/view/settingsView/epic/fetchNotificationSettingsEpic.js +21 -2
- package/lib/esm/view/settingsView/epic/saveNotificationSettingsEpic.js +2 -1
- package/lib/esm/view/settingsView/settingsViewHelpers.js +3 -2
- package/lib/esm/view/transactionDetail/transactionDetailLocalDataHelper.js +28 -0
- package/lib/index.d.ts +9 -4
- package/lib/index.js +52 -42
- package/lib/reducer.d.ts +6 -0
- package/lib/reducer.js +6 -0
- package/lib/view/common/recurringViewHelper.d.ts +2 -2
- package/lib/view/expenseAutomationView/selectors/statementParseViewSelector.d.ts +1 -15
- package/lib/view/expenseAutomationView/selectors/statementParseViewSelector.js +1 -233
- package/lib/view/expenseAutomationView/types/reconciliationViewState.d.ts +7 -44
- package/lib/view/notificationPreferencesView/epics/saveNotificationPreferencesEpic.d.ts +34 -0
- package/lib/view/notificationPreferencesView/epics/saveNotificationPreferencesEpic.js +107 -0
- package/lib/view/notificationPreferencesView/notificationPreferencesEndpoint.d.ts +2 -0
- package/lib/view/notificationPreferencesView/notificationPreferencesEndpoint.js +9 -0
- package/lib/view/notificationPreferencesView/notificationPreferencesViewPayload.d.ts +7 -0
- package/lib/view/notificationPreferencesView/notificationPreferencesViewPayload.js +41 -0
- package/lib/view/notificationPreferencesView/notificationPreferencesViewReducer.d.ts +30 -0
- package/lib/view/notificationPreferencesView/notificationPreferencesViewReducer.js +226 -0
- package/lib/view/notificationPreferencesView/notificationPreferencesViewSelector.d.ts +7 -0
- package/lib/view/notificationPreferencesView/notificationPreferencesViewSelector.js +32 -0
- package/lib/view/notificationPreferencesView/notificationPreferencesViewState.d.ts +14 -0
- package/lib/view/notificationPreferencesView/notificationPreferencesViewState.js +8 -0
- package/lib/view/settingsView/epic/fetchNotificationSettingsEpic.d.ts +9 -1
- package/lib/view/settingsView/epic/fetchNotificationSettingsEpic.js +21 -2
- package/lib/view/settingsView/epic/saveNotificationSettingsEpic.js +2 -1
- package/lib/view/settingsView/settingsViewHelpers.d.ts +1 -1
- package/lib/view/settingsView/settingsViewHelpers.js +3 -2
- package/lib/view/settingsView/settingsViewPayload.d.ts +4 -0
- package/lib/view/settingsView/settingsViewState.d.ts +1 -1
- package/lib/view/transactionDetail/transactionDetailLocalDataHelper.js +28 -0
- package/package.json +1 -1
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var _a;
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.toggleEventChannel = exports.setGroupFrequency = exports.saveNotificationPreferencesSuccess = exports.saveNotificationPreferencesFailure = exports.saveNotificationPreferences = exports.fetchNotificationPreferencesSuccess = exports.clearNotificationPreferencesLocalOverrides = exports.clearAllNotificationPreferencesView = exports.initialState = void 0;
|
|
5
|
+
const toolkit_1 = require("@reduxjs/toolkit");
|
|
6
|
+
const notificationPreferencesViewPayload_1 = require("./notificationPreferencesViewPayload");
|
|
7
|
+
const notificationPreferencesViewState_1 = require("./notificationPreferencesViewState");
|
|
8
|
+
exports.initialState = {
|
|
9
|
+
cancelEpoch: 0,
|
|
10
|
+
localOverrides: (0, notificationPreferencesViewState_1.emptyNotificationPreferences)(),
|
|
11
|
+
preferences: (0, notificationPreferencesViewState_1.emptyNotificationPreferences)(),
|
|
12
|
+
saveEpoch: 0,
|
|
13
|
+
savePreferencesState: { fetchState: 'Not-Started' },
|
|
14
|
+
};
|
|
15
|
+
const mergePreferences = (base, patch) => {
|
|
16
|
+
const eventEnabledByChannel = {
|
|
17
|
+
...base.eventEnabledByChannel,
|
|
18
|
+
};
|
|
19
|
+
Object.entries(patch.eventEnabledByChannel).forEach(([eventId, channels]) => {
|
|
20
|
+
eventEnabledByChannel[eventId] = {
|
|
21
|
+
...(base.eventEnabledByChannel[eventId] ?? {}),
|
|
22
|
+
...channels,
|
|
23
|
+
};
|
|
24
|
+
});
|
|
25
|
+
return {
|
|
26
|
+
eventEnabledByChannel,
|
|
27
|
+
groupFrequencyByGroupId: {
|
|
28
|
+
...base.groupFrequencyByGroupId,
|
|
29
|
+
...patch.groupFrequencyByGroupId,
|
|
30
|
+
},
|
|
31
|
+
};
|
|
32
|
+
};
|
|
33
|
+
// Remove only the (eventId, channel) and groupId keys that were actually saved
|
|
34
|
+
// to the server from `localOverrides` — AND whose current value still equals
|
|
35
|
+
// what was saved. Any new edits the user added while the PUT was in flight
|
|
36
|
+
// (either new keys not present in `saved`, OR same keys the user flipped back
|
|
37
|
+
// to a different value) are preserved so the next debounce cycle picks them up.
|
|
38
|
+
//
|
|
39
|
+
// Presence-only subtraction (the prior implementation) silently dropped a
|
|
40
|
+
// same-key re-edit that landed AFTER debounce fired but BEFORE the response
|
|
41
|
+
// returned. Concrete case:
|
|
42
|
+
// 1. toggle evt1.email = false → localOverrides = {evt1:{email:false}}
|
|
43
|
+
// 2. debounce PUT #1 fires with savedOverrides = {evt1:{email:false}}
|
|
44
|
+
// 3. user re-toggles evt1.email = true → localOverrides = {evt1:{email:true}}
|
|
45
|
+
// 4. PUT #1 success → subtract dropped `email` on presence, so the true
|
|
46
|
+
// re-edit disappeared and next-debounce found nothing to send.
|
|
47
|
+
const subtractSavedOverrides = (current, saved) => {
|
|
48
|
+
const eventEnabledByChannel = {};
|
|
49
|
+
Object.entries(current.eventEnabledByChannel).forEach(([eventId, channels]) => {
|
|
50
|
+
const savedChannels = saved.eventEnabledByChannel[eventId];
|
|
51
|
+
if (savedChannels == null) {
|
|
52
|
+
eventEnabledByChannel[eventId] = channels;
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
const remainingChannels = {};
|
|
56
|
+
Object.keys(channels).forEach((channel) => {
|
|
57
|
+
// Preserve the key when it's a new channel OR when the user's
|
|
58
|
+
// current value differs from what was saved (same-key re-edit).
|
|
59
|
+
if (!(channel in savedChannels) ||
|
|
60
|
+
channels[channel] !== savedChannels[channel]) {
|
|
61
|
+
remainingChannels[channel] = channels[channel];
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
if (Object.keys(remainingChannels).length > 0) {
|
|
65
|
+
eventEnabledByChannel[eventId] = remainingChannels;
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
const groupFrequencyByGroupId = {};
|
|
69
|
+
Object.entries(current.groupFrequencyByGroupId).forEach(([groupId, frequency]) => {
|
|
70
|
+
if (saved.groupFrequencyByGroupId[groupId] !== frequency) {
|
|
71
|
+
groupFrequencyByGroupId[groupId] = frequency;
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
return { eventEnabledByChannel, groupFrequencyByGroupId };
|
|
75
|
+
};
|
|
76
|
+
const notificationPreferencesView = (0, toolkit_1.createSlice)({
|
|
77
|
+
name: 'notificationPreferencesView',
|
|
78
|
+
initialState: exports.initialState,
|
|
79
|
+
reducers: {
|
|
80
|
+
clearAllNotificationPreferencesView(draft) {
|
|
81
|
+
// Reset everything EXCEPT `cancelEpoch`, which must stay monotonic
|
|
82
|
+
// across the lifetime of the app instance. `initialState.cancelEpoch`
|
|
83
|
+
// is `0`; returning `initialState` verbatim would rewind the counter
|
|
84
|
+
// to zero, and any in-flight save whose `cancelEpochAtDispatch` was
|
|
85
|
+
// captured pre-clearAll (>0) would then satisfy the "captured >=
|
|
86
|
+
// current" epoch guard and merge stale edits into fresh preferences.
|
|
87
|
+
// Bumping instead of resetting also invalidates the abandoned save
|
|
88
|
+
// for free — Cursor Bugbot bc7876f1 followup.
|
|
89
|
+
const nextCancelEpoch = draft.cancelEpoch + 1;
|
|
90
|
+
// saveEpoch must also stay monotonic across clearAll for the same
|
|
91
|
+
// reason (Cursor Bugbot 3632510237). Rewinding to 0 would let a
|
|
92
|
+
// stale-in-flight GET whose `saveEpochAtDispatch` was captured >0
|
|
93
|
+
// satisfy the "captured >= current" epoch guard and clobber fresh
|
|
94
|
+
// preferences on any subsequent save.
|
|
95
|
+
const nextSaveEpoch = draft.saveEpoch + 1;
|
|
96
|
+
return {
|
|
97
|
+
...exports.initialState,
|
|
98
|
+
cancelEpoch: nextCancelEpoch,
|
|
99
|
+
saveEpoch: nextSaveEpoch,
|
|
100
|
+
};
|
|
101
|
+
},
|
|
102
|
+
clearNotificationPreferencesLocalOverrides(draft) {
|
|
103
|
+
// Discards in-flight per-event/per-group edits held in `localOverrides`
|
|
104
|
+
// without touching the fetched `preferences` snapshot. Used by the
|
|
105
|
+
// settings-page Cancel affordance so the effective preferences revert
|
|
106
|
+
// to the last server-known state without triggering a refetch race.
|
|
107
|
+
//
|
|
108
|
+
// Cancel/in-flight-save race: every Cancel bumps `cancelEpoch`
|
|
109
|
+
// monotonically. Any save that captured a lower epoch value at
|
|
110
|
+
// dispatch time is treated as stale by the Success/Failure reducer
|
|
111
|
+
// — its merge is skipped. Unconditional bump (vs the earlier
|
|
112
|
+
// counter model) survives switchMap abandonment and double-Cancel
|
|
113
|
+
// (Cursor Bugbot 4aa021f7): even if the abandoned save's
|
|
114
|
+
// Success/Failure never dispatches, subsequent legitimate saves
|
|
115
|
+
// still work because their captured epoch matches the current one.
|
|
116
|
+
draft.cancelEpoch += 1;
|
|
117
|
+
draft.localOverrides = (0, notificationPreferencesViewState_1.emptyNotificationPreferences)();
|
|
118
|
+
// Also drop `savePreferencesState` back to Not-Started so any
|
|
119
|
+
// "Saving…" affordance bound to `getNotificationPreferencesSaveState`
|
|
120
|
+
// clears on Cancel. Without this, a Cancel-during-save whose stale
|
|
121
|
+
// Success/Failure never fires (switchMap abandonment) leaves the
|
|
122
|
+
// selector reporting In-Progress forever — Cursor Bugbot bc7876f1.
|
|
123
|
+
draft.savePreferencesState = { fetchState: 'Not-Started' };
|
|
124
|
+
},
|
|
125
|
+
fetchNotificationPreferencesSuccess(draft, action) {
|
|
126
|
+
// Piggybacks on the settings-envelope fetch. The GET response is a full
|
|
127
|
+
// snapshot of the server-known preferences (empty maps included), so
|
|
128
|
+
// REPLACE `preferences` rather than merging — merging would leak keys
|
|
129
|
+
// the server has since removed. DO NOT touch `localOverrides`: a refetch
|
|
130
|
+
// that fires while the user has in-flight edits (pre-debounce) must not
|
|
131
|
+
// silently drop them; the save-success path is the only clearer.
|
|
132
|
+
// A `null`/`undefined` payload isn't a snapshot at all (e.g. the
|
|
133
|
+
// envelope key was omitted); no-op instead of wiping preferences.
|
|
134
|
+
if (action.payload.preferences == null) {
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
// Stale-GET guard (Cursor Bugbot 3632510237): if the fetch epic
|
|
138
|
+
// captured a `saveEpoch` lower than the current one, a save has
|
|
139
|
+
// succeeded since this GET dispatched — the response is carrying
|
|
140
|
+
// the pre-PUT snapshot and would clobber the just-saved server
|
|
141
|
+
// truth back to the pre-edit state until the next refetch. Skip
|
|
142
|
+
// the replace; the store already reflects the fresher save.
|
|
143
|
+
if (action.payload.saveEpochAtDispatch < draft.saveEpoch) {
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
draft.preferences = (0, notificationPreferencesViewPayload_1.mapPayloadToPreferences)(action.payload.preferences);
|
|
147
|
+
},
|
|
148
|
+
saveNotificationPreferences(draft) {
|
|
149
|
+
draft.savePreferencesState = { fetchState: 'In-Progress' };
|
|
150
|
+
},
|
|
151
|
+
saveNotificationPreferencesFailure(draft, action) {
|
|
152
|
+
// Stale failure from a cancelled-since save — swallow silently so
|
|
153
|
+
// the UI doesn't surface an error banner for a save the user
|
|
154
|
+
// already abandoned.
|
|
155
|
+
if (action.payload.cancelEpochAtDispatch < draft.cancelEpoch) {
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
// Preserve `localOverrides` so the user's in-flight edits survive a
|
|
159
|
+
// transient network blip. UI should surface an error affordance and
|
|
160
|
+
// allow retry.
|
|
161
|
+
draft.savePreferencesState = {
|
|
162
|
+
fetchState: 'Error',
|
|
163
|
+
error: action.payload.error,
|
|
164
|
+
};
|
|
165
|
+
},
|
|
166
|
+
saveNotificationPreferencesSuccess(draft, action) {
|
|
167
|
+
// Preserve-on-partial: PUT /preferences is patch-semantic. The response
|
|
168
|
+
// echoes only the fields that changed, so merge into `preferences`
|
|
169
|
+
// instead of replacing — otherwise a single-channel toggle would wipe
|
|
170
|
+
// every other stored preference.
|
|
171
|
+
//
|
|
172
|
+
// Rollback invariant (F5): `serverEcho` may be `undefined` if the server
|
|
173
|
+
// rolls back to an older shape that omits the echo entirely. In that
|
|
174
|
+
// case fall back to merging `savedOverrides` into `preferences` — the
|
|
175
|
+
// PUT succeeded (2xx), so the values we sent are now server truth. If
|
|
176
|
+
// we merged an empty patch instead, `subtractSavedOverrides` would
|
|
177
|
+
// still strip the just-saved keys from `localOverrides`, leaving the
|
|
178
|
+
// effective preferences (preferences ∪ localOverrides) reverted to the
|
|
179
|
+
// pre-edit server snapshot until the next refetch.
|
|
180
|
+
//
|
|
181
|
+
// In-flight-edit invariant: `savedOverrides` is the exact snapshot the
|
|
182
|
+
// epic PUT to the server. Subtracting those keys from `localOverrides`
|
|
183
|
+
// (instead of clearing it wholesale) preserves any edits the user
|
|
184
|
+
// added AFTER the debounce fired but BEFORE the response landed. The
|
|
185
|
+
// next debounce cycle will pick them up. Clearing wholesale drops
|
|
186
|
+
// in-flight edits from both UI (once server echo lands) and server.
|
|
187
|
+
// Cancel/in-flight-save race: `cancelEpoch` monotonically increases
|
|
188
|
+
// on every Cancel. If the save captured a lower epoch at dispatch,
|
|
189
|
+
// the user has pressed Cancel since — skip the `preferences` merge
|
|
190
|
+
// and the `localOverrides` subtract (Cancel already emptied it).
|
|
191
|
+
// Do NOT flip fetchState so a subsequent legit save can still show
|
|
192
|
+
// its own In-Progress → Completed lifecycle. The server itself has
|
|
193
|
+
// accepted the write — reverting server-side is out of FE scope; UI
|
|
194
|
+
// reflects the cancelled intention until the next refetch merges
|
|
195
|
+
// whatever the server persisted.
|
|
196
|
+
if (action.payload.cancelEpochAtDispatch < draft.cancelEpoch) {
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
// Bump `saveEpoch` so any settings-envelope GET that was in flight
|
|
200
|
+
// BEFORE this PUT resolved is treated as stale. Its captured epoch
|
|
201
|
+
// will be lower than the new value, so its reducer branch will
|
|
202
|
+
// skip the `preferences` replace. Cursor Bugbot 3632510237.
|
|
203
|
+
draft.saveEpoch += 1;
|
|
204
|
+
draft.savePreferencesState = { fetchState: 'Completed' };
|
|
205
|
+
const patch = action.payload.serverEcho == null
|
|
206
|
+
? action.payload.savedOverrides
|
|
207
|
+
: (0, notificationPreferencesViewPayload_1.mapPayloadToPreferences)(action.payload.serverEcho);
|
|
208
|
+
draft.preferences = mergePreferences(draft.preferences, patch);
|
|
209
|
+
draft.localOverrides = subtractSavedOverrides(draft.localOverrides, action.payload.savedOverrides);
|
|
210
|
+
},
|
|
211
|
+
setGroupFrequency(draft, action) {
|
|
212
|
+
draft.localOverrides.groupFrequencyByGroupId[action.payload.groupId] =
|
|
213
|
+
action.payload.frequency;
|
|
214
|
+
},
|
|
215
|
+
toggleEventChannel(draft, action) {
|
|
216
|
+
const { channel, enabled, eventId } = action.payload;
|
|
217
|
+
const eventMap = {
|
|
218
|
+
...(draft.localOverrides.eventEnabledByChannel[eventId] ?? {}),
|
|
219
|
+
};
|
|
220
|
+
eventMap[channel] = enabled;
|
|
221
|
+
draft.localOverrides.eventEnabledByChannel[eventId] = eventMap;
|
|
222
|
+
},
|
|
223
|
+
},
|
|
224
|
+
});
|
|
225
|
+
_a = notificationPreferencesView.actions, exports.clearAllNotificationPreferencesView = _a.clearAllNotificationPreferencesView, exports.clearNotificationPreferencesLocalOverrides = _a.clearNotificationPreferencesLocalOverrides, exports.fetchNotificationPreferencesSuccess = _a.fetchNotificationPreferencesSuccess, exports.saveNotificationPreferences = _a.saveNotificationPreferences, exports.saveNotificationPreferencesFailure = _a.saveNotificationPreferencesFailure, exports.saveNotificationPreferencesSuccess = _a.saveNotificationPreferencesSuccess, exports.setGroupFrequency = _a.setGroupFrequency, exports.toggleEventChannel = _a.toggleEventChannel;
|
|
226
|
+
exports.default = notificationPreferencesView.reducer;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { FetchStateAndError } from '../../commonStateTypes/common';
|
|
2
|
+
import { RootState } from '../../reducer';
|
|
3
|
+
import { NotificationPreferences } from './notificationPreferencesViewState';
|
|
4
|
+
export declare const getNotificationPreferencesSaveState: (state: RootState) => FetchStateAndError;
|
|
5
|
+
export declare const getEffectiveNotificationPreferences: (state: RootState) => NotificationPreferences;
|
|
6
|
+
export declare const getNotificationLocalOverrides: (state: RootState) => NotificationPreferences;
|
|
7
|
+
export declare const hasUnsavedNotificationPreferences: (state: RootState) => boolean;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.hasUnsavedNotificationPreferences = exports.getNotificationLocalOverrides = exports.getEffectiveNotificationPreferences = exports.getNotificationPreferencesSaveState = void 0;
|
|
4
|
+
const getView = (state) => state.notificationPreferencesViewState;
|
|
5
|
+
const getNotificationPreferencesSaveState = (state) => getView(state).savePreferencesState;
|
|
6
|
+
exports.getNotificationPreferencesSaveState = getNotificationPreferencesSaveState;
|
|
7
|
+
const getEffectiveNotificationPreferences = (state) => {
|
|
8
|
+
const view = getView(state);
|
|
9
|
+
const mergedEventEnabledByChannel = { ...view.preferences.eventEnabledByChannel };
|
|
10
|
+
Object.entries(view.localOverrides.eventEnabledByChannel).forEach(([eventId, channels]) => {
|
|
11
|
+
mergedEventEnabledByChannel[eventId] = {
|
|
12
|
+
...(view.preferences.eventEnabledByChannel[eventId] ?? {}),
|
|
13
|
+
...channels,
|
|
14
|
+
};
|
|
15
|
+
});
|
|
16
|
+
return {
|
|
17
|
+
eventEnabledByChannel: mergedEventEnabledByChannel,
|
|
18
|
+
groupFrequencyByGroupId: {
|
|
19
|
+
...view.preferences.groupFrequencyByGroupId,
|
|
20
|
+
...view.localOverrides.groupFrequencyByGroupId,
|
|
21
|
+
},
|
|
22
|
+
};
|
|
23
|
+
};
|
|
24
|
+
exports.getEffectiveNotificationPreferences = getEffectiveNotificationPreferences;
|
|
25
|
+
const getNotificationLocalOverrides = (state) => getView(state).localOverrides;
|
|
26
|
+
exports.getNotificationLocalOverrides = getNotificationLocalOverrides;
|
|
27
|
+
const hasUnsavedNotificationPreferences = (state) => {
|
|
28
|
+
const overrides = getView(state).localOverrides;
|
|
29
|
+
return (Object.keys(overrides.eventEnabledByChannel).length > 0 ||
|
|
30
|
+
Object.keys(overrides.groupFrequencyByGroupId).length > 0);
|
|
31
|
+
};
|
|
32
|
+
exports.hasUnsavedNotificationPreferences = hasUnsavedNotificationPreferences;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { FetchStateAndError } from '../../commonStateTypes/common';
|
|
2
|
+
import { NotificationChannel, NotificationFrequency } from '../../entity/notificationRegistry/notificationRegistryState';
|
|
3
|
+
export interface NotificationPreferences {
|
|
4
|
+
eventEnabledByChannel: Record<string, Partial<Record<NotificationChannel, boolean>>>;
|
|
5
|
+
groupFrequencyByGroupId: Record<string, NotificationFrequency>;
|
|
6
|
+
}
|
|
7
|
+
export interface NotificationPreferencesViewState {
|
|
8
|
+
cancelEpoch: number;
|
|
9
|
+
localOverrides: NotificationPreferences;
|
|
10
|
+
preferences: NotificationPreferences;
|
|
11
|
+
saveEpoch: number;
|
|
12
|
+
savePreferencesState: FetchStateAndError;
|
|
13
|
+
}
|
|
14
|
+
export declare const emptyNotificationPreferences: () => NotificationPreferences;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.emptyNotificationPreferences = void 0;
|
|
4
|
+
const emptyNotificationPreferences = () => ({
|
|
5
|
+
eventEnabledByChannel: {},
|
|
6
|
+
groupFrequencyByGroupId: {},
|
|
7
|
+
});
|
|
8
|
+
exports.emptyNotificationPreferences = emptyNotificationPreferences;
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { ActionsObservable, StateObservable } from 'redux-observable';
|
|
2
|
+
import { updateNotificationRegistry } from '../../../entity/notificationRegistry/notificationRegistryReducer';
|
|
2
3
|
import { RootState } from '../../../reducer';
|
|
3
4
|
import { ZeniAPI } from '../../../zeniAPI';
|
|
5
|
+
import { fetchNotificationPreferencesSuccess } from '../../notificationPreferencesView/notificationPreferencesViewReducer';
|
|
4
6
|
import { fetchNotificationSettings, updateNotificationSettingsOnFailure, updateNotificationSettingsOnSuccess } from '../settingsViewReducer';
|
|
5
|
-
export type ActionType = ReturnType<typeof fetchNotificationSettings> | ReturnType<typeof updateNotificationSettingsOnSuccess> | ReturnType<typeof updateNotificationSettingsOnFailure>;
|
|
7
|
+
export type ActionType = ReturnType<typeof fetchNotificationSettings> | ReturnType<typeof updateNotificationSettingsOnSuccess> | ReturnType<typeof updateNotificationSettingsOnFailure> | ReturnType<typeof updateNotificationRegistry> | ReturnType<typeof fetchNotificationPreferencesSuccess>;
|
|
6
8
|
export declare const fetchNotificationSettingsEpic: (actions$: ActionsObservable<ActionType>, state$: StateObservable<RootState>, zeniAPI: ZeniAPI) => import("rxjs").Observable<{
|
|
7
9
|
payload: undefined;
|
|
8
10
|
type: "settings/fetchNotificationSettings";
|
|
@@ -15,4 +17,10 @@ export declare const fetchNotificationSettingsEpic: (actions$: ActionsObservable
|
|
|
15
17
|
} | {
|
|
16
18
|
payload: import("../../../responsePayload").ZeniAPIStatus<Record<string, unknown>>;
|
|
17
19
|
type: "settings/updateNotificationSettingsOnFailure";
|
|
20
|
+
} | {
|
|
21
|
+
payload: import("../../../entity/notificationRegistry/notificationRegistryPayload").NotificationRegistryPayload;
|
|
22
|
+
type: "notificationRegistry/updateNotificationRegistry";
|
|
23
|
+
} | {
|
|
24
|
+
payload: import("../../notificationPreferencesView/notificationPreferencesViewReducer").FetchNotificationPreferencesSuccessPayload;
|
|
25
|
+
type: "notificationPreferencesView/fetchNotificationPreferencesSuccess";
|
|
18
26
|
}>;
|
|
@@ -3,20 +3,39 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.fetchNotificationSettingsEpic = void 0;
|
|
4
4
|
const rxjs_1 = require("rxjs");
|
|
5
5
|
const operators_1 = require("rxjs/operators");
|
|
6
|
+
const notificationRegistryReducer_1 = require("../../../entity/notificationRegistry/notificationRegistryReducer");
|
|
6
7
|
const responsePayload_1 = require("../../../responsePayload");
|
|
8
|
+
const notificationPreferencesEndpoint_1 = require("../../notificationPreferencesView/notificationPreferencesEndpoint");
|
|
9
|
+
const notificationPreferencesViewReducer_1 = require("../../notificationPreferencesView/notificationPreferencesViewReducer");
|
|
7
10
|
const settingsViewReducer_1 = require("../settingsViewReducer");
|
|
8
11
|
const fetchNotificationSettingsEpic = (actions$, state$, zeniAPI) => actions$.pipe((0, operators_1.filter)(settingsViewReducer_1.fetchNotificationSettings.match), (0, operators_1.switchMap)(() => {
|
|
9
12
|
const state = state$.value;
|
|
10
|
-
const URL = `${zeniAPI.apiEndPoints.notificationMicroServiceBaseUrl}/1.0/notification-preferences`;
|
|
11
13
|
const userEmail = state.tenantState.loggedInUser?.userEmail;
|
|
12
14
|
if (userEmail == null) {
|
|
13
15
|
return (0, rxjs_1.from)([]);
|
|
14
16
|
}
|
|
15
|
-
|
|
17
|
+
// Snapshot the save epoch at GET-dispatch time. The reducer compares
|
|
18
|
+
// the captured value against the current `saveEpoch` on response and
|
|
19
|
+
// skips the `preferences` replace when a save has landed in the
|
|
20
|
+
// meantime — the GET is carrying the pre-PUT snapshot and would
|
|
21
|
+
// otherwise clobber the fresh save. Cursor Bugbot 3632510237.
|
|
22
|
+
const saveEpochAtDispatch = state.notificationPreferencesViewState.saveEpoch;
|
|
23
|
+
return zeniAPI
|
|
24
|
+
.getJSON((0, notificationPreferencesEndpoint_1.notificationPreferencesUrl)(zeniAPI))
|
|
25
|
+
.pipe((0, operators_1.mergeMap)((response) => {
|
|
16
26
|
if ((0, responsePayload_1.isSuccessResponse)(response) && response.data != null) {
|
|
17
27
|
const updateActions = [
|
|
18
28
|
(0, settingsViewReducer_1.updateNotificationSettingsOnSuccess)(response.data, userEmail),
|
|
19
29
|
];
|
|
30
|
+
if (response.data.task_checklist_registry != null) {
|
|
31
|
+
updateActions.push((0, notificationRegistryReducer_1.updateNotificationRegistry)(response.data.task_checklist_registry));
|
|
32
|
+
}
|
|
33
|
+
if (response.data.task_checklist_preferences != null) {
|
|
34
|
+
updateActions.push((0, notificationPreferencesViewReducer_1.fetchNotificationPreferencesSuccess)({
|
|
35
|
+
preferences: response.data.task_checklist_preferences,
|
|
36
|
+
saveEpochAtDispatch,
|
|
37
|
+
}));
|
|
38
|
+
}
|
|
20
39
|
return (0, rxjs_1.of)(...updateActions);
|
|
21
40
|
}
|
|
22
41
|
else {
|
|
@@ -5,9 +5,10 @@ const rxjs_1 = require("rxjs");
|
|
|
5
5
|
const operators_1 = require("rxjs/operators");
|
|
6
6
|
const snackbarReducer_1 = require("../../../entity/snackbar/snackbarReducer");
|
|
7
7
|
const responsePayload_1 = require("../../../responsePayload");
|
|
8
|
+
const notificationPreferencesEndpoint_1 = require("../../notificationPreferencesView/notificationPreferencesEndpoint");
|
|
8
9
|
const settingsViewReducer_1 = require("../settingsViewReducer");
|
|
9
10
|
const saveNotificationSettingsEpic = (actions$, state$, zeniAPI) => actions$.pipe((0, operators_1.filter)(settingsViewReducer_1.saveNotificationSettings.match), (0, operators_1.switchMap)(() => {
|
|
10
|
-
const URL =
|
|
11
|
+
const URL = (0, notificationPreferencesEndpoint_1.notificationPreferencesUrl)(zeniAPI);
|
|
11
12
|
const { notificationSettings, notificationSettingsLocalData } = state$.value.settingsViewState.notification;
|
|
12
13
|
const payload = toSaveNotificationSettingsPayload(notificationSettingsLocalData, notificationSettings);
|
|
13
14
|
return zeniAPI
|
|
@@ -14,4 +14,4 @@ export declare const isMyBankConnectionsTabVisible: (currentTenant: CurrentTenan
|
|
|
14
14
|
export declare const isPerformanceTabVisible: (userRole: UserRoleType[], loggedInUser?: LoggedInUser) => boolean;
|
|
15
15
|
export declare const isRemindersSectionVisibleOnSettingsPage: (reminderNotificationSettings: ReminderNotificationSettingsData) => boolean;
|
|
16
16
|
export declare const isMonthEndNotificationsSectionVisibleOnSettingsPage: (monthEndInsightsNotificationSettings: MonthEndInsightsNotificationSettingsData, signedInUseEmail: string) => boolean;
|
|
17
|
-
export declare const isNotificationsTabVisible: (notificationSettings: NotificationSettingsData, signedInUseEmail: string, isDebitCardFlagEnabled: boolean, currentTenant: CurrentTenant | undefined) => boolean;
|
|
17
|
+
export declare const isNotificationsTabVisible: (notificationSettings: NotificationSettingsData, signedInUseEmail: string, isDebitCardFlagEnabled: boolean, currentTenant: CurrentTenant | undefined, hasTaskChecklistAccess: boolean) => boolean;
|
|
@@ -160,13 +160,14 @@ const isMonthEndNotificationsSectionVisibleOnSettingsPage = (monthEndInsightsNot
|
|
|
160
160
|
monthEndInsightsNotificationSettings.recipientEmailIds.includes(signedInUseEmail));
|
|
161
161
|
};
|
|
162
162
|
exports.isMonthEndNotificationsSectionVisibleOnSettingsPage = isMonthEndNotificationsSectionVisibleOnSettingsPage;
|
|
163
|
-
const isNotificationsTabVisible = (notificationSettings, signedInUseEmail, isDebitCardFlagEnabled, currentTenant) => {
|
|
163
|
+
const isNotificationsTabVisible = (notificationSettings, signedInUseEmail, isDebitCardFlagEnabled, currentTenant, hasTaskChecklistAccess) => {
|
|
164
164
|
if (currentTenant == null) {
|
|
165
165
|
return false;
|
|
166
166
|
}
|
|
167
167
|
const { reminderNotificationSettings, monthEndInsightsNotificationSettings } = notificationSettings;
|
|
168
168
|
return (((0, exports.isRemindersSectionVisibleOnSettingsPage)(reminderNotificationSettings) ||
|
|
169
|
-
(0, exports.isMonthEndNotificationsSectionVisibleOnSettingsPage)(monthEndInsightsNotificationSettings, signedInUseEmail)
|
|
169
|
+
(0, exports.isMonthEndNotificationsSectionVisibleOnSettingsPage)(monthEndInsightsNotificationSettings, signedInUseEmail) ||
|
|
170
|
+
hasTaskChecklistAccess) &&
|
|
170
171
|
((0, tenantSelector_1.isTenantAccountingServicesEnabled)(currentTenant) ||
|
|
171
172
|
((0, tenantSelector_1.isTenantBankingOnly)(isDebitCardFlagEnabled, currentTenant) === false &&
|
|
172
173
|
(0, tenantSelector_1.isTenantCardsOnly)(currentTenant) === false)));
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { AddressPayload } from '../../entity/address/addressPayload';
|
|
2
2
|
import { CompanyPayload } from '../../entity/company/companyPayload';
|
|
3
|
+
import { NotificationRegistryPayload } from '../../entity/notificationRegistry/notificationRegistryPayload';
|
|
3
4
|
import { UserPayload } from '../../entity/user/userPayload';
|
|
4
5
|
import { UserRolePayload } from '../../entity/userRole/userRolePayload';
|
|
5
6
|
import { ZeniAPIResponse } from '../../responsePayload';
|
|
6
7
|
import { AddressUpdatableInfoPayload } from '../addressView/addressViewPayload';
|
|
8
|
+
import { NotificationPreferencesPayload } from '../notificationPreferencesView/notificationPreferencesViewPayload';
|
|
7
9
|
interface MyProfilePeoplePayload {
|
|
8
10
|
user_roles: UserRolePayload[];
|
|
9
11
|
users: UserPayload[];
|
|
@@ -36,6 +38,8 @@ export interface NotificationSettingsPayload {
|
|
|
36
38
|
pending_reimbursement_approval_notification: RemindersPayload | null;
|
|
37
39
|
uncategorized_transaction_notification: RemindersPayload | null;
|
|
38
40
|
month_end_email_recipient_email_ids?: string[];
|
|
41
|
+
task_checklist_preferences?: NotificationPreferencesPayload;
|
|
42
|
+
task_checklist_registry?: NotificationRegistryPayload;
|
|
39
43
|
}
|
|
40
44
|
export type NotificationSettingsResponse = ZeniAPIResponse<NotificationSettingsPayload>;
|
|
41
45
|
interface RefreshQBOPayload {
|
|
@@ -12,7 +12,7 @@ export interface IntegrationsSettings {
|
|
|
12
12
|
export declare const REMINDER_NOTIFICATION_TYPES: readonly ["missingReceiptNotification", "uncategorizedTransactionNotification", "pendingBillApprovalNotification", "pendingReimbursementApprovalNotification"];
|
|
13
13
|
declare const toReminderTypeKey: (v: string) => "missingReceiptNotification" | "uncategorizedTransactionNotification" | "pendingBillApprovalNotification" | "pendingReimbursementApprovalNotification";
|
|
14
14
|
export type ReminderTypeKey = ReturnType<typeof toReminderTypeKey>;
|
|
15
|
-
export declare const toRemindersFrequencyType: (v: string) => "
|
|
15
|
+
export declare const toRemindersFrequencyType: (v: string) => "daily" | "weekly" | "monthly" | "bi-weekly";
|
|
16
16
|
export type FrequencyTypeKey = ReturnType<typeof toRemindersFrequencyType>;
|
|
17
17
|
export declare const NOTIFICATION_MODES: readonly ["email", "dashboard"];
|
|
18
18
|
export declare const toNotificationMode: (v: string) => "dashboard" | "email";
|
|
@@ -301,11 +301,13 @@ const toUpdateLineItemsOriginalCategoryClass = (transaction, transactionDetailLo
|
|
|
301
301
|
const isLineIdInReplaceList = (findLineID) => lineIdsForReplace.find((lineId) => findLineID === lineId);
|
|
302
302
|
const isLineIdInUpdateList = (findLineID) => lineIdsForUpdateAll.find((lineId) => findLineID === lineId);
|
|
303
303
|
const newLineItems = {};
|
|
304
|
+
const persistedLineIds = new Set();
|
|
304
305
|
const checkIfNotJEAndDeposit = (0, vendorTransaction_1.isVendorTransaction)(transaction) === true ||
|
|
305
306
|
(0, customerTransaction_1.isCustomerTransaction)(transaction) === true;
|
|
306
307
|
if (transaction.lines != null) {
|
|
307
308
|
// always preserving the order of the line items. hence iterating over this
|
|
308
309
|
transaction.lines.forEach((line) => {
|
|
310
|
+
persistedLineIds.add(line.id);
|
|
309
311
|
if (line.type === 'transaction_with_account_and_class_line' ||
|
|
310
312
|
line.type === 'transaction_with_product_or_service_line' ||
|
|
311
313
|
line.type === 'journal_entry_transaction_line') {
|
|
@@ -436,6 +438,7 @@ const toUpdateLineItemsOriginalCategoryClass = (transaction, transactionDetailLo
|
|
|
436
438
|
}
|
|
437
439
|
});
|
|
438
440
|
}
|
|
441
|
+
preserveLocalLines(newLineItems, transactionDetailLocalData.lineItemById, persistedLineIds);
|
|
439
442
|
const newLocalData = {
|
|
440
443
|
...transactionDetailState_1.initialSupportedTransactionDetail.transactionDetailLocalData,
|
|
441
444
|
memo: transactionDetailLocalData.memo,
|
|
@@ -457,11 +460,13 @@ const toUpdateLineItemsOriginalCategoryClass = (transaction, transactionDetailLo
|
|
|
457
460
|
exports.toUpdateLineItemsOriginalCategoryClass = toUpdateLineItemsOriginalCategoryClass;
|
|
458
461
|
const toSetAllLineItemsToCategoryClass = (transaction, transactionDetailLocalData, isUpdateAll, lineEntity, chosenAccount, chosenClass) => {
|
|
459
462
|
const newLineItems = {};
|
|
463
|
+
const persistedLineIds = new Set();
|
|
460
464
|
const updateAllLines = (0, vendorTransaction_1.isVendorTransaction)(transaction) === true ||
|
|
461
465
|
(0, customerTransaction_1.isCustomerTransaction)(transaction) === true;
|
|
462
466
|
if (transaction.lines != null) {
|
|
463
467
|
// always preserving the order of the line items. hence iterating over this
|
|
464
468
|
transaction.lines.forEach((line) => {
|
|
469
|
+
persistedLineIds.add(line.id);
|
|
465
470
|
if (line.type === 'transaction_with_account_and_class_line' ||
|
|
466
471
|
line.type === 'transaction_with_product_or_service_line' ||
|
|
467
472
|
line.type === 'journal_entry_transaction_line') {
|
|
@@ -542,6 +547,7 @@ const toSetAllLineItemsToCategoryClass = (transaction, transactionDetailLocalDat
|
|
|
542
547
|
}
|
|
543
548
|
});
|
|
544
549
|
}
|
|
550
|
+
preserveLocalLines(newLineItems, transactionDetailLocalData.lineItemById, persistedLineIds);
|
|
545
551
|
const newLocalData = {
|
|
546
552
|
...transactionDetailState_1.initialSupportedTransactionDetail.transactionDetailLocalData,
|
|
547
553
|
memo: transactionDetailLocalData.memo,
|
|
@@ -563,11 +569,13 @@ const toSetAllLineItemsToCategoryClass = (transaction, transactionDetailLocalDat
|
|
|
563
569
|
exports.toSetAllLineItemsToCategoryClass = toSetAllLineItemsToCategoryClass;
|
|
564
570
|
const toSetAllLineItemsLocalDataIsUpdateAllChecked = (transaction, transactionDetailLocalData, isUpdateAll, entity) => {
|
|
565
571
|
const newLineItems = {};
|
|
572
|
+
const persistedLineIds = new Set();
|
|
566
573
|
const updateAllLines = (0, vendorTransaction_1.isVendorTransaction)(transaction) === true ||
|
|
567
574
|
(0, customerTransaction_1.isCustomerTransaction)(transaction) === true;
|
|
568
575
|
if (transaction.lines != null) {
|
|
569
576
|
// always preserving the order of the line items. hence iterating over this
|
|
570
577
|
transaction.lines.forEach((line) => {
|
|
578
|
+
persistedLineIds.add(line.id);
|
|
571
579
|
const lineId = line.id;
|
|
572
580
|
if (line.type === 'transaction_with_account_and_class_line' ||
|
|
573
581
|
line.type === 'transaction_with_product_or_service_line' ||
|
|
@@ -589,6 +597,7 @@ const toSetAllLineItemsLocalDataIsUpdateAllChecked = (transaction, transactionDe
|
|
|
589
597
|
}
|
|
590
598
|
});
|
|
591
599
|
}
|
|
600
|
+
preserveLocalLines(newLineItems, transactionDetailLocalData.lineItemById, persistedLineIds);
|
|
592
601
|
const newLocalData = {
|
|
593
602
|
...transactionDetailState_1.initialSupportedTransactionDetail.transactionDetailLocalData,
|
|
594
603
|
memo: transactionDetailLocalData.memo,
|
|
@@ -608,14 +617,23 @@ const toSetAllLineItemsLocalDataIsUpdateAllChecked = (transaction, transactionDe
|
|
|
608
617
|
return newLocalData;
|
|
609
618
|
};
|
|
610
619
|
exports.toSetAllLineItemsLocalDataIsUpdateAllChecked = toSetAllLineItemsLocalDataIsUpdateAllChecked;
|
|
620
|
+
const preserveLocalLines = (target, source, persistedLineIds) => {
|
|
621
|
+
Object.keys(source).forEach((lineId) => {
|
|
622
|
+
if (!persistedLineIds.has(lineId)) {
|
|
623
|
+
target[lineId] = { ...source[lineId] };
|
|
624
|
+
}
|
|
625
|
+
});
|
|
626
|
+
};
|
|
611
627
|
const setEntityRecommendationForLineIdInLocalData = (transaction, transactionDetailLocalData, entity, recommendationLineIds, uncategorizedIncomeExpense, recommendationWithCOTByLineId) => {
|
|
612
628
|
const newLineItems = {};
|
|
613
629
|
let matchingEntityLineId = undefined;
|
|
614
630
|
const checkIfNotJEAndDeposit = (0, vendorTransaction_1.isVendorTransaction)(transaction) === true ||
|
|
615
631
|
(0, customerTransaction_1.isCustomerTransaction)(transaction) === true;
|
|
632
|
+
const persistedLineIds = new Set();
|
|
616
633
|
if (transaction.lines != null) {
|
|
617
634
|
// always preserving the order of the line items. hence iterating over this
|
|
618
635
|
transaction.lines.forEach((line) => {
|
|
636
|
+
persistedLineIds.add(line.id);
|
|
619
637
|
const lineId = line.id;
|
|
620
638
|
const oldRecord = transactionDetailLocalData.lineItemById[lineId];
|
|
621
639
|
// check if any line already has this entity
|
|
@@ -727,6 +745,7 @@ const setEntityRecommendationForLineIdInLocalData = (transaction, transactionDet
|
|
|
727
745
|
}
|
|
728
746
|
});
|
|
729
747
|
}
|
|
748
|
+
preserveLocalLines(newLineItems, transactionDetailLocalData.lineItemById, persistedLineIds);
|
|
730
749
|
// if we have found a matching entity
|
|
731
750
|
if (matchingEntityLineId != null) {
|
|
732
751
|
const matchingRecord = transactionDetailLocalData.lineItemById[matchingEntityLineId];
|
|
@@ -771,9 +790,11 @@ const setEntityRecommendationForLineIdInLocalData = (transaction, transactionDet
|
|
|
771
790
|
exports.setEntityRecommendationForLineIdInLocalData = setEntityRecommendationForLineIdInLocalData;
|
|
772
791
|
const removeEntityRecommendationForLineIdInLocalData = (transaction, transactionDetailLocalData, recommendationLineIds) => {
|
|
773
792
|
const newLineItems = {};
|
|
793
|
+
const persistedLineIds = new Set();
|
|
774
794
|
if (transaction.lines != null) {
|
|
775
795
|
// always preserving the order of the line items. hence iterating over this
|
|
776
796
|
transaction.lines.forEach((line) => {
|
|
797
|
+
persistedLineIds.add(line.id);
|
|
777
798
|
const lineId = line.id;
|
|
778
799
|
const oldRecord = transactionDetailLocalData.lineItemById[lineId];
|
|
779
800
|
// check if any line already has this entity
|
|
@@ -804,6 +825,7 @@ const removeEntityRecommendationForLineIdInLocalData = (transaction, transaction
|
|
|
804
825
|
}
|
|
805
826
|
});
|
|
806
827
|
}
|
|
828
|
+
preserveLocalLines(newLineItems, transactionDetailLocalData.lineItemById, persistedLineIds);
|
|
807
829
|
const newLocalData = {
|
|
808
830
|
...transactionDetailState_1.initialSupportedTransactionDetail.transactionDetailLocalData,
|
|
809
831
|
memo: transactionDetailLocalData.memo,
|
|
@@ -871,9 +893,11 @@ const toLineCustomerOrVendor = (entity) => {
|
|
|
871
893
|
};
|
|
872
894
|
const toSetAllLineItemsToVendor = (transaction, transactionDetailLocalData, entity) => {
|
|
873
895
|
const newLineItems = {};
|
|
896
|
+
const persistedLineIds = new Set();
|
|
874
897
|
if (transaction.lines != null) {
|
|
875
898
|
// always preserving the order of the line items. hence iterating over this
|
|
876
899
|
transaction.lines.forEach((line) => {
|
|
900
|
+
persistedLineIds.add(line.id);
|
|
877
901
|
if (line.type === 'transaction_with_account_and_class_line' ||
|
|
878
902
|
line.type === 'transaction_with_product_or_service_line' ||
|
|
879
903
|
line.type === 'journal_entry_transaction_line') {
|
|
@@ -918,6 +942,7 @@ const toSetAllLineItemsToVendor = (transaction, transactionDetailLocalData, enti
|
|
|
918
942
|
}
|
|
919
943
|
});
|
|
920
944
|
}
|
|
945
|
+
preserveLocalLines(newLineItems, transactionDetailLocalData.lineItemById, persistedLineIds);
|
|
921
946
|
const newLocalData = {
|
|
922
947
|
...transactionDetailLocalData,
|
|
923
948
|
lineItemById: newLineItems,
|
|
@@ -929,9 +954,11 @@ exports.toSetAllLineItemsToVendor = toSetAllLineItemsToVendor;
|
|
|
929
954
|
const toUpdateLineItemsToOriginalVendor = (transaction, transactionDetailLocalData, lineIdToRetainVendorSelection) => {
|
|
930
955
|
const newLineItems = {};
|
|
931
956
|
const transactionWithCOT = (0, transactionHelper_1.getTransactionWithCOT)(transaction);
|
|
957
|
+
const persistedLineIds = new Set();
|
|
932
958
|
if (transaction.lines != null) {
|
|
933
959
|
// always preserving the order of the line items. hence iterating over this
|
|
934
960
|
transaction.lines.forEach((line) => {
|
|
961
|
+
persistedLineIds.add(line.id);
|
|
935
962
|
if (line.type === 'transaction_with_account_and_class_line' ||
|
|
936
963
|
line.type === 'transaction_with_product_or_service_line' ||
|
|
937
964
|
line.type === 'journal_entry_transaction_line') {
|
|
@@ -1032,6 +1059,7 @@ const toUpdateLineItemsToOriginalVendor = (transaction, transactionDetailLocalDa
|
|
|
1032
1059
|
}
|
|
1033
1060
|
});
|
|
1034
1061
|
}
|
|
1062
|
+
preserveLocalLines(newLineItems, transactionDetailLocalData.lineItemById, persistedLineIds);
|
|
1035
1063
|
const newLocalData = {
|
|
1036
1064
|
...transactionDetailState_1.initialSupportedTransactionDetail.transactionDetailLocalData,
|
|
1037
1065
|
memo: transactionDetailLocalData.memo,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zeniai/client-epic-state",
|
|
3
|
-
"version": "5.1.
|
|
3
|
+
"version": "5.1.57-betaDI0",
|
|
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",
|