@zeniai/client-epic-state 5.2.49 → 5.2.50-betaAK0

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 (54) hide show
  1. package/lib/esm/view/invoicing/editInvoicingCatalogItemDetailView/editInvoicingCatalogItemDetailViewReducer.js +22 -11
  2. package/lib/esm/view/invoicing/editInvoicingCatalogItemDetailView/editInvoicingCatalogItemDetailViewSelector.js +4 -1
  3. package/lib/esm/view/invoicing/editInvoicingCatalogItemDetailView/saveInvoicingCatalogItemEpic.js +3 -2
  4. package/lib/esm/view/invoicing/editInvoicingCatalogItemDetailView/seedInvoicingCatalogItemFormDraftEpic.js +30 -7
  5. package/lib/esm/view/invoicing/editInvoicingCouponDetailView/editInvoicingCouponDetailViewReducer.js +22 -11
  6. package/lib/esm/view/invoicing/editInvoicingCouponDetailView/editInvoicingCouponDetailViewSelector.js +3 -1
  7. package/lib/esm/view/invoicing/editInvoicingCouponDetailView/saveInvoicingCouponEpic.js +1 -1
  8. package/lib/esm/view/invoicing/editInvoicingCouponDetailView/seedInvoicingCouponFormDraftEpic.js +29 -6
  9. package/lib/esm/view/invoicing/editInvoicingCustomerDetailView/editInvoicingCustomerDetailViewReducer.js +22 -11
  10. package/lib/esm/view/invoicing/editInvoicingCustomerDetailView/editInvoicingCustomerDetailViewSelector.js +4 -2
  11. package/lib/esm/view/invoicing/editInvoicingCustomerDetailView/saveInvoicingCustomerEpic.js +1 -1
  12. package/lib/esm/view/invoicing/editInvoicingCustomerDetailView/seedInvoicingCustomerFormDraftEpic.js +29 -6
  13. package/lib/esm/view/invoicing/editInvoicingSubscriptionDetailView/editInvoicingSubscriptionDetailViewReducer.js +24 -13
  14. package/lib/esm/view/invoicing/editInvoicingSubscriptionDetailView/editInvoicingSubscriptionDetailViewSelector.js +3 -2
  15. package/lib/esm/view/invoicing/editInvoicingSubscriptionDetailView/fetchInvoicingSubscriptionFormPageEpic.js +4 -1
  16. package/lib/esm/view/invoicing/editInvoicingSubscriptionDetailView/saveInvoicingSubscriptionEpic.js +1 -1
  17. package/lib/esm/view/invoicing/editInvoicingSubscriptionDetailView/seedInvoicingSubscriptionFormDraftEpic.js +29 -8
  18. package/lib/esm/view/invoicing/invoicingFormDraft.js +78 -0
  19. package/lib/view/invoicing/editInvoicingCatalogItemDetailView/editInvoicingCatalogItemDetailViewReducer.d.ts +3 -1
  20. package/lib/view/invoicing/editInvoicingCatalogItemDetailView/editInvoicingCatalogItemDetailViewReducer.js +22 -11
  21. package/lib/view/invoicing/editInvoicingCatalogItemDetailView/editInvoicingCatalogItemDetailViewSelector.d.ts +10 -0
  22. package/lib/view/invoicing/editInvoicingCatalogItemDetailView/editInvoicingCatalogItemDetailViewSelector.js +4 -1
  23. package/lib/view/invoicing/editInvoicingCatalogItemDetailView/editInvoicingCatalogItemDetailViewState.d.ts +2 -1
  24. package/lib/view/invoicing/editInvoicingCatalogItemDetailView/saveInvoicingCatalogItemEpic.js +3 -2
  25. package/lib/view/invoicing/editInvoicingCatalogItemDetailView/seedInvoicingCatalogItemFormDraftEpic.d.ts +10 -6
  26. package/lib/view/invoicing/editInvoicingCatalogItemDetailView/seedInvoicingCatalogItemFormDraftEpic.js +29 -6
  27. package/lib/view/invoicing/editInvoicingCouponDetailView/editInvoicingCouponDetailViewReducer.d.ts +3 -1
  28. package/lib/view/invoicing/editInvoicingCouponDetailView/editInvoicingCouponDetailViewReducer.js +22 -11
  29. package/lib/view/invoicing/editInvoicingCouponDetailView/editInvoicingCouponDetailViewSelector.d.ts +13 -0
  30. package/lib/view/invoicing/editInvoicingCouponDetailView/editInvoicingCouponDetailViewSelector.js +3 -1
  31. package/lib/view/invoicing/editInvoicingCouponDetailView/editInvoicingCouponDetailViewState.d.ts +2 -1
  32. package/lib/view/invoicing/editInvoicingCouponDetailView/saveInvoicingCouponEpic.js +1 -1
  33. package/lib/view/invoicing/editInvoicingCouponDetailView/seedInvoicingCouponFormDraftEpic.d.ts +10 -6
  34. package/lib/view/invoicing/editInvoicingCouponDetailView/seedInvoicingCouponFormDraftEpic.js +28 -5
  35. package/lib/view/invoicing/editInvoicingCustomerDetailView/editInvoicingCustomerDetailViewReducer.d.ts +3 -1
  36. package/lib/view/invoicing/editInvoicingCustomerDetailView/editInvoicingCustomerDetailViewReducer.js +22 -11
  37. package/lib/view/invoicing/editInvoicingCustomerDetailView/editInvoicingCustomerDetailViewSelector.d.ts +9 -0
  38. package/lib/view/invoicing/editInvoicingCustomerDetailView/editInvoicingCustomerDetailViewSelector.js +4 -2
  39. package/lib/view/invoicing/editInvoicingCustomerDetailView/editInvoicingCustomerDetailViewState.d.ts +2 -1
  40. package/lib/view/invoicing/editInvoicingCustomerDetailView/saveInvoicingCustomerEpic.js +1 -1
  41. package/lib/view/invoicing/editInvoicingCustomerDetailView/seedInvoicingCustomerFormDraftEpic.d.ts +10 -6
  42. package/lib/view/invoicing/editInvoicingCustomerDetailView/seedInvoicingCustomerFormDraftEpic.js +28 -5
  43. package/lib/view/invoicing/editInvoicingSubscriptionDetailView/editInvoicingSubscriptionDetailViewReducer.d.ts +3 -1
  44. package/lib/view/invoicing/editInvoicingSubscriptionDetailView/editInvoicingSubscriptionDetailViewReducer.js +24 -13
  45. package/lib/view/invoicing/editInvoicingSubscriptionDetailView/editInvoicingSubscriptionDetailViewSelector.d.ts +9 -0
  46. package/lib/view/invoicing/editInvoicingSubscriptionDetailView/editInvoicingSubscriptionDetailViewSelector.js +3 -2
  47. package/lib/view/invoicing/editInvoicingSubscriptionDetailView/editInvoicingSubscriptionDetailViewState.d.ts +2 -1
  48. package/lib/view/invoicing/editInvoicingSubscriptionDetailView/fetchInvoicingSubscriptionFormPageEpic.js +4 -1
  49. package/lib/view/invoicing/editInvoicingSubscriptionDetailView/saveInvoicingSubscriptionEpic.js +1 -1
  50. package/lib/view/invoicing/editInvoicingSubscriptionDetailView/seedInvoicingSubscriptionFormDraftEpic.d.ts +10 -6
  51. package/lib/view/invoicing/editInvoicingSubscriptionDetailView/seedInvoicingSubscriptionFormDraftEpic.js +28 -7
  52. package/lib/view/invoicing/invoicingFormDraft.d.ts +63 -0
  53. package/lib/view/invoicing/invoicingFormDraft.js +86 -0
  54. package/package.json +1 -1
@@ -1,17 +1,38 @@
1
1
  import { EMPTY, of } from 'rxjs';
2
2
  import { filter, mergeMap, withLatestFrom } from 'rxjs/operators';
3
- import { seedInvoicingSubscriptionFormDraft, updateInvoicingSubscriptionDetail, } from './editInvoicingSubscriptionDetailViewReducer';
3
+ import { fetchInvoicingSubscriptionFormPage, seedInvoicingSubscriptionFormDraft, updateInvoicingSubscriptionDetail, } from './editInvoicingSubscriptionDetailViewReducer';
4
4
  import { getInvoicingSubscriptionById } from './invoicingSubscriptionDetailHelper';
5
5
  import { entityToInvoicingSubscriptionFormLocalData } from './invoicingSubscriptionFormConfig';
6
6
  /**
7
- * Seeds the edit draft from the record the moment the detail fetch lands, so
8
- * the form has its values before it mounts. The reducer ignores the seed when a
9
- * draft already exists, which is what stops a background refetch from
10
- * overwriting edits in progress.
7
+ * Seeds the edit draft from the record, so the form has its values before it
8
+ * mounts. The reducer ignores a seed once the draft holds the record, which is
9
+ * what stops a background refetch from overwriting edits in progress.
10
+ *
11
+ * Opening the page counts as a trigger, not just the detail response: the page
12
+ * fetch is cache-guarded, so re-opening a form for a record already loaded this
13
+ * session issues no request at all — and a draft cleared in between (by a save
14
+ * or a cancel) would have nothing left to seed it.
11
15
  */
12
- export const seedInvoicingSubscriptionFormDraftEpic = (actions$, state$) => actions$.pipe(filter(updateInvoicingSubscriptionDetail.match), withLatestFrom(state$), mergeMap(([action, state]) => {
13
- const { id } = action.payload;
14
- const subscription = getInvoicingSubscriptionById(state, id);
16
+ export const seedInvoicingSubscriptionFormDraftEpic = (actions$, state$) => actions$.pipe(filter((action) => updateInvoicingSubscriptionDetail.match(action) ||
17
+ fetchInvoicingSubscriptionFormPage.match(action)), withLatestFrom(state$), mergeMap(([action, state]) => {
18
+ const id = updateInvoicingSubscriptionDetail.match(action)
19
+ ? action.payload.id
20
+ : action.payload.subscriptionId;
21
+ if (id == null) {
22
+ return EMPTY;
23
+ }
24
+ // The entity alone does not say the whole record is loaded — the list
25
+ // endpoints merge their own list-shaped rows into the same store. Only a
26
+ // completed detail load does, which is also exactly when the page's
27
+ // cache-guarded fetch issues no request and this is the sole seed.
28
+ if (fetchInvoicingSubscriptionFormPage.match(action) &&
29
+ state.editInvoicingSubscriptionDetailViewState.recordStateById[id]
30
+ ?.fetchState !== 'Completed') {
31
+ return EMPTY;
32
+ }
33
+ // Nothing to seed from on a cold open; the detail response triggers this
34
+ // again once it lands.
35
+ const subscription = id != null ? getInvoicingSubscriptionById(state, id) : undefined;
15
36
  if (subscription == null) {
16
37
  return EMPTY;
17
38
  }
@@ -0,0 +1,78 @@
1
+ /**
2
+ * The form's own write. Keeps the status: an edit on top of a seeded draft is
3
+ * still the record's draft, and an edit made before the record arrived must not
4
+ * pass for one.
5
+ */
6
+ export function applyInvoicingFormDraftEdit(draftById, id, localData) {
7
+ draftById[id] = {
8
+ fetchState: draftById[id]?.fetchState ?? 'Not-Started',
9
+ localData,
10
+ };
11
+ }
12
+ /**
13
+ * Fill the draft from the loaded record, once. A second seed is ignored so a
14
+ * late refetch cannot overwrite edits in progress — but a draft the form wrote
15
+ * before the record landed is replaced, since it was never the record's.
16
+ */
17
+ export function applyInvoicingFormDraftSeed(draftById, id, localData) {
18
+ if (draftById[id]?.fetchState === 'Completed') {
19
+ return;
20
+ }
21
+ draftById[id] = { fetchState: 'Completed', localData };
22
+ }
23
+ /**
24
+ * Record that the fetch failed, so the form renders instead of waiting behind a
25
+ * skeleton that will never resolve.
26
+ *
27
+ * Mirrors the seed: a draft holding the record is left alone, since a
28
+ * background refetch failing is no reason to discard it, and anything else is
29
+ * marked failed. A draft the form wrote before the record landed keeps its
30
+ * values — there is no reason to throw away what the user typed — but stops
31
+ * counting as still loading, and a later successful fetch can still seed it.
32
+ */
33
+ export function applyInvoicingFormDraftFailure(draftById, id, blankLocalData) {
34
+ const existing = draftById[id];
35
+ if (existing == null) {
36
+ draftById[id] = { fetchState: 'Error', localData: blankLocalData };
37
+ return;
38
+ }
39
+ if (existing.fetchState === 'Completed') {
40
+ return;
41
+ }
42
+ existing.fetchState = 'Error';
43
+ }
44
+ /**
45
+ * The record behind this draft was just saved and is about to be refetched.
46
+ * Keep the values on screen — dropping them would blank the form for the round
47
+ * trip, and the form remounts on the response anyway — but stop counting them
48
+ * as the loaded record's, so that response is allowed to replace them.
49
+ */
50
+ export function applyInvoicingFormDraftSaved(draftById, id) {
51
+ const existing = draftById[id];
52
+ if (existing == null) {
53
+ return;
54
+ }
55
+ existing.fetchState = 'Not-Started';
56
+ }
57
+ /** The draft's values, or the blank form when nothing is drafted yet. */
58
+ export function getInvoicingFormDraftLocalData(draftById, id, blankLocalData) {
59
+ if (id == null) {
60
+ return blankLocalData;
61
+ }
62
+ return draftById[id]?.localData ?? blankLocalData;
63
+ }
64
+ /**
65
+ * Whether the form should still be showing its skeleton — the record has
66
+ * neither reached the draft nor failed trying.
67
+ *
68
+ * Settles once and stays settled, which is what keeps a later refetch from
69
+ * swapping a form the user is typing into back for a skeleton. Create mode
70
+ * (no id) has no record to wait for.
71
+ */
72
+ export function isInvoicingFormDraftPending(draftById, id) {
73
+ if (id == null) {
74
+ return false;
75
+ }
76
+ const fetchState = draftById[id]?.fetchState;
77
+ return fetchState !== 'Completed' && fetchState !== 'Error';
78
+ }
@@ -74,6 +74,8 @@ export declare const updateInvoicingCatalogItemFormDraft: import("@reduxjs/toolk
74
74
  }, "editInvoicingCatalogItemDetailView/runInvoicingCatalogProductActionFailure">, submitInvoicingCatalogItemForm: import("@reduxjs/toolkit").ActionCreatorWithPreparedPayload<[payload: SubmitInvoicingCatalogItemFormPayload], SubmitInvoicingCatalogItemFormPayload, "editInvoicingCatalogItemDetailView/submitInvoicingCatalogItemForm", never, never>, submitInvoicingCatalogItemFormSuccess: import("@reduxjs/toolkit").ActionCreatorWithPayload<{
75
75
  itemId: ID;
76
76
  kind: InvoicingCatalogItemKind;
77
- }, "editInvoicingCatalogItemDetailView/submitInvoicingCatalogItemFormSuccess">, submitInvoicingCatalogItemFormFailure: import("@reduxjs/toolkit").ActionCreatorWithPayload<ZeniAPIStatus<Record<string, unknown>>, "editInvoicingCatalogItemDetailView/submitInvoicingCatalogItemFormFailure">, resetEditInvoicingCatalogItemDetailView: import("@reduxjs/toolkit").ActionCreatorWithoutPayload<"editInvoicingCatalogItemDetailView/resetEditInvoicingCatalogItemDetailView">;
77
+ }, "editInvoicingCatalogItemDetailView/submitInvoicingCatalogItemFormSuccess">, submitInvoicingCatalogItemFormFailure: import("@reduxjs/toolkit").ActionCreatorWithPayload<ZeniAPIStatus<Record<string, unknown>>, "editInvoicingCatalogItemDetailView/submitInvoicingCatalogItemFormFailure">, resetEditInvoicingCatalogItemDetailView: import("@reduxjs/toolkit").ActionCreatorWithOptionalPayload<{
78
+ id?: ID;
79
+ } | undefined, "editInvoicingCatalogItemDetailView/resetEditInvoicingCatalogItemDetailView">;
78
80
  declare const _default: import("redux").Reducer<EditInvoicingCatalogItemDetailViewState>;
79
81
  export default _default;
@@ -4,6 +4,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
4
4
  exports.resetEditInvoicingCatalogItemDetailView = exports.submitInvoicingCatalogItemFormFailure = exports.submitInvoicingCatalogItemFormSuccess = exports.submitInvoicingCatalogItemForm = exports.runInvoicingCatalogProductActionFailure = exports.runInvoicingCatalogProductActionSuccess = exports.runInvoicingCatalogProductAction = exports.runInvoicingCatalogPlanActionFailure = exports.runInvoicingCatalogPlanActionSuccess = exports.runInvoicingCatalogPlanAction = exports.seedInvoicingCatalogItemFormDraft = exports.updateInvoicingCatalogItemDetailFailure = exports.updateInvoicingCatalogItemDetail = exports.fetchInvoicingCatalogItemDetailPage = exports.fetchInvoicingCatalogItemDetail = exports.updateInvoicingCatalogItemFormDraft = exports.initialState = void 0;
5
5
  const toolkit_1 = require("@reduxjs/toolkit");
6
6
  const rootActions_1 = require("../../../rootActions");
7
+ const invoicingFormDraft_1 = require("../invoicingFormDraft");
7
8
  const invoicingCatalogItemFormHelper_1 = require("./invoicingCatalogItemFormHelper");
8
9
  exports.initialState = {
9
10
  fetchState: 'Not-Started',
@@ -25,7 +26,7 @@ const editInvoicingCatalogItemDetailView = (0, toolkit_1.createSlice)({
25
26
  updateInvoicingCatalogItemFormDraft(draft, action) {
26
27
  const { id, localData } = action.payload;
27
28
  if (id != null) {
28
- draft.editDraftById[id] = localData;
29
+ (0, invoicingFormDraft_1.applyInvoicingFormDraftEdit)(draft.editDraftById, id, localData);
29
30
  }
30
31
  else {
31
32
  draft.newItemDraft = localData;
@@ -46,6 +47,9 @@ const editInvoicingCatalogItemDetailView = (0, toolkit_1.createSlice)({
46
47
  draft.error = undefined;
47
48
  draft.savedItemId = action.payload.itemId;
48
49
  draft.savedKind = action.payload.kind;
50
+ // An edit is refetched on success; keep the saved values on screen until
51
+ // that lands, and let it replace them.
52
+ (0, invoicingFormDraft_1.applyInvoicingFormDraftSaved)(draft.editDraftById, action.payload.itemId);
49
53
  },
50
54
  submitInvoicingCatalogItemFormFailure(draft, action) {
51
55
  draft.fetchState = 'Error';
@@ -68,6 +72,7 @@ const editInvoicingCatalogItemDetailView = (0, toolkit_1.createSlice)({
68
72
  fetchState: 'Error',
69
73
  error: action.payload.error,
70
74
  };
75
+ (0, invoicingFormDraft_1.applyInvoicingFormDraftFailure)(draft.editDraftById, action.payload.id, invoicingCatalogItemFormHelper_1.initialInvoicingCatalogItemFormLocalData);
71
76
  },
72
77
  fetchInvoicingCatalogItemDetailPage: {
73
78
  reducer() {
@@ -83,14 +88,10 @@ const editInvoicingCatalogItemDetailView = (0, toolkit_1.createSlice)({
83
88
  };
84
89
  },
85
90
  },
86
- /**
87
- * Seed the draft from the loaded record, once. Skipped when a draft already
88
- * exists so a late-arriving refetch cannot overwrite in-progress edits.
89
- */
91
+ /** Fill the draft from the loaded record — see `applyInvoicingFormDraftSeed`. */
90
92
  seedInvoicingCatalogItemFormDraft(draft, action) {
91
- if (draft.editDraftById[action.payload.id] == null) {
92
- draft.editDraftById[action.payload.id] = action.payload.localData;
93
- }
93
+ const { id, localData } = action.payload;
94
+ (0, invoicingFormDraft_1.applyInvoicingFormDraftSeed)(draft.editDraftById, id, localData);
94
95
  },
95
96
  runInvoicingCatalogPlanAction(draft, action) {
96
97
  draft.actionStateById[action.payload.id] = {
@@ -129,13 +130,23 @@ const editInvoicingCatalogItemDetailView = (0, toolkit_1.createSlice)({
129
130
  error: action.payload.error,
130
131
  };
131
132
  },
132
- resetEditInvoicingCatalogItemDetailView(draft) {
133
+ /**
134
+ * Discard a form's draft — the catalog item's own when `id` is given,
135
+ * the create draft otherwise. Scoped to the one form on purpose: another
136
+ * catalog item's half-finished edit is not this form's to throw away.
137
+ * Clearing every draft at once is what `clearAll` is for.
138
+ */
139
+ resetEditInvoicingCatalogItemDetailView(draft, action) {
133
140
  draft.fetchState = 'Not-Started';
134
141
  draft.error = undefined;
135
142
  draft.savedItemId = undefined;
136
143
  draft.savedKind = undefined;
137
- draft.editDraftById = {};
138
- draft.newItemDraft = { ...invoicingCatalogItemFormHelper_1.initialInvoicingCatalogItemFormLocalData };
144
+ const id = action.payload?.id;
145
+ if (id == null) {
146
+ draft.newItemDraft = { ...invoicingCatalogItemFormHelper_1.initialInvoicingCatalogItemFormLocalData };
147
+ return;
148
+ }
149
+ delete draft.editDraftById[id];
139
150
  },
140
151
  },
141
152
  extraReducers: (builder) => {
@@ -44,6 +44,16 @@ export interface InvoicingCatalogItemFormView extends SelectorView {
44
44
  * Folded in here so the screen never reaches for the config view itself.
45
45
  */
46
46
  fieldHelp: InvoicingFieldHelpByCode;
47
+ /**
48
+ * True while anything the form's fields mount against is still loading: the
49
+ * accounting lists, and — until it has reached the draft — the item being
50
+ * edited. The form holds a skeleton on this rather than mount, because both
51
+ * arrive too late to be picked up: it seeds react-hook-form once, at first
52
+ * render, and the accounting fields choose between a picker and a text input
53
+ * from the lists. A later refetch does not raise this again, so a refresh
54
+ * leaves the form on screen instead of blanking it mid-edit.
55
+ */
56
+ isFormLoading: boolean;
47
57
  /**
48
58
  * True while the accounting lists are still loading, so the form can wait
49
59
  * instead of mounting pickers whose options are not there yet.
@@ -5,6 +5,7 @@ const toolkit_1 = require("@reduxjs/toolkit");
5
5
  const reduceFetchState_1 = require("../../../commonStateTypes/reduceFetchState");
6
6
  const planSelector_1 = require("../../../entity/invoicing/plan/planSelector");
7
7
  const invoicingConfigViewSelector_1 = require("../invoicingConfigView/invoicingConfigViewSelector");
8
+ const invoicingFormDraft_1 = require("../invoicingFormDraft");
8
9
  const invoicingQboViewSelector_1 = require("../invoicingQboView/invoicingQboViewSelector");
9
10
  const invoicingCatalogItemFormHelper_1 = require("./invoicingCatalogItemFormHelper");
10
11
  const getEditInvoicingCatalogItemDetailViewState = (state) => ({
@@ -58,7 +59,7 @@ const getInvoicingCatalogItemFormView = (state, id) => {
58
59
  // lands. Until then the page is showing its skeleton, so the blank shape here
59
60
  // is never rendered.
60
61
  const localData = id != null
61
- ? (editDraftById[id] ?? invoicingCatalogItemFormHelper_1.initialInvoicingCatalogItemFormLocalData)
62
+ ? (0, invoicingFormDraft_1.getInvoicingFormDraftLocalData)(editDraftById, id, invoicingCatalogItemFormHelper_1.initialInvoicingCatalogItemFormLocalData)
62
63
  : newItemDraft;
63
64
  const allApplicableItemOptions = (0, exports.getInvoicingApplicableCatalogItemOptions)(state);
64
65
  const applicableItemOptions = id != null
@@ -96,6 +97,8 @@ const getInvoicingCatalogItemFormView = (state, id) => {
96
97
  catalogProductLifecycleActionOptions,
97
98
  recordState,
98
99
  fieldHelp: (0, invoicingConfigViewSelector_1.invoicingFieldHelpForGroup)(state, 'catalog'),
100
+ isFormLoading: (0, invoicingQboViewSelector_1.isInvoicingAccountingPickerDataLoading)(state) ||
101
+ (0, invoicingFormDraft_1.isInvoicingFormDraftPending)(editDraftById, id),
99
102
  isQboPickerDataLoading: (0, invoicingQboViewSelector_1.isInvoicingAccountingPickerDataLoading)(state),
100
103
  qboAccountHierarchy: qboView?.nestedAccountHierarchy ?? [],
101
104
  qboClassHierarchy: qboView?.nestedClassHierarchy ?? [],
@@ -1,5 +1,6 @@
1
1
  import { Amount } from '../../../commonStateTypes/amount';
2
2
  import { FetchStateAndError, FetchedState, ID } from '../../../commonStateTypes/common';
3
+ import { InvoicingFormDraftById } from '../invoicingFormDraft';
3
4
  /** A single pricing tier within a price point (values kept as raw strings). */
4
5
  export interface InvoicingCatalogItemFormTier {
5
6
  endingUnit: string;
@@ -63,7 +64,7 @@ export interface EditInvoicingCatalogItemDetailViewState extends FetchedState {
63
64
  */
64
65
  actionStateById: Record<ID, FetchStateAndError>;
65
66
  /** Inline-edit drafts, keyed by catalog item id. */
66
- editDraftById: Record<ID, InvoicingCatalogItemFormLocalData>;
67
+ editDraftById: InvoicingFormDraftById<InvoicingCatalogItemFormLocalData>;
67
68
  newItemDraft: InvoicingCatalogItemFormLocalData;
68
69
  /**
69
70
  * Detail-load state per catalog item id. Keyed rather than a single slot, so
@@ -20,8 +20,9 @@ const saveInvoicingCatalogItemEpic = (actions$, state$, zeniAPI) => actions$.pip
20
20
  // class become the records the service stores. Price points ride along
21
21
  // nested, so the detail page and the create/edit form share one request.
22
22
  const viewState = state.editInvoicingCatalogItemDetailViewState;
23
- const localData = (id != null ? viewState.editDraftById[id] : viewState.newItemDraft) ??
24
- viewState.newItemDraft;
23
+ const localData = (id != null
24
+ ? viewState.editDraftById[id]?.localData
25
+ : viewState.newItemDraft) ?? viewState.newItemDraft;
25
26
  const data = (0, editInvoicingCatalogItemDetailViewPayload_1.localDataToSaveInvoicingCatalogItemPayload)(localData, id == null, accountingLookup);
26
27
  const baseUrl = `${zeniAPI.apiEndPoints.invoicingMicroServiceBaseUrl}/1.0`;
27
28
  const path = id != null
@@ -1,12 +1,16 @@
1
1
  import { ActionsObservable, StateObservable } from 'redux-observable';
2
2
  import { Observable } from 'rxjs';
3
3
  import { RootState } from '../../../rootStateTypes';
4
- import { seedInvoicingCatalogItemFormDraft, updateInvoicingCatalogItemDetail } from './editInvoicingCatalogItemDetailViewReducer';
5
- export type ActionType = ReturnType<typeof updateInvoicingCatalogItemDetail> | ReturnType<typeof seedInvoicingCatalogItemFormDraft>;
4
+ import { fetchInvoicingCatalogItemDetailPage, seedInvoicingCatalogItemFormDraft, updateInvoicingCatalogItemDetail } from './editInvoicingCatalogItemDetailViewReducer';
5
+ export type ActionType = ReturnType<typeof fetchInvoicingCatalogItemDetailPage> | ReturnType<typeof updateInvoicingCatalogItemDetail> | ReturnType<typeof seedInvoicingCatalogItemFormDraft>;
6
6
  /**
7
- * Seeds the edit draft from the record the moment the detail fetch lands, so
8
- * the form has its values before it mounts. The reducer ignores the seed when a
9
- * draft already exists, which is what stops a background refetch from
10
- * overwriting edits in progress.
7
+ * Seeds the edit draft from the record, so the form has its values before it
8
+ * mounts. The reducer ignores a seed once the draft holds the record, which is
9
+ * what stops a background refetch from overwriting edits in progress.
10
+ *
11
+ * Opening the page counts as a trigger, not just the detail response: the page
12
+ * fetch is cache-guarded, so re-opening a form for a record already loaded this
13
+ * session issues no request at all — and a draft cleared in between (by a save
14
+ * or a cancel) would have nothing left to seed it.
11
15
  */
12
16
  export declare const seedInvoicingCatalogItemFormDraftEpic: (actions$: ActionsObservable<ActionType>, state$: StateObservable<RootState>) => Observable<ActionType>;
@@ -7,13 +7,36 @@ const planSelector_1 = require("../../../entity/invoicing/plan/planSelector");
7
7
  const editInvoicingCatalogItemDetailViewReducer_1 = require("./editInvoicingCatalogItemDetailViewReducer");
8
8
  const invoicingCatalogItemFormHelper_1 = require("./invoicingCatalogItemFormHelper");
9
9
  /**
10
- * Seeds the edit draft from the record the moment the detail fetch lands, so
11
- * the form has its values before it mounts. The reducer ignores the seed when a
12
- * draft already exists, which is what stops a background refetch from
13
- * overwriting edits in progress.
10
+ * Seeds the edit draft from the record, so the form has its values before it
11
+ * mounts. The reducer ignores a seed once the draft holds the record, which is
12
+ * what stops a background refetch from overwriting edits in progress.
13
+ *
14
+ * Opening the page counts as a trigger, not just the detail response: the page
15
+ * fetch is cache-guarded, so re-opening a form for a record already loaded this
16
+ * session issues no request at all — and a draft cleared in between (by a save
17
+ * or a cancel) would have nothing left to seed it.
14
18
  */
15
- const seedInvoicingCatalogItemFormDraftEpic = (actions$, state$) => actions$.pipe((0, operators_1.filter)(editInvoicingCatalogItemDetailViewReducer_1.updateInvoicingCatalogItemDetail.match), (0, operators_1.withLatestFrom)(state$), (0, operators_1.mergeMap)(([action, state]) => {
16
- const { id } = action.payload;
19
+ const seedInvoicingCatalogItemFormDraftEpic = (actions$, state$) => actions$.pipe((0, operators_1.filter)((action) => editInvoicingCatalogItemDetailViewReducer_1.updateInvoicingCatalogItemDetail.match(action) ||
20
+ editInvoicingCatalogItemDetailViewReducer_1.fetchInvoicingCatalogItemDetailPage.match(action)), (0, operators_1.withLatestFrom)(state$), (0, operators_1.mergeMap)(([action, state]) => {
21
+ const id = action.payload.id;
22
+ if (id == null) {
23
+ return rxjs_1.EMPTY;
24
+ }
25
+ // The entity alone does not say the whole record is loaded — the list
26
+ // endpoints merge their own list-shaped rows into the same store. Only a
27
+ // completed detail load does, which is also exactly when the page's
28
+ // cache-guarded fetch issues no request and this is the sole seed.
29
+ // A forced refetch is the caller asking for fresh data: the response will
30
+ // seed, and seeding first from the entity as it stands would mark the
31
+ // draft loaded and lock that response out.
32
+ if (editInvoicingCatalogItemDetailViewReducer_1.fetchInvoicingCatalogItemDetailPage.match(action) &&
33
+ (action.payload.cacheOverride === true ||
34
+ state.editInvoicingCatalogItemDetailViewState.recordStateById[id]
35
+ ?.fetchState !== 'Completed')) {
36
+ return rxjs_1.EMPTY;
37
+ }
38
+ // Nothing to seed from on a cold open; the detail response triggers this
39
+ // again once it lands.
17
40
  const plan = (0, planSelector_1.getInvoicingPlanById)(state.invoicingPlanState, id);
18
41
  if (plan == null) {
19
42
  return rxjs_1.EMPTY;
@@ -48,6 +48,8 @@ export declare const updateInvoicingCouponFormDraft: import("@reduxjs/toolkit").
48
48
  id: ID;
49
49
  }, "editInvoicingCouponDetailView/runInvoicingDiscountActionFailure">, submitInvoicingCouponForm: import("@reduxjs/toolkit").ActionCreatorWithPreparedPayload<[payload: SubmitInvoicingCouponFormPayload], SubmitInvoicingCouponFormPayload, "editInvoicingCouponDetailView/submitInvoicingCouponForm", never, never>, saveInvoicingCoupon: import("@reduxjs/toolkit").ActionCreatorWithPreparedPayload<[payload: SaveInvoicingCouponPayload], SaveInvoicingCouponPayload, "editInvoicingCouponDetailView/saveInvoicingCoupon", never, never>, submitInvoicingCouponFormSuccess: import("@reduxjs/toolkit").ActionCreatorWithPayload<{
50
50
  couponId: ID;
51
- }, "editInvoicingCouponDetailView/submitInvoicingCouponFormSuccess">, submitInvoicingCouponFormFailure: import("@reduxjs/toolkit").ActionCreatorWithPayload<ZeniAPIStatus<Record<string, unknown>>, "editInvoicingCouponDetailView/submitInvoicingCouponFormFailure">, resetEditInvoicingCouponDetailView: import("@reduxjs/toolkit").ActionCreatorWithoutPayload<"editInvoicingCouponDetailView/resetEditInvoicingCouponDetailView">;
51
+ }, "editInvoicingCouponDetailView/submitInvoicingCouponFormSuccess">, submitInvoicingCouponFormFailure: import("@reduxjs/toolkit").ActionCreatorWithPayload<ZeniAPIStatus<Record<string, unknown>>, "editInvoicingCouponDetailView/submitInvoicingCouponFormFailure">, resetEditInvoicingCouponDetailView: import("@reduxjs/toolkit").ActionCreatorWithOptionalPayload<{
52
+ id?: ID;
53
+ } | undefined, "editInvoicingCouponDetailView/resetEditInvoicingCouponDetailView">;
52
54
  declare const _default: import("redux").Reducer<EditInvoicingCouponDetailViewState>;
53
55
  export default _default;
@@ -4,6 +4,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
4
4
  exports.resetEditInvoicingCouponDetailView = exports.submitInvoicingCouponFormFailure = exports.submitInvoicingCouponFormSuccess = exports.saveInvoicingCoupon = exports.submitInvoicingCouponForm = exports.runInvoicingDiscountActionFailure = exports.runInvoicingDiscountActionSuccess = exports.runInvoicingDiscountAction = exports.updateInvoicingCouponDetailFailure = exports.updateInvoicingCouponDetail = exports.seedInvoicingCouponFormDraft = exports.fetchInvoicingCouponDetailPage = exports.fetchInvoicingCouponDetail = exports.updateInvoicingCouponFormDraft = exports.initialState = void 0;
5
5
  const toolkit_1 = require("@reduxjs/toolkit");
6
6
  const rootActions_1 = require("../../../rootActions");
7
+ const invoicingFormDraft_1 = require("../invoicingFormDraft");
7
8
  const editInvoicingCouponDetailViewState_1 = require("./editInvoicingCouponDetailViewState");
8
9
  exports.initialState = {
9
10
  fetchState: 'Not-Started',
@@ -24,7 +25,7 @@ const editInvoicingCouponDetailView = (0, toolkit_1.createSlice)({
24
25
  updateInvoicingCouponFormDraft(draft, action) {
25
26
  const { id, localData } = action.payload;
26
27
  if (id != null) {
27
- draft.editDraftById[id] = localData;
28
+ (0, invoicingFormDraft_1.applyInvoicingFormDraftEdit)(draft.editDraftById, id, localData);
28
29
  }
29
30
  else {
30
31
  draft.newCouponDraft = localData;
@@ -54,6 +55,9 @@ const editInvoicingCouponDetailView = (0, toolkit_1.createSlice)({
54
55
  draft.fetchState = 'Completed';
55
56
  draft.error = undefined;
56
57
  draft.savedCouponId = action.payload.couponId;
58
+ // An edit is refetched on success; keep the saved values on screen until
59
+ // that lands, and let it replace them.
60
+ (0, invoicingFormDraft_1.applyInvoicingFormDraftSaved)(draft.editDraftById, action.payload.couponId);
57
61
  },
58
62
  submitInvoicingCouponFormFailure(draft, action) {
59
63
  draft.fetchState = 'Error';
@@ -89,15 +93,12 @@ const editInvoicingCouponDetailView = (0, toolkit_1.createSlice)({
89
93
  fetchState: 'Error',
90
94
  error: action.payload.status,
91
95
  };
96
+ (0, invoicingFormDraft_1.applyInvoicingFormDraftFailure)(draft.editDraftById, action.payload.id, editInvoicingCouponDetailViewState_1.initialInvoicingCouponFormLocalData);
92
97
  },
93
- /**
94
- * Seed the draft from the loaded record, once. Skipped when a draft already
95
- * exists so a late refetch cannot overwrite in-progress edits.
96
- */
98
+ /** Fill the draft from the loaded record — see `applyInvoicingFormDraftSeed`. */
97
99
  seedInvoicingCouponFormDraft(draft, action) {
98
- if (draft.editDraftById[action.payload.id] == null) {
99
- draft.editDraftById[action.payload.id] = action.payload.localData;
100
- }
100
+ const { id, localData } = action.payload;
101
+ (0, invoicingFormDraft_1.applyInvoicingFormDraftSeed)(draft.editDraftById, id, localData);
101
102
  },
102
103
  runInvoicingDiscountAction(draft, action) {
103
104
  draft.actionStateById[action.payload.id] = {
@@ -117,12 +118,22 @@ const editInvoicingCouponDetailView = (0, toolkit_1.createSlice)({
117
118
  error: action.payload.error,
118
119
  };
119
120
  },
120
- resetEditInvoicingCouponDetailView(draft) {
121
+ /**
122
+ * Discard a form's draft — the coupon's own when `id` is given,
123
+ * the create draft otherwise. Scoped to the one form on purpose: another
124
+ * coupon's half-finished edit is not this form's to throw away.
125
+ * Clearing every draft at once is what `clearAll` is for.
126
+ */
127
+ resetEditInvoicingCouponDetailView(draft, action) {
121
128
  draft.fetchState = 'Not-Started';
122
129
  draft.error = undefined;
123
130
  draft.savedCouponId = undefined;
124
- draft.editDraftById = {};
125
- draft.newCouponDraft = { ...editInvoicingCouponDetailViewState_1.initialInvoicingCouponFormLocalData };
131
+ const id = action.payload?.id;
132
+ if (id == null) {
133
+ draft.newCouponDraft = { ...editInvoicingCouponDetailViewState_1.initialInvoicingCouponFormLocalData };
134
+ return;
135
+ }
136
+ delete draft.editDraftById[id];
126
137
  },
127
138
  },
128
139
  extraReducers: (builder) => {
@@ -19,6 +19,19 @@ export interface EditInvoicingCouponDetailView extends SelectorView {
19
19
  * Folded in here so the screen never reaches for the config view itself.
20
20
  */
21
21
  fieldHelp: InvoicingFieldHelpByCode;
22
+ /**
23
+ * True while the coupon being edited is still on its way to the form. The
24
+ * form holds a skeleton on this rather than mount: it seeds react-hook-form
25
+ * once, at first render, so fields mounted against the blank draft stay blank
26
+ * and the first change writes that blankness back over the coupon. A later
27
+ * refetch does not raise this again, so a refresh leaves the form on screen
28
+ * instead of blanking it mid-edit.
29
+ *
30
+ * Narrower than `pageFetchState`, which also waits on the accounting lists:
31
+ * the discounts-account picker carries its own loading state, so the form is
32
+ * useful before the lists land.
33
+ */
34
+ isFormLoading: boolean;
22
35
  /**
23
36
  * Every request the page renders from, reduced to one state: the record and
24
37
  * the config behind its dropdowns and field help. The page holds a skeleton
@@ -5,6 +5,7 @@ const reduceFetchState_1 = require("../../../commonStateTypes/reduceFetchState")
5
5
  const couponSelector_1 = require("../../../entity/invoicing/coupon/couponSelector");
6
6
  const invoicingCommonPayload_1 = require("../../../entity/invoicing/invoicingCommonPayload");
7
7
  const invoicingConfigViewSelector_1 = require("../invoicingConfigView/invoicingConfigViewSelector");
8
+ const invoicingFormDraft_1 = require("../invoicingFormDraft");
8
9
  const invoicingQboViewSelector_1 = require("../invoicingQboView/invoicingQboViewSelector");
9
10
  const settingsViewSelector_1 = require("../settingsView/settingsViewSelector");
10
11
  const editInvoicingCouponDetailViewState_1 = require("./editInvoicingCouponDetailViewState");
@@ -44,6 +45,7 @@ const getEditInvoicingCouponDetailViewState = (state, couponId) => {
44
45
  { error: undefined, fetchState: configFetchState },
45
46
  ]),
46
47
  recordState,
48
+ isFormLoading: (0, invoicingFormDraft_1.isInvoicingFormDraftPending)(state.editInvoicingCouponDetailViewState.editDraftById, couponId),
47
49
  coupon,
48
50
  discountsAccountName: (0, invoicingQboViewSelector_1.invoicingQboAccountByQboId)(state, coupon?.discountsAccountId)?.accountName,
49
51
  savedCouponId,
@@ -74,7 +76,7 @@ const getInvoicingCouponFormView = (state, couponId) => {
74
76
  // `seedInvoicingCouponFormDraftEpic` when the detail load lands. Until then
75
77
  // the page is showing its skeleton.
76
78
  const localData = couponId != null
77
- ? (editDraftById[couponId] ?? editInvoicingCouponDetailViewState_1.initialInvoicingCouponFormLocalData)
79
+ ? (0, invoicingFormDraft_1.getInvoicingFormDraftLocalData)(editDraftById, couponId, editInvoicingCouponDetailViewState_1.initialInvoicingCouponFormLocalData)
78
80
  : newCouponDraft;
79
81
  const { billingPeriodUnitOptions, discountApplyOnOptions, discountDurationTypeOptions, discountTypeOptions, qboAccountMappingKindOptions, } = (0, invoicingConfigViewSelector_1.getInvoicingConfigView)(state);
80
82
  const isQboConnected = (0, invoicingQboViewSelector_1.isInvoicingQboConnected)(state);
@@ -2,6 +2,7 @@ import { Amount } from '../../../commonStateTypes/amount';
2
2
  import { FetchStateAndError, FetchedState, ID } from '../../../commonStateTypes/common';
3
3
  import { InvoicingCoupon } from '../../../entity/invoicing/coupon/couponState';
4
4
  import { InvoicingQboAccountMappingsPayload } from '../../../entity/invoicing/invoicingCommonPayload';
5
+ import { InvoicingFormDraftById } from '../invoicingFormDraft';
5
6
  /**
6
7
  * Draft form state for the create/edit discount-coupon form. Held in CES so the
7
8
  * form flows its data from here (mirrors the customer form pattern). Dates are
@@ -37,7 +38,7 @@ export interface InvoicingCouponFormLocalData {
37
38
  export interface EditInvoicingCouponDetailViewState extends FetchedState {
38
39
  /** Lifecycle action (archive, activate, …) fetch state per coupon id. */
39
40
  actionStateById: Record<ID, FetchStateAndError>;
40
- editDraftById: Record<ID, InvoicingCouponFormLocalData>;
41
+ editDraftById: InvoicingFormDraftById<InvoicingCouponFormLocalData>;
41
42
  newCouponDraft: InvoicingCouponFormLocalData;
42
43
  /** Detail-load state per coupon id. */
43
44
  recordStateById: Record<ID, FetchStateAndError>;
@@ -23,7 +23,7 @@ const saveInvoicingCouponEpic = (actions$, state$, zeniAPI) => actions$.pipe((0,
23
23
  const state = state$.value;
24
24
  const viewState = state.editInvoicingCouponDetailViewState;
25
25
  const draft = (id != null
26
- ? viewState.editDraftById[id]
26
+ ? viewState.editDraftById[id]?.localData
27
27
  : viewState.newCouponDraft) ?? viewState.newCouponDraft;
28
28
  // The create default is resolved here as well as in the form view,
29
29
  // so a create that never touched the picker still persists the
@@ -1,12 +1,16 @@
1
1
  import { ActionsObservable, StateObservable } from 'redux-observable';
2
2
  import { Observable } from 'rxjs';
3
3
  import { RootState } from '../../../rootStateTypes';
4
- import { seedInvoicingCouponFormDraft, updateInvoicingCouponDetail } from './editInvoicingCouponDetailViewReducer';
5
- export type ActionType = ReturnType<typeof updateInvoicingCouponDetail> | ReturnType<typeof seedInvoicingCouponFormDraft>;
4
+ import { fetchInvoicingCouponDetailPage, seedInvoicingCouponFormDraft, updateInvoicingCouponDetail } from './editInvoicingCouponDetailViewReducer';
5
+ export type ActionType = ReturnType<typeof fetchInvoicingCouponDetailPage> | ReturnType<typeof updateInvoicingCouponDetail> | ReturnType<typeof seedInvoicingCouponFormDraft>;
6
6
  /**
7
- * Seeds the edit draft from the record the moment the detail fetch lands, so
8
- * the form has its values before it mounts. The reducer ignores the seed when a
9
- * draft already exists, which is what stops a background refetch from
10
- * overwriting edits in progress.
7
+ * Seeds the edit draft from the record, so the form has its values before it
8
+ * mounts. The reducer ignores a seed once the draft holds the record, which is
9
+ * what stops a background refetch from overwriting edits in progress.
10
+ *
11
+ * Opening the page counts as a trigger, not just the detail response: the page
12
+ * fetch is cache-guarded, so re-opening a form for a record already loaded this
13
+ * session issues no request at all — and a draft cleared in between (by a save
14
+ * or a cancel) would have nothing left to seed it.
11
15
  */
12
16
  export declare const seedInvoicingCouponFormDraftEpic: (actions$: ActionsObservable<ActionType>, state$: StateObservable<RootState>) => Observable<ActionType>;
@@ -7,13 +7,36 @@ const couponSelector_1 = require("../../../entity/invoicing/coupon/couponSelecto
7
7
  const editInvoicingCouponDetailViewReducer_1 = require("./editInvoicingCouponDetailViewReducer");
8
8
  const editInvoicingCouponDetailViewState_1 = require("./editInvoicingCouponDetailViewState");
9
9
  /**
10
- * Seeds the edit draft from the record the moment the detail fetch lands, so
11
- * the form has its values before it mounts. The reducer ignores the seed when a
12
- * draft already exists, which is what stops a background refetch from
13
- * overwriting edits in progress.
10
+ * Seeds the edit draft from the record, so the form has its values before it
11
+ * mounts. The reducer ignores a seed once the draft holds the record, which is
12
+ * what stops a background refetch from overwriting edits in progress.
13
+ *
14
+ * Opening the page counts as a trigger, not just the detail response: the page
15
+ * fetch is cache-guarded, so re-opening a form for a record already loaded this
16
+ * session issues no request at all — and a draft cleared in between (by a save
17
+ * or a cancel) would have nothing left to seed it.
14
18
  */
15
- const seedInvoicingCouponFormDraftEpic = (actions$, state$) => actions$.pipe((0, operators_1.filter)(editInvoicingCouponDetailViewReducer_1.updateInvoicingCouponDetail.match), (0, operators_1.withLatestFrom)(state$), (0, operators_1.mergeMap)(([action, state]) => {
19
+ const seedInvoicingCouponFormDraftEpic = (actions$, state$) => actions$.pipe((0, operators_1.filter)((action) => editInvoicingCouponDetailViewReducer_1.updateInvoicingCouponDetail.match(action) ||
20
+ editInvoicingCouponDetailViewReducer_1.fetchInvoicingCouponDetailPage.match(action)), (0, operators_1.withLatestFrom)(state$), (0, operators_1.mergeMap)(([action, state]) => {
16
21
  const { id } = action.payload;
22
+ if (id == null) {
23
+ return rxjs_1.EMPTY;
24
+ }
25
+ // The entity alone does not say the whole record is loaded — the list
26
+ // endpoints merge their own list-shaped rows into the same store. Only a
27
+ // completed detail load does, which is also exactly when the page's
28
+ // cache-guarded fetch issues no request and this is the sole seed.
29
+ // A forced refetch is the caller asking for fresh data: the response will
30
+ // seed, and seeding first from the entity as it stands would mark the
31
+ // draft loaded and lock that response out.
32
+ if (editInvoicingCouponDetailViewReducer_1.fetchInvoicingCouponDetailPage.match(action) &&
33
+ (action.payload.cacheOverride === true ||
34
+ state.editInvoicingCouponDetailViewState.recordStateById[id]
35
+ ?.fetchState !== 'Completed')) {
36
+ return rxjs_1.EMPTY;
37
+ }
38
+ // Nothing to seed from on a cold open; the detail response triggers this
39
+ // again once it lands.
17
40
  const coupon = (0, couponSelector_1.getInvoicingCouponById)(state.invoicingCouponState, id);
18
41
  if (coupon == null) {
19
42
  return rxjs_1.EMPTY;
@@ -54,6 +54,8 @@ export declare const fetchInvoicingPaymentLinkEmailPreview: import("@reduxjs/too
54
54
  status: ZeniAPIStatus;
55
55
  }, "editInvoicingCustomerDetailView/updateInvoicingCustomerDetailFailure">, updateInvoicingCustomerFormDraft: import("@reduxjs/toolkit").ActionCreatorWithPayload<UpdateInvoicingCustomerFormDraftPayload, "editInvoicingCustomerDetailView/updateInvoicingCustomerFormDraft">, submitInvoicingCustomerForm: import("@reduxjs/toolkit").ActionCreatorWithPreparedPayload<[payload: SubmitInvoicingCustomerFormPayload], SubmitInvoicingCustomerFormPayload, "editInvoicingCustomerDetailView/submitInvoicingCustomerForm", never, never>, submitInvoicingCustomerFormSuccess: import("@reduxjs/toolkit").ActionCreatorWithPayload<{
56
56
  customerId: ID;
57
- }, "editInvoicingCustomerDetailView/submitInvoicingCustomerFormSuccess">, submitInvoicingCustomerFormFailure: import("@reduxjs/toolkit").ActionCreatorWithPayload<ZeniAPIStatus<Record<string, unknown>>, "editInvoicingCustomerDetailView/submitInvoicingCustomerFormFailure">, resetEditInvoicingCustomerDetailView: import("@reduxjs/toolkit").ActionCreatorWithoutPayload<"editInvoicingCustomerDetailView/resetEditInvoicingCustomerDetailView">, initializeInvoicingCustomerAddress: import("@reduxjs/toolkit").ActionCreatorWithPreparedPayload<[payload: InitializeInvoicingCustomerAddressPayload], InitializeInvoicingCustomerAddressPayload, "editInvoicingCustomerDetailView/initializeInvoicingCustomerAddress", never, never>;
57
+ }, "editInvoicingCustomerDetailView/submitInvoicingCustomerFormSuccess">, submitInvoicingCustomerFormFailure: import("@reduxjs/toolkit").ActionCreatorWithPayload<ZeniAPIStatus<Record<string, unknown>>, "editInvoicingCustomerDetailView/submitInvoicingCustomerFormFailure">, resetEditInvoicingCustomerDetailView: import("@reduxjs/toolkit").ActionCreatorWithOptionalPayload<{
58
+ id?: ID;
59
+ } | undefined, "editInvoicingCustomerDetailView/resetEditInvoicingCustomerDetailView">, initializeInvoicingCustomerAddress: import("@reduxjs/toolkit").ActionCreatorWithPreparedPayload<[payload: InitializeInvoicingCustomerAddressPayload], InitializeInvoicingCustomerAddressPayload, "editInvoicingCustomerDetailView/initializeInvoicingCustomerAddress", never, never>;
58
60
  declare const _default: import("redux").Reducer<EditInvoicingCustomerDetailViewState>;
59
61
  export default _default;