@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.
Files changed (164) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/dist/modules/cpq/backend/cpq/inventory/AssetsTable.js +3 -9
  3. package/dist/modules/cpq/backend/cpq/inventory/AssetsTable.js.map +2 -2
  4. package/dist/modules/cpq/backend/cpq/inventory/SubscriptionsTable.js +21 -25
  5. package/dist/modules/cpq/backend/cpq/inventory/SubscriptionsTable.js.map +2 -2
  6. package/dist/modules/cpq/backend/cpq/inventory/assets/[id]/page.js +48 -47
  7. package/dist/modules/cpq/backend/cpq/inventory/assets/[id]/page.js.map +2 -2
  8. package/dist/modules/cpq/backend/cpq/inventory/assets/[id]/page.meta.js +1 -1
  9. package/dist/modules/cpq/backend/cpq/inventory/assets/[id]/page.meta.js.map +2 -2
  10. package/dist/modules/cpq/backend/cpq/inventory/page.meta.js +2 -2
  11. package/dist/modules/cpq/backend/cpq/inventory/page.meta.js.map +2 -2
  12. package/dist/modules/cpq/backend/cpq/inventory/shared.js +37 -2
  13. package/dist/modules/cpq/backend/cpq/inventory/shared.js.map +2 -2
  14. package/dist/modules/cpq/backend/cpq/inventory/subscriptions/[id]/page.js +154 -178
  15. package/dist/modules/cpq/backend/cpq/inventory/subscriptions/[id]/page.js.map +2 -2
  16. package/dist/modules/cpq/backend/cpq/inventory/subscriptions/[id]/page.meta.js +1 -1
  17. package/dist/modules/cpq/backend/cpq/inventory/subscriptions/[id]/page.meta.js.map +2 -2
  18. package/dist/modules/cpq/backend/cpq/offerings/[id]/page.js +168 -143
  19. package/dist/modules/cpq/backend/cpq/offerings/[id]/page.js.map +2 -2
  20. package/dist/modules/cpq/backend/cpq/offerings/page.js +36 -34
  21. package/dist/modules/cpq/backend/cpq/offerings/page.js.map +2 -2
  22. package/dist/modules/cpq/backend/cpq/orders/[id]/page.js +69 -66
  23. package/dist/modules/cpq/backend/cpq/orders/[id]/page.js.map +2 -2
  24. package/dist/modules/cpq/backend/cpq/orders/page.js +6 -6
  25. package/dist/modules/cpq/backend/cpq/orders/page.js.map +2 -2
  26. package/dist/modules/cpq/backend/cpq/price-rules/PriceRuleForm.js +41 -36
  27. package/dist/modules/cpq/backend/cpq/price-rules/PriceRuleForm.js.map +2 -2
  28. package/dist/modules/cpq/backend/cpq/price-rules/[id]/page.js +76 -72
  29. package/dist/modules/cpq/backend/cpq/price-rules/[id]/page.js.map +2 -2
  30. package/dist/modules/cpq/backend/cpq/price-rules/[id]/page.meta.js +1 -1
  31. package/dist/modules/cpq/backend/cpq/price-rules/[id]/page.meta.js.map +2 -2
  32. package/dist/modules/cpq/backend/cpq/price-rules/page.js +18 -15
  33. package/dist/modules/cpq/backend/cpq/price-rules/page.js.map +2 -2
  34. package/dist/modules/cpq/backend/cpq/pricing/[id]/EntriesEditor.js +23 -21
  35. package/dist/modules/cpq/backend/cpq/pricing/[id]/EntriesEditor.js.map +2 -2
  36. package/dist/modules/cpq/backend/cpq/pricing/[id]/ImportPreview.js +22 -50
  37. package/dist/modules/cpq/backend/cpq/pricing/[id]/ImportPreview.js.map +2 -2
  38. package/dist/modules/cpq/backend/cpq/pricing/[id]/page.js +74 -52
  39. package/dist/modules/cpq/backend/cpq/pricing/[id]/page.js.map +2 -2
  40. package/dist/modules/cpq/backend/cpq/pricing/[id]/xlsxImport.js +20 -17
  41. package/dist/modules/cpq/backend/cpq/pricing/[id]/xlsxImport.js.map +2 -2
  42. package/dist/modules/cpq/backend/cpq/pricing/page.js +1 -1
  43. package/dist/modules/cpq/backend/cpq/pricing/page.js.map +2 -2
  44. package/dist/modules/cpq/backend/cpq/quotes/[id]/_components/ArcQuoteConfigurator.js +115 -123
  45. package/dist/modules/cpq/backend/cpq/quotes/[id]/_components/ArcQuoteConfigurator.js.map +2 -2
  46. package/dist/modules/cpq/backend/cpq/quotes/[id]/_components/PriceAdjustmentDialog.js +6 -3
  47. package/dist/modules/cpq/backend/cpq/quotes/[id]/_components/PriceAdjustmentDialog.js.map +2 -2
  48. package/dist/modules/cpq/backend/cpq/quotes/[id]/page.js +129 -94
  49. package/dist/modules/cpq/backend/cpq/quotes/[id]/page.js.map +2 -2
  50. package/dist/modules/cpq/backend/cpq/quotes/page.js +23 -19
  51. package/dist/modules/cpq/backend/cpq/quotes/page.js.map +2 -2
  52. package/dist/modules/cpq/backend/cpq/specifications/[id]/DependsOnRulesEditor.js +19 -15
  53. package/dist/modules/cpq/backend/cpq/specifications/[id]/DependsOnRulesEditor.js.map +2 -2
  54. package/dist/modules/cpq/backend/cpq/specifications/[id]/page.js +171 -178
  55. package/dist/modules/cpq/backend/cpq/specifications/[id]/page.js.map +2 -2
  56. package/dist/modules/cpq/backend/cpq/specifications/page.js +2 -2
  57. package/dist/modules/cpq/backend/cpq/specifications/page.js.map +2 -2
  58. package/dist/modules/cpq/backend/cpq/wizards/[definitionCode]/detail/page.js +60 -50
  59. package/dist/modules/cpq/backend/cpq/wizards/[definitionCode]/detail/page.js.map +2 -2
  60. package/dist/modules/cpq/backend/cpq/wizards/[definitionCode]/page.js +22 -18
  61. package/dist/modules/cpq/backend/cpq/wizards/[definitionCode]/page.js.map +2 -2
  62. package/dist/modules/cpq/backend/cpq/wizards/page.js +1 -1
  63. package/dist/modules/cpq/backend/cpq/wizards/page.js.map +2 -2
  64. package/dist/modules/cpq/components/ArcLineDiff.js +2 -2
  65. package/dist/modules/cpq/components/ArcLineDiff.js.map +2 -2
  66. package/dist/modules/cpq/components/ChargeBreakdownTable.js +4 -10
  67. package/dist/modules/cpq/components/ChargeBreakdownTable.js.map +2 -2
  68. package/dist/modules/cpq/components/PriceWaterfall.js +3 -1
  69. package/dist/modules/cpq/components/PriceWaterfall.js.map +2 -2
  70. package/dist/modules/cpq/components/PricingSummaryCard.js +1 -6
  71. package/dist/modules/cpq/components/PricingSummaryCard.js.map +2 -2
  72. package/dist/modules/cpq/components/StatusPath.js +5 -3
  73. package/dist/modules/cpq/components/StatusPath.js.map +2 -2
  74. package/dist/modules/cpq/components/useCpqRowActions.js +10 -22
  75. package/dist/modules/cpq/components/useCpqRowActions.js.map +2 -2
  76. package/dist/modules/cpq/i18n/de.json +1220 -0
  77. package/dist/modules/cpq/i18n/en.json +1220 -0
  78. package/dist/modules/cpq/i18n/es.json +1220 -0
  79. package/dist/modules/cpq/i18n/pl.json +1220 -0
  80. package/dist/modules/cpq/widgets/injection/customer-inventory/widget.client.js +39 -31
  81. package/dist/modules/cpq/widgets/injection/customer-inventory/widget.client.js.map +2 -2
  82. package/dist/modules/cpq/widgets/injection/order-cpq-tab/widget.client.js +13 -5
  83. package/dist/modules/cpq/widgets/injection/order-cpq-tab/widget.client.js.map +2 -2
  84. package/dist/modules/cpq/widgets/injection/quote-configurator/widget.client.js +41 -21
  85. package/dist/modules/cpq/widgets/injection/quote-configurator/widget.client.js.map +2 -2
  86. package/dist/modules/cpq/widgets/injection-table.js +2 -2
  87. package/dist/modules/cpq/widgets/injection-table.js.map +2 -2
  88. package/dist/modules/cpq/workflows/WizardRunner.js +10 -8
  89. package/dist/modules/cpq/workflows/WizardRunner.js.map +2 -2
  90. package/dist/modules/cpq/workflows/WizardTrigger.js +15 -9
  91. package/dist/modules/cpq/workflows/WizardTrigger.js.map +2 -2
  92. package/dist/modules/cpq/workflows/steps/CustomerSelectStep.js +9 -7
  93. package/dist/modules/cpq/workflows/steps/CustomerSelectStep.js.map +2 -2
  94. package/dist/modules/cpq/workflows/steps/InventorySelectStep.js +9 -4
  95. package/dist/modules/cpq/workflows/steps/InventorySelectStep.js.map +2 -2
  96. package/dist/modules/cpq/workflows/steps/ItemListStep.js +16 -19
  97. package/dist/modules/cpq/workflows/steps/ItemListStep.js.map +2 -2
  98. package/dist/modules/cpq/workflows/steps/OfferingSelectStep.js +19 -32
  99. package/dist/modules/cpq/workflows/steps/OfferingSelectStep.js.map +2 -2
  100. package/dist/modules/cpq/workflows/steps/ProductConfigureStep.js +8 -6
  101. package/dist/modules/cpq/workflows/steps/ProductConfigureStep.js.map +2 -2
  102. package/dist/modules/cpq/workflows/steps/ReviewStep.js +32 -30
  103. package/dist/modules/cpq/workflows/steps/ReviewStep.js.map +2 -2
  104. package/dist/modules/cpq/workflows/steps/index.js +12 -0
  105. package/dist/modules/cpq/workflows/steps/index.js.map +2 -2
  106. package/package.json +1 -1
  107. package/src/modules/cpq/__tests__/i18n/dictionaries.test.ts +62 -0
  108. package/src/modules/cpq/__tests__/i18n/hardcodedStrings.test.ts +35 -0
  109. package/src/modules/cpq/__tests__/i18n/sourceScan.ts +109 -0
  110. package/src/modules/cpq/backend/cpq/inventory/AssetsTable.tsx +3 -9
  111. package/src/modules/cpq/backend/cpq/inventory/SubscriptionsTable.tsx +22 -26
  112. package/src/modules/cpq/backend/cpq/inventory/assets/[id]/page.meta.ts +1 -1
  113. package/src/modules/cpq/backend/cpq/inventory/assets/[id]/page.tsx +43 -46
  114. package/src/modules/cpq/backend/cpq/inventory/page.meta.ts +2 -2
  115. package/src/modules/cpq/backend/cpq/inventory/shared.tsx +37 -1
  116. package/src/modules/cpq/backend/cpq/inventory/subscriptions/[id]/page.meta.ts +1 -1
  117. package/src/modules/cpq/backend/cpq/inventory/subscriptions/[id]/page.tsx +134 -112
  118. package/src/modules/cpq/backend/cpq/offerings/[id]/page.tsx +169 -130
  119. package/src/modules/cpq/backend/cpq/offerings/page.tsx +34 -24
  120. package/src/modules/cpq/backend/cpq/orders/[id]/page.tsx +66 -43
  121. package/src/modules/cpq/backend/cpq/orders/page.tsx +6 -6
  122. package/src/modules/cpq/backend/cpq/price-rules/PriceRuleForm.tsx +48 -34
  123. package/src/modules/cpq/backend/cpq/price-rules/[id]/page.meta.ts +1 -1
  124. package/src/modules/cpq/backend/cpq/price-rules/[id]/page.tsx +76 -70
  125. package/src/modules/cpq/backend/cpq/price-rules/page.tsx +25 -16
  126. package/src/modules/cpq/backend/cpq/pricing/[id]/EntriesEditor.tsx +24 -18
  127. package/src/modules/cpq/backend/cpq/pricing/[id]/ImportPreview.tsx +29 -19
  128. package/src/modules/cpq/backend/cpq/pricing/[id]/page.tsx +95 -47
  129. package/src/modules/cpq/backend/cpq/pricing/[id]/xlsxImport.ts +23 -15
  130. package/src/modules/cpq/backend/cpq/pricing/page.tsx +1 -1
  131. package/src/modules/cpq/backend/cpq/quotes/[id]/_components/ArcQuoteConfigurator.tsx +111 -88
  132. package/src/modules/cpq/backend/cpq/quotes/[id]/_components/PriceAdjustmentDialog.tsx +3 -3
  133. package/src/modules/cpq/backend/cpq/quotes/[id]/page.tsx +134 -89
  134. package/src/modules/cpq/backend/cpq/quotes/page.tsx +29 -21
  135. package/src/modules/cpq/backend/cpq/specifications/[id]/DependsOnRulesEditor.tsx +19 -15
  136. package/src/modules/cpq/backend/cpq/specifications/[id]/page.tsx +171 -171
  137. package/src/modules/cpq/backend/cpq/specifications/page.tsx +2 -2
  138. package/src/modules/cpq/backend/cpq/wizards/[definitionCode]/detail/page.tsx +51 -41
  139. package/src/modules/cpq/backend/cpq/wizards/[definitionCode]/page.tsx +17 -13
  140. package/src/modules/cpq/backend/cpq/wizards/page.tsx +1 -1
  141. package/src/modules/cpq/components/ArcLineDiff.tsx +2 -2
  142. package/src/modules/cpq/components/ChargeBreakdownTable.tsx +4 -2
  143. package/src/modules/cpq/components/PriceWaterfall.tsx +4 -2
  144. package/src/modules/cpq/components/PricingSummaryCard.tsx +1 -1
  145. package/src/modules/cpq/components/StatusPath.tsx +7 -4
  146. package/src/modules/cpq/components/useCpqRowActions.tsx +17 -25
  147. package/src/modules/cpq/i18n/de.json +1220 -0
  148. package/src/modules/cpq/i18n/en.json +1220 -0
  149. package/src/modules/cpq/i18n/es.json +1220 -0
  150. package/src/modules/cpq/i18n/pl.json +1220 -0
  151. package/src/modules/cpq/widgets/injection/customer-inventory/widget.client.tsx +38 -31
  152. package/src/modules/cpq/widgets/injection/order-cpq-tab/widget.client.tsx +7 -5
  153. package/src/modules/cpq/widgets/injection/quote-configurator/widget.client.tsx +36 -21
  154. package/src/modules/cpq/widgets/injection-table.ts +8 -2
  155. package/src/modules/cpq/workflows/WizardRunner.tsx +8 -5
  156. package/src/modules/cpq/workflows/WizardTrigger.tsx +15 -9
  157. package/src/modules/cpq/workflows/steps/CustomerSelectStep.tsx +11 -7
  158. package/src/modules/cpq/workflows/steps/InventorySelectStep.tsx +9 -5
  159. package/src/modules/cpq/workflows/steps/ItemListStep.tsx +18 -12
  160. package/src/modules/cpq/workflows/steps/OfferingSelectStep.tsx +20 -16
  161. package/src/modules/cpq/workflows/steps/ProductConfigureStep.tsx +8 -6
  162. package/src/modules/cpq/workflows/steps/ReviewStep.tsx +33 -18
  163. package/src/modules/cpq/workflows/steps/index.ts +12 -0
  164. package/src/modules/cpq/workflows/types.ts +4 -0
@@ -2,20 +2,23 @@
2
2
  import { jsx, jsxs } from "react/jsx-runtime";
3
3
  import * as React from "react";
4
4
  import { useRouter } from "next/navigation";
5
+ import { useT } from "@open-mercato/shared/lib/i18n/context";
5
6
  import { Tag } from "@open-mercato/ui/primitives/tag";
6
7
  import {
7
8
  assetStatusMap,
8
- formatStatusLabel,
9
9
  subscriptionStatusMap
10
10
  } from "../../../components/statusMaps.js";
11
+ import { inventoryStatusLabel } from "../../../backend/cpq/inventory/shared.js";
11
12
  function fmt(amount, currency) {
12
13
  return new Intl.NumberFormat("en-US", { style: "currency", currency }).format(amount);
13
14
  }
14
15
  function StatusBadge({ status }) {
16
+ const t = useT();
15
17
  const variant = subscriptionStatusMap[status] ?? assetStatusMap[status] ?? "neutral";
16
- return /* @__PURE__ */ jsx(Tag, { variant, dot: true, children: formatStatusLabel(status) });
18
+ return /* @__PURE__ */ jsx(Tag, { variant, dot: true, children: inventoryStatusLabel(t, status) });
17
19
  }
18
20
  function CustomerInventoryWidget({ data, context }) {
21
+ const t = useT();
19
22
  const router = useRouter();
20
23
  const record = data;
21
24
  const companyRecord = record?.company;
@@ -43,32 +46,33 @@ function CustomerInventoryWidget({ data, context }) {
43
46
  cancelled = true;
44
47
  };
45
48
  }, [customerId]);
46
- if (!customerId) return /* @__PURE__ */ jsx("div", { className: "p-4 text-sm text-muted-foreground", children: "No customer context available." });
49
+ if (!customerId) return /* @__PURE__ */ jsx("div", { className: "p-4 text-sm text-muted-foreground", children: t("cpq.widgets.customerInventory.noContext", "No customer context available.") });
47
50
  if (loading) {
48
51
  return /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 p-6 text-sm text-muted-foreground", children: [
49
52
  /* @__PURE__ */ jsx(Spinner, {}),
50
- " Loading inventory\u2026"
53
+ " ",
54
+ t("cpq.widgets.customerInventory.loading", "Loading inventory\u2026")
51
55
  ] });
52
56
  }
53
57
  if (!inventory || inventory.subscriptions.length === 0 && inventory.assets.length === 0) {
54
58
  return /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center justify-center py-12 px-4", children: [
55
59
  /* @__PURE__ */ jsx("div", { className: "rounded-full bg-primary/10 p-3 mb-3", children: /* @__PURE__ */ jsx("svg", { className: "h-6 w-6 text-primary", fill: "none", viewBox: "0 0 24 24", strokeWidth: "1.5", stroke: "currentColor", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M20.25 7.5l-.625 10.632a2.25 2.25 0 01-2.247 2.118H6.622a2.25 2.25 0 01-2.247-2.118L3.75 7.5M10 11.25h4M3.375 7.5h17.25c.621 0 1.125-.504 1.125-1.125v-1.5c0-.621-.504-1.125-1.125-1.125H3.375c-.621 0-1.125.504-1.125 1.125v1.5c0 .621.504 1.125 1.125 1.125z" }) }) }),
56
- /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: "No inventory records found." })
60
+ /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: t("cpq.widgets.customerInventory.empty", "No inventory records found.") })
57
61
  ] });
58
62
  }
59
63
  const { summary } = inventory;
60
64
  const currency = summary.currencyCode || "USD";
61
65
  const tabs = [
62
- { key: "subscriptions", label: "Subscriptions", count: inventory.subscriptions.length },
63
- { key: "items", label: "Subscription Items", count: inventory.subscriptionItems.length },
64
- { key: "assets", label: "Assets", count: inventory.assets.length }
66
+ { key: "subscriptions", label: t("cpq.widgets.customerInventory.tabs.subscriptions", "Subscriptions"), count: inventory.subscriptions.length },
67
+ { key: "items", label: t("cpq.widgets.customerInventory.tabs.items", "Subscription Items"), count: inventory.subscriptionItems.length },
68
+ { key: "assets", label: t("cpq.widgets.customerInventory.tabs.assets", "Assets"), count: inventory.assets.length }
65
69
  ];
66
70
  return /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
67
71
  /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 sm:grid-cols-4 gap-3", children: [
68
- /* @__PURE__ */ jsx(SummaryCard, { label: "Active Subscriptions", value: String(summary.activeSubscriptions) }),
69
- /* @__PURE__ */ jsx(SummaryCard, { label: "Total MRC", value: fmt(summary.totalMrc, currency), mono: true }),
70
- /* @__PURE__ */ jsx(SummaryCard, { label: "Active Assets", value: String(summary.activeAssets) }),
71
- /* @__PURE__ */ jsx(SummaryCard, { label: "Pending Items", value: String(summary.pendingItems) })
72
+ /* @__PURE__ */ jsx(SummaryCard, { label: t("cpq.widgets.customerInventory.summary.activeSubscriptions", "Active Subscriptions"), value: String(summary.activeSubscriptions) }),
73
+ /* @__PURE__ */ jsx(SummaryCard, { label: t("cpq.widgets.customerInventory.summary.totalMrc", "Total MRC"), value: fmt(summary.totalMrc, currency), mono: true }),
74
+ /* @__PURE__ */ jsx(SummaryCard, { label: t("cpq.widgets.customerInventory.summary.activeAssets", "Active Assets"), value: String(summary.activeAssets) }),
75
+ /* @__PURE__ */ jsx(SummaryCard, { label: t("cpq.widgets.customerInventory.summary.pendingItems", "Pending Items"), value: String(summary.pendingItems) })
72
76
  ] }),
73
77
  /* @__PURE__ */ jsx("div", { className: "flex gap-1 border-b", children: tabs.map((tab) => /* @__PURE__ */ jsxs(
74
78
  "button",
@@ -85,7 +89,7 @@ function CustomerInventoryWidget({ data, context }) {
85
89
  activeTab === "subscriptions" && /* @__PURE__ */ jsx(SubscriptionsTable, { items: inventory.subscriptions, currency, onOpen: (id) => router.push(`/backend/cpq/inventory/subscriptions/${id}`) }),
86
90
  activeTab === "items" && /* @__PURE__ */ jsx(SubscriptionItemsTable, { items: inventory.subscriptionItems, currency, onOpen: (id) => router.push(`/backend/cpq/inventory/subscriptions/${id}`) }),
87
91
  activeTab === "assets" && /* @__PURE__ */ jsx(AssetsTable, { items: inventory.assets, currency, onOpen: (id) => router.push(`/backend/cpq/inventory/assets/${id}`) }),
88
- /* @__PURE__ */ jsx("div", { className: "pt-2 text-right", children: /* @__PURE__ */ jsx("a", { href: "/backend/cpq/inventory", className: "text-sm text-primary hover:underline", children: "View full inventory \u2192" }) })
92
+ /* @__PURE__ */ jsx("div", { className: "pt-2 text-right", children: /* @__PURE__ */ jsx("a", { href: "/backend/cpq/inventory", className: "text-sm text-primary hover:underline", children: t("cpq.widgets.customerInventory.viewFull", "View full inventory \u2192") }) })
89
93
  ] });
90
94
  }
91
95
  function SummaryCard({ label, value, mono }) {
@@ -95,15 +99,16 @@ function SummaryCard({ label, value, mono }) {
95
99
  ] });
96
100
  }
97
101
  function SubscriptionsTable({ items, currency, onOpen }) {
102
+ const t = useT();
98
103
  if (items.length === 0) return /* @__PURE__ */ jsx(EmptyTab, {});
99
104
  return /* @__PURE__ */ jsx("div", { className: "rounded-lg border bg-card overflow-hidden", children: /* @__PURE__ */ jsxs("table", { className: "w-full text-sm", children: [
100
105
  /* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsxs("tr", { className: "border-b border-border bg-muted/40 text-muted-foreground", children: [
101
- /* @__PURE__ */ jsx("th", { className: "px-4 py-2.5 text-left text-xs font-medium uppercase tracking-wide", children: "Name" }),
102
- /* @__PURE__ */ jsx("th", { className: "px-4 py-2.5 text-left text-xs font-medium uppercase tracking-wide", children: "Status" }),
103
- /* @__PURE__ */ jsx("th", { className: "px-4 py-2.5 text-right text-xs font-medium uppercase tracking-wide", children: "MRC" }),
104
- /* @__PURE__ */ jsx("th", { className: "px-4 py-2.5 text-left text-xs font-medium uppercase tracking-wide", children: "Billing" }),
105
- /* @__PURE__ */ jsx("th", { className: "px-4 py-2.5 text-left text-xs font-medium uppercase tracking-wide", children: "Start Date" }),
106
- /* @__PURE__ */ jsx("th", { className: "px-4 py-2.5 text-left text-xs font-medium uppercase tracking-wide", children: "Term End" })
106
+ /* @__PURE__ */ jsx("th", { className: "px-4 py-2.5 text-left text-xs font-medium uppercase tracking-wide", children: t("cpq.widgets.customerInventory.table.name", "Name") }),
107
+ /* @__PURE__ */ jsx("th", { className: "px-4 py-2.5 text-left text-xs font-medium uppercase tracking-wide", children: t("cpq.widgets.customerInventory.table.status", "Status") }),
108
+ /* @__PURE__ */ jsx("th", { className: "px-4 py-2.5 text-right text-xs font-medium uppercase tracking-wide", children: t("cpq.widgets.customerInventory.table.mrc", "MRC") }),
109
+ /* @__PURE__ */ jsx("th", { className: "px-4 py-2.5 text-left text-xs font-medium uppercase tracking-wide", children: t("cpq.widgets.customerInventory.table.billing", "Billing") }),
110
+ /* @__PURE__ */ jsx("th", { className: "px-4 py-2.5 text-left text-xs font-medium uppercase tracking-wide", children: t("cpq.widgets.customerInventory.table.startDate", "Start Date") }),
111
+ /* @__PURE__ */ jsx("th", { className: "px-4 py-2.5 text-left text-xs font-medium uppercase tracking-wide", children: t("cpq.widgets.customerInventory.table.termEnd", "Term End") })
107
112
  ] }) }),
108
113
  /* @__PURE__ */ jsx("tbody", { children: items.map((s) => /* @__PURE__ */ jsxs(
109
114
  "tr",
@@ -124,14 +129,15 @@ function SubscriptionsTable({ items, currency, onOpen }) {
124
129
  ] }) });
125
130
  }
126
131
  function SubscriptionItemsTable({ items, currency, onOpen }) {
132
+ const t = useT();
127
133
  if (items.length === 0) return /* @__PURE__ */ jsx(EmptyTab, {});
128
134
  return /* @__PURE__ */ jsx("div", { className: "rounded-lg border bg-card overflow-hidden", children: /* @__PURE__ */ jsxs("table", { className: "w-full text-sm", children: [
129
135
  /* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsxs("tr", { className: "border-b border-border bg-muted/40 text-muted-foreground", children: [
130
- /* @__PURE__ */ jsx("th", { className: "px-4 py-2.5 text-left text-xs font-medium uppercase tracking-wide", children: "Name" }),
131
- /* @__PURE__ */ jsx("th", { className: "px-4 py-2.5 text-left text-xs font-medium uppercase tracking-wide", children: "Status" }),
132
- /* @__PURE__ */ jsx("th", { className: "px-4 py-2.5 text-right text-xs font-medium uppercase tracking-wide", children: "MRC" }),
133
- /* @__PURE__ */ jsx("th", { className: "px-4 py-2.5 text-right text-xs font-medium uppercase tracking-wide", children: "NRC" }),
134
- /* @__PURE__ */ jsx("th", { className: "px-4 py-2.5 text-right text-xs font-medium uppercase tracking-wide", children: "Qty" })
136
+ /* @__PURE__ */ jsx("th", { className: "px-4 py-2.5 text-left text-xs font-medium uppercase tracking-wide", children: t("cpq.widgets.customerInventory.table.name", "Name") }),
137
+ /* @__PURE__ */ jsx("th", { className: "px-4 py-2.5 text-left text-xs font-medium uppercase tracking-wide", children: t("cpq.widgets.customerInventory.table.status", "Status") }),
138
+ /* @__PURE__ */ jsx("th", { className: "px-4 py-2.5 text-right text-xs font-medium uppercase tracking-wide", children: t("cpq.widgets.customerInventory.table.mrc", "MRC") }),
139
+ /* @__PURE__ */ jsx("th", { className: "px-4 py-2.5 text-right text-xs font-medium uppercase tracking-wide", children: t("cpq.widgets.customerInventory.table.nrc", "NRC") }),
140
+ /* @__PURE__ */ jsx("th", { className: "px-4 py-2.5 text-right text-xs font-medium uppercase tracking-wide", children: t("cpq.widgets.customerInventory.table.qty", "Qty") })
135
141
  ] }) }),
136
142
  /* @__PURE__ */ jsx("tbody", { children: items.map((item) => /* @__PURE__ */ jsxs(
137
143
  "tr",
@@ -151,14 +157,15 @@ function SubscriptionItemsTable({ items, currency, onOpen }) {
151
157
  ] }) });
152
158
  }
153
159
  function AssetsTable({ items, currency, onOpen }) {
160
+ const t = useT();
154
161
  if (items.length === 0) return /* @__PURE__ */ jsx(EmptyTab, {});
155
162
  return /* @__PURE__ */ jsx("div", { className: "rounded-lg border bg-card overflow-hidden", children: /* @__PURE__ */ jsxs("table", { className: "w-full text-sm", children: [
156
163
  /* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsxs("tr", { className: "border-b border-border bg-muted/40 text-muted-foreground", children: [
157
- /* @__PURE__ */ jsx("th", { className: "px-4 py-2.5 text-left text-xs font-medium uppercase tracking-wide", children: "Name" }),
158
- /* @__PURE__ */ jsx("th", { className: "px-4 py-2.5 text-left text-xs font-medium uppercase tracking-wide", children: "Type" }),
159
- /* @__PURE__ */ jsx("th", { className: "px-4 py-2.5 text-left text-xs font-medium uppercase tracking-wide", children: "Status" }),
160
- /* @__PURE__ */ jsx("th", { className: "px-4 py-2.5 text-right text-xs font-medium uppercase tracking-wide", children: "Price" }),
161
- /* @__PURE__ */ jsx("th", { className: "px-4 py-2.5 text-left text-xs font-medium uppercase tracking-wide", children: "Linked To" })
164
+ /* @__PURE__ */ jsx("th", { className: "px-4 py-2.5 text-left text-xs font-medium uppercase tracking-wide", children: t("cpq.widgets.customerInventory.table.name", "Name") }),
165
+ /* @__PURE__ */ jsx("th", { className: "px-4 py-2.5 text-left text-xs font-medium uppercase tracking-wide", children: t("cpq.widgets.customerInventory.table.type", "Type") }),
166
+ /* @__PURE__ */ jsx("th", { className: "px-4 py-2.5 text-left text-xs font-medium uppercase tracking-wide", children: t("cpq.widgets.customerInventory.table.status", "Status") }),
167
+ /* @__PURE__ */ jsx("th", { className: "px-4 py-2.5 text-right text-xs font-medium uppercase tracking-wide", children: t("cpq.widgets.customerInventory.table.price", "Price") }),
168
+ /* @__PURE__ */ jsx("th", { className: "px-4 py-2.5 text-left text-xs font-medium uppercase tracking-wide", children: t("cpq.widgets.customerInventory.table.linkedTo", "Linked To") })
162
169
  ] }) }),
163
170
  /* @__PURE__ */ jsx("tbody", { children: items.map((a) => /* @__PURE__ */ jsxs(
164
171
  "tr",
@@ -170,7 +177,7 @@ function AssetsTable({ items, currency, onOpen }) {
170
177
  /* @__PURE__ */ jsx("td", { className: "px-4 py-3 capitalize", children: a.assetType.replace(/_/g, " ") }),
171
178
  /* @__PURE__ */ jsx("td", { className: "px-4 py-3", children: /* @__PURE__ */ jsx(StatusBadge, { status: a.status }) }),
172
179
  /* @__PURE__ */ jsx("td", { className: "px-4 py-3 text-right font-mono", children: fmt(a.purchasePrice, a.currencyCode || currency) }),
173
- /* @__PURE__ */ jsx("td", { className: "px-4 py-3 text-muted-foreground", children: a.subscriptionId ? `Sub ${a.subscriptionId.slice(0, 8)}\u2026` : "\u2014" })
180
+ /* @__PURE__ */ jsx("td", { className: "px-4 py-3 text-muted-foreground", children: a.subscriptionId ? t("cpq.widgets.customerInventory.table.linkedSubscription", "Sub {id}\u2026", { id: a.subscriptionId.slice(0, 8) }) : "\u2014" })
174
181
  ]
175
182
  },
176
183
  a.id
@@ -178,7 +185,8 @@ function AssetsTable({ items, currency, onOpen }) {
178
185
  ] }) });
179
186
  }
180
187
  function EmptyTab() {
181
- return /* @__PURE__ */ jsx("div", { className: "rounded-lg border bg-card py-8 text-center text-sm text-muted-foreground", children: "No records in this category." });
188
+ const t = useT();
189
+ return /* @__PURE__ */ jsx("div", { className: "rounded-lg border bg-card py-8 text-center text-sm text-muted-foreground", children: t("cpq.widgets.customerInventory.emptyTab", "No records in this category.") });
182
190
  }
183
191
  function Spinner() {
184
192
  return /* @__PURE__ */ jsxs("svg", { className: "h-4 w-4 animate-spin", viewBox: "0 0 24 24", fill: "none", children: [
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../../src/modules/cpq/widgets/injection/customer-inventory/widget.client.tsx"],
4
- "sourcesContent": ["\"use client\"\nimport * as React from 'react'\nimport type { InjectionWidgetComponentProps } from '@open-mercato/shared/modules/widgets/injection'\nimport { useRouter } from 'next/navigation'\nimport { Tag } from '@open-mercato/ui/primitives/tag'\nimport {\n assetStatusMap,\n formatStatusLabel,\n subscriptionStatusMap,\n type AssetStatus,\n type SubscriptionStatus,\n} from '../../../components/statusMaps'\n\n// \u2500\u2500\u2500 Types \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\ntype Subscription = {\n id: string\n code: string\n name: string\n status: string\n mrcAmount: number\n nrcAmount: number\n billingCycle: string\n currencyCode: string\n startDate: string\n currentTermEnd: string | null\n autoRenew: boolean\n createdAt: string\n}\n\ntype SubscriptionItem = {\n id: string\n subscriptionId: string\n parentItemId: string | null\n productId: string | null\n name: string\n status: string\n mrcAmount: number\n nrcAmount: number\n currencyCode: string\n quantity: number\n}\n\ntype Asset = {\n id: string\n code: string\n name: string\n status: string\n assetType: string\n purchasePrice: number\n currencyCode: string\n subscriptionId: string | null\n subscriptionItemId: string | null\n createdAt: string\n}\n\ntype InventorySummary = {\n activeSubscriptions: number\n totalMrc: number\n activeAssets: number\n pendingItems: number\n currencyCode: string\n}\n\ntype InventoryResponse = {\n customerId: string\n subscriptions: Subscription[]\n subscriptionItems: SubscriptionItem[]\n assets: Asset[]\n summary: InventorySummary\n}\n\ntype TabKey = 'subscriptions' | 'items' | 'assets'\n\n// \u2500\u2500\u2500 Helpers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nfunction fmt(amount: number, currency: string): string {\n return new Intl.NumberFormat('en-US', { style: 'currency', currency }).format(amount)\n}\n\nfunction StatusBadge({ status }: { status: string }) {\n const variant =\n subscriptionStatusMap[status as SubscriptionStatus] ??\n assetStatusMap[status as AssetStatus] ??\n 'neutral'\n return (\n <Tag variant={variant} dot>\n {formatStatusLabel(status)}\n </Tag>\n )\n}\n\n// \u2500\u2500\u2500 Main Widget \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport default function CustomerInventoryWidget({ data, context }: InjectionWidgetComponentProps & { context?: Record<string, unknown> }) {\n const router = useRouter()\n const record = data as Record<string, unknown> | null\n const companyRecord = record?.company as Record<string, unknown> | undefined\n const customerId =\n (context?.companyId as string) ??\n (context?.resourceId as string) ??\n (companyRecord?.id as string) ??\n (record?.id as string) ??\n null\n\n const [inventory, setInventory] = React.useState<InventoryResponse | null>(null)\n const [loading, setLoading] = React.useState(true)\n const [activeTab, setActiveTab] = React.useState<TabKey>('subscriptions')\n\n React.useEffect(() => {\n if (!customerId) { setLoading(false); return }\n let cancelled = false\n async function load() {\n try {\n const res = await fetch(`/api/cpq/inventory/customer/${customerId}`)\n if (res.ok && !cancelled) setInventory(await res.json())\n } catch { /* no inventory data */ }\n finally { if (!cancelled) setLoading(false) }\n }\n load()\n return () => { cancelled = true }\n }, [customerId])\n\n if (!customerId) return <div className=\"p-4 text-sm text-muted-foreground\">No customer context available.</div>\n\n if (loading) {\n return (\n <div className=\"flex items-center gap-2 p-6 text-sm text-muted-foreground\">\n <Spinner /> Loading inventory\u2026\n </div>\n )\n }\n\n if (!inventory || (inventory.subscriptions.length === 0 && inventory.assets.length === 0)) {\n return (\n <div className=\"flex flex-col items-center justify-center py-12 px-4\">\n <div className=\"rounded-full bg-primary/10 p-3 mb-3\">\n <svg className=\"h-6 w-6 text-primary\" fill=\"none\" viewBox=\"0 0 24 24\" strokeWidth=\"1.5\" stroke=\"currentColor\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M20.25 7.5l-.625 10.632a2.25 2.25 0 01-2.247 2.118H6.622a2.25 2.25 0 01-2.247-2.118L3.75 7.5M10 11.25h4M3.375 7.5h17.25c.621 0 1.125-.504 1.125-1.125v-1.5c0-.621-.504-1.125-1.125-1.125H3.375c-.621 0-1.125.504-1.125 1.125v1.5c0 .621.504 1.125 1.125 1.125z\" />\n </svg>\n </div>\n <p className=\"text-sm text-muted-foreground\">No inventory records found.</p>\n </div>\n )\n }\n\n const { summary } = inventory\n const currency = summary.currencyCode || 'USD'\n\n const tabs: { key: TabKey; label: string; count: number }[] = [\n { key: 'subscriptions', label: 'Subscriptions', count: inventory.subscriptions.length },\n { key: 'items', label: 'Subscription Items', count: inventory.subscriptionItems.length },\n { key: 'assets', label: 'Assets', count: inventory.assets.length },\n ]\n\n return (\n <div className=\"space-y-4\">\n {/* Summary Cards */}\n <div className=\"grid grid-cols-2 sm:grid-cols-4 gap-3\">\n <SummaryCard label=\"Active Subscriptions\" value={String(summary.activeSubscriptions)} />\n <SummaryCard label=\"Total MRC\" value={fmt(summary.totalMrc, currency)} mono />\n <SummaryCard label=\"Active Assets\" value={String(summary.activeAssets)} />\n <SummaryCard label=\"Pending Items\" value={String(summary.pendingItems)} />\n </div>\n\n {/* Tab Switcher */}\n <div className=\"flex gap-1 border-b\">\n {tabs.map((tab) => (\n <button\n key={tab.key}\n onClick={() => setActiveTab(tab.key)}\n className={`px-3 py-2 text-sm font-medium transition-colors border-b-2 -mb-px ${\n activeTab === tab.key\n ? 'border-primary text-primary'\n : 'border-transparent text-muted-foreground hover:text-foreground'\n }`}\n >\n {tab.label}\n <span className=\"ml-1.5 rounded-full bg-muted px-1.5 py-0.5 text-xs\">{tab.count}</span>\n </button>\n ))}\n </div>\n\n {/* Tab Content */}\n {activeTab === 'subscriptions' && <SubscriptionsTable items={inventory.subscriptions} currency={currency} onOpen={(id) => router.push(`/backend/cpq/inventory/subscriptions/${id}`)} />}\n {activeTab === 'items' && <SubscriptionItemsTable items={inventory.subscriptionItems} currency={currency} onOpen={(id) => router.push(`/backend/cpq/inventory/subscriptions/${id}`)} />}\n {activeTab === 'assets' && <AssetsTable items={inventory.assets} currency={currency} onOpen={(id) => router.push(`/backend/cpq/inventory/assets/${id}`)} />}\n\n {/* Link to full page */}\n <div className=\"pt-2 text-right\">\n <a href=\"/backend/cpq/inventory\" className=\"text-sm text-primary hover:underline\">\n View full inventory \u2192\n </a>\n </div>\n </div>\n )\n}\n\n// \u2500\u2500\u2500 Summary Card \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nfunction SummaryCard({ label, value, mono }: { label: string; value: string; mono?: boolean }) {\n return (\n <div className=\"rounded-lg border bg-card p-3\">\n <p className=\"text-xs text-muted-foreground\">{label}</p>\n <p className={`text-lg font-semibold ${mono ? 'font-mono' : ''}`}>{value}</p>\n </div>\n )\n}\n\n// \u2500\u2500\u2500 Subscriptions Table \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nfunction SubscriptionsTable({ items, currency, onOpen }: { items: Subscription[]; currency: string; onOpen: (id: string) => void }) {\n if (items.length === 0) return <EmptyTab />\n return (\n <div className=\"rounded-lg border bg-card overflow-hidden\">\n <table className=\"w-full text-sm\">\n <thead>\n <tr className=\"border-b border-border bg-muted/40 text-muted-foreground\">\n <th className=\"px-4 py-2.5 text-left text-xs font-medium uppercase tracking-wide\">Name</th>\n <th className=\"px-4 py-2.5 text-left text-xs font-medium uppercase tracking-wide\">Status</th>\n <th className=\"px-4 py-2.5 text-right text-xs font-medium uppercase tracking-wide\">MRC</th>\n <th className=\"px-4 py-2.5 text-left text-xs font-medium uppercase tracking-wide\">Billing</th>\n <th className=\"px-4 py-2.5 text-left text-xs font-medium uppercase tracking-wide\">Start Date</th>\n <th className=\"px-4 py-2.5 text-left text-xs font-medium uppercase tracking-wide\">Term End</th>\n </tr>\n </thead>\n <tbody>\n {items.map((s) => (\n <tr\n key={s.id}\n onClick={() => onOpen(s.id)}\n className=\"border-b border-border last:border-0 cursor-pointer hover:bg-accent/40 transition-colors\"\n >\n <td className=\"px-4 py-3 font-medium\">{s.name}</td>\n <td className=\"px-4 py-3\"><StatusBadge status={s.status} /></td>\n <td className=\"px-4 py-3 text-right font-mono\">{fmt(s.mrcAmount, s.currencyCode || currency)}</td>\n <td className=\"px-4 py-3 capitalize\">{s.billingCycle}</td>\n <td className=\"px-4 py-3 text-muted-foreground\">{s.startDate ? new Date(s.startDate).toLocaleDateString() : '\u2014'}</td>\n <td className=\"px-4 py-3 text-muted-foreground\">{s.currentTermEnd ? new Date(s.currentTermEnd).toLocaleDateString() : '\u2014'}</td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n )\n}\n\n// \u2500\u2500\u2500 Subscription Items Table \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nfunction SubscriptionItemsTable({ items, currency, onOpen }: { items: SubscriptionItem[]; currency: string; onOpen: (subscriptionId: string) => void }) {\n if (items.length === 0) return <EmptyTab />\n return (\n <div className=\"rounded-lg border bg-card overflow-hidden\">\n <table className=\"w-full text-sm\">\n <thead>\n <tr className=\"border-b border-border bg-muted/40 text-muted-foreground\">\n <th className=\"px-4 py-2.5 text-left text-xs font-medium uppercase tracking-wide\">Name</th>\n <th className=\"px-4 py-2.5 text-left text-xs font-medium uppercase tracking-wide\">Status</th>\n <th className=\"px-4 py-2.5 text-right text-xs font-medium uppercase tracking-wide\">MRC</th>\n <th className=\"px-4 py-2.5 text-right text-xs font-medium uppercase tracking-wide\">NRC</th>\n <th className=\"px-4 py-2.5 text-right text-xs font-medium uppercase tracking-wide\">Qty</th>\n </tr>\n </thead>\n <tbody>\n {items.map((item) => (\n <tr\n key={item.id}\n onClick={() => onOpen(item.subscriptionId)}\n className=\"border-b border-border last:border-0 cursor-pointer hover:bg-accent/40 transition-colors\"\n >\n <td className=\"px-4 py-3 font-medium\">{item.name}</td>\n <td className=\"px-4 py-3\"><StatusBadge status={item.status} /></td>\n <td className=\"px-4 py-3 text-right font-mono\">{fmt(item.mrcAmount, item.currencyCode || currency)}</td>\n <td className=\"px-4 py-3 text-right font-mono\">{fmt(item.nrcAmount, item.currencyCode || currency)}</td>\n <td className=\"px-4 py-3 text-right font-mono\">{item.quantity}</td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n )\n}\n\n// \u2500\u2500\u2500 Assets Table \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nfunction AssetsTable({ items, currency, onOpen }: { items: Asset[]; currency: string; onOpen: (id: string) => void }) {\n if (items.length === 0) return <EmptyTab />\n return (\n <div className=\"rounded-lg border bg-card overflow-hidden\">\n <table className=\"w-full text-sm\">\n <thead>\n <tr className=\"border-b border-border bg-muted/40 text-muted-foreground\">\n <th className=\"px-4 py-2.5 text-left text-xs font-medium uppercase tracking-wide\">Name</th>\n <th className=\"px-4 py-2.5 text-left text-xs font-medium uppercase tracking-wide\">Type</th>\n <th className=\"px-4 py-2.5 text-left text-xs font-medium uppercase tracking-wide\">Status</th>\n <th className=\"px-4 py-2.5 text-right text-xs font-medium uppercase tracking-wide\">Price</th>\n <th className=\"px-4 py-2.5 text-left text-xs font-medium uppercase tracking-wide\">Linked To</th>\n </tr>\n </thead>\n <tbody>\n {items.map((a) => (\n <tr\n key={a.id}\n onClick={() => onOpen(a.id)}\n className=\"border-b border-border last:border-0 cursor-pointer hover:bg-accent/40 transition-colors\"\n >\n <td className=\"px-4 py-3 font-medium\">{a.name}</td>\n <td className=\"px-4 py-3 capitalize\">{a.assetType.replace(/_/g, ' ')}</td>\n <td className=\"px-4 py-3\"><StatusBadge status={a.status} /></td>\n <td className=\"px-4 py-3 text-right font-mono\">{fmt(a.purchasePrice, a.currencyCode || currency)}</td>\n <td className=\"px-4 py-3 text-muted-foreground\">\n {a.subscriptionId ? `Sub ${a.subscriptionId.slice(0, 8)}\u2026` : '\u2014'}\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n )\n}\n\n// \u2500\u2500\u2500 Shared \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nfunction EmptyTab() {\n return (\n <div className=\"rounded-lg border bg-card py-8 text-center text-sm text-muted-foreground\">\n No records in this category.\n </div>\n )\n}\n\nfunction Spinner() {\n return (\n <svg className=\"h-4 w-4 animate-spin\" viewBox=\"0 0 24 24\" fill=\"none\">\n <circle className=\"opacity-25\" cx=\"12\" cy=\"12\" r=\"10\" stroke=\"currentColor\" strokeWidth=\"4\" />\n <path className=\"opacity-75\" fill=\"currentColor\" d=\"M4 12a8 8 0 018-8v4a4 4 0 00-4 4H4z\" />\n </svg>\n )\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["\"use client\"\nimport * as React from 'react'\nimport type { InjectionWidgetComponentProps } from '@open-mercato/shared/modules/widgets/injection'\nimport { useRouter } from 'next/navigation'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { Tag } from '@open-mercato/ui/primitives/tag'\nimport {\n assetStatusMap,\n subscriptionStatusMap,\n type AssetStatus,\n type SubscriptionStatus,\n} from '../../../components/statusMaps'\nimport { inventoryStatusLabel } from '../../../backend/cpq/inventory/shared'\n\n// \u2500\u2500\u2500 Types \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\ntype Subscription = {\n id: string\n code: string\n name: string\n status: string\n mrcAmount: number\n nrcAmount: number\n billingCycle: string\n currencyCode: string\n startDate: string\n currentTermEnd: string | null\n autoRenew: boolean\n createdAt: string\n}\n\ntype SubscriptionItem = {\n id: string\n subscriptionId: string\n parentItemId: string | null\n productId: string | null\n name: string\n status: string\n mrcAmount: number\n nrcAmount: number\n currencyCode: string\n quantity: number\n}\n\ntype Asset = {\n id: string\n code: string\n name: string\n status: string\n assetType: string\n purchasePrice: number\n currencyCode: string\n subscriptionId: string | null\n subscriptionItemId: string | null\n createdAt: string\n}\n\ntype InventorySummary = {\n activeSubscriptions: number\n totalMrc: number\n activeAssets: number\n pendingItems: number\n currencyCode: string\n}\n\ntype InventoryResponse = {\n customerId: string\n subscriptions: Subscription[]\n subscriptionItems: SubscriptionItem[]\n assets: Asset[]\n summary: InventorySummary\n}\n\ntype TabKey = 'subscriptions' | 'items' | 'assets'\n\n// \u2500\u2500\u2500 Helpers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nfunction fmt(amount: number, currency: string): string {\n return new Intl.NumberFormat('en-US', { style: 'currency', currency }).format(amount)\n}\n\nfunction StatusBadge({ status }: { status: string }) {\n const t = useT()\n const variant =\n subscriptionStatusMap[status as SubscriptionStatus] ??\n assetStatusMap[status as AssetStatus] ??\n 'neutral'\n return (\n <Tag variant={variant} dot>\n {inventoryStatusLabel(t, status)}\n </Tag>\n )\n}\n\n// \u2500\u2500\u2500 Main Widget \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport default function CustomerInventoryWidget({ data, context }: InjectionWidgetComponentProps & { context?: Record<string, unknown> }) {\n const t = useT()\n const router = useRouter()\n const record = data as Record<string, unknown> | null\n const companyRecord = record?.company as Record<string, unknown> | undefined\n const customerId =\n (context?.companyId as string) ??\n (context?.resourceId as string) ??\n (companyRecord?.id as string) ??\n (record?.id as string) ??\n null\n\n const [inventory, setInventory] = React.useState<InventoryResponse | null>(null)\n const [loading, setLoading] = React.useState(true)\n const [activeTab, setActiveTab] = React.useState<TabKey>('subscriptions')\n\n React.useEffect(() => {\n if (!customerId) { setLoading(false); return }\n let cancelled = false\n async function load() {\n try {\n const res = await fetch(`/api/cpq/inventory/customer/${customerId}`)\n if (res.ok && !cancelled) setInventory(await res.json())\n } catch { /* no inventory data */ }\n finally { if (!cancelled) setLoading(false) }\n }\n load()\n return () => { cancelled = true }\n }, [customerId])\n\n if (!customerId) return <div className=\"p-4 text-sm text-muted-foreground\">{t('cpq.widgets.customerInventory.noContext', 'No customer context available.')}</div>\n\n if (loading) {\n return (\n <div className=\"flex items-center gap-2 p-6 text-sm text-muted-foreground\">\n <Spinner /> {t('cpq.widgets.customerInventory.loading', 'Loading inventory\u2026')}\n </div>\n )\n }\n\n if (!inventory || (inventory.subscriptions.length === 0 && inventory.assets.length === 0)) {\n return (\n <div className=\"flex flex-col items-center justify-center py-12 px-4\">\n <div className=\"rounded-full bg-primary/10 p-3 mb-3\">\n <svg className=\"h-6 w-6 text-primary\" fill=\"none\" viewBox=\"0 0 24 24\" strokeWidth=\"1.5\" stroke=\"currentColor\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M20.25 7.5l-.625 10.632a2.25 2.25 0 01-2.247 2.118H6.622a2.25 2.25 0 01-2.247-2.118L3.75 7.5M10 11.25h4M3.375 7.5h17.25c.621 0 1.125-.504 1.125-1.125v-1.5c0-.621-.504-1.125-1.125-1.125H3.375c-.621 0-1.125.504-1.125 1.125v1.5c0 .621.504 1.125 1.125 1.125z\" />\n </svg>\n </div>\n <p className=\"text-sm text-muted-foreground\">{t('cpq.widgets.customerInventory.empty', 'No inventory records found.')}</p>\n </div>\n )\n }\n\n const { summary } = inventory\n const currency = summary.currencyCode || 'USD'\n\n const tabs: { key: TabKey; label: string; count: number }[] = [\n { key: 'subscriptions', label: t('cpq.widgets.customerInventory.tabs.subscriptions', 'Subscriptions'), count: inventory.subscriptions.length },\n { key: 'items', label: t('cpq.widgets.customerInventory.tabs.items', 'Subscription Items'), count: inventory.subscriptionItems.length },\n { key: 'assets', label: t('cpq.widgets.customerInventory.tabs.assets', 'Assets'), count: inventory.assets.length },\n ]\n\n return (\n <div className=\"space-y-4\">\n {/* Summary Cards */}\n <div className=\"grid grid-cols-2 sm:grid-cols-4 gap-3\">\n <SummaryCard label={t('cpq.widgets.customerInventory.summary.activeSubscriptions', 'Active Subscriptions')} value={String(summary.activeSubscriptions)} />\n <SummaryCard label={t('cpq.widgets.customerInventory.summary.totalMrc', 'Total MRC')} value={fmt(summary.totalMrc, currency)} mono />\n <SummaryCard label={t('cpq.widgets.customerInventory.summary.activeAssets', 'Active Assets')} value={String(summary.activeAssets)} />\n <SummaryCard label={t('cpq.widgets.customerInventory.summary.pendingItems', 'Pending Items')} value={String(summary.pendingItems)} />\n </div>\n\n {/* Tab Switcher */}\n <div className=\"flex gap-1 border-b\">\n {tabs.map((tab) => (\n <button\n key={tab.key}\n onClick={() => setActiveTab(tab.key)}\n className={`px-3 py-2 text-sm font-medium transition-colors border-b-2 -mb-px ${\n activeTab === tab.key\n ? 'border-primary text-primary'\n : 'border-transparent text-muted-foreground hover:text-foreground'\n }`}\n >\n {tab.label}\n <span className=\"ml-1.5 rounded-full bg-muted px-1.5 py-0.5 text-xs\">{tab.count}</span>\n </button>\n ))}\n </div>\n\n {/* Tab Content */}\n {activeTab === 'subscriptions' && <SubscriptionsTable items={inventory.subscriptions} currency={currency} onOpen={(id) => router.push(`/backend/cpq/inventory/subscriptions/${id}`)} />}\n {activeTab === 'items' && <SubscriptionItemsTable items={inventory.subscriptionItems} currency={currency} onOpen={(id) => router.push(`/backend/cpq/inventory/subscriptions/${id}`)} />}\n {activeTab === 'assets' && <AssetsTable items={inventory.assets} currency={currency} onOpen={(id) => router.push(`/backend/cpq/inventory/assets/${id}`)} />}\n\n {/* Link to full page */}\n <div className=\"pt-2 text-right\">\n <a href=\"/backend/cpq/inventory\" className=\"text-sm text-primary hover:underline\">\n {t('cpq.widgets.customerInventory.viewFull', 'View full inventory \u2192')}\n </a>\n </div>\n </div>\n )\n}\n\n// \u2500\u2500\u2500 Summary Card \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nfunction SummaryCard({ label, value, mono }: { label: string; value: string; mono?: boolean }) {\n return (\n <div className=\"rounded-lg border bg-card p-3\">\n <p className=\"text-xs text-muted-foreground\">{label}</p>\n <p className={`text-lg font-semibold ${mono ? 'font-mono' : ''}`}>{value}</p>\n </div>\n )\n}\n\n// \u2500\u2500\u2500 Subscriptions Table \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nfunction SubscriptionsTable({ items, currency, onOpen }: { items: Subscription[]; currency: string; onOpen: (id: string) => void }) {\n const t = useT()\n if (items.length === 0) return <EmptyTab />\n return (\n <div className=\"rounded-lg border bg-card overflow-hidden\">\n <table className=\"w-full text-sm\">\n <thead>\n <tr className=\"border-b border-border bg-muted/40 text-muted-foreground\">\n <th className=\"px-4 py-2.5 text-left text-xs font-medium uppercase tracking-wide\">{t('cpq.widgets.customerInventory.table.name', 'Name')}</th>\n <th className=\"px-4 py-2.5 text-left text-xs font-medium uppercase tracking-wide\">{t('cpq.widgets.customerInventory.table.status', 'Status')}</th>\n <th className=\"px-4 py-2.5 text-right text-xs font-medium uppercase tracking-wide\">{t('cpq.widgets.customerInventory.table.mrc', 'MRC')}</th>\n <th className=\"px-4 py-2.5 text-left text-xs font-medium uppercase tracking-wide\">{t('cpq.widgets.customerInventory.table.billing', 'Billing')}</th>\n <th className=\"px-4 py-2.5 text-left text-xs font-medium uppercase tracking-wide\">{t('cpq.widgets.customerInventory.table.startDate', 'Start Date')}</th>\n <th className=\"px-4 py-2.5 text-left text-xs font-medium uppercase tracking-wide\">{t('cpq.widgets.customerInventory.table.termEnd', 'Term End')}</th>\n </tr>\n </thead>\n <tbody>\n {items.map((s) => (\n <tr\n key={s.id}\n onClick={() => onOpen(s.id)}\n className=\"border-b border-border last:border-0 cursor-pointer hover:bg-accent/40 transition-colors\"\n >\n <td className=\"px-4 py-3 font-medium\">{s.name}</td>\n <td className=\"px-4 py-3\"><StatusBadge status={s.status} /></td>\n <td className=\"px-4 py-3 text-right font-mono\">{fmt(s.mrcAmount, s.currencyCode || currency)}</td>\n <td className=\"px-4 py-3 capitalize\">{s.billingCycle}</td>\n <td className=\"px-4 py-3 text-muted-foreground\">{s.startDate ? new Date(s.startDate).toLocaleDateString() : '\u2014'}</td>\n <td className=\"px-4 py-3 text-muted-foreground\">{s.currentTermEnd ? new Date(s.currentTermEnd).toLocaleDateString() : '\u2014'}</td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n )\n}\n\n// \u2500\u2500\u2500 Subscription Items Table \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nfunction SubscriptionItemsTable({ items, currency, onOpen }: { items: SubscriptionItem[]; currency: string; onOpen: (subscriptionId: string) => void }) {\n const t = useT()\n if (items.length === 0) return <EmptyTab />\n return (\n <div className=\"rounded-lg border bg-card overflow-hidden\">\n <table className=\"w-full text-sm\">\n <thead>\n <tr className=\"border-b border-border bg-muted/40 text-muted-foreground\">\n <th className=\"px-4 py-2.5 text-left text-xs font-medium uppercase tracking-wide\">{t('cpq.widgets.customerInventory.table.name', 'Name')}</th>\n <th className=\"px-4 py-2.5 text-left text-xs font-medium uppercase tracking-wide\">{t('cpq.widgets.customerInventory.table.status', 'Status')}</th>\n <th className=\"px-4 py-2.5 text-right text-xs font-medium uppercase tracking-wide\">{t('cpq.widgets.customerInventory.table.mrc', 'MRC')}</th>\n <th className=\"px-4 py-2.5 text-right text-xs font-medium uppercase tracking-wide\">{t('cpq.widgets.customerInventory.table.nrc', 'NRC')}</th>\n <th className=\"px-4 py-2.5 text-right text-xs font-medium uppercase tracking-wide\">{t('cpq.widgets.customerInventory.table.qty', 'Qty')}</th>\n </tr>\n </thead>\n <tbody>\n {items.map((item) => (\n <tr\n key={item.id}\n onClick={() => onOpen(item.subscriptionId)}\n className=\"border-b border-border last:border-0 cursor-pointer hover:bg-accent/40 transition-colors\"\n >\n <td className=\"px-4 py-3 font-medium\">{item.name}</td>\n <td className=\"px-4 py-3\"><StatusBadge status={item.status} /></td>\n <td className=\"px-4 py-3 text-right font-mono\">{fmt(item.mrcAmount, item.currencyCode || currency)}</td>\n <td className=\"px-4 py-3 text-right font-mono\">{fmt(item.nrcAmount, item.currencyCode || currency)}</td>\n <td className=\"px-4 py-3 text-right font-mono\">{item.quantity}</td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n )\n}\n\n// \u2500\u2500\u2500 Assets Table \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nfunction AssetsTable({ items, currency, onOpen }: { items: Asset[]; currency: string; onOpen: (id: string) => void }) {\n const t = useT()\n if (items.length === 0) return <EmptyTab />\n return (\n <div className=\"rounded-lg border bg-card overflow-hidden\">\n <table className=\"w-full text-sm\">\n <thead>\n <tr className=\"border-b border-border bg-muted/40 text-muted-foreground\">\n <th className=\"px-4 py-2.5 text-left text-xs font-medium uppercase tracking-wide\">{t('cpq.widgets.customerInventory.table.name', 'Name')}</th>\n <th className=\"px-4 py-2.5 text-left text-xs font-medium uppercase tracking-wide\">{t('cpq.widgets.customerInventory.table.type', 'Type')}</th>\n <th className=\"px-4 py-2.5 text-left text-xs font-medium uppercase tracking-wide\">{t('cpq.widgets.customerInventory.table.status', 'Status')}</th>\n <th className=\"px-4 py-2.5 text-right text-xs font-medium uppercase tracking-wide\">{t('cpq.widgets.customerInventory.table.price', 'Price')}</th>\n <th className=\"px-4 py-2.5 text-left text-xs font-medium uppercase tracking-wide\">{t('cpq.widgets.customerInventory.table.linkedTo', 'Linked To')}</th>\n </tr>\n </thead>\n <tbody>\n {items.map((a) => (\n <tr\n key={a.id}\n onClick={() => onOpen(a.id)}\n className=\"border-b border-border last:border-0 cursor-pointer hover:bg-accent/40 transition-colors\"\n >\n <td className=\"px-4 py-3 font-medium\">{a.name}</td>\n <td className=\"px-4 py-3 capitalize\">{a.assetType.replace(/_/g, ' ')}</td>\n <td className=\"px-4 py-3\"><StatusBadge status={a.status} /></td>\n <td className=\"px-4 py-3 text-right font-mono\">{fmt(a.purchasePrice, a.currencyCode || currency)}</td>\n <td className=\"px-4 py-3 text-muted-foreground\">\n {a.subscriptionId ? t('cpq.widgets.customerInventory.table.linkedSubscription', 'Sub {id}\u2026', { id: a.subscriptionId.slice(0, 8) }) : '\u2014'}\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n )\n}\n\n// \u2500\u2500\u2500 Shared \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nfunction EmptyTab() {\n const t = useT()\n return (\n <div className=\"rounded-lg border bg-card py-8 text-center text-sm text-muted-foreground\">\n {t('cpq.widgets.customerInventory.emptyTab', 'No records in this category.')}\n </div>\n )\n}\n\nfunction Spinner() {\n return (\n <svg className=\"h-4 w-4 animate-spin\" viewBox=\"0 0 24 24\" fill=\"none\">\n <circle className=\"opacity-25\" cx=\"12\" cy=\"12\" r=\"10\" stroke=\"currentColor\" strokeWidth=\"4\" />\n <path className=\"opacity-75\" fill=\"currentColor\" d=\"M4 12a8 8 0 018-8v4a4 4 0 00-4 4H4z\" />\n </svg>\n )\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -3,6 +3,7 @@ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
3
3
  import * as React from "react";
4
4
  import { useRouter } from "next/navigation";
5
5
  import { Tag } from "@open-mercato/ui/primitives/tag";
6
+ import { useT } from "@open-mercato/shared/lib/i18n/context";
6
7
  import {
7
8
  formatStatusLabel,
8
9
  orderCpqStatusMap
@@ -13,6 +14,7 @@ function fmt(amount, currency) {
13
14
  }
14
15
  function OrderCpqTabWidget({ data }) {
15
16
  const router = useRouter();
17
+ const t = useT();
16
18
  const salesOrderId = data?.id;
17
19
  const [cpqOrders, setCpqOrders] = React.useState([]);
18
20
  const [loading, setLoading] = React.useState(true);
@@ -38,11 +40,11 @@ function OrderCpqTabWidget({ data }) {
38
40
  /* @__PURE__ */ jsx("circle", { className: "opacity-25", cx: "12", cy: "12", r: "10", stroke: "currentColor", strokeWidth: "4" }),
39
41
  /* @__PURE__ */ jsx("path", { className: "opacity-75", fill: "currentColor", d: "M4 12a8 8 0 018-8v4a4 4 0 00-4 4H4z" })
40
42
  ] }),
41
- "Loading CPQ orders\u2026"
43
+ t("cpq.widgets.orderCpqTab.loading", "Loading CPQ orders\u2026")
42
44
  ] });
43
45
  }
44
46
  if (cpqOrders.length === 0) {
45
- return /* @__PURE__ */ jsx("div", { className: "py-8 text-center text-sm text-muted-foreground", children: "No CPQ orders linked to this sales order." });
47
+ return /* @__PURE__ */ jsx("div", { className: "py-8 text-center text-sm text-muted-foreground", children: t("cpq.widgets.orderCpqTab.empty", "No CPQ orders linked to this sales order.") });
46
48
  }
47
49
  return /* @__PURE__ */ jsx("div", { className: "space-y-2", children: cpqOrders.map((o) => /* @__PURE__ */ jsxs(
48
50
  "div",
@@ -57,16 +59,22 @@ function OrderCpqTabWidget({ data }) {
57
59
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-4 text-xs", children: [
58
60
  o.pricingSummary && /* @__PURE__ */ jsxs(Fragment, { children: [
59
61
  /* @__PURE__ */ jsxs("span", { children: [
60
- /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "NRC " }),
62
+ /* @__PURE__ */ jsxs("span", { className: "text-muted-foreground", children: [
63
+ t("cpq.lines.nrc", "NRC"),
64
+ " "
65
+ ] }),
61
66
  /* @__PURE__ */ jsx("span", { className: "font-mono font-medium", children: fmt(o.pricingSummary.nrcTotal, o.currencyCode) })
62
67
  ] }),
63
68
  /* @__PURE__ */ jsxs("span", { children: [
64
- /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "MRC " }),
69
+ /* @__PURE__ */ jsxs("span", { className: "text-muted-foreground", children: [
70
+ t("cpq.lines.mrc", "MRC"),
71
+ " "
72
+ ] }),
65
73
  /* @__PURE__ */ jsx("span", { className: "font-mono font-medium", children: fmt(o.pricingSummary.mrcTotal, o.currencyCode) })
66
74
  ] })
67
75
  ] }),
68
76
  /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: new Date(o.createdAt).toLocaleDateString() }),
69
- /* @__PURE__ */ jsx("span", { className: "text-primary font-medium", children: "Open \u2192" })
77
+ /* @__PURE__ */ jsx("span", { className: "text-primary font-medium", children: t("cpq.widgets.orderCpqTab.open", "Open \u2192") })
70
78
  ] })
71
79
  ]
72
80
  },
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../../src/modules/cpq/widgets/injection/order-cpq-tab/widget.client.tsx"],
4
- "sourcesContent": ["\"use client\"\nimport * as React from 'react'\nimport type { InjectionWidgetComponentProps } from '@open-mercato/shared/modules/widgets/injection'\nimport { useRouter } from 'next/navigation'\nimport { Tag } from '@open-mercato/ui/primitives/tag'\nimport {\n formatStatusLabel,\n orderCpqStatusMap,\n type OrderCpqStatus,\n} from '../../../components/statusMaps'\n\ntype CpqOrderSummary = {\n id: string\n orderId: string\n orderNumber?: string\n cpqStatus: string\n sourceQuoteId: string | null\n currencyCode: string\n pricingSummary: { nrcTotal: number; mrcTotal: number } | null\n activatedAt: string | null\n createdAt: string\n}\n\nfunction fmt(amount: number | undefined | null, currency: string): string {\n if (amount == null) return '\u2014'\n return new Intl.NumberFormat('en-US', { style: 'currency', currency }).format(amount)\n}\n\nexport default function OrderCpqTabWidget({ data }: InjectionWidgetComponentProps<any, any>) {\n const router = useRouter()\n const salesOrderId = data?.id as string | undefined\n const [cpqOrders, setCpqOrders] = React.useState<CpqOrderSummary[]>([])\n const [loading, setLoading] = React.useState(true)\n\n React.useEffect(() => {\n if (!salesOrderId) { setLoading(false); return }\n let cancelled = false\n fetch(`/api/cpq/orders?salesOrderId=${salesOrderId}&pageSize=50`)\n .then((r) => r.json())\n .then((result) => {\n if (!cancelled) setCpqOrders(result.items ?? [])\n })\n .catch(() => {})\n .finally(() => { if (!cancelled) setLoading(false) })\n return () => { cancelled = true }\n }, [salesOrderId])\n\n if (loading) {\n return (\n <div className=\"flex items-center gap-2 py-8 justify-center text-sm text-muted-foreground\">\n <svg className=\"h-4 w-4 animate-spin\" viewBox=\"0 0 24 24\" fill=\"none\">\n <circle className=\"opacity-25\" cx=\"12\" cy=\"12\" r=\"10\" stroke=\"currentColor\" strokeWidth=\"4\" />\n <path className=\"opacity-75\" fill=\"currentColor\" d=\"M4 12a8 8 0 018-8v4a4 4 0 00-4 4H4z\" />\n </svg>\n Loading CPQ orders\u2026\n </div>\n )\n }\n\n if (cpqOrders.length === 0) {\n return (\n <div className=\"py-8 text-center text-sm text-muted-foreground\">\n No CPQ orders linked to this sales order.\n </div>\n )\n }\n\n return (\n <div className=\"space-y-2\">\n {cpqOrders.map((o) => (\n <div\n key={o.id}\n onClick={() => router.push(`/backend/cpq/orders/${o.id}`)}\n className=\"flex items-center justify-between rounded-lg border p-3 hover:bg-muted/30 cursor-pointer transition-colors\"\n >\n <div className=\"flex items-center gap-3\">\n <Tag variant={orderCpqStatusMap[o.cpqStatus as OrderCpqStatus] ?? 'neutral'} dot>\n {formatStatusLabel(o.cpqStatus)}\n </Tag>\n <span className=\"text-sm font-medium\">{o.currencyCode}</span>\n </div>\n <div className=\"flex items-center gap-4 text-xs\">\n {o.pricingSummary && (\n <>\n <span><span className=\"text-muted-foreground\">NRC </span><span className=\"font-mono font-medium\">{fmt(o.pricingSummary.nrcTotal, o.currencyCode)}</span></span>\n <span><span className=\"text-muted-foreground\">MRC </span><span className=\"font-mono font-medium\">{fmt(o.pricingSummary.mrcTotal, o.currencyCode)}</span></span>\n </>\n )}\n <span className=\"text-muted-foreground\">{new Date(o.createdAt).toLocaleDateString()}</span>\n <span className=\"text-primary font-medium\">Open \u2192</span>\n </div>\n </div>\n ))}\n </div>\n )\n}\n"],
5
- "mappings": ";AAkDQ,SAiCM,UAhCJ,KADF;AAjDR,YAAY,WAAW;AAEvB,SAAS,iBAAiB;AAC1B,SAAS,WAAW;AACpB;AAAA,EACE;AAAA,EACA;AAAA,OAEK;AAcP,SAAS,IAAI,QAAmC,UAA0B;AACxE,MAAI,UAAU,KAAM,QAAO;AAC3B,SAAO,IAAI,KAAK,aAAa,SAAS,EAAE,OAAO,YAAY,SAAS,CAAC,EAAE,OAAO,MAAM;AACtF;AAEe,SAAR,kBAAmC,EAAE,KAAK,GAA4C;AAC3F,QAAM,SAAS,UAAU;AACzB,QAAM,eAAe,MAAM;AAC3B,QAAM,CAAC,WAAW,YAAY,IAAI,MAAM,SAA4B,CAAC,CAAC;AACtE,QAAM,CAAC,SAAS,UAAU,IAAI,MAAM,SAAS,IAAI;AAEjD,QAAM,UAAU,MAAM;AACpB,QAAI,CAAC,cAAc;AAAE,iBAAW,KAAK;AAAG;AAAA,IAAO;AAC/C,QAAI,YAAY;AAChB,UAAM,gCAAgC,YAAY,cAAc,EAC7D,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,EACpB,KAAK,CAAC,WAAW;AAChB,UAAI,CAAC,UAAW,cAAa,OAAO,SAAS,CAAC,CAAC;AAAA,IACjD,CAAC,EACA,MAAM,MAAM;AAAA,IAAC,CAAC,EACd,QAAQ,MAAM;AAAE,UAAI,CAAC,UAAW,YAAW,KAAK;AAAA,IAAE,CAAC;AACtD,WAAO,MAAM;AAAE,kBAAY;AAAA,IAAK;AAAA,EAClC,GAAG,CAAC,YAAY,CAAC;AAEjB,MAAI,SAAS;AACX,WACE,qBAAC,SAAI,WAAU,6EACb;AAAA,2BAAC,SAAI,WAAU,wBAAuB,SAAQ,aAAY,MAAK,QAC7D;AAAA,4BAAC,YAAO,WAAU,cAAa,IAAG,MAAK,IAAG,MAAK,GAAE,MAAK,QAAO,gBAAe,aAAY,KAAI;AAAA,QAC5F,oBAAC,UAAK,WAAU,cAAa,MAAK,gBAAe,GAAE,uCAAsC;AAAA,SAC3F;AAAA,MAAM;AAAA,OAER;AAAA,EAEJ;AAEA,MAAI,UAAU,WAAW,GAAG;AAC1B,WACE,oBAAC,SAAI,WAAU,kDAAiD,uDAEhE;AAAA,EAEJ;AAEA,SACE,oBAAC,SAAI,WAAU,aACZ,oBAAU,IAAI,CAAC,MACd;AAAA,IAAC;AAAA;AAAA,MAEC,SAAS,MAAM,OAAO,KAAK,uBAAuB,EAAE,EAAE,EAAE;AAAA,MACxD,WAAU;AAAA,MAEV;AAAA,6BAAC,SAAI,WAAU,2BACb;AAAA,8BAAC,OAAI,SAAS,kBAAkB,EAAE,SAA2B,KAAK,WAAW,KAAG,MAC7E,4BAAkB,EAAE,SAAS,GAChC;AAAA,UACA,oBAAC,UAAK,WAAU,uBAAuB,YAAE,cAAa;AAAA,WACxD;AAAA,QACA,qBAAC,SAAI,WAAU,mCACZ;AAAA,YAAE,kBACD,iCACE;AAAA,iCAAC,UAAK;AAAA,kCAAC,UAAK,WAAU,yBAAwB,kBAAI;AAAA,cAAO,oBAAC,UAAK,WAAU,yBAAyB,cAAI,EAAE,eAAe,UAAU,EAAE,YAAY,GAAE;AAAA,eAAO;AAAA,YACxJ,qBAAC,UAAK;AAAA,kCAAC,UAAK,WAAU,yBAAwB,kBAAI;AAAA,cAAO,oBAAC,UAAK,WAAU,yBAAyB,cAAI,EAAE,eAAe,UAAU,EAAE,YAAY,GAAE;AAAA,eAAO;AAAA,aAC1J;AAAA,UAEF,oBAAC,UAAK,WAAU,yBAAyB,cAAI,KAAK,EAAE,SAAS,EAAE,mBAAmB,GAAE;AAAA,UACpF,oBAAC,UAAK,WAAU,4BAA2B,yBAAM;AAAA,WACnD;AAAA;AAAA;AAAA,IAnBK,EAAE;AAAA,EAoBT,CACD,GACH;AAEJ;",
4
+ "sourcesContent": ["\"use client\"\nimport * as React from 'react'\nimport type { InjectionWidgetComponentProps } from '@open-mercato/shared/modules/widgets/injection'\nimport { useRouter } from 'next/navigation'\nimport { Tag } from '@open-mercato/ui/primitives/tag'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport {\n formatStatusLabel,\n orderCpqStatusMap,\n type OrderCpqStatus,\n} from '../../../components/statusMaps'\n\ntype CpqOrderSummary = {\n id: string\n orderId: string\n orderNumber?: string\n cpqStatus: string\n sourceQuoteId: string | null\n currencyCode: string\n pricingSummary: { nrcTotal: number; mrcTotal: number } | null\n activatedAt: string | null\n createdAt: string\n}\n\nfunction fmt(amount: number | undefined | null, currency: string): string {\n if (amount == null) return '\u2014'\n return new Intl.NumberFormat('en-US', { style: 'currency', currency }).format(amount)\n}\n\nexport default function OrderCpqTabWidget({ data }: InjectionWidgetComponentProps<any, any>) {\n const router = useRouter()\n const t = useT()\n const salesOrderId = data?.id as string | undefined\n const [cpqOrders, setCpqOrders] = React.useState<CpqOrderSummary[]>([])\n const [loading, setLoading] = React.useState(true)\n\n React.useEffect(() => {\n if (!salesOrderId) { setLoading(false); return }\n let cancelled = false\n fetch(`/api/cpq/orders?salesOrderId=${salesOrderId}&pageSize=50`)\n .then((r) => r.json())\n .then((result) => {\n if (!cancelled) setCpqOrders(result.items ?? [])\n })\n .catch(() => {})\n .finally(() => { if (!cancelled) setLoading(false) })\n return () => { cancelled = true }\n }, [salesOrderId])\n\n if (loading) {\n return (\n <div className=\"flex items-center gap-2 py-8 justify-center text-sm text-muted-foreground\">\n <svg className=\"h-4 w-4 animate-spin\" viewBox=\"0 0 24 24\" fill=\"none\">\n <circle className=\"opacity-25\" cx=\"12\" cy=\"12\" r=\"10\" stroke=\"currentColor\" strokeWidth=\"4\" />\n <path className=\"opacity-75\" fill=\"currentColor\" d=\"M4 12a8 8 0 018-8v4a4 4 0 00-4 4H4z\" />\n </svg>\n {t('cpq.widgets.orderCpqTab.loading', 'Loading CPQ orders\u2026')}\n </div>\n )\n }\n\n if (cpqOrders.length === 0) {\n return (\n <div className=\"py-8 text-center text-sm text-muted-foreground\">\n {t('cpq.widgets.orderCpqTab.empty', 'No CPQ orders linked to this sales order.')}\n </div>\n )\n }\n\n return (\n <div className=\"space-y-2\">\n {cpqOrders.map((o) => (\n <div\n key={o.id}\n onClick={() => router.push(`/backend/cpq/orders/${o.id}`)}\n className=\"flex items-center justify-between rounded-lg border p-3 hover:bg-muted/30 cursor-pointer transition-colors\"\n >\n <div className=\"flex items-center gap-3\">\n <Tag variant={orderCpqStatusMap[o.cpqStatus as OrderCpqStatus] ?? 'neutral'} dot>\n {formatStatusLabel(o.cpqStatus)}\n </Tag>\n <span className=\"text-sm font-medium\">{o.currencyCode}</span>\n </div>\n <div className=\"flex items-center gap-4 text-xs\">\n {o.pricingSummary && (\n <>\n <span><span className=\"text-muted-foreground\">{t('cpq.lines.nrc', 'NRC')} </span><span className=\"font-mono font-medium\">{fmt(o.pricingSummary.nrcTotal, o.currencyCode)}</span></span>\n <span><span className=\"text-muted-foreground\">{t('cpq.lines.mrc', 'MRC')} </span><span className=\"font-mono font-medium\">{fmt(o.pricingSummary.mrcTotal, o.currencyCode)}</span></span>\n </>\n )}\n <span className=\"text-muted-foreground\">{new Date(o.createdAt).toLocaleDateString()}</span>\n <span className=\"text-primary font-medium\">{t('cpq.widgets.orderCpqTab.open', 'Open \u2192')}</span>\n </div>\n </div>\n ))}\n </div>\n )\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -3,6 +3,7 @@ import { jsx, jsxs } from "react/jsx-runtime";
3
3
  import * as React from "react";
4
4
  import { useRouter } from "next/navigation";
5
5
  import { Tag } from "@open-mercato/ui/primitives/tag";
6
+ import { useT } from "@open-mercato/shared/lib/i18n/context";
6
7
  import {
7
8
  formatStatusLabel,
8
9
  quoteCpqStatusMap
@@ -10,8 +11,21 @@ import {
10
11
  function fmt(amount, currency) {
11
12
  return new Intl.NumberFormat("en-US", { style: "currency", currency }).format(amount);
12
13
  }
14
+ function chargeTypeLabel(t, chargeType) {
15
+ switch (chargeType) {
16
+ case "nrc":
17
+ return t("cpq.lines.chargeType.nrc", "nrc");
18
+ case "mrc":
19
+ return t("cpq.lines.chargeType.mrc", "mrc");
20
+ case "usage":
21
+ return t("cpq.lines.chargeType.usage", "usage");
22
+ default:
23
+ return chargeType;
24
+ }
25
+ }
13
26
  function QuoteConfiguratorWidget({ data }) {
14
27
  const router = useRouter();
28
+ const t = useT();
15
29
  const record = data;
16
30
  const quoteId = record?.id ?? null;
17
31
  const [cpqQuote, setCpqQuote] = React.useState(null);
@@ -37,11 +51,12 @@ function QuoteConfiguratorWidget({ data }) {
37
51
  cancelled = true;
38
52
  };
39
53
  }, [quoteId]);
40
- if (!quoteId) return /* @__PURE__ */ jsx("div", { className: "p-4 text-sm text-muted-foreground", children: "No quote context available." });
54
+ if (!quoteId) return /* @__PURE__ */ jsx("div", { className: "p-4 text-sm text-muted-foreground", children: t("cpq.widgets.quoteConfigurator.noContext", "No quote context available.") });
41
55
  if (loading) {
42
56
  return /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 p-6 text-sm text-muted-foreground", children: [
43
57
  /* @__PURE__ */ jsx(Spinner, {}),
44
- " Loading CPQ configuration\u2026"
58
+ " ",
59
+ t("cpq.widgets.quoteConfigurator.loading", "Loading CPQ configuration\u2026")
45
60
  ] });
46
61
  }
47
62
  if (!cpqQuote) {
@@ -51,7 +66,7 @@ function QuoteConfiguratorWidget({ data }) {
51
66
  /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M9.594 3.94c.09-.542.56-.94 1.11-.94h2.593c.55 0 1.02.398 1.11.94l.213 1.281c.063.374.313.686.645.87.074.04.147.083.22.127.325.196.72.257 1.075.124l1.217-.456a1.125 1.125 0 011.37.49l1.296 2.247a1.125 1.125 0 01-.26 1.431l-1.003.827c-.293.241-.438.613-.43.992a7.723 7.723 0 010 .255c-.008.378.137.75.43.991l1.004.827c.424.35.534.955.26 1.43l-1.298 2.247a1.125 1.125 0 01-1.369.491l-1.217-.456c-.355-.133-.75-.072-1.076.124a6.47 6.47 0 01-.22.128c-.331.183-.581.495-.644.869l-.213 1.281c-.09.543-.56.94-1.11.94h-2.594c-.55 0-1.019-.398-1.11-.94l-.213-1.281c-.062-.374-.312-.686-.644-.87a6.52 6.52 0 01-.22-.127c-.325-.196-.72-.257-1.076-.124l-1.217.456a1.125 1.125 0 01-1.369-.49l-1.297-2.247a1.125 1.125 0 01.26-1.431l1.004-.827c.292-.24.437-.613.43-.991a6.932 6.932 0 010-.255c.007-.38-.138-.751-.43-.992l-1.004-.827a1.125 1.125 0 01-.26-1.43l1.297-2.247a1.125 1.125 0 011.37-.491l1.216.456c.356.133.751.072 1.076-.124.072-.044.146-.086.22-.128.332-.183.582-.495.644-.869l.214-1.28z" }),
52
67
  /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M15 12a3 3 0 11-6 0 3 3 0 016 0z" })
53
68
  ] }) }),
54
- /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground mb-4", children: "This quote has no CPQ configuration yet." }),
69
+ /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground mb-4", children: t("cpq.widgets.quoteConfigurator.noConfig", "This quote has no CPQ configuration yet.") }),
55
70
  /* @__PURE__ */ jsxs(
56
71
  "button",
57
72
  {
@@ -59,11 +74,11 @@ function QuoteConfiguratorWidget({ data }) {
59
74
  className: "inline-flex items-center gap-2 rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground shadow-sm hover:bg-primary/90 transition-colors",
60
75
  children: [
61
76
  /* @__PURE__ */ jsx("svg", { className: "h-4 w-4", 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" }) }),
62
- "Create CPQ Quote"
77
+ t("cpq.widgets.quoteConfigurator.create", "Create CPQ Quote")
63
78
  ]
64
79
  }
65
80
  ),
66
- !custId && /* @__PURE__ */ jsx("p", { className: "mt-2 text-xs text-status-warning-text", children: "Assign a customer to this quote first." })
81
+ !custId && /* @__PURE__ */ jsx("p", { className: "mt-2 text-xs text-status-warning-text", children: t("cpq.widgets.quoteConfigurator.assignCustomer", "Assign a customer to this quote first.") })
67
82
  ] });
68
83
  }
69
84
  const { pricingSummary: summary, currencyCode: currency } = cpqQuote;
@@ -90,13 +105,13 @@ function QuoteConfiguratorWidget({ data }) {
90
105
  onClick: () => router.push(`/backend/cpq/quotes/${cpqQuote.id}`),
91
106
  className: "inline-flex items-center gap-1.5 rounded-md bg-primary px-3 py-1.5 text-sm font-medium text-primary-foreground shadow-sm hover:bg-primary/90 transition-colors",
92
107
  children: [
93
- "Open CPQ Configurator",
108
+ t("cpq.widgets.quoteConfigurator.open", "Open CPQ Configurator"),
94
109
  /* @__PURE__ */ jsx("svg", { className: "h-4 w-4", fill: "none", viewBox: "0 0 24 24", strokeWidth: "2", stroke: "currentColor", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M13.5 6H5.25A2.25 2.25 0 003 8.25v10.5A2.25 2.25 0 005.25 21h10.5A2.25 2.25 0 0018 18.75V10.5m-10.5 6L21 3m0 0h-5.25M21 3v5.25" }) })
95
110
  ]
96
111
  }
97
112
  )
98
113
  ] }),
99
- cpqQuote.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." }) : /* @__PURE__ */ jsx("div", { className: "rounded-lg border bg-card divide-y", children: cpqQuote.lines.map((line) => {
114
+ cpqQuote.lines.length === 0 ? /* @__PURE__ */ jsx("div", { className: "rounded-lg border bg-card py-8 text-center text-sm text-muted-foreground", children: t("cpq.widgets.quoteConfigurator.noLines", "No items configured yet.") }) : /* @__PURE__ */ jsx("div", { className: "rounded-lg border bg-card divide-y", children: cpqQuote.lines.map((line) => {
100
115
  const isExpanded = expandedLines.has(line.lineId);
101
116
  return /* @__PURE__ */ jsxs("div", { children: [
102
117
  /* @__PURE__ */ jsxs(
@@ -113,17 +128,23 @@ function QuoteConfiguratorWidget({ data }) {
113
128
  "\xD7",
114
129
  line.quantity
115
130
  ] }),
116
- 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" })
131
+ 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") })
117
132
  ] }),
118
133
  line.validationErrors && line.validationErrors.length > 0 && /* @__PURE__ */ jsx("p", { className: "text-xs text-destructive mt-0.5", children: line.validationErrors[0].message })
119
134
  ] }),
120
135
  /* @__PURE__ */ jsxs("div", { className: "shrink-0 text-right text-xs space-y-0.5", children: [
121
136
  line.nrcTotal > 0 && /* @__PURE__ */ jsxs("div", { children: [
122
- /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "NRC " }),
137
+ /* @__PURE__ */ jsxs("span", { className: "text-muted-foreground", children: [
138
+ t("cpq.lines.nrc", "NRC"),
139
+ " "
140
+ ] }),
123
141
  /* @__PURE__ */ jsx("span", { className: "font-mono font-medium", children: fmt(line.nrcTotal, currency) })
124
142
  ] }),
125
143
  line.mrcTotal > 0 && /* @__PURE__ */ jsxs("div", { children: [
126
- /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "MRC " }),
144
+ /* @__PURE__ */ jsxs("span", { className: "text-muted-foreground", children: [
145
+ t("cpq.lines.mrc", "MRC"),
146
+ " "
147
+ ] }),
127
148
  /* @__PURE__ */ jsx("span", { className: "font-mono font-medium", children: fmt(line.mrcTotal, currency) })
128
149
  ] })
129
150
  ] })
@@ -132,15 +153,15 @@ function QuoteConfiguratorWidget({ data }) {
132
153
  ),
133
154
  isExpanded && line.charges.length > 0 && /* @__PURE__ */ jsx("div", { className: "border-t bg-muted/10 px-12 py-2", children: /* @__PURE__ */ jsxs("table", { className: "w-full text-xs", children: [
134
155
  /* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsxs("tr", { className: "text-muted-foreground", children: [
135
- /* @__PURE__ */ jsx("th", { className: "text-left py-1 font-medium", children: "Charge" }),
136
- /* @__PURE__ */ jsx("th", { className: "text-left py-1 font-medium", children: "Type" }),
137
- /* @__PURE__ */ jsx("th", { className: "text-right py-1 font-medium", children: "Unit Price" }),
138
- /* @__PURE__ */ jsx("th", { className: "text-right py-1 font-medium", children: "Qty" }),
139
- /* @__PURE__ */ jsx("th", { className: "text-right py-1 font-medium", children: "Total" })
156
+ /* @__PURE__ */ jsx("th", { className: "text-left py-1 font-medium", children: t("cpq.widgets.quoteConfigurator.charges.charge", "Charge") }),
157
+ /* @__PURE__ */ jsx("th", { className: "text-left py-1 font-medium", children: t("cpq.widgets.quoteConfigurator.charges.type", "Type") }),
158
+ /* @__PURE__ */ jsx("th", { className: "text-right py-1 font-medium", children: t("cpq.widgets.quoteConfigurator.charges.unitPrice", "Unit Price") }),
159
+ /* @__PURE__ */ jsx("th", { className: "text-right py-1 font-medium", children: t("cpq.widgets.quoteConfigurator.charges.qty", "Qty") }),
160
+ /* @__PURE__ */ jsx("th", { className: "text-right py-1 font-medium", children: t("cpq.widgets.quoteConfigurator.charges.total", "Total") })
140
161
  ] }) }),
141
162
  /* @__PURE__ */ jsx("tbody", { children: line.charges.map((c, i) => /* @__PURE__ */ jsxs("tr", { className: "border-t border-dashed border-border/50", children: [
142
163
  /* @__PURE__ */ jsx("td", { className: "py-1", children: c.chargeName }),
143
- /* @__PURE__ */ jsx("td", { className: "py-1 uppercase", children: c.chargeType }),
164
+ /* @__PURE__ */ jsx("td", { className: "py-1 uppercase", children: chargeTypeLabel(t, c.chargeType) }),
144
165
  /* @__PURE__ */ jsx("td", { className: "py-1 text-right font-mono", children: fmt(c.unitPrice, currency) }),
145
166
  /* @__PURE__ */ jsx("td", { className: "py-1 text-right font-mono", children: c.quantity ?? "\u2014" }),
146
167
  /* @__PURE__ */ jsx("td", { className: "py-1 text-right font-mono", children: c.totalPrice != null ? fmt(c.totalPrice, currency) : c.note ?? "\u2014" })
@@ -150,20 +171,19 @@ function QuoteConfiguratorWidget({ data }) {
150
171
  }) }),
151
172
  cpqQuote.lines.length > 0 && /* @__PURE__ */ jsx("div", { className: "rounded-lg border bg-card p-4", children: /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 sm:grid-cols-3 gap-4", children: [
152
173
  /* @__PURE__ */ jsxs("div", { children: [
153
- /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: "Non-Recurring (NRC)" }),
174
+ /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: t("cpq.quotes.summary.nrc", "Non-Recurring (NRC)") }),
154
175
  /* @__PURE__ */ jsx("p", { className: "text-lg font-semibold font-mono", children: fmt(summary.nrcTotal, currency) })
155
176
  ] }),
156
177
  /* @__PURE__ */ jsxs("div", { children: [
157
- /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: "Monthly Recurring (MRC)" }),
178
+ /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: t("cpq.quotes.summary.mrc", "Monthly Recurring (MRC)") }),
158
179
  /* @__PURE__ */ jsx("p", { className: "text-lg font-semibold font-mono", children: fmt(summary.mrcTotal, currency) })
159
180
  ] }),
160
181
  summary.usageCharges.length > 0 && /* @__PURE__ */ jsxs("div", { children: [
161
- /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: "Usage Charges" }),
182
+ /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: t("cpq.quotes.summary.usageCharges", "Usage Charges") }),
162
183
  /* @__PURE__ */ jsx("div", { className: "mt-1 space-y-0.5", children: summary.usageCharges.map((uc, i) => /* @__PURE__ */ jsxs("p", { className: "text-xs", children: [
163
184
  uc.chargeName,
164
185
  ": ",
165
- fmt(uc.unitPrice, currency),
166
- "/unit"
186
+ t("cpq.lines.perUnit", "{price}/unit", { price: fmt(uc.unitPrice, currency) })
167
187
  ] }, i)) })
168
188
  ] })
169
189
  ] }) })