@zeniai/client-epic-state 5.2.59-beta0ND → 5.2.60

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 (27) hide show
  1. package/lib/entity/snackbar/snackbarTypes.d.ts +1 -1
  2. package/lib/entity/snackbar/snackbarTypes.js +1 -0
  3. package/lib/esm/entity/snackbar/snackbarTypes.js +1 -0
  4. package/lib/esm/index.js +2 -1
  5. package/lib/esm/view/invoicing/editInvoicingSubscriptionDetailView/editInvoicingSubscriptionDetailViewSelector.js +106 -6
  6. package/lib/esm/view/invoicing/invoicingCatalogListView/invoicingCatalogListViewSelector.js +12 -0
  7. package/lib/esm/view/recommendation/recommendationPayload.js +3 -1
  8. package/lib/esm/view/recommendation/recommendationReducer.js +27 -7
  9. package/lib/esm/view/recommendation/recommendationSelector.js +1 -0
  10. package/lib/esm/view/recommendation/submitRecommendationFeedbackEpic.js +20 -8
  11. package/lib/index.d.ts +3 -2
  12. package/lib/index.js +26 -24
  13. package/lib/view/expenseAutomationView/helpers/transactionCategorizationLocalDataHelper.d.ts +1 -1
  14. package/lib/view/invoicing/editInvoicingSubscriptionDetailView/editInvoicingSubscriptionDetailViewSelector.d.ts +64 -13
  15. package/lib/view/invoicing/editInvoicingSubscriptionDetailView/editInvoicingSubscriptionDetailViewSelector.js +108 -7
  16. package/lib/view/invoicing/invoicingCatalogListView/invoicingCatalogListViewSelector.d.ts +10 -0
  17. package/lib/view/invoicing/invoicingCatalogListView/invoicingCatalogListViewSelector.js +12 -0
  18. package/lib/view/recommendation/recommendationPayload.d.ts +1 -0
  19. package/lib/view/recommendation/recommendationPayload.js +5 -0
  20. package/lib/view/recommendation/recommendationReducer.d.ts +7 -1
  21. package/lib/view/recommendation/recommendationReducer.js +28 -8
  22. package/lib/view/recommendation/recommendationSelector.d.ts +2 -0
  23. package/lib/view/recommendation/recommendationSelector.js +3 -1
  24. package/lib/view/recommendation/recommendationState.d.ts +2 -1
  25. package/lib/view/recommendation/submitRecommendationFeedbackEpic.d.ts +2 -2
  26. package/lib/view/recommendation/submitRecommendationFeedbackEpic.js +18 -6
  27. package/package.json +26 -1
@@ -1,4 +1,4 @@
1
- export declare const toSnackbarMessageSection: (v: string) => "common" | "transactionDetails_updatingPastTransactions" | "transactionDetails_transactionUpdated" | "cockpit_month_end_email_sent" | "cockpit_month_end_email_save" | "cockpit_month_end_email_attachment_upload" | "je_bill_link" | "je_posted" | "actual_matching_match_and_reverse" | "actual_matching_undo_reversal" | "audit_score_updated" | "people_invite_people" | "people_invite_multiple_people" | "people_delete_person" | "people_update_person" | "reimbursement_updated" | "reimbursement_deleted" | "reimbursement_cancelled_deleted" | "reimbursement_cancelled" | "reimbursement_approved" | "reimbursement_rejected" | "reimbursement_sent_for_approval" | "account_added" | "business_verification_save" | "business_verification_submit" | "business_verification_from_bills_submit" | "plaid_connection" | "unlink_deposit_account" | "reimbursement_setup" | "reimbursement_approval_create" | "reimbursement_duplicate_approval_create" | "reimbursement_approval_update" | "reimbursement_duplicate_approval_update" | "reimbursement_approval_delete" | "reimbursement_approval_reorder" | "reimbursement_create_mileage" | "reimbursement_update_mileage" | "reimbursement_accept_term" | "reimbursement_accept_employee_term" | "reimbursement_bulk_submit" | "reimbursement_bulk_processed" | "bill_pay_setup" | "zeni_accounts_setup" | "bill_pay_approval_create" | "bill_pay_duplicate_approval_create" | "bill_pay_approval_update" | "bill_pay_duplicate_approval_update" | "bill_pay_approval_delete" | "bill_pay_approval_reorder" | "bill_pay_updated" | "bill_pay_deleted" | "bill_pay_cancelled_deleted" | "bill_pay_cancelled" | "bill_pay_approved" | "real_time_approver_added" | "bill_pay_rejected" | "bill_pay_sent_for_approval" | "bill_pay_accept_term" | "bill_pay_bulk_submit" | "bill_pay_bulk_processed" | "bill_pay_refund" | "bill_pay_retry" | "bill_pay_marked_as_paid" | "zeni_account_accept_term" | "update_vendor" | "data_refresh_update" | "delete_bank_account" | "create_bank_account" | "create_bank_account_ach" | "create_bank_account_wire" | "create_bank_account_international" | "transfer_money" | "update_zeni_account_nickname" | "create_checking_account" | "deposit_check" | "create_vendor" | "onboarding_customer_view" | "onboarding_customer_view_complete" | "onboarding_customer_identity_verification_save" | "onboarding_customer_identity_verification_submit" | "onboarding_customer_business_verification_save" | "onboarding_customer_business_verification_submit" | "retry_bank_account_connection" | "dashboard_invite_sent" | "onboarding_info_saved" | "approve_original_merchant" | "approve_global_merchant" | "reject_global_merchant" | "create_global_merchant" | "fetch_global_merchant_no_recommendation" | "save_vendor_renamed" | "save_vendor_sent_for_review" | "save_vendor_marked_as_employee" | "save_vendor_marked_as_local_contractor" | "charge_card_setup" | "charge_card_accept_term" | "charge_card_receipt_upload" | "charge_card_resend_invite" | "charge_card_revoke_invite" | "card_policy_created" | "card_policy_updated" | "card_policy_deleted" | "charge_card_update_limit" | "charge_cards_update_limit" | "close_charge_card" | "lock_charge_card" | "lock_charge_card_card_user" | "lock_charge_cards" | "unlock_charge_card" | "unlock_charge_card_card_user" | "unlock_charge_cards" | "close_charge_cards" | "revoke_invite_charge_cards" | "charge_card_express_interest" | "create_schedule" | "save_schedule" | "delete_schedule" | "ignore_schedule" | "revert_schedule" | "ignore_accrual" | "revert_accrual" | "save_task_detail" | "fetch_task_detail" | "delete_task" | "archive_task" | "snooze_task" | "unsnooze_task" | "create_tag" | "delete_tag" | "update_charge_card" | "update_charge_card_name" | "update_charge_card_name_card_user" | "issue_charge_card" | "issue_charge_cards" | "notification_settings_saved" | "referral_invite_sent" | "notification_mark_as_read" | "mark_as_complete_schedule" | "cancel_journal_entry" | "settings_accounting_accounts_updated" | "create_card_setup" | "confirm_card_setup" | "add_card_payment_source" | "fetch_payment_sources" | "task_assigned_toast_notification" | "task_due_tomorrow_toast_notification" | "task_deleted_toast_notification" | "task_archived_toast_notification" | "task_overdue_toast_notification" | "task_overdue_toast_notification_creator" | "task_notification_count" | "task_activities_toast_notification" | "task_created_toast_notification" | "task_group_creation_success" | "task_group_deletion_success" | "task_group_update_success" | "primary_funding_account_updated" | "task_time_spent_validation" | "missing_receipts_attachment" | "flux_analysis_unreviewed" | "flux_analysis_reviewed" | "receipt_match" | "receipts_upload" | "receipts_bulk_match" | "billing_address_view" | "express_pay_submit" | "exclude_transaction" | "reconcile" | "save_reconcile_for_later" | "recon_transaction_categorize" | "recon_transaction_match" | "update_debit_card_pin_attempt" | "set_debit_card_pin" | "ai_cfo_create_session_and_submit" | "ai_cfo_chat_session_deleted" | "charge_card_auto_pay_enable" | "charge_card_auto_pay_disable" | "treasury_setup" | "treasury_accept_term" | "treasury_transfer_money" | "treasury_transfer_money_failed" | "auto_transfer_rule_create" | "auto_transfer_rule_update" | "auto_transfer_rule_delete" | "auto_transfer_rule_pause" | "auto_transfer_rule_resume" | "treasury_update_portfolio_allocation" | "send_email_magic_link_to_user" | "complete_profile_done" | "create_transfer_entry" | "reports_resync" | "invalid_phone_number" | "transactions_categorized_updated_failed" | "transaction_categorized_updated_failed" | "transactionsCategorized_transactionsUpdated" | "transactionsCategorized_transactionUpdated" | "transactionCategorized_transactionsUpdated" | "transactionCategorized_transactionUpdated" | "transactionsCategorized_transactionsFailed" | "transactionsCategorized_transactionFailed" | "transactionCategorized_transactionsFailed" | "transactionCategorized_transactionFailed" | "transactionsUpdated_transactionsFailed" | "transactionsUpdated_transactionFailed" | "transactionUpdated_transactionsFailed" | "transactionUpdated_transactionFailed" | "transactionsCategorized_transactionsUpdated_transactionsFailed" | "transactionsCategorized_transactionsUpdated_transactionFailed" | "transactionsCategorized_transactionUpdated_transactionsFailed" | "transactionCategorized_transactionsUpdated_transactionsFailed" | "transactionsCategorized_transactionUpdated_transactionFailed" | "transactionCategorized_transactionsUpdated_transactionFailed" | "transactionCategorized_transactionUpdated_transactionsFailed" | "transactionCategorized_transactionUpdated_transactionFailed" | "accounting_classes_enabled_update" | "accounting_projects_enabled_update" | "accounting_projects_qbo_not_enabled" | "capitalization_threshold_update" | "account_excluded_from_reconciliation" | "account_included_in_reconciliation" | "confirm_statement_mapping" | "statement_parsing_in_progress" | "statement_parsing_complete" | "ai_accountant_trigger_job" | "oauth_consent_approve" | "oauth_consent_invalid_request" | "credit_agent_update_profile" | "credit_agent_save_macro" | "credit_agent_schedule_cron" | "create_sub_task" | "qbo_connection_already_linked" | "qbo_connection_failed" | "accounting_projects_qbo_reconnect_failed" | "product_services_update" | "qbo_realm_id_update" | "invoicing_dunning_case_resolved" | "invoicing_dunning_retry" | "invoicing_dunning_cancel" | "invoicing_dunning_settings_save" | "invoicing_qbo_backfill" | "invoicing_qbo_sync_health_retry" | "invoicing_qbo_settings_save" | "invoicing_branding_save" | "invoicing_discount_archive" | "invoicing_discount_unarchive" | "invoicing_discount_delete" | "invoicing_invoice_reminder_sent" | "invoicing_invoice_regenerated" | "invoicing_invoice_voided" | "invoicing_catalog_item_saved" | "invoicing_customer_saved" | "invoicing_subscription_saved" | "invoicing_coupon_saved" | "invoicing_invoice_saved" | "invoicing_credit_note_saved" | "invoicing_payment_recorded" | "invoicing_subscription_activated" | "invoicing_subscription_cancellation_removed" | "invoicing_subscription_cancelled" | "invoicing_subscription_non_renewing" | "invoicing_subscription_paused" | "invoicing_subscription_reactivated" | "invoicing_subscription_resumed" | "invoicing_subscription_term_end_changed";
1
+ export declare const toSnackbarMessageSection: (v: string) => "common" | "recommendation_feedback" | "transactionDetails_updatingPastTransactions" | "transactionDetails_transactionUpdated" | "cockpit_month_end_email_sent" | "cockpit_month_end_email_save" | "cockpit_month_end_email_attachment_upload" | "je_bill_link" | "je_posted" | "actual_matching_match_and_reverse" | "actual_matching_undo_reversal" | "audit_score_updated" | "people_invite_people" | "people_invite_multiple_people" | "people_delete_person" | "people_update_person" | "reimbursement_updated" | "reimbursement_deleted" | "reimbursement_cancelled_deleted" | "reimbursement_cancelled" | "reimbursement_approved" | "reimbursement_rejected" | "reimbursement_sent_for_approval" | "account_added" | "business_verification_save" | "business_verification_submit" | "business_verification_from_bills_submit" | "plaid_connection" | "unlink_deposit_account" | "reimbursement_setup" | "reimbursement_approval_create" | "reimbursement_duplicate_approval_create" | "reimbursement_approval_update" | "reimbursement_duplicate_approval_update" | "reimbursement_approval_delete" | "reimbursement_approval_reorder" | "reimbursement_create_mileage" | "reimbursement_update_mileage" | "reimbursement_accept_term" | "reimbursement_accept_employee_term" | "reimbursement_bulk_submit" | "reimbursement_bulk_processed" | "bill_pay_setup" | "zeni_accounts_setup" | "bill_pay_approval_create" | "bill_pay_duplicate_approval_create" | "bill_pay_approval_update" | "bill_pay_duplicate_approval_update" | "bill_pay_approval_delete" | "bill_pay_approval_reorder" | "bill_pay_updated" | "bill_pay_deleted" | "bill_pay_cancelled_deleted" | "bill_pay_cancelled" | "bill_pay_approved" | "real_time_approver_added" | "bill_pay_rejected" | "bill_pay_sent_for_approval" | "bill_pay_accept_term" | "bill_pay_bulk_submit" | "bill_pay_bulk_processed" | "bill_pay_refund" | "bill_pay_retry" | "bill_pay_marked_as_paid" | "zeni_account_accept_term" | "update_vendor" | "data_refresh_update" | "delete_bank_account" | "create_bank_account" | "create_bank_account_ach" | "create_bank_account_wire" | "create_bank_account_international" | "transfer_money" | "update_zeni_account_nickname" | "create_checking_account" | "deposit_check" | "create_vendor" | "onboarding_customer_view" | "onboarding_customer_view_complete" | "onboarding_customer_identity_verification_save" | "onboarding_customer_identity_verification_submit" | "onboarding_customer_business_verification_save" | "onboarding_customer_business_verification_submit" | "retry_bank_account_connection" | "dashboard_invite_sent" | "onboarding_info_saved" | "approve_original_merchant" | "approve_global_merchant" | "reject_global_merchant" | "create_global_merchant" | "fetch_global_merchant_no_recommendation" | "save_vendor_renamed" | "save_vendor_sent_for_review" | "save_vendor_marked_as_employee" | "save_vendor_marked_as_local_contractor" | "charge_card_setup" | "charge_card_accept_term" | "charge_card_receipt_upload" | "charge_card_resend_invite" | "charge_card_revoke_invite" | "card_policy_created" | "card_policy_updated" | "card_policy_deleted" | "charge_card_update_limit" | "charge_cards_update_limit" | "close_charge_card" | "lock_charge_card" | "lock_charge_card_card_user" | "lock_charge_cards" | "unlock_charge_card" | "unlock_charge_card_card_user" | "unlock_charge_cards" | "close_charge_cards" | "revoke_invite_charge_cards" | "charge_card_express_interest" | "create_schedule" | "save_schedule" | "delete_schedule" | "ignore_schedule" | "revert_schedule" | "ignore_accrual" | "revert_accrual" | "save_task_detail" | "fetch_task_detail" | "delete_task" | "archive_task" | "snooze_task" | "unsnooze_task" | "create_tag" | "delete_tag" | "update_charge_card" | "update_charge_card_name" | "update_charge_card_name_card_user" | "issue_charge_card" | "issue_charge_cards" | "notification_settings_saved" | "referral_invite_sent" | "notification_mark_as_read" | "mark_as_complete_schedule" | "cancel_journal_entry" | "settings_accounting_accounts_updated" | "create_card_setup" | "confirm_card_setup" | "add_card_payment_source" | "fetch_payment_sources" | "task_assigned_toast_notification" | "task_due_tomorrow_toast_notification" | "task_deleted_toast_notification" | "task_archived_toast_notification" | "task_overdue_toast_notification" | "task_overdue_toast_notification_creator" | "task_notification_count" | "task_activities_toast_notification" | "task_created_toast_notification" | "task_group_creation_success" | "task_group_deletion_success" | "task_group_update_success" | "primary_funding_account_updated" | "task_time_spent_validation" | "missing_receipts_attachment" | "flux_analysis_unreviewed" | "flux_analysis_reviewed" | "receipt_match" | "receipts_upload" | "receipts_bulk_match" | "billing_address_view" | "express_pay_submit" | "exclude_transaction" | "reconcile" | "save_reconcile_for_later" | "recon_transaction_categorize" | "recon_transaction_match" | "update_debit_card_pin_attempt" | "set_debit_card_pin" | "ai_cfo_create_session_and_submit" | "ai_cfo_chat_session_deleted" | "charge_card_auto_pay_enable" | "charge_card_auto_pay_disable" | "treasury_setup" | "treasury_accept_term" | "treasury_transfer_money" | "treasury_transfer_money_failed" | "auto_transfer_rule_create" | "auto_transfer_rule_update" | "auto_transfer_rule_delete" | "auto_transfer_rule_pause" | "auto_transfer_rule_resume" | "treasury_update_portfolio_allocation" | "send_email_magic_link_to_user" | "complete_profile_done" | "create_transfer_entry" | "reports_resync" | "invalid_phone_number" | "transactions_categorized_updated_failed" | "transaction_categorized_updated_failed" | "transactionsCategorized_transactionsUpdated" | "transactionsCategorized_transactionUpdated" | "transactionCategorized_transactionsUpdated" | "transactionCategorized_transactionUpdated" | "transactionsCategorized_transactionsFailed" | "transactionsCategorized_transactionFailed" | "transactionCategorized_transactionsFailed" | "transactionCategorized_transactionFailed" | "transactionsUpdated_transactionsFailed" | "transactionsUpdated_transactionFailed" | "transactionUpdated_transactionsFailed" | "transactionUpdated_transactionFailed" | "transactionsCategorized_transactionsUpdated_transactionsFailed" | "transactionsCategorized_transactionsUpdated_transactionFailed" | "transactionsCategorized_transactionUpdated_transactionsFailed" | "transactionCategorized_transactionsUpdated_transactionsFailed" | "transactionsCategorized_transactionUpdated_transactionFailed" | "transactionCategorized_transactionsUpdated_transactionFailed" | "transactionCategorized_transactionUpdated_transactionsFailed" | "transactionCategorized_transactionUpdated_transactionFailed" | "accounting_classes_enabled_update" | "accounting_projects_enabled_update" | "accounting_projects_qbo_not_enabled" | "capitalization_threshold_update" | "account_excluded_from_reconciliation" | "account_included_in_reconciliation" | "confirm_statement_mapping" | "statement_parsing_in_progress" | "statement_parsing_complete" | "ai_accountant_trigger_job" | "oauth_consent_approve" | "oauth_consent_invalid_request" | "credit_agent_update_profile" | "credit_agent_save_macro" | "credit_agent_schedule_cron" | "create_sub_task" | "qbo_connection_already_linked" | "qbo_connection_failed" | "accounting_projects_qbo_reconnect_failed" | "product_services_update" | "qbo_realm_id_update" | "invoicing_dunning_case_resolved" | "invoicing_dunning_retry" | "invoicing_dunning_cancel" | "invoicing_dunning_settings_save" | "invoicing_qbo_backfill" | "invoicing_qbo_sync_health_retry" | "invoicing_qbo_settings_save" | "invoicing_branding_save" | "invoicing_discount_archive" | "invoicing_discount_unarchive" | "invoicing_discount_delete" | "invoicing_invoice_reminder_sent" | "invoicing_invoice_regenerated" | "invoicing_invoice_voided" | "invoicing_catalog_item_saved" | "invoicing_customer_saved" | "invoicing_subscription_saved" | "invoicing_coupon_saved" | "invoicing_invoice_saved" | "invoicing_credit_note_saved" | "invoicing_payment_recorded" | "invoicing_subscription_activated" | "invoicing_subscription_cancellation_removed" | "invoicing_subscription_cancelled" | "invoicing_subscription_non_renewing" | "invoicing_subscription_paused" | "invoicing_subscription_reactivated" | "invoicing_subscription_resumed" | "invoicing_subscription_term_end_changed";
2
2
  export type SnackbarMessageSections = ReturnType<typeof toSnackbarMessageSection>;
3
3
  export declare const toSnackbarMessageSectionTexts: (v: string) => "notification" | "failed" | "success";
4
4
  export type SnackbarMessageSectionTexts = ReturnType<typeof toSnackbarMessageSectionTexts>;
@@ -4,6 +4,7 @@ exports.toSnackbarMessageSectionTexts = exports.toSnackbarMessageSection = void
4
4
  const stringToUnion_1 = require("../../commonStateTypes/stringToUnion");
5
5
  const ALL_SNACKBAR_MESSAGE_SECTIONS = [
6
6
  'common',
7
+ 'recommendation_feedback',
7
8
  'transactionDetails_updatingPastTransactions',
8
9
  'transactionDetails_transactionUpdated',
9
10
  'cockpit_month_end_email_sent',
@@ -1,6 +1,7 @@
1
1
  import { stringToUnion } from '../../commonStateTypes/stringToUnion';
2
2
  const ALL_SNACKBAR_MESSAGE_SECTIONS = [
3
3
  'common',
4
+ 'recommendation_feedback',
4
5
  'transactionDetails_updatingPastTransactions',
5
6
  'transactionDetails_transactionUpdated',
6
7
  'cockpit_month_end_email_sent',
package/lib/esm/index.js CHANGED
@@ -273,6 +273,7 @@ import { getProfitAndLossProjectView } from './view/profitAndLossProjectView/pro
273
273
  import { fetchProjectList } from './view/projectList/projectListReducer';
274
274
  import { getProjectList, } from './view/projectList/projectListSelector';
275
275
  import { fetchEntityRecommendationsByTransactionId, fetchEntityRecommendationsForLineUpdate, fetchRecommendationByEntityId, fetchRecommendationByEntityName, submitRecommendationFeedback, } from './view/recommendation/recommendationReducer';
276
+ import { getRecommendationFeedbackSubmitState } from './view/recommendation/recommendationSelector';
276
277
  import { DEFAULT_REFERRER_AMOUNT, clearReferrals, fetchReferrals, fetchRewardsPlan, resendReferralInvite, saveReferralFormDataInLocalStore, sendReferralInvite, updateReferViewed, updateReferralListSortUiState, } from './view/referralView/referralReducer';
277
278
  import { getInviteFormView, getReferralListView, getRewardsPlanCard, } from './view/referralView/referralSelector';
278
279
  import { AmountStatusTypes, StatusTypes, toReferralListViewSortKeyType, } from './view/referralView/referralState';
@@ -638,7 +639,7 @@ export { getSpendManagementEffectiveListPeriod, getSelectedCompanyOfficer, showB
638
639
  export { canSendMonthEndEmailReport, shouldEnableCalendarPickerForLastReportSent, };
639
640
  export { getInternationalSubConfigCodeKey, BILL_NEW_PAYMENT_METHODS, NEW_INTERNATIONAL_METHOD_SUBTEXT, SWIFT_OUR_INTERNATIONAL_METHOD_SUBTEXT, LOCAL_CURRENCY_INTERNATIONAL_METHOD_SUBTEXT, };
640
641
  export { getVendorList, updateSortUiState, updatePageToken, updateYTDSelectionUIState, isColumnYTDSpend, isVendorsTabVisible, toVendorReportIDType, getVendorFiling1099List, fetchVendorsFiling1099Download, };
641
- export { fetchEntityRecommendationsByTransactionId, fetchEntityRecommendationsForLineUpdate, fetchRecommendationByEntityId, fetchRecommendationByEntityName, submitRecommendationFeedback, };
642
+ export { fetchEntityRecommendationsByTransactionId, fetchEntityRecommendationsForLineUpdate, fetchRecommendationByEntityId, fetchRecommendationByEntityName, getRecommendationFeedbackSubmitState, submitRecommendationFeedback, };
642
643
  export { fetchOwnerList };
643
644
  export { getZeniAccountsConfigDetail, getZeniAccountList, fetchZeniAccountList, fetchAccountList, createCheckingAccount, fetchPaymentAccountList, unlinkPaymentAccount, getDepositAccountDetail, getAllDepositAccounts, getDepositAccountDetailForPDF, fetchDepositAccount, fetchZeniAccountsConfig, updateTransferMoneyLocalData, updateTransferToLocalData, updateDepositToLocalData, transferMoney, getTransferDetail, clearTransferDetail, clearReviewTransferDetail, fetchReviewTransferDetail, fetchDepositAccountDetail, depositCheck, updateCheckDepositLocalData, clearCheckDeposit, getCheckDepositDetail, updateDepositAccount, fetchDepositAccountHistorySuccess, fetchDepositAccountHistoryFailure, fetchZeniAccStatementPage, getZeniAccStatements, };
644
645
  export { fetchDepositAccountTransactionList, getDepositAccountTransactionList, };
@@ -56,6 +56,98 @@ const isShippingAddressUnsaved = (state, id, savedShippingAddressId) => {
56
56
  pending.country === saved.country &&
57
57
  (pending.countryCode ?? '') === (saved.countryCode ?? ''));
58
58
  };
59
+ /**
60
+ * The add-ons / one-time charges a plan actually accepts.
61
+ *
62
+ * A catalog item is either `restricted` — it names the item ids it may be
63
+ * subscribed alongside in `applicableItems` — or unrestricted, in which case
64
+ * every item is fair game. Matching is on `itemID` (the catalog item the price
65
+ * row was flattened from), not the price code, because applicability is
66
+ * declared item-to-item.
67
+ *
68
+ * Fails open where the rule is unknown: no plan selected yet, a plan that is
69
+ * not `restricted`, or a `restricted` plan whose allow-list never came down all
70
+ * return the full list. The create/update endpoint rejects a disallowed item
71
+ * with a 422 regardless, so offering one too many costs a server error the user
72
+ * already gets today, where hiding one too few makes a legitimate add-on
73
+ * unreachable with nothing on screen to explain why.
74
+ *
75
+ * An allow-list that arrived *empty* is not unknown — a restricted item is
76
+ * saved with `applicable_items: []` when nothing was picked — so that narrows
77
+ * to nothing, as the server does.
78
+ *
79
+ * Lives here rather than in a screen so the create/edit form and the detail
80
+ * page's inline edit narrow their pickers by the same rule.
81
+ */
82
+ export const getInvoicingItemsAllowedForPlan = (products, plan) => {
83
+ const allowedItemIDs = plan?.applicableItems;
84
+ if (plan?.itemApplicability !== 'restricted' || allowedItemIDs == null) {
85
+ return products;
86
+ }
87
+ return products.filter((product) => product.itemID != null && allowedItemIDs.includes(product.itemID));
88
+ };
89
+ /**
90
+ * A price row can only be subscribed by its price code, so one without a code
91
+ * is not an option the form can offer.
92
+ */
93
+ const hasInvoicingPriceCode = (product) => product.priceCode != null && product.priceCode.trim() !== '';
94
+ /**
95
+ * `displayPrice` is the service-computed single-unit amount. Tiered, volume and
96
+ * stairstep price points store `price` as `0` because the money lives in their
97
+ * tiers, so `price` is only a fallback for responses predating `displayPrice`.
98
+ */
99
+ const invoicingUnitPrice = (product) => product.displayPrice ?? product.price;
100
+ const toInvoicingPlanOption = (plan) => ({
101
+ billingCycles: plan.billingCycles,
102
+ // The price point's own cadence: the backend derives billing period from the
103
+ // price point and rejects a subscription that claims a different one.
104
+ billingPeriod: plan.period,
105
+ billingPeriodUnit: plan.periodUnit,
106
+ label: plan.name ?? plan.id,
107
+ price: invoicingUnitPrice(plan),
108
+ productCode: plan.productCode,
109
+ trialPeriod: plan.trialPeriod,
110
+ trialPeriodUnit: plan.trialPeriodUnit,
111
+ value: plan.priceCode,
112
+ });
113
+ const toInvoicingCatalogItemOption = (product) => ({
114
+ // A one-time charge has no cadence, so its price is quoted flat rather than
115
+ // per period.
116
+ billingPeriodUnit: product.itemType === 'charge' ? undefined : product.periodUnit,
117
+ label: product.name ?? product.id,
118
+ price: invoicingUnitPrice(product),
119
+ productCode: product.productCode,
120
+ value: product.priceCode,
121
+ });
122
+ const toInvoicingCouponOption = (coupon) => ({
123
+ label: coupon.name ?? coupon.couponCode ?? coupon.id,
124
+ // Create/apply/remove coupon APIs resolve by coupon_code.
125
+ value: coupon.couponCode ?? coupon.id,
126
+ });
127
+ /**
128
+ * Company first, then the person's name, then the email — whichever the
129
+ * customer actually has. The id is the last resort so a record with no
130
+ * identifying field at all is still selectable rather than a blank row.
131
+ */
132
+ const invoicingCustomerDisplayName = (customer) => {
133
+ const fullName = [customer.firstName, customer.lastName]
134
+ .filter((part) => part != null && part.trim() !== '')
135
+ .join(' ')
136
+ .trim();
137
+ const company = customer.company?.trim() ?? '';
138
+ const email = customer.email?.trim() ?? '';
139
+ return company !== ''
140
+ ? company
141
+ : fullName !== ''
142
+ ? fullName
143
+ : email !== ''
144
+ ? email
145
+ : customer.id;
146
+ };
147
+ const toInvoicingCustomerOption = (customer) => ({
148
+ label: invoicingCustomerDisplayName(customer),
149
+ value: customer.id,
150
+ });
59
151
  export const getInvoicingSubscriptionFormView = (state, invoicingSubscriptionID) => {
60
152
  const { editDraftById, error, fetchState, newSubscriptionDraft, savedSubscriptionId, } = state.editInvoicingSubscriptionDetailViewState;
61
153
  const mode = invoicingSubscriptionID != null ? 'edit' : 'create';
@@ -77,8 +169,15 @@ export const getInvoicingSubscriptionFormView = (state, invoicingSubscriptionID)
77
169
  : undefined;
78
170
  const hasUnsavedShippingAddress = isShippingAddressUnsaved(state, invoicingSubscriptionID, subscription?.shippingAddressId);
79
171
  const catalogListView = getInvoicingCatalogListView(state);
80
- const planPrices = getInvoicingCatalogPrices(catalogListView.plans);
81
- const addonAndChargePrices = getInvoicingCatalogPrices(catalogListView.products);
172
+ const planPrices = getInvoicingCatalogPrices(catalogListView.plans).filter(hasInvoicingPriceCode);
173
+ // A restricted plan names the catalog items it may be sold with, so the
174
+ // pickers offer only those: subscription create rejects the rest with a 422,
175
+ // and an option that can only fail is not a choice. The applicability rides
176
+ // on the price rows already in the store, so this is a join, not a refetch.
177
+ const allowedCatalogPrices = getInvoicingItemsAllowedForPlan(getInvoicingCatalogPrices(catalogListView.products), planPrices.find((plan) => plan.priceCode === localData.planPriceCode)).filter(hasInvoicingPriceCode);
178
+ const catalogItemOptionsOfType = (itemType) => allowedCatalogPrices
179
+ .filter((product) => product.itemType === itemType)
180
+ .map(toInvoicingCatalogItemOption);
82
181
  // In create mode there is nothing to load, so the record state only applies
83
182
  // when editing an existing subscription.
84
183
  const recordState = invoicingSubscriptionID != null
@@ -100,12 +199,13 @@ export const getInvoicingSubscriptionFormView = (state, invoicingSubscriptionID)
100
199
  recordState,
101
200
  isFormLoading: isInvoicingFormDraftPending(editDraftById, invoicingSubscriptionID),
102
201
  fieldHelp: invoicingFieldHelpForGroup(state, 'subscription'),
103
- coupons: getInvoicingCouponListItems(state),
104
- customers: getInvoicingCustomerListView(state).customers,
202
+ addons: catalogItemOptionsOfType('addon'),
203
+ charges: catalogItemOptionsOfType('charge'),
204
+ coupons: getInvoicingCouponListItems(state).map(toInvoicingCouponOption),
205
+ customers: getInvoicingCustomerListView(state).customers.map(toInvoicingCustomerOption),
105
206
  localData,
106
207
  mode,
107
- plans: planPrices,
108
- products: addonAndChargePrices,
208
+ plans: planPrices.map(toInvoicingPlanOption),
109
209
  savedSubscriptionId,
110
210
  shippingAddressLabel,
111
211
  hasUnsavedShippingAddress,
@@ -2,8 +2,20 @@ import { createSelector } from '@reduxjs/toolkit';
2
2
  import { getInvoicingPlansByIds } from '../../../entity/invoicing/plan/planSelector';
3
3
  import { runningInvoicingActionId } from '../runningInvoicingActionId';
4
4
  import { INVOICING_PRODUCT_COLUMNS, } from './invoicingCatalogListViewState';
5
+ /**
6
+ * Flatten catalog items into the price rows the pickers render.
7
+ *
8
+ * The parent item's `applicableItems` / `itemApplicability` are carried onto
9
+ * every row it produces: applicability is a property of the catalog item, not
10
+ * of its price points, and a row that has lost it cannot be matched against the
11
+ * selected plan's allow-list (see `getInvoicingItemsAllowedForPlan`). Both are
12
+ * written after the spread so the item's own rule wins over any stale copy a
13
+ * price point payload may carry.
14
+ */
5
15
  export const getInvoicingCatalogPrices = (items) => items.flatMap((item) => (item.subFamilies ?? []).map((subFamily) => ({
6
16
  ...subFamily,
17
+ applicableItems: item.applicableItems,
18
+ itemApplicability: item.itemApplicability,
7
19
  itemID: item.id,
8
20
  itemType: item.type ?? item.itemType,
9
21
  name: subFamily.name,
@@ -1 +1,3 @@
1
- export {};
1
+ // Only an override opens the feedback popup. Silent accepts and retractions post
2
+ // in the background, so they must not drive the popup's loader or its toast.
3
+ export const isPromptedRecommendationFeedback = (outcome) => outcome === 'override_outside' || outcome === 'override_ranked';
@@ -1,7 +1,9 @@
1
1
  import { createSlice } from '@reduxjs/toolkit';
2
2
  import { clearAll } from '../../rootActions';
3
+ import { isPromptedRecommendationFeedback, } from './recommendationPayload';
3
4
  import { getEntityRecommendationKey, initialEntityRecommendationState, } from './recommendationState';
4
5
  export const initialState = {
6
+ feedbackSubmitState: { fetchState: 'Not-Started', error: undefined },
5
7
  recommendationByEntity: {},
6
8
  };
7
9
  const recommendation = createSlice({
@@ -131,13 +133,31 @@ const recommendation = createSlice({
131
133
  };
132
134
  },
133
135
  },
134
- // Fire-and-forget human feedback on a recommendation (accept, ranked
135
- // override or outside override). Handled by submitRecommendationFeedbackEpic
136
- // which POSTs to the accounting recommendation-feedback endpoint. No state
137
- // mutation: the categorization UX must not depend on the feedback round-trip.
136
+ // Human feedback on a recommendation (accept, ranked override or outside
137
+ // override). Handled by submitRecommendationFeedbackEpic, which POSTs to the
138
+ // accounting recommendation-feedback endpoint. The categorization itself
139
+ // never waits on this: only the feedback popup reads the submit state.
138
140
  submitRecommendationFeedback: {
139
- reducer() {
140
- // Fire-and-forget: no state mutation; the epic performs the POST.
141
+ reducer(draft, action) {
142
+ if (!isPromptedRecommendationFeedback(action.payload.outcome)) {
143
+ return;
144
+ }
145
+ draft.feedbackSubmitState = {
146
+ fetchState: 'In-Progress',
147
+ error: undefined,
148
+ };
149
+ },
150
+ prepare(args) {
151
+ return { payload: args };
152
+ },
153
+ },
154
+ submitRecommendationFeedbackCompleted: {
155
+ reducer(draft, action) {
156
+ const { succeeded, error } = action.payload;
157
+ draft.feedbackSubmitState = {
158
+ fetchState: succeeded ? 'Completed' : 'Error',
159
+ error,
160
+ };
141
161
  },
142
162
  prepare(args) {
143
163
  return { payload: args };
@@ -150,7 +170,7 @@ const recommendation = createSlice({
150
170
  });
151
171
  },
152
172
  });
153
- export const { fetchEntityRecommendationsByTransactionId, fetchEntityRecommendationsForLineUpdate, fetchRecommendationByEntityName, fetchRecommendationByEntityId, updateRecommendationForEntity, updateRecommendationForEntityFailure, indicateReadyToInitializeRecommendation, submitRecommendationFeedback, } = recommendation.actions;
173
+ export const { fetchEntityRecommendationsByTransactionId, fetchEntityRecommendationsForLineUpdate, fetchRecommendationByEntityName, fetchRecommendationByEntityId, updateRecommendationForEntity, updateRecommendationForEntityFailure, indicateReadyToInitializeRecommendation, submitRecommendationFeedback, submitRecommendationFeedbackCompleted, } = recommendation.actions;
154
174
  export default recommendation.reducer;
155
175
  const doUpdateRecommendationForEntity = (draft, entityId, entityType, payload) => {
156
176
  const key = getEntityRecommendationKey(entityType, entityId);
@@ -11,3 +11,4 @@ export const getRecommendationsForEntity = (state, entityId, entityType) => {
11
11
  recommendations,
12
12
  };
13
13
  };
14
+ export const getRecommendationFeedbackSubmitState = (state) => state.entityRecommendationState.feedbackSubmitState;
@@ -1,7 +1,8 @@
1
- import { EMPTY } from 'rxjs';
1
+ import { EMPTY, of } from 'rxjs';
2
2
  import { catchError, filter, mergeMap } from 'rxjs/operators';
3
3
  import { isSuccessStatus } from '../../responsePayload';
4
- import { submitRecommendationFeedback } from './recommendationReducer';
4
+ import { isPromptedRecommendationFeedback, } from './recommendationPayload';
5
+ import { submitRecommendationFeedback, submitRecommendationFeedbackCompleted, } from './recommendationReducer';
5
6
  const toRequestBody = (payload) => ({
6
7
  line_id: payload.lineId ?? null,
7
8
  dimension: payload.dimension,
@@ -33,20 +34,31 @@ const toRequestBody = (payload) => ({
33
34
  retracts_feedback_id: payload.retractsFeedbackId ?? null,
34
35
  features: payload.features ?? null,
35
36
  });
36
- // Fire-and-forget: the epic never re-emits an action. Feedback delivery is a
37
- // side-effect that must not disrupt the categorization UX, so both the
38
- // success and error paths complete silently (errors are logged for debugging).
37
+ // Always reports completion so the feedback popup can show a loader and tell the
38
+ // user what happened. The categorization itself still never waits on this: a
39
+ // failure is surfaced in a toast rather than blocking or reverting the change.
39
40
  export const submitRecommendationFeedbackEpic = (actions$, _state$, zeniAPI) => actions$.pipe(filter(submitRecommendationFeedback.match), mergeMap((action) => {
40
41
  const { transactionId } = action.payload;
42
+ // Only the override that opened the popup reports completion; accepts and
43
+ // retractions stay fire-and-forget so they cannot settle the popup.
44
+ const isPrompted = isPromptedRecommendationFeedback(action.payload.outcome);
41
45
  return zeniAPI
42
46
  .postAndGetJSON(`${zeniAPI.apiEndPoints.accountMicroServiceBaseUrl}/1.0/transactions/${transactionId}/recommendation-feedback`, toRequestBody(action.payload))
43
47
  .pipe(mergeMap((response) => {
44
- if (!isSuccessStatus(response)) {
48
+ const succeeded = isSuccessStatus(response);
49
+ if (!succeeded) {
45
50
  console.error('submitRecommendationFeedbackEpic: recommendation feedback was not recorded', response.status);
46
51
  }
47
- return EMPTY;
52
+ return isPrompted
53
+ ? of(submitRecommendationFeedbackCompleted({
54
+ succeeded,
55
+ error: succeeded ? undefined : response.status,
56
+ }))
57
+ : EMPTY;
48
58
  }), catchError((error) => {
49
59
  console.error('submitRecommendationFeedbackEpic: failed to submit recommendation feedback', error);
50
- return EMPTY;
60
+ return isPrompted
61
+ ? of(submitRecommendationFeedbackCompleted({ succeeded: false }))
62
+ : EMPTY;
51
63
  }));
52
64
  }));
package/lib/index.d.ts CHANGED
@@ -432,6 +432,7 @@ import { ProfitAndLossProjectViewUIState } from './view/profitAndLossProjectView
432
432
  import { fetchProjectList } from './view/projectList/projectListReducer';
433
433
  import { ProjectListSelectorView, getProjectList } from './view/projectList/projectListSelector';
434
434
  import { fetchEntityRecommendationsByTransactionId, fetchEntityRecommendationsForLineUpdate, fetchRecommendationByEntityId, fetchRecommendationByEntityName, submitRecommendationFeedback } from './view/recommendation/recommendationReducer';
435
+ import { getRecommendationFeedbackSubmitState } from './view/recommendation/recommendationSelector';
435
436
  import { DEFAULT_REFERRER_AMOUNT, clearReferrals, fetchReferrals, fetchRewardsPlan, resendReferralInvite, saveReferralFormDataInLocalStore, sendReferralInvite, updateReferViewed, updateReferralListSortUiState } from './view/referralView/referralReducer';
436
437
  import { ReferralListSelectorView, RewardsPlanCardReport, getInviteFormView, getReferralListView, getRewardsPlanCard } from './view/referralView/referralSelector';
437
438
  import { AmountStatusTypes, InviteCompanyLocalData, ReferralAmountStatus, ReferralInvitation, ReferralListViewSortKey, ReferralStatus, ReferralViewState, ReferralViewUIState, RewardsPlanData, StatusTypes, toReferralListViewSortKeyType } from './view/referralView/referralState';
@@ -919,7 +920,7 @@ export { Filing1099TinType };
919
920
  export { BillPayCardReport };
920
921
  export { ReimbursementCardReport };
921
922
  export { VendorListViewSortKey, VendorViewUIState, VendorListSelectorView, VendorListQuery, getVendorList, VendorListView, updateSortUiState, updatePageToken, updateYTDSelectionUIState, VendorListViewYTDSpendSortKey, isColumnYTDSpend, isVendorsTabVisible, VendorViewType, VendorReportIDType, toVendorReportIDType, VendorFiling1099ListSelectorView, getVendorFiling1099List, VendorFiling1099ListViewSortKey, VendorFiling1099ViewUIState, VendorFiling1099DownloadData, fetchVendorsFiling1099Download, Type1099Download, VendorFiling1099DownloadDataForType, };
922
- export { fetchEntityRecommendationsByTransactionId, fetchEntityRecommendationsForLineUpdate, fetchRecommendationByEntityId, fetchRecommendationByEntityName, submitRecommendationFeedback, };
923
+ export { fetchEntityRecommendationsByTransactionId, fetchEntityRecommendationsForLineUpdate, fetchRecommendationByEntityId, fetchRecommendationByEntityName, getRecommendationFeedbackSubmitState, submitRecommendationFeedback, };
923
924
  export type { FetchEntityRecommendationsForLineUpdatePayload, RecommendationLineUpdateFlowType, } from './view/recommendation/recommendationReducer';
924
925
  export type { RecommendationFeedbackDimension, RecommendationFeedbackOutcome, RecommendationFeedbackSource, RecommendationFeedbackValue, ShownRecommendationForFeedback, SubmitRecommendationFeedbackPayload, } from './view/recommendation/recommendationPayload';
925
926
  export { fetchOwnerList };
@@ -1131,7 +1132,7 @@ export type { SubmitInvoicingSubscriptionFormPayload, UpdateInvoicingSubscriptio
1131
1132
  export type { InvoicingSubscriptionFormLocalData } from './view/invoicing/editInvoicingSubscriptionDetailView/editInvoicingSubscriptionDetailViewState';
1132
1133
  export { INVOICING_SUBSCRIPTION_SHIPPING_ADDRESS_TYPE, entityToInvoicingSubscriptionFormLocalData, initialInvoicingSubscriptionFormLocalData, invoicingSubscriptionTodayIso, toInvoicingSubscriptionQuantity, } from './view/invoicing/editInvoicingSubscriptionDetailView/invoicingSubscriptionFormConfig';
1133
1134
  export { getEditInvoicingSubscriptionDetailViewState, getInvoicingSubscriptionFormView, } from './view/invoicing/editInvoicingSubscriptionDetailView/editInvoicingSubscriptionDetailViewSelector';
1134
- export type { EditInvoicingSubscriptionDetailView, InvoicingSubscriptionFormView, } from './view/invoicing/editInvoicingSubscriptionDetailView/editInvoicingSubscriptionDetailViewSelector';
1135
+ export type { EditInvoicingSubscriptionDetailView, InvoicingSubscriptionFormView, InvoicingSubscriptionOption, } from './view/invoicing/editInvoicingSubscriptionDetailView/editInvoicingSubscriptionDetailViewSelector';
1135
1136
  export { resetEditInvoicingCatalogItemDetailView, submitInvoicingCatalogItemForm, updateInvoicingCatalogItemFormDraft, } from './view/invoicing/editInvoicingCatalogItemDetailView/editInvoicingCatalogItemDetailViewReducer';
1136
1137
  export type { SubmitInvoicingCatalogItemFormPayload, UpdateInvoicingCatalogItemFormDraftPayload, } from './view/invoicing/editInvoicingCatalogItemDetailView/editInvoicingCatalogItemDetailViewReducer';
1137
1138
  export type { InvoicingCatalogAccountingLookup } from './view/invoicing/editInvoicingCatalogItemDetailView/editInvoicingCatalogItemDetailViewPayload';