@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
|
@@ -29,12 +29,24 @@ import {
|
|
|
29
29
|
function fmt(amount, currency) {
|
|
30
30
|
return new Intl.NumberFormat("en-US", { style: "currency", currency }).format(amount);
|
|
31
31
|
}
|
|
32
|
-
async function apiJson(url, init) {
|
|
32
|
+
async function apiJson(t, url, init) {
|
|
33
33
|
const res = await fetch(url, init);
|
|
34
34
|
const json = await res.json();
|
|
35
|
-
if (!res.ok) throw new Error(json?.error ??
|
|
35
|
+
if (!res.ok) throw new Error(json?.error ?? t("cpq.common.requestFailed", "Request failed ({status})", { status: res.status }));
|
|
36
36
|
return json;
|
|
37
37
|
}
|
|
38
|
+
function quoteTypeLabel(t, quoteType) {
|
|
39
|
+
switch (quoteType) {
|
|
40
|
+
case "amend":
|
|
41
|
+
return t("cpq.quotes.type.amend", "amend");
|
|
42
|
+
case "renew":
|
|
43
|
+
return t("cpq.quotes.type.renew", "renew");
|
|
44
|
+
case "cancel":
|
|
45
|
+
return t("cpq.quotes.type.cancel", "cancel");
|
|
46
|
+
default:
|
|
47
|
+
return quoteType;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
38
50
|
function MetaCard({ label, children }) {
|
|
39
51
|
return /* @__PURE__ */ jsxs("div", { className: "rounded-lg border bg-card p-4", children: [
|
|
40
52
|
/* @__PURE__ */ jsx("div", { className: "text-[10px] font-medium uppercase tracking-wide text-muted-foreground", children: label }),
|
|
@@ -42,6 +54,7 @@ function MetaCard({ label, children }) {
|
|
|
42
54
|
] });
|
|
43
55
|
}
|
|
44
56
|
function MoreActionsDropdown({ items }) {
|
|
57
|
+
const t = useT();
|
|
45
58
|
const [open, setOpen] = React.useState(false);
|
|
46
59
|
const ref = React.useRef(null);
|
|
47
60
|
React.useEffect(() => {
|
|
@@ -55,7 +68,7 @@ function MoreActionsDropdown({ items }) {
|
|
|
55
68
|
if (items.length === 0) return null;
|
|
56
69
|
return /* @__PURE__ */ jsxs("div", { className: "relative", ref, children: [
|
|
57
70
|
/* @__PURE__ */ jsxs(Button, { type: "button", variant: "outline", onClick: () => setOpen((v) => !v), children: [
|
|
58
|
-
"Actions",
|
|
71
|
+
t("cpq.quotes.detail.actions", "Actions"),
|
|
59
72
|
/* @__PURE__ */ jsx("svg", { className: "h-3 w-3 ml-1", fill: "none", viewBox: "0 0 24 24", strokeWidth: "2", stroke: "currentColor", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M19.5 8.25l-7.5 7.5-7.5-7.5" }) })
|
|
60
73
|
] }),
|
|
61
74
|
open && /* @__PURE__ */ jsx("div", { className: "absolute right-0 top-full mt-1 z-50 min-w-[200px] rounded-md border bg-popover shadow-md py-1", children: items.map((item) => {
|
|
@@ -81,6 +94,7 @@ function MoreActionsDropdown({ items }) {
|
|
|
81
94
|
] });
|
|
82
95
|
}
|
|
83
96
|
function buildMoreActions({
|
|
97
|
+
t,
|
|
84
98
|
recalculate,
|
|
85
99
|
canRecalculate,
|
|
86
100
|
submitting,
|
|
@@ -92,7 +106,7 @@ function buildMoreActions({
|
|
|
92
106
|
if (canRecalculate) {
|
|
93
107
|
items.push({
|
|
94
108
|
id: "recalculate",
|
|
95
|
-
label: "Recalculate",
|
|
109
|
+
label: t("cpq.quotes.detail.recalculate", "Recalculate"),
|
|
96
110
|
onSelect: recalculate,
|
|
97
111
|
loading: submitting,
|
|
98
112
|
disabled: submitting
|
|
@@ -101,7 +115,7 @@ function buildMoreActions({
|
|
|
101
115
|
if (deletable) {
|
|
102
116
|
items.push({
|
|
103
117
|
id: "delete",
|
|
104
|
-
label: "Delete",
|
|
118
|
+
label: t("cpq.common.delete", "Delete"),
|
|
105
119
|
onSelect: onDelete,
|
|
106
120
|
disabled: deleting,
|
|
107
121
|
loading: deleting
|
|
@@ -162,11 +176,11 @@ function CpqQuoteDetailPage(props) {
|
|
|
162
176
|
}, [cpqConfigId, isNew, loadArcTargets]);
|
|
163
177
|
const reloadQuote = React.useCallback(async () => {
|
|
164
178
|
try {
|
|
165
|
-
setCpqQuote(await apiJson(`/api/cpq/quotes/${cpqConfigId}`));
|
|
179
|
+
setCpqQuote(await apiJson(t, `/api/cpq/quotes/${cpqConfigId}`));
|
|
166
180
|
} catch (err) {
|
|
167
181
|
setError(err.message);
|
|
168
182
|
}
|
|
169
|
-
}, [cpqConfigId]);
|
|
183
|
+
}, [cpqConfigId, t]);
|
|
170
184
|
const priceAdjustments = usePriceAdjustments({
|
|
171
185
|
quote: isNew ? null : cpqQuote,
|
|
172
186
|
quoteType: arcQuoteType,
|
|
@@ -179,7 +193,7 @@ function CpqQuoteDetailPage(props) {
|
|
|
179
193
|
const quoteId = searchParams.get("quoteId");
|
|
180
194
|
const customerId = searchParams.get("customerId");
|
|
181
195
|
if (!customerId) {
|
|
182
|
-
setError("customerId is required to create a CPQ quote");
|
|
196
|
+
setError(t("cpq.quotes.detail.customerIdRequired", "customerId is required to create a CPQ quote"));
|
|
183
197
|
setLoading(false);
|
|
184
198
|
return;
|
|
185
199
|
}
|
|
@@ -187,7 +201,7 @@ function CpqQuoteDetailPage(props) {
|
|
|
187
201
|
try {
|
|
188
202
|
const body = { customerId };
|
|
189
203
|
if (quoteId) body.quoteId = quoteId;
|
|
190
|
-
const result = await apiJson("/api/cpq/quotes", {
|
|
204
|
+
const result = await apiJson(t, "/api/cpq/quotes", {
|
|
191
205
|
method: "POST",
|
|
192
206
|
headers: { "Content-Type": "application/json" },
|
|
193
207
|
body: JSON.stringify(body)
|
|
@@ -204,7 +218,7 @@ function CpqQuoteDetailPage(props) {
|
|
|
204
218
|
let cancelled = false;
|
|
205
219
|
async function load() {
|
|
206
220
|
try {
|
|
207
|
-
const result = await apiJson(`/api/cpq/quotes/${cpqConfigId}`);
|
|
221
|
+
const result = await apiJson(t, `/api/cpq/quotes/${cpqConfigId}`);
|
|
208
222
|
if (!cancelled) setCpqQuote(result);
|
|
209
223
|
} catch (err) {
|
|
210
224
|
if (!cancelled) setError(err.message);
|
|
@@ -216,11 +230,11 @@ function CpqQuoteDetailPage(props) {
|
|
|
216
230
|
return () => {
|
|
217
231
|
cancelled = true;
|
|
218
232
|
};
|
|
219
|
-
}, [cpqConfigId, isNew, searchParams, router]);
|
|
233
|
+
}, [cpqConfigId, isNew, searchParams, router, t]);
|
|
220
234
|
const loadOfferings = async () => {
|
|
221
235
|
setOfferingsLoading(true);
|
|
222
236
|
try {
|
|
223
|
-
const result = await apiJson("/api/cpq/product-offerings?pageSize=100&lifecycleStatus=active");
|
|
237
|
+
const result = await apiJson(t, "/api/cpq/product-offerings?pageSize=100&lifecycleStatus=active");
|
|
224
238
|
setOfferings(result.items ?? []);
|
|
225
239
|
} catch {
|
|
226
240
|
setOfferings([]);
|
|
@@ -232,7 +246,7 @@ function CpqQuoteDetailPage(props) {
|
|
|
232
246
|
try {
|
|
233
247
|
const params = new URLSearchParams({ offeringId });
|
|
234
248
|
if (Object.keys(currentConfig).length > 0) params.set("configuration", JSON.stringify(currentConfig));
|
|
235
|
-
const result = await apiJson(`/api/cpq/quotes/attributes?${params}`);
|
|
249
|
+
const result = await apiJson(t, `/api/cpq/quotes/attributes?${params}`);
|
|
236
250
|
setAttributes(result.attributes ?? []);
|
|
237
251
|
} catch {
|
|
238
252
|
setAttributes([]);
|
|
@@ -249,7 +263,7 @@ function CpqQuoteDetailPage(props) {
|
|
|
249
263
|
const body = { offeringId: selectedOffering.id, configuration: config, quantity };
|
|
250
264
|
if (addingToParentLineId) body.parentLineId = addingToParentLineId;
|
|
251
265
|
if (tid) body.targetSubscriptionId = tid;
|
|
252
|
-
lastResult = await apiJson(`/api/cpq/quotes/${cpqQuote.id}/items`, {
|
|
266
|
+
lastResult = await apiJson(t, `/api/cpq/quotes/${cpqQuote.id}/items`, {
|
|
253
267
|
method: "POST",
|
|
254
268
|
headers: { "Content-Type": "application/json" },
|
|
255
269
|
body: JSON.stringify(body)
|
|
@@ -269,7 +283,7 @@ function CpqQuoteDetailPage(props) {
|
|
|
269
283
|
try {
|
|
270
284
|
setSubmitting(true);
|
|
271
285
|
setError(null);
|
|
272
|
-
const result = await apiJson(`/api/cpq/quotes/${cpqQuote.id}/items/${lineId}`, {
|
|
286
|
+
const result = await apiJson(t, `/api/cpq/quotes/${cpqQuote.id}/items/${lineId}`, {
|
|
273
287
|
method: "PUT",
|
|
274
288
|
headers: { "Content-Type": "application/json" },
|
|
275
289
|
body: JSON.stringify({ configuration: config, quantity })
|
|
@@ -295,7 +309,7 @@ function CpqQuoteDetailPage(props) {
|
|
|
295
309
|
try {
|
|
296
310
|
setSubmitting(true);
|
|
297
311
|
setError(null);
|
|
298
|
-
const result = await apiJson(`/api/cpq/quotes/${cpqQuote.id}/recalculate`, {
|
|
312
|
+
const result = await apiJson(t, `/api/cpq/quotes/${cpqQuote.id}/recalculate`, {
|
|
299
313
|
method: "POST",
|
|
300
314
|
headers: { "Content-Type": "application/json" },
|
|
301
315
|
body: JSON.stringify({ save: true })
|
|
@@ -312,7 +326,7 @@ function CpqQuoteDetailPage(props) {
|
|
|
312
326
|
try {
|
|
313
327
|
setConverting(true);
|
|
314
328
|
setError(null);
|
|
315
|
-
const result = await apiJson("/api/cpq/orders", {
|
|
329
|
+
const result = await apiJson(t, "/api/cpq/orders", {
|
|
316
330
|
method: "POST",
|
|
317
331
|
headers: { "Content-Type": "application/json" },
|
|
318
332
|
body: JSON.stringify({ quoteId: cpqQuote.id })
|
|
@@ -329,7 +343,7 @@ function CpqQuoteDetailPage(props) {
|
|
|
329
343
|
try {
|
|
330
344
|
setTransitioning(true);
|
|
331
345
|
setError(null);
|
|
332
|
-
const result = await apiJson(`/api/cpq/quotes/${cpqQuote.id}/status`, {
|
|
346
|
+
const result = await apiJson(t, `/api/cpq/quotes/${cpqQuote.id}/status`, {
|
|
333
347
|
method: "POST",
|
|
334
348
|
headers: { "Content-Type": "application/json" },
|
|
335
349
|
body: JSON.stringify({ targetStatus })
|
|
@@ -347,7 +361,7 @@ function CpqQuoteDetailPage(props) {
|
|
|
347
361
|
setDeleting(true);
|
|
348
362
|
setError(null);
|
|
349
363
|
setShowDeleteConfirm(false);
|
|
350
|
-
await apiJson(`/api/cpq/quotes/${cpqQuote.id}`, { method: "DELETE" });
|
|
364
|
+
await apiJson(t, `/api/cpq/quotes/${cpqQuote.id}`, { method: "DELETE" });
|
|
351
365
|
router.push("/backend/cpq/quotes");
|
|
352
366
|
} catch (err) {
|
|
353
367
|
setError(err.message);
|
|
@@ -381,7 +395,7 @@ function CpqQuoteDetailPage(props) {
|
|
|
381
395
|
setAddingTargetSubIds(inherited ? [inherited] : []);
|
|
382
396
|
if (offeringId) {
|
|
383
397
|
try {
|
|
384
|
-
const result = await apiJson("/api/cpq/product-offerings?pageSize=100&lifecycleStatus=active");
|
|
398
|
+
const result = await apiJson(t, "/api/cpq/product-offerings?pageSize=100&lifecycleStatus=active");
|
|
385
399
|
const match = (result.items ?? []).find((o) => o.id === offeringId);
|
|
386
400
|
if (match) {
|
|
387
401
|
selectOffering(match);
|
|
@@ -417,14 +431,15 @@ function CpqQuoteDetailPage(props) {
|
|
|
417
431
|
if (loading) {
|
|
418
432
|
return /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 py-12 justify-center text-sm text-muted-foreground", children: [
|
|
419
433
|
/* @__PURE__ */ jsx(Spinner, {}),
|
|
420
|
-
"
|
|
434
|
+
" ",
|
|
435
|
+
t("cpq.quotes.detail.loading", "Loading\u2026")
|
|
421
436
|
] });
|
|
422
437
|
}
|
|
423
438
|
if (!cpqQuote) {
|
|
424
439
|
return /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
|
|
425
|
-
/* @__PURE__ */ jsx("button", { onClick: () => router.push("/backend/cpq/quotes"), className: "text-sm text-muted-foreground hover:text-foreground", children: "\u2190 Back to Quotes" }),
|
|
440
|
+
/* @__PURE__ */ jsx("button", { onClick: () => router.push("/backend/cpq/quotes"), className: "text-sm text-muted-foreground hover:text-foreground", children: t("cpq.quotes.detail.backToQuotes", "\u2190 Back to Quotes") }),
|
|
426
441
|
error && /* @__PURE__ */ jsx(ErrorBanner, { message: error }),
|
|
427
|
-
/* @__PURE__ */ jsx("div", { className: "rounded-lg border bg-card p-6 text-center text-sm text-muted-foreground", children: "Quote not found." })
|
|
442
|
+
/* @__PURE__ */ jsx("div", { className: "rounded-lg border bg-card p-6 text-center text-sm text-muted-foreground", children: t("cpq.quotes.detail.notFound", "Quote not found.") })
|
|
428
443
|
] });
|
|
429
444
|
}
|
|
430
445
|
const { pricingSummary: summary, currencyCode: currency } = cpqQuote;
|
|
@@ -452,7 +467,7 @@ function CpqQuoteDetailPage(props) {
|
|
|
452
467
|
onChanged: async () => {
|
|
453
468
|
await loadArcTargets();
|
|
454
469
|
try {
|
|
455
|
-
const fresh = await apiJson(`/api/cpq/quotes/${cpqQuote.id}`);
|
|
470
|
+
const fresh = await apiJson(t, `/api/cpq/quotes/${cpqQuote.id}`);
|
|
456
471
|
setCpqQuote(fresh);
|
|
457
472
|
} catch {
|
|
458
473
|
}
|
|
@@ -464,13 +479,13 @@ function CpqQuoteDetailPage(props) {
|
|
|
464
479
|
{
|
|
465
480
|
mode: "detail",
|
|
466
481
|
backHref: "/backend/cpq/quotes",
|
|
467
|
-
backLabel: "Back to CPQ Quotes",
|
|
468
|
-
entityTypeLabel: "CPQ Quote",
|
|
469
|
-
title: cpqQuote.quoteNumber || cpqQuote.customerName || "Untitled",
|
|
482
|
+
backLabel: t("cpq.quotes.detail.backLabel", "Back to CPQ Quotes"),
|
|
483
|
+
entityTypeLabel: t("cpq.quotes.detail.entityType", "CPQ Quote"),
|
|
484
|
+
title: cpqQuote.quoteNumber || cpqQuote.customerName || t("cpq.quotes.detail.untitled", "Untitled"),
|
|
470
485
|
statusBadge: /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-2 pt-1", children: [
|
|
471
486
|
/* @__PURE__ */ jsx(Tag, { variant: quoteCpqStatusMap[cpqQuote.cpqStatus] ?? "neutral", dot: true, children: formatStatusLabel(cpqQuote.cpqStatus) }),
|
|
472
|
-
arcQuoteType !== "new" && /* @__PURE__ */ jsx(Tag, { variant: "brand", className: "uppercase", children: arcQuoteType }),
|
|
473
|
-
cpqQuote.convertedOrderId && /* @__PURE__ */ jsx(Tag, { variant: "success", dot: true, children: "Converted" })
|
|
487
|
+
arcQuoteType !== "new" && /* @__PURE__ */ jsx(Tag, { variant: "brand", className: "uppercase", children: quoteTypeLabel(t, arcQuoteType) }),
|
|
488
|
+
cpqQuote.convertedOrderId && /* @__PURE__ */ jsx(Tag, { variant: "success", dot: true, children: t("cpq.quotes.detail.converted", "Converted") })
|
|
474
489
|
] }),
|
|
475
490
|
actionsContent: /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
476
491
|
/* @__PURE__ */ jsxs(
|
|
@@ -481,7 +496,7 @@ function CpqQuoteDetailPage(props) {
|
|
|
481
496
|
onClick: () => router.push(`/backend/sales/quotes/${cpqQuote.quoteId}`),
|
|
482
497
|
children: [
|
|
483
498
|
/* @__PURE__ */ jsx(ExternalLink, { className: "h-3.5 w-3.5" }),
|
|
484
|
-
"View Sales Quote"
|
|
499
|
+
t("cpq.quotes.detail.viewSalesQuote", "View Sales Quote")
|
|
485
500
|
]
|
|
486
501
|
}
|
|
487
502
|
),
|
|
@@ -492,26 +507,27 @@ function CpqQuoteDetailPage(props) {
|
|
|
492
507
|
onClick: () => router.push(`/backend/cpq/orders/${cpqQuote.convertedOrderId}`),
|
|
493
508
|
children: [
|
|
494
509
|
/* @__PURE__ */ jsx(ArrowRight, { className: "h-4 w-4" }),
|
|
495
|
-
"Go to order"
|
|
510
|
+
t("cpq.quotes.detail.goToOrder", "Go to order")
|
|
496
511
|
]
|
|
497
512
|
}
|
|
498
513
|
) : view !== "summary" ? /* @__PURE__ */ jsx(Button, { type: "button", variant: "outline", onClick: () => {
|
|
499
514
|
resetConfigState();
|
|
500
515
|
setView("summary");
|
|
501
|
-
}, children: "Cancel" }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
516
|
+
}, children: t("cpq.common.cancel", "Cancel") }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
502
517
|
/* @__PURE__ */ jsxs(Button, { type: "button", onClick: startAddOffering, children: [
|
|
503
518
|
/* @__PURE__ */ jsx(Plus, { className: "h-4 w-4" }),
|
|
504
|
-
"Add Offering"
|
|
519
|
+
t("cpq.quotes.detail.addOffering", "Add Offering")
|
|
505
520
|
] }),
|
|
506
|
-
arcEditable && /* @__PURE__ */ jsx(Button, { type: "button", variant: "outline", onClick: () => setArcDrawerOpen(true), children: "Modify Subscription" }),
|
|
521
|
+
arcEditable && /* @__PURE__ */ jsx(Button, { type: "button", variant: "outline", onClick: () => setArcDrawerOpen(true), children: t("cpq.quotes.detail.modifySubscription", "Modify Subscription") }),
|
|
507
522
|
cpqQuote.cpqStatus === "accepted" && /* @__PURE__ */ jsxs(Button, { type: "button", onClick: convertToOrder, disabled: converting, children: [
|
|
508
523
|
converting ? /* @__PURE__ */ jsx(Spinner, {}) : /* @__PURE__ */ jsx(ArrowRight, { className: "h-4 w-4" }),
|
|
509
|
-
"Convert to Order"
|
|
524
|
+
t("cpq.quotes.detail.convertToOrder", "Convert to Order")
|
|
510
525
|
] }),
|
|
511
526
|
/* @__PURE__ */ jsx(
|
|
512
527
|
MoreActionsDropdown,
|
|
513
528
|
{
|
|
514
529
|
items: buildMoreActions({
|
|
530
|
+
t,
|
|
515
531
|
recalculate,
|
|
516
532
|
canRecalculate: canRecalculateQuote(grantedFeatures, cpqQuote.cpqStatus),
|
|
517
533
|
submitting,
|
|
@@ -535,19 +551,16 @@ function CpqQuoteDetailPage(props) {
|
|
|
535
551
|
statusMap: quoteCpqStatusMap,
|
|
536
552
|
onTransition: transitionStatus,
|
|
537
553
|
disabled: transitioning,
|
|
538
|
-
ariaLabel: "Quote status path"
|
|
554
|
+
ariaLabel: t("cpq.quotes.detail.statusPath", "Quote status path")
|
|
539
555
|
}
|
|
540
556
|
),
|
|
541
557
|
transitioning && /* @__PURE__ */ jsx(Spinner, {})
|
|
542
558
|
] }),
|
|
543
559
|
error && /* @__PURE__ */ jsx(ErrorBanner, { message: error, onDismiss: () => setError(null) }),
|
|
544
560
|
arcQuoteType !== "new" && arcTargets.length > 0 && /* @__PURE__ */ jsx("div", { className: "rounded-md border border-brand-violet/30 bg-brand-violet/10 px-4 py-3 text-sm text-brand-violet", children: /* @__PURE__ */ jsx("div", { className: "flex items-center justify-between", children: /* @__PURE__ */ jsxs("div", { children: [
|
|
545
|
-
/* @__PURE__ */ jsx("span", { className: "font-medium uppercase", children: arcQuoteType }),
|
|
561
|
+
/* @__PURE__ */ jsx("span", { className: "font-medium uppercase", children: quoteTypeLabel(t, arcQuoteType) }),
|
|
546
562
|
" \u2022 ",
|
|
547
|
-
arcTargets.length,
|
|
548
|
-
" target",
|
|
549
|
-
arcTargets.length === 1 ? "" : "s",
|
|
550
|
-
":",
|
|
563
|
+
arcTargets.length === 1 ? t("cpq.quotes.detail.arcTargets.one", "{count} target:", { count: arcTargets.length }) : t("cpq.quotes.detail.arcTargets.other", "{count} targets:", { count: arcTargets.length }),
|
|
551
564
|
" ",
|
|
552
565
|
arcTargets.map((t2, i) => /* @__PURE__ */ jsxs("span", { children: [
|
|
553
566
|
i > 0 && ", ",
|
|
@@ -560,34 +573,35 @@ function CpqQuoteDetailPage(props) {
|
|
|
560
573
|
}
|
|
561
574
|
)
|
|
562
575
|
] }, t2.id)),
|
|
563
|
-
isMergeRenew && /* @__PURE__ */ jsx("span", { className: "ml-2 text-status-warning-text font-medium", children: "\u2022 Merging into a new contract" })
|
|
576
|
+
isMergeRenew && /* @__PURE__ */ jsx("span", { className: "ml-2 text-status-warning-text font-medium", children: t("cpq.quotes.detail.mergingRenew", "\u2022 Merging into a new contract") })
|
|
564
577
|
] }) }) }),
|
|
565
578
|
/* @__PURE__ */ jsxs("div", { className: "grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-3", children: [
|
|
566
|
-
/* @__PURE__ */ jsx(MetaCard, { label: "Customer", children: cpqQuote.customerName ? /* @__PURE__ */ jsx("span", { className: "font-medium", children: cpqQuote.customerName }) : /* @__PURE__ */ jsxs("span", { className: "font-mono text-xs text-muted-foreground", children: [
|
|
579
|
+
/* @__PURE__ */ jsx(MetaCard, { label: t("cpq.quotes.detail.meta.customer", "Customer"), children: cpqQuote.customerName ? /* @__PURE__ */ jsx("span", { className: "font-medium", children: cpqQuote.customerName }) : /* @__PURE__ */ jsxs("span", { className: "font-mono text-xs text-muted-foreground", children: [
|
|
567
580
|
cpqQuote.customerId.slice(0, 8),
|
|
568
581
|
"\u2026"
|
|
569
582
|
] }) }),
|
|
570
|
-
/* @__PURE__ */ jsx(MetaCard, { label: "Version", children: /* @__PURE__ */ jsxs("span", { className: "font-medium", children: [
|
|
583
|
+
/* @__PURE__ */ jsx(MetaCard, { label: t("cpq.quotes.detail.meta.version", "Version"), children: /* @__PURE__ */ jsxs("span", { className: "font-medium", children: [
|
|
571
584
|
"v",
|
|
572
585
|
cpqQuote.version
|
|
573
586
|
] }) }),
|
|
574
|
-
/* @__PURE__ */ jsx(MetaCard, { label: "Currency", children: /* @__PURE__ */ jsx("span", { className: "font-medium", children: currency }) })
|
|
587
|
+
/* @__PURE__ */ jsx(MetaCard, { label: t("cpq.quotes.detail.meta.currency", "Currency"), children: /* @__PURE__ */ jsx("span", { className: "font-medium", children: currency }) })
|
|
575
588
|
] }),
|
|
576
589
|
showDeleteConfirm && /* @__PURE__ */ jsx("div", { className: "fixed inset-0 z-50 flex items-center justify-center bg-black/50", onClick: () => setShowDeleteConfirm(false), children: /* @__PURE__ */ jsxs("div", { className: "w-full max-w-sm rounded-lg border bg-card shadow-xl", onClick: (e) => e.stopPropagation(), children: [
|
|
577
|
-
/* @__PURE__ */ jsx("div", { className: "px-4 py-3 border-b", children: /* @__PURE__ */ jsx("h3", { className: "text-sm font-medium", children: "Delete Quote" }) }),
|
|
578
|
-
/* @__PURE__ */ jsx("div", { className: "p-4", children: /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: "Are you sure you want to delete this quote? This will soft-delete the quote and all its line items." }) }),
|
|
590
|
+
/* @__PURE__ */ jsx("div", { className: "px-4 py-3 border-b", children: /* @__PURE__ */ jsx("h3", { className: "text-sm font-medium", children: t("cpq.quotes.detail.deleteConfirm.title", "Delete Quote") }) }),
|
|
591
|
+
/* @__PURE__ */ jsx("div", { className: "p-4", children: /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: t("cpq.quotes.detail.deleteConfirm.text", "Are you sure you want to delete this quote? This will soft-delete the quote and all its line items.") }) }),
|
|
579
592
|
/* @__PURE__ */ jsxs("div", { className: "flex justify-end gap-2 px-4 py-3 border-t", children: [
|
|
580
|
-
/* @__PURE__ */ jsx(Button, { type: "button", variant: "outline", onClick: () => setShowDeleteConfirm(false), children: "Cancel" }),
|
|
593
|
+
/* @__PURE__ */ jsx(Button, { type: "button", variant: "outline", onClick: () => setShowDeleteConfirm(false), children: t("cpq.common.cancel", "Cancel") }),
|
|
581
594
|
/* @__PURE__ */ jsxs(Button, { type: "button", variant: "destructive", onClick: deleteQuote, disabled: deleting, children: [
|
|
582
595
|
deleting ? /* @__PURE__ */ jsx(Spinner, {}) : null,
|
|
583
|
-
"
|
|
596
|
+
" ",
|
|
597
|
+
t("cpq.common.delete", "Delete")
|
|
584
598
|
] })
|
|
585
599
|
] })
|
|
586
600
|
] }) }),
|
|
587
601
|
view === "summary" && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
588
602
|
/* @__PURE__ */ jsx(PricingSummaryCard, { summary, currency, arcDelta }),
|
|
589
603
|
!cpqQuote.validationResult.valid && /* @__PURE__ */ jsxs(Alert, { variant: "warning", children: [
|
|
590
|
-
/* @__PURE__ */ jsx(AlertTitle, { children: "Validation Issues" }),
|
|
604
|
+
/* @__PURE__ */ jsx(AlertTitle, { children: t("cpq.quotes.detail.validationIssues", "Validation Issues") }),
|
|
591
605
|
/* @__PURE__ */ jsx(AlertDescription, { children: /* @__PURE__ */ jsx("span", { className: "text-xs space-y-0.5 block", children: cpqQuote.validationResult.errors.map((e, i) => /* @__PURE__ */ jsxs("span", { className: "block", children: [
|
|
592
606
|
"\u2014 ",
|
|
593
607
|
e.message
|
|
@@ -631,8 +645,9 @@ function CpqQuoteDetailPage(props) {
|
|
|
631
645
|
] }),
|
|
632
646
|
view === "add-offering" && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
633
647
|
addingToParentLineId && /* @__PURE__ */ jsxs(Alert, { variant: "info", children: [
|
|
634
|
-
"Adding component to bundle:
|
|
635
|
-
|
|
648
|
+
t("cpq.quotes.detail.addingComponentTo", "Adding component to bundle:"),
|
|
649
|
+
" ",
|
|
650
|
+
/* @__PURE__ */ jsx("span", { className: "font-medium", children: cpqQuote.lines.find((l) => l.lineId === addingToParentLineId)?.offeringName ?? t("cpq.quotes.detail.bundleFallback", "Bundle") })
|
|
636
651
|
] }),
|
|
637
652
|
/* @__PURE__ */ jsx(
|
|
638
653
|
OfferingBrowser,
|
|
@@ -648,7 +663,7 @@ function CpqQuoteDetailPage(props) {
|
|
|
648
663
|
view === "configure" && selectedOffering && /* @__PURE__ */ jsx(
|
|
649
664
|
ConfigurePanel,
|
|
650
665
|
{
|
|
651
|
-
title: addingToParentLineId ?
|
|
666
|
+
title: addingToParentLineId ? t("cpq.quotes.detail.configure.addComponentTitle", "Add Component: {name}", { name: selectedOffering.name }) : t("cpq.quotes.detail.configure.configureTitle", "Configure: {name}", { name: selectedOffering.name }),
|
|
652
667
|
attributes,
|
|
653
668
|
config,
|
|
654
669
|
quantity,
|
|
@@ -670,14 +685,16 @@ function CpqQuoteDetailPage(props) {
|
|
|
670
685
|
},
|
|
671
686
|
onQuantityChange: setQuantity,
|
|
672
687
|
onSubmit: addItem,
|
|
673
|
-
submitLabel: "Add to Quote",
|
|
688
|
+
submitLabel: t("cpq.quotes.detail.configure.addToQuote", "Add to Quote"),
|
|
674
689
|
submitting
|
|
675
690
|
}
|
|
676
691
|
),
|
|
677
692
|
view === "edit" && editingLineId && /* @__PURE__ */ jsx(
|
|
678
693
|
ConfigurePanel,
|
|
679
694
|
{
|
|
680
|
-
title:
|
|
695
|
+
title: t("cpq.quotes.detail.configure.editTitle", "Edit: {name}", {
|
|
696
|
+
name: cpqQuote.lines.find((l) => l.lineId === editingLineId)?.offeringName ?? t("cpq.quotes.detail.configure.lineFallback", "Line")
|
|
697
|
+
}),
|
|
681
698
|
attributes,
|
|
682
699
|
config,
|
|
683
700
|
quantity,
|
|
@@ -693,13 +710,14 @@ function CpqQuoteDetailPage(props) {
|
|
|
693
710
|
},
|
|
694
711
|
onQuantityChange: setQuantity,
|
|
695
712
|
onSubmit: () => updateItem(editingLineId),
|
|
696
|
-
submitLabel: "Update Line",
|
|
713
|
+
submitLabel: t("cpq.quotes.detail.configure.updateLine", "Update Line"),
|
|
697
714
|
submitting
|
|
698
715
|
}
|
|
699
716
|
)
|
|
700
717
|
] }) }) });
|
|
701
718
|
}
|
|
702
719
|
function QuoteLineTree({ lines, currency, expandedLines, pricingDetail, targetCodes, onToggleLine, onEditLine, onRemoveLine, onAddComponent, onTogglePricingDetail }) {
|
|
720
|
+
const t = useT();
|
|
703
721
|
const [bundleTrees, setBundleTrees] = React.useState(/* @__PURE__ */ new Map());
|
|
704
722
|
const [loadingTrees, setLoadingTrees] = React.useState(/* @__PURE__ */ new Set());
|
|
705
723
|
const rootLines = lines.filter((l) => !l.parentLineId);
|
|
@@ -715,7 +733,7 @@ function QuoteLineTree({ lines, currency, expandedLines, pricingDetail, targetCo
|
|
|
715
733
|
if (bundleTrees.has(offeringId) || loadingTrees.has(offeringId)) return;
|
|
716
734
|
setLoadingTrees((prev) => new Set(prev).add(offeringId));
|
|
717
735
|
try {
|
|
718
|
-
const result = await apiJson(`/api/cpq/bundle-tree?offeringId=${offeringId}`);
|
|
736
|
+
const result = await apiJson(t, `/api/cpq/bundle-tree?offeringId=${offeringId}`);
|
|
719
737
|
setBundleTrees((prev) => new Map(prev).set(offeringId, result.tree));
|
|
720
738
|
} catch {
|
|
721
739
|
} finally {
|
|
@@ -725,10 +743,10 @@ function QuoteLineTree({ lines, currency, expandedLines, pricingDetail, targetCo
|
|
|
725
743
|
return n;
|
|
726
744
|
});
|
|
727
745
|
}
|
|
728
|
-
}, [bundleTrees, loadingTrees]);
|
|
746
|
+
}, [bundleTrees, loadingTrees, t]);
|
|
729
747
|
return /* @__PURE__ */ jsxs("div", { children: [
|
|
730
|
-
/* @__PURE__ */ jsx("h3", { className: "text-sm font-medium mb-2 px-1", children: "Line Items" }),
|
|
731
|
-
lines.length === 0 ? /* @__PURE__ */ jsx("div", { className: "rounded-lg border bg-card py-8 text-center text-sm text-muted-foreground", children: 'No items configured yet. Click "Add Offering" to start.' }) : /* @__PURE__ */ jsx("div", { className: "rounded-lg border bg-card divide-y", children: rootLines.map((line) => {
|
|
748
|
+
/* @__PURE__ */ jsx("h3", { className: "text-sm font-medium mb-2 px-1", children: t("cpq.quotes.detail.lineItems", "Line Items") }),
|
|
749
|
+
lines.length === 0 ? /* @__PURE__ */ jsx("div", { className: "rounded-lg border bg-card py-8 text-center text-sm text-muted-foreground", children: t("cpq.quotes.detail.noLines", 'No items configured yet. Click "Add Offering" to start.') }) : /* @__PURE__ */ jsx("div", { className: "rounded-lg border bg-card divide-y", children: rootLines.map((line) => {
|
|
732
750
|
const lineIdx = lines.indexOf(line);
|
|
733
751
|
const isBundle = line.offeringType === "bundle";
|
|
734
752
|
const children = childrenByParent.get(line.lineId) ?? [];
|
|
@@ -782,10 +800,12 @@ function QuoteLineTree({ lines, currency, expandedLines, pricingDetail, targetCo
|
|
|
782
800
|
] });
|
|
783
801
|
}
|
|
784
802
|
function BundleSlotPanel({ bundleTree, treeLoading, children, allLines, currency, expandedLines, pricingDetail, parentLineId, targetCodes, onToggleLine, onEditLine, onRemoveLine, onAddComponent, onTogglePricingDetail }) {
|
|
803
|
+
const t = useT();
|
|
785
804
|
if (treeLoading) {
|
|
786
805
|
return /* @__PURE__ */ jsx("div", { className: "border-t bg-muted/5 px-8 py-3", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-xs text-muted-foreground", children: [
|
|
787
806
|
/* @__PURE__ */ jsx(Spinner, {}),
|
|
788
|
-
"
|
|
807
|
+
" ",
|
|
808
|
+
t("cpq.quotes.bundle.loadingStructure", "Loading bundle structure\u2026")
|
|
789
809
|
] }) });
|
|
790
810
|
}
|
|
791
811
|
if (!bundleTree || bundleTree.slots.length === 0) {
|
|
@@ -826,12 +846,13 @@ function BundleSlotPanel({ bundleTree, treeLoading, children, allLines, currency
|
|
|
826
846
|
return /* @__PURE__ */ jsxs("div", { className: "border-b last:border-b-0", children: [
|
|
827
847
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 px-6 py-2 bg-muted/20", children: [
|
|
828
848
|
/* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-muted-foreground uppercase tracking-wide", children: slot.name }),
|
|
829
|
-
isRequired ? /* @__PURE__ */ jsx(Tag, { variant: "warning", className: "text-[10px] px-1.5", children: "required" }) : /* @__PURE__ */ jsx(Tag, { variant: "neutral", className: "text-[10px] px-1.5", children: "optional" }),
|
|
849
|
+
isRequired ? /* @__PURE__ */ jsx(Tag, { variant: "warning", className: "text-[10px] px-1.5", children: t("cpq.quotes.bundle.slotRequired", "required") }) : /* @__PURE__ */ jsx(Tag, { variant: "neutral", className: "text-[10px] px-1.5", children: t("cpq.quotes.bundle.slotOptional", "optional") }),
|
|
830
850
|
/* @__PURE__ */ jsxs("span", { className: "text-[10px] text-muted-foreground", children: [
|
|
831
851
|
filledCount,
|
|
832
852
|
"/",
|
|
833
853
|
slot.cardinalityMax ?? "\u221E",
|
|
834
|
-
slot.cardinalityMin > 0 &&
|
|
854
|
+
slot.cardinalityMin > 0 && " ",
|
|
855
|
+
slot.cardinalityMin > 0 && t("cpq.quotes.bundle.slotMin", "(min {min})", { min: slot.cardinalityMin })
|
|
835
856
|
] }),
|
|
836
857
|
/* @__PURE__ */ jsx("div", { className: "flex-1" }),
|
|
837
858
|
/* @__PURE__ */ jsx("div", { className: "flex items-center gap-1", children: slot.components.map((comp) => {
|
|
@@ -842,7 +863,7 @@ function BundleSlotPanel({ bundleTree, treeLoading, children, allLines, currency
|
|
|
842
863
|
onClick: () => !isFilled && canAdd && onAddComponent(parentLineId, comp.childOffering.offeringId),
|
|
843
864
|
disabled: isFilled || !canAdd,
|
|
844
865
|
className: `inline-flex items-center gap-1 rounded border px-2 py-1 text-[11px] font-medium transition-colors ${isFilled ? "border-status-success-border bg-status-success-bg text-status-success-text cursor-default" : canAdd ? "border-border hover:border-primary hover:bg-primary/5 hover:text-primary cursor-pointer" : "border-border text-muted-foreground opacity-50 cursor-not-allowed"}`,
|
|
845
|
-
title: isFilled ? "Already added" : canAdd ?
|
|
866
|
+
title: isFilled ? t("cpq.quotes.bundle.alreadyAdded", "Already added") : canAdd ? t("cpq.quotes.bundle.addComponent", "Add {name}", { name: comp.childOffering.offeringName }) : t("cpq.quotes.bundle.slotFull", "Slot is full"),
|
|
846
867
|
children: [
|
|
847
868
|
isFilled ? /* @__PURE__ */ jsx("svg", { className: "h-3 w-3", fill: "none", viewBox: "0 0 24 24", strokeWidth: "2", stroke: "currentColor", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M4.5 12.75l6 6 9-13.5" }) }) : /* @__PURE__ */ jsx("svg", { className: "h-3 w-3", fill: "none", viewBox: "0 0 24 24", strokeWidth: "2", stroke: "currentColor", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M12 4.5v15m7.5-7.5h-15" }) }),
|
|
848
869
|
comp.childOffering.offeringName
|
|
@@ -917,7 +938,7 @@ function QuoteLineRow({ line, lineIdx, currency, isExpanded, pricingDetail, isBu
|
|
|
917
938
|
/* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0", children: [
|
|
918
939
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
919
940
|
indent > 0 && /* @__PURE__ */ jsx("span", { className: "text-muted-foreground text-xs", children: "\u2514" }),
|
|
920
|
-
isBundle && /* @__PURE__ */ jsx(Tag, { variant: "brand", className: "px-1.5 text-xs", children: "bundle" }),
|
|
941
|
+
isBundle && /* @__PURE__ */ jsx(Tag, { variant: "brand", className: "px-1.5 text-xs", children: t("cpq.lines.bundle", "bundle") }),
|
|
921
942
|
/* @__PURE__ */ jsx("span", { className: `font-medium text-sm ${isRemoved ? "text-muted-foreground line-through" : ""}`, children: line.offeringName }),
|
|
922
943
|
line.quantity > 1 && /* @__PURE__ */ jsxs("span", { className: "rounded bg-muted px-1.5 py-0.5 text-xs font-medium", children: [
|
|
923
944
|
"\xD7",
|
|
@@ -948,33 +969,38 @@ function QuoteLineRow({ line, lineIdx, currency, isExpanded, pricingDetail, isBu
|
|
|
948
969
|
{
|
|
949
970
|
variant: "brand",
|
|
950
971
|
className: "px-1.5 text-xs",
|
|
951
|
-
title:
|
|
972
|
+
title: t("cpq.quotes.detail.actsOnSubscription", "Acts on subscription {code}", { code: targetCodes.get(line.targetSubscriptionId) ?? "" }),
|
|
952
973
|
children: [
|
|
953
974
|
"\u2192 ",
|
|
954
975
|
targetCodes.get(line.targetSubscriptionId)
|
|
955
976
|
]
|
|
956
977
|
}
|
|
957
978
|
),
|
|
958
|
-
isRemoved ? null : line.isConfigured ? /* @__PURE__ */ jsx(Tag, { variant: "success", className: "px-1.5 text-xs", children: "configured" }) : /* @__PURE__ */ jsx(Tag, { variant: "warning", className: "px-1.5 text-xs", children: "incomplete" }),
|
|
959
|
-
isBundle && /* @__PURE__ */
|
|
960
|
-
childCount,
|
|
961
|
-
" component",
|
|
962
|
-
childCount !== 1 ? "s" : ""
|
|
963
|
-
] })
|
|
979
|
+
isRemoved ? null : line.isConfigured ? /* @__PURE__ */ jsx(Tag, { variant: "success", className: "px-1.5 text-xs", children: t("cpq.quotes.detail.lineConfigured", "configured") }) : /* @__PURE__ */ jsx(Tag, { variant: "warning", className: "px-1.5 text-xs", children: t("cpq.quotes.detail.lineIncomplete", "incomplete") }),
|
|
980
|
+
isBundle && /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: childCount !== 1 ? t("cpq.lines.componentCount.other", "{count} components", { count: childCount }) : t("cpq.lines.componentCount.one", "{count} component", { count: childCount }) })
|
|
964
981
|
] }),
|
|
965
982
|
line.validationErrors && line.validationErrors.length > 0 && /* @__PURE__ */ jsx("p", { className: "text-xs text-destructive mt-0.5", children: line.validationErrors[0].message })
|
|
966
983
|
] }),
|
|
967
984
|
/* @__PURE__ */ jsxs("div", { className: "shrink-0 text-right text-xs space-y-0.5", children: [
|
|
968
985
|
isRemoved && line.arcSource && line.arcSource.mrcAmount > 0 && /* @__PURE__ */ jsxs("div", { children: [
|
|
969
|
-
/* @__PURE__ */
|
|
986
|
+
/* @__PURE__ */ jsxs("span", { className: "text-muted-foreground", children: [
|
|
987
|
+
t("cpq.lines.mrc", "MRC"),
|
|
988
|
+
" "
|
|
989
|
+
] }),
|
|
970
990
|
/* @__PURE__ */ jsx("span", { className: "font-mono text-muted-foreground line-through", children: fmt(line.arcSource.mrcAmount, currency) })
|
|
971
991
|
] }),
|
|
972
992
|
line.nrcTotal > 0 && /* @__PURE__ */ jsxs("div", { children: [
|
|
973
|
-
/* @__PURE__ */
|
|
993
|
+
/* @__PURE__ */ jsxs("span", { className: "text-muted-foreground", children: [
|
|
994
|
+
t("cpq.lines.nrc", "NRC"),
|
|
995
|
+
" "
|
|
996
|
+
] }),
|
|
974
997
|
/* @__PURE__ */ jsx("span", { className: "font-mono font-medium", children: fmt(line.nrcTotal, currency) })
|
|
975
998
|
] }),
|
|
976
999
|
line.mrcTotal > 0 && /* @__PURE__ */ jsxs("div", { children: [
|
|
977
|
-
/* @__PURE__ */
|
|
1000
|
+
/* @__PURE__ */ jsxs("span", { className: "text-muted-foreground", children: [
|
|
1001
|
+
t("cpq.lines.mrc", "MRC"),
|
|
1002
|
+
" "
|
|
1003
|
+
] }),
|
|
978
1004
|
/* @__PURE__ */ jsx("span", { className: "font-mono font-medium", children: fmt(line.mrcTotal, currency) })
|
|
979
1005
|
] })
|
|
980
1006
|
] }),
|
|
@@ -994,9 +1020,9 @@ function QuoteLineRow({ line, lineIdx, currency, isExpanded, pricingDetail, isBu
|
|
|
994
1020
|
}
|
|
995
1021
|
) }) : /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1 shrink-0", children: [
|
|
996
1022
|
/* @__PURE__ */ jsx(DiscountLineAction, { line }),
|
|
997
|
-
onAddComponent && /* @__PURE__ */ jsx("button", { onClick: onAddComponent, className: "rounded p-1.5 text-muted-foreground hover:text-primary hover:bg-primary/5 transition-colors", title: "Add Component", children: /* @__PURE__ */ jsx("svg", { className: "h-4 w-4", fill: "none", viewBox: "0 0 24 24", strokeWidth: "1.5", stroke: "currentColor", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M12 4.5v15m7.5-7.5h-15" }) }) }),
|
|
998
|
-
/* @__PURE__ */ jsx("button", { onClick: onEdit, className: "rounded p-1.5 text-muted-foreground hover:text-foreground hover:bg-muted transition-colors", title: "Edit", children: /* @__PURE__ */ jsx("svg", { className: "h-4 w-4", fill: "none", viewBox: "0 0 24 24", strokeWidth: "1.5", stroke: "currentColor", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M16.862 4.487l1.687-1.688a1.875 1.875 0 112.652 2.652L10.582 16.07a4.5 4.5 0 01-1.897 1.13L6 18l.8-2.685a4.5 4.5 0 011.13-1.897l8.932-8.931zm0 0L19.5 7.125M18 14v4.75A2.25 2.25 0 0115.75 21H5.25A2.25 2.25 0 013 18.75V8.25A2.25 2.25 0 015.25 6H10" }) }) }),
|
|
999
|
-
/* @__PURE__ */ jsx("button", { onClick: onRemove, className: "rounded p-1.5 text-muted-foreground hover:text-destructive hover:bg-destructive/10 transition-colors", title: "Remove", children: /* @__PURE__ */ jsx("svg", { className: "h-4 w-4", fill: "none", viewBox: "0 0 24 24", strokeWidth: "1.5", stroke: "currentColor", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M14.74 9l-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 01-2.244 2.077H8.084a2.25 2.25 0 01-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 00-3.478-.397m-12 .562c.34-.059.68-.114 1.022-.165m0 0a48.11 48.11 0 013.478-.397m7.5 0v-.916c0-1.18-.91-2.164-2.09-2.201a51.964 51.964 0 00-3.32 0c-1.18.037-2.09 1.022-2.09 2.201v.916m7.5 0a48.667 48.667 0 00-7.5 0" }) }) })
|
|
1023
|
+
onAddComponent && /* @__PURE__ */ jsx("button", { onClick: onAddComponent, className: "rounded p-1.5 text-muted-foreground hover:text-primary hover:bg-primary/5 transition-colors", title: t("cpq.quotes.detail.addComponent", "Add Component"), children: /* @__PURE__ */ jsx("svg", { className: "h-4 w-4", fill: "none", viewBox: "0 0 24 24", strokeWidth: "1.5", stroke: "currentColor", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M12 4.5v15m7.5-7.5h-15" }) }) }),
|
|
1024
|
+
/* @__PURE__ */ jsx("button", { onClick: onEdit, className: "rounded p-1.5 text-muted-foreground hover:text-foreground hover:bg-muted transition-colors", title: t("cpq.common.edit", "Edit"), children: /* @__PURE__ */ jsx("svg", { className: "h-4 w-4", fill: "none", viewBox: "0 0 24 24", strokeWidth: "1.5", stroke: "currentColor", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M16.862 4.487l1.687-1.688a1.875 1.875 0 112.652 2.652L10.582 16.07a4.5 4.5 0 01-1.897 1.13L6 18l.8-2.685a4.5 4.5 0 011.13-1.897l8.932-8.931zm0 0L19.5 7.125M18 14v4.75A2.25 2.25 0 0115.75 21H5.25A2.25 2.25 0 013 18.75V8.25A2.25 2.25 0 015.25 6H10" }) }) }),
|
|
1025
|
+
/* @__PURE__ */ jsx("button", { onClick: onRemove, className: "rounded p-1.5 text-muted-foreground hover:text-destructive hover:bg-destructive/10 transition-colors", title: t("cpq.quotes.detail.removeLine", "Remove"), children: /* @__PURE__ */ jsx("svg", { className: "h-4 w-4", fill: "none", viewBox: "0 0 24 24", strokeWidth: "1.5", stroke: "currentColor", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M14.74 9l-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 01-2.244 2.077H8.084a2.25 2.25 0 01-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 00-3.478-.397m-12 .562c.34-.059.68-.114 1.022-.165m0 0a48.11 48.11 0 013.478-.397m7.5 0v-.916c0-1.18-.91-2.164-2.09-2.201a51.964 51.964 0 00-3.32 0c-1.18.037-2.09 1.022-2.09 2.201v.916m7.5 0a48.667 48.667 0 00-7.5 0" }) }) })
|
|
1000
1026
|
] })
|
|
1001
1027
|
] }),
|
|
1002
1028
|
isExpanded && !isBundle && line.charges.length > 0 && /* @__PURE__ */ jsx(ChargeBreakdown, { line, lineIdx, currency, pricingDetail, onTogglePricingDetail, ...chargeActions }),
|
|
@@ -1006,20 +1032,24 @@ function QuoteLineRow({ line, lineIdx, currency, isExpanded, pricingDetail, isBu
|
|
|
1006
1032
|
] });
|
|
1007
1033
|
}
|
|
1008
1034
|
function LineSummaryFallback({ line, currency }) {
|
|
1035
|
+
const t = useT();
|
|
1009
1036
|
const hasTotals = line.nrcTotal > 0 || line.mrcTotal > 0;
|
|
1010
1037
|
const mirroredFromItemId = line.configuration?._arcMirroredFromItemId ?? null;
|
|
1011
1038
|
return /* @__PURE__ */ jsxs("div", { className: "border-t bg-muted/10 px-12 py-2 text-xs text-muted-foreground space-y-1", children: [
|
|
1012
1039
|
/* @__PURE__ */ jsxs("div", { children: [
|
|
1013
|
-
"No detailed charge breakdown available for this line.",
|
|
1014
|
-
mirroredFromItemId && "
|
|
1040
|
+
t("cpq.quotes.detail.noBreakdown", "No detailed charge breakdown available for this line."),
|
|
1041
|
+
mirroredFromItemId && " ",
|
|
1042
|
+
mirroredFromItemId && t("cpq.orders.detail.mirroredItem", "Mirrored from existing subscription item.")
|
|
1015
1043
|
] }),
|
|
1016
1044
|
hasTotals && /* @__PURE__ */ jsxs("div", { className: "flex gap-4", children: [
|
|
1017
1045
|
line.nrcTotal > 0 && /* @__PURE__ */ jsxs("span", { children: [
|
|
1018
|
-
"
|
|
1046
|
+
t("cpq.lines.nrc", "NRC"),
|
|
1047
|
+
" ",
|
|
1019
1048
|
/* @__PURE__ */ jsx("span", { className: "font-mono font-medium text-foreground", children: fmt(line.nrcTotal, currency) })
|
|
1020
1049
|
] }),
|
|
1021
1050
|
line.mrcTotal > 0 && /* @__PURE__ */ jsxs("span", { children: [
|
|
1022
|
-
"
|
|
1051
|
+
t("cpq.lines.mrc", "MRC"),
|
|
1052
|
+
" ",
|
|
1023
1053
|
/* @__PURE__ */ jsx("span", { className: "font-mono font-medium text-foreground", children: fmt(line.mrcTotal, currency) })
|
|
1024
1054
|
] })
|
|
1025
1055
|
] })
|
|
@@ -1043,6 +1073,7 @@ function Spinner() {
|
|
|
1043
1073
|
] });
|
|
1044
1074
|
}
|
|
1045
1075
|
function ErrorBanner({ message, onDismiss }) {
|
|
1076
|
+
const t = useT();
|
|
1046
1077
|
return /* @__PURE__ */ jsxs(Alert, { variant: "destructive", className: "flex items-start gap-2", children: [
|
|
1047
1078
|
/* @__PURE__ */ jsx("span", { className: "flex-1", children: message }),
|
|
1048
1079
|
onDismiss && /* @__PURE__ */ jsx(
|
|
@@ -1050,27 +1081,28 @@ function ErrorBanner({ message, onDismiss }) {
|
|
|
1050
1081
|
{
|
|
1051
1082
|
onClick: onDismiss,
|
|
1052
1083
|
className: "text-destructive/70 hover:text-destructive text-sm font-bold",
|
|
1053
|
-
"aria-label": "Dismiss",
|
|
1084
|
+
"aria-label": t("cpq.common.dismiss", "Dismiss"),
|
|
1054
1085
|
children: "\xD7"
|
|
1055
1086
|
}
|
|
1056
1087
|
)
|
|
1057
1088
|
] });
|
|
1058
1089
|
}
|
|
1059
1090
|
function OfferingBrowser({ offerings, loading, search, onSearchChange, onSelect }) {
|
|
1091
|
+
const t = useT();
|
|
1060
1092
|
const filtered = offerings.filter((o) => {
|
|
1061
1093
|
if (!search.trim()) return true;
|
|
1062
1094
|
const q = search.toLowerCase();
|
|
1063
1095
|
return o.name.toLowerCase().includes(q) || o.code.toLowerCase().includes(q) || (o.description ?? "").toLowerCase().includes(q);
|
|
1064
1096
|
});
|
|
1065
1097
|
return /* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
|
|
1066
|
-
/* @__PURE__ */ jsx("h3", { className: "text-sm font-medium px-1", children: "Select Product Offering" }),
|
|
1098
|
+
/* @__PURE__ */ jsx("h3", { className: "text-sm font-medium px-1", children: t("cpq.quotes.offeringBrowser.title", "Select Product Offering") }),
|
|
1067
1099
|
/* @__PURE__ */ jsxs("div", { className: "relative", children: [
|
|
1068
1100
|
/* @__PURE__ */ jsx("svg", { className: "absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground", fill: "none", viewBox: "0 0 24 24", strokeWidth: "2", stroke: "currentColor", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M21 21l-5.197-5.197m0 0A7.5 7.5 0 105.196 5.196a7.5 7.5 0 0010.607 10.607z" }) }),
|
|
1069
1101
|
/* @__PURE__ */ jsx(
|
|
1070
1102
|
"input",
|
|
1071
1103
|
{
|
|
1072
1104
|
type: "text",
|
|
1073
|
-
placeholder: "Search offerings\u2026",
|
|
1105
|
+
placeholder: t("cpq.quotes.offeringBrowser.searchPlaceholder", "Search offerings\u2026"),
|
|
1074
1106
|
value: search,
|
|
1075
1107
|
onChange: (e) => onSearchChange(e.target.value),
|
|
1076
1108
|
className: "w-full rounded-md border bg-background pl-10 pr-4 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-primary/50"
|
|
@@ -1079,8 +1111,9 @@ function OfferingBrowser({ offerings, loading, search, onSearchChange, onSelect
|
|
|
1079
1111
|
] }),
|
|
1080
1112
|
loading ? /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 py-8 justify-center text-sm text-muted-foreground", children: [
|
|
1081
1113
|
/* @__PURE__ */ jsx(Spinner, {}),
|
|
1082
|
-
"
|
|
1083
|
-
|
|
1114
|
+
" ",
|
|
1115
|
+
t("cpq.quotes.offeringBrowser.loading", "Loading offerings\u2026")
|
|
1116
|
+
] }) : filtered.length === 0 ? /* @__PURE__ */ jsx("div", { className: "py-8 text-center text-sm text-muted-foreground", children: search ? t("cpq.quotes.offeringBrowser.noMatch", "No offerings match your search.") : t("cpq.quotes.offeringBrowser.empty", "No active offerings available.") }) : /* @__PURE__ */ jsx("div", { className: "grid gap-2 sm:grid-cols-2 lg:grid-cols-3", children: filtered.map((offering) => /* @__PURE__ */ jsxs(
|
|
1084
1117
|
"button",
|
|
1085
1118
|
{
|
|
1086
1119
|
onClick: () => onSelect(offering),
|
|
@@ -1096,13 +1129,14 @@ function OfferingBrowser({ offerings, loading, search, onSearchChange, onSelect
|
|
|
1096
1129
|
] });
|
|
1097
1130
|
}
|
|
1098
1131
|
function ConfigurePanel({ title, attributes, config, quantity, arcTargetOptions, arcSelectedTargetIds, onArcTargetToggle, onConfigChange, onQuantityChange, onSubmit, submitLabel, submitting }) {
|
|
1132
|
+
const t = useT();
|
|
1099
1133
|
const noTargetsPicked = arcTargetOptions !== null && arcTargetOptions.length > 0 && arcSelectedTargetIds.length === 0;
|
|
1100
1134
|
return /* @__PURE__ */ jsxs("div", { className: "rounded-lg border bg-card", children: [
|
|
1101
1135
|
/* @__PURE__ */ jsx("div", { className: "border-b px-4 py-3", children: /* @__PURE__ */ jsx("h3", { className: "text-sm font-medium", children: title }) }),
|
|
1102
1136
|
/* @__PURE__ */ jsxs("div", { className: "p-4 space-y-4", children: [
|
|
1103
1137
|
arcTargetOptions && arcTargetOptions.length > 0 && /* @__PURE__ */ jsxs("div", { children: [
|
|
1104
1138
|
/* @__PURE__ */ jsxs("label", { className: "block text-sm font-medium mb-1", children: [
|
|
1105
|
-
"Apply to subscription(s)",
|
|
1139
|
+
t("cpq.quotes.detail.configure.applyToSubscriptions", "Apply to subscription(s)"),
|
|
1106
1140
|
/* @__PURE__ */ jsx("span", { className: "text-destructive ml-1", children: "*" })
|
|
1107
1141
|
] }),
|
|
1108
1142
|
/* @__PURE__ */ jsx("div", { className: "space-y-1.5 rounded-md border bg-background px-3 py-2", children: arcTargetOptions.map((opt) => {
|
|
@@ -1131,11 +1165,11 @@ function ConfigurePanel({ title, attributes, config, quantity, arcTargetOptions,
|
|
|
1131
1165
|
opt.subscriptionId
|
|
1132
1166
|
);
|
|
1133
1167
|
}) }),
|
|
1134
|
-
/* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground mt-1", children: "Pick one or more \u2014 a separate line will be created on each selected subscription." }),
|
|
1135
|
-
noTargetsPicked && /* @__PURE__ */ jsx("p", { className: "text-xs text-destructive mt-1", children: "Select at least one target." })
|
|
1168
|
+
/* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground mt-1", children: t("cpq.quotes.detail.configure.applyToSubscriptionsHint", "Pick one or more \u2014 a separate line will be created on each selected subscription.") }),
|
|
1169
|
+
noTargetsPicked && /* @__PURE__ */ jsx("p", { className: "text-xs text-destructive mt-1", children: t("cpq.quotes.detail.configure.selectTarget", "Select at least one target.") })
|
|
1136
1170
|
] }),
|
|
1137
1171
|
/* @__PURE__ */ jsxs("div", { children: [
|
|
1138
|
-
/* @__PURE__ */ jsx("label", { className: "block text-sm font-medium mb-1", children: "Quantity" }),
|
|
1172
|
+
/* @__PURE__ */ jsx("label", { className: "block text-sm font-medium mb-1", children: t("cpq.quotes.detail.configure.quantity", "Quantity") }),
|
|
1139
1173
|
/* @__PURE__ */ jsx(
|
|
1140
1174
|
NumberInput,
|
|
1141
1175
|
{
|
|
@@ -1147,7 +1181,7 @@ function ConfigurePanel({ title, attributes, config, quantity, arcTargetOptions,
|
|
|
1147
1181
|
}
|
|
1148
1182
|
)
|
|
1149
1183
|
] }),
|
|
1150
|
-
attributes.length === 0 ? /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: "No configurable attributes for this offering." }) : attributes.map((attr) => /* @__PURE__ */ jsx(AttributeField, { attribute: attr, value: config[attr.code], onChange: (v) => onConfigChange(attr.code, v) }, attr.code))
|
|
1184
|
+
attributes.length === 0 ? /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: t("cpq.quotes.detail.configure.noAttributes", "No configurable attributes for this offering.") }) : attributes.map((attr) => /* @__PURE__ */ jsx(AttributeField, { attribute: attr, value: config[attr.code], onChange: (v) => onConfigChange(attr.code, v) }, attr.code))
|
|
1151
1185
|
] }),
|
|
1152
1186
|
/* @__PURE__ */ jsx("div", { className: "border-t px-4 py-3 flex justify-end", children: /* @__PURE__ */ jsxs(
|
|
1153
1187
|
"button",
|
|
@@ -1165,6 +1199,7 @@ function ConfigurePanel({ title, attributes, config, quantity, arcTargetOptions,
|
|
|
1165
1199
|
] });
|
|
1166
1200
|
}
|
|
1167
1201
|
function AttributeField({ attribute, value, onChange }) {
|
|
1202
|
+
const t = useT();
|
|
1168
1203
|
const { code, name, attributeType, isRequired, options, constraints, helpText, defaultValue } = attribute;
|
|
1169
1204
|
const currentValue = value ?? defaultValue ?? "";
|
|
1170
1205
|
return /* @__PURE__ */ jsxs("div", { children: [
|
|
@@ -1179,13 +1214,13 @@ function AttributeField({ attribute, value, onChange }) {
|
|
|
1179
1214
|
onChange: (e) => onChange(e.target.value),
|
|
1180
1215
|
className: "w-full rounded-md border bg-background px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-primary/50",
|
|
1181
1216
|
children: [
|
|
1182
|
-
/* @__PURE__ */ jsx("option", { value: "", children: "\u2014 Select \u2014" }),
|
|
1217
|
+
/* @__PURE__ */ jsx("option", { value: "", children: t("cpq.quotes.detail.configure.selectPlaceholder", "\u2014 Select \u2014") }),
|
|
1183
1218
|
options.map((opt) => /* @__PURE__ */ jsx("option", { value: opt.value, children: opt.label }, opt.value))
|
|
1184
1219
|
]
|
|
1185
1220
|
}
|
|
1186
1221
|
) : attributeType === "boolean" ? /* @__PURE__ */ jsxs("label", { className: "flex items-center gap-2", children: [
|
|
1187
1222
|
/* @__PURE__ */ jsx("input", { type: "checkbox", checked: Boolean(currentValue), onChange: (e) => onChange(e.target.checked), className: "rounded border-border" }),
|
|
1188
|
-
/* @__PURE__ */ jsx("span", { className: "text-sm text-muted-foreground", children: helpText ?? "Enable" })
|
|
1223
|
+
/* @__PURE__ */ jsx("span", { className: "text-sm text-muted-foreground", children: helpText ?? t("cpq.quotes.detail.configure.enable", "Enable") })
|
|
1189
1224
|
] }) : attributeType === "number" ? /* @__PURE__ */ jsx(
|
|
1190
1225
|
NumberInput,
|
|
1191
1226
|
{
|