@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
@@ -87,8 +87,8 @@ function SpecificationsListPage() {
87
87
  header: t("cpq.specifications.name", "Name"),
88
88
  cell: ({ row }) => /* @__PURE__ */ jsxs("span", { className: "font-medium", children: [
89
89
  row.original.name,
90
- row.original.specType === "bundle" && /* @__PURE__ */ jsx(Tag, { variant: "brand", className: "ml-2 px-2 text-[10px]", children: "bundle" }),
91
- row.original.isAssetizable && /* @__PURE__ */ jsx(Tag, { variant: "warning", className: "ml-1 px-2 text-[10px]", children: "asset" })
90
+ row.original.specType === "bundle" && /* @__PURE__ */ jsx(Tag, { variant: "brand", className: "ml-2 px-2 text-[10px]", children: t("cpq.specifications.list.tag.bundle", "bundle") }),
91
+ row.original.isAssetizable && /* @__PURE__ */ jsx(Tag, { variant: "warning", className: "ml-1 px-2 text-[10px]", children: t("cpq.specifications.list.tag.asset", "asset") })
92
92
  ] })
93
93
  },
94
94
  {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../../src/modules/cpq/backend/cpq/specifications/page.tsx"],
4
- "sourcesContent": ["\"use client\"\nimport * as React from 'react'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { useRouter } from 'next/navigation'\nimport type { LegacyColumnDef as ColumnDef } from '@tanstack/react-table/legacy'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { Checkbox } from '@open-mercato/ui/primitives/checkbox'\nimport { Tag } from '@open-mercato/ui/primitives/tag'\nimport type { FilterDef, FilterValues } from '@open-mercato/ui/backend/FilterBar'\nimport { CpqListView, useCpqListData } from '../../../components/CpqListView'\nimport {\n formatStatusLabel,\n specificationLifecycleStatusMap,\n type SpecificationLifecycleStatus,\n} from '../../../components/statusMaps'\n\ntype Specification = {\n id: string\n productId: string\n code: string\n name: string\n description: string | null\n specType: string\n isAssetizable: boolean\n lifecycleStatus: string\n version: number\n isActive: boolean\n createdAt: string\n}\n\nconst PAGE_SIZE = 50\n\nfunction buildFilterParams(values: FilterValues, params: URLSearchParams) {\n if (typeof values.lifecycleStatus === 'string' && values.lifecycleStatus) {\n params.set('lifecycleStatus', values.lifecycleStatus)\n }\n if (typeof values.specType === 'string' && values.specType) {\n params.set('specType', values.specType)\n }\n if (values.isActive === true) params.set('isActive', 'true')\n if (values.isActive === false) params.set('isActive', 'false')\n if (values.isAssetizable === true) params.set('isAssetizable', 'true')\n if (values.isAssetizable === false) params.set('isAssetizable', 'false')\n}\n\nexport default function SpecificationsListPage() {\n const t = useT()\n const router = useRouter()\n\n const data = useCpqListData<Specification>({\n endpoint: '/api/cpq/product-specifications',\n pageSize: PAGE_SIZE,\n buildFilterParams,\n loadErrorMessage: t('cpq.specifications.list.error.load', 'Failed to load specifications'),\n })\n\n const lifecycleOptions = React.useMemo(\n () => [\n { value: 'draft', label: t('cpq.specifications.lifecycle.draft', 'Draft') },\n { value: 'active', label: t('cpq.specifications.lifecycle.active', 'Active') },\n { value: 'deprecated', label: t('cpq.specifications.lifecycle.deprecated', 'Deprecated') },\n ],\n [t],\n )\n\n const specTypeOptions = React.useMemo(\n () => [\n { value: 'simple', label: t('cpq.specifications.type.simple', 'Simple') },\n { value: 'bundle', label: t('cpq.specifications.type.bundle', 'Bundle') },\n ],\n [t],\n )\n\n const filters = React.useMemo<FilterDef[]>(\n () => [\n {\n id: 'lifecycleStatus',\n label: t('cpq.specifications.filters.lifecycleStatus', 'Lifecycle Status'),\n type: 'select',\n options: lifecycleOptions,\n },\n {\n id: 'specType',\n label: t('cpq.specifications.filters.specType', 'Type'),\n type: 'select',\n options: specTypeOptions,\n },\n {\n id: 'isActive',\n label: t('cpq.specifications.filters.isActive', 'Active'),\n type: 'checkbox',\n },\n {\n id: 'isAssetizable',\n label: t('cpq.specifications.filters.isAssetizable', 'Assetizable'),\n type: 'checkbox',\n },\n ],\n [lifecycleOptions, specTypeOptions, t],\n )\n\n const columns = React.useMemo<ColumnDef<Specification>[]>(\n () => [\n {\n accessorKey: 'code',\n header: t('cpq.specifications.code', 'Code'),\n cell: ({ row }) => <span className=\"font-mono text-xs\">{row.original.code}</span>,\n },\n {\n accessorKey: 'name',\n header: t('cpq.specifications.name', 'Name'),\n cell: ({ row }) => (\n <span className=\"font-medium\">\n {row.original.name}\n {row.original.specType === 'bundle' && (\n <Tag variant=\"brand\" className=\"ml-2 px-2 text-[10px]\">\n bundle\n </Tag>\n )}\n {row.original.isAssetizable && (\n <Tag variant=\"warning\" className=\"ml-1 px-2 text-[10px]\">\n asset\n </Tag>\n )}\n </span>\n ),\n },\n {\n accessorKey: 'isActive',\n header: t('cpq.specifications.isActive', 'Is Active?'),\n cell: ({ row }) => <Checkbox checked={row.original.isActive} disabled />,\n },\n {\n accessorKey: 'lifecycleStatus',\n header: t('cpq.specifications.lifecycleStatus', 'Lifecycle Status'),\n cell: ({ row }) => (\n <Tag variant={specificationLifecycleStatusMap[row.original.lifecycleStatus as SpecificationLifecycleStatus] ?? 'neutral'} dot>\n {formatStatusLabel(row.original.lifecycleStatus)}\n </Tag>\n ),\n },\n {\n accessorKey: 'version',\n header: t('cpq.specifications.version', 'Version'),\n cell: ({ row }) => <span>v{row.original.version}</span>,\n },\n {\n accessorKey: 'description',\n header: t('cpq.specifications.description', 'Description'),\n cell: ({ row }) => (\n <span className=\"text-muted-foreground\">{row.original.description ?? '\u2014'}</span>\n ),\n meta: { truncate: true, maxWidth: 320 },\n },\n ],\n [t],\n )\n\n return (\n <CpqListView<Specification>\n title={t('cpq.specifications.list.title', 'Product Specifications')}\n tableId=\"cpq.specifications.list\"\n data={data}\n columns={columns}\n filters={filters}\n pageSize={PAGE_SIZE}\n searchPlaceholder={t('cpq.specifications.search.placeholder', 'Search specifications...')}\n actions={\n <Button asChild>\n <a href=\"/backend/cpq/specifications/new\">\n {t('cpq.specifications.add', 'New Specification')}\n </a>\n </Button>\n }\n crud={{\n endpoint: '/api/cpq/product-specifications',\n entityName: t('cpq.specifications.entityName', 'specification'),\n editHref: (row) => `/backend/cpq/specifications/${row.id}`,\n }}\n onRowClick={(row) => router.push(`/backend/cpq/specifications/${row.id}`)}\n emptyState={\n <div className=\"rounded-lg border bg-card p-6 text-center text-sm text-muted-foreground\">\n {t(\n 'cpq.specifications.empty',\n 'No product specifications found. Create one to define your product catalogue.',\n )}\n </div>\n }\n />\n )\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["\"use client\"\nimport * as React from 'react'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { useRouter } from 'next/navigation'\nimport type { LegacyColumnDef as ColumnDef } from '@tanstack/react-table/legacy'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { Checkbox } from '@open-mercato/ui/primitives/checkbox'\nimport { Tag } from '@open-mercato/ui/primitives/tag'\nimport type { FilterDef, FilterValues } from '@open-mercato/ui/backend/FilterBar'\nimport { CpqListView, useCpqListData } from '../../../components/CpqListView'\nimport {\n formatStatusLabel,\n specificationLifecycleStatusMap,\n type SpecificationLifecycleStatus,\n} from '../../../components/statusMaps'\n\ntype Specification = {\n id: string\n productId: string\n code: string\n name: string\n description: string | null\n specType: string\n isAssetizable: boolean\n lifecycleStatus: string\n version: number\n isActive: boolean\n createdAt: string\n}\n\nconst PAGE_SIZE = 50\n\nfunction buildFilterParams(values: FilterValues, params: URLSearchParams) {\n if (typeof values.lifecycleStatus === 'string' && values.lifecycleStatus) {\n params.set('lifecycleStatus', values.lifecycleStatus)\n }\n if (typeof values.specType === 'string' && values.specType) {\n params.set('specType', values.specType)\n }\n if (values.isActive === true) params.set('isActive', 'true')\n if (values.isActive === false) params.set('isActive', 'false')\n if (values.isAssetizable === true) params.set('isAssetizable', 'true')\n if (values.isAssetizable === false) params.set('isAssetizable', 'false')\n}\n\nexport default function SpecificationsListPage() {\n const t = useT()\n const router = useRouter()\n\n const data = useCpqListData<Specification>({\n endpoint: '/api/cpq/product-specifications',\n pageSize: PAGE_SIZE,\n buildFilterParams,\n loadErrorMessage: t('cpq.specifications.list.error.load', 'Failed to load specifications'),\n })\n\n const lifecycleOptions = React.useMemo(\n () => [\n { value: 'draft', label: t('cpq.specifications.lifecycle.draft', 'Draft') },\n { value: 'active', label: t('cpq.specifications.lifecycle.active', 'Active') },\n { value: 'deprecated', label: t('cpq.specifications.lifecycle.deprecated', 'Deprecated') },\n ],\n [t],\n )\n\n const specTypeOptions = React.useMemo(\n () => [\n { value: 'simple', label: t('cpq.specifications.type.simple', 'Simple') },\n { value: 'bundle', label: t('cpq.specifications.type.bundle', 'Bundle') },\n ],\n [t],\n )\n\n const filters = React.useMemo<FilterDef[]>(\n () => [\n {\n id: 'lifecycleStatus',\n label: t('cpq.specifications.filters.lifecycleStatus', 'Lifecycle Status'),\n type: 'select',\n options: lifecycleOptions,\n },\n {\n id: 'specType',\n label: t('cpq.specifications.filters.specType', 'Type'),\n type: 'select',\n options: specTypeOptions,\n },\n {\n id: 'isActive',\n label: t('cpq.specifications.filters.isActive', 'Active'),\n type: 'checkbox',\n },\n {\n id: 'isAssetizable',\n label: t('cpq.specifications.filters.isAssetizable', 'Assetizable'),\n type: 'checkbox',\n },\n ],\n [lifecycleOptions, specTypeOptions, t],\n )\n\n const columns = React.useMemo<ColumnDef<Specification>[]>(\n () => [\n {\n accessorKey: 'code',\n header: t('cpq.specifications.code', 'Code'),\n cell: ({ row }) => <span className=\"font-mono text-xs\">{row.original.code}</span>,\n },\n {\n accessorKey: 'name',\n header: t('cpq.specifications.name', 'Name'),\n cell: ({ row }) => (\n <span className=\"font-medium\">\n {row.original.name}\n {row.original.specType === 'bundle' && (\n <Tag variant=\"brand\" className=\"ml-2 px-2 text-[10px]\">\n {t('cpq.specifications.list.tag.bundle', 'bundle')}\n </Tag>\n )}\n {row.original.isAssetizable && (\n <Tag variant=\"warning\" className=\"ml-1 px-2 text-[10px]\">\n {t('cpq.specifications.list.tag.asset', 'asset')}\n </Tag>\n )}\n </span>\n ),\n },\n {\n accessorKey: 'isActive',\n header: t('cpq.specifications.isActive', 'Is Active?'),\n cell: ({ row }) => <Checkbox checked={row.original.isActive} disabled />,\n },\n {\n accessorKey: 'lifecycleStatus',\n header: t('cpq.specifications.lifecycleStatus', 'Lifecycle Status'),\n cell: ({ row }) => (\n <Tag variant={specificationLifecycleStatusMap[row.original.lifecycleStatus as SpecificationLifecycleStatus] ?? 'neutral'} dot>\n {formatStatusLabel(row.original.lifecycleStatus)}\n </Tag>\n ),\n },\n {\n accessorKey: 'version',\n header: t('cpq.specifications.version', 'Version'),\n cell: ({ row }) => <span>v{row.original.version}</span>,\n },\n {\n accessorKey: 'description',\n header: t('cpq.specifications.description', 'Description'),\n cell: ({ row }) => (\n <span className=\"text-muted-foreground\">{row.original.description ?? '\u2014'}</span>\n ),\n meta: { truncate: true, maxWidth: 320 },\n },\n ],\n [t],\n )\n\n return (\n <CpqListView<Specification>\n title={t('cpq.specifications.list.title', 'Product Specifications')}\n tableId=\"cpq.specifications.list\"\n data={data}\n columns={columns}\n filters={filters}\n pageSize={PAGE_SIZE}\n searchPlaceholder={t('cpq.specifications.search.placeholder', 'Search specifications...')}\n actions={\n <Button asChild>\n <a href=\"/backend/cpq/specifications/new\">\n {t('cpq.specifications.add', 'New Specification')}\n </a>\n </Button>\n }\n crud={{\n endpoint: '/api/cpq/product-specifications',\n entityName: t('cpq.specifications.entityName', 'specification'),\n editHref: (row) => `/backend/cpq/specifications/${row.id}`,\n }}\n onRowClick={(row) => router.push(`/backend/cpq/specifications/${row.id}`)}\n emptyState={\n <div className=\"rounded-lg border bg-card p-6 text-center text-sm text-muted-foreground\">\n {t(\n 'cpq.specifications.empty',\n 'No product specifications found. Create one to define your product catalogue.',\n )}\n </div>\n }\n />\n )\n}\n"],
5
+ "mappings": ";AA0G2B,cAMjB,YANiB;AAzG3B,YAAY,WAAW;AACvB,SAAS,YAAY;AACrB,SAAS,iBAAiB;AAE1B,SAAS,cAAc;AACvB,SAAS,gBAAgB;AACzB,SAAS,WAAW;AAEpB,SAAS,aAAa,sBAAsB;AAC5C;AAAA,EACE;AAAA,EACA;AAAA,OAEK;AAgBP,MAAM,YAAY;AAElB,SAAS,kBAAkB,QAAsB,QAAyB;AACxE,MAAI,OAAO,OAAO,oBAAoB,YAAY,OAAO,iBAAiB;AACxE,WAAO,IAAI,mBAAmB,OAAO,eAAe;AAAA,EACtD;AACA,MAAI,OAAO,OAAO,aAAa,YAAY,OAAO,UAAU;AAC1D,WAAO,IAAI,YAAY,OAAO,QAAQ;AAAA,EACxC;AACA,MAAI,OAAO,aAAa,KAAM,QAAO,IAAI,YAAY,MAAM;AAC3D,MAAI,OAAO,aAAa,MAAO,QAAO,IAAI,YAAY,OAAO;AAC7D,MAAI,OAAO,kBAAkB,KAAM,QAAO,IAAI,iBAAiB,MAAM;AACrE,MAAI,OAAO,kBAAkB,MAAO,QAAO,IAAI,iBAAiB,OAAO;AACzE;AAEe,SAAR,yBAA0C;AAC/C,QAAM,IAAI,KAAK;AACf,QAAM,SAAS,UAAU;AAEzB,QAAM,OAAO,eAA8B;AAAA,IACzC,UAAU;AAAA,IACV,UAAU;AAAA,IACV;AAAA,IACA,kBAAkB,EAAE,sCAAsC,+BAA+B;AAAA,EAC3F,CAAC;AAED,QAAM,mBAAmB,MAAM;AAAA,IAC7B,MAAM;AAAA,MACJ,EAAE,OAAO,SAAS,OAAO,EAAE,sCAAsC,OAAO,EAAE;AAAA,MAC1E,EAAE,OAAO,UAAU,OAAO,EAAE,uCAAuC,QAAQ,EAAE;AAAA,MAC7E,EAAE,OAAO,cAAc,OAAO,EAAE,2CAA2C,YAAY,EAAE;AAAA,IAC3F;AAAA,IACA,CAAC,CAAC;AAAA,EACJ;AAEA,QAAM,kBAAkB,MAAM;AAAA,IAC5B,MAAM;AAAA,MACJ,EAAE,OAAO,UAAU,OAAO,EAAE,kCAAkC,QAAQ,EAAE;AAAA,MACxE,EAAE,OAAO,UAAU,OAAO,EAAE,kCAAkC,QAAQ,EAAE;AAAA,IAC1E;AAAA,IACA,CAAC,CAAC;AAAA,EACJ;AAEA,QAAM,UAAU,MAAM;AAAA,IACpB,MAAM;AAAA,MACJ;AAAA,QACE,IAAI;AAAA,QACJ,OAAO,EAAE,8CAA8C,kBAAkB;AAAA,QACzE,MAAM;AAAA,QACN,SAAS;AAAA,MACX;AAAA,MACA;AAAA,QACE,IAAI;AAAA,QACJ,OAAO,EAAE,uCAAuC,MAAM;AAAA,QACtD,MAAM;AAAA,QACN,SAAS;AAAA,MACX;AAAA,MACA;AAAA,QACE,IAAI;AAAA,QACJ,OAAO,EAAE,uCAAuC,QAAQ;AAAA,QACxD,MAAM;AAAA,MACR;AAAA,MACA;AAAA,QACE,IAAI;AAAA,QACJ,OAAO,EAAE,4CAA4C,aAAa;AAAA,QAClE,MAAM;AAAA,MACR;AAAA,IACF;AAAA,IACA,CAAC,kBAAkB,iBAAiB,CAAC;AAAA,EACvC;AAEA,QAAM,UAAU,MAAM;AAAA,IACpB,MAAM;AAAA,MACJ;AAAA,QACE,aAAa;AAAA,QACb,QAAQ,EAAE,2BAA2B,MAAM;AAAA,QAC3C,MAAM,CAAC,EAAE,IAAI,MAAM,oBAAC,UAAK,WAAU,qBAAqB,cAAI,SAAS,MAAK;AAAA,MAC5E;AAAA,MACA;AAAA,QACE,aAAa;AAAA,QACb,QAAQ,EAAE,2BAA2B,MAAM;AAAA,QAC3C,MAAM,CAAC,EAAE,IAAI,MACX,qBAAC,UAAK,WAAU,eACb;AAAA,cAAI,SAAS;AAAA,UACb,IAAI,SAAS,aAAa,YACzB,oBAAC,OAAI,SAAQ,SAAQ,WAAU,yBAC5B,YAAE,sCAAsC,QAAQ,GACnD;AAAA,UAED,IAAI,SAAS,iBACZ,oBAAC,OAAI,SAAQ,WAAU,WAAU,yBAC9B,YAAE,qCAAqC,OAAO,GACjD;AAAA,WAEJ;AAAA,MAEJ;AAAA,MACA;AAAA,QACE,aAAa;AAAA,QACb,QAAQ,EAAE,+BAA+B,YAAY;AAAA,QACrD,MAAM,CAAC,EAAE,IAAI,MAAM,oBAAC,YAAS,SAAS,IAAI,SAAS,UAAU,UAAQ,MAAC;AAAA,MACxE;AAAA,MACA;AAAA,QACE,aAAa;AAAA,QACb,QAAQ,EAAE,sCAAsC,kBAAkB;AAAA,QAClE,MAAM,CAAC,EAAE,IAAI,MACX,oBAAC,OAAI,SAAS,gCAAgC,IAAI,SAAS,eAA+C,KAAK,WAAW,KAAG,MAC1H,4BAAkB,IAAI,SAAS,eAAe,GACjD;AAAA,MAEJ;AAAA,MACA;AAAA,QACE,aAAa;AAAA,QACb,QAAQ,EAAE,8BAA8B,SAAS;AAAA,QACjD,MAAM,CAAC,EAAE,IAAI,MAAM,qBAAC,UAAK;AAAA;AAAA,UAAE,IAAI,SAAS;AAAA,WAAQ;AAAA,MAClD;AAAA,MACA;AAAA,QACE,aAAa;AAAA,QACb,QAAQ,EAAE,kCAAkC,aAAa;AAAA,QACzD,MAAM,CAAC,EAAE,IAAI,MACX,oBAAC,UAAK,WAAU,yBAAyB,cAAI,SAAS,eAAe,UAAI;AAAA,QAE3E,MAAM,EAAE,UAAU,MAAM,UAAU,IAAI;AAAA,MACxC;AAAA,IACF;AAAA,IACA,CAAC,CAAC;AAAA,EACJ;AAEA,SACE;AAAA,IAAC;AAAA;AAAA,MACC,OAAO,EAAE,iCAAiC,wBAAwB;AAAA,MAClE,SAAQ;AAAA,MACR;AAAA,MACA;AAAA,MACA;AAAA,MACA,UAAU;AAAA,MACV,mBAAmB,EAAE,yCAAyC,0BAA0B;AAAA,MACxF,SACE,oBAAC,UAAO,SAAO,MACb,8BAAC,OAAE,MAAK,mCACL,YAAE,0BAA0B,mBAAmB,GAClD,GACF;AAAA,MAEF,MAAM;AAAA,QACJ,UAAU;AAAA,QACV,YAAY,EAAE,iCAAiC,eAAe;AAAA,QAC9D,UAAU,CAAC,QAAQ,+BAA+B,IAAI,EAAE;AAAA,MAC1D;AAAA,MACA,YAAY,CAAC,QAAQ,OAAO,KAAK,+BAA+B,IAAI,EAAE,EAAE;AAAA,MACxE,YACE,oBAAC,SAAI,WAAU,2EACZ;AAAA,QACC;AAAA,QACA;AAAA,MACF,GACF;AAAA;AAAA,EAEJ;AAEJ;",
6
6
  "names": []
7
7
  }
@@ -3,11 +3,12 @@ import { jsx, jsxs } from "react/jsx-runtime";
3
3
  import * as React from "react";
4
4
  import { useRouter } from "next/navigation";
5
5
  import { Alert } from "@open-mercato/ui/primitives/alert";
6
+ import { useT } from "@open-mercato/shared/lib/i18n/context";
6
7
  import { RowActions } from "@open-mercato/ui/backend/RowActions";
7
8
  import { Tag } from "@open-mercato/ui/primitives/tag";
8
- async function apiJson(url) {
9
+ async function apiJson(url, t) {
9
10
  const res = await fetch(url);
10
- if (!res.ok) throw new Error(`API error ${res.status}`);
11
+ if (!res.ok) throw new Error(t("cpq.wizards.runner.errors.api", "API error {status}", { status: res.status }));
11
12
  return res.json();
12
13
  }
13
14
  function Badge({ children, variant = "default" }) {
@@ -27,10 +28,12 @@ function KV({ label, children }) {
27
28
  ] });
28
29
  }
29
30
  function JsonBlock({ data }) {
30
- if (data == null) return /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: "none" });
31
+ const t = useT();
32
+ if (data == null) return /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: t("cpq.wizards.detail.none", "none") });
31
33
  return /* @__PURE__ */ jsx("pre", { className: "rounded-md bg-muted/50 p-3 text-xs overflow-x-auto max-h-48", children: JSON.stringify(data, null, 2) });
32
34
  }
33
- function TransitionRow({ t, index }) {
35
+ function TransitionRow({ transition, index }) {
36
+ const t = useT();
34
37
  return /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-3 text-xs", children: [
35
38
  /* @__PURE__ */ jsxs("span", { className: "font-mono text-muted-foreground w-4 shrink-0", children: [
36
39
  index + 1,
@@ -39,27 +42,29 @@ function TransitionRow({ t, index }) {
39
42
  /* @__PURE__ */ jsxs("div", { className: "space-y-0.5", children: [
40
43
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
41
44
  /* @__PURE__ */ jsxs("span", { className: "font-medium", children: [
42
- "-> ",
43
- t.targetStepId
45
+ "->",
46
+ " ",
47
+ transition.targetStepId
44
48
  ] }),
45
- t.isDefault && /* @__PURE__ */ jsx(Badge, { variant: "muted", children: "default" }),
46
- t.label && /* @__PURE__ */ jsxs("span", { className: "text-muted-foreground", children: [
49
+ transition.isDefault && /* @__PURE__ */ jsx(Badge, { variant: "muted", children: t("cpq.wizards.detail.transitionDefault", "default") }),
50
+ transition.label && /* @__PURE__ */ jsxs("span", { className: "text-muted-foreground", children: [
47
51
  "(",
48
- t.label,
52
+ transition.label,
49
53
  ")"
50
54
  ] })
51
55
  ] }),
52
- t.condition && /* @__PURE__ */ jsxs("div", { className: "font-mono text-muted-foreground", children: [
53
- "when ",
54
- t.condition.field,
55
- " ",
56
- t.condition.operator,
57
- t.condition.value !== void 0 ? ` ${JSON.stringify(t.condition.value)}` : ""
56
+ transition.condition && /* @__PURE__ */ jsxs("div", { className: "font-mono text-muted-foreground", children: [
57
+ t("cpq.wizards.detail.transitionWhen", "when {field} {operator}", {
58
+ field: transition.condition.field,
59
+ operator: transition.condition.operator
60
+ }),
61
+ transition.condition.value !== void 0 ? ` ${JSON.stringify(transition.condition.value)}` : ""
58
62
  ] })
59
63
  ] })
60
64
  ] });
61
65
  }
62
66
  function StepCard({ step, index }) {
67
+ const t = useT();
63
68
  const [open, setOpen] = React.useState(false);
64
69
  const configKeys = Object.keys(step.config);
65
70
  return /* @__PURE__ */ jsxs("div", { className: "rounded-lg border", children: [
@@ -75,7 +80,7 @@ function StepCard({ step, index }) {
75
80
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
76
81
  /* @__PURE__ */ jsx("span", { className: "text-sm font-medium truncate", children: step.title }),
77
82
  /* @__PURE__ */ jsx(Badge, { children: step.type }),
78
- step.isOptional && /* @__PURE__ */ jsx(Badge, { variant: "muted", children: "optional" })
83
+ step.isOptional && /* @__PURE__ */ jsx(Badge, { variant: "muted", children: t("cpq.wizards.detail.optional", "optional") })
79
84
  ] }),
80
85
  step.description && /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground truncate mt-0.5", children: step.description })
81
86
  ] }),
@@ -85,41 +90,39 @@ function StepCard({ step, index }) {
85
90
  ),
86
91
  open && /* @__PURE__ */ jsxs("div", { className: "border-t px-4 py-3 space-y-4", children: [
87
92
  /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-4", children: [
88
- /* @__PURE__ */ jsx(KV, { label: "Step ID", children: /* @__PURE__ */ jsx("span", { className: "font-mono text-xs", children: step.stepId }) }),
89
- /* @__PURE__ */ jsx(KV, { label: "Type", children: /* @__PURE__ */ jsx("span", { className: "font-mono text-xs", children: step.type }) })
93
+ /* @__PURE__ */ jsx(KV, { label: t("cpq.wizards.detail.stepId", "Step ID"), children: /* @__PURE__ */ jsx("span", { className: "font-mono text-xs", children: step.stepId }) }),
94
+ /* @__PURE__ */ jsx(KV, { label: t("cpq.wizards.detail.type", "Type"), children: /* @__PURE__ */ jsx("span", { className: "font-mono text-xs", children: step.type }) })
90
95
  ] }),
91
96
  configKeys.length > 0 && /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
92
- /* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-muted-foreground", children: "Config" }),
97
+ /* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-muted-foreground", children: t("cpq.wizards.detail.config", "Config") }),
93
98
  /* @__PURE__ */ jsx(JsonBlock, { data: step.config })
94
99
  ] }),
95
100
  step.transitions.length > 0 && /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
96
- /* @__PURE__ */ jsxs("span", { className: "text-xs font-medium text-muted-foreground", children: [
97
- "Transitions (",
98
- step.transitions.length,
99
- ")"
100
- ] }),
101
- /* @__PURE__ */ jsx("div", { className: "space-y-1.5", children: step.transitions.map((t, i) => /* @__PURE__ */ jsx(TransitionRow, { t, index: i }, `${t.targetStepId}-${i}`)) })
101
+ /* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-muted-foreground", children: t("cpq.wizards.detail.transitions", "Transitions ({count})", { count: step.transitions.length }) }),
102
+ /* @__PURE__ */ jsx("div", { className: "space-y-1.5", children: step.transitions.map((transition, i) => /* @__PURE__ */ jsx(TransitionRow, { transition, index: i }, `${transition.targetStepId}-${i}`)) })
102
103
  ] }),
103
- step.transitions.length === 0 && /* @__PURE__ */ jsx("div", { className: "text-xs text-muted-foreground", children: "No transitions (terminal step)" }),
104
+ step.transitions.length === 0 && /* @__PURE__ */ jsx("div", { className: "text-xs text-muted-foreground", children: t("cpq.wizards.detail.noTransitions", "No transitions (terminal step)") }),
104
105
  step.validationRules && step.validationRules.length > 0 && /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
105
- /* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-muted-foreground", children: "Validation Rules" }),
106
+ /* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-muted-foreground", children: t("cpq.wizards.detail.validationRules", "Validation Rules") }),
106
107
  /* @__PURE__ */ jsx(JsonBlock, { data: step.validationRules })
107
108
  ] })
108
109
  ] })
109
110
  ] });
110
111
  }
111
112
  function ApplicabilityPanel({ applicability }) {
113
+ const t = useT();
112
114
  if (!applicability) {
113
- return /* @__PURE__ */ jsx("span", { className: "text-sm text-muted-foreground", children: "No applicability constraints" });
115
+ return /* @__PURE__ */ jsx("span", { className: "text-sm text-muted-foreground", children: t("cpq.wizards.detail.noApplicability", "No applicability constraints") });
114
116
  }
115
117
  return /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-4", children: [
116
- applicability.priority != null && /* @__PURE__ */ jsx(KV, { label: "Priority", children: applicability.priority }),
117
- applicability.specCodes?.length ? /* @__PURE__ */ jsx(KV, { label: "Spec Codes", children: /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-1", children: applicability.specCodes.map((c) => /* @__PURE__ */ jsx("span", { className: "font-mono text-xs rounded bg-muted px-1.5 py-0.5", children: c }, c)) }) }) : null,
118
- applicability.offeringCodes?.length ? /* @__PURE__ */ jsx(KV, { label: "Offering Codes", children: /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-1", children: applicability.offeringCodes.map((c) => /* @__PURE__ */ jsx("span", { className: "font-mono text-xs rounded bg-muted px-1.5 py-0.5", children: c }, c)) }) }) : null,
119
- applicability.customerSegments?.length ? /* @__PURE__ */ jsx(KV, { label: "Customer Segments", children: /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-1", children: applicability.customerSegments.map((c) => /* @__PURE__ */ jsx("span", { className: "font-mono text-xs rounded bg-muted px-1.5 py-0.5", children: c }, c)) }) }) : null
118
+ applicability.priority != null && /* @__PURE__ */ jsx(KV, { label: t("cpq.wizards.detail.priority", "Priority"), children: applicability.priority }),
119
+ applicability.specCodes?.length ? /* @__PURE__ */ jsx(KV, { label: t("cpq.wizards.detail.specCodes", "Spec Codes"), children: /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-1", children: applicability.specCodes.map((c) => /* @__PURE__ */ jsx("span", { className: "font-mono text-xs rounded bg-muted px-1.5 py-0.5", children: c }, c)) }) }) : null,
120
+ applicability.offeringCodes?.length ? /* @__PURE__ */ jsx(KV, { label: t("cpq.wizards.detail.offeringCodes", "Offering Codes"), children: /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-1", children: applicability.offeringCodes.map((c) => /* @__PURE__ */ jsx("span", { className: "font-mono text-xs rounded bg-muted px-1.5 py-0.5", children: c }, c)) }) }) : null,
121
+ applicability.customerSegments?.length ? /* @__PURE__ */ jsx(KV, { label: t("cpq.wizards.detail.customerSegments", "Customer Segments"), children: /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-1", children: applicability.customerSegments.map((c) => /* @__PURE__ */ jsx("span", { className: "font-mono text-xs rounded bg-muted px-1.5 py-0.5", children: c }, c)) }) }) : null
120
122
  ] });
121
123
  }
122
124
  function CpqWizardDetailPage({ params }) {
125
+ const t = useT();
123
126
  const router = useRouter();
124
127
  const definitionCode = params.definitionCode;
125
128
  const [definition, setDefinition] = React.useState(null);
@@ -132,37 +135,44 @@ function CpqWizardDetailPage({ params }) {
132
135
  setError(null);
133
136
  try {
134
137
  const def = await apiJson(
135
- `/api/cpq/wizards?code=${encodeURIComponent(definitionCode)}`
138
+ `/api/cpq/wizards?code=${encodeURIComponent(definitionCode)}`,
139
+ t
136
140
  );
137
141
  setDefinition(def);
138
142
  } catch (err) {
139
- setError(err instanceof Error ? err.message : "Failed to load wizard");
143
+ setError(err instanceof Error ? err.message : t("cpq.wizards.runner.errors.load", "Failed to load wizard"));
140
144
  } finally {
141
145
  setLoading(false);
142
146
  }
143
147
  }
144
148
  load();
145
- }, [definitionCode]);
149
+ }, [definitionCode, t]);
146
150
  if (loading) {
147
- return /* @__PURE__ */ jsx("div", { className: "text-sm text-muted-foreground", children: "Loading..." });
151
+ return /* @__PURE__ */ jsx("div", { className: "text-sm text-muted-foreground", children: t("cpq.common.loading", "Loading...") });
148
152
  }
149
153
  if (error) {
150
154
  return /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
151
155
  /* @__PURE__ */ jsx(Alert, { variant: "destructive", children: error }),
152
- /* @__PURE__ */ jsx("button", { type: "button", onClick: () => router.push("/backend/cpq/wizards"), className: "text-sm text-muted-foreground hover:text-foreground", children: "\u2190 Back to Wizards" })
156
+ /* @__PURE__ */ jsxs("button", { type: "button", onClick: () => router.push("/backend/cpq/wizards"), className: "text-sm text-muted-foreground hover:text-foreground", children: [
157
+ "\u2190 ",
158
+ t("cpq.wizards.runner.backToList", "Back to Wizards")
159
+ ] })
153
160
  ] });
154
161
  }
155
162
  if (!definition) {
156
- return /* @__PURE__ */ jsx("div", { className: "rounded-lg border bg-card p-6 text-center text-sm text-muted-foreground", children: "Wizard not found." });
163
+ return /* @__PURE__ */ jsx("div", { className: "rounded-lg border bg-card p-6 text-center text-sm text-muted-foreground", children: t("cpq.wizards.runner.notFound", "Wizard not found.") });
157
164
  }
158
165
  return /* @__PURE__ */ jsxs("div", { className: "space-y-6 max-w-[900px] mx-auto", children: [
159
- /* @__PURE__ */ jsx("div", { className: "flex items-center gap-3", children: /* @__PURE__ */ jsx(
166
+ /* @__PURE__ */ jsx("div", { className: "flex items-center gap-3", children: /* @__PURE__ */ jsxs(
160
167
  "button",
161
168
  {
162
169
  type: "button",
163
170
  onClick: () => router.push("/backend/cpq/wizards"),
164
171
  className: "text-sm text-muted-foreground hover:text-foreground",
165
- children: "\u2190 All Wizards"
172
+ children: [
173
+ "\u2190 ",
174
+ t("cpq.wizards.runner.allWizards", "All Wizards")
175
+ ]
166
176
  }
167
177
  ) }),
168
178
  /* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between gap-4", children: [
@@ -176,26 +186,26 @@ function CpqWizardDetailPage({ params }) {
176
186
  items: [
177
187
  {
178
188
  id: "preview",
179
- label: "Preview",
189
+ label: t("cpq.wizards.actions.preview", "Preview"),
180
190
  onSelect: () => router.push(`/backend/cpq/wizards/${definitionCode}`)
181
191
  }
182
192
  ]
183
193
  }
184
194
  ) })
185
195
  ] }),
186
- /* @__PURE__ */ jsx(Section, { title: "General", children: /* @__PURE__ */ jsx("div", { className: "rounded-lg border p-4", children: /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 sm:grid-cols-4 gap-4", children: [
187
- /* @__PURE__ */ jsx(KV, { label: "Code", children: /* @__PURE__ */ jsx("span", { className: "font-mono text-xs", children: definition.code }) }),
188
- /* @__PURE__ */ jsxs(KV, { label: "Version", children: [
196
+ /* @__PURE__ */ jsx(Section, { title: t("cpq.wizards.detail.sections.general", "General"), children: /* @__PURE__ */ jsx("div", { className: "rounded-lg border p-4", children: /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 sm:grid-cols-4 gap-4", children: [
197
+ /* @__PURE__ */ jsx(KV, { label: t("cpq.wizards.detail.code", "Code"), children: /* @__PURE__ */ jsx("span", { className: "font-mono text-xs", children: definition.code }) }),
198
+ /* @__PURE__ */ jsxs(KV, { label: t("cpq.wizards.detail.version", "Version"), children: [
189
199
  "v",
190
200
  definition.version
191
201
  ] }),
192
- /* @__PURE__ */ jsx(KV, { label: "Surface", children: definition.surface }),
193
- /* @__PURE__ */ jsx(KV, { label: "Active", children: /* @__PURE__ */ jsx(Badge, { variant: definition.isActive ? "success" : "muted", children: definition.isActive ? "Yes" : "No" }) })
202
+ /* @__PURE__ */ jsx(KV, { label: t("cpq.wizards.detail.surface", "Surface"), children: definition.surface }),
203
+ /* @__PURE__ */ jsx(KV, { label: t("cpq.wizards.detail.active", "Active"), children: /* @__PURE__ */ jsx(Badge, { variant: definition.isActive ? "success" : "muted", children: definition.isActive ? t("cpq.common.yes", "Yes") : t("cpq.common.no", "No") }) })
194
204
  ] }) }) }),
195
- /* @__PURE__ */ jsx(Section, { title: "Applicability", children: /* @__PURE__ */ jsx("div", { className: "rounded-lg border p-4", children: /* @__PURE__ */ jsx(ApplicabilityPanel, { applicability: definition.applicability }) }) }),
196
- definition.paramsSchema && Object.keys(definition.paramsSchema).length > 0 && /* @__PURE__ */ jsx(Section, { title: "Parameters Schema", children: /* @__PURE__ */ jsx(JsonBlock, { data: definition.paramsSchema }) }),
197
- /* @__PURE__ */ jsx(Section, { title: `Steps (${definition.steps.length})`, children: /* @__PURE__ */ jsx("div", { className: "space-y-2", children: definition.steps.map((step, i) => /* @__PURE__ */ jsx(StepCard, { step, index: i }, step.stepId)) }) }),
198
- definition.metadata && Object.keys(definition.metadata).length > 0 && /* @__PURE__ */ jsx(Section, { title: "Metadata", children: /* @__PURE__ */ jsx(JsonBlock, { data: definition.metadata }) })
205
+ /* @__PURE__ */ jsx(Section, { title: t("cpq.wizards.detail.sections.applicability", "Applicability"), children: /* @__PURE__ */ jsx("div", { className: "rounded-lg border p-4", children: /* @__PURE__ */ jsx(ApplicabilityPanel, { applicability: definition.applicability }) }) }),
206
+ definition.paramsSchema && Object.keys(definition.paramsSchema).length > 0 && /* @__PURE__ */ jsx(Section, { title: t("cpq.wizards.detail.sections.paramsSchema", "Parameters Schema"), children: /* @__PURE__ */ jsx(JsonBlock, { data: definition.paramsSchema }) }),
207
+ /* @__PURE__ */ jsx(Section, { title: t("cpq.wizards.detail.sections.steps", "Steps ({count})", { count: definition.steps.length }), children: /* @__PURE__ */ jsx("div", { className: "space-y-2", children: definition.steps.map((step, i) => /* @__PURE__ */ jsx(StepCard, { step, index: i }, step.stepId)) }) }),
208
+ definition.metadata && Object.keys(definition.metadata).length > 0 && /* @__PURE__ */ jsx(Section, { title: t("cpq.wizards.detail.sections.metadata", "Metadata"), children: /* @__PURE__ */ jsx(JsonBlock, { data: definition.metadata }) })
199
209
  ] });
200
210
  }
201
211
  export {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../../../../src/modules/cpq/backend/cpq/wizards/%5BdefinitionCode%5D/detail/page.tsx"],
4
- "sourcesContent": ["\"use client\"\nimport * as React from 'react'\nimport { useRouter } from 'next/navigation'\nimport { Alert } from '@open-mercato/ui/primitives/alert'\nimport { RowActions } from '@open-mercato/ui/backend/RowActions'\nimport { Tag } from '@open-mercato/ui/primitives/tag'\nimport type {\n WizardDefinitionResult,\n WizardStepDefinition,\n WizardTransition,\n WizardApplicability,\n} from '../../../../../workflows/types'\n\nasync function apiJson<T>(url: string): Promise<T> {\n const res = await fetch(url)\n if (!res.ok) throw new Error(`API error ${res.status}`)\n return res.json() as Promise<T>\n}\n\n// \u2500\u2500\u2500 Sub-components \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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 Badge({ children, variant = 'default' }: { children: React.ReactNode; variant?: 'default' | 'success' | 'muted' }) {\n const tagVariant = variant === 'success' ? 'success' : variant === 'muted' ? 'neutral' : 'info'\n return <Tag variant={tagVariant}>{children}</Tag>\n}\n\nfunction Section({ title, children }: { title: string; children: React.ReactNode }) {\n return (\n <div className=\"space-y-3\">\n <h2 className=\"text-base font-semibold\">{title}</h2>\n {children}\n </div>\n )\n}\n\nfunction KV({ label, children }: { label: string; children: React.ReactNode }) {\n return (\n <div className=\"flex flex-col gap-0.5\">\n <span className=\"text-xs font-medium text-muted-foreground\">{label}</span>\n <span className=\"text-sm\">{children}</span>\n </div>\n )\n}\n\nfunction JsonBlock({ data }: { data: unknown }) {\n if (data == null) return <span className=\"text-xs text-muted-foreground\">none</span>\n return (\n <pre className=\"rounded-md bg-muted/50 p-3 text-xs overflow-x-auto max-h-48\">\n {JSON.stringify(data, null, 2)}\n </pre>\n )\n}\n\nfunction TransitionRow({ t, index }: { t: WizardTransition; index: number }) {\n return (\n <div className=\"flex items-start gap-3 text-xs\">\n <span className=\"font-mono text-muted-foreground w-4 shrink-0\">{index + 1}.</span>\n <div className=\"space-y-0.5\">\n <div className=\"flex items-center gap-2\">\n <span className=\"font-medium\">-&gt; {t.targetStepId}</span>\n {t.isDefault && <Badge variant=\"muted\">default</Badge>}\n {t.label && <span className=\"text-muted-foreground\">({t.label})</span>}\n </div>\n {t.condition && (\n <div className=\"font-mono text-muted-foreground\">\n when {t.condition.field} {t.condition.operator}\n {t.condition.value !== undefined ? ` ${JSON.stringify(t.condition.value)}` : ''}\n </div>\n )}\n </div>\n </div>\n )\n}\n\nfunction StepCard({ step, index }: { step: WizardStepDefinition; index: number }) {\n const [open, setOpen] = React.useState(false)\n const configKeys = Object.keys(step.config)\n\n return (\n <div className=\"rounded-lg border\">\n <button\n type=\"button\"\n onClick={() => setOpen((v) => !v)}\n className=\"w-full flex items-center gap-3 px-4 py-3 text-left hover:bg-muted/30 transition-colors\"\n >\n <span className=\"flex items-center justify-center rounded-full bg-primary/10 text-primary text-xs font-bold w-7 h-7 shrink-0\">\n {index + 1}\n </span>\n <div className=\"flex-1 min-w-0\">\n <div className=\"flex items-center gap-2\">\n <span className=\"text-sm font-medium truncate\">{step.title}</span>\n <Badge>{step.type}</Badge>\n {step.isOptional && <Badge variant=\"muted\">optional</Badge>}\n </div>\n {step.description && (\n <p className=\"text-xs text-muted-foreground truncate mt-0.5\">{step.description}</p>\n )}\n </div>\n <span className=\"text-xs text-muted-foreground shrink-0\">{open ? '\\u25B2' : '\\u25BC'}</span>\n </button>\n\n {open && (\n <div className=\"border-t px-4 py-3 space-y-4\">\n <div className=\"grid grid-cols-2 gap-4\">\n <KV label=\"Step ID\"><span className=\"font-mono text-xs\">{step.stepId}</span></KV>\n <KV label=\"Type\"><span className=\"font-mono text-xs\">{step.type}</span></KV>\n </div>\n\n {configKeys.length > 0 && (\n <div className=\"space-y-1\">\n <span className=\"text-xs font-medium text-muted-foreground\">Config</span>\n <JsonBlock data={step.config} />\n </div>\n )}\n\n {step.transitions.length > 0 && (\n <div className=\"space-y-2\">\n <span className=\"text-xs font-medium text-muted-foreground\">\n Transitions ({step.transitions.length})\n </span>\n <div className=\"space-y-1.5\">\n {step.transitions.map((t, i) => (\n <TransitionRow key={`${t.targetStepId}-${i}`} t={t} index={i} />\n ))}\n </div>\n </div>\n )}\n\n {step.transitions.length === 0 && (\n <div className=\"text-xs text-muted-foreground\">No transitions (terminal step)</div>\n )}\n\n {step.validationRules && step.validationRules.length > 0 && (\n <div className=\"space-y-1\">\n <span className=\"text-xs font-medium text-muted-foreground\">Validation Rules</span>\n <JsonBlock data={step.validationRules} />\n </div>\n )}\n </div>\n )}\n </div>\n )\n}\n\nfunction ApplicabilityPanel({ applicability }: { applicability: WizardApplicability | null }) {\n if (!applicability) {\n return <span className=\"text-sm text-muted-foreground\">No applicability constraints</span>\n }\n return (\n <div className=\"grid grid-cols-2 gap-4\">\n {applicability.priority != null && (\n <KV label=\"Priority\">{applicability.priority}</KV>\n )}\n {applicability.specCodes?.length ? (\n <KV label=\"Spec Codes\">\n <div className=\"flex flex-wrap gap-1\">\n {applicability.specCodes.map((c) => (\n <span key={c} className=\"font-mono text-xs rounded bg-muted px-1.5 py-0.5\">{c}</span>\n ))}\n </div>\n </KV>\n ) : null}\n {applicability.offeringCodes?.length ? (\n <KV label=\"Offering Codes\">\n <div className=\"flex flex-wrap gap-1\">\n {applicability.offeringCodes.map((c) => (\n <span key={c} className=\"font-mono text-xs rounded bg-muted px-1.5 py-0.5\">{c}</span>\n ))}\n </div>\n </KV>\n ) : null}\n {applicability.customerSegments?.length ? (\n <KV label=\"Customer Segments\">\n <div className=\"flex flex-wrap gap-1\">\n {applicability.customerSegments.map((c) => (\n <span key={c} className=\"font-mono text-xs rounded bg-muted px-1.5 py-0.5\">{c}</span>\n ))}\n </div>\n </KV>\n ) : null}\n </div>\n )\n}\n\n// \u2500\u2500\u2500 Main Page \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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 CpqWizardDetailPage({ params }: { params: Record<string, string | string[]> }) {\n const router = useRouter()\n const definitionCode = params.definitionCode as string\n\n const [definition, setDefinition] = React.useState<WizardDefinitionResult | null>(null)\n const [loading, setLoading] = React.useState(true)\n const [error, setError] = React.useState<string | null>(null)\n\n React.useEffect(() => {\n async function load() {\n if (!definitionCode) return\n setLoading(true)\n setError(null)\n try {\n const def = await apiJson<WizardDefinitionResult>(\n `/api/cpq/wizards?code=${encodeURIComponent(definitionCode)}`,\n )\n setDefinition(def)\n } catch (err) {\n setError(err instanceof Error ? err.message : 'Failed to load wizard')\n } finally {\n setLoading(false)\n }\n }\n load()\n }, [definitionCode])\n\n if (loading) {\n return <div className=\"text-sm text-muted-foreground\">Loading...</div>\n }\n\n if (error) {\n return (\n <div className=\"space-y-4\">\n <Alert variant=\"destructive\">{error}</Alert>\n <button type=\"button\" onClick={() => router.push('/backend/cpq/wizards')} className=\"text-sm text-muted-foreground hover:text-foreground\">\n &larr; Back to Wizards\n </button>\n </div>\n )\n }\n\n if (!definition) {\n return (\n <div className=\"rounded-lg border bg-card p-6 text-center text-sm text-muted-foreground\">\n Wizard not found.\n </div>\n )\n }\n\n return (\n <div className=\"space-y-6 max-w-[900px] mx-auto\">\n {/* Header */}\n <div className=\"flex items-center gap-3\">\n <button\n type=\"button\"\n onClick={() => router.push('/backend/cpq/wizards')}\n className=\"text-sm text-muted-foreground hover:text-foreground\"\n >\n &larr; All Wizards\n </button>\n </div>\n\n <div className=\"flex items-start justify-between gap-4\">\n <div>\n <h1 className=\"text-2xl font-bold\">{definition.name}</h1>\n {definition.description && (\n <p className=\"text-sm text-muted-foreground mt-1\">{definition.description}</p>\n )}\n </div>\n {/* Actions live in a 3-dot menu \u2014 wizards are read-only in admin UI\n for the time being, so only `Preview` is exposed. */}\n <div className=\"shrink-0\">\n <RowActions\n items={[\n {\n id: 'preview',\n label: 'Preview',\n onSelect: () => router.push(`/backend/cpq/wizards/${definitionCode}`),\n },\n ]}\n />\n </div>\n </div>\n\n {/* General Info */}\n <Section title=\"General\">\n <div className=\"rounded-lg border p-4\">\n <div className=\"grid grid-cols-2 sm:grid-cols-4 gap-4\">\n <KV label=\"Code\"><span className=\"font-mono text-xs\">{definition.code}</span></KV>\n <KV label=\"Version\">v{definition.version}</KV>\n <KV label=\"Surface\">{definition.surface}</KV>\n <KV label=\"Active\">\n <Badge variant={definition.isActive ? 'success' : 'muted'}>\n {definition.isActive ? 'Yes' : 'No'}\n </Badge>\n </KV>\n </div>\n </div>\n </Section>\n\n {/* Applicability */}\n <Section title=\"Applicability\">\n <div className=\"rounded-lg border p-4\">\n <ApplicabilityPanel applicability={definition.applicability} />\n </div>\n </Section>\n\n {/* Params Schema */}\n {definition.paramsSchema && Object.keys(definition.paramsSchema).length > 0 && (\n <Section title=\"Parameters Schema\">\n <JsonBlock data={definition.paramsSchema} />\n </Section>\n )}\n\n {/* Steps */}\n <Section title={`Steps (${definition.steps.length})`}>\n <div className=\"space-y-2\">\n {definition.steps.map((step, i) => (\n <StepCard key={step.stepId} step={step} index={i} />\n ))}\n </div>\n </Section>\n\n {/* Metadata */}\n {definition.metadata && Object.keys(definition.metadata).length > 0 && (\n <Section title=\"Metadata\">\n <JsonBlock data={definition.metadata} />\n </Section>\n )}\n </div>\n )\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["\"use client\"\nimport * as React from 'react'\nimport { useRouter } from 'next/navigation'\nimport { Alert } from '@open-mercato/ui/primitives/alert'\nimport { useT, type TranslateFn } from '@open-mercato/shared/lib/i18n/context'\nimport { RowActions } from '@open-mercato/ui/backend/RowActions'\nimport { Tag } from '@open-mercato/ui/primitives/tag'\nimport type {\n WizardDefinitionResult,\n WizardStepDefinition,\n WizardTransition,\n WizardApplicability,\n} from '../../../../../workflows/types'\n\nasync function apiJson<T>(url: string, t: TranslateFn): Promise<T> {\n const res = await fetch(url)\n if (!res.ok) throw new Error(t('cpq.wizards.runner.errors.api', 'API error {status}', { status: res.status }))\n return res.json() as Promise<T>\n}\n\n// \u2500\u2500\u2500 Sub-components \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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 Badge({ children, variant = 'default' }: { children: React.ReactNode; variant?: 'default' | 'success' | 'muted' }) {\n const tagVariant = variant === 'success' ? 'success' : variant === 'muted' ? 'neutral' : 'info'\n return <Tag variant={tagVariant}>{children}</Tag>\n}\n\nfunction Section({ title, children }: { title: string; children: React.ReactNode }) {\n return (\n <div className=\"space-y-3\">\n <h2 className=\"text-base font-semibold\">{title}</h2>\n {children}\n </div>\n )\n}\n\nfunction KV({ label, children }: { label: string; children: React.ReactNode }) {\n return (\n <div className=\"flex flex-col gap-0.5\">\n <span className=\"text-xs font-medium text-muted-foreground\">{label}</span>\n <span className=\"text-sm\">{children}</span>\n </div>\n )\n}\n\nfunction JsonBlock({ data }: { data: unknown }) {\n const t = useT()\n if (data == null) return <span className=\"text-xs text-muted-foreground\">{t('cpq.wizards.detail.none', 'none')}</span>\n return (\n <pre className=\"rounded-md bg-muted/50 p-3 text-xs overflow-x-auto max-h-48\">\n {JSON.stringify(data, null, 2)}\n </pre>\n )\n}\n\nfunction TransitionRow({ transition, index }: { transition: WizardTransition; index: number }) {\n const t = useT()\n return (\n <div className=\"flex items-start gap-3 text-xs\">\n <span className=\"font-mono text-muted-foreground w-4 shrink-0\">{index + 1}.</span>\n <div className=\"space-y-0.5\">\n <div className=\"flex items-center gap-2\">\n <span className=\"font-medium\">{'->'} {transition.targetStepId}</span>\n {transition.isDefault && <Badge variant=\"muted\">{t('cpq.wizards.detail.transitionDefault', 'default')}</Badge>}\n {transition.label && <span className=\"text-muted-foreground\">({transition.label})</span>}\n </div>\n {transition.condition && (\n <div className=\"font-mono text-muted-foreground\">\n {t('cpq.wizards.detail.transitionWhen', 'when {field} {operator}', {\n field: transition.condition.field,\n operator: transition.condition.operator,\n })}\n {transition.condition.value !== undefined ? ` ${JSON.stringify(transition.condition.value)}` : ''}\n </div>\n )}\n </div>\n </div>\n )\n}\n\nfunction StepCard({ step, index }: { step: WizardStepDefinition; index: number }) {\n const t = useT()\n const [open, setOpen] = React.useState(false)\n const configKeys = Object.keys(step.config)\n\n return (\n <div className=\"rounded-lg border\">\n <button\n type=\"button\"\n onClick={() => setOpen((v) => !v)}\n className=\"w-full flex items-center gap-3 px-4 py-3 text-left hover:bg-muted/30 transition-colors\"\n >\n <span className=\"flex items-center justify-center rounded-full bg-primary/10 text-primary text-xs font-bold w-7 h-7 shrink-0\">\n {index + 1}\n </span>\n <div className=\"flex-1 min-w-0\">\n <div className=\"flex items-center gap-2\">\n <span className=\"text-sm font-medium truncate\">{step.title}</span>\n <Badge>{step.type}</Badge>\n {step.isOptional && <Badge variant=\"muted\">{t('cpq.wizards.detail.optional', 'optional')}</Badge>}\n </div>\n {step.description && (\n <p className=\"text-xs text-muted-foreground truncate mt-0.5\">{step.description}</p>\n )}\n </div>\n <span className=\"text-xs text-muted-foreground shrink-0\">{open ? '\\u25B2' : '\\u25BC'}</span>\n </button>\n\n {open && (\n <div className=\"border-t px-4 py-3 space-y-4\">\n <div className=\"grid grid-cols-2 gap-4\">\n <KV label={t('cpq.wizards.detail.stepId', 'Step ID')}><span className=\"font-mono text-xs\">{step.stepId}</span></KV>\n <KV label={t('cpq.wizards.detail.type', 'Type')}><span className=\"font-mono text-xs\">{step.type}</span></KV>\n </div>\n\n {configKeys.length > 0 && (\n <div className=\"space-y-1\">\n <span className=\"text-xs font-medium text-muted-foreground\">{t('cpq.wizards.detail.config', 'Config')}</span>\n <JsonBlock data={step.config} />\n </div>\n )}\n\n {step.transitions.length > 0 && (\n <div className=\"space-y-2\">\n <span className=\"text-xs font-medium text-muted-foreground\">\n {t('cpq.wizards.detail.transitions', 'Transitions ({count})', { count: step.transitions.length })}\n </span>\n <div className=\"space-y-1.5\">\n {step.transitions.map((transition, i) => (\n <TransitionRow key={`${transition.targetStepId}-${i}`} transition={transition} index={i} />\n ))}\n </div>\n </div>\n )}\n\n {step.transitions.length === 0 && (\n <div className=\"text-xs text-muted-foreground\">{t('cpq.wizards.detail.noTransitions', 'No transitions (terminal step)')}</div>\n )}\n\n {step.validationRules && step.validationRules.length > 0 && (\n <div className=\"space-y-1\">\n <span className=\"text-xs font-medium text-muted-foreground\">{t('cpq.wizards.detail.validationRules', 'Validation Rules')}</span>\n <JsonBlock data={step.validationRules} />\n </div>\n )}\n </div>\n )}\n </div>\n )\n}\n\nfunction ApplicabilityPanel({ applicability }: { applicability: WizardApplicability | null }) {\n const t = useT()\n if (!applicability) {\n return <span className=\"text-sm text-muted-foreground\">{t('cpq.wizards.detail.noApplicability', 'No applicability constraints')}</span>\n }\n return (\n <div className=\"grid grid-cols-2 gap-4\">\n {applicability.priority != null && (\n <KV label={t('cpq.wizards.detail.priority', 'Priority')}>{applicability.priority}</KV>\n )}\n {applicability.specCodes?.length ? (\n <KV label={t('cpq.wizards.detail.specCodes', 'Spec Codes')}>\n <div className=\"flex flex-wrap gap-1\">\n {applicability.specCodes.map((c) => (\n <span key={c} className=\"font-mono text-xs rounded bg-muted px-1.5 py-0.5\">{c}</span>\n ))}\n </div>\n </KV>\n ) : null}\n {applicability.offeringCodes?.length ? (\n <KV label={t('cpq.wizards.detail.offeringCodes', 'Offering Codes')}>\n <div className=\"flex flex-wrap gap-1\">\n {applicability.offeringCodes.map((c) => (\n <span key={c} className=\"font-mono text-xs rounded bg-muted px-1.5 py-0.5\">{c}</span>\n ))}\n </div>\n </KV>\n ) : null}\n {applicability.customerSegments?.length ? (\n <KV label={t('cpq.wizards.detail.customerSegments', 'Customer Segments')}>\n <div className=\"flex flex-wrap gap-1\">\n {applicability.customerSegments.map((c) => (\n <span key={c} className=\"font-mono text-xs rounded bg-muted px-1.5 py-0.5\">{c}</span>\n ))}\n </div>\n </KV>\n ) : null}\n </div>\n )\n}\n\n// \u2500\u2500\u2500 Main Page \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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 CpqWizardDetailPage({ params }: { params: Record<string, string | string[]> }) {\n const t = useT()\n const router = useRouter()\n const definitionCode = params.definitionCode as string\n\n const [definition, setDefinition] = React.useState<WizardDefinitionResult | null>(null)\n const [loading, setLoading] = React.useState(true)\n const [error, setError] = React.useState<string | null>(null)\n\n React.useEffect(() => {\n async function load() {\n if (!definitionCode) return\n setLoading(true)\n setError(null)\n try {\n const def = await apiJson<WizardDefinitionResult>(\n `/api/cpq/wizards?code=${encodeURIComponent(definitionCode)}`,\n t,\n )\n setDefinition(def)\n } catch (err) {\n setError(err instanceof Error ? err.message : t('cpq.wizards.runner.errors.load', 'Failed to load wizard'))\n } finally {\n setLoading(false)\n }\n }\n load()\n }, [definitionCode, t])\n\n if (loading) {\n return <div className=\"text-sm text-muted-foreground\">{t('cpq.common.loading', 'Loading...')}</div>\n }\n\n if (error) {\n return (\n <div className=\"space-y-4\">\n <Alert variant=\"destructive\">{error}</Alert>\n <button type=\"button\" onClick={() => router.push('/backend/cpq/wizards')} className=\"text-sm text-muted-foreground hover:text-foreground\">\n \u2190 {t('cpq.wizards.runner.backToList', 'Back to Wizards')}\n </button>\n </div>\n )\n }\n\n if (!definition) {\n return (\n <div className=\"rounded-lg border bg-card p-6 text-center text-sm text-muted-foreground\">\n {t('cpq.wizards.runner.notFound', 'Wizard not found.')}\n </div>\n )\n }\n\n return (\n <div className=\"space-y-6 max-w-[900px] mx-auto\">\n {/* Header */}\n <div className=\"flex items-center gap-3\">\n <button\n type=\"button\"\n onClick={() => router.push('/backend/cpq/wizards')}\n className=\"text-sm text-muted-foreground hover:text-foreground\"\n >\n \u2190 {t('cpq.wizards.runner.allWizards', 'All Wizards')}\n </button>\n </div>\n\n <div className=\"flex items-start justify-between gap-4\">\n <div>\n <h1 className=\"text-2xl font-bold\">{definition.name}</h1>\n {definition.description && (\n <p className=\"text-sm text-muted-foreground mt-1\">{definition.description}</p>\n )}\n </div>\n {/* Actions live in a 3-dot menu \u2014 wizards are read-only in admin UI\n for the time being, so only `Preview` is exposed. */}\n <div className=\"shrink-0\">\n <RowActions\n items={[\n {\n id: 'preview',\n label: t('cpq.wizards.actions.preview', 'Preview'),\n onSelect: () => router.push(`/backend/cpq/wizards/${definitionCode}`),\n },\n ]}\n />\n </div>\n </div>\n\n {/* General Info */}\n <Section title={t('cpq.wizards.detail.sections.general', 'General')}>\n <div className=\"rounded-lg border p-4\">\n <div className=\"grid grid-cols-2 sm:grid-cols-4 gap-4\">\n <KV label={t('cpq.wizards.detail.code', 'Code')}><span className=\"font-mono text-xs\">{definition.code}</span></KV>\n <KV label={t('cpq.wizards.detail.version', 'Version')}>v{definition.version}</KV>\n <KV label={t('cpq.wizards.detail.surface', 'Surface')}>{definition.surface}</KV>\n <KV label={t('cpq.wizards.detail.active', 'Active')}>\n <Badge variant={definition.isActive ? 'success' : 'muted'}>\n {definition.isActive ? t('cpq.common.yes', 'Yes') : t('cpq.common.no', 'No')}\n </Badge>\n </KV>\n </div>\n </div>\n </Section>\n\n {/* Applicability */}\n <Section title={t('cpq.wizards.detail.sections.applicability', 'Applicability')}>\n <div className=\"rounded-lg border p-4\">\n <ApplicabilityPanel applicability={definition.applicability} />\n </div>\n </Section>\n\n {/* Params Schema */}\n {definition.paramsSchema && Object.keys(definition.paramsSchema).length > 0 && (\n <Section title={t('cpq.wizards.detail.sections.paramsSchema', 'Parameters Schema')}>\n <JsonBlock data={definition.paramsSchema} />\n </Section>\n )}\n\n {/* Steps */}\n <Section title={t('cpq.wizards.detail.sections.steps', 'Steps ({count})', { count: definition.steps.length })}>\n <div className=\"space-y-2\">\n {definition.steps.map((step, i) => (\n <StepCard key={step.stepId} step={step} index={i} />\n ))}\n </div>\n </Section>\n\n {/* Metadata */}\n {definition.metadata && Object.keys(definition.metadata).length > 0 && (\n <Section title={t('cpq.wizards.detail.sections.metadata', 'Metadata')}>\n <JsonBlock data={definition.metadata} />\n </Section>\n )}\n </div>\n )\n}\n"],
5
+ "mappings": ";AAwBS,cAKL,YALK;AAvBT,YAAY,WAAW;AACvB,SAAS,iBAAiB;AAC1B,SAAS,aAAa;AACtB,SAAS,YAA8B;AACvC,SAAS,kBAAkB;AAC3B,SAAS,WAAW;AAQpB,eAAe,QAAW,KAAa,GAA4B;AACjE,QAAM,MAAM,MAAM,MAAM,GAAG;AAC3B,MAAI,CAAC,IAAI,GAAI,OAAM,IAAI,MAAM,EAAE,iCAAiC,sBAAsB,EAAE,QAAQ,IAAI,OAAO,CAAC,CAAC;AAC7G,SAAO,IAAI,KAAK;AAClB;AAIA,SAAS,MAAM,EAAE,UAAU,UAAU,UAAU,GAA6E;AAC1H,QAAM,aAAa,YAAY,YAAY,YAAY,YAAY,UAAU,YAAY;AACzF,SAAO,oBAAC,OAAI,SAAS,YAAa,UAAS;AAC7C;AAEA,SAAS,QAAQ,EAAE,OAAO,SAAS,GAAiD;AAClF,SACE,qBAAC,SAAI,WAAU,aACb;AAAA,wBAAC,QAAG,WAAU,2BAA2B,iBAAM;AAAA,IAC9C;AAAA,KACH;AAEJ;AAEA,SAAS,GAAG,EAAE,OAAO,SAAS,GAAiD;AAC7E,SACE,qBAAC,SAAI,WAAU,yBACb;AAAA,wBAAC,UAAK,WAAU,6CAA6C,iBAAM;AAAA,IACnE,oBAAC,UAAK,WAAU,WAAW,UAAS;AAAA,KACtC;AAEJ;AAEA,SAAS,UAAU,EAAE,KAAK,GAAsB;AAC9C,QAAM,IAAI,KAAK;AACf,MAAI,QAAQ,KAAM,QAAO,oBAAC,UAAK,WAAU,iCAAiC,YAAE,2BAA2B,MAAM,GAAE;AAC/G,SACE,oBAAC,SAAI,WAAU,+DACZ,eAAK,UAAU,MAAM,MAAM,CAAC,GAC/B;AAEJ;AAEA,SAAS,cAAc,EAAE,YAAY,MAAM,GAAoD;AAC7F,QAAM,IAAI,KAAK;AACf,SACE,qBAAC,SAAI,WAAU,kCACb;AAAA,yBAAC,UAAK,WAAU,gDAAgD;AAAA,cAAQ;AAAA,MAAE;AAAA,OAAC;AAAA,IAC3E,qBAAC,SAAI,WAAU,eACb;AAAA,2BAAC,SAAI,WAAU,2BACb;AAAA,6BAAC,UAAK,WAAU,eAAe;AAAA;AAAA,UAAK;AAAA,UAAE,WAAW;AAAA,WAAa;AAAA,QAC7D,WAAW,aAAa,oBAAC,SAAM,SAAQ,SAAS,YAAE,wCAAwC,SAAS,GAAE;AAAA,QACrG,WAAW,SAAS,qBAAC,UAAK,WAAU,yBAAwB;AAAA;AAAA,UAAE,WAAW;AAAA,UAAM;AAAA,WAAC;AAAA,SACnF;AAAA,MACC,WAAW,aACV,qBAAC,SAAI,WAAU,mCACZ;AAAA,UAAE,qCAAqC,2BAA2B;AAAA,UACjE,OAAO,WAAW,UAAU;AAAA,UAC5B,UAAU,WAAW,UAAU;AAAA,QACjC,CAAC;AAAA,QACA,WAAW,UAAU,UAAU,SAAY,IAAI,KAAK,UAAU,WAAW,UAAU,KAAK,CAAC,KAAK;AAAA,SACjG;AAAA,OAEJ;AAAA,KACF;AAEJ;AAEA,SAAS,SAAS,EAAE,MAAM,MAAM,GAAkD;AAChF,QAAM,IAAI,KAAK;AACf,QAAM,CAAC,MAAM,OAAO,IAAI,MAAM,SAAS,KAAK;AAC5C,QAAM,aAAa,OAAO,KAAK,KAAK,MAAM;AAE1C,SACE,qBAAC,SAAI,WAAU,qBACb;AAAA;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,SAAS,MAAM,QAAQ,CAAC,MAAM,CAAC,CAAC;AAAA,QAChC,WAAU;AAAA,QAEV;AAAA,8BAAC,UAAK,WAAU,+GACb,kBAAQ,GACX;AAAA,UACA,qBAAC,SAAI,WAAU,kBACb;AAAA,iCAAC,SAAI,WAAU,2BACb;AAAA,kCAAC,UAAK,WAAU,gCAAgC,eAAK,OAAM;AAAA,cAC3D,oBAAC,SAAO,eAAK,MAAK;AAAA,cACjB,KAAK,cAAc,oBAAC,SAAM,SAAQ,SAAS,YAAE,+BAA+B,UAAU,GAAE;AAAA,eAC3F;AAAA,YACC,KAAK,eACJ,oBAAC,OAAE,WAAU,iDAAiD,eAAK,aAAY;AAAA,aAEnF;AAAA,UACA,oBAAC,UAAK,WAAU,0CAA0C,iBAAO,WAAW,UAAS;AAAA;AAAA;AAAA,IACvF;AAAA,IAEC,QACC,qBAAC,SAAI,WAAU,gCACb;AAAA,2BAAC,SAAI,WAAU,0BACb;AAAA,4BAAC,MAAG,OAAO,EAAE,6BAA6B,SAAS,GAAG,8BAAC,UAAK,WAAU,qBAAqB,eAAK,QAAO,GAAO;AAAA,QAC9G,oBAAC,MAAG,OAAO,EAAE,2BAA2B,MAAM,GAAG,8BAAC,UAAK,WAAU,qBAAqB,eAAK,MAAK,GAAO;AAAA,SACzG;AAAA,MAEC,WAAW,SAAS,KACnB,qBAAC,SAAI,WAAU,aACb;AAAA,4BAAC,UAAK,WAAU,6CAA6C,YAAE,6BAA6B,QAAQ,GAAE;AAAA,QACtG,oBAAC,aAAU,MAAM,KAAK,QAAQ;AAAA,SAChC;AAAA,MAGD,KAAK,YAAY,SAAS,KACzB,qBAAC,SAAI,WAAU,aACb;AAAA,4BAAC,UAAK,WAAU,6CACb,YAAE,kCAAkC,yBAAyB,EAAE,OAAO,KAAK,YAAY,OAAO,CAAC,GAClG;AAAA,QACA,oBAAC,SAAI,WAAU,eACZ,eAAK,YAAY,IAAI,CAAC,YAAY,MACjC,oBAAC,iBAAsD,YAAwB,OAAO,KAAlE,GAAG,WAAW,YAAY,IAAI,CAAC,EAAsC,CAC1F,GACH;AAAA,SACF;AAAA,MAGD,KAAK,YAAY,WAAW,KAC3B,oBAAC,SAAI,WAAU,iCAAiC,YAAE,oCAAoC,gCAAgC,GAAE;AAAA,MAGzH,KAAK,mBAAmB,KAAK,gBAAgB,SAAS,KACrD,qBAAC,SAAI,WAAU,aACb;AAAA,4BAAC,UAAK,WAAU,6CAA6C,YAAE,sCAAsC,kBAAkB,GAAE;AAAA,QACzH,oBAAC,aAAU,MAAM,KAAK,iBAAiB;AAAA,SACzC;AAAA,OAEJ;AAAA,KAEJ;AAEJ;AAEA,SAAS,mBAAmB,EAAE,cAAc,GAAkD;AAC5F,QAAM,IAAI,KAAK;AACf,MAAI,CAAC,eAAe;AAClB,WAAO,oBAAC,UAAK,WAAU,iCAAiC,YAAE,sCAAsC,8BAA8B,GAAE;AAAA,EAClI;AACA,SACE,qBAAC,SAAI,WAAU,0BACZ;AAAA,kBAAc,YAAY,QACzB,oBAAC,MAAG,OAAO,EAAE,+BAA+B,UAAU,GAAI,wBAAc,UAAS;AAAA,IAElF,cAAc,WAAW,SACxB,oBAAC,MAAG,OAAO,EAAE,gCAAgC,YAAY,GACvD,8BAAC,SAAI,WAAU,wBACZ,wBAAc,UAAU,IAAI,CAAC,MAC5B,oBAAC,UAAa,WAAU,oDAAoD,eAAjE,CAAmE,CAC/E,GACH,GACF,IACE;AAAA,IACH,cAAc,eAAe,SAC5B,oBAAC,MAAG,OAAO,EAAE,oCAAoC,gBAAgB,GAC/D,8BAAC,SAAI,WAAU,wBACZ,wBAAc,cAAc,IAAI,CAAC,MAChC,oBAAC,UAAa,WAAU,oDAAoD,eAAjE,CAAmE,CAC/E,GACH,GACF,IACE;AAAA,IACH,cAAc,kBAAkB,SAC/B,oBAAC,MAAG,OAAO,EAAE,uCAAuC,mBAAmB,GACrE,8BAAC,SAAI,WAAU,wBACZ,wBAAc,iBAAiB,IAAI,CAAC,MACnC,oBAAC,UAAa,WAAU,oDAAoD,eAAjE,CAAmE,CAC/E,GACH,GACF,IACE;AAAA,KACN;AAEJ;AAIe,SAAR,oBAAqC,EAAE,OAAO,GAAkD;AACrG,QAAM,IAAI,KAAK;AACf,QAAM,SAAS,UAAU;AACzB,QAAM,iBAAiB,OAAO;AAE9B,QAAM,CAAC,YAAY,aAAa,IAAI,MAAM,SAAwC,IAAI;AACtF,QAAM,CAAC,SAAS,UAAU,IAAI,MAAM,SAAS,IAAI;AACjD,QAAM,CAAC,OAAO,QAAQ,IAAI,MAAM,SAAwB,IAAI;AAE5D,QAAM,UAAU,MAAM;AACpB,mBAAe,OAAO;AACpB,UAAI,CAAC,eAAgB;AACrB,iBAAW,IAAI;AACf,eAAS,IAAI;AACb,UAAI;AACF,cAAM,MAAM,MAAM;AAAA,UAChB,yBAAyB,mBAAmB,cAAc,CAAC;AAAA,UAC3D;AAAA,QACF;AACA,sBAAc,GAAG;AAAA,MACnB,SAAS,KAAK;AACZ,iBAAS,eAAe,QAAQ,IAAI,UAAU,EAAE,kCAAkC,uBAAuB,CAAC;AAAA,MAC5G,UAAE;AACA,mBAAW,KAAK;AAAA,MAClB;AAAA,IACF;AACA,SAAK;AAAA,EACP,GAAG,CAAC,gBAAgB,CAAC,CAAC;AAEtB,MAAI,SAAS;AACX,WAAO,oBAAC,SAAI,WAAU,iCAAiC,YAAE,sBAAsB,YAAY,GAAE;AAAA,EAC/F;AAEA,MAAI,OAAO;AACT,WACE,qBAAC,SAAI,WAAU,aACb;AAAA,0BAAC,SAAM,SAAQ,eAAe,iBAAM;AAAA,MACpC,qBAAC,YAAO,MAAK,UAAS,SAAS,MAAM,OAAO,KAAK,sBAAsB,GAAG,WAAU,uDAAsD;AAAA;AAAA,QACrI,EAAE,iCAAiC,iBAAiB;AAAA,SACzD;AAAA,OACF;AAAA,EAEJ;AAEA,MAAI,CAAC,YAAY;AACf,WACE,oBAAC,SAAI,WAAU,2EACZ,YAAE,+BAA+B,mBAAmB,GACvD;AAAA,EAEJ;AAEA,SACE,qBAAC,SAAI,WAAU,mCAEb;AAAA,wBAAC,SAAI,WAAU,2BACb;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,SAAS,MAAM,OAAO,KAAK,sBAAsB;AAAA,QACjD,WAAU;AAAA,QACX;AAAA;AAAA,UACI,EAAE,iCAAiC,aAAa;AAAA;AAAA;AAAA,IACrD,GACF;AAAA,IAEA,qBAAC,SAAI,WAAU,0CACb;AAAA,2BAAC,SACC;AAAA,4BAAC,QAAG,WAAU,sBAAsB,qBAAW,MAAK;AAAA,QACnD,WAAW,eACV,oBAAC,OAAE,WAAU,sCAAsC,qBAAW,aAAY;AAAA,SAE9E;AAAA,MAGA,oBAAC,SAAI,WAAU,YACb;AAAA,QAAC;AAAA;AAAA,UACC,OAAO;AAAA,YACL;AAAA,cACE,IAAI;AAAA,cACJ,OAAO,EAAE,+BAA+B,SAAS;AAAA,cACjD,UAAU,MAAM,OAAO,KAAK,wBAAwB,cAAc,EAAE;AAAA,YACtE;AAAA,UACF;AAAA;AAAA,MACF,GACF;AAAA,OACF;AAAA,IAGA,oBAAC,WAAQ,OAAO,EAAE,uCAAuC,SAAS,GAChE,8BAAC,SAAI,WAAU,yBACb,+BAAC,SAAI,WAAU,yCACb;AAAA,0BAAC,MAAG,OAAO,EAAE,2BAA2B,MAAM,GAAG,8BAAC,UAAK,WAAU,qBAAqB,qBAAW,MAAK,GAAO;AAAA,MAC7G,qBAAC,MAAG,OAAO,EAAE,8BAA8B,SAAS,GAAG;AAAA;AAAA,QAAE,WAAW;AAAA,SAAQ;AAAA,MAC5E,oBAAC,MAAG,OAAO,EAAE,8BAA8B,SAAS,GAAI,qBAAW,SAAQ;AAAA,MAC3E,oBAAC,MAAG,OAAO,EAAE,6BAA6B,QAAQ,GAChD,8BAAC,SAAM,SAAS,WAAW,WAAW,YAAY,SAC/C,qBAAW,WAAW,EAAE,kBAAkB,KAAK,IAAI,EAAE,iBAAiB,IAAI,GAC7E,GACF;AAAA,OACF,GACF,GACF;AAAA,IAGA,oBAAC,WAAQ,OAAO,EAAE,6CAA6C,eAAe,GAC5E,8BAAC,SAAI,WAAU,yBACb,8BAAC,sBAAmB,eAAe,WAAW,eAAe,GAC/D,GACF;AAAA,IAGC,WAAW,gBAAgB,OAAO,KAAK,WAAW,YAAY,EAAE,SAAS,KACxE,oBAAC,WAAQ,OAAO,EAAE,4CAA4C,mBAAmB,GAC/E,8BAAC,aAAU,MAAM,WAAW,cAAc,GAC5C;AAAA,IAIF,oBAAC,WAAQ,OAAO,EAAE,qCAAqC,mBAAmB,EAAE,OAAO,WAAW,MAAM,OAAO,CAAC,GAC1G,8BAAC,SAAI,WAAU,aACZ,qBAAW,MAAM,IAAI,CAAC,MAAM,MAC3B,oBAAC,YAA2B,MAAY,OAAO,KAAhC,KAAK,MAA8B,CACnD,GACH,GACF;AAAA,IAGC,WAAW,YAAY,OAAO,KAAK,WAAW,QAAQ,EAAE,SAAS,KAChE,oBAAC,WAAQ,OAAO,EAAE,wCAAwC,UAAU,GAClE,8BAAC,aAAU,MAAM,WAAW,UAAU,GACxC;AAAA,KAEJ;AAEJ;",
6
6
  "names": []
7
7
  }
@@ -3,18 +3,20 @@ import { jsx, jsxs } from "react/jsx-runtime";
3
3
  import * as React from "react";
4
4
  import { useRouter, useSearchParams } from "next/navigation";
5
5
  import { Alert } from "@open-mercato/ui/primitives/alert";
6
+ import { useT } from "@open-mercato/shared/lib/i18n/context";
6
7
  import { WizardRunner } from "../../../../workflows/WizardRunner.js";
7
8
  import { registerBuiltInStepTypes } from "../../../../workflows/steps/index.js";
8
9
  registerBuiltInStepTypes();
9
- async function apiJson(url) {
10
+ async function apiJson(url, t) {
10
11
  const res = await fetch(url);
11
- if (!res.ok) throw new Error(`API error ${res.status}`);
12
+ if (!res.ok) throw new Error(t("cpq.wizards.runner.errors.api", "API error {status}", { status: res.status }));
12
13
  return res.json();
13
14
  }
14
15
  function ParamsForm({
15
16
  schema,
16
17
  onStart
17
18
  }) {
19
+ const t = useT();
18
20
  const properties = schema.properties ?? {};
19
21
  const requiredFields = schema.required ?? [];
20
22
  const fieldNames = Object.keys(properties);
@@ -26,8 +28,8 @@ function ParamsForm({
26
28
  const isValid = requiredFields.every((key) => values[key]?.trim());
27
29
  return /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
28
30
  /* @__PURE__ */ jsxs("div", { className: "rounded-lg border bg-muted/30 p-4 space-y-1", children: [
29
- /* @__PURE__ */ jsx("h4", { className: "text-sm font-medium", children: "This wizard requires input parameters" }),
30
- /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: "Fill in the required fields before starting." })
31
+ /* @__PURE__ */ jsx("h4", { className: "text-sm font-medium", children: t("cpq.wizards.runner.params.title", "This wizard requires input parameters") }),
32
+ /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: t("cpq.wizards.runner.params.hint", "Fill in the required fields before starting.") })
31
33
  ] }),
32
34
  /* @__PURE__ */ jsx("div", { className: "space-y-3", children: fieldNames.map((key) => {
33
35
  const prop = properties[key];
@@ -47,10 +49,7 @@ function ParamsForm({
47
49
  className: "w-full rounded-md border px-3 py-2 text-sm font-mono"
48
50
  }
49
51
  ),
50
- prop?.format && /* @__PURE__ */ jsxs("p", { className: "text-xs text-muted-foreground mt-0.5", children: [
51
- "Format: ",
52
- prop.format
53
- ] })
52
+ prop?.format && /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground mt-0.5", children: t("cpq.wizards.runner.params.format", "Format: {format}", { format: prop.format }) })
54
53
  ] }, key);
55
54
  }) }),
56
55
  /* @__PURE__ */ jsx(
@@ -60,12 +59,13 @@ function ParamsForm({
60
59
  onClick: () => onStart(values),
61
60
  disabled: !isValid,
62
61
  className: "inline-flex items-center justify-center rounded-md bg-primary px-5 py-2 text-sm font-medium text-primary-foreground hover:bg-primary/90 disabled:opacity-50 disabled:cursor-not-allowed",
63
- children: "Preview Wizard"
62
+ children: t("cpq.wizards.runner.params.start", "Preview Wizard")
64
63
  }
65
64
  )
66
65
  ] });
67
66
  }
68
67
  function CpqWizardRunnerPage({ params }) {
68
+ const t = useT();
69
69
  const router = useRouter();
70
70
  const searchParams = useSearchParams();
71
71
  const definitionCode = params.definitionCode;
@@ -86,7 +86,7 @@ function CpqWizardRunnerPage({ params }) {
86
86
  React.useEffect(() => {
87
87
  async function load() {
88
88
  if (!definitionCode || definitionCode === "undefined") {
89
- setError("Invalid wizard definition code");
89
+ setError(t("cpq.wizards.runner.errors.invalidCode", "Invalid wizard definition code"));
90
90
  setLoading(false);
91
91
  return;
92
92
  }
@@ -94,7 +94,8 @@ function CpqWizardRunnerPage({ params }) {
94
94
  setError(null);
95
95
  try {
96
96
  const def = await apiJson(
97
- `/api/cpq/wizards?code=${encodeURIComponent(definitionCode)}`
97
+ `/api/cpq/wizards?code=${encodeURIComponent(definitionCode)}`,
98
+ t
98
99
  );
99
100
  setDefinition(def);
100
101
  const schema = def.paramsSchema;
@@ -103,13 +104,13 @@ function CpqWizardRunnerPage({ params }) {
103
104
  setStarted(true);
104
105
  }
105
106
  } catch (err) {
106
- setError(err instanceof Error ? err.message : "Failed to load wizard");
107
+ setError(err instanceof Error ? err.message : t("cpq.wizards.runner.errors.load", "Failed to load wizard"));
107
108
  } finally {
108
109
  setLoading(false);
109
110
  }
110
111
  }
111
112
  load();
112
- }, [definitionCode, queryParams]);
113
+ }, [definitionCode, queryParams, t]);
113
114
  const handleComplete = React.useCallback((stepData) => {
114
115
  let orderId;
115
116
  let quoteId;
@@ -130,7 +131,7 @@ function CpqWizardRunnerPage({ params }) {
130
131
  setStarted(true);
131
132
  }, []);
132
133
  if (loading) {
133
- return /* @__PURE__ */ jsx("div", { className: "text-sm text-muted-foreground", children: "Loading wizard..." });
134
+ return /* @__PURE__ */ jsx("div", { className: "text-sm text-muted-foreground", children: t("cpq.wizards.runner.loading", "Loading wizard...") });
134
135
  }
135
136
  if (error) {
136
137
  return /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
@@ -141,23 +142,26 @@ function CpqWizardRunnerPage({ params }) {
141
142
  type: "button",
142
143
  onClick: () => router.push("/backend/cpq/wizards"),
143
144
  className: "inline-flex items-center justify-center rounded-md border px-4 py-2 text-sm font-medium hover:bg-muted",
144
- children: "Back to Wizards"
145
+ children: t("cpq.wizards.runner.backToList", "Back to Wizards")
145
146
  }
146
147
  )
147
148
  ] });
148
149
  }
149
150
  if (!definition) {
150
- return /* @__PURE__ */ jsx("div", { className: "rounded-lg border bg-card p-6 text-center text-sm text-muted-foreground", children: "Wizard not found." });
151
+ return /* @__PURE__ */ jsx("div", { className: "rounded-lg border bg-card p-6 text-center text-sm text-muted-foreground", children: t("cpq.wizards.runner.notFound", "Wizard not found.") });
151
152
  }
152
153
  const scope = { organizationId: "", tenantId: "" };
153
154
  return /* @__PURE__ */ jsxs("div", { className: "space-y-4 max-w-[900px] mx-auto", children: [
154
- /* @__PURE__ */ jsx("div", { className: "flex items-center gap-3", children: /* @__PURE__ */ jsx(
155
+ /* @__PURE__ */ jsx("div", { className: "flex items-center gap-3", children: /* @__PURE__ */ jsxs(
155
156
  "button",
156
157
  {
157
158
  type: "button",
158
159
  onClick: () => router.push("/backend/cpq/wizards"),
159
160
  className: "text-sm text-muted-foreground hover:text-foreground",
160
- children: "\u2190 All Wizards"
161
+ children: [
162
+ "\u2190 ",
163
+ t("cpq.wizards.runner.allWizards", "All Wizards")
164
+ ]
161
165
  }
162
166
  ) }),
163
167
  !started ? /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [