@dainamite/cpq 0.6.0 → 0.7.0
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/CHANGELOG.md +16 -0
- package/dist/modules/cpq/backend/cpq/inventory/AssetsTable.js +3 -9
- package/dist/modules/cpq/backend/cpq/inventory/AssetsTable.js.map +2 -2
- package/dist/modules/cpq/backend/cpq/inventory/SubscriptionsTable.js +21 -25
- package/dist/modules/cpq/backend/cpq/inventory/SubscriptionsTable.js.map +2 -2
- package/dist/modules/cpq/backend/cpq/inventory/assets/[id]/page.js +48 -47
- package/dist/modules/cpq/backend/cpq/inventory/assets/[id]/page.js.map +2 -2
- package/dist/modules/cpq/backend/cpq/inventory/assets/[id]/page.meta.js +1 -1
- package/dist/modules/cpq/backend/cpq/inventory/assets/[id]/page.meta.js.map +2 -2
- package/dist/modules/cpq/backend/cpq/inventory/page.meta.js +2 -2
- package/dist/modules/cpq/backend/cpq/inventory/page.meta.js.map +2 -2
- package/dist/modules/cpq/backend/cpq/inventory/shared.js +37 -2
- package/dist/modules/cpq/backend/cpq/inventory/shared.js.map +2 -2
- package/dist/modules/cpq/backend/cpq/inventory/subscriptions/[id]/page.js +154 -178
- package/dist/modules/cpq/backend/cpq/inventory/subscriptions/[id]/page.js.map +2 -2
- package/dist/modules/cpq/backend/cpq/inventory/subscriptions/[id]/page.meta.js +1 -1
- package/dist/modules/cpq/backend/cpq/inventory/subscriptions/[id]/page.meta.js.map +2 -2
- package/dist/modules/cpq/backend/cpq/offerings/[id]/page.js +168 -143
- package/dist/modules/cpq/backend/cpq/offerings/[id]/page.js.map +2 -2
- package/dist/modules/cpq/backend/cpq/offerings/page.js +36 -34
- package/dist/modules/cpq/backend/cpq/offerings/page.js.map +2 -2
- package/dist/modules/cpq/backend/cpq/orders/[id]/page.js +69 -66
- package/dist/modules/cpq/backend/cpq/orders/[id]/page.js.map +2 -2
- package/dist/modules/cpq/backend/cpq/orders/page.js +6 -6
- package/dist/modules/cpq/backend/cpq/orders/page.js.map +2 -2
- package/dist/modules/cpq/backend/cpq/price-rules/PriceRuleForm.js +41 -36
- package/dist/modules/cpq/backend/cpq/price-rules/PriceRuleForm.js.map +2 -2
- package/dist/modules/cpq/backend/cpq/price-rules/[id]/page.js +76 -72
- package/dist/modules/cpq/backend/cpq/price-rules/[id]/page.js.map +2 -2
- package/dist/modules/cpq/backend/cpq/price-rules/[id]/page.meta.js +1 -1
- package/dist/modules/cpq/backend/cpq/price-rules/[id]/page.meta.js.map +2 -2
- package/dist/modules/cpq/backend/cpq/price-rules/page.js +18 -15
- package/dist/modules/cpq/backend/cpq/price-rules/page.js.map +2 -2
- package/dist/modules/cpq/backend/cpq/pricing/[id]/EntriesEditor.js +23 -21
- package/dist/modules/cpq/backend/cpq/pricing/[id]/EntriesEditor.js.map +2 -2
- package/dist/modules/cpq/backend/cpq/pricing/[id]/ImportPreview.js +22 -50
- package/dist/modules/cpq/backend/cpq/pricing/[id]/ImportPreview.js.map +2 -2
- package/dist/modules/cpq/backend/cpq/pricing/[id]/page.js +74 -52
- package/dist/modules/cpq/backend/cpq/pricing/[id]/page.js.map +2 -2
- package/dist/modules/cpq/backend/cpq/pricing/[id]/xlsxImport.js +20 -17
- package/dist/modules/cpq/backend/cpq/pricing/[id]/xlsxImport.js.map +2 -2
- package/dist/modules/cpq/backend/cpq/pricing/page.js +1 -1
- package/dist/modules/cpq/backend/cpq/pricing/page.js.map +2 -2
- package/dist/modules/cpq/backend/cpq/quotes/[id]/_components/ArcQuoteConfigurator.js +115 -123
- package/dist/modules/cpq/backend/cpq/quotes/[id]/_components/ArcQuoteConfigurator.js.map +2 -2
- package/dist/modules/cpq/backend/cpq/quotes/[id]/_components/PriceAdjustmentDialog.js +6 -3
- package/dist/modules/cpq/backend/cpq/quotes/[id]/_components/PriceAdjustmentDialog.js.map +2 -2
- package/dist/modules/cpq/backend/cpq/quotes/[id]/page.js +129 -94
- package/dist/modules/cpq/backend/cpq/quotes/[id]/page.js.map +2 -2
- package/dist/modules/cpq/backend/cpq/quotes/page.js +23 -19
- package/dist/modules/cpq/backend/cpq/quotes/page.js.map +2 -2
- package/dist/modules/cpq/backend/cpq/specifications/[id]/DependsOnRulesEditor.js +19 -15
- package/dist/modules/cpq/backend/cpq/specifications/[id]/DependsOnRulesEditor.js.map +2 -2
- package/dist/modules/cpq/backend/cpq/specifications/[id]/page.js +171 -178
- package/dist/modules/cpq/backend/cpq/specifications/[id]/page.js.map +2 -2
- package/dist/modules/cpq/backend/cpq/specifications/page.js +2 -2
- package/dist/modules/cpq/backend/cpq/specifications/page.js.map +2 -2
- package/dist/modules/cpq/backend/cpq/wizards/[definitionCode]/detail/page.js +60 -50
- package/dist/modules/cpq/backend/cpq/wizards/[definitionCode]/detail/page.js.map +2 -2
- package/dist/modules/cpq/backend/cpq/wizards/[definitionCode]/page.js +22 -18
- package/dist/modules/cpq/backend/cpq/wizards/[definitionCode]/page.js.map +2 -2
- package/dist/modules/cpq/backend/cpq/wizards/page.js +1 -1
- package/dist/modules/cpq/backend/cpq/wizards/page.js.map +2 -2
- package/dist/modules/cpq/components/ArcLineDiff.js +2 -2
- package/dist/modules/cpq/components/ArcLineDiff.js.map +2 -2
- package/dist/modules/cpq/components/ChargeBreakdownTable.js +4 -10
- package/dist/modules/cpq/components/ChargeBreakdownTable.js.map +2 -2
- package/dist/modules/cpq/components/PriceWaterfall.js +3 -1
- package/dist/modules/cpq/components/PriceWaterfall.js.map +2 -2
- package/dist/modules/cpq/components/PricingSummaryCard.js +1 -6
- package/dist/modules/cpq/components/PricingSummaryCard.js.map +2 -2
- package/dist/modules/cpq/components/StatusPath.js +5 -3
- package/dist/modules/cpq/components/StatusPath.js.map +2 -2
- package/dist/modules/cpq/components/useCpqRowActions.js +10 -22
- package/dist/modules/cpq/components/useCpqRowActions.js.map +2 -2
- package/dist/modules/cpq/i18n/de.json +1220 -0
- package/dist/modules/cpq/i18n/en.json +1220 -0
- package/dist/modules/cpq/i18n/es.json +1220 -0
- package/dist/modules/cpq/i18n/pl.json +1220 -0
- package/dist/modules/cpq/widgets/injection/customer-inventory/widget.client.js +39 -31
- package/dist/modules/cpq/widgets/injection/customer-inventory/widget.client.js.map +2 -2
- package/dist/modules/cpq/widgets/injection/order-cpq-tab/widget.client.js +13 -5
- package/dist/modules/cpq/widgets/injection/order-cpq-tab/widget.client.js.map +2 -2
- package/dist/modules/cpq/widgets/injection/quote-configurator/widget.client.js +41 -21
- package/dist/modules/cpq/widgets/injection/quote-configurator/widget.client.js.map +2 -2
- package/dist/modules/cpq/widgets/injection-table.js +2 -2
- package/dist/modules/cpq/widgets/injection-table.js.map +2 -2
- package/dist/modules/cpq/workflows/WizardRunner.js +10 -8
- package/dist/modules/cpq/workflows/WizardRunner.js.map +2 -2
- package/dist/modules/cpq/workflows/WizardTrigger.js +15 -9
- package/dist/modules/cpq/workflows/WizardTrigger.js.map +2 -2
- package/dist/modules/cpq/workflows/steps/CustomerSelectStep.js +9 -7
- package/dist/modules/cpq/workflows/steps/CustomerSelectStep.js.map +2 -2
- package/dist/modules/cpq/workflows/steps/InventorySelectStep.js +9 -4
- package/dist/modules/cpq/workflows/steps/InventorySelectStep.js.map +2 -2
- package/dist/modules/cpq/workflows/steps/ItemListStep.js +16 -19
- package/dist/modules/cpq/workflows/steps/ItemListStep.js.map +2 -2
- package/dist/modules/cpq/workflows/steps/OfferingSelectStep.js +19 -32
- package/dist/modules/cpq/workflows/steps/OfferingSelectStep.js.map +2 -2
- package/dist/modules/cpq/workflows/steps/ProductConfigureStep.js +8 -6
- package/dist/modules/cpq/workflows/steps/ProductConfigureStep.js.map +2 -2
- package/dist/modules/cpq/workflows/steps/ReviewStep.js +32 -30
- package/dist/modules/cpq/workflows/steps/ReviewStep.js.map +2 -2
- package/dist/modules/cpq/workflows/steps/index.js +12 -0
- package/dist/modules/cpq/workflows/steps/index.js.map +2 -2
- package/package.json +1 -1
- package/src/modules/cpq/__tests__/i18n/dictionaries.test.ts +62 -0
- package/src/modules/cpq/__tests__/i18n/hardcodedStrings.test.ts +35 -0
- package/src/modules/cpq/__tests__/i18n/sourceScan.ts +109 -0
- package/src/modules/cpq/backend/cpq/inventory/AssetsTable.tsx +3 -9
- package/src/modules/cpq/backend/cpq/inventory/SubscriptionsTable.tsx +22 -26
- package/src/modules/cpq/backend/cpq/inventory/assets/[id]/page.meta.ts +1 -1
- package/src/modules/cpq/backend/cpq/inventory/assets/[id]/page.tsx +43 -46
- package/src/modules/cpq/backend/cpq/inventory/page.meta.ts +2 -2
- package/src/modules/cpq/backend/cpq/inventory/shared.tsx +37 -1
- package/src/modules/cpq/backend/cpq/inventory/subscriptions/[id]/page.meta.ts +1 -1
- package/src/modules/cpq/backend/cpq/inventory/subscriptions/[id]/page.tsx +134 -112
- package/src/modules/cpq/backend/cpq/offerings/[id]/page.tsx +169 -130
- package/src/modules/cpq/backend/cpq/offerings/page.tsx +34 -24
- package/src/modules/cpq/backend/cpq/orders/[id]/page.tsx +66 -43
- package/src/modules/cpq/backend/cpq/orders/page.tsx +6 -6
- package/src/modules/cpq/backend/cpq/price-rules/PriceRuleForm.tsx +48 -34
- package/src/modules/cpq/backend/cpq/price-rules/[id]/page.meta.ts +1 -1
- package/src/modules/cpq/backend/cpq/price-rules/[id]/page.tsx +76 -70
- package/src/modules/cpq/backend/cpq/price-rules/page.tsx +25 -16
- package/src/modules/cpq/backend/cpq/pricing/[id]/EntriesEditor.tsx +24 -18
- package/src/modules/cpq/backend/cpq/pricing/[id]/ImportPreview.tsx +29 -19
- package/src/modules/cpq/backend/cpq/pricing/[id]/page.tsx +95 -47
- package/src/modules/cpq/backend/cpq/pricing/[id]/xlsxImport.ts +23 -15
- package/src/modules/cpq/backend/cpq/pricing/page.tsx +1 -1
- package/src/modules/cpq/backend/cpq/quotes/[id]/_components/ArcQuoteConfigurator.tsx +111 -88
- package/src/modules/cpq/backend/cpq/quotes/[id]/_components/PriceAdjustmentDialog.tsx +3 -3
- package/src/modules/cpq/backend/cpq/quotes/[id]/page.tsx +134 -89
- package/src/modules/cpq/backend/cpq/quotes/page.tsx +29 -21
- package/src/modules/cpq/backend/cpq/specifications/[id]/DependsOnRulesEditor.tsx +19 -15
- package/src/modules/cpq/backend/cpq/specifications/[id]/page.tsx +171 -171
- package/src/modules/cpq/backend/cpq/specifications/page.tsx +2 -2
- package/src/modules/cpq/backend/cpq/wizards/[definitionCode]/detail/page.tsx +51 -41
- package/src/modules/cpq/backend/cpq/wizards/[definitionCode]/page.tsx +17 -13
- package/src/modules/cpq/backend/cpq/wizards/page.tsx +1 -1
- package/src/modules/cpq/components/ArcLineDiff.tsx +2 -2
- package/src/modules/cpq/components/ChargeBreakdownTable.tsx +4 -2
- package/src/modules/cpq/components/PriceWaterfall.tsx +4 -2
- package/src/modules/cpq/components/PricingSummaryCard.tsx +1 -1
- package/src/modules/cpq/components/StatusPath.tsx +7 -4
- package/src/modules/cpq/components/useCpqRowActions.tsx +17 -25
- package/src/modules/cpq/i18n/de.json +1220 -0
- package/src/modules/cpq/i18n/en.json +1220 -0
- package/src/modules/cpq/i18n/es.json +1220 -0
- package/src/modules/cpq/i18n/pl.json +1220 -0
- package/src/modules/cpq/widgets/injection/customer-inventory/widget.client.tsx +38 -31
- package/src/modules/cpq/widgets/injection/order-cpq-tab/widget.client.tsx +7 -5
- package/src/modules/cpq/widgets/injection/quote-configurator/widget.client.tsx +36 -21
- package/src/modules/cpq/widgets/injection-table.ts +8 -2
- package/src/modules/cpq/workflows/WizardRunner.tsx +8 -5
- package/src/modules/cpq/workflows/WizardTrigger.tsx +15 -9
- package/src/modules/cpq/workflows/steps/CustomerSelectStep.tsx +11 -7
- package/src/modules/cpq/workflows/steps/InventorySelectStep.tsx +9 -5
- package/src/modules/cpq/workflows/steps/ItemListStep.tsx +18 -12
- package/src/modules/cpq/workflows/steps/OfferingSelectStep.tsx +20 -16
- package/src/modules/cpq/workflows/steps/ProductConfigureStep.tsx +8 -6
- package/src/modules/cpq/workflows/steps/ReviewStep.tsx +33 -18
- package/src/modules/cpq/workflows/steps/index.ts +12 -0
- package/src/modules/cpq/workflows/types.ts +4 -0
|
@@ -54,16 +54,44 @@ const EMPTY_CHARGE = {
|
|
|
54
54
|
sortOrder: 0,
|
|
55
55
|
isActive: true
|
|
56
56
|
};
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
57
|
+
function chargeModelLabel(t, model) {
|
|
58
|
+
switch (model) {
|
|
59
|
+
case "flat":
|
|
60
|
+
return t("cpq.offerings.chargeModel.flat", "Flat Fee");
|
|
61
|
+
case "per_unit":
|
|
62
|
+
return t("cpq.offerings.chargeModel.perUnit", "Per Unit");
|
|
63
|
+
case "volume":
|
|
64
|
+
return t("cpq.offerings.chargeModel.volume", "Volume-based");
|
|
65
|
+
case "tiered":
|
|
66
|
+
return t("cpq.offerings.chargeModel.tiered", "Tiered");
|
|
67
|
+
default:
|
|
68
|
+
return model;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
function pricingSourceLabel(t, source) {
|
|
72
|
+
switch (source) {
|
|
73
|
+
case "fixed":
|
|
74
|
+
return t("cpq.offerings.pricingMethod.fixed", "Fixed Price");
|
|
75
|
+
case "table":
|
|
76
|
+
return t("cpq.offerings.pricingMethod.table", "Table Lookup");
|
|
77
|
+
default:
|
|
78
|
+
return source;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
function chargeMissingFieldLabel(t, field) {
|
|
82
|
+
switch (field) {
|
|
83
|
+
case "fixedPrice":
|
|
84
|
+
return t("cpq.offerings.charge.fields.fixedPrice", "Fixed Price");
|
|
85
|
+
case "currency":
|
|
86
|
+
return t("cpq.offerings.charge.fields.currency", "Currency");
|
|
87
|
+
case "quantityAttribute":
|
|
88
|
+
return t("cpq.offerings.charge.fields.quantityAttribute", "Quantity Attribute");
|
|
89
|
+
case "pricingTable":
|
|
90
|
+
return t("cpq.offerings.charge.fields.pricingTable", "Pricing Table");
|
|
91
|
+
case "priceColumn":
|
|
92
|
+
return t("cpq.offerings.charge.fields.priceColumn", "Price Column");
|
|
93
|
+
}
|
|
94
|
+
}
|
|
67
95
|
function isChargeComplete(charge) {
|
|
68
96
|
return chargeMissingFields(charge).length === 0;
|
|
69
97
|
}
|
|
@@ -71,13 +99,13 @@ function chargeMissingFields(charge) {
|
|
|
71
99
|
const { model, source } = normalizeChargePricing(charge);
|
|
72
100
|
const missing = [];
|
|
73
101
|
if (source === "fixed") {
|
|
74
|
-
if (!charge.fixedPrice) missing.push("
|
|
75
|
-
if (!charge.currencyCode) missing.push("
|
|
76
|
-
if (model === "per_unit" && !charge.quantityAttributeCode) missing.push("
|
|
102
|
+
if (!charge.fixedPrice) missing.push("fixedPrice");
|
|
103
|
+
if (!charge.currencyCode) missing.push("currency");
|
|
104
|
+
if (model === "per_unit" && !charge.quantityAttributeCode) missing.push("quantityAttribute");
|
|
77
105
|
} else {
|
|
78
|
-
if (!charge.pricingTableId) missing.push("
|
|
79
|
-
if (!charge.priceColumnKey) missing.push("
|
|
80
|
-
if (model !== "flat" && !charge.quantityAttributeCode) missing.push("
|
|
106
|
+
if (!charge.pricingTableId) missing.push("pricingTable");
|
|
107
|
+
if (!charge.priceColumnKey) missing.push("priceColumn");
|
|
108
|
+
if (model !== "flat" && !charge.quantityAttributeCode) missing.push("quantityAttribute");
|
|
81
109
|
}
|
|
82
110
|
return missing;
|
|
83
111
|
}
|
|
@@ -118,7 +146,7 @@ function OfferingDetailPage(props) {
|
|
|
118
146
|
if (isNew) return;
|
|
119
147
|
const res = await fetch(`/api/cpq/product-offerings?id=${encodeURIComponent(offeringId)}`);
|
|
120
148
|
if (!res.ok) {
|
|
121
|
-
if (!cancelled) setError("Failed to load offering");
|
|
149
|
+
if (!cancelled) setError(t("cpq.offerings.detail.error.load", "Failed to load offering"));
|
|
122
150
|
return;
|
|
123
151
|
}
|
|
124
152
|
const data = await res.json();
|
|
@@ -159,7 +187,7 @@ function OfferingDetailPage(props) {
|
|
|
159
187
|
}
|
|
160
188
|
} catch (err) {
|
|
161
189
|
console.error("Failed to load", err);
|
|
162
|
-
if (!cancelled) setError("Failed to load");
|
|
190
|
+
if (!cancelled) setError(t("cpq.offerings.detail.error.loadGeneric", "Failed to load"));
|
|
163
191
|
} finally {
|
|
164
192
|
if (!cancelled) setLoading(false);
|
|
165
193
|
}
|
|
@@ -196,7 +224,7 @@ function OfferingDetailPage(props) {
|
|
|
196
224
|
});
|
|
197
225
|
if (!res.ok) {
|
|
198
226
|
const d = await res.json();
|
|
199
|
-
setError(d.error ?? "Failed to save");
|
|
227
|
+
setError(d.error ?? t("cpq.offerings.detail.error.save", "Failed to save"));
|
|
200
228
|
return;
|
|
201
229
|
}
|
|
202
230
|
const saved = await res.json();
|
|
@@ -220,7 +248,7 @@ function OfferingDetailPage(props) {
|
|
|
220
248
|
setGeneralMode("view");
|
|
221
249
|
}
|
|
222
250
|
} catch {
|
|
223
|
-
setError("Failed to save");
|
|
251
|
+
setError(t("cpq.offerings.detail.error.save", "Failed to save"));
|
|
224
252
|
} finally {
|
|
225
253
|
setSaving(false);
|
|
226
254
|
}
|
|
@@ -237,10 +265,10 @@ function OfferingDetailPage(props) {
|
|
|
237
265
|
router.push("/backend/cpq/offerings");
|
|
238
266
|
} else {
|
|
239
267
|
const d = await res.json();
|
|
240
|
-
setError(d.error ?? "Failed to delete");
|
|
268
|
+
setError(d.error ?? t("cpq.offerings.detail.error.delete", "Failed to delete"));
|
|
241
269
|
}
|
|
242
270
|
} catch {
|
|
243
|
-
setError("Failed to delete");
|
|
271
|
+
setError(t("cpq.offerings.detail.error.delete", "Failed to delete"));
|
|
244
272
|
}
|
|
245
273
|
};
|
|
246
274
|
const loadPricingTables = async () => {
|
|
@@ -273,7 +301,7 @@ function OfferingDetailPage(props) {
|
|
|
273
301
|
});
|
|
274
302
|
if (!res.ok) {
|
|
275
303
|
const d = await res.json();
|
|
276
|
-
setError(d.error ?? "Failed to save charge");
|
|
304
|
+
setError(d.error ?? t("cpq.offerings.detail.error.saveCharge", "Failed to save charge"));
|
|
277
305
|
return;
|
|
278
306
|
}
|
|
279
307
|
const offeringRes = await fetch(`/api/cpq/product-offerings?id=${encodeURIComponent(offeringId)}`);
|
|
@@ -283,13 +311,13 @@ function OfferingDetailPage(props) {
|
|
|
283
311
|
}
|
|
284
312
|
setEditingCharge(null);
|
|
285
313
|
} catch {
|
|
286
|
-
setError("Failed to save charge");
|
|
314
|
+
setError(t("cpq.offerings.detail.error.saveCharge", "Failed to save charge"));
|
|
287
315
|
} finally {
|
|
288
316
|
setSaving(false);
|
|
289
317
|
}
|
|
290
318
|
};
|
|
291
319
|
const deleteCharge = async (chargeId) => {
|
|
292
|
-
if (!confirm("Delete this charge?")) return;
|
|
320
|
+
if (!confirm(t("cpq.offerings.detail.confirmDeleteCharge", "Delete this charge?"))) return;
|
|
293
321
|
try {
|
|
294
322
|
const res = await fetch("/api/cpq/product-charges", {
|
|
295
323
|
method: "DELETE",
|
|
@@ -298,13 +326,13 @@ function OfferingDetailPage(props) {
|
|
|
298
326
|
});
|
|
299
327
|
if (res.ok) setCharges((prev) => prev.filter((c) => c.id !== chargeId));
|
|
300
328
|
} catch {
|
|
301
|
-
setError("Failed to delete charge");
|
|
329
|
+
setError(t("cpq.offerings.detail.error.deleteCharge", "Failed to delete charge"));
|
|
302
330
|
}
|
|
303
331
|
};
|
|
304
332
|
const selectedPricingTable = editingCharge?.pricingTableId ? pricingTables.find((pt) => pt.id === editingCharge.pricingTableId) : null;
|
|
305
333
|
const designTimeAttrs = attributes.filter((a) => a.resolutionTime === "design_time");
|
|
306
334
|
if (loading) {
|
|
307
|
-
return /* @__PURE__ */ jsx("div", { className: "text-sm text-muted-foreground", children: t("common.loading", "Loading...") });
|
|
335
|
+
return /* @__PURE__ */ jsx("div", { className: "text-sm text-muted-foreground", children: t("cpq.common.loading", "Loading...") });
|
|
308
336
|
}
|
|
309
337
|
return /* @__PURE__ */ jsxs("div", { className: "space-y-6", children: [
|
|
310
338
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
|
|
@@ -316,14 +344,15 @@ function OfferingDetailPage(props) {
|
|
|
316
344
|
className: "text-sm text-muted-foreground hover:text-foreground",
|
|
317
345
|
children: [
|
|
318
346
|
"\u2190 ",
|
|
319
|
-
t("common.back", "Back")
|
|
347
|
+
t("cpq.common.back", "Back")
|
|
320
348
|
]
|
|
321
349
|
}
|
|
322
350
|
),
|
|
323
351
|
/* @__PURE__ */ jsx("h1", { className: "text-2xl font-bold", children: isNew ? t("cpq.offerings.new", "New Offering") : form.name }),
|
|
324
352
|
!isNew && /* @__PURE__ */ jsx(Tag, { variant: lifecycleStatusMap[form.lifecycleStatus] ?? "neutral", dot: true, children: formatStatusLabel(form.lifecycleStatus) }),
|
|
325
353
|
specDetail && /* @__PURE__ */ jsxs("span", { className: "text-sm text-muted-foreground", children: [
|
|
326
|
-
"Spec:
|
|
354
|
+
t("cpq.offerings.detail.specLabel", "Spec:"),
|
|
355
|
+
" ",
|
|
327
356
|
/* @__PURE__ */ jsx("button", { onClick: () => router.push(`/backend/cpq/specifications/${specDetail.id}`), className: "text-primary hover:underline", children: specDetail.name })
|
|
328
357
|
] })
|
|
329
358
|
] }),
|
|
@@ -337,10 +366,10 @@ function OfferingDetailPage(props) {
|
|
|
337
366
|
setDesignTimeSnapshot(designTimeValues);
|
|
338
367
|
setGeneralMode("edit");
|
|
339
368
|
},
|
|
340
|
-
children: t("common.edit", "Edit")
|
|
369
|
+
children: t("cpq.common.edit", "Edit")
|
|
341
370
|
}
|
|
342
371
|
),
|
|
343
|
-
/* @__PURE__ */ jsx(Button, { type: "button", variant: "destructive", onClick: deleteOffering, children: t("common.delete", "Delete") })
|
|
372
|
+
/* @__PURE__ */ jsx(Button, { type: "button", variant: "destructive", onClick: deleteOffering, children: t("cpq.common.delete", "Delete") })
|
|
344
373
|
] })
|
|
345
374
|
] }),
|
|
346
375
|
error && /* @__PURE__ */ jsx(Alert, { variant: "destructive", children: error }),
|
|
@@ -354,16 +383,16 @@ function OfferingDetailPage(props) {
|
|
|
354
383
|
onClick: () => setTab(t_),
|
|
355
384
|
className: `px-4 py-2 text-sm font-medium border-b-2 transition-colors ${tab === t_ ? "border-primary text-primary" : "border-transparent text-muted-foreground hover:text-foreground"}`,
|
|
356
385
|
children: [
|
|
357
|
-
t_ === "general" && "General",
|
|
358
|
-
t_ === "charges" &&
|
|
359
|
-
t_ === "components" &&
|
|
386
|
+
t_ === "general" && t("cpq.offerings.detail.tabs.general", "General"),
|
|
387
|
+
t_ === "charges" && t("cpq.offerings.detail.tabs.charges", "Charges ({count})", { count: charges.length }),
|
|
388
|
+
t_ === "components" && t("cpq.offerings.detail.tabs.components", "Components ({count})", { count: components.length })
|
|
360
389
|
]
|
|
361
390
|
},
|
|
362
391
|
t_
|
|
363
392
|
)) }),
|
|
364
393
|
(isNew || tab === "general") && /* @__PURE__ */ jsxs("div", { className: "rounded-lg border bg-card p-6 space-y-4", children: [
|
|
365
394
|
isNew && /* @__PURE__ */ jsxs("div", { children: [
|
|
366
|
-
/* @__PURE__ */ jsx("label", { className: "block text-sm font-medium mb-1", children: "Specification" }),
|
|
395
|
+
/* @__PURE__ */ jsx("label", { className: "block text-sm font-medium mb-1", children: t("cpq.offerings.detail.specification", "Specification") }),
|
|
367
396
|
/* @__PURE__ */ jsxs(
|
|
368
397
|
"select",
|
|
369
398
|
{
|
|
@@ -375,7 +404,7 @@ function OfferingDetailPage(props) {
|
|
|
375
404
|
},
|
|
376
405
|
className: "w-full rounded-md border px-3 py-2 text-sm",
|
|
377
406
|
children: [
|
|
378
|
-
/* @__PURE__ */ jsx("option", { value: "", children: "Select a specification..." }),
|
|
407
|
+
/* @__PURE__ */ jsx("option", { value: "", children: t("cpq.offerings.detail.selectSpecification", "Select a specification...") }),
|
|
379
408
|
specs.map((s) => /* @__PURE__ */ jsxs("option", { value: s.id, children: [
|
|
380
409
|
s.name,
|
|
381
410
|
" (",
|
|
@@ -395,7 +424,7 @@ function OfferingDetailPage(props) {
|
|
|
395
424
|
type: "text",
|
|
396
425
|
value: form.code,
|
|
397
426
|
onChange: (e) => setForm({ ...form, code: e.target.value }),
|
|
398
|
-
placeholder: "e.g. gix-cloud-connect-aws",
|
|
427
|
+
placeholder: t("cpq.offerings.detail.codePlaceholder", "e.g. gix-cloud-connect-aws"),
|
|
399
428
|
className: "w-full rounded-md border px-3 py-2 text-sm"
|
|
400
429
|
}
|
|
401
430
|
)
|
|
@@ -421,16 +450,16 @@ function OfferingDetailPage(props) {
|
|
|
421
450
|
onChange: (e) => setForm({ ...form, lifecycleStatus: e.target.value }),
|
|
422
451
|
className: "w-full rounded-md border px-3 py-2 text-sm",
|
|
423
452
|
children: [
|
|
424
|
-
/* @__PURE__ */ jsx("option", { value: "draft", children: "Draft" }),
|
|
425
|
-
/* @__PURE__ */ jsx("option", { value: "active", children: "Active" }),
|
|
426
|
-
/* @__PURE__ */ jsx("option", { value: "deprecated", children: "Deprecated" })
|
|
453
|
+
/* @__PURE__ */ jsx("option", { value: "draft", children: t("cpq.offerings.lifecycle.draft", "Draft") }),
|
|
454
|
+
/* @__PURE__ */ jsx("option", { value: "active", children: t("cpq.offerings.lifecycle.active", "Active") }),
|
|
455
|
+
/* @__PURE__ */ jsx("option", { value: "deprecated", children: t("cpq.offerings.lifecycle.deprecated", "Deprecated") })
|
|
427
456
|
]
|
|
428
457
|
}
|
|
429
458
|
)
|
|
430
459
|
] }),
|
|
431
460
|
/* @__PURE__ */ jsxs("div", { children: [
|
|
432
461
|
/* @__PURE__ */ jsx("label", { className: "block text-sm font-medium mb-1", children: t("cpq.offerings.isActive", "Is Active?") }),
|
|
433
|
-
/* @__PURE__ */ jsx("div", { className: "flex items-center h-[38px]", children: generalMode === "view" && !isNew ? /* @__PURE__ */ jsx(Tag, { variant: form.isActive ? "success" : "neutral", dot: true, children: form.isActive ? t("common.yes", "Yes") : t("common.no", "No") }) : /* @__PURE__ */ jsx(
|
|
462
|
+
/* @__PURE__ */ jsx("div", { className: "flex items-center h-[38px]", children: generalMode === "view" && !isNew ? /* @__PURE__ */ jsx(Tag, { variant: form.isActive ? "success" : "neutral", dot: true, children: form.isActive ? t("cpq.common.yes", "Yes") : t("cpq.common.no", "No") }) : /* @__PURE__ */ jsx(
|
|
434
463
|
"input",
|
|
435
464
|
{
|
|
436
465
|
type: "checkbox",
|
|
@@ -454,7 +483,7 @@ function OfferingDetailPage(props) {
|
|
|
454
483
|
)
|
|
455
484
|
] }),
|
|
456
485
|
designTimeAttrs.length > 0 && /* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
|
|
457
|
-
/* @__PURE__ */ jsx("label", { className: "block text-sm font-medium", children: "Design-Time Values" }),
|
|
486
|
+
/* @__PURE__ */ jsx("label", { className: "block text-sm font-medium", children: t("cpq.offerings.detail.designTimeValues", "Design-Time Values") }),
|
|
458
487
|
/* @__PURE__ */ jsx("div", { className: "grid grid-cols-2 gap-3", children: designTimeAttrs.map((attr) => {
|
|
459
488
|
const value = designTimeValues[attr.code];
|
|
460
489
|
const isViewing = generalMode === "view" && !isNew;
|
|
@@ -464,18 +493,14 @@ function OfferingDetailPage(props) {
|
|
|
464
493
|
attr.name,
|
|
465
494
|
attr.isRequired && /* @__PURE__ */ jsx("span", { className: "text-destructive ml-0.5", children: "*" })
|
|
466
495
|
] }),
|
|
467
|
-
isViewing ? /* @__PURE__ */ jsx("p", { className: "text-sm py-2", children: value == null || value === "" ? /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "\u2014" }) : attr.attributeType === "boolean" ? /* @__PURE__ */ jsx(Tag, { variant: value ? "success" : "neutral", dot: true, children: value ? t("common.yes", "Yes") : t("common.no", "No") }) : optionLabel ?? String(value) }) : (attr.attributeType === "select" || attr.attributeType === "enum") && attr.options ? /* @__PURE__ */ jsxs(
|
|
496
|
+
isViewing ? /* @__PURE__ */ jsx("p", { className: "text-sm py-2", children: value == null || value === "" ? /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "\u2014" }) : attr.attributeType === "boolean" ? /* @__PURE__ */ jsx(Tag, { variant: value ? "success" : "neutral", dot: true, children: value ? t("cpq.common.yes", "Yes") : t("cpq.common.no", "No") }) : optionLabel ?? String(value) }) : (attr.attributeType === "select" || attr.attributeType === "enum") && attr.options ? /* @__PURE__ */ jsxs(
|
|
468
497
|
"select",
|
|
469
498
|
{
|
|
470
499
|
value: String(value ?? ""),
|
|
471
500
|
onChange: (e) => setDesignTimeValues({ ...designTimeValues, [attr.code]: e.target.value || null }),
|
|
472
501
|
className: "w-full rounded-md border px-2 py-1.5 text-sm",
|
|
473
502
|
children: [
|
|
474
|
-
/* @__PURE__ */
|
|
475
|
-
"Select ",
|
|
476
|
-
attr.name,
|
|
477
|
-
"..."
|
|
478
|
-
] }),
|
|
503
|
+
/* @__PURE__ */ jsx("option", { value: "", children: t("cpq.offerings.detail.selectAttribute", "Select {name}...", { name: attr.name }) }),
|
|
479
504
|
attr.options.map((opt) => /* @__PURE__ */ jsx("option", { value: opt.value, children: opt.label }, opt.value))
|
|
480
505
|
]
|
|
481
506
|
}
|
|
@@ -517,7 +542,7 @@ function OfferingDetailPage(props) {
|
|
|
517
542
|
type: "button",
|
|
518
543
|
onClick: saveOffering,
|
|
519
544
|
disabled: saving || !form.code || !form.name || isNew && !form.specId,
|
|
520
|
-
children: saving ? t("common.saving", "Saving...") : t("common.save", "Save")
|
|
545
|
+
children: saving ? t("cpq.common.saving", "Saving...") : t("cpq.common.save", "Save")
|
|
521
546
|
}
|
|
522
547
|
),
|
|
523
548
|
/* @__PURE__ */ jsx(
|
|
@@ -536,7 +561,7 @@ function OfferingDetailPage(props) {
|
|
|
536
561
|
setDesignTimeSnapshot(null);
|
|
537
562
|
setGeneralMode("view");
|
|
538
563
|
},
|
|
539
|
-
children: t("common.cancel", "Cancel")
|
|
564
|
+
children: t("cpq.common.cancel", "Cancel")
|
|
540
565
|
}
|
|
541
566
|
)
|
|
542
567
|
] })
|
|
@@ -551,26 +576,26 @@ function OfferingDetailPage(props) {
|
|
|
551
576
|
}
|
|
552
577
|
) }),
|
|
553
578
|
editingCharge && /* @__PURE__ */ jsxs("div", { className: "rounded-lg border bg-card p-4 space-y-3", children: [
|
|
554
|
-
/* @__PURE__ */ jsx("h3", { className: "font-medium text-sm", children: editingCharge.id ? "Edit Charge" : "New Charge" }),
|
|
579
|
+
/* @__PURE__ */ jsx("h3", { className: "font-medium text-sm", children: editingCharge.id ? t("cpq.offerings.charge.form.editTitle", "Edit Charge") : t("cpq.offerings.charge.form.newTitle", "New Charge") }),
|
|
555
580
|
/* @__PURE__ */ jsxs("div", { className: "grid grid-cols-3 gap-3", children: [
|
|
556
581
|
/* @__PURE__ */ jsxs("div", { children: [
|
|
557
|
-
/* @__PURE__ */ jsx("label", { className: "block text-xs font-medium mb-1", children: "Code" }),
|
|
558
|
-
/* @__PURE__ */ jsx("input", { type: "text", value: editingCharge.code, onChange: (e) => setEditingCharge({ ...editingCharge, code: e.target.value }), placeholder: "e.g. mrc-monthly", className: "w-full rounded-md border px-2 py-1.5 text-sm" })
|
|
582
|
+
/* @__PURE__ */ jsx("label", { className: "block text-xs font-medium mb-1", children: t("cpq.offerings.charge.fields.code", "Code") }),
|
|
583
|
+
/* @__PURE__ */ jsx("input", { type: "text", value: editingCharge.code, onChange: (e) => setEditingCharge({ ...editingCharge, code: e.target.value }), placeholder: t("cpq.offerings.charge.fields.codePlaceholder", "e.g. mrc-monthly"), className: "w-full rounded-md border px-2 py-1.5 text-sm" })
|
|
559
584
|
] }),
|
|
560
585
|
/* @__PURE__ */ jsxs("div", { children: [
|
|
561
|
-
/* @__PURE__ */ jsx("label", { className: "block text-xs font-medium mb-1", children: "Name" }),
|
|
586
|
+
/* @__PURE__ */ jsx("label", { className: "block text-xs font-medium mb-1", children: t("cpq.offerings.charge.fields.name", "Name") }),
|
|
562
587
|
/* @__PURE__ */ jsx("input", { type: "text", value: editingCharge.name, onChange: (e) => setEditingCharge({ ...editingCharge, name: e.target.value }), className: "w-full rounded-md border px-2 py-1.5 text-sm" })
|
|
563
588
|
] }),
|
|
564
589
|
/* @__PURE__ */ jsxs("div", { children: [
|
|
565
|
-
/* @__PURE__ */ jsx("label", { className: "block text-xs font-medium mb-1", children: "Charge Type" }),
|
|
590
|
+
/* @__PURE__ */ jsx("label", { className: "block text-xs font-medium mb-1", children: t("cpq.offerings.charge.fields.chargeType", "Charge Type") }),
|
|
566
591
|
/* @__PURE__ */ jsxs("select", { value: editingCharge.chargeType, onChange: (e) => setEditingCharge({ ...editingCharge, chargeType: e.target.value }), className: "w-full rounded-md border px-2 py-1.5 text-sm", children: [
|
|
567
|
-
/* @__PURE__ */ jsx("option", { value: "mrc", children: "MRC (Monthly Recurring)" }),
|
|
568
|
-
/* @__PURE__ */ jsx("option", { value: "nrc", children: "NRC (Non-Recurring)" }),
|
|
569
|
-
/* @__PURE__ */ jsx("option", { value: "usage", children: "Usage" })
|
|
592
|
+
/* @__PURE__ */ jsx("option", { value: "mrc", children: t("cpq.offerings.chargeType.mrc", "MRC (Monthly Recurring)") }),
|
|
593
|
+
/* @__PURE__ */ jsx("option", { value: "nrc", children: t("cpq.offerings.chargeType.nrc", "NRC (Non-Recurring)") }),
|
|
594
|
+
/* @__PURE__ */ jsx("option", { value: "usage", children: t("cpq.offerings.chargeType.usage", "Usage") })
|
|
570
595
|
] })
|
|
571
596
|
] }),
|
|
572
597
|
/* @__PURE__ */ jsxs("div", { children: [
|
|
573
|
-
/* @__PURE__ */ jsx("label", { className: "block text-xs font-medium mb-1", children: "Charge Model" }),
|
|
598
|
+
/* @__PURE__ */ jsx("label", { className: "block text-xs font-medium mb-1", children: t("cpq.offerings.charge.fields.chargeModel", "Charge Model") }),
|
|
574
599
|
/* @__PURE__ */ jsxs(
|
|
575
600
|
"select",
|
|
576
601
|
{
|
|
@@ -587,16 +612,16 @@ function OfferingDetailPage(props) {
|
|
|
587
612
|
},
|
|
588
613
|
className: "w-full rounded-md border px-2 py-1.5 text-sm",
|
|
589
614
|
children: [
|
|
590
|
-
/* @__PURE__ */ jsx("option", { value: "flat", children:
|
|
591
|
-
/* @__PURE__ */ jsx("option", { value: "per_unit", children:
|
|
592
|
-
/* @__PURE__ */ jsx("option", { value: "volume", children: "
|
|
593
|
-
/* @__PURE__ */ jsx("option", { value: "tiered", children: "
|
|
615
|
+
/* @__PURE__ */ jsx("option", { value: "flat", children: chargeModelLabel(t, "flat") }),
|
|
616
|
+
/* @__PURE__ */ jsx("option", { value: "per_unit", children: chargeModelLabel(t, "per_unit") }),
|
|
617
|
+
/* @__PURE__ */ jsx("option", { value: "volume", children: chargeModelLabel(t, "volume") }),
|
|
618
|
+
/* @__PURE__ */ jsx("option", { value: "tiered", children: chargeModelLabel(t, "tiered") })
|
|
594
619
|
]
|
|
595
620
|
}
|
|
596
621
|
)
|
|
597
622
|
] }),
|
|
598
623
|
/* @__PURE__ */ jsxs("div", { children: [
|
|
599
|
-
/* @__PURE__ */ jsx("label", { className: "block text-xs font-medium mb-1", children: "Pricing Method" }),
|
|
624
|
+
/* @__PURE__ */ jsx("label", { className: "block text-xs font-medium mb-1", children: t("cpq.offerings.charge.fields.pricingMethod", "Pricing Method") }),
|
|
600
625
|
/* @__PURE__ */ jsxs(
|
|
601
626
|
"select",
|
|
602
627
|
{
|
|
@@ -612,8 +637,8 @@ function OfferingDetailPage(props) {
|
|
|
612
637
|
},
|
|
613
638
|
className: "w-full rounded-md border px-2 py-1.5 text-sm",
|
|
614
639
|
children: [
|
|
615
|
-
editingCharge.chargeModel !== "volume" && editingCharge.chargeModel !== "tiered" && /* @__PURE__ */ jsx("option", { value: "fixed", children:
|
|
616
|
-
/* @__PURE__ */ jsx("option", { value: "table", children:
|
|
640
|
+
editingCharge.chargeModel !== "volume" && editingCharge.chargeModel !== "tiered" && /* @__PURE__ */ jsx("option", { value: "fixed", children: pricingSourceLabel(t, "fixed") }),
|
|
641
|
+
/* @__PURE__ */ jsx("option", { value: "table", children: pricingSourceLabel(t, "table") })
|
|
617
642
|
]
|
|
618
643
|
}
|
|
619
644
|
)
|
|
@@ -621,14 +646,16 @@ function OfferingDetailPage(props) {
|
|
|
621
646
|
editingCharge.pricingMethod === "fixed" ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
622
647
|
/* @__PURE__ */ jsxs("div", { children: [
|
|
623
648
|
/* @__PURE__ */ jsxs("label", { className: "block text-xs font-medium mb-1", children: [
|
|
624
|
-
|
|
649
|
+
chargeMissingFieldLabel(t, "fixedPrice"),
|
|
650
|
+
" ",
|
|
625
651
|
/* @__PURE__ */ jsx("span", { className: "text-destructive", children: "*" })
|
|
626
652
|
] }),
|
|
627
653
|
/* @__PURE__ */ jsx("input", { type: "text", value: editingCharge.fixedPrice ?? "", onChange: (e) => setEditingCharge({ ...editingCharge, fixedPrice: e.target.value || null }), placeholder: "0.00", className: "w-full rounded-md border px-2 py-1.5 text-sm" })
|
|
628
654
|
] }),
|
|
629
655
|
/* @__PURE__ */ jsxs("div", { children: [
|
|
630
656
|
/* @__PURE__ */ jsxs("label", { className: "block text-xs font-medium mb-1", children: [
|
|
631
|
-
|
|
657
|
+
chargeMissingFieldLabel(t, "currency"),
|
|
658
|
+
" ",
|
|
632
659
|
/* @__PURE__ */ jsx("span", { className: "text-destructive", children: "*" })
|
|
633
660
|
] }),
|
|
634
661
|
/* @__PURE__ */ jsx("input", { type: "text", value: editingCharge.currencyCode ?? "USD", onChange: (e) => setEditingCharge({ ...editingCharge, currencyCode: e.target.value || null }), className: "w-full rounded-md border px-2 py-1.5 text-sm" })
|
|
@@ -636,11 +663,12 @@ function OfferingDetailPage(props) {
|
|
|
636
663
|
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
637
664
|
/* @__PURE__ */ jsxs("div", { children: [
|
|
638
665
|
/* @__PURE__ */ jsxs("label", { className: "block text-xs font-medium mb-1", children: [
|
|
639
|
-
|
|
666
|
+
chargeMissingFieldLabel(t, "pricingTable"),
|
|
667
|
+
" ",
|
|
640
668
|
/* @__PURE__ */ jsx("span", { className: "text-destructive", children: "*" })
|
|
641
669
|
] }),
|
|
642
670
|
/* @__PURE__ */ jsxs("select", { value: editingCharge.pricingTableId ?? "", onChange: (e) => setEditingCharge({ ...editingCharge, pricingTableId: e.target.value || null, priceColumnKey: null }), className: "w-full rounded-md border px-2 py-1.5 text-sm", children: [
|
|
643
|
-
/* @__PURE__ */ jsx("option", { value: "", children: "Select table..." }),
|
|
671
|
+
/* @__PURE__ */ jsx("option", { value: "", children: t("cpq.offerings.charge.fields.selectTable", "Select table...") }),
|
|
644
672
|
pricingTables.map((pt) => /* @__PURE__ */ jsxs("option", { value: pt.id, children: [
|
|
645
673
|
pt.name,
|
|
646
674
|
" (",
|
|
@@ -649,31 +677,33 @@ function OfferingDetailPage(props) {
|
|
|
649
677
|
] }, pt.id))
|
|
650
678
|
] }),
|
|
651
679
|
pricingTables.length === 0 && /* @__PURE__ */ jsxs("p", { className: "text-xs text-warning mt-0.5", children: [
|
|
652
|
-
"No pricing tables yet \u2014",
|
|
680
|
+
t("cpq.offerings.charge.noPricingTables.prefix", "No pricing tables yet \u2014"),
|
|
653
681
|
" ",
|
|
654
|
-
/* @__PURE__ */ jsx("a", { href: "/backend/cpq/pricing-tables", className: "text-primary hover:underline", children: "create one" }),
|
|
682
|
+
/* @__PURE__ */ jsx("a", { href: "/backend/cpq/pricing-tables", className: "text-primary hover:underline", children: t("cpq.offerings.charge.noPricingTables.link", "create one") }),
|
|
655
683
|
" ",
|
|
656
|
-
"before using Table Lookup pricing."
|
|
684
|
+
t("cpq.offerings.charge.noPricingTables.suffix", "before using Table Lookup pricing.")
|
|
657
685
|
] })
|
|
658
686
|
] }),
|
|
659
687
|
/* @__PURE__ */ jsxs("div", { children: [
|
|
660
688
|
/* @__PURE__ */ jsxs("label", { className: "block text-xs font-medium mb-1", children: [
|
|
661
|
-
|
|
689
|
+
chargeMissingFieldLabel(t, "priceColumn"),
|
|
690
|
+
" ",
|
|
662
691
|
/* @__PURE__ */ jsx("span", { className: "text-destructive", children: "*" })
|
|
663
692
|
] }),
|
|
664
693
|
/* @__PURE__ */ jsxs("select", { value: editingCharge.priceColumnKey ?? "", onChange: (e) => setEditingCharge({ ...editingCharge, priceColumnKey: e.target.value || null }), className: "w-full rounded-md border px-2 py-1.5 text-sm", disabled: !selectedPricingTable, children: [
|
|
665
|
-
/* @__PURE__ */ jsx("option", { value: "", children: "Select column..." }),
|
|
694
|
+
/* @__PURE__ */ jsx("option", { value: "", children: t("cpq.offerings.charge.fields.selectColumn", "Select column...") }),
|
|
666
695
|
selectedPricingTable?.priceColumns.map((col) => /* @__PURE__ */ jsx("option", { value: col.key, children: col.label }, col.key))
|
|
667
696
|
] })
|
|
668
697
|
] })
|
|
669
698
|
] }),
|
|
670
699
|
(editingCharge.pricingMethod === "table" && editingCharge.chargeModel !== "flat" || editingCharge.pricingMethod === "fixed" && editingCharge.chargeModel === "per_unit") && /* @__PURE__ */ jsxs("div", { children: [
|
|
671
700
|
/* @__PURE__ */ jsxs("label", { className: "block text-xs font-medium mb-1", children: [
|
|
672
|
-
|
|
701
|
+
chargeMissingFieldLabel(t, "quantityAttribute"),
|
|
702
|
+
" ",
|
|
673
703
|
/* @__PURE__ */ jsx("span", { className: "text-destructive", children: "*" })
|
|
674
704
|
] }),
|
|
675
705
|
/* @__PURE__ */ jsxs("select", { value: editingCharge.quantityAttributeCode ?? "", onChange: (e) => setEditingCharge({ ...editingCharge, quantityAttributeCode: e.target.value || null }), className: "w-full rounded-md border px-2 py-1.5 text-sm", children: [
|
|
676
|
-
/* @__PURE__ */ jsx("option", { value: "", children: "Select attribute..." }),
|
|
706
|
+
/* @__PURE__ */ jsx("option", { value: "", children: t("cpq.offerings.charge.fields.selectAttribute", "Select attribute...") }),
|
|
677
707
|
attributes.filter((a) => a.attributeType === "number").map((a) => /* @__PURE__ */ jsxs("option", { value: a.code, children: [
|
|
678
708
|
a.name,
|
|
679
709
|
" (",
|
|
@@ -681,17 +711,17 @@ function OfferingDetailPage(props) {
|
|
|
681
711
|
")"
|
|
682
712
|
] }, a.code))
|
|
683
713
|
] }),
|
|
684
|
-
/* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground mt-0.5", children: "Attribute whose value drives the quantity for pricing" }),
|
|
714
|
+
/* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground mt-0.5", children: t("cpq.offerings.charge.fields.quantityAttributeHelp", "Attribute whose value drives the quantity for pricing") }),
|
|
685
715
|
attributes.filter((a) => a.attributeType === "number").length === 0 && form.specId && /* @__PURE__ */ jsxs("p", { className: "text-xs text-warning mt-0.5", children: [
|
|
686
|
-
"Spec has no number attributes \u2014",
|
|
716
|
+
t("cpq.offerings.charge.noNumberAttributes.prefix", "Spec has no number attributes \u2014"),
|
|
687
717
|
" ",
|
|
688
|
-
/* @__PURE__ */ jsx("a", { href: `/backend/cpq/specifications/${form.specId}`, className: "text-primary hover:underline", children: "add one to the spec" }),
|
|
718
|
+
/* @__PURE__ */ jsx("a", { href: `/backend/cpq/specifications/${form.specId}`, className: "text-primary hover:underline", children: t("cpq.offerings.charge.noNumberAttributes.link", "add one to the spec") }),
|
|
689
719
|
" ",
|
|
690
|
-
"first."
|
|
720
|
+
t("cpq.offerings.charge.noNumberAttributes.suffix", "first.")
|
|
691
721
|
] })
|
|
692
722
|
] }),
|
|
693
723
|
/* @__PURE__ */ jsxs("div", { children: [
|
|
694
|
-
/* @__PURE__ */ jsx("label", { className: "block text-xs font-medium mb-1", children: "Sort Order" }),
|
|
724
|
+
/* @__PURE__ */ jsx("label", { className: "block text-xs font-medium mb-1", children: t("cpq.offerings.charge.fields.sortOrder", "Sort Order") }),
|
|
695
725
|
/* @__PURE__ */ jsx(
|
|
696
726
|
NumberInput,
|
|
697
727
|
{
|
|
@@ -703,41 +733,40 @@ function OfferingDetailPage(props) {
|
|
|
703
733
|
] })
|
|
704
734
|
] }),
|
|
705
735
|
/* @__PURE__ */ jsxs("div", { children: [
|
|
706
|
-
/* @__PURE__ */ jsx("label", { className: "block text-xs font-medium mb-1", children: "Description" }),
|
|
736
|
+
/* @__PURE__ */ jsx("label", { className: "block text-xs font-medium mb-1", children: t("cpq.offerings.charge.fields.description", "Description") }),
|
|
707
737
|
/* @__PURE__ */ jsx("input", { type: "text", value: editingCharge.description ?? "", onChange: (e) => setEditingCharge({ ...editingCharge, description: e.target.value || null }), className: "w-full rounded-md border px-2 py-1.5 text-sm" })
|
|
708
738
|
] }),
|
|
709
739
|
/* @__PURE__ */ jsx("div", { className: "flex items-end gap-4", children: /* @__PURE__ */ jsxs("label", { className: "flex items-center gap-1.5 text-sm", children: [
|
|
710
740
|
/* @__PURE__ */ jsx("input", { type: "checkbox", checked: editingCharge.isActive, onChange: (e) => setEditingCharge({ ...editingCharge, isActive: e.target.checked }), className: "rounded border" }),
|
|
711
|
-
"Active"
|
|
741
|
+
t("cpq.common.active", "Active")
|
|
712
742
|
] }) }),
|
|
713
743
|
(() => {
|
|
714
744
|
const missing = chargeMissingFields(editingCharge);
|
|
715
745
|
const blocked = saving || !editingCharge.code || !editingCharge.name || missing.length > 0;
|
|
716
746
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
717
|
-
missing.length > 0 && /* @__PURE__ */
|
|
718
|
-
|
|
719
|
-
missing.
|
|
720
|
-
|
|
721
|
-
editingCharge.pricingMethod,
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
] }),
|
|
747
|
+
missing.length > 0 && /* @__PURE__ */ jsx(Alert, { variant: "destructive", children: missing.length > 1 ? t("cpq.offerings.charge.missingFieldsPlural", "Missing required fields for {method} pricing: {fields}", {
|
|
748
|
+
method: editingCharge.pricingMethod,
|
|
749
|
+
fields: missing.map((field) => chargeMissingFieldLabel(t, field)).join(", ")
|
|
750
|
+
}) : t("cpq.offerings.charge.missingFieldsSingular", "Missing required field for {method} pricing: {fields}", {
|
|
751
|
+
method: editingCharge.pricingMethod,
|
|
752
|
+
fields: missing.map((field) => chargeMissingFieldLabel(t, field)).join(", ")
|
|
753
|
+
}) }),
|
|
725
754
|
/* @__PURE__ */ jsxs("div", { className: "flex gap-2", children: [
|
|
726
|
-
/* @__PURE__ */ jsx("button", { onClick: saveCharge, disabled: blocked, className: "inline-flex items-center rounded-md bg-primary px-3 py-1.5 text-sm font-medium text-primary-foreground hover:bg-primary/90 disabled:opacity-50 disabled:cursor-not-allowed", children: saving ? "Saving..." : "Save" }),
|
|
727
|
-
/* @__PURE__ */ jsx("button", { onClick: () => setEditingCharge(null), className: "inline-flex items-center rounded-md border px-3 py-1.5 text-sm font-medium hover:bg-muted", children: "Cancel" })
|
|
755
|
+
/* @__PURE__ */ jsx("button", { onClick: saveCharge, disabled: blocked, className: "inline-flex items-center rounded-md bg-primary px-3 py-1.5 text-sm font-medium text-primary-foreground hover:bg-primary/90 disabled:opacity-50 disabled:cursor-not-allowed", children: saving ? t("cpq.common.saving", "Saving...") : t("cpq.common.save", "Save") }),
|
|
756
|
+
/* @__PURE__ */ jsx("button", { onClick: () => setEditingCharge(null), className: "inline-flex items-center rounded-md border px-3 py-1.5 text-sm font-medium hover:bg-muted", children: t("cpq.common.cancel", "Cancel") })
|
|
728
757
|
] })
|
|
729
758
|
] });
|
|
730
759
|
})()
|
|
731
760
|
] }),
|
|
732
|
-
charges.length === 0 ? /* @__PURE__ */ jsx("div", { className: "rounded-lg border bg-card p-6 text-center text-sm text-muted-foreground", children: "No charges defined. Add recurring, non-recurring, or usage charges to this offering." }) : /* @__PURE__ */ jsx("div", { className: "rounded-lg border", children: /* @__PURE__ */ jsxs("table", { className: "w-full text-sm", children: [
|
|
761
|
+
charges.length === 0 ? /* @__PURE__ */ jsx("div", { className: "rounded-lg border bg-card p-6 text-center text-sm text-muted-foreground", children: t("cpq.offerings.charges.empty", "No charges defined. Add recurring, non-recurring, or usage charges to this offering.") }) : /* @__PURE__ */ jsx("div", { className: "rounded-lg border", children: /* @__PURE__ */ jsxs("table", { className: "w-full text-sm", children: [
|
|
733
762
|
/* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsxs("tr", { className: "border-b bg-muted/50", children: [
|
|
734
|
-
/* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left font-medium", children: "Code" }),
|
|
735
|
-
/* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left font-medium", children: "Name" }),
|
|
736
|
-
/* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left font-medium", children: "Type" }),
|
|
737
|
-
/* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left font-medium", children: "Pricing" }),
|
|
738
|
-
/* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left font-medium", children: "Price" }),
|
|
739
|
-
/* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left font-medium", children: "Active" }),
|
|
740
|
-
/* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-right font-medium", children: "Actions" })
|
|
763
|
+
/* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left font-medium", children: t("cpq.offerings.charges.columns.code", "Code") }),
|
|
764
|
+
/* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left font-medium", children: t("cpq.offerings.charges.columns.name", "Name") }),
|
|
765
|
+
/* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left font-medium", children: t("cpq.offerings.charges.columns.type", "Type") }),
|
|
766
|
+
/* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left font-medium", children: t("cpq.offerings.charges.columns.pricing", "Pricing") }),
|
|
767
|
+
/* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left font-medium", children: t("cpq.offerings.charges.columns.price", "Price") }),
|
|
768
|
+
/* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-left font-medium", children: t("cpq.offerings.charges.columns.active", "Active") }),
|
|
769
|
+
/* @__PURE__ */ jsx("th", { className: "px-4 py-3 text-right font-medium", children: t("cpq.offerings.charges.columns.actions", "Actions") })
|
|
741
770
|
] }) }),
|
|
742
771
|
/* @__PURE__ */ jsx("tbody", { children: charges.map((charge) => {
|
|
743
772
|
const incomplete = !isChargeComplete(charge);
|
|
@@ -748,45 +777,45 @@ function OfferingDetailPage(props) {
|
|
|
748
777
|
/* @__PURE__ */ jsx("td", { className: "px-4 py-3 font-mono text-xs", children: charge.code }),
|
|
749
778
|
/* @__PURE__ */ jsxs("td", { className: "px-4 py-3", children: [
|
|
750
779
|
charge.name,
|
|
751
|
-
incomplete && /* @__PURE__ */ jsx(Tag, { variant: "error", className: "ml-2 px-2 text-[10px]", dot: true, children: "Incomplete" })
|
|
780
|
+
incomplete && /* @__PURE__ */ jsx(Tag, { variant: "error", className: "ml-2 px-2 text-[10px]", dot: true, children: t("cpq.offerings.charges.incomplete", "Incomplete") })
|
|
752
781
|
] }),
|
|
753
782
|
/* @__PURE__ */ jsx("td", { className: "px-4 py-3", children: /* @__PURE__ */ jsx(Tag, { variant: chargeTypeMap[charge.chargeType] ?? "neutral", className: "px-2 text-xs", children: charge.chargeType.toUpperCase() }) }),
|
|
754
783
|
/* @__PURE__ */ jsxs("td", { className: "px-4 py-3 text-xs", children: [
|
|
755
|
-
|
|
784
|
+
chargeModelLabel(t, model),
|
|
756
785
|
/* @__PURE__ */ jsxs("span", { className: "text-muted-foreground", children: [
|
|
757
786
|
" \xB7 ",
|
|
758
|
-
|
|
787
|
+
pricingSourceLabel(t, source)
|
|
759
788
|
] })
|
|
760
789
|
] }),
|
|
761
790
|
/* @__PURE__ */ jsx("td", { className: "px-4 py-3 text-xs", children: source === "fixed" ? /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-0.5", children: [
|
|
762
791
|
charge.fixedPrice != null ? /* @__PURE__ */ jsx("span", { children: `${charge.currencyCode ?? "USD"} ${charge.fixedPrice}` }) : /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "\u2014" }),
|
|
763
792
|
model === "per_unit" && /* @__PURE__ */ jsxs("span", { children: [
|
|
764
|
-
/* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "\xD7 Qty:" }),
|
|
793
|
+
/* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: t("cpq.offerings.charges.qtyLabel", "\xD7 Qty:") }),
|
|
765
794
|
" ",
|
|
766
|
-
qtyAttr ? `${qtyAttr.name} (${qtyAttr.code})` : /* @__PURE__ */ jsx("span", { className: "text-destructive", children: "missing" })
|
|
795
|
+
qtyAttr ? `${qtyAttr.name} (${qtyAttr.code})` : /* @__PURE__ */ jsx("span", { className: "text-destructive", children: t("cpq.offerings.charges.missing", "missing") })
|
|
767
796
|
] })
|
|
768
797
|
] }) : /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-0.5", children: [
|
|
769
798
|
/* @__PURE__ */ jsxs("span", { children: [
|
|
770
|
-
/* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "Table:" }),
|
|
799
|
+
/* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: t("cpq.offerings.charges.tableLabel", "Table:") }),
|
|
771
800
|
" ",
|
|
772
|
-
tableRef ? `${tableRef.name} \u2192 ${charge.priceColumnKey ?? "?"}` : /* @__PURE__ */ jsx("span", { className: "text-destructive", children: "missing" })
|
|
801
|
+
tableRef ? `${tableRef.name} \u2192 ${charge.priceColumnKey ?? "?"}` : /* @__PURE__ */ jsx("span", { className: "text-destructive", children: t("cpq.offerings.charges.missing", "missing") })
|
|
773
802
|
] }),
|
|
774
803
|
model !== "flat" && /* @__PURE__ */ jsxs("span", { children: [
|
|
775
|
-
/* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "\xD7 Qty:" }),
|
|
804
|
+
/* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: t("cpq.offerings.charges.qtyLabel", "\xD7 Qty:") }),
|
|
776
805
|
" ",
|
|
777
|
-
qtyAttr ? `${qtyAttr.name} (${qtyAttr.code})` : /* @__PURE__ */ jsx("span", { className: "text-destructive", children: "missing" })
|
|
806
|
+
qtyAttr ? `${qtyAttr.name} (${qtyAttr.code})` : /* @__PURE__ */ jsx("span", { className: "text-destructive", children: t("cpq.offerings.charges.missing", "missing") })
|
|
778
807
|
] })
|
|
779
808
|
] }) }),
|
|
780
|
-
/* @__PURE__ */ jsx("td", { className: "px-4 py-3", children: charge.isActive ? "Yes" : "No" }),
|
|
809
|
+
/* @__PURE__ */ jsx("td", { className: "px-4 py-3", children: charge.isActive ? t("cpq.common.yes", "Yes") : t("cpq.common.no", "No") }),
|
|
781
810
|
/* @__PURE__ */ jsxs("td", { className: "px-4 py-3 text-right", children: [
|
|
782
|
-
/* @__PURE__ */ jsx("button", { onClick: () => startEditCharge(charge), className: "text-xs text-primary hover:underline mr-2", children: "Edit" }),
|
|
783
|
-
/* @__PURE__ */ jsx("button", { onClick: () => deleteCharge(charge.id), className: "text-xs text-destructive hover:underline", children: "Delete" })
|
|
811
|
+
/* @__PURE__ */ jsx("button", { onClick: () => startEditCharge(charge), className: "text-xs text-primary hover:underline mr-2", children: t("cpq.common.edit", "Edit") }),
|
|
812
|
+
/* @__PURE__ */ jsx("button", { onClick: () => deleteCharge(charge.id), className: "text-xs text-destructive hover:underline", children: t("cpq.common.delete", "Delete") })
|
|
784
813
|
] })
|
|
785
814
|
] }, charge.id);
|
|
786
815
|
}) })
|
|
787
816
|
] }) })
|
|
788
817
|
] }),
|
|
789
|
-
tab === "components" && !isNew && form.offeringType === "bundle" && /* @__PURE__ */ jsx("div", { className: "space-y-4", children: bundleSlots.length === 0 ? /* @__PURE__ */ jsx("div", { className: "rounded-lg border bg-card p-6 text-center text-sm text-muted-foreground", children: "No bundle slots defined on this specification. Add slots on the specification first." }) : /* @__PURE__ */ jsx(Fragment, { children: bundleSlots.map((slot) => {
|
|
818
|
+
tab === "components" && !isNew && form.offeringType === "bundle" && /* @__PURE__ */ jsx("div", { className: "space-y-4", children: bundleSlots.length === 0 ? /* @__PURE__ */ jsx("div", { className: "rounded-lg border bg-card p-6 text-center text-sm text-muted-foreground", children: t("cpq.offerings.components.noSlots", "No bundle slots defined on this specification. Add slots on the specification first.") }) : /* @__PURE__ */ jsx(Fragment, { children: bundleSlots.map((slot) => {
|
|
790
819
|
const slotComponents = components.filter((c) => c.slotId === slot.id);
|
|
791
820
|
return /* @__PURE__ */ jsxs("div", { className: "rounded-lg border bg-card overflow-hidden", children: [
|
|
792
821
|
/* @__PURE__ */ jsxs("div", { className: "bg-muted/50 px-4 py-3 border-b flex items-center justify-between", children: [
|
|
@@ -817,14 +846,14 @@ function OfferingDetailPage(props) {
|
|
|
817
846
|
}
|
|
818
847
|
},
|
|
819
848
|
className: "inline-flex items-center justify-center rounded-md bg-primary px-3 py-1.5 text-xs font-medium text-primary-foreground hover:bg-primary/90",
|
|
820
|
-
children: "+ Add Component"
|
|
849
|
+
children: t("cpq.offerings.components.add", "+ Add Component")
|
|
821
850
|
}
|
|
822
851
|
)
|
|
823
852
|
] }),
|
|
824
853
|
addingComponent?.slotId === slot.id && /* @__PURE__ */ jsxs("div", { className: "p-4 border-b bg-muted/20 space-y-3", children: [
|
|
825
854
|
/* @__PURE__ */ jsxs("div", { className: "grid grid-cols-3 gap-3", children: [
|
|
826
855
|
/* @__PURE__ */ jsxs("div", { className: "col-span-2", children: [
|
|
827
|
-
/* @__PURE__ */ jsx("label", { className: "block text-xs font-medium mb-1", children: "Component Offering" }),
|
|
856
|
+
/* @__PURE__ */ jsx("label", { className: "block text-xs font-medium mb-1", children: t("cpq.offerings.components.fields.componentOffering", "Component Offering") }),
|
|
828
857
|
/* @__PURE__ */ jsxs(
|
|
829
858
|
"select",
|
|
830
859
|
{
|
|
@@ -832,20 +861,20 @@ function OfferingDetailPage(props) {
|
|
|
832
861
|
onChange: (e) => setAddingComponent({ ...addingComponent, childOfferingId: e.target.value }),
|
|
833
862
|
className: "w-full rounded-md border px-3 py-2 text-sm",
|
|
834
863
|
children: [
|
|
835
|
-
/* @__PURE__ */ jsx("option", { value: "", children: "\u2014 Select offering \u2014" }),
|
|
864
|
+
/* @__PURE__ */ jsx("option", { value: "", children: t("cpq.offerings.components.fields.selectOffering", "\u2014 Select offering \u2014") }),
|
|
836
865
|
(slotOfferings[slot.targetSpecId] ?? []).map((o) => /* @__PURE__ */ jsxs("option", { value: o.id, children: [
|
|
837
866
|
o.name,
|
|
838
867
|
" (",
|
|
839
868
|
o.code,
|
|
840
869
|
")",
|
|
841
|
-
o.offeringType === "bundle" ? " [bundle]" : ""
|
|
870
|
+
o.offeringType === "bundle" ? t("cpq.offerings.components.bundleSuffix", " [bundle]") : ""
|
|
842
871
|
] }, o.id))
|
|
843
872
|
]
|
|
844
873
|
}
|
|
845
874
|
)
|
|
846
875
|
] }),
|
|
847
876
|
/* @__PURE__ */ jsxs("div", { children: [
|
|
848
|
-
/* @__PURE__ */ jsx("label", { className: "block text-xs font-medium mb-1", children: "Default?" }),
|
|
877
|
+
/* @__PURE__ */ jsx("label", { className: "block text-xs font-medium mb-1", children: t("cpq.offerings.components.fields.isDefault", "Default?") }),
|
|
849
878
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center h-[38px]", children: [
|
|
850
879
|
/* @__PURE__ */ jsx(
|
|
851
880
|
"input",
|
|
@@ -856,7 +885,7 @@ function OfferingDetailPage(props) {
|
|
|
856
885
|
className: "rounded border"
|
|
857
886
|
}
|
|
858
887
|
),
|
|
859
|
-
/* @__PURE__ */ jsx("span", { className: "ml-2 text-xs text-muted-foreground", children: "Pre-selected in quote" })
|
|
888
|
+
/* @__PURE__ */ jsx("span", { className: "ml-2 text-xs text-muted-foreground", children: t("cpq.offerings.components.fields.isDefaultHelp", "Pre-selected in quote") })
|
|
860
889
|
] })
|
|
861
890
|
] })
|
|
862
891
|
] }),
|
|
@@ -881,7 +910,7 @@ function OfferingDetailPage(props) {
|
|
|
881
910
|
});
|
|
882
911
|
if (!res.ok) {
|
|
883
912
|
const d = await res.json();
|
|
884
|
-
setError(d.error ?? "Failed to add component");
|
|
913
|
+
setError(d.error ?? t("cpq.offerings.components.error.add", "Failed to add component"));
|
|
885
914
|
return;
|
|
886
915
|
}
|
|
887
916
|
setAddingComponent(null);
|
|
@@ -891,13 +920,13 @@ function OfferingDetailPage(props) {
|
|
|
891
920
|
setComponents(d.items ?? []);
|
|
892
921
|
}
|
|
893
922
|
} catch {
|
|
894
|
-
setError("Failed to add component");
|
|
923
|
+
setError(t("cpq.offerings.components.error.add", "Failed to add component"));
|
|
895
924
|
} finally {
|
|
896
925
|
setSaving(false);
|
|
897
926
|
}
|
|
898
927
|
},
|
|
899
928
|
className: "inline-flex items-center justify-center rounded-md bg-primary px-3 py-1.5 text-xs font-medium text-primary-foreground hover:bg-primary/90 disabled:opacity-50",
|
|
900
|
-
children: saving ? "Adding..." : "Add"
|
|
929
|
+
children: saving ? t("cpq.offerings.components.adding", "Adding...") : t("cpq.offerings.components.addSubmit", "Add")
|
|
901
930
|
}
|
|
902
931
|
),
|
|
903
932
|
/* @__PURE__ */ jsx(
|
|
@@ -905,30 +934,26 @@ function OfferingDetailPage(props) {
|
|
|
905
934
|
{
|
|
906
935
|
onClick: () => setAddingComponent(null),
|
|
907
936
|
className: "inline-flex items-center justify-center rounded-md border px-3 py-1.5 text-xs font-medium hover:bg-muted",
|
|
908
|
-
children: "Cancel"
|
|
937
|
+
children: t("cpq.common.cancel", "Cancel")
|
|
909
938
|
}
|
|
910
939
|
)
|
|
911
940
|
] })
|
|
912
941
|
] }),
|
|
913
942
|
slotComponents.length === 0 ? /* @__PURE__ */ jsxs("div", { className: "p-4 text-center text-xs text-muted-foreground", children: [
|
|
914
|
-
"No components assigned to this slot",
|
|
915
|
-
slot.cardinalityMin > 0 && /* @__PURE__ */
|
|
916
|
-
"(required: min ",
|
|
917
|
-
slot.cardinalityMin,
|
|
918
|
-
")"
|
|
919
|
-
] })
|
|
943
|
+
t("cpq.offerings.components.emptySlot", "No components assigned to this slot"),
|
|
944
|
+
slot.cardinalityMin > 0 && /* @__PURE__ */ jsx("span", { className: "ml-1 text-status-warning-text font-medium", children: t("cpq.offerings.components.requiredMin", "(required: min {min})", { min: slot.cardinalityMin }) })
|
|
920
945
|
] }) : /* @__PURE__ */ jsxs("table", { className: "w-full text-sm", children: [
|
|
921
946
|
/* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsxs("tr", { className: "border-b bg-muted/30", children: [
|
|
922
|
-
/* @__PURE__ */ jsx("th", { className: "px-4 py-2 text-left text-xs font-medium", children: "Offering" }),
|
|
923
|
-
/* @__PURE__ */ jsx("th", { className: "px-4 py-2 text-left text-xs font-medium", children: "Code" }),
|
|
924
|
-
/* @__PURE__ */ jsx("th", { className: "px-4 py-2 text-left text-xs font-medium", children: "Type" }),
|
|
925
|
-
/* @__PURE__ */ jsx("th", { className: "px-4 py-2 text-left text-xs font-medium", children: "Default" }),
|
|
926
|
-
/* @__PURE__ */ jsx("th", { className: "px-4 py-2 text-right text-xs font-medium", children: "Actions" })
|
|
947
|
+
/* @__PURE__ */ jsx("th", { className: "px-4 py-2 text-left text-xs font-medium", children: t("cpq.offerings.components.columns.offering", "Offering") }),
|
|
948
|
+
/* @__PURE__ */ jsx("th", { className: "px-4 py-2 text-left text-xs font-medium", children: t("cpq.offerings.components.columns.code", "Code") }),
|
|
949
|
+
/* @__PURE__ */ jsx("th", { className: "px-4 py-2 text-left text-xs font-medium", children: t("cpq.offerings.components.columns.type", "Type") }),
|
|
950
|
+
/* @__PURE__ */ jsx("th", { className: "px-4 py-2 text-left text-xs font-medium", children: t("cpq.offerings.components.columns.default", "Default") }),
|
|
951
|
+
/* @__PURE__ */ jsx("th", { className: "px-4 py-2 text-right text-xs font-medium", children: t("cpq.offerings.components.columns.actions", "Actions") })
|
|
927
952
|
] }) }),
|
|
928
953
|
/* @__PURE__ */ jsx("tbody", { children: slotComponents.map((comp) => /* @__PURE__ */ jsxs("tr", { className: "border-b last:border-0", children: [
|
|
929
|
-
/* @__PURE__ */ jsx("td", { className: "px-4 py-2.5 font-medium", children: comp.childOffering?.name ?? "Unknown" }),
|
|
954
|
+
/* @__PURE__ */ jsx("td", { className: "px-4 py-2.5 font-medium", children: comp.childOffering?.name ?? t("cpq.offerings.components.unknown", "Unknown") }),
|
|
930
955
|
/* @__PURE__ */ jsx("td", { className: "px-4 py-2.5 text-muted-foreground text-xs", children: comp.childOffering?.code ?? "\u2014" }),
|
|
931
|
-
/* @__PURE__ */ jsx("td", { className: "px-4 py-2.5", children: comp.childOffering?.offeringType === "bundle" ? /* @__PURE__ */ jsx(Tag, { variant: "brand", className: "px-2 text-[10px]", children: "bundle" }) : /* @__PURE__ */ jsx(Tag, { variant: "neutral", className: "px-2 text-[10px]", children: "simple" }) }),
|
|
956
|
+
/* @__PURE__ */ jsx("td", { className: "px-4 py-2.5", children: comp.childOffering?.offeringType === "bundle" ? /* @__PURE__ */ jsx(Tag, { variant: "brand", className: "px-2 text-[10px]", children: t("cpq.offerings.components.tag.bundle", "bundle") }) : /* @__PURE__ */ jsx(Tag, { variant: "neutral", className: "px-2 text-[10px]", children: t("cpq.offerings.components.tag.simple", "simple") }) }),
|
|
932
957
|
/* @__PURE__ */ jsx("td", { className: "px-4 py-2.5", children: /* @__PURE__ */ jsx(
|
|
933
958
|
"button",
|
|
934
959
|
{
|
|
@@ -946,14 +971,14 @@ function OfferingDetailPage(props) {
|
|
|
946
971
|
}
|
|
947
972
|
},
|
|
948
973
|
className: "cursor-pointer",
|
|
949
|
-
children: /* @__PURE__ */ jsx(Tag, { variant: comp.isDefault ? "success" : "neutral", className: "px-2 text-[10px]", children: comp.isDefault ? "Yes" : "No" })
|
|
974
|
+
children: /* @__PURE__ */ jsx(Tag, { variant: comp.isDefault ? "success" : "neutral", className: "px-2 text-[10px]", children: comp.isDefault ? t("cpq.common.yes", "Yes") : t("cpq.common.no", "No") })
|
|
950
975
|
}
|
|
951
976
|
) }),
|
|
952
977
|
/* @__PURE__ */ jsx("td", { className: "px-4 py-2.5 text-right", children: /* @__PURE__ */ jsx(
|
|
953
978
|
"button",
|
|
954
979
|
{
|
|
955
980
|
onClick: async () => {
|
|
956
|
-
if (!confirm("Remove this component from the bundle?")) return;
|
|
981
|
+
if (!confirm(t("cpq.offerings.components.confirmRemove", "Remove this component from the bundle?"))) return;
|
|
957
982
|
try {
|
|
958
983
|
const res = await fetch("/api/cpq/offering-components", {
|
|
959
984
|
method: "DELETE",
|
|
@@ -964,14 +989,14 @@ function OfferingDetailPage(props) {
|
|
|
964
989
|
setComponents((prev) => prev.filter((c) => c.id !== comp.id));
|
|
965
990
|
} else {
|
|
966
991
|
const d = await res.json();
|
|
967
|
-
setError(d.error ?? "Failed to remove");
|
|
992
|
+
setError(d.error ?? t("cpq.offerings.components.error.remove", "Failed to remove"));
|
|
968
993
|
}
|
|
969
994
|
} catch {
|
|
970
|
-
setError("Failed to remove component");
|
|
995
|
+
setError(t("cpq.offerings.components.error.removeComponent", "Failed to remove component"));
|
|
971
996
|
}
|
|
972
997
|
},
|
|
973
998
|
className: "text-xs text-destructive hover:underline",
|
|
974
|
-
children: "Remove"
|
|
999
|
+
children: t("cpq.offerings.components.remove", "Remove")
|
|
975
1000
|
}
|
|
976
1001
|
) })
|
|
977
1002
|
] }, comp.id)) })
|