@zeniai/client-epic-state 5.1.91 → 5.1.92-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.
- package/lib/entity/snackbar/snackbarApiError.d.ts +8 -0
- package/lib/entity/snackbar/snackbarApiError.js +15 -0
- package/lib/epic.d.ts +2 -1
- package/lib/epic.js +2 -1
- package/lib/esm/entity/snackbar/snackbarApiError.js +11 -0
- package/lib/esm/epic.js +2 -1
- package/lib/esm/index.js +3 -3
- package/lib/esm/view/invoicing/createCreditNote/createCreditNoteEpic.js +2 -0
- package/lib/esm/view/invoicing/createInvoice/createInvoiceEpic.js +2 -0
- package/lib/esm/view/invoicing/discountAction/discountActionEpic.js +6 -3
- package/lib/esm/view/invoicing/dunningAction/dunningActionEpic.js +6 -3
- package/lib/esm/view/invoicing/editInvoicingCatalogItemDetailView/editInvoicingCatalogItemDetailViewPayload.js +5 -4
- package/lib/esm/view/invoicing/editInvoicingCatalogItemDetailView/saveInvoicingCatalogItemEpic.js +3 -0
- package/lib/esm/view/invoicing/editInvoicingCouponDetailView/saveInvoicingCouponEpic.js +2 -0
- package/lib/esm/view/invoicing/editInvoicingCustomerDetailView/saveInvoicingCustomerEpic.js +2 -0
- package/lib/esm/view/invoicing/editInvoicingSubscriptionDetailView/saveInvoicingSubscriptionEpic.js +2 -0
- package/lib/esm/view/invoicing/invoiceAction/invoiceActionEpic.js +7 -3
- package/lib/esm/view/invoicing/invoicingQboView/epics/retryInvoicingQboSyncTaskEpic.js +2 -0
- package/lib/esm/view/invoicing/invoicingQboView/epics/startInvoicingQboBackfillEpic.js +2 -0
- package/lib/esm/view/invoicing/issueCreditNote/issueCreditNoteEpic.js +2 -0
- package/lib/esm/view/invoicing/recordPayment/recordPaymentEpic.js +3 -0
- package/lib/esm/view/invoicing/settingsView/settingsViewEpics.js +6 -3
- package/lib/esm/view/invoicing/settingsView/settingsViewSelector.js +52 -0
- package/lib/esm/view/invoicing/subscriptionAction/subscriptionActionEpic.js +6 -3
- package/lib/esm/view/recommendation/recommendationReducer.js +17 -1
- package/lib/esm/view/recommendation/submitRecommendationFeedbackEpic.js +52 -0
- package/lib/esm/view/vendorTabView/vendorTabViewReducer.js +1 -1
- package/lib/index.d.ts +5 -5
- package/lib/index.js +26 -24
- package/lib/view/invoicing/createCreditNote/createCreditNoteEpic.js +2 -0
- package/lib/view/invoicing/createInvoice/createInvoiceEpic.js +2 -0
- package/lib/view/invoicing/discountAction/discountActionEpic.js +5 -2
- package/lib/view/invoicing/dunningAction/dunningActionEpic.js +5 -2
- package/lib/view/invoicing/editInvoicingCatalogItemDetailView/editInvoicingCatalogItemDetailViewPayload.js +5 -4
- package/lib/view/invoicing/editInvoicingCatalogItemDetailView/saveInvoicingCatalogItemEpic.js +3 -0
- package/lib/view/invoicing/editInvoicingCouponDetailView/saveInvoicingCouponEpic.js +2 -0
- package/lib/view/invoicing/editInvoicingCustomerDetailView/saveInvoicingCustomerEpic.js +2 -0
- package/lib/view/invoicing/editInvoicingSubscriptionDetailView/saveInvoicingSubscriptionEpic.js +2 -0
- package/lib/view/invoicing/invoiceAction/invoiceActionEpic.js +6 -2
- package/lib/view/invoicing/invoicingQboView/epics/retryInvoicingQboSyncTaskEpic.js +2 -0
- package/lib/view/invoicing/invoicingQboView/epics/startInvoicingQboBackfillEpic.js +2 -0
- package/lib/view/invoicing/issueCreditNote/issueCreditNoteEpic.js +2 -0
- package/lib/view/invoicing/recordPayment/recordPaymentEpic.js +3 -0
- package/lib/view/invoicing/settingsView/settingsViewEpics.js +5 -2
- package/lib/view/invoicing/settingsView/settingsViewSelector.d.ts +41 -1
- package/lib/view/invoicing/settingsView/settingsViewSelector.js +55 -1
- package/lib/view/invoicing/subscriptionAction/subscriptionActionEpic.js +5 -2
- package/lib/view/recommendation/recommendationPayload.d.ts +34 -0
- package/lib/view/recommendation/recommendationReducer.d.ts +2 -1
- package/lib/view/recommendation/recommendationReducer.js +18 -2
- package/lib/view/recommendation/submitRecommendationFeedbackEpic.d.ts +7 -0
- package/lib/view/recommendation/submitRecommendationFeedbackEpic.js +56 -0
- package/package.json +1 -1
|
@@ -4,6 +4,7 @@ exports.saveInvoicingSettingsEpic = exports.disconnectInvoicingStripeEpic = expo
|
|
|
4
4
|
const rxjs_1 = require("rxjs");
|
|
5
5
|
const operators_1 = require("rxjs/operators");
|
|
6
6
|
const addressReducer_1 = require("../../../entity/address/addressReducer");
|
|
7
|
+
const snackbarApiError_1 = require("../../../entity/snackbar/snackbarApiError");
|
|
7
8
|
const snackbarReducer_1 = require("../../../entity/snackbar/snackbarReducer");
|
|
8
9
|
const responsePayload_1 = require("../../../responsePayload");
|
|
9
10
|
const settingsViewReducer_1 = require("./settingsViewReducer");
|
|
@@ -65,13 +66,15 @@ exports.disconnectInvoicingStripeEpic = disconnectInvoicingStripeEpic;
|
|
|
65
66
|
const saveInvoicingSettingsEpic = (actions$, _state$, zeniAPI) => actions$.pipe((0, operators_1.filter)(settingsViewReducer_1.saveInvoicingSettings.match), (0, operators_1.mergeMap)((action) => {
|
|
66
67
|
const apiUrl = `${zeniAPI.apiEndPoints.invoicingMicroServiceBaseUrl}/1.0/settings`;
|
|
67
68
|
const { settings, snackbarSection } = action.payload;
|
|
68
|
-
|
|
69
|
+
/** `status` surfaces the platform's error text; omit it to keep the generic copy. */
|
|
70
|
+
const snackbar = (messageText, status) => snackbarSection == null
|
|
69
71
|
? []
|
|
70
72
|
: [
|
|
71
73
|
(0, snackbarReducer_1.openSnackbar)({
|
|
72
74
|
messageSection: snackbarSection,
|
|
73
75
|
messageText,
|
|
74
76
|
type: messageText === 'success' ? 'success' : 'error',
|
|
77
|
+
variables: (0, snackbarApiError_1.apiErrorSnackbarVariables)(status),
|
|
75
78
|
}),
|
|
76
79
|
];
|
|
77
80
|
return zeniAPI
|
|
@@ -85,7 +88,7 @@ const saveInvoicingSettingsEpic = (actions$, _state$, zeniAPI) => actions$.pipe(
|
|
|
85
88
|
}
|
|
86
89
|
return (0, rxjs_1.from)([
|
|
87
90
|
(0, settingsViewReducer_1.saveInvoicingSettingsFailure)(response.status),
|
|
88
|
-
...snackbar('failed'),
|
|
91
|
+
...snackbar('failed', response.status),
|
|
89
92
|
]);
|
|
90
93
|
}), (0, operators_1.catchError)((error) => (0, rxjs_1.from)([
|
|
91
94
|
(0, settingsViewReducer_1.saveInvoicingSettingsFailure)((0, responsePayload_1.createZeniAPIStatus)('Unexpected Error', 'Save settings REST API call errored out ' +
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { FetchState, FetchStateAndError } from '../../../commonStateTypes/common';
|
|
2
|
-
import { InvoicingNamedOption, InvoicingSettingsPayload } from '../../../entity/invoicing/invoicingCommonPayload';
|
|
2
|
+
import { InvoicingNamedOption, InvoicingQboAccountMappingKindOption, InvoicingSettingsPayload } from '../../../entity/invoicing/invoicingCommonPayload';
|
|
3
3
|
import { RootState } from '../../../reducer';
|
|
4
4
|
import { ZeniAPIStatus } from '../../../responsePayload';
|
|
5
|
+
import { InvoicingOnboardingStatus } from '../invoicingConfigView/invoicingConfigViewPayload';
|
|
5
6
|
import { InvoicingBrandingFormLocalData } from './invoicingBrandingFormConfig';
|
|
6
7
|
/**
|
|
7
8
|
* Shared primitive: the raw invoicing settings. Consumed internally by other
|
|
@@ -27,6 +28,45 @@ export interface InvoicingSettingsView {
|
|
|
27
28
|
* Stripe-connect fetch state.
|
|
28
29
|
*/
|
|
29
30
|
export declare const getInvoicingSettingsView: (state: RootState) => InvoicingSettingsView;
|
|
31
|
+
export interface InvoicingEnablePrerequisites {
|
|
32
|
+
canEnable: boolean;
|
|
33
|
+
isQboConfigured: boolean;
|
|
34
|
+
isStripeConnected: boolean;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Gates the Enable Invoicing action: payments must be able to land (Stripe
|
|
38
|
+
* connected *and* accepting charges) and the QBO accounting step must be
|
|
39
|
+
* finished, so an enabled tenant can always book what it invoices.
|
|
40
|
+
*
|
|
41
|
+
* Deliberately not part of `deriveInvoicingOnboardingStatus`, which routes the
|
|
42
|
+
* module off the config flags alone. Folding these in there would (a) demote a
|
|
43
|
+
* live tenant to the settings tree the moment an integration broke, stranding
|
|
44
|
+
* its existing invoices, and (b) deadlock the route gate, which fetches only the
|
|
45
|
+
* config — never the settings or QBO connection these read.
|
|
46
|
+
*/
|
|
47
|
+
export declare function deriveInvoicingEnablePrerequisites(settings: InvoicingSettingsPayload | undefined, isQboConnected: boolean, qboAccountMappingKindOptions: InvoicingQboAccountMappingKindOption[]): InvoicingEnablePrerequisites;
|
|
48
|
+
export interface InvoicingSettingsHubView {
|
|
49
|
+
canEnableInvoicing: boolean;
|
|
50
|
+
isEnablingInvoicing: boolean;
|
|
51
|
+
isQboConfigured: boolean;
|
|
52
|
+
isStripeConnected: boolean;
|
|
53
|
+
status?: InvoicingOnboardingStatus;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* The settings hub's composite of everything it derives from the store: whether
|
|
57
|
+
* to offer Enable Invoicing at all, the in-flight flag for that action, and the
|
|
58
|
+
* two integration prerequisites kept separate so the hub can name the step still
|
|
59
|
+
* outstanding instead of showing a dead button.
|
|
60
|
+
*
|
|
61
|
+
* `canEnableInvoicing` folds in the onboarding step, so the screen does not need
|
|
62
|
+
* to re-check it: the footer is only offered mid-onboarding and only once both
|
|
63
|
+
* integrations are ready.
|
|
64
|
+
*
|
|
65
|
+
* Deliberately not folded into `getInvoicingConfigView`: that selector gates
|
|
66
|
+
* every invoicing route and stays a pure read of the config slice. The settings
|
|
67
|
+
* and QBO slices read here are only fetched once a settings screen is mounted.
|
|
68
|
+
*/
|
|
69
|
+
export declare const getInvoicingSettingsHubView: (state: RootState) => InvoicingSettingsHubView;
|
|
30
70
|
export interface InvoicingBrandingFormView {
|
|
31
71
|
dateFormatOptions: InvoicingNamedOption[];
|
|
32
72
|
localData: InvoicingBrandingFormLocalData;
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.getInvoicingBrandingFormView = exports.getInvoicingSettingsView = exports.getInvoicingSettingsFetchState = exports.getInvoicingSettings = void 0;
|
|
3
|
+
exports.getInvoicingBrandingFormView = exports.getInvoicingSettingsHubView = exports.getInvoicingSettingsView = exports.getInvoicingSettingsFetchState = exports.getInvoicingSettings = void 0;
|
|
4
|
+
exports.deriveInvoicingEnablePrerequisites = deriveInvoicingEnablePrerequisites;
|
|
5
|
+
const invoicingCommonPayload_1 = require("../../../entity/invoicing/invoicingCommonPayload");
|
|
4
6
|
const addressViewSelector_1 = require("../../addressView/addressViewSelector");
|
|
5
7
|
const invoicingConfigViewSelector_1 = require("../invoicingConfigView/invoicingConfigViewSelector");
|
|
6
8
|
const invoicingBrandingFormConfig_1 = require("./invoicingBrandingFormConfig");
|
|
@@ -36,6 +38,58 @@ const getInvoicingSettingsView = (state) => {
|
|
|
36
38
|
};
|
|
37
39
|
};
|
|
38
40
|
exports.getInvoicingSettingsView = getInvoicingSettingsView;
|
|
41
|
+
/**
|
|
42
|
+
* Gates the Enable Invoicing action: payments must be able to land (Stripe
|
|
43
|
+
* connected *and* accepting charges) and the QBO accounting step must be
|
|
44
|
+
* finished, so an enabled tenant can always book what it invoices.
|
|
45
|
+
*
|
|
46
|
+
* Deliberately not part of `deriveInvoicingOnboardingStatus`, which routes the
|
|
47
|
+
* module off the config flags alone. Folding these in there would (a) demote a
|
|
48
|
+
* live tenant to the settings tree the moment an integration broke, stranding
|
|
49
|
+
* its existing invoices, and (b) deadlock the route gate, which fetches only the
|
|
50
|
+
* config — never the settings or QBO connection these read.
|
|
51
|
+
*/
|
|
52
|
+
function deriveInvoicingEnablePrerequisites(settings, isQboConnected, qboAccountMappingKindOptions) {
|
|
53
|
+
const isStripeConnected = settings?.stripe_connected === true &&
|
|
54
|
+
settings?.stripe_account?.charges_enabled === true;
|
|
55
|
+
const accountMappings = settings?.qbo?.account_mappings ?? undefined;
|
|
56
|
+
// An empty option list means the config has not landed yet — treating that as
|
|
57
|
+
// configured would let `every` pass vacuously and unlock the button early.
|
|
58
|
+
const isQboConfigured = isQboConnected &&
|
|
59
|
+
qboAccountMappingKindOptions.length > 0 &&
|
|
60
|
+
qboAccountMappingKindOptions.every((option) => (0, invoicingCommonPayload_1.getInvoicingQboAccountMappingId)(accountMappings, option.code) != null);
|
|
61
|
+
return {
|
|
62
|
+
canEnable: isStripeConnected && isQboConfigured,
|
|
63
|
+
isQboConfigured,
|
|
64
|
+
isStripeConnected,
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* The settings hub's composite of everything it derives from the store: whether
|
|
69
|
+
* to offer Enable Invoicing at all, the in-flight flag for that action, and the
|
|
70
|
+
* two integration prerequisites kept separate so the hub can name the step still
|
|
71
|
+
* outstanding instead of showing a dead button.
|
|
72
|
+
*
|
|
73
|
+
* `canEnableInvoicing` folds in the onboarding step, so the screen does not need
|
|
74
|
+
* to re-check it: the footer is only offered mid-onboarding and only once both
|
|
75
|
+
* integrations are ready.
|
|
76
|
+
*
|
|
77
|
+
* Deliberately not folded into `getInvoicingConfigView`: that selector gates
|
|
78
|
+
* every invoicing route and stays a pure read of the config slice. The settings
|
|
79
|
+
* and QBO slices read here are only fetched once a settings screen is mounted.
|
|
80
|
+
*/
|
|
81
|
+
const getInvoicingSettingsHubView = (state) => {
|
|
82
|
+
const { enableState, qboAccountMappingKindOptions, status } = (0, invoicingConfigViewSelector_1.getInvoicingConfigView)(state);
|
|
83
|
+
const { canEnable, isQboConfigured, isStripeConnected } = deriveInvoicingEnablePrerequisites(state.invoicingSettingsViewState.settings, state.invoicingQboViewState.connection?.connected === true, qboAccountMappingKindOptions);
|
|
84
|
+
return {
|
|
85
|
+
canEnableInvoicing: status === 'settings' && canEnable,
|
|
86
|
+
isEnablingInvoicing: enableState.fetchState === 'In-Progress',
|
|
87
|
+
isQboConfigured,
|
|
88
|
+
isStripeConnected,
|
|
89
|
+
status,
|
|
90
|
+
};
|
|
91
|
+
};
|
|
92
|
+
exports.getInvoicingSettingsHubView = getInvoicingSettingsHubView;
|
|
39
93
|
/**
|
|
40
94
|
* Bundled view for the branding settings form: the draft `localData` (seeded
|
|
41
95
|
* from the existing settings until the user edits), the business-address label
|
|
@@ -6,6 +6,7 @@ const operators_1 = require("rxjs/operators");
|
|
|
6
6
|
const addressReducer_1 = require("../../../entity/address/addressReducer");
|
|
7
7
|
const invoicingSubscriptionPayload_1 = require("../../../entity/invoicing/invoicingSubscription/invoicingSubscriptionPayload");
|
|
8
8
|
const invoicingSubscriptionReducer_1 = require("../../../entity/invoicing/invoicingSubscription/invoicingSubscriptionReducer");
|
|
9
|
+
const snackbarApiError_1 = require("../../../entity/snackbar/snackbarApiError");
|
|
9
10
|
const snackbarReducer_1 = require("../../../entity/snackbar/snackbarReducer");
|
|
10
11
|
const responsePayload_1 = require("../../../responsePayload");
|
|
11
12
|
const subscriptionActionReducer_1 = require("./subscriptionActionReducer");
|
|
@@ -27,13 +28,15 @@ const runInvoicingSubscriptionActionEpic = (actions$, _state$, zeniAPI) => actio
|
|
|
27
28
|
const { action: kind, body, id } = action.payload;
|
|
28
29
|
const requestBody = { action: kind, ...(body ?? {}) };
|
|
29
30
|
const snackbarSection = SNACKBAR_SECTION_BY_ACTION[kind];
|
|
30
|
-
|
|
31
|
+
/** `status` surfaces the platform's error text; omit it to keep the generic copy. */
|
|
32
|
+
const snackbar = (messageText, status) => snackbarSection == null
|
|
31
33
|
? []
|
|
32
34
|
: [
|
|
33
35
|
(0, snackbarReducer_1.openSnackbar)({
|
|
34
36
|
messageSection: snackbarSection,
|
|
35
37
|
messageText,
|
|
36
38
|
type: messageText === 'success' ? 'success' : 'error',
|
|
39
|
+
variables: (0, snackbarApiError_1.apiErrorSnackbarVariables)(status),
|
|
37
40
|
}),
|
|
38
41
|
];
|
|
39
42
|
const apiUrl = `${zeniAPI.apiEndPoints.invoicingMicroServiceBaseUrl}/1.0/subscriptions/${encodeURIComponent(id)}/actions`;
|
|
@@ -53,7 +56,7 @@ const runInvoicingSubscriptionActionEpic = (actions$, _state$, zeniAPI) => actio
|
|
|
53
56
|
error: response.status,
|
|
54
57
|
id,
|
|
55
58
|
}),
|
|
56
|
-
...snackbar('failed'),
|
|
59
|
+
...snackbar('failed', response.status),
|
|
57
60
|
]);
|
|
58
61
|
}), (0, operators_1.catchError)((error) => (0, rxjs_1.from)([
|
|
59
62
|
(0, subscriptionActionReducer_1.runInvoicingSubscriptionActionFailure)({
|
|
@@ -12,4 +12,38 @@ interface FetchRecommendationPayloadWithCOT {
|
|
|
12
12
|
recommendations: RecommendationPayloadWithCOT[];
|
|
13
13
|
}
|
|
14
14
|
export type FetchRecommendationResponseWithCOT = ZeniAPIResponse<FetchRecommendationPayloadWithCOT>;
|
|
15
|
+
export type RecommendationFeedbackDimension = 'vendor' | 'category' | 'class';
|
|
16
|
+
export type RecommendationFeedbackSource = 'primary' | 'alternate' | 'shadow' | 'qbo';
|
|
17
|
+
export type RecommendationFeedbackOutcome = 'accepted' | 'override_ranked' | 'override_outside' | 'retracted';
|
|
18
|
+
export interface RecommendationFeedbackValue {
|
|
19
|
+
name: string;
|
|
20
|
+
id?: string | null;
|
|
21
|
+
integrationId?: string | null;
|
|
22
|
+
}
|
|
23
|
+
export interface ShownRecommendationForFeedback {
|
|
24
|
+
rank: number;
|
|
25
|
+
source: RecommendationFeedbackSource;
|
|
26
|
+
value: RecommendationFeedbackValue;
|
|
27
|
+
confidence?: number | null;
|
|
28
|
+
cot?: string[];
|
|
29
|
+
reasoning?: string | null;
|
|
30
|
+
}
|
|
31
|
+
export interface SubmitRecommendationFeedbackPayload {
|
|
32
|
+
dimension: RecommendationFeedbackDimension;
|
|
33
|
+
outcome: RecommendationFeedbackOutcome;
|
|
34
|
+
selected: RecommendationFeedbackValue & {
|
|
35
|
+
isNewEntity?: boolean;
|
|
36
|
+
};
|
|
37
|
+
transactionId: string;
|
|
38
|
+
features?: Record<string, unknown> | null;
|
|
39
|
+
lineId?: string | null;
|
|
40
|
+
matchedRank?: number | null;
|
|
41
|
+
matchedSource?: RecommendationFeedbackSource | null;
|
|
42
|
+
reasonText?: string | null;
|
|
43
|
+
recommendationSetId?: string | null;
|
|
44
|
+
retractsFeedbackId?: string | null;
|
|
45
|
+
shownRecommendations?: ShownRecommendationForFeedback[];
|
|
46
|
+
skipped?: boolean;
|
|
47
|
+
topPickSource?: RecommendationFeedbackSource | null;
|
|
48
|
+
}
|
|
15
49
|
export {};
|
|
@@ -5,6 +5,7 @@ import { TransactionID } from '../../entity/transaction/stateTypes/transaction';
|
|
|
5
5
|
import { SupportedTransaction } from '../../entity/transaction/transactionState';
|
|
6
6
|
import { ZeniAPIStatus } from '../../responsePayload';
|
|
7
7
|
import { TransactionsTab } from '../expenseAutomationView/types/transactionsViewState';
|
|
8
|
+
import { SubmitRecommendationFeedbackPayload } from './recommendationPayload';
|
|
8
9
|
import { EntityRecommendationState } from './recommendationState';
|
|
9
10
|
export type RecommendationLineUpdateFlowType = 'categorization' | 'detail';
|
|
10
11
|
type FetchEntityRecommendationsForLineUpdateCommonPayload = {
|
|
@@ -57,6 +58,6 @@ export declare const fetchEntityRecommendationsByTransactionId: import("@reduxjs
|
|
|
57
58
|
}, "recommendation/updateRecommendationForEntityFailure">, indicateReadyToInitializeRecommendation: import("@reduxjs/toolkit").ActionCreatorWithPreparedPayload<[entityIdOrName: string, entityType: EntityType], {
|
|
58
59
|
entityIdOrName: string;
|
|
59
60
|
entityType: EntityType;
|
|
60
|
-
}, "recommendation/indicateReadyToInitializeRecommendation", never, never>, clearRecommendation: import("@reduxjs/toolkit").ActionCreatorWithoutPayload<"recommendation/clearRecommendation">;
|
|
61
|
+
}, "recommendation/indicateReadyToInitializeRecommendation", never, never>, clearRecommendation: import("@reduxjs/toolkit").ActionCreatorWithoutPayload<"recommendation/clearRecommendation">, submitRecommendationFeedback: import("@reduxjs/toolkit").ActionCreatorWithPreparedPayload<[args: SubmitRecommendationFeedbackPayload], SubmitRecommendationFeedbackPayload, "recommendation/submitRecommendationFeedback", never, never>;
|
|
61
62
|
declare const _default: import("redux").Reducer<EntityRecommendationState>;
|
|
62
63
|
export default _default;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
var _a;
|
|
3
3
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
-
exports.clearRecommendation = exports.indicateReadyToInitializeRecommendation = exports.updateRecommendationForEntityFailure = exports.updateRecommendationForEntity = exports.fetchRecommendationByEntityId = exports.fetchRecommendationByEntityName = exports.fetchEntityRecommendationsForLineUpdate = exports.fetchEntityRecommendationsByTransactionId = exports.initialState = void 0;
|
|
4
|
+
exports.submitRecommendationFeedback = exports.clearRecommendation = exports.indicateReadyToInitializeRecommendation = exports.updateRecommendationForEntityFailure = exports.updateRecommendationForEntity = exports.fetchRecommendationByEntityId = exports.fetchRecommendationByEntityName = exports.fetchEntityRecommendationsForLineUpdate = exports.fetchEntityRecommendationsByTransactionId = exports.initialState = void 0;
|
|
5
5
|
const toolkit_1 = require("@reduxjs/toolkit");
|
|
6
6
|
const rootActions_1 = require("../../rootActions");
|
|
7
7
|
const recommendationState_1 = require("./recommendationState");
|
|
@@ -138,6 +138,22 @@ const recommendation = (0, toolkit_1.createSlice)({
|
|
|
138
138
|
clearRecommendation(draft) {
|
|
139
139
|
Object.assign(draft, exports.initialState);
|
|
140
140
|
},
|
|
141
|
+
// Fire-and-forget human feedback on a recommendation (accept, ranked
|
|
142
|
+
// override or outside override). Handled by submitRecommendationFeedbackEpic
|
|
143
|
+
// which POSTs to the accounting recommendation-feedback endpoint. No state
|
|
144
|
+
// mutation: the categorization UX must not depend on the feedback round-trip.
|
|
145
|
+
submitRecommendationFeedback: {
|
|
146
|
+
reducer(
|
|
147
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
148
|
+
_draft,
|
|
149
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
150
|
+
_action) {
|
|
151
|
+
// do nothing
|
|
152
|
+
},
|
|
153
|
+
prepare(args) {
|
|
154
|
+
return { payload: args };
|
|
155
|
+
},
|
|
156
|
+
},
|
|
141
157
|
},
|
|
142
158
|
extraReducers: (builder) => {
|
|
143
159
|
builder.addCase(rootActions_1.clearAll, (draft) => {
|
|
@@ -145,7 +161,7 @@ const recommendation = (0, toolkit_1.createSlice)({
|
|
|
145
161
|
});
|
|
146
162
|
},
|
|
147
163
|
});
|
|
148
|
-
_a = recommendation.actions, exports.fetchEntityRecommendationsByTransactionId = _a.fetchEntityRecommendationsByTransactionId, exports.fetchEntityRecommendationsForLineUpdate = _a.fetchEntityRecommendationsForLineUpdate, exports.fetchRecommendationByEntityName = _a.fetchRecommendationByEntityName, exports.fetchRecommendationByEntityId = _a.fetchRecommendationByEntityId, exports.updateRecommendationForEntity = _a.updateRecommendationForEntity, exports.updateRecommendationForEntityFailure = _a.updateRecommendationForEntityFailure, exports.indicateReadyToInitializeRecommendation = _a.indicateReadyToInitializeRecommendation, exports.clearRecommendation = _a.clearRecommendation;
|
|
164
|
+
_a = recommendation.actions, exports.fetchEntityRecommendationsByTransactionId = _a.fetchEntityRecommendationsByTransactionId, exports.fetchEntityRecommendationsForLineUpdate = _a.fetchEntityRecommendationsForLineUpdate, exports.fetchRecommendationByEntityName = _a.fetchRecommendationByEntityName, exports.fetchRecommendationByEntityId = _a.fetchRecommendationByEntityId, exports.updateRecommendationForEntity = _a.updateRecommendationForEntity, exports.updateRecommendationForEntityFailure = _a.updateRecommendationForEntityFailure, exports.indicateReadyToInitializeRecommendation = _a.indicateReadyToInitializeRecommendation, exports.clearRecommendation = _a.clearRecommendation, exports.submitRecommendationFeedback = _a.submitRecommendationFeedback;
|
|
149
165
|
exports.default = recommendation.reducer;
|
|
150
166
|
const doUpdateRecommendationForEntity = (draft, entityId, entityType, payload) => {
|
|
151
167
|
const key = (0, recommendationState_1.getEntityRecommendationKey)(entityType, entityId);
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { ActionsObservable, StateObservable } from 'redux-observable';
|
|
2
|
+
import { Observable } from 'rxjs';
|
|
3
|
+
import { RootState } from '../../reducer';
|
|
4
|
+
import { ZeniAPI } from '../../zeniAPI';
|
|
5
|
+
import { submitRecommendationFeedback } from './recommendationReducer';
|
|
6
|
+
export type ActionType = ReturnType<typeof submitRecommendationFeedback>;
|
|
7
|
+
export declare const submitRecommendationFeedbackEpic: (actions$: ActionsObservable<ActionType>, _state$: StateObservable<RootState>, zeniAPI: ZeniAPI) => Observable<ActionType>;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.submitRecommendationFeedbackEpic = void 0;
|
|
4
|
+
const rxjs_1 = require("rxjs");
|
|
5
|
+
const operators_1 = require("rxjs/operators");
|
|
6
|
+
const responsePayload_1 = require("../../responsePayload");
|
|
7
|
+
const recommendationReducer_1 = require("./recommendationReducer");
|
|
8
|
+
const toRequestBody = (payload) => ({
|
|
9
|
+
line_id: payload.lineId ?? null,
|
|
10
|
+
dimension: payload.dimension,
|
|
11
|
+
recommendation_set_id: payload.recommendationSetId ?? null,
|
|
12
|
+
top_pick_source: payload.topPickSource ?? null,
|
|
13
|
+
shown_recommendations: (payload.shownRecommendations ?? []).map((recommendation) => ({
|
|
14
|
+
source: recommendation.source,
|
|
15
|
+
rank: recommendation.rank,
|
|
16
|
+
value: {
|
|
17
|
+
name: recommendation.value.name,
|
|
18
|
+
id: recommendation.value.id ?? null,
|
|
19
|
+
integration_id: recommendation.value.integrationId ?? null,
|
|
20
|
+
},
|
|
21
|
+
confidence: recommendation.confidence ?? null,
|
|
22
|
+
reasoning: recommendation.reasoning ?? null,
|
|
23
|
+
cot: recommendation.cot ?? [],
|
|
24
|
+
})),
|
|
25
|
+
selected: {
|
|
26
|
+
name: payload.selected.name,
|
|
27
|
+
id: payload.selected.id ?? null,
|
|
28
|
+
integration_id: payload.selected.integrationId ?? null,
|
|
29
|
+
is_new_entity: payload.selected.isNewEntity ?? false,
|
|
30
|
+
},
|
|
31
|
+
matched_source: payload.matchedSource ?? null,
|
|
32
|
+
matched_rank: payload.matchedRank ?? null,
|
|
33
|
+
outcome: payload.outcome,
|
|
34
|
+
reason_text: payload.reasonText ?? null,
|
|
35
|
+
skipped: payload.skipped ?? false,
|
|
36
|
+
retracts_feedback_id: payload.retractsFeedbackId ?? null,
|
|
37
|
+
features: payload.features ?? null,
|
|
38
|
+
});
|
|
39
|
+
// Fire-and-forget: the epic never re-emits an action. Feedback delivery is a
|
|
40
|
+
// side-effect that must not disrupt the categorization UX, so both the
|
|
41
|
+
// success and error paths complete silently (errors are logged for debugging).
|
|
42
|
+
const submitRecommendationFeedbackEpic = (actions$, _state$, zeniAPI) => actions$.pipe((0, operators_1.filter)(recommendationReducer_1.submitRecommendationFeedback.match), (0, operators_1.mergeMap)((action) => {
|
|
43
|
+
const { transactionId } = action.payload;
|
|
44
|
+
return zeniAPI
|
|
45
|
+
.postAndGetJSON(`${zeniAPI.apiEndPoints.accountMicroServiceBaseUrl}/1.0/transactions/${transactionId}/recommendation-feedback`, toRequestBody(action.payload))
|
|
46
|
+
.pipe((0, operators_1.mergeMap)((response) => {
|
|
47
|
+
if (!(0, responsePayload_1.isSuccessStatus)(response)) {
|
|
48
|
+
console.error('submitRecommendationFeedbackEpic: recommendation feedback was not recorded', response.status);
|
|
49
|
+
}
|
|
50
|
+
return rxjs_1.EMPTY;
|
|
51
|
+
}), (0, operators_1.catchError)((error) => {
|
|
52
|
+
console.error('submitRecommendationFeedbackEpic: failed to submit recommendation feedback', error);
|
|
53
|
+
return rxjs_1.EMPTY;
|
|
54
|
+
}));
|
|
55
|
+
}));
|
|
56
|
+
exports.submitRecommendationFeedbackEpic = submitRecommendationFeedbackEpic;
|
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.92-beta0ND",
|
|
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",
|