@zeniai/client-epic-state 5.2.72 → 5.2.74

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.
@@ -86,6 +86,27 @@ export const getInvoicingItemsAllowedForPlan = (products, plan) => {
86
86
  }
87
87
  return products.filter((product) => product.itemID != null && allowedItemIDs.includes(product.itemID));
88
88
  };
89
+ // Years count as months so they compare; any other unit only meets itself.
90
+ const billingPeriodInCommonUnit = (pricePoint) => {
91
+ const { period, periodUnit } = pricePoint;
92
+ if (period == null || periodUnit == null || periodUnit === '') {
93
+ return undefined;
94
+ }
95
+ return periodUnit === 'year'
96
+ ? { count: period * 12, unit: 'month' }
97
+ : { count: period, unit: periodUnit };
98
+ };
99
+ // The add-on's period must divide the plan's (create 422s otherwise); fails open when they cannot be compared.
100
+ export const isInvoicingAddonPeriodCompatible = (addon, plan) => {
101
+ const addonPeriod = billingPeriodInCommonUnit(addon);
102
+ const planPeriod = plan != null ? billingPeriodInCommonUnit(plan) : undefined;
103
+ if (addonPeriod == null ||
104
+ planPeriod == null ||
105
+ addonPeriod.unit !== planPeriod.unit) {
106
+ return true;
107
+ }
108
+ return addonPeriod.count > 0 && planPeriod.count % addonPeriod.count === 0;
109
+ };
89
110
  /**
90
111
  * A price row can only be subscribed by its price code, so one without a code
91
112
  * is not an option the form can offer.
@@ -174,7 +195,12 @@ export const getInvoicingSubscriptionFormView = (state, invoicingSubscriptionID)
174
195
  // pickers offer only those: subscription create rejects the rest with a 422,
175
196
  // and an option that can only fail is not a choice. The applicability rides
176
197
  // 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);
198
+ const selectedPlanPrice = planPrices.find((plan) => plan.priceCode === localData.planPriceCode);
199
+ // Add-ons also have to bill on the plan's cadence; charges are one-time.
200
+ const allowedCatalogPrices = getInvoicingItemsAllowedForPlan(getInvoicingCatalogPrices(catalogListView.products), selectedPlanPrice)
201
+ .filter(hasInvoicingPriceCode)
202
+ .filter((product) => product.itemType !== 'addon' ||
203
+ isInvoicingAddonPeriodCompatible(product, selectedPlanPrice));
178
204
  const catalogItemOptionsOfType = (itemType) => allowedCatalogPrices
179
205
  .filter((product) => product.itemType === itemType)
180
206
  .map(toInvoicingCatalogItemOption);
@@ -90,8 +90,8 @@ export const updateOnboardingCustomerViewEpic = (actions$, state$, zeniAPI) => a
90
90
  save: 'onboarding_customer_business_verification_save',
91
91
  },
92
92
  setup_billing: {
93
- save: 'billing_address_view',
94
- sendForVerification: 'billing_address_view',
93
+ save: 'common',
94
+ sendForVerification: 'common',
95
95
  },
96
96
  };
97
97
  let messageSection;
@@ -108,6 +108,7 @@ export declare const getEditInvoicingSubscriptionDetailViewState: (state: RootSt
108
108
  * page's inline edit narrow their pickers by the same rule.
109
109
  */
110
110
  export declare const getInvoicingItemsAllowedForPlan: (products: InvoicingCatalogPricePoint[], plan: InvoicingCatalogPricePoint | undefined) => InvoicingCatalogPricePoint[];
111
+ export declare const isInvoicingAddonPeriodCompatible: (addon: InvoicingCatalogPricePoint, plan: InvoicingCatalogPricePoint | undefined) => boolean;
111
112
  /**
112
113
  * One entry in a subscription-form picker, ready for the screen to render.
113
114
  *
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getInvoicingSubscriptionFormView = exports.getInvoicingItemsAllowedForPlan = exports.getEditInvoicingSubscriptionDetailViewState = void 0;
3
+ exports.getInvoicingSubscriptionFormView = exports.isInvoicingAddonPeriodCompatible = exports.getInvoicingItemsAllowedForPlan = exports.getEditInvoicingSubscriptionDetailViewState = void 0;
4
4
  const reduceFetchState_1 = require("../../../commonStateTypes/reduceFetchState");
5
5
  const addressSelector_1 = require("../../../entity/address/addressSelector");
6
6
  const invoicingSubscriptionSelector_1 = require("../../../entity/invoicing/invoicingSubscription/invoicingSubscriptionSelector");
@@ -91,6 +91,28 @@ const getInvoicingItemsAllowedForPlan = (products, plan) => {
91
91
  return products.filter((product) => product.itemID != null && allowedItemIDs.includes(product.itemID));
92
92
  };
93
93
  exports.getInvoicingItemsAllowedForPlan = getInvoicingItemsAllowedForPlan;
94
+ // Years count as months so they compare; any other unit only meets itself.
95
+ const billingPeriodInCommonUnit = (pricePoint) => {
96
+ const { period, periodUnit } = pricePoint;
97
+ if (period == null || periodUnit == null || periodUnit === '') {
98
+ return undefined;
99
+ }
100
+ return periodUnit === 'year'
101
+ ? { count: period * 12, unit: 'month' }
102
+ : { count: period, unit: periodUnit };
103
+ };
104
+ // The add-on's period must divide the plan's (create 422s otherwise); fails open when they cannot be compared.
105
+ const isInvoicingAddonPeriodCompatible = (addon, plan) => {
106
+ const addonPeriod = billingPeriodInCommonUnit(addon);
107
+ const planPeriod = plan != null ? billingPeriodInCommonUnit(plan) : undefined;
108
+ if (addonPeriod == null ||
109
+ planPeriod == null ||
110
+ addonPeriod.unit !== planPeriod.unit) {
111
+ return true;
112
+ }
113
+ return addonPeriod.count > 0 && planPeriod.count % addonPeriod.count === 0;
114
+ };
115
+ exports.isInvoicingAddonPeriodCompatible = isInvoicingAddonPeriodCompatible;
94
116
  /**
95
117
  * A price row can only be subscribed by its price code, so one without a code
96
118
  * is not an option the form can offer.
@@ -179,7 +201,12 @@ const getInvoicingSubscriptionFormView = (state, invoicingSubscriptionID) => {
179
201
  // pickers offer only those: subscription create rejects the rest with a 422,
180
202
  // and an option that can only fail is not a choice. The applicability rides
181
203
  // on the price rows already in the store, so this is a join, not a refetch.
182
- const allowedCatalogPrices = (0, exports.getInvoicingItemsAllowedForPlan)((0, invoicingCatalogListViewSelector_1.getInvoicingCatalogPrices)(catalogListView.products), planPrices.find((plan) => plan.priceCode === localData.planPriceCode)).filter(hasInvoicingPriceCode);
204
+ const selectedPlanPrice = planPrices.find((plan) => plan.priceCode === localData.planPriceCode);
205
+ // Add-ons also have to bill on the plan's cadence; charges are one-time.
206
+ const allowedCatalogPrices = (0, exports.getInvoicingItemsAllowedForPlan)((0, invoicingCatalogListViewSelector_1.getInvoicingCatalogPrices)(catalogListView.products), selectedPlanPrice)
207
+ .filter(hasInvoicingPriceCode)
208
+ .filter((product) => product.itemType !== 'addon' ||
209
+ (0, exports.isInvoicingAddonPeriodCompatible)(product, selectedPlanPrice));
183
210
  const catalogItemOptionsOfType = (itemType) => allowedCatalogPrices
184
211
  .filter((product) => product.itemType === itemType)
185
212
  .map(toInvoicingCatalogItemOption);
@@ -93,8 +93,8 @@ const updateOnboardingCustomerViewEpic = (actions$, state$, zeniAPI) => actions$
93
93
  save: 'onboarding_customer_business_verification_save',
94
94
  },
95
95
  setup_billing: {
96
- save: 'billing_address_view',
97
- sendForVerification: 'billing_address_view',
96
+ save: 'common',
97
+ sendForVerification: 'common',
98
98
  },
99
99
  };
100
100
  let messageSection;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zeniai/client-epic-state",
3
- "version": "5.2.72",
3
+ "version": "5.2.74",
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",
@@ -53,31 +53,6 @@
53
53
  "url": "https://github.com/zeni-ai/client-epic-state/issues"
54
54
  },
55
55
  "homepage": "https://github.com/zeni-ai/client-epic-state#readme",
56
- "devDependencies": {
57
- "@eslint/js": "^9.24.0",
58
- "@liveblocks/client": "^2.23.0",
59
- "@trivago/prettier-plugin-sort-imports": "^5.2.2",
60
- "@types/big.js": "^6.2.2",
61
- "@types/lodash": "^4.17.23",
62
- "@types/node": "^20.19.0",
63
- "@types/url-parse": "^1.4.11",
64
- "@typescript-eslint/eslint-plugin": "^8.56.0",
65
- "@typescript-eslint/parser": "^8.56.0",
66
- "concurrently": "^9.1.2",
67
- "eslint": "^9.24.0",
68
- "eslint-config-prettier": "^10.0.2",
69
- "eslint-plugin-perfectionist": "^4.15.0",
70
- "eslint-plugin-unused-imports": "^4.1.4",
71
- "globals": "^16.0.0",
72
- "knip": "^6.21.0",
73
- "madge": "^8.0.0",
74
- "prettier": "^3.5.3",
75
- "rimraf": "^6.0.1",
76
- "semver": "^7.7.1",
77
- "typescript": "^5.7.3",
78
- "vite": "^7.3.5",
79
- "vitest": "^4.1.11"
80
- },
81
56
  "dependencies": {
82
57
  "@redux-devtools/extension": "^3.3.0",
83
58
  "@reduxjs/toolkit": "^1.6.2",