@powerhousedao/service-offering 1.0.0-dev.4 → 1.0.0-dev.6
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/dist/document-models/facet/v1/actions.d.ts +3 -1
- package/dist/document-models/facet/v1/actions.d.ts.map +1 -1
- package/dist/document-models/facet/v1/gen/controller.d.ts +4 -0
- package/dist/document-models/facet/v1/gen/controller.d.ts.map +1 -0
- package/dist/document-models/facet/v1/gen/controller.js +3 -0
- package/dist/document-models/facet/v1/gen/document-model.d.ts.map +1 -1
- package/dist/document-models/facet/v1/gen/document-model.js +31 -7
- package/dist/document-models/facet/v1/gen/document-schema.d.ts +6 -6
- package/dist/document-models/facet/v1/gen/index.d.ts +1 -0
- package/dist/document-models/facet/v1/gen/index.d.ts.map +1 -1
- package/dist/document-models/facet/v1/gen/index.js +1 -0
- package/dist/document-models/facet/v1/gen/option-management/error.d.ts +27 -1
- package/dist/document-models/facet/v1/gen/option-management/error.d.ts.map +1 -1
- package/dist/document-models/facet/v1/gen/option-management/error.js +23 -1
- package/dist/document-models/facet/v1/gen/ph-factories.js +2 -2
- package/dist/document-models/facet/v1/gen/schema/types.d.ts +2 -2
- package/dist/document-models/facet/v1/gen/schema/types.d.ts.map +1 -1
- package/dist/document-models/facet/v1/gen/schema/zod.js +2 -2
- package/dist/document-models/facet/v1/gen/utils.js +2 -2
- package/dist/document-models/facet/v1/module.d.ts +1 -1
- package/dist/document-models/facet/v1/module.d.ts.map +1 -1
- package/dist/document-models/facet/v1/module.js +4 -1
- package/dist/document-models/resource-instance/v1/actions.d.ts +4 -1
- package/dist/document-models/resource-instance/v1/actions.d.ts.map +1 -1
- package/dist/document-models/resource-instance/v1/gen/configuration-management/error.d.ts +34 -1
- package/dist/document-models/resource-instance/v1/gen/configuration-management/error.d.ts.map +1 -1
- package/dist/document-models/resource-instance/v1/gen/configuration-management/error.js +32 -1
- package/dist/document-models/resource-instance/v1/gen/controller.d.ts +4 -0
- package/dist/document-models/resource-instance/v1/gen/controller.d.ts.map +1 -0
- package/dist/document-models/resource-instance/v1/gen/controller.js +3 -0
- package/dist/document-models/resource-instance/v1/gen/document-model.d.ts.map +1 -1
- package/dist/document-models/resource-instance/v1/gen/document-model.js +222 -70
- package/dist/document-models/resource-instance/v1/gen/document-schema.d.ts +0 -6
- package/dist/document-models/resource-instance/v1/gen/document-schema.d.ts.map +1 -1
- package/dist/document-models/resource-instance/v1/gen/index.d.ts +1 -0
- package/dist/document-models/resource-instance/v1/gen/index.d.ts.map +1 -1
- package/dist/document-models/resource-instance/v1/gen/index.js +1 -0
- package/dist/document-models/resource-instance/v1/gen/instance-management/actions.d.ts +6 -2
- package/dist/document-models/resource-instance/v1/gen/instance-management/actions.d.ts.map +1 -1
- package/dist/document-models/resource-instance/v1/gen/instance-management/creators.d.ts +3 -2
- package/dist/document-models/resource-instance/v1/gen/instance-management/creators.d.ts.map +1 -1
- package/dist/document-models/resource-instance/v1/gen/instance-management/creators.js +2 -1
- package/dist/document-models/resource-instance/v1/gen/instance-management/error.d.ts +98 -1
- package/dist/document-models/resource-instance/v1/gen/instance-management/error.d.ts.map +1 -1
- package/dist/document-models/resource-instance/v1/gen/instance-management/error.js +112 -1
- package/dist/document-models/resource-instance/v1/gen/instance-management/operations.d.ts +2 -1
- package/dist/document-models/resource-instance/v1/gen/instance-management/operations.d.ts.map +1 -1
- package/dist/document-models/resource-instance/v1/gen/ph-factories.d.ts.map +1 -1
- package/dist/document-models/resource-instance/v1/gen/ph-factories.js +0 -2
- package/dist/document-models/resource-instance/v1/gen/reducer.d.ts.map +1 -1
- package/dist/document-models/resource-instance/v1/gen/reducer.js +6 -1
- package/dist/document-models/resource-instance/v1/gen/schema/types.d.ts +3 -3
- package/dist/document-models/resource-instance/v1/gen/schema/types.d.ts.map +1 -1
- package/dist/document-models/resource-instance/v1/gen/schema/zod.d.ts +2 -1
- package/dist/document-models/resource-instance/v1/gen/schema/zod.d.ts.map +1 -1
- package/dist/document-models/resource-instance/v1/gen/schema/zod.js +5 -3
- package/dist/document-models/resource-instance/v1/gen/utils.d.ts.map +1 -1
- package/dist/document-models/resource-instance/v1/gen/utils.js +0 -2
- package/dist/document-models/resource-instance/v1/module.d.ts +1 -1
- package/dist/document-models/resource-instance/v1/module.d.ts.map +1 -1
- package/dist/document-models/resource-instance/v1/module.js +4 -1
- package/dist/document-models/resource-instance/v1/src/reducers/configuration-management.d.ts.map +1 -1
- package/dist/document-models/resource-instance/v1/src/reducers/configuration-management.js +57 -53
- package/dist/document-models/resource-instance/v1/src/reducers/instance-management.d.ts.map +1 -1
- package/dist/document-models/resource-instance/v1/src/reducers/instance-management.js +57 -21
- package/dist/document-models/resource-instance/v1/tests/instance-management.test.js +11 -1
- package/dist/document-models/resource-template/v1/actions.d.ts +3 -1
- package/dist/document-models/resource-template/v1/actions.d.ts.map +1 -1
- package/dist/document-models/resource-template/v1/gen/audience-management/error.d.ts +20 -1
- package/dist/document-models/resource-template/v1/gen/audience-management/error.d.ts.map +1 -1
- package/dist/document-models/resource-template/v1/gen/audience-management/error.js +16 -1
- package/dist/document-models/resource-template/v1/gen/controller.d.ts +4 -0
- package/dist/document-models/resource-template/v1/gen/controller.d.ts.map +1 -0
- package/dist/document-models/resource-template/v1/gen/controller.js +3 -0
- package/dist/document-models/resource-template/v1/gen/document-model.d.ts.map +1 -1
- package/dist/document-models/resource-template/v1/gen/document-model.js +207 -89
- package/dist/document-models/resource-template/v1/gen/document-schema.d.ts +12 -12
- package/dist/document-models/resource-template/v1/gen/facet-targeting/error.d.ts +27 -1
- package/dist/document-models/resource-template/v1/gen/facet-targeting/error.d.ts.map +1 -1
- package/dist/document-models/resource-template/v1/gen/facet-targeting/error.js +23 -1
- package/dist/document-models/resource-template/v1/gen/index.d.ts +1 -0
- package/dist/document-models/resource-template/v1/gen/index.d.ts.map +1 -1
- package/dist/document-models/resource-template/v1/gen/index.js +1 -0
- package/dist/document-models/resource-template/v1/gen/option-group-management/error.d.ts +27 -1
- package/dist/document-models/resource-template/v1/gen/option-group-management/error.d.ts.map +1 -1
- package/dist/document-models/resource-template/v1/gen/option-group-management/error.js +23 -1
- package/dist/document-models/resource-template/v1/gen/ph-factories.js +3 -3
- package/dist/document-models/resource-template/v1/gen/schema/types.d.ts +4 -4
- package/dist/document-models/resource-template/v1/gen/schema/types.d.ts.map +1 -1
- package/dist/document-models/resource-template/v1/gen/schema/zod.js +4 -4
- package/dist/document-models/resource-template/v1/gen/service-management/error.d.ts +51 -1
- package/dist/document-models/resource-template/v1/gen/service-management/error.d.ts.map +1 -1
- package/dist/document-models/resource-template/v1/gen/service-management/error.js +49 -1
- package/dist/document-models/resource-template/v1/gen/utils.js +3 -3
- package/dist/document-models/resource-template/v1/module.d.ts +1 -1
- package/dist/document-models/resource-template/v1/module.d.ts.map +1 -1
- package/dist/document-models/resource-template/v1/module.js +4 -1
- package/dist/document-models/resource-template/v1/src/reducers/option-group-management.d.ts.map +1 -1
- package/dist/document-models/resource-template/v1/src/reducers/option-group-management.js +2 -21
- package/dist/document-models/service-offering/v1/actions.d.ts +3 -1
- package/dist/document-models/service-offering/v1/actions.d.ts.map +1 -1
- package/dist/document-models/service-offering/v1/gen/controller.d.ts +4 -0
- package/dist/document-models/service-offering/v1/gen/controller.d.ts.map +1 -0
- package/dist/document-models/service-offering/v1/gen/controller.js +3 -0
- package/dist/document-models/service-offering/v1/gen/document-model.d.ts.map +1 -1
- package/dist/document-models/service-offering/v1/gen/document-model.js +421 -199
- package/dist/document-models/service-offering/v1/gen/document-schema.d.ts +9 -9
- package/dist/document-models/service-offering/v1/gen/index.d.ts +1 -0
- package/dist/document-models/service-offering/v1/gen/index.d.ts.map +1 -1
- package/dist/document-models/service-offering/v1/gen/index.js +1 -0
- package/dist/document-models/service-offering/v1/gen/offering/error.d.ts +41 -1
- package/dist/document-models/service-offering/v1/gen/offering/error.d.ts.map +1 -1
- package/dist/document-models/service-offering/v1/gen/offering/error.js +37 -1
- package/dist/document-models/service-offering/v1/gen/option-groups/error.d.ts +55 -1
- package/dist/document-models/service-offering/v1/gen/option-groups/error.d.ts.map +1 -1
- package/dist/document-models/service-offering/v1/gen/option-groups/error.js +53 -1
- package/dist/document-models/service-offering/v1/gen/ph-factories.js +3 -3
- package/dist/document-models/service-offering/v1/gen/schema/types.d.ts +134 -61
- package/dist/document-models/service-offering/v1/gen/schema/types.d.ts.map +1 -1
- package/dist/document-models/service-offering/v1/gen/schema/zod.d.ts +35 -10
- package/dist/document-models/service-offering/v1/gen/schema/zod.d.ts.map +1 -1
- package/dist/document-models/service-offering/v1/gen/schema/zod.js +182 -64
- package/dist/document-models/service-offering/v1/gen/services/error.d.ts +20 -1
- package/dist/document-models/service-offering/v1/gen/services/error.d.ts.map +1 -1
- package/dist/document-models/service-offering/v1/gen/services/error.js +16 -1
- package/dist/document-models/service-offering/v1/gen/tiers/error.d.ts +100 -1
- package/dist/document-models/service-offering/v1/gen/tiers/error.d.ts.map +1 -1
- package/dist/document-models/service-offering/v1/gen/tiers/error.js +106 -1
- package/dist/document-models/service-offering/v1/gen/utils.js +4 -4
- package/dist/document-models/service-offering/v1/module.d.ts +1 -1
- package/dist/document-models/service-offering/v1/module.d.ts.map +1 -1
- package/dist/document-models/service-offering/v1/module.js +4 -1
- package/dist/document-models/service-offering/v1/src/reducers/offering.d.ts.map +1 -1
- package/dist/document-models/service-offering/v1/src/reducers/offering.js +20 -12
- package/dist/document-models/service-offering/v1/src/reducers/option-groups.d.ts.map +1 -1
- package/dist/document-models/service-offering/v1/src/reducers/option-groups.js +157 -39
- package/dist/document-models/service-offering/v1/src/reducers/services.d.ts.map +1 -1
- package/dist/document-models/service-offering/v1/src/reducers/services.js +17 -14
- package/dist/document-models/service-offering/v1/src/reducers/tiers.d.ts.map +1 -1
- package/dist/document-models/service-offering/v1/src/reducers/tiers.js +111 -78
- package/dist/document-models/service-offering/v1/src/utils.d.ts +60 -1
- package/dist/document-models/service-offering/v1/src/utils.d.ts.map +1 -1
- package/dist/document-models/service-offering/v1/src/utils.js +173 -1
- package/dist/document-models/service-offering/v1/tests/option-groups.test.js +1 -1
- package/dist/document-models/service-offering/v1/utils.d.ts +3 -0
- package/dist/document-models/service-offering/v1/utils.d.ts.map +1 -1
- package/dist/document-models/subscription-instance/v1/actions.d.ts +3 -1
- package/dist/document-models/subscription-instance/v1/actions.d.ts.map +1 -1
- package/dist/document-models/subscription-instance/v1/gen/controller.d.ts +4 -0
- package/dist/document-models/subscription-instance/v1/gen/controller.d.ts.map +1 -0
- package/dist/document-models/subscription-instance/v1/gen/controller.js +3 -0
- package/dist/document-models/subscription-instance/v1/gen/document-model.d.ts.map +1 -1
- package/dist/document-models/subscription-instance/v1/gen/document-model.js +488 -246
- package/dist/document-models/subscription-instance/v1/gen/document-schema.d.ts +3 -3
- package/dist/document-models/subscription-instance/v1/gen/index.d.ts +1 -0
- package/dist/document-models/subscription-instance/v1/gen/index.d.ts.map +1 -1
- package/dist/document-models/subscription-instance/v1/gen/index.js +1 -0
- package/dist/document-models/subscription-instance/v1/gen/metrics/error.d.ts +73 -1
- package/dist/document-models/subscription-instance/v1/gen/metrics/error.d.ts.map +1 -1
- package/dist/document-models/subscription-instance/v1/gen/metrics/error.js +86 -1
- package/dist/document-models/subscription-instance/v1/gen/ph-factories.js +1 -1
- package/dist/document-models/subscription-instance/v1/gen/schema/types.d.ts +199 -82
- package/dist/document-models/subscription-instance/v1/gen/schema/types.d.ts.map +1 -1
- package/dist/document-models/subscription-instance/v1/gen/schema/zod.d.ts +22 -12
- package/dist/document-models/subscription-instance/v1/gen/schema/zod.d.ts.map +1 -1
- package/dist/document-models/subscription-instance/v1/gen/schema/zod.js +230 -84
- package/dist/document-models/subscription-instance/v1/gen/service/error.d.ts +62 -1
- package/dist/document-models/subscription-instance/v1/gen/service/error.d.ts.map +1 -1
- package/dist/document-models/subscription-instance/v1/gen/service/error.js +60 -1
- package/dist/document-models/subscription-instance/v1/gen/service-group/error.d.ts +39 -1
- package/dist/document-models/subscription-instance/v1/gen/service-group/error.d.ts.map +1 -1
- package/dist/document-models/subscription-instance/v1/gen/service-group/error.js +39 -1
- package/dist/document-models/subscription-instance/v1/gen/subscription/error.d.ts +55 -1
- package/dist/document-models/subscription-instance/v1/gen/subscription/error.d.ts.map +1 -1
- package/dist/document-models/subscription-instance/v1/gen/subscription/error.js +51 -1
- package/dist/document-models/subscription-instance/v1/gen/utils.js +2 -2
- package/dist/document-models/subscription-instance/v1/module.d.ts +1 -1
- package/dist/document-models/subscription-instance/v1/module.d.ts.map +1 -1
- package/dist/document-models/subscription-instance/v1/module.js +4 -1
- package/dist/document-models/subscription-instance/v1/src/reducers/customer.d.ts.map +1 -1
- package/dist/document-models/subscription-instance/v1/src/reducers/customer.js +1 -0
- package/dist/document-models/subscription-instance/v1/src/reducers/metrics.d.ts.map +1 -1
- package/dist/document-models/subscription-instance/v1/src/reducers/metrics.js +70 -45
- package/dist/document-models/subscription-instance/v1/src/reducers/service-group.d.ts.map +1 -1
- package/dist/document-models/subscription-instance/v1/src/reducers/service-group.js +108 -30
- package/dist/document-models/subscription-instance/v1/src/reducers/service.d.ts.map +1 -1
- package/dist/document-models/subscription-instance/v1/src/reducers/service.js +108 -39
- package/dist/document-models/subscription-instance/v1/src/reducers/subscription.d.ts.map +1 -1
- package/dist/document-models/subscription-instance/v1/src/reducers/subscription.js +193 -35
- package/dist/editors/resource-instance-editor/editor.d.ts.map +1 -1
- package/dist/editors/resource-instance-editor/editor.js +13 -3
- package/dist/editors/service-offering-editor/components/ResourceTemplateSelector.d.ts.map +1 -1
- package/dist/editors/service-offering-editor/components/ResourceTemplateSelector.js +4 -2
- package/dist/editors/service-offering-editor/components/ServiceCatalog.d.ts.map +1 -1
- package/dist/editors/service-offering-editor/components/ServiceCatalog.js +189 -32
- package/dist/editors/service-offering-editor/components/TheMatrix.d.ts +1 -1
- package/dist/editors/service-offering-editor/components/TheMatrix.d.ts.map +1 -1
- package/dist/editors/service-offering-editor/components/TheMatrix.js +295 -140
- package/dist/editors/service-offering-editor/components/TierDefinition.d.ts.map +1 -1
- package/dist/editors/service-offering-editor/components/TierDefinition.js +2 -0
- package/dist/editors/service-offering-editor/components/TierPricingOptionsPanel.js +3 -3
- package/dist/editors/service-offering-editor/components/pricing-utils.d.ts.map +1 -1
- package/dist/editors/service-offering-editor/components/pricing-utils.js +26 -7
- package/dist/editors/subscription-instance-editor/components/BillingPanel.d.ts.map +1 -1
- package/dist/editors/subscription-instance-editor/components/BillingPanel.js +4 -4
- package/dist/editors/subscription-instance-editor/components/CustomerInfo.d.ts.map +1 -1
- package/dist/editors/subscription-instance-editor/components/CustomerInfo.js +3 -2
- package/dist/editors/subscription-instance-editor/components/ImportServiceConfigButton.d.ts +3 -0
- package/dist/editors/subscription-instance-editor/components/ImportServiceConfigButton.d.ts.map +1 -1
- package/dist/editors/subscription-instance-editor/components/ImportServiceConfigButton.js +12 -0
- package/dist/editors/subscription-instance-editor/components/MetricActions.d.ts.map +1 -1
- package/dist/editors/subscription-instance-editor/components/MetricActions.js +4 -2
- package/dist/editors/subscription-instance-editor/components/MockDataButton.d.ts.map +1 -1
- package/dist/editors/subscription-instance-editor/components/MockDataButton.js +214 -2
- package/dist/editors/subscription-instance-editor/components/OperatorNotes.js +1 -1
- package/dist/editors/subscription-instance-editor/components/ServicesPanel.d.ts.map +1 -1
- package/dist/editors/subscription-instance-editor/components/ServicesPanel.js +9 -20
- package/dist/editors/subscription-instance-editor/components/SubscriptionActions.d.ts.map +1 -1
- package/dist/editors/subscription-instance-editor/components/SubscriptionActions.js +8 -9
- package/dist/editors/subscription-instance-editor/components/SubscriptionHeader.d.ts.map +1 -1
- package/dist/editors/subscription-instance-editor/components/SubscriptionHeader.js +1 -1
- package/dist/editors/subscription-instance-editor/components/billing-utils.d.ts +14 -6
- package/dist/editors/subscription-instance-editor/components/billing-utils.d.ts.map +1 -1
- package/dist/editors/subscription-instance-editor/components/billing-utils.js +19 -23
- package/dist/editors/subscription-instance-editor/components/mapOfferingToSubscription.d.ts +16 -2
- package/dist/editors/subscription-instance-editor/components/mapOfferingToSubscription.d.ts.map +1 -1
- package/dist/editors/subscription-instance-editor/components/mapOfferingToSubscription.js +155 -6
- package/dist/powerhouse.manifest.json +29 -3
- package/dist/style.css +14 -0
- package/dist/subgraphs/resources-services/resolvers.d.ts +1 -1
- package/dist/subgraphs/resources-services/resolvers.d.ts.map +1 -1
- package/dist/subgraphs/resources-services/resolvers.js +273 -158
- package/dist/subgraphs/resources-services/schema.d.ts.map +1 -1
- package/dist/subgraphs/resources-services/schema.js +107 -41
- package/package.json +22 -18
|
@@ -107,6 +107,7 @@ export function ServiceCatalog({ document, dispatch }) {
|
|
|
107
107
|
QUARTERLY: "",
|
|
108
108
|
SEMI_ANNUAL: "",
|
|
109
109
|
ANNUAL: "",
|
|
110
|
+
ONE_TIME: "",
|
|
110
111
|
});
|
|
111
112
|
// Per-tier pricing state for edit modal
|
|
112
113
|
const [editTierTab, setEditTierTab] = useState(null);
|
|
@@ -148,6 +149,8 @@ export function ServiceCatalog({ document, dispatch }) {
|
|
|
148
149
|
name: "New Group",
|
|
149
150
|
isAddOn: false,
|
|
150
151
|
defaultSelected: true,
|
|
152
|
+
costType: "RECURRING",
|
|
153
|
+
availableBillingCycles: inheritedCycles,
|
|
151
154
|
lastModified: new Date().toISOString(),
|
|
152
155
|
}));
|
|
153
156
|
// Construct minimal group shape to open Edit modal immediately
|
|
@@ -194,6 +197,7 @@ export function ServiceCatalog({ document, dispatch }) {
|
|
|
194
197
|
: "recurring";
|
|
195
198
|
setEditGroupType(groupType);
|
|
196
199
|
setEditGroupPrice(group.price?.toString() || "");
|
|
200
|
+
// Initialize per-tier setup fee discounts from tier-dependent pricing
|
|
197
201
|
const SUBSCRIPTION_CYCLES = [
|
|
198
202
|
"MONTHLY",
|
|
199
203
|
"QUARTERLY",
|
|
@@ -206,6 +210,17 @@ export function ServiceCatalog({ document, dispatch }) {
|
|
|
206
210
|
c,
|
|
207
211
|
{ discountType: "PERCENTAGE", discountValue: "" },
|
|
208
212
|
]));
|
|
213
|
+
const tierPricingEntry = group.tierDependentPricing?.find((tp) => tp.tierId === tier.id);
|
|
214
|
+
if (tierPricingEntry?.setupCostDiscounts) {
|
|
215
|
+
tierPricingEntry.setupCostDiscounts.forEach((d) => {
|
|
216
|
+
if (d.billingCycle && d.discountRule) {
|
|
217
|
+
emptyDiscounts[d.billingCycle] = {
|
|
218
|
+
discountType: d.discountRule.discountType,
|
|
219
|
+
discountValue: d.discountRule.discountValue?.toString() || "",
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
});
|
|
223
|
+
}
|
|
209
224
|
setupTierDiscounts[tier.id] = emptyDiscounts;
|
|
210
225
|
}
|
|
211
226
|
setEditSetupTierDiscounts(setupTierDiscounts);
|
|
@@ -223,17 +238,21 @@ export function ServiceCatalog({ document, dispatch }) {
|
|
|
223
238
|
else {
|
|
224
239
|
setEditGroupPricingMode("STANDALONE");
|
|
225
240
|
}
|
|
226
|
-
|
|
227
|
-
|
|
241
|
+
// Initialize standalone pricing (for add-ons in STANDALONE mode or fallback)
|
|
242
|
+
setEditGroupSetupCost(group.standalonePricing?.setupCost?.amount?.toString() || "");
|
|
243
|
+
const monthlyPricing = group.standalonePricing?.recurringPricing?.find((p) => p.billingCycle === "MONTHLY");
|
|
244
|
+
setEditGroupBasePrice(monthlyPricing?.amount?.toString() || "");
|
|
245
|
+
// Initialize per-group billing cycle discounts (flat amount only)
|
|
228
246
|
const discounts = {
|
|
229
247
|
MONTHLY: "",
|
|
230
248
|
QUARTERLY: "",
|
|
231
249
|
SEMI_ANNUAL: "",
|
|
232
250
|
ANNUAL: "",
|
|
251
|
+
ONE_TIME: "",
|
|
233
252
|
};
|
|
234
253
|
group.billingCycleDiscounts?.forEach((d) => {
|
|
235
|
-
if (d.
|
|
236
|
-
discounts[d.
|
|
254
|
+
if (d.billingCycle && d.discountRule?.discountValue) {
|
|
255
|
+
discounts[d.billingCycle] = d.discountRule.discountValue.toString();
|
|
237
256
|
}
|
|
238
257
|
});
|
|
239
258
|
setEditGroupDiscounts(discounts);
|
|
@@ -243,22 +262,39 @@ export function ServiceCatalog({ document, dispatch }) {
|
|
|
243
262
|
const tierDiscounts = {};
|
|
244
263
|
for (const tier of tiers) {
|
|
245
264
|
const tierPricingEntry = group.tierDependentPricing?.find((tp) => tp.tierId === tier.id);
|
|
265
|
+
const tierMonthlyPricing = tierPricingEntry?.recurringPricing?.find((p) => p.billingCycle === "MONTHLY");
|
|
266
|
+
// If no tier pricing exists but group has standalone pricing, use standalone as starting point
|
|
246
267
|
if (tierPricingEntry) {
|
|
247
|
-
tierPrices[tier.id] =
|
|
268
|
+
tierPrices[tier.id] = tierMonthlyPricing?.amount?.toString() || "";
|
|
269
|
+
tierSetupCosts[tier.id] =
|
|
270
|
+
tierPricingEntry.setupCost?.amount?.toString() || "";
|
|
248
271
|
}
|
|
249
|
-
else if (
|
|
250
|
-
|
|
272
|
+
else if (monthlyPricing) {
|
|
273
|
+
// Pre-fill from standalone as migration aid
|
|
274
|
+
tierPrices[tier.id] = monthlyPricing.amount?.toString() || "";
|
|
275
|
+
tierSetupCosts[tier.id] =
|
|
276
|
+
group.standalonePricing?.setupCost?.amount?.toString() || "";
|
|
251
277
|
}
|
|
252
278
|
else {
|
|
253
279
|
tierPrices[tier.id] = "";
|
|
280
|
+
tierSetupCosts[tier.id] = "";
|
|
254
281
|
}
|
|
255
|
-
|
|
282
|
+
// Per-tier discounts: populate from tierDependentPricing[].recurringPricing[].discount
|
|
256
283
|
const tierDiscountValues = {
|
|
257
284
|
MONTHLY: "",
|
|
258
285
|
QUARTERLY: "",
|
|
259
286
|
SEMI_ANNUAL: "",
|
|
260
287
|
ANNUAL: "",
|
|
288
|
+
ONE_TIME: "",
|
|
261
289
|
};
|
|
290
|
+
if (tierPricingEntry) {
|
|
291
|
+
tierPricingEntry.recurringPricing?.forEach((rp) => {
|
|
292
|
+
if (rp.discount && rp.discount.discountValue > 0) {
|
|
293
|
+
tierDiscountValues[rp.billingCycle] =
|
|
294
|
+
rp.discount.discountValue.toString();
|
|
295
|
+
}
|
|
296
|
+
});
|
|
297
|
+
}
|
|
262
298
|
tierDiscounts[tier.id] = tierDiscountValues;
|
|
263
299
|
}
|
|
264
300
|
setEditTierPrices(tierPrices);
|
|
@@ -271,56 +307,153 @@ export function ServiceCatalog({ document, dispatch }) {
|
|
|
271
307
|
return;
|
|
272
308
|
const isSetup = editGroupType === "setup";
|
|
273
309
|
const isAddOn = editGroupType === "addon";
|
|
310
|
+
const costType = isSetup ? "SETUP" : "RECURRING";
|
|
274
311
|
const price = editGroupPrice ? parseFloat(editGroupPrice) : null;
|
|
312
|
+
// Update the option group in the document
|
|
275
313
|
dispatch(updateOptionGroup({
|
|
276
314
|
id: editingGroup.id,
|
|
277
315
|
name: editGroupName.trim(),
|
|
278
316
|
isAddOn,
|
|
279
317
|
defaultSelected: !isAddOn,
|
|
318
|
+
costType,
|
|
319
|
+
availableBillingCycles: isSetup ? ["ONE_TIME"] : editGroupBillingCycles,
|
|
320
|
+
price: price ?? undefined,
|
|
321
|
+
currency: price ? "USD" : undefined,
|
|
280
322
|
lastModified: new Date().toISOString(),
|
|
281
323
|
}));
|
|
324
|
+
// Save setup pricing: base cost via standalone, per-tier discounts via tier pricing
|
|
282
325
|
if (isSetup && price && price > 0) {
|
|
283
326
|
const now = new Date().toISOString();
|
|
327
|
+
// Store base setup cost via standalone pricing
|
|
284
328
|
dispatch(setOptionGroupStandalonePricing({
|
|
285
329
|
optionGroupId: editingGroup.id,
|
|
286
|
-
amount: price,
|
|
287
|
-
|
|
330
|
+
setupCost: { amount: price, currency: "USD" },
|
|
331
|
+
recurringPricing: [],
|
|
288
332
|
lastModified: now,
|
|
289
333
|
}));
|
|
334
|
+
// Store per-tier setup fee discounts
|
|
335
|
+
for (const tier of tiers) {
|
|
336
|
+
if (tier.isCustomPricing)
|
|
337
|
+
continue;
|
|
338
|
+
const tierDiscountEntries = editSetupTierDiscounts[tier.id];
|
|
339
|
+
const setupCostDiscounts = Object.entries(tierDiscountEntries || {})
|
|
340
|
+
.filter(([, d]) => parseFloat(d.discountValue) > 0)
|
|
341
|
+
.map(([cycle, d]) => ({
|
|
342
|
+
billingCycle: cycle,
|
|
343
|
+
discountRule: {
|
|
344
|
+
discountType: "PERCENTAGE",
|
|
345
|
+
discountValue: parseFloat(d.discountValue),
|
|
346
|
+
},
|
|
347
|
+
}));
|
|
348
|
+
const existingTierPricing = editingGroup.tierDependentPricing?.find((tp) => tp.tierId === tier.id);
|
|
349
|
+
if (existingTierPricing) {
|
|
350
|
+
dispatch(updateOptionGroupTierPricing({
|
|
351
|
+
optionGroupId: editingGroup.id,
|
|
352
|
+
tierId: tier.id,
|
|
353
|
+
setupCost: { amount: price, currency: "USD" },
|
|
354
|
+
setupCostDiscounts,
|
|
355
|
+
recurringPricing: [],
|
|
356
|
+
lastModified: now,
|
|
357
|
+
}));
|
|
358
|
+
}
|
|
359
|
+
else {
|
|
360
|
+
dispatch(addOptionGroupTierPricing({
|
|
361
|
+
optionGroupId: editingGroup.id,
|
|
362
|
+
tierPricingId: generateId(),
|
|
363
|
+
tierId: tier.id,
|
|
364
|
+
setupCost: { amount: price, currency: "USD" },
|
|
365
|
+
setupCostDiscounts,
|
|
366
|
+
recurringPricing: [],
|
|
367
|
+
lastModified: now,
|
|
368
|
+
}));
|
|
369
|
+
}
|
|
370
|
+
}
|
|
290
371
|
}
|
|
372
|
+
// Save pricing based on mode
|
|
291
373
|
if (!isSetup && editGroupPricingMode === "TIER_DEPENDENT") {
|
|
374
|
+
// Per-tier pricing: dispatch addOptionGroupTierPricing or updateOptionGroupTierPricing per tier
|
|
292
375
|
const now = new Date().toISOString();
|
|
293
376
|
for (const tier of tiers) {
|
|
294
377
|
if (tier.isCustomPricing)
|
|
295
|
-
continue;
|
|
378
|
+
continue; // Skip custom tiers
|
|
296
379
|
const baseMonthly = parseFloat(editTierPrices[tier.id]) || 0;
|
|
380
|
+
const setupCostVal = parseFloat(editTierSetupCosts[tier.id]) || 0;
|
|
381
|
+
const setupCost = setupCostVal > 0
|
|
382
|
+
? { amount: setupCostVal, currency: "USD" }
|
|
383
|
+
: undefined;
|
|
384
|
+
const recurringPricing = editGroupBillingCycles
|
|
385
|
+
.filter(() => baseMonthly > 0)
|
|
386
|
+
.map((cycle) => {
|
|
387
|
+
const discountPct = parseFloat(editTierDiscounts[tier.id]?.[cycle] || "0") || 0;
|
|
388
|
+
return {
|
|
389
|
+
id: generateId(),
|
|
390
|
+
billingCycle: cycle,
|
|
391
|
+
amount: baseMonthly,
|
|
392
|
+
currency: "USD",
|
|
393
|
+
discount: discountPct > 0
|
|
394
|
+
? {
|
|
395
|
+
discountType: "PERCENTAGE",
|
|
396
|
+
discountValue: discountPct,
|
|
397
|
+
}
|
|
398
|
+
: undefined,
|
|
399
|
+
};
|
|
400
|
+
});
|
|
297
401
|
const existingTierPricing = editingGroup.tierDependentPricing?.find((tp) => tp.tierId === tier.id);
|
|
298
402
|
if (existingTierPricing) {
|
|
299
403
|
dispatch(updateOptionGroupTierPricing({
|
|
300
404
|
optionGroupId: editingGroup.id,
|
|
301
405
|
tierId: tier.id,
|
|
302
|
-
|
|
303
|
-
|
|
406
|
+
setupCost,
|
|
407
|
+
recurringPricing,
|
|
304
408
|
lastModified: now,
|
|
305
409
|
}));
|
|
306
410
|
}
|
|
307
411
|
else {
|
|
308
412
|
dispatch(addOptionGroupTierPricing({
|
|
309
413
|
optionGroupId: editingGroup.id,
|
|
414
|
+
tierPricingId: generateId(),
|
|
310
415
|
tierId: tier.id,
|
|
311
|
-
|
|
312
|
-
|
|
416
|
+
setupCost,
|
|
417
|
+
recurringPricing,
|
|
313
418
|
lastModified: now,
|
|
314
419
|
}));
|
|
315
420
|
}
|
|
316
421
|
}
|
|
317
422
|
}
|
|
318
423
|
else if (!isSetup && editGroupPricingMode === "STANDALONE") {
|
|
424
|
+
// Standalone pricing (add-ons or groups with no tiers)
|
|
425
|
+
const setupCost = editGroupSetupCost && parseFloat(editGroupSetupCost) > 0
|
|
426
|
+
? {
|
|
427
|
+
amount: parseFloat(editGroupSetupCost),
|
|
428
|
+
currency: "USD",
|
|
429
|
+
}
|
|
430
|
+
: undefined;
|
|
319
431
|
const baseMonthly = parseFloat(editGroupBasePrice) || 0;
|
|
320
|
-
|
|
321
|
-
|
|
432
|
+
const recurringPricing = editGroupBillingCycles
|
|
433
|
+
.filter(() => baseMonthly > 0)
|
|
434
|
+
.map((cycle) => ({
|
|
435
|
+
id: generateId(),
|
|
436
|
+
billingCycle: cycle,
|
|
322
437
|
amount: baseMonthly,
|
|
323
438
|
currency: "USD",
|
|
439
|
+
}));
|
|
440
|
+
const billingCycleDiscounts = editGroupBillingCycles
|
|
441
|
+
.map((cycle) => {
|
|
442
|
+
const discountPct = parseFloat(editGroupDiscounts[cycle]) || 0;
|
|
443
|
+
return {
|
|
444
|
+
billingCycle: cycle,
|
|
445
|
+
discountRule: {
|
|
446
|
+
discountType: "PERCENTAGE",
|
|
447
|
+
discountValue: discountPct,
|
|
448
|
+
},
|
|
449
|
+
};
|
|
450
|
+
})
|
|
451
|
+
.filter((d) => d.discountRule.discountValue > 0);
|
|
452
|
+
dispatch(setOptionGroupStandalonePricing({
|
|
453
|
+
optionGroupId: editingGroup.id,
|
|
454
|
+
setupCost,
|
|
455
|
+
recurringPricing,
|
|
456
|
+
billingCycleDiscounts,
|
|
324
457
|
lastModified: new Date().toISOString(),
|
|
325
458
|
}));
|
|
326
459
|
}
|
|
@@ -353,12 +486,14 @@ export function ServiceCatalog({ document, dispatch }) {
|
|
|
353
486
|
optionGroupId: selectedGroupId || undefined,
|
|
354
487
|
lastModified: now,
|
|
355
488
|
}));
|
|
489
|
+
// Create ServiceLevelBindings for each selected tier
|
|
356
490
|
selectedTierIds.forEach((tierId) => {
|
|
357
491
|
dispatch(addServiceLevel({
|
|
358
|
-
|
|
492
|
+
serviceLevelId: generateId(),
|
|
359
493
|
serviceId,
|
|
360
494
|
tierId,
|
|
361
495
|
level: "INCLUDED",
|
|
496
|
+
optionGroupId: selectedGroupId || undefined,
|
|
362
497
|
lastModified: now,
|
|
363
498
|
}));
|
|
364
499
|
});
|
|
@@ -366,6 +501,7 @@ export function ServiceCatalog({ document, dispatch }) {
|
|
|
366
501
|
setSelectedTierIds(new Set());
|
|
367
502
|
setIsAddingService(false);
|
|
368
503
|
};
|
|
504
|
+
// Quick-add service from template (reduces activation energy)
|
|
369
505
|
const handleAddFromTemplate = (template) => {
|
|
370
506
|
if (!selectedGroupId)
|
|
371
507
|
return;
|
|
@@ -380,12 +516,14 @@ export function ServiceCatalog({ document, dispatch }) {
|
|
|
380
516
|
optionGroupId: selectedGroupId,
|
|
381
517
|
lastModified: now,
|
|
382
518
|
}));
|
|
519
|
+
// Auto-include in all tiers for convenience (can be changed later)
|
|
383
520
|
tiers.forEach((tier) => {
|
|
384
521
|
dispatch(addServiceLevel({
|
|
385
|
-
|
|
522
|
+
serviceLevelId: generateId(),
|
|
386
523
|
serviceId,
|
|
387
524
|
tierId: tier.id,
|
|
388
525
|
level: "INCLUDED",
|
|
526
|
+
optionGroupId: selectedGroupId,
|
|
389
527
|
lastModified: now,
|
|
390
528
|
}));
|
|
391
529
|
});
|
|
@@ -406,20 +544,29 @@ export function ServiceCatalog({ document, dispatch }) {
|
|
|
406
544
|
// Find existing service level binding for this service-tier combo
|
|
407
545
|
const existingBinding = tier.serviceLevels.find((sl) => sl.serviceId === serviceId);
|
|
408
546
|
if (isIncluded) {
|
|
409
|
-
|
|
547
|
+
// Add or update service level binding
|
|
548
|
+
if (existingBinding) {
|
|
549
|
+
// Service level exists, might need to update it if level changed
|
|
550
|
+
// (for now we just use INCLUDED)
|
|
551
|
+
}
|
|
552
|
+
else {
|
|
553
|
+
// Create new service level binding
|
|
554
|
+
const service = services.find((s) => s.id === serviceId);
|
|
410
555
|
dispatch(addServiceLevel({
|
|
411
|
-
|
|
556
|
+
serviceLevelId: generateId(),
|
|
412
557
|
serviceId,
|
|
413
558
|
tierId,
|
|
414
559
|
level: "INCLUDED",
|
|
560
|
+
optionGroupId: service?.optionGroupId || undefined,
|
|
415
561
|
lastModified: now,
|
|
416
562
|
}));
|
|
417
563
|
}
|
|
418
564
|
}
|
|
419
565
|
else {
|
|
566
|
+
// Remove service level binding
|
|
420
567
|
if (existingBinding) {
|
|
421
568
|
dispatch(removeServiceLevel({
|
|
422
|
-
|
|
569
|
+
serviceLevelId: existingBinding.id,
|
|
423
570
|
tierId,
|
|
424
571
|
lastModified: now,
|
|
425
572
|
}));
|
|
@@ -467,7 +614,9 @@ export function ServiceCatalog({ document, dispatch }) {
|
|
|
467
614
|
: color === "emerald"
|
|
468
615
|
? "border-emerald-500 bg-emerald-50 text-emerald-700"
|
|
469
616
|
: "border-violet-500 bg-violet-50 text-violet-700"
|
|
470
|
-
: "border-slate-200 bg-white text-slate-600 hover:border-slate-300"}`, style: fontSans, children: label }, type))) })] }), editGroupType !== "setup" && (_jsxs("div", { className: "flex flex-col gap-1.5", children: [_jsx("label", { className: "text-xs font-semibold uppercase tracking-[0.05em] text-slate-500", style: fontSans, children: "Available Billing Cycles" }), _jsx("div", { className: "flex flex-col gap-2.5 p-3 bg-slate-50 rounded-[10px]", children: Object.entries(BILLING_CYCLE_SHORT_LABELS)
|
|
617
|
+
: "border-slate-200 bg-white text-slate-600 hover:border-slate-300"}`, style: fontSans, children: label }, type))) })] }), editGroupType !== "setup" && (_jsxs("div", { className: "flex flex-col gap-1.5", children: [_jsx("label", { className: "text-xs font-semibold uppercase tracking-[0.05em] text-slate-500", style: fontSans, children: "Available Billing Cycles" }), _jsx("div", { className: "flex flex-col gap-2.5 p-3 bg-slate-50 rounded-[10px]", children: Object.entries(BILLING_CYCLE_SHORT_LABELS)
|
|
618
|
+
.filter(([value]) => value !== "ONE_TIME")
|
|
619
|
+
.map(([value, label]) => (_jsxs("label", { className: "flex items-center gap-2.5 cursor-pointer text-sm text-slate-700", children: [_jsx("input", { type: "checkbox", checked: editGroupBillingCycles.includes(value), onChange: (e) => {
|
|
471
620
|
if (e.target.checked) {
|
|
472
621
|
setEditGroupBillingCycles([
|
|
473
622
|
...editGroupBillingCycles,
|
|
@@ -495,20 +644,25 @@ export function ServiceCatalog({ document, dispatch }) {
|
|
|
495
644
|
return (_jsxs("div", { className: "flex items-center gap-2 p-3 bg-slate-50 border border-dashed border-slate-300 rounded-md text-xs text-slate-500 italic", children: [_jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", width: "16", height: "16", children: _jsx("path", { d: "M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" }) }), _jsx("span", { children: "Price negotiated per customer. No group-level price input for custom tiers." })] }));
|
|
496
645
|
}
|
|
497
646
|
const tierBase = parseFloat(editTierPrices[activeTier.id]) || 0;
|
|
498
|
-
const tierAmount = activeTier.pricing
|
|
647
|
+
const tierAmount = activeTier.pricing.amount ?? 0;
|
|
648
|
+
// Budget: sum of other groups' prices for this tier
|
|
499
649
|
const otherGroupsTotal = regularGroups
|
|
500
650
|
.filter((g) => editingGroup && g.id !== editingGroup.id)
|
|
501
651
|
.reduce((sum, g) => {
|
|
502
652
|
const tp = g.tierDependentPricing?.find((p) => p.tierId === activeTier.id);
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
653
|
+
const mp = tp?.recurringPricing?.find((p) => p.billingCycle === "MONTHLY");
|
|
654
|
+
if (mp)
|
|
655
|
+
return sum + (mp.amount ?? 0);
|
|
656
|
+
// Fallback to standalone
|
|
657
|
+
const sp = g.standalonePricing?.recurringPricing?.find((p) => p.billingCycle === "MONTHLY");
|
|
658
|
+
return sum + (sp?.amount ?? 0);
|
|
506
659
|
}, 0);
|
|
507
660
|
const projectedTotal = otherGroupsTotal + tierBase;
|
|
508
661
|
return (_jsxs("div", { style: { animation: "catalog__fade-in 0.15s ease" }, children: [_jsxs("div", { className: "flex flex-col gap-1.5", children: [_jsxs("label", { className: "text-xs font-semibold uppercase tracking-[0.05em] text-slate-500", style: fontSans, children: ["Recurring Price (", activeTier.name, ")"] }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx("span", { className: "text-sm text-slate-500", children: "$" }), _jsx("input", { type: "number", value: editTierPrices[activeTier.id] || "", onChange: (e) => setEditTierPrices({
|
|
509
662
|
...editTierPrices,
|
|
510
663
|
[activeTier.id]: e.target.value,
|
|
511
|
-
}), placeholder: "0.00", className: "flex-1 px-2.5 py-2 text-sm text-slate-800 bg-white border-[1.5px] border-slate-200 rounded-md focus:outline-none focus:border-violet-500 focus:shadow-[0_0_0_2px_rgb(237,233,254)]", style: fontSans, step: "0.01" })] })] }), tierAmount > 0 &&
|
|
664
|
+
}), placeholder: "0.00", className: "flex-1 px-2.5 py-2 text-sm text-slate-800 bg-white border-[1.5px] border-slate-200 rounded-md focus:outline-none focus:border-violet-500 focus:shadow-[0_0_0_2px_rgb(237,233,254)]", style: fontSans, step: "0.01" })] })] }), tierAmount > 0 &&
|
|
665
|
+
activeTier.pricingMode !== "CALCULATED" && (_jsxs("div", { className: "mt-2 p-2 px-2.5 bg-slate-50 border border-slate-200 rounded-md", children: [_jsxs("span", { className: "block text-[0.6875rem] font-semibold text-slate-700 mb-1.5", children: [activeTier.name, " budget:", " ", formatPrice(projectedTotal), "/mo of", " ", formatPrice(tierAmount), "/mo"] }), _jsxs("div", { className: "flex items-center gap-1.5 py-[3px]", children: [_jsx("div", { className: "flex-1 h-[5px] bg-slate-200 rounded-full overflow-hidden", children: _jsx("div", { className: `h-full rounded-full transition-[width] duration-200 ease-linear ${projectedTotal > tierAmount ? "bg-rose-500" : "bg-emerald-500"}`, style: {
|
|
512
666
|
width: `${Math.min((projectedTotal / tierAmount) * 100, 100)}%`,
|
|
513
667
|
} }) }), _jsxs("span", { className: `shrink-0 text-[0.625rem] ${projectedTotal > tierAmount ? "text-rose-600 font-semibold" : "text-slate-600"}`, style: fontMono, children: [formatPrice(projectedTotal), " /", " ", formatPrice(tierAmount), projectedTotal > tierAmount && (_jsxs("span", { className: "text-rose-500 font-bold", children: [" ", "+", formatPrice(projectedTotal - tierAmount)] }))] })] })] })), _jsxs("div", { className: "flex flex-col gap-1.5", children: [_jsx("label", { className: "text-xs font-semibold uppercase tracking-[0.05em] text-slate-500", style: fontSans, children: "Setup Cost (one-time)" }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx("span", { className: "text-sm text-slate-500", children: "$" }), _jsx("input", { type: "number", value: editTierSetupCosts[activeTier.id] || "", onChange: (e) => setEditTierSetupCosts({
|
|
514
668
|
...editTierSetupCosts,
|
|
@@ -523,7 +677,9 @@ export function ServiceCatalog({ document, dispatch }) {
|
|
|
523
677
|
QUARTERLY: "Quarterly",
|
|
524
678
|
SEMI_ANNUAL: "Semi-Annual",
|
|
525
679
|
ANNUAL: "Annual",
|
|
680
|
+
ONE_TIME: "One-Time",
|
|
526
681
|
}[cycle];
|
|
682
|
+
// Percentage discount from user input (always editable)
|
|
527
683
|
const discountPct = parseFloat(editTierDiscounts[activeTier.id]?.[cycle] || "0") || 0;
|
|
528
684
|
let effective = null;
|
|
529
685
|
let savingsPct = 0;
|
|
@@ -559,6 +715,7 @@ export function ServiceCatalog({ document, dispatch }) {
|
|
|
559
715
|
QUARTERLY: "Quarterly",
|
|
560
716
|
SEMI_ANNUAL: "Semi-Annual",
|
|
561
717
|
ANNUAL: "Annual",
|
|
718
|
+
ONE_TIME: "One-Time",
|
|
562
719
|
}[cycle];
|
|
563
720
|
const shortLabel = `${months}mo`;
|
|
564
721
|
return (_jsxs("div", { className: `border border-slate-200 rounded-[10px] px-3.5 py-2.5 transition-[150ms] ${base > 0 ? "bg-white" : "bg-slate-50"}`, children: [_jsxs("div", { className: "flex items-center justify-between gap-2", children: [_jsx("span", { className: "text-sm font-semibold text-slate-700", children: cycleLabel }), total !== null ? (_jsx("span", { className: "text-[0.9375rem] font-bold text-slate-800", style: fontMono, children: formatPrice(total, "USD") })) : (_jsx("span", { className: "text-sm text-slate-400", children: "--" }))] }), base > 0 && (_jsxs("div", { className: "flex gap-4 mt-2 pt-2 border-t border-dashed border-slate-200", children: [!isMonthly && (_jsxs("div", { className: "flex-1 flex flex-col gap-0.5", children: [_jsx("span", { className: "text-[0.625rem] font-medium uppercase tracking-[0.06em] text-violet-500", style: fontMono, children: "Standard Price" }), _jsxs("span", { className: "text-[0.8125rem] text-slate-600 flex items-baseline gap-1.5", children: ["$", base, " \u00D7 ", shortLabel, _jsx("span", { className: "font-semibold text-slate-700", children: formatPrice(total ?? 0, "USD") })] })] })), _jsxs("div", { className: "flex-1 flex flex-col gap-0.5", children: [_jsx("span", { className: "text-[0.625rem] font-medium uppercase tracking-[0.06em] text-violet-500", style: fontMono, children: "Discount" }), _jsxs("div", { className: "flex items-center border border-slate-200 rounded-[10px] overflow-hidden transition-all duration-150 h-[34px] focus-within:border-violet-400 focus-within:shadow-[0_0_0_3px_rgba(124,58,237,0.1)]", children: [_jsx("input", { type: "number", value: editGroupDiscounts[cycle], onChange: (e) => setEditGroupDiscounts({
|
|
@@ -661,7 +818,7 @@ export function ServiceCatalog({ document, dispatch }) {
|
|
|
661
818
|
newSet.delete(tier.id);
|
|
662
819
|
}
|
|
663
820
|
setSelectedTierIds(newSet);
|
|
664
|
-
}, className: "w-[18px] h-[18px] shrink-0 accent-emerald-600 cursor-pointer" }), _jsx("span", { className: `flex-1 text-sm font-medium ${isSelected ? "text-emerald-800" : "text-slate-800"}`, children: tier.name }), tier.pricing
|
|
821
|
+
}, className: "w-[18px] h-[18px] shrink-0 accent-emerald-600 cursor-pointer" }), _jsx("span", { className: `flex-1 text-sm font-medium ${isSelected ? "text-emerald-800" : "text-slate-800"}`, children: tier.name }), tier.pricing.amount !== null && (_jsxs("span", { className: `text-xs font-medium whitespace-nowrap ${isSelected ? "text-emerald-600" : "text-slate-500"}`, children: ["$", tier.pricing.amount] }))] }, tier.id));
|
|
665
822
|
}) }), selectedTierIds.size === 0 && (_jsx("p", { className: "text-xs text-slate-500 mt-2 m-0 italic", children: "Select at least one tier to include this service" }))] })), tiers.length === 0 && (_jsxs("div", { className: "flex items-start gap-3 px-4 py-3.5 rounded-[10px] mb-5 bg-amber-50 border border-amber-200 text-amber-700", children: [_jsx("svg", { className: "w-5 h-5 shrink-0 mt-px", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.75", children: _jsx("path", { d: "M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z" }) }), _jsx("p", { className: "text-[0.8125rem] m-0 leading-relaxed", children: "No tiers defined yet. Define tiers in the Tier Definition tab first to specify which tiers include this service." })] })), _jsxs("div", { className: "flex gap-2", children: [_jsx("button", { onClick: handleAddService, disabled: !newService.title.trim(), className: "flex-1 px-4 py-2.5 text-[0.8125rem] font-semibold rounded-[10px] border-none cursor-pointer flex items-center justify-center gap-1.5 transition-all duration-150 text-white hover:enabled:-translate-y-px disabled:opacity-50 disabled:cursor-not-allowed", style: {
|
|
666
823
|
...fontSans,
|
|
667
824
|
background: "linear-gradient(135deg, #7c3aed 0%, #6d28d9 100%)",
|
|
@@ -695,8 +852,8 @@ function GroupButton({ group, serviceCount, isSelected, onSelect, onEdit, onDele
|
|
|
695
852
|
.join(", ") }))] }), _jsxs("div", { className: "flex items-center gap-2 text-xs text-slate-500 mt-0.5", children: [_jsxs("span", { children: [serviceCount, " services", serviceCount === 0 && (_jsxs("span", { className: "text-[0.6875rem] text-amber-600", children: [" ", "\u2014 add services"] }))] }), group.costType === "SETUP" && group.price != null && (_jsx("span", { className: "text-amber-600", children: formatPrice(group.price, "USD") })), group.isAddOn && group.price != null && (_jsx("span", { className: "text-amber-600", children: formatPrice(group.price, "USD") })), !isSetup &&
|
|
696
853
|
!group.isAddOn &&
|
|
697
854
|
(() => {
|
|
698
|
-
const monthlyPrice = group.tierDependentPricing?.[0]?.amount ??
|
|
699
|
-
group.standalonePricing?.amount;
|
|
855
|
+
const monthlyPrice = group.tierDependentPricing?.[0]?.recurringPricing?.find((p) => p.billingCycle === "MONTHLY")?.amount ??
|
|
856
|
+
group.standalonePricing?.recurringPricing?.find((p) => p.billingCycle === "MONTHLY")?.amount;
|
|
700
857
|
return monthlyPrice != null && monthlyPrice > 0 ? (_jsxs("span", { className: "text-amber-600", children: [formatPrice(monthlyPrice, "USD"), "/mo"] })) : null;
|
|
701
858
|
})()] })] }), isHovered && (_jsxs("div", { className: "absolute right-2.5 top-1/2 -translate-y-1/2 flex gap-0.5", style: { animation: "so-fade-in 150ms ease-out" }, children: [_jsx("button", { onClick: (e) => {
|
|
702
859
|
e.stopPropagation();
|
|
@@ -763,6 +920,6 @@ function ServiceCard({ service, tiers, optionGroups, onUpdate, onDelete, onToggl
|
|
|
763
920
|
? "border-emerald-500 bg-emerald-50 hover:border-emerald-600"
|
|
764
921
|
: "border-slate-200 hover:border-slate-300 hover:bg-slate-50"}`, children: [_jsx("input", { type: "checkbox", checked: isIncluded, onChange: (e) => {
|
|
765
922
|
onToggleTier(service.id, tier.id, e.target.checked);
|
|
766
|
-
}, className: "w-[18px] h-[18px] shrink-0 accent-emerald-600 cursor-pointer" }), _jsx("span", { className: `flex-1 text-sm font-medium ${isIncluded ? "text-emerald-800" : "text-slate-800"}`, children: tier.name }), tier.pricing
|
|
923
|
+
}, className: "w-[18px] h-[18px] shrink-0 accent-emerald-600 cursor-pointer" }), _jsx("span", { className: `flex-1 text-sm font-medium ${isIncluded ? "text-emerald-800" : "text-slate-800"}`, children: tier.name }), tier.pricing.amount !== null && (_jsxs("span", { className: `text-xs font-medium whitespace-nowrap ${isIncluded ? "text-emerald-600" : "text-slate-500"}`, children: ["$", tier.pricing.amount] }))] }, tier.id));
|
|
767
924
|
}) })] }))] }))] }));
|
|
768
925
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type DocumentDispatch } from "@powerhousedao/reactor-browser";
|
|
2
|
-
import type
|
|
2
|
+
import { type ServiceOfferingDocument, type ServiceOfferingAction } from "@powerhousedao/service-offering/document-models/service-offering";
|
|
3
3
|
interface TheMatrixProps {
|
|
4
4
|
document: ServiceOfferingDocument;
|
|
5
5
|
dispatch: DocumentDispatch<ServiceOfferingAction>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TheMatrix.d.ts","sourceRoot":"","sources":["../../../../editors/service-offering-editor/components/TheMatrix.tsx"],"names":[],"mappings":"AAEA,OAAO,EACL,KAAK,gBAAgB,EAEtB,MAAM,gCAAgC,CAAC;AACxC,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"TheMatrix.d.ts","sourceRoot":"","sources":["../../../../editors/service-offering-editor/components/TheMatrix.tsx"],"names":[],"mappings":"AAEA,OAAO,EACL,KAAK,gBAAgB,EAEtB,MAAM,gCAAgC,CAAC;AACxC,OAAO,EACL,KAAK,uBAAuB,EAC5B,KAAK,qBAAqB,EAS3B,MAAM,kEAAkE,CAAC;AA2B1E,UAAU,cAAc;IACtB,QAAQ,EAAE,uBAAuB,CAAC;IAClC,QAAQ,EAAE,gBAAgB,CAAC,qBAAqB,CAAC,CAAC;CACnD;AAgDD,wBAAgB,SAAS,CAAC,EAAE,QAAQ,EAAE,QAAQ,EAAE,EAAE,cAAc,2CAy7E/D"}
|