@dainamite/cpq 0.6.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +16 -0
- package/dist/modules/cpq/backend/cpq/inventory/AssetsTable.js +3 -9
- package/dist/modules/cpq/backend/cpq/inventory/AssetsTable.js.map +2 -2
- package/dist/modules/cpq/backend/cpq/inventory/SubscriptionsTable.js +21 -25
- package/dist/modules/cpq/backend/cpq/inventory/SubscriptionsTable.js.map +2 -2
- package/dist/modules/cpq/backend/cpq/inventory/assets/[id]/page.js +48 -47
- package/dist/modules/cpq/backend/cpq/inventory/assets/[id]/page.js.map +2 -2
- package/dist/modules/cpq/backend/cpq/inventory/assets/[id]/page.meta.js +1 -1
- package/dist/modules/cpq/backend/cpq/inventory/assets/[id]/page.meta.js.map +2 -2
- package/dist/modules/cpq/backend/cpq/inventory/page.meta.js +2 -2
- package/dist/modules/cpq/backend/cpq/inventory/page.meta.js.map +2 -2
- package/dist/modules/cpq/backend/cpq/inventory/shared.js +37 -2
- package/dist/modules/cpq/backend/cpq/inventory/shared.js.map +2 -2
- package/dist/modules/cpq/backend/cpq/inventory/subscriptions/[id]/page.js +154 -178
- package/dist/modules/cpq/backend/cpq/inventory/subscriptions/[id]/page.js.map +2 -2
- package/dist/modules/cpq/backend/cpq/inventory/subscriptions/[id]/page.meta.js +1 -1
- package/dist/modules/cpq/backend/cpq/inventory/subscriptions/[id]/page.meta.js.map +2 -2
- package/dist/modules/cpq/backend/cpq/offerings/[id]/page.js +168 -143
- package/dist/modules/cpq/backend/cpq/offerings/[id]/page.js.map +2 -2
- package/dist/modules/cpq/backend/cpq/offerings/page.js +36 -34
- package/dist/modules/cpq/backend/cpq/offerings/page.js.map +2 -2
- package/dist/modules/cpq/backend/cpq/orders/[id]/page.js +69 -66
- package/dist/modules/cpq/backend/cpq/orders/[id]/page.js.map +2 -2
- package/dist/modules/cpq/backend/cpq/orders/page.js +6 -6
- package/dist/modules/cpq/backend/cpq/orders/page.js.map +2 -2
- package/dist/modules/cpq/backend/cpq/price-rules/PriceRuleForm.js +41 -36
- package/dist/modules/cpq/backend/cpq/price-rules/PriceRuleForm.js.map +2 -2
- package/dist/modules/cpq/backend/cpq/price-rules/[id]/page.js +76 -72
- package/dist/modules/cpq/backend/cpq/price-rules/[id]/page.js.map +2 -2
- package/dist/modules/cpq/backend/cpq/price-rules/[id]/page.meta.js +1 -1
- package/dist/modules/cpq/backend/cpq/price-rules/[id]/page.meta.js.map +2 -2
- package/dist/modules/cpq/backend/cpq/price-rules/page.js +18 -15
- package/dist/modules/cpq/backend/cpq/price-rules/page.js.map +2 -2
- package/dist/modules/cpq/backend/cpq/pricing/[id]/EntriesEditor.js +23 -21
- package/dist/modules/cpq/backend/cpq/pricing/[id]/EntriesEditor.js.map +2 -2
- package/dist/modules/cpq/backend/cpq/pricing/[id]/ImportPreview.js +22 -50
- package/dist/modules/cpq/backend/cpq/pricing/[id]/ImportPreview.js.map +2 -2
- package/dist/modules/cpq/backend/cpq/pricing/[id]/page.js +74 -52
- package/dist/modules/cpq/backend/cpq/pricing/[id]/page.js.map +2 -2
- package/dist/modules/cpq/backend/cpq/pricing/[id]/xlsxImport.js +20 -17
- package/dist/modules/cpq/backend/cpq/pricing/[id]/xlsxImport.js.map +2 -2
- package/dist/modules/cpq/backend/cpq/pricing/page.js +1 -1
- package/dist/modules/cpq/backend/cpq/pricing/page.js.map +2 -2
- package/dist/modules/cpq/backend/cpq/quotes/[id]/_components/ArcQuoteConfigurator.js +115 -123
- package/dist/modules/cpq/backend/cpq/quotes/[id]/_components/ArcQuoteConfigurator.js.map +2 -2
- package/dist/modules/cpq/backend/cpq/quotes/[id]/_components/PriceAdjustmentDialog.js +6 -3
- package/dist/modules/cpq/backend/cpq/quotes/[id]/_components/PriceAdjustmentDialog.js.map +2 -2
- package/dist/modules/cpq/backend/cpq/quotes/[id]/page.js +129 -94
- package/dist/modules/cpq/backend/cpq/quotes/[id]/page.js.map +2 -2
- package/dist/modules/cpq/backend/cpq/quotes/page.js +23 -19
- package/dist/modules/cpq/backend/cpq/quotes/page.js.map +2 -2
- package/dist/modules/cpq/backend/cpq/specifications/[id]/DependsOnRulesEditor.js +19 -15
- package/dist/modules/cpq/backend/cpq/specifications/[id]/DependsOnRulesEditor.js.map +2 -2
- package/dist/modules/cpq/backend/cpq/specifications/[id]/page.js +171 -178
- package/dist/modules/cpq/backend/cpq/specifications/[id]/page.js.map +2 -2
- package/dist/modules/cpq/backend/cpq/specifications/page.js +2 -2
- package/dist/modules/cpq/backend/cpq/specifications/page.js.map +2 -2
- package/dist/modules/cpq/backend/cpq/wizards/[definitionCode]/detail/page.js +60 -50
- package/dist/modules/cpq/backend/cpq/wizards/[definitionCode]/detail/page.js.map +2 -2
- package/dist/modules/cpq/backend/cpq/wizards/[definitionCode]/page.js +22 -18
- package/dist/modules/cpq/backend/cpq/wizards/[definitionCode]/page.js.map +2 -2
- package/dist/modules/cpq/backend/cpq/wizards/page.js +1 -1
- package/dist/modules/cpq/backend/cpq/wizards/page.js.map +2 -2
- package/dist/modules/cpq/components/ArcLineDiff.js +2 -2
- package/dist/modules/cpq/components/ArcLineDiff.js.map +2 -2
- package/dist/modules/cpq/components/ChargeBreakdownTable.js +4 -10
- package/dist/modules/cpq/components/ChargeBreakdownTable.js.map +2 -2
- package/dist/modules/cpq/components/PriceWaterfall.js +3 -1
- package/dist/modules/cpq/components/PriceWaterfall.js.map +2 -2
- package/dist/modules/cpq/components/PricingSummaryCard.js +1 -6
- package/dist/modules/cpq/components/PricingSummaryCard.js.map +2 -2
- package/dist/modules/cpq/components/StatusPath.js +5 -3
- package/dist/modules/cpq/components/StatusPath.js.map +2 -2
- package/dist/modules/cpq/components/useCpqRowActions.js +10 -22
- package/dist/modules/cpq/components/useCpqRowActions.js.map +2 -2
- package/dist/modules/cpq/i18n/de.json +1220 -0
- package/dist/modules/cpq/i18n/en.json +1220 -0
- package/dist/modules/cpq/i18n/es.json +1220 -0
- package/dist/modules/cpq/i18n/pl.json +1220 -0
- package/dist/modules/cpq/widgets/injection/customer-inventory/widget.client.js +39 -31
- package/dist/modules/cpq/widgets/injection/customer-inventory/widget.client.js.map +2 -2
- package/dist/modules/cpq/widgets/injection/order-cpq-tab/widget.client.js +13 -5
- package/dist/modules/cpq/widgets/injection/order-cpq-tab/widget.client.js.map +2 -2
- package/dist/modules/cpq/widgets/injection/quote-configurator/widget.client.js +41 -21
- package/dist/modules/cpq/widgets/injection/quote-configurator/widget.client.js.map +2 -2
- package/dist/modules/cpq/widgets/injection-table.js +2 -2
- package/dist/modules/cpq/widgets/injection-table.js.map +2 -2
- package/dist/modules/cpq/workflows/WizardRunner.js +10 -8
- package/dist/modules/cpq/workflows/WizardRunner.js.map +2 -2
- package/dist/modules/cpq/workflows/WizardTrigger.js +15 -9
- package/dist/modules/cpq/workflows/WizardTrigger.js.map +2 -2
- package/dist/modules/cpq/workflows/steps/CustomerSelectStep.js +9 -7
- package/dist/modules/cpq/workflows/steps/CustomerSelectStep.js.map +2 -2
- package/dist/modules/cpq/workflows/steps/InventorySelectStep.js +9 -4
- package/dist/modules/cpq/workflows/steps/InventorySelectStep.js.map +2 -2
- package/dist/modules/cpq/workflows/steps/ItemListStep.js +16 -19
- package/dist/modules/cpq/workflows/steps/ItemListStep.js.map +2 -2
- package/dist/modules/cpq/workflows/steps/OfferingSelectStep.js +19 -32
- package/dist/modules/cpq/workflows/steps/OfferingSelectStep.js.map +2 -2
- package/dist/modules/cpq/workflows/steps/ProductConfigureStep.js +8 -6
- package/dist/modules/cpq/workflows/steps/ProductConfigureStep.js.map +2 -2
- package/dist/modules/cpq/workflows/steps/ReviewStep.js +32 -30
- package/dist/modules/cpq/workflows/steps/ReviewStep.js.map +2 -2
- package/dist/modules/cpq/workflows/steps/index.js +12 -0
- package/dist/modules/cpq/workflows/steps/index.js.map +2 -2
- package/package.json +1 -1
- package/src/modules/cpq/__tests__/i18n/dictionaries.test.ts +62 -0
- package/src/modules/cpq/__tests__/i18n/hardcodedStrings.test.ts +35 -0
- package/src/modules/cpq/__tests__/i18n/sourceScan.ts +109 -0
- package/src/modules/cpq/backend/cpq/inventory/AssetsTable.tsx +3 -9
- package/src/modules/cpq/backend/cpq/inventory/SubscriptionsTable.tsx +22 -26
- package/src/modules/cpq/backend/cpq/inventory/assets/[id]/page.meta.ts +1 -1
- package/src/modules/cpq/backend/cpq/inventory/assets/[id]/page.tsx +43 -46
- package/src/modules/cpq/backend/cpq/inventory/page.meta.ts +2 -2
- package/src/modules/cpq/backend/cpq/inventory/shared.tsx +37 -1
- package/src/modules/cpq/backend/cpq/inventory/subscriptions/[id]/page.meta.ts +1 -1
- package/src/modules/cpq/backend/cpq/inventory/subscriptions/[id]/page.tsx +134 -112
- package/src/modules/cpq/backend/cpq/offerings/[id]/page.tsx +169 -130
- package/src/modules/cpq/backend/cpq/offerings/page.tsx +34 -24
- package/src/modules/cpq/backend/cpq/orders/[id]/page.tsx +66 -43
- package/src/modules/cpq/backend/cpq/orders/page.tsx +6 -6
- package/src/modules/cpq/backend/cpq/price-rules/PriceRuleForm.tsx +48 -34
- package/src/modules/cpq/backend/cpq/price-rules/[id]/page.meta.ts +1 -1
- package/src/modules/cpq/backend/cpq/price-rules/[id]/page.tsx +76 -70
- package/src/modules/cpq/backend/cpq/price-rules/page.tsx +25 -16
- package/src/modules/cpq/backend/cpq/pricing/[id]/EntriesEditor.tsx +24 -18
- package/src/modules/cpq/backend/cpq/pricing/[id]/ImportPreview.tsx +29 -19
- package/src/modules/cpq/backend/cpq/pricing/[id]/page.tsx +95 -47
- package/src/modules/cpq/backend/cpq/pricing/[id]/xlsxImport.ts +23 -15
- package/src/modules/cpq/backend/cpq/pricing/page.tsx +1 -1
- package/src/modules/cpq/backend/cpq/quotes/[id]/_components/ArcQuoteConfigurator.tsx +111 -88
- package/src/modules/cpq/backend/cpq/quotes/[id]/_components/PriceAdjustmentDialog.tsx +3 -3
- package/src/modules/cpq/backend/cpq/quotes/[id]/page.tsx +134 -89
- package/src/modules/cpq/backend/cpq/quotes/page.tsx +29 -21
- package/src/modules/cpq/backend/cpq/specifications/[id]/DependsOnRulesEditor.tsx +19 -15
- package/src/modules/cpq/backend/cpq/specifications/[id]/page.tsx +171 -171
- package/src/modules/cpq/backend/cpq/specifications/page.tsx +2 -2
- package/src/modules/cpq/backend/cpq/wizards/[definitionCode]/detail/page.tsx +51 -41
- package/src/modules/cpq/backend/cpq/wizards/[definitionCode]/page.tsx +17 -13
- package/src/modules/cpq/backend/cpq/wizards/page.tsx +1 -1
- package/src/modules/cpq/components/ArcLineDiff.tsx +2 -2
- package/src/modules/cpq/components/ChargeBreakdownTable.tsx +4 -2
- package/src/modules/cpq/components/PriceWaterfall.tsx +4 -2
- package/src/modules/cpq/components/PricingSummaryCard.tsx +1 -1
- package/src/modules/cpq/components/StatusPath.tsx +7 -4
- package/src/modules/cpq/components/useCpqRowActions.tsx +17 -25
- package/src/modules/cpq/i18n/de.json +1220 -0
- package/src/modules/cpq/i18n/en.json +1220 -0
- package/src/modules/cpq/i18n/es.json +1220 -0
- package/src/modules/cpq/i18n/pl.json +1220 -0
- package/src/modules/cpq/widgets/injection/customer-inventory/widget.client.tsx +38 -31
- package/src/modules/cpq/widgets/injection/order-cpq-tab/widget.client.tsx +7 -5
- package/src/modules/cpq/widgets/injection/quote-configurator/widget.client.tsx +36 -21
- package/src/modules/cpq/widgets/injection-table.ts +8 -2
- package/src/modules/cpq/workflows/WizardRunner.tsx +8 -5
- package/src/modules/cpq/workflows/WizardTrigger.tsx +15 -9
- package/src/modules/cpq/workflows/steps/CustomerSelectStep.tsx +11 -7
- package/src/modules/cpq/workflows/steps/InventorySelectStep.tsx +9 -5
- package/src/modules/cpq/workflows/steps/ItemListStep.tsx +18 -12
- package/src/modules/cpq/workflows/steps/OfferingSelectStep.tsx +20 -16
- package/src/modules/cpq/workflows/steps/ProductConfigureStep.tsx +8 -6
- package/src/modules/cpq/workflows/steps/ReviewStep.tsx +33 -18
- package/src/modules/cpq/workflows/steps/index.ts +12 -0
- package/src/modules/cpq/workflows/types.ts +4 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../../src/modules/cpq/backend/cpq/orders/page.tsx"],
|
|
4
|
-
"sourcesContent": ["\"use client\"\nimport * as React from 'react'\nimport { useRouter } from 'next/navigation'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport type { LegacyColumnDef as ColumnDef } from '@tanstack/react-table/legacy'\nimport type { FilterDef, FilterValues } from '@open-mercato/ui/backend/FilterBar'\nimport { RowActions } from '@open-mercato/ui/backend/RowActions'\nimport { Tag } from '@open-mercato/ui/primitives/tag'\nimport { CpqListView, useCpqListData } from '../../../components/CpqListView'\nimport {\n formatStatusLabel,\n orderCpqStatusMap,\n type OrderCpqStatus,\n} from '../../../components/statusMaps'\n\ntype OrderConfig = {\n id: string\n orderId: string\n orderNumber: string | null\n customerId: string\n cpqStatus: string\n currencyCode: string\n pricingSummary: {\n nrcTotal?: number\n mrcTotal?: number\n } | null\n createdAt: string\n activatedAt: string | null\n}\n\nconst PAGE_SIZE = 50\n\nfunction fmt(amount: number | undefined, currency: string): string {\n if (amount == null || amount === 0) return '\u2014'\n return new Intl.NumberFormat('en-US', { style: 'currency', currency }).format(amount)\n}\n\nfunction buildFilterParams(values: FilterValues, params: URLSearchParams) {\n if (typeof values.cpqStatus === 'string' && values.cpqStatus) {\n params.set('cpqStatus', values.cpqStatus)\n }\n if (typeof values.currencyCode === 'string' && values.currencyCode.trim()) {\n params.set('currencyCode', values.currencyCode.trim().toUpperCase())\n }\n}\n\nexport default function CpqOrdersListPage() {\n const router = useRouter()\n const t = useT()\n\n const data = useCpqListData<OrderConfig>({\n endpoint: '/api/cpq/orders',\n pageSize: PAGE_SIZE,\n buildFilterParams,\n loadErrorMessage: t('cpq.orders.list.error.load', 'Failed to load orders'),\n })\n\n const statusOptions = React.useMemo(\n () => [\n { value: 'draft', label: 'Draft' },\n { value: 'pending_activation', label: 'Pending Activation' },\n { value: 'active', label: 'Active' },\n { value: 'fulfilled', label: 'Fulfilled' },\n { value: 'cancelled', label: 'Cancelled' },\n ],\n [],\n )\n\n const filters = React.useMemo<FilterDef[]>(\n () => [\n {\n id: 'cpqStatus',\n label: t('cpq.orders.filters.status', 'Status'),\n type: 'select',\n options: statusOptions,\n },\n {\n id: 'currencyCode',\n label: t('cpq.orders.filters.currency', 'Currency'),\n type: 'text',\n },\n ],\n [statusOptions, t],\n )\n\n const columns = React.useMemo<ColumnDef<OrderConfig>[]>(\n () => [\n {\n id: 'orderNumber',\n header: t('cpq.orders.table.order', 'Order'),\n cell: ({ row }) => (\n <span className=\"text-sm font-medium text-primary\">\n {row.original.orderNumber ?? `${row.original.orderId?.slice(0, 8)}\u2026`}\n </span>\n ),\n },\n {\n accessorKey: 'cpqStatus',\n header: t('cpq.orders.table.status', 'Status'),\n cell: ({ row }) => (\n <Tag variant={orderCpqStatusMap[row.original.cpqStatus as OrderCpqStatus] ?? 'neutral'} dot>\n {formatStatusLabel(row.original.cpqStatus)}\n </Tag>\n ),\n },\n {\n accessorKey: 'currencyCode',\n header: t('cpq.orders.table.currency', 'Currency'),\n cell: ({ row }) => <span className=\"text-muted-foreground\">{row.original.currencyCode}</span>,\n },\n {\n id: 'nrcTotal',\n header: t('cpq.orders.table.nrcTotal', 'NRC Total'),\n cell: ({ row }) => (\n <span className=\"font-mono text-xs\">\n {fmt(row.original.pricingSummary?.nrcTotal, row.original.currencyCode)}\n </span>\n ),\n },\n {\n id: 'mrcTotal',\n header: t('cpq.orders.table.mrcTotal', 'MRC Total'),\n cell: ({ row }) => (\n <span className=\"font-mono text-xs\">\n {fmt(row.original.pricingSummary?.mrcTotal, row.original.currencyCode)}\n </span>\n ),\n },\n {\n accessorKey: 'createdAt',\n header: t('cpq.orders.table.createdAt', 'Created'),\n cell: ({ row }) => (\n <span className=\"text-xs text-muted-foreground\">\n {new Date(row.original.createdAt).toLocaleDateString()}\n </span>\n ),\n },\n {\n accessorKey: 'activatedAt',\n header: t('cpq.orders.table.activatedAt', 'Activated'),\n cell: ({ row }) => (\n <span className=\"text-xs text-muted-foreground\">\n {row.original.activatedAt ? new Date(row.original.activatedAt).toLocaleDateString() : '\u2014'}\n </span>\n ),\n },\n ],\n [t],\n )\n\n return (\n <CpqListView<OrderConfig>\n title={t('cpq.orders.list.title', 'CPQ Orders')}\n tableId=\"cpq.orders.list\"\n data={data}\n columns={columns}\n filters={filters}\n pageSize={PAGE_SIZE}\n searchPlaceholder={t('cpq.orders.search.placeholder', 'Search by order / customer id...')}\n onRowClick={(row) => router.push(`/backend/cpq/orders/${row.id}`)}\n rowActions={(row) => (\n <RowActions\n items={[\n {\n id: 'open',\n label: t('cpq.orders.actions.open', 'Open'),\n href: `/backend/cpq/orders/${row.id}`,\n },\n ]}\n />\n )}\n emptyState={\n <div className=\"rounded-lg border bg-card p-6 text-center text-sm text-muted-foreground\">\n {t(\n 'cpq.orders.empty',\n 'No CPQ orders found. Convert an accepted quote to create an order.',\n )}\n </div>\n }\n />\n )\n}\n"],
|
|
5
|
-
"mappings": ";AA2FU;AA1FV,YAAY,WAAW;AACvB,SAAS,iBAAiB;AAC1B,SAAS,YAAY;AAGrB,SAAS,kBAAkB;AAC3B,SAAS,WAAW;AACpB,SAAS,aAAa,sBAAsB;AAC5C;AAAA,EACE;AAAA,EACA;AAAA,OAEK;AAiBP,MAAM,YAAY;AAElB,SAAS,IAAI,QAA4B,UAA0B;AACjE,MAAI,UAAU,QAAQ,WAAW,EAAG,QAAO;AAC3C,SAAO,IAAI,KAAK,aAAa,SAAS,EAAE,OAAO,YAAY,SAAS,CAAC,EAAE,OAAO,MAAM;AACtF;AAEA,SAAS,kBAAkB,QAAsB,QAAyB;AACxE,MAAI,OAAO,OAAO,cAAc,YAAY,OAAO,WAAW;AAC5D,WAAO,IAAI,aAAa,OAAO,SAAS;AAAA,EAC1C;AACA,MAAI,OAAO,OAAO,iBAAiB,YAAY,OAAO,aAAa,KAAK,GAAG;AACzE,WAAO,IAAI,gBAAgB,OAAO,aAAa,KAAK,EAAE,YAAY,CAAC;AAAA,EACrE;AACF;AAEe,SAAR,oBAAqC;AAC1C,QAAM,SAAS,UAAU;AACzB,QAAM,IAAI,KAAK;AAEf,QAAM,OAAO,eAA4B;AAAA,IACvC,UAAU;AAAA,IACV,UAAU;AAAA,IACV;AAAA,IACA,kBAAkB,EAAE,8BAA8B,uBAAuB;AAAA,EAC3E,CAAC;AAED,QAAM,gBAAgB,MAAM;AAAA,IAC1B,MAAM;AAAA,MACJ,EAAE,OAAO,SAAS,OAAO,
|
|
4
|
+
"sourcesContent": ["\"use client\"\nimport * as React from 'react'\nimport { useRouter } from 'next/navigation'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport type { LegacyColumnDef as ColumnDef } from '@tanstack/react-table/legacy'\nimport type { FilterDef, FilterValues } from '@open-mercato/ui/backend/FilterBar'\nimport { RowActions } from '@open-mercato/ui/backend/RowActions'\nimport { Tag } from '@open-mercato/ui/primitives/tag'\nimport { CpqListView, useCpqListData } from '../../../components/CpqListView'\nimport {\n formatStatusLabel,\n orderCpqStatusMap,\n type OrderCpqStatus,\n} from '../../../components/statusMaps'\n\ntype OrderConfig = {\n id: string\n orderId: string\n orderNumber: string | null\n customerId: string\n cpqStatus: string\n currencyCode: string\n pricingSummary: {\n nrcTotal?: number\n mrcTotal?: number\n } | null\n createdAt: string\n activatedAt: string | null\n}\n\nconst PAGE_SIZE = 50\n\nfunction fmt(amount: number | undefined, currency: string): string {\n if (amount == null || amount === 0) return '\u2014'\n return new Intl.NumberFormat('en-US', { style: 'currency', currency }).format(amount)\n}\n\nfunction buildFilterParams(values: FilterValues, params: URLSearchParams) {\n if (typeof values.cpqStatus === 'string' && values.cpqStatus) {\n params.set('cpqStatus', values.cpqStatus)\n }\n if (typeof values.currencyCode === 'string' && values.currencyCode.trim()) {\n params.set('currencyCode', values.currencyCode.trim().toUpperCase())\n }\n}\n\nexport default function CpqOrdersListPage() {\n const router = useRouter()\n const t = useT()\n\n const data = useCpqListData<OrderConfig>({\n endpoint: '/api/cpq/orders',\n pageSize: PAGE_SIZE,\n buildFilterParams,\n loadErrorMessage: t('cpq.orders.list.error.load', 'Failed to load orders'),\n })\n\n const statusOptions = React.useMemo(\n () => [\n { value: 'draft', label: t('cpq.orders.status.draft', 'Draft') },\n { value: 'pending_activation', label: t('cpq.orders.status.pending_activation', 'Pending Activation') },\n { value: 'active', label: t('cpq.orders.status.active', 'Active') },\n { value: 'fulfilled', label: t('cpq.orders.status.fulfilled', 'Fulfilled') },\n { value: 'cancelled', label: t('cpq.orders.status.cancelled', 'Cancelled') },\n ],\n [t],\n )\n\n const filters = React.useMemo<FilterDef[]>(\n () => [\n {\n id: 'cpqStatus',\n label: t('cpq.orders.filters.status', 'Status'),\n type: 'select',\n options: statusOptions,\n },\n {\n id: 'currencyCode',\n label: t('cpq.orders.filters.currency', 'Currency'),\n type: 'text',\n },\n ],\n [statusOptions, t],\n )\n\n const columns = React.useMemo<ColumnDef<OrderConfig>[]>(\n () => [\n {\n id: 'orderNumber',\n header: t('cpq.orders.table.order', 'Order'),\n cell: ({ row }) => (\n <span className=\"text-sm font-medium text-primary\">\n {row.original.orderNumber ?? `${row.original.orderId?.slice(0, 8)}\u2026`}\n </span>\n ),\n },\n {\n accessorKey: 'cpqStatus',\n header: t('cpq.orders.table.status', 'Status'),\n cell: ({ row }) => (\n <Tag variant={orderCpqStatusMap[row.original.cpqStatus as OrderCpqStatus] ?? 'neutral'} dot>\n {formatStatusLabel(row.original.cpqStatus)}\n </Tag>\n ),\n },\n {\n accessorKey: 'currencyCode',\n header: t('cpq.orders.table.currency', 'Currency'),\n cell: ({ row }) => <span className=\"text-muted-foreground\">{row.original.currencyCode}</span>,\n },\n {\n id: 'nrcTotal',\n header: t('cpq.orders.table.nrcTotal', 'NRC Total'),\n cell: ({ row }) => (\n <span className=\"font-mono text-xs\">\n {fmt(row.original.pricingSummary?.nrcTotal, row.original.currencyCode)}\n </span>\n ),\n },\n {\n id: 'mrcTotal',\n header: t('cpq.orders.table.mrcTotal', 'MRC Total'),\n cell: ({ row }) => (\n <span className=\"font-mono text-xs\">\n {fmt(row.original.pricingSummary?.mrcTotal, row.original.currencyCode)}\n </span>\n ),\n },\n {\n accessorKey: 'createdAt',\n header: t('cpq.orders.table.createdAt', 'Created'),\n cell: ({ row }) => (\n <span className=\"text-xs text-muted-foreground\">\n {new Date(row.original.createdAt).toLocaleDateString()}\n </span>\n ),\n },\n {\n accessorKey: 'activatedAt',\n header: t('cpq.orders.table.activatedAt', 'Activated'),\n cell: ({ row }) => (\n <span className=\"text-xs text-muted-foreground\">\n {row.original.activatedAt ? new Date(row.original.activatedAt).toLocaleDateString() : '\u2014'}\n </span>\n ),\n },\n ],\n [t],\n )\n\n return (\n <CpqListView<OrderConfig>\n title={t('cpq.orders.list.title', 'CPQ Orders')}\n tableId=\"cpq.orders.list\"\n data={data}\n columns={columns}\n filters={filters}\n pageSize={PAGE_SIZE}\n searchPlaceholder={t('cpq.orders.search.placeholder', 'Search by order / customer id...')}\n onRowClick={(row) => router.push(`/backend/cpq/orders/${row.id}`)}\n rowActions={(row) => (\n <RowActions\n items={[\n {\n id: 'open',\n label: t('cpq.orders.actions.open', 'Open'),\n href: `/backend/cpq/orders/${row.id}`,\n },\n ]}\n />\n )}\n emptyState={\n <div className=\"rounded-lg border bg-card p-6 text-center text-sm text-muted-foreground\">\n {t(\n 'cpq.orders.empty',\n 'No CPQ orders found. Convert an accepted quote to create an order.',\n )}\n </div>\n }\n />\n )\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -10,14 +10,17 @@ import {
|
|
|
10
10
|
SelectTrigger,
|
|
11
11
|
SelectValue
|
|
12
12
|
} from "@open-mercato/ui/primitives/select";
|
|
13
|
+
import { useT } from "@open-mercato/shared/lib/i18n/context";
|
|
13
14
|
import { NumberInput } from "../../../components/NumberInput.js";
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
15
|
+
function buildRuleTypeLabels(t) {
|
|
16
|
+
return {
|
|
17
|
+
discount_percent: t("cpq.priceRules.ruleTypes.discountPercent", "Discount %"),
|
|
18
|
+
discount_absolute: t("cpq.priceRules.ruleTypes.discountAbsolute", "Discount $"),
|
|
19
|
+
surcharge_percent: t("cpq.priceRules.ruleTypes.surchargePercent", "Surcharge %"),
|
|
20
|
+
surcharge_absolute: t("cpq.priceRules.ruleTypes.surchargeAbsolute", "Surcharge $"),
|
|
21
|
+
price_override: t("cpq.priceRules.ruleTypes.priceOverride", "Override")
|
|
22
|
+
};
|
|
23
|
+
}
|
|
21
24
|
const emptyPriceRuleForm = {
|
|
22
25
|
code: "",
|
|
23
26
|
name: "",
|
|
@@ -85,12 +88,14 @@ function PriceRuleForm({
|
|
|
85
88
|
onSave,
|
|
86
89
|
onCancel
|
|
87
90
|
}) {
|
|
91
|
+
const t = useT();
|
|
92
|
+
const ruleTypeLabels = buildRuleTypeLabels(t);
|
|
88
93
|
return /* @__PURE__ */ jsxs("div", { className: "rounded-lg border bg-card p-6 space-y-4", children: [
|
|
89
|
-
/* @__PURE__ */ jsx("h2", { className: "text-lg font-semibold", children: editingId ? "Edit Rule" : "New Rule" }),
|
|
94
|
+
/* @__PURE__ */ jsx("h2", { className: "text-lg font-semibold", children: editingId ? t("cpq.priceRules.form.editTitle", "Edit Rule") : t("cpq.priceRules.form.newTitle", "New Rule") }),
|
|
90
95
|
error && /* @__PURE__ */ jsx("div", { className: "rounded-md bg-destructive/10 p-3 text-sm text-destructive", children: error }),
|
|
91
96
|
/* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-4", children: [
|
|
92
97
|
/* @__PURE__ */ jsxs("label", { className: "space-y-1", children: [
|
|
93
|
-
/* @__PURE__ */ jsx("span", { className: "text-sm font-medium", children: "Code" }),
|
|
98
|
+
/* @__PURE__ */ jsx("span", { className: "text-sm font-medium", children: t("cpq.priceRules.form.code", "Code") }),
|
|
94
99
|
/* @__PURE__ */ jsx(
|
|
95
100
|
Input,
|
|
96
101
|
{
|
|
@@ -101,7 +106,7 @@ function PriceRuleForm({
|
|
|
101
106
|
)
|
|
102
107
|
] }),
|
|
103
108
|
/* @__PURE__ */ jsxs("label", { className: "space-y-1", children: [
|
|
104
|
-
/* @__PURE__ */ jsx("span", { className: "text-sm font-medium", children: "Name" }),
|
|
109
|
+
/* @__PURE__ */ jsx("span", { className: "text-sm font-medium", children: t("cpq.priceRules.form.name", "Name") }),
|
|
105
110
|
/* @__PURE__ */ jsx(
|
|
106
111
|
Input,
|
|
107
112
|
{
|
|
@@ -111,7 +116,7 @@ function PriceRuleForm({
|
|
|
111
116
|
)
|
|
112
117
|
] }),
|
|
113
118
|
/* @__PURE__ */ jsxs("label", { className: "space-y-1", children: [
|
|
114
|
-
/* @__PURE__ */ jsx("span", { className: "text-sm font-medium", children: "Rule Type" }),
|
|
119
|
+
/* @__PURE__ */ jsx("span", { className: "text-sm font-medium", children: t("cpq.priceRules.form.ruleType", "Rule Type") }),
|
|
115
120
|
/* @__PURE__ */ jsxs(
|
|
116
121
|
Select,
|
|
117
122
|
{
|
|
@@ -119,13 +124,13 @@ function PriceRuleForm({
|
|
|
119
124
|
onValueChange: (value) => onFormChange({ ...form, ruleType: value }),
|
|
120
125
|
children: [
|
|
121
126
|
/* @__PURE__ */ jsx(SelectTrigger, { children: /* @__PURE__ */ jsx(SelectValue, {}) }),
|
|
122
|
-
/* @__PURE__ */ jsx(SelectContent, { children: Object.entries(
|
|
127
|
+
/* @__PURE__ */ jsx(SelectContent, { children: Object.entries(ruleTypeLabels).map(([k, v]) => /* @__PURE__ */ jsx(SelectItem, { value: k, children: v }, k)) })
|
|
123
128
|
]
|
|
124
129
|
}
|
|
125
130
|
)
|
|
126
131
|
] }),
|
|
127
132
|
/* @__PURE__ */ jsxs("label", { className: "space-y-1", children: [
|
|
128
|
-
/* @__PURE__ */ jsx("span", { className: "text-sm font-medium", children: "Value" }),
|
|
133
|
+
/* @__PURE__ */ jsx("span", { className: "text-sm font-medium", children: t("cpq.priceRules.form.value", "Value") }),
|
|
129
134
|
/* @__PURE__ */ jsx(
|
|
130
135
|
NumberInput,
|
|
131
136
|
{
|
|
@@ -135,7 +140,7 @@ function PriceRuleForm({
|
|
|
135
140
|
)
|
|
136
141
|
] }),
|
|
137
142
|
/* @__PURE__ */ jsxs("label", { className: "space-y-1", children: [
|
|
138
|
-
/* @__PURE__ */ jsx("span", { className: "text-sm font-medium", children: "Charge Type Filter" }),
|
|
143
|
+
/* @__PURE__ */ jsx("span", { className: "text-sm font-medium", children: t("cpq.priceRules.form.chargeTypeFilter", "Charge Type Filter") }),
|
|
139
144
|
/* @__PURE__ */ jsxs(
|
|
140
145
|
Select,
|
|
141
146
|
{
|
|
@@ -144,28 +149,28 @@ function PriceRuleForm({
|
|
|
144
149
|
children: [
|
|
145
150
|
/* @__PURE__ */ jsx(SelectTrigger, { children: /* @__PURE__ */ jsx(SelectValue, {}) }),
|
|
146
151
|
/* @__PURE__ */ jsxs(SelectContent, { children: [
|
|
147
|
-
/* @__PURE__ */ jsx(SelectItem, { value: "__all__", children: "All charge types" }),
|
|
148
|
-
/* @__PURE__ */ jsx(SelectItem, { value: "nrc", children: "NRC only" }),
|
|
149
|
-
/* @__PURE__ */ jsx(SelectItem, { value: "mrc", children: "MRC only" }),
|
|
150
|
-
/* @__PURE__ */ jsx(SelectItem, { value: "usage", children: "Usage only" })
|
|
152
|
+
/* @__PURE__ */ jsx(SelectItem, { value: "__all__", children: t("cpq.priceRules.form.allChargeTypes", "All charge types") }),
|
|
153
|
+
/* @__PURE__ */ jsx(SelectItem, { value: "nrc", children: t("cpq.priceRules.form.nrcOnly", "NRC only") }),
|
|
154
|
+
/* @__PURE__ */ jsx(SelectItem, { value: "mrc", children: t("cpq.priceRules.form.mrcOnly", "MRC only") }),
|
|
155
|
+
/* @__PURE__ */ jsx(SelectItem, { value: "usage", children: t("cpq.priceRules.form.usageOnly", "Usage only") })
|
|
151
156
|
] })
|
|
152
157
|
]
|
|
153
158
|
}
|
|
154
159
|
)
|
|
155
160
|
] }),
|
|
156
161
|
/* @__PURE__ */ jsxs("label", { className: "space-y-1", children: [
|
|
157
|
-
/* @__PURE__ */ jsx("span", { className: "text-sm font-medium", children: "Charge Code Filter" }),
|
|
162
|
+
/* @__PURE__ */ jsx("span", { className: "text-sm font-medium", children: t("cpq.priceRules.form.chargeCodeFilter", "Charge Code Filter") }),
|
|
158
163
|
/* @__PURE__ */ jsx(
|
|
159
164
|
Input,
|
|
160
165
|
{
|
|
161
|
-
placeholder: "e.g. setup_fee (leave empty for all)",
|
|
166
|
+
placeholder: t("cpq.priceRules.form.chargeCodeFilterPlaceholder", "e.g. setup_fee (leave empty for all)"),
|
|
162
167
|
value: form.chargeCodeFilter,
|
|
163
168
|
onChange: (e) => onFormChange({ ...form, chargeCodeFilter: e.target.value })
|
|
164
169
|
}
|
|
165
170
|
)
|
|
166
171
|
] }),
|
|
167
172
|
/* @__PURE__ */ jsxs("label", { className: "space-y-1", children: [
|
|
168
|
-
/* @__PURE__ */ jsx("span", { className: "text-sm font-medium", children: "Sort Order" }),
|
|
173
|
+
/* @__PURE__ */ jsx("span", { className: "text-sm font-medium", children: t("cpq.priceRules.form.sortOrder", "Sort Order") }),
|
|
169
174
|
/* @__PURE__ */ jsx(
|
|
170
175
|
NumberInput,
|
|
171
176
|
{
|
|
@@ -176,18 +181,18 @@ function PriceRuleForm({
|
|
|
176
181
|
)
|
|
177
182
|
] }),
|
|
178
183
|
/* @__PURE__ */ jsxs("label", { className: "space-y-1", children: [
|
|
179
|
-
/* @__PURE__ */ jsx("span", { className: "text-sm font-medium", children: "Description" }),
|
|
184
|
+
/* @__PURE__ */ jsx("span", { className: "text-sm font-medium", children: t("cpq.priceRules.form.description", "Description") }),
|
|
180
185
|
/* @__PURE__ */ jsx(
|
|
181
186
|
Input,
|
|
182
187
|
{
|
|
183
|
-
placeholder: "Optional",
|
|
188
|
+
placeholder: t("cpq.priceRules.form.descriptionPlaceholder", "Optional"),
|
|
184
189
|
value: form.description,
|
|
185
190
|
onChange: (e) => onFormChange({ ...form, description: e.target.value })
|
|
186
191
|
}
|
|
187
192
|
)
|
|
188
193
|
] }),
|
|
189
194
|
/* @__PURE__ */ jsxs("label", { className: "space-y-1 col-span-2", children: [
|
|
190
|
-
/* @__PURE__ */ jsx("span", { className: "text-sm font-medium", children: "Product Offering" }),
|
|
195
|
+
/* @__PURE__ */ jsx("span", { className: "text-sm font-medium", children: t("cpq.priceRules.form.productOffering", "Product Offering") }),
|
|
191
196
|
/* @__PURE__ */ jsxs(
|
|
192
197
|
Select,
|
|
193
198
|
{
|
|
@@ -196,7 +201,7 @@ function PriceRuleForm({
|
|
|
196
201
|
children: [
|
|
197
202
|
/* @__PURE__ */ jsx(SelectTrigger, { children: /* @__PURE__ */ jsx(SelectValue, {}) }),
|
|
198
203
|
/* @__PURE__ */ jsxs(SelectContent, { children: [
|
|
199
|
-
/* @__PURE__ */ jsx(SelectItem, { value: "__global__", children: "Global (all products)" }),
|
|
204
|
+
/* @__PURE__ */ jsx(SelectItem, { value: "__global__", children: t("cpq.priceRules.form.globalAllProducts", "Global (all products)") }),
|
|
200
205
|
offerings.map((o) => /* @__PURE__ */ jsxs(SelectItem, { value: o.id, children: [
|
|
201
206
|
o.name,
|
|
202
207
|
" (",
|
|
@@ -207,16 +212,16 @@ function PriceRuleForm({
|
|
|
207
212
|
]
|
|
208
213
|
}
|
|
209
214
|
),
|
|
210
|
-
/* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: 'Leave as "Global" to apply to all products, or select a specific offering' })
|
|
215
|
+
/* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: t("cpq.priceRules.form.productOfferingHint", 'Leave as "Global" to apply to all products, or select a specific offering') })
|
|
211
216
|
] }),
|
|
212
217
|
/* @__PURE__ */ jsxs("div", { className: "col-span-2 space-y-1", children: [
|
|
213
|
-
/* @__PURE__ */ jsx("span", { className: "text-sm font-medium", children: "Applicability Condition" }),
|
|
214
|
-
/* @__PURE__ */ jsx("span", { className: "ml-2 text-xs text-muted-foreground", children: "(optional \u2014 only apply when a product attribute matches)" }),
|
|
218
|
+
/* @__PURE__ */ jsx("span", { className: "text-sm font-medium", children: t("cpq.priceRules.form.applicabilityCondition", "Applicability Condition") }),
|
|
219
|
+
/* @__PURE__ */ jsx("span", { className: "ml-2 text-xs text-muted-foreground", children: t("cpq.priceRules.form.applicabilityConditionHint", "(optional \u2014 only apply when a product attribute matches)") }),
|
|
215
220
|
/* @__PURE__ */ jsxs("div", { className: "grid grid-cols-3 gap-2", children: [
|
|
216
221
|
/* @__PURE__ */ jsx(
|
|
217
222
|
Input,
|
|
218
223
|
{
|
|
219
|
-
placeholder: "Attribute (e.g. port_size)",
|
|
224
|
+
placeholder: t("cpq.priceRules.form.conditionAttributePlaceholder", "Attribute (e.g. port_size)"),
|
|
220
225
|
value: form.conditionAttribute,
|
|
221
226
|
onChange: (e) => onFormChange({ ...form, conditionAttribute: e.target.value })
|
|
222
227
|
}
|
|
@@ -229,8 +234,8 @@ function PriceRuleForm({
|
|
|
229
234
|
children: [
|
|
230
235
|
/* @__PURE__ */ jsx(SelectTrigger, { children: /* @__PURE__ */ jsx(SelectValue, {}) }),
|
|
231
236
|
/* @__PURE__ */ jsxs(SelectContent, { children: [
|
|
232
|
-
/* @__PURE__ */ jsx(SelectItem, { value: "eq", children: "equals (=)" }),
|
|
233
|
-
/* @__PURE__ */ jsx(SelectItem, { value: "neq", children: "not equals (\u2260)" })
|
|
237
|
+
/* @__PURE__ */ jsx(SelectItem, { value: "eq", children: t("cpq.priceRules.form.operatorEq", "equals (=)") }),
|
|
238
|
+
/* @__PURE__ */ jsx(SelectItem, { value: "neq", children: t("cpq.priceRules.form.operatorNeq", "not equals (\u2260)") })
|
|
234
239
|
] })
|
|
235
240
|
]
|
|
236
241
|
}
|
|
@@ -238,7 +243,7 @@ function PriceRuleForm({
|
|
|
238
243
|
/* @__PURE__ */ jsx(
|
|
239
244
|
Input,
|
|
240
245
|
{
|
|
241
|
-
placeholder: "Value (e.g. 100G)",
|
|
246
|
+
placeholder: t("cpq.priceRules.form.conditionValuePlaceholder", "Value (e.g. 100G)"),
|
|
242
247
|
value: form.conditionValue,
|
|
243
248
|
onChange: (e) => onFormChange({ ...form, conditionValue: e.target.value })
|
|
244
249
|
}
|
|
@@ -254,17 +259,17 @@ function PriceRuleForm({
|
|
|
254
259
|
onCheckedChange: (checked) => onFormChange({ ...form, isActive: checked === true })
|
|
255
260
|
}
|
|
256
261
|
),
|
|
257
|
-
"Active"
|
|
262
|
+
t("cpq.common.active", "Active")
|
|
258
263
|
] }),
|
|
259
264
|
/* @__PURE__ */ jsxs("div", { className: "flex gap-2", children: [
|
|
260
|
-
/* @__PURE__ */ jsx(Button, { type: "button", onClick: onSave, disabled: saving, children: saving ? "Saving..." : editingId ? "Update" : "Create" }),
|
|
261
|
-
/* @__PURE__ */ jsx(Button, { type: "button", variant: "outline", onClick: onCancel, children: "Cancel" })
|
|
265
|
+
/* @__PURE__ */ jsx(Button, { type: "button", onClick: onSave, disabled: saving, children: saving ? t("cpq.common.saving", "Saving...") : editingId ? t("cpq.priceRules.form.update", "Update") : t("cpq.priceRules.form.create", "Create") }),
|
|
266
|
+
/* @__PURE__ */ jsx(Button, { type: "button", variant: "outline", onClick: onCancel, children: t("cpq.common.cancel", "Cancel") })
|
|
262
267
|
] })
|
|
263
268
|
] });
|
|
264
269
|
}
|
|
265
270
|
export {
|
|
266
271
|
PriceRuleForm,
|
|
267
|
-
|
|
272
|
+
buildRuleTypeLabels,
|
|
268
273
|
emptyPriceRuleForm,
|
|
269
274
|
priceRuleFormToPayload,
|
|
270
275
|
priceRuleToFormData
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../../src/modules/cpq/backend/cpq/price-rules/PriceRuleForm.tsx"],
|
|
4
|
-
"sourcesContent": ["\"use client\"\nimport * as React from 'react'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { Checkbox } from '@open-mercato/ui/primitives/checkbox'\nimport { Input } from '@open-mercato/ui/primitives/input'\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from '@open-mercato/ui/primitives/select'\nimport { NumberInput } from '../../../components/NumberInput'\n\n// \u2500\u2500\u2500 Shared 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\n\nexport const RULE_TYPE_LABELS: Record<string, string> = {\n discount_percent: 'Discount %',\n discount_absolute: 'Discount $',\n surcharge_percent: 'Surcharge %',\n surcharge_absolute: 'Surcharge $',\n price_override: 'Override',\n}\n\nexport type PriceRuleApplicabilityCondition = {\n attribute?: string\n operator?: string\n value?: string\n}\n\nexport type PriceRule = {\n id: string\n code: string\n name: string\n description: string | null\n productOfferingId: string | null\n productOfferingName: string | null\n ruleType: string\n value: number\n chargeCodeFilter: string | null\n chargeTypeFilter: string | null\n applicabilityCondition: Record<string, unknown> | null\n sortOrder: number\n isActive: boolean\n}\n\nexport type ProductOffering = { id: string; code: string; name: string }\n\nexport type PriceRuleFormData = {\n code: string\n name: string\n description: string\n productOfferingId: string\n ruleType: string\n value: string\n chargeCodeFilter: string\n chargeTypeFilter: string\n conditionAttribute: string\n conditionOperator: string\n conditionValue: string\n sortOrder: string\n isActive: boolean\n}\n\nexport const emptyPriceRuleForm: PriceRuleFormData = {\n code: '',\n name: '',\n description: '',\n productOfferingId: '',\n ruleType: 'discount_percent',\n value: '',\n chargeCodeFilter: '',\n chargeTypeFilter: '',\n conditionAttribute: '',\n conditionOperator: 'eq',\n conditionValue: '',\n sortOrder: '0',\n isActive: true,\n}\n\nexport function priceRuleToFormData(rule: PriceRule): PriceRuleFormData {\n const cond = rule.applicabilityCondition as PriceRuleApplicabilityCondition | null\n return {\n code: rule.code,\n name: rule.name,\n description: rule.description ?? '',\n productOfferingId: rule.productOfferingId ?? '',\n ruleType: rule.ruleType,\n value: String(rule.value),\n chargeCodeFilter: rule.chargeCodeFilter ?? '',\n chargeTypeFilter: rule.chargeTypeFilter ?? '',\n conditionAttribute: cond?.attribute ?? '',\n conditionOperator: cond?.operator ?? 'eq',\n conditionValue: cond?.value ?? '',\n sortOrder: String(rule.sortOrder),\n isActive: rule.isActive,\n }\n}\n\nexport function priceRuleFormToPayload(form: PriceRuleFormData): Record<string, unknown> {\n const payload: Record<string, unknown> = {\n code: form.code,\n name: form.name,\n ruleType: form.ruleType,\n value: Number(form.value),\n sortOrder: Number(form.sortOrder),\n isActive: form.isActive,\n productOfferingId: form.productOfferingId || null,\n }\n if (form.description) payload.description = form.description\n if (form.chargeCodeFilter) payload.chargeCodeFilter = form.chargeCodeFilter\n if (form.chargeTypeFilter) payload.chargeTypeFilter = form.chargeTypeFilter\n if (form.conditionAttribute) {\n payload.applicabilityCondition = {\n attribute: form.conditionAttribute,\n operator: form.conditionOperator || 'eq',\n value: form.conditionValue,\n }\n } else {\n payload.applicabilityCondition = null\n }\n return payload\n}\n\n// \u2500\u2500\u2500 Form component \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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 PriceRuleFormProps = {\n editingId: string | null\n form: PriceRuleFormData\n onFormChange: (next: PriceRuleFormData) => void\n offerings: ProductOffering[]\n saving: boolean\n error: string | null\n onSave: () => void\n onCancel: () => void\n}\n\nexport function PriceRuleForm({\n editingId,\n form,\n onFormChange,\n offerings,\n saving,\n error,\n onSave,\n onCancel,\n}: PriceRuleFormProps) {\n return (\n <div className=\"rounded-lg border bg-card p-6 space-y-4\">\n <h2 className=\"text-lg font-semibold\">{editingId ? 'Edit Rule' : 'New Rule'}</h2>\n {error && (\n <div className=\"rounded-md bg-destructive/10 p-3 text-sm text-destructive\">{error}</div>\n )}\n <div className=\"grid grid-cols-2 gap-4\">\n <label className=\"space-y-1\">\n <span className=\"text-sm font-medium\">Code</span>\n <Input\n value={form.code}\n onChange={(e) => onFormChange({ ...form, code: e.target.value })}\n disabled={!!editingId}\n />\n </label>\n <label className=\"space-y-1\">\n <span className=\"text-sm font-medium\">Name</span>\n <Input\n value={form.name}\n onChange={(e) => onFormChange({ ...form, name: e.target.value })}\n />\n </label>\n <label className=\"space-y-1\">\n <span className=\"text-sm font-medium\">Rule Type</span>\n <Select\n value={form.ruleType}\n onValueChange={(value) => onFormChange({ ...form, ruleType: value })}\n >\n <SelectTrigger>\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {Object.entries(RULE_TYPE_LABELS).map(([k, v]) => (\n <SelectItem key={k} value={k}>\n {v}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </label>\n <label className=\"space-y-1\">\n <span className=\"text-sm font-medium\">Value</span>\n <NumberInput\n value={form.value === '' ? null : Number(form.value)}\n onChange={(n) => onFormChange({ ...form, value: n == null ? '' : String(n) })}\n />\n </label>\n <label className=\"space-y-1\">\n <span className=\"text-sm font-medium\">Charge Type Filter</span>\n <Select\n value={form.chargeTypeFilter || '__all__'}\n onValueChange={(value) =>\n onFormChange({ ...form, chargeTypeFilter: value === '__all__' ? '' : value })\n }\n >\n <SelectTrigger>\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"__all__\">All charge types</SelectItem>\n <SelectItem value=\"nrc\">NRC only</SelectItem>\n <SelectItem value=\"mrc\">MRC only</SelectItem>\n <SelectItem value=\"usage\">Usage only</SelectItem>\n </SelectContent>\n </Select>\n </label>\n <label className=\"space-y-1\">\n <span className=\"text-sm font-medium\">Charge Code Filter</span>\n <Input\n placeholder=\"e.g. setup_fee (leave empty for all)\"\n value={form.chargeCodeFilter}\n onChange={(e) => onFormChange({ ...form, chargeCodeFilter: e.target.value })}\n />\n </label>\n <label className=\"space-y-1\">\n <span className=\"text-sm font-medium\">Sort Order</span>\n <NumberInput\n integer\n value={form.sortOrder === '' ? null : Number(form.sortOrder)}\n onChange={(n) => onFormChange({ ...form, sortOrder: n == null ? '' : String(n) })}\n />\n </label>\n <label className=\"space-y-1\">\n <span className=\"text-sm font-medium\">Description</span>\n <Input\n placeholder=\"Optional\"\n value={form.description}\n onChange={(e) => onFormChange({ ...form, description: e.target.value })}\n />\n </label>\n <label className=\"space-y-1 col-span-2\">\n <span className=\"text-sm font-medium\">Product Offering</span>\n <Select\n value={form.productOfferingId || '__global__'}\n onValueChange={(value) =>\n onFormChange({ ...form, productOfferingId: value === '__global__' ? '' : value })\n }\n >\n <SelectTrigger>\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"__global__\">Global (all products)</SelectItem>\n {offerings.map((o) => (\n <SelectItem key={o.id} value={o.id}>\n {o.name} ({o.code})\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n <span className=\"text-xs text-muted-foreground\">\n Leave as "Global" to apply to all products, or select a specific offering\n </span>\n </label>\n <div className=\"col-span-2 space-y-1\">\n <span className=\"text-sm font-medium\">Applicability Condition</span>\n <span className=\"ml-2 text-xs text-muted-foreground\">\n (optional \u2014 only apply when a product attribute matches)\n </span>\n <div className=\"grid grid-cols-3 gap-2\">\n <Input\n placeholder=\"Attribute (e.g. port_size)\"\n value={form.conditionAttribute}\n onChange={(e) => onFormChange({ ...form, conditionAttribute: e.target.value })}\n />\n <Select\n value={form.conditionOperator}\n onValueChange={(value) => onFormChange({ ...form, conditionOperator: value })}\n >\n <SelectTrigger>\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"eq\">equals (=)</SelectItem>\n <SelectItem value=\"neq\">not equals (\u2260)</SelectItem>\n </SelectContent>\n </Select>\n <Input\n placeholder=\"Value (e.g. 100G)\"\n value={form.conditionValue}\n onChange={(e) => onFormChange({ ...form, conditionValue: e.target.value })}\n />\n </div>\n </div>\n </div>\n <label className=\"flex items-center gap-2 text-sm\">\n <Checkbox\n checked={form.isActive}\n onCheckedChange={(checked) => onFormChange({ ...form, isActive: checked === true })}\n />\n Active\n </label>\n <div className=\"flex gap-2\">\n <Button type=\"button\" onClick={onSave} disabled={saving}>\n {saving ? 'Saving...' : editingId ? 'Update' : 'Create'}\n </Button>\n <Button type=\"button\" variant=\"outline\" onClick={onCancel}>\n Cancel\n </Button>\n </div>\n </div>\n )\n}\n"],
|
|
5
|
-
"mappings": ";
|
|
4
|
+
"sourcesContent": ["\"use client\"\nimport * as React from 'react'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { Checkbox } from '@open-mercato/ui/primitives/checkbox'\nimport { Input } from '@open-mercato/ui/primitives/input'\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from '@open-mercato/ui/primitives/select'\nimport { useT, type TranslateFn } from '@open-mercato/shared/lib/i18n/context'\nimport { NumberInput } from '../../../components/NumberInput'\n\n// \u2500\u2500\u2500 Shared 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\n\n/**\n * Display labels for price-rule types, keyed by the persisted `ruleType`\n * value. Single translatable source shared by the list, the create form and\n * the detail page \u2014 call inside render with the component's `t`.\n */\nexport function buildRuleTypeLabels(t: TranslateFn): Record<string, string> {\n return {\n discount_percent: t('cpq.priceRules.ruleTypes.discountPercent', 'Discount %'),\n discount_absolute: t('cpq.priceRules.ruleTypes.discountAbsolute', 'Discount $'),\n surcharge_percent: t('cpq.priceRules.ruleTypes.surchargePercent', 'Surcharge %'),\n surcharge_absolute: t('cpq.priceRules.ruleTypes.surchargeAbsolute', 'Surcharge $'),\n price_override: t('cpq.priceRules.ruleTypes.priceOverride', 'Override'),\n }\n}\n\nexport type PriceRuleApplicabilityCondition = {\n attribute?: string\n operator?: string\n value?: string\n}\n\nexport type PriceRule = {\n id: string\n code: string\n name: string\n description: string | null\n productOfferingId: string | null\n productOfferingName: string | null\n ruleType: string\n value: number\n chargeCodeFilter: string | null\n chargeTypeFilter: string | null\n applicabilityCondition: Record<string, unknown> | null\n sortOrder: number\n isActive: boolean\n}\n\nexport type ProductOffering = { id: string; code: string; name: string }\n\nexport type PriceRuleFormData = {\n code: string\n name: string\n description: string\n productOfferingId: string\n ruleType: string\n value: string\n chargeCodeFilter: string\n chargeTypeFilter: string\n conditionAttribute: string\n conditionOperator: string\n conditionValue: string\n sortOrder: string\n isActive: boolean\n}\n\nexport const emptyPriceRuleForm: PriceRuleFormData = {\n code: '',\n name: '',\n description: '',\n productOfferingId: '',\n ruleType: 'discount_percent',\n value: '',\n chargeCodeFilter: '',\n chargeTypeFilter: '',\n conditionAttribute: '',\n conditionOperator: 'eq',\n conditionValue: '',\n sortOrder: '0',\n isActive: true,\n}\n\nexport function priceRuleToFormData(rule: PriceRule): PriceRuleFormData {\n const cond = rule.applicabilityCondition as PriceRuleApplicabilityCondition | null\n return {\n code: rule.code,\n name: rule.name,\n description: rule.description ?? '',\n productOfferingId: rule.productOfferingId ?? '',\n ruleType: rule.ruleType,\n value: String(rule.value),\n chargeCodeFilter: rule.chargeCodeFilter ?? '',\n chargeTypeFilter: rule.chargeTypeFilter ?? '',\n conditionAttribute: cond?.attribute ?? '',\n conditionOperator: cond?.operator ?? 'eq',\n conditionValue: cond?.value ?? '',\n sortOrder: String(rule.sortOrder),\n isActive: rule.isActive,\n }\n}\n\nexport function priceRuleFormToPayload(form: PriceRuleFormData): Record<string, unknown> {\n const payload: Record<string, unknown> = {\n code: form.code,\n name: form.name,\n ruleType: form.ruleType,\n value: Number(form.value),\n sortOrder: Number(form.sortOrder),\n isActive: form.isActive,\n productOfferingId: form.productOfferingId || null,\n }\n if (form.description) payload.description = form.description\n if (form.chargeCodeFilter) payload.chargeCodeFilter = form.chargeCodeFilter\n if (form.chargeTypeFilter) payload.chargeTypeFilter = form.chargeTypeFilter\n if (form.conditionAttribute) {\n payload.applicabilityCondition = {\n attribute: form.conditionAttribute,\n operator: form.conditionOperator || 'eq',\n value: form.conditionValue,\n }\n } else {\n payload.applicabilityCondition = null\n }\n return payload\n}\n\n// \u2500\u2500\u2500 Form component \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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 PriceRuleFormProps = {\n editingId: string | null\n form: PriceRuleFormData\n onFormChange: (next: PriceRuleFormData) => void\n offerings: ProductOffering[]\n saving: boolean\n error: string | null\n onSave: () => void\n onCancel: () => void\n}\n\nexport function PriceRuleForm({\n editingId,\n form,\n onFormChange,\n offerings,\n saving,\n error,\n onSave,\n onCancel,\n}: PriceRuleFormProps) {\n const t = useT()\n const ruleTypeLabels = buildRuleTypeLabels(t)\n return (\n <div className=\"rounded-lg border bg-card p-6 space-y-4\">\n <h2 className=\"text-lg font-semibold\">{editingId ? t('cpq.priceRules.form.editTitle', 'Edit Rule') : t('cpq.priceRules.form.newTitle', 'New Rule')}</h2>\n {error && (\n <div className=\"rounded-md bg-destructive/10 p-3 text-sm text-destructive\">{error}</div>\n )}\n <div className=\"grid grid-cols-2 gap-4\">\n <label className=\"space-y-1\">\n <span className=\"text-sm font-medium\">{t('cpq.priceRules.form.code', 'Code')}</span>\n <Input\n value={form.code}\n onChange={(e) => onFormChange({ ...form, code: e.target.value })}\n disabled={!!editingId}\n />\n </label>\n <label className=\"space-y-1\">\n <span className=\"text-sm font-medium\">{t('cpq.priceRules.form.name', 'Name')}</span>\n <Input\n value={form.name}\n onChange={(e) => onFormChange({ ...form, name: e.target.value })}\n />\n </label>\n <label className=\"space-y-1\">\n <span className=\"text-sm font-medium\">{t('cpq.priceRules.form.ruleType', 'Rule Type')}</span>\n <Select\n value={form.ruleType}\n onValueChange={(value) => onFormChange({ ...form, ruleType: value })}\n >\n <SelectTrigger>\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {Object.entries(ruleTypeLabels).map(([k, v]) => (\n <SelectItem key={k} value={k}>\n {v}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </label>\n <label className=\"space-y-1\">\n <span className=\"text-sm font-medium\">{t('cpq.priceRules.form.value', 'Value')}</span>\n <NumberInput\n value={form.value === '' ? null : Number(form.value)}\n onChange={(n) => onFormChange({ ...form, value: n == null ? '' : String(n) })}\n />\n </label>\n <label className=\"space-y-1\">\n <span className=\"text-sm font-medium\">{t('cpq.priceRules.form.chargeTypeFilter', 'Charge Type Filter')}</span>\n <Select\n value={form.chargeTypeFilter || '__all__'}\n onValueChange={(value) =>\n onFormChange({ ...form, chargeTypeFilter: value === '__all__' ? '' : value })\n }\n >\n <SelectTrigger>\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"__all__\">{t('cpq.priceRules.form.allChargeTypes', 'All charge types')}</SelectItem>\n <SelectItem value=\"nrc\">{t('cpq.priceRules.form.nrcOnly', 'NRC only')}</SelectItem>\n <SelectItem value=\"mrc\">{t('cpq.priceRules.form.mrcOnly', 'MRC only')}</SelectItem>\n <SelectItem value=\"usage\">{t('cpq.priceRules.form.usageOnly', 'Usage only')}</SelectItem>\n </SelectContent>\n </Select>\n </label>\n <label className=\"space-y-1\">\n <span className=\"text-sm font-medium\">{t('cpq.priceRules.form.chargeCodeFilter', 'Charge Code Filter')}</span>\n <Input\n placeholder={t('cpq.priceRules.form.chargeCodeFilterPlaceholder', 'e.g. setup_fee (leave empty for all)')}\n value={form.chargeCodeFilter}\n onChange={(e) => onFormChange({ ...form, chargeCodeFilter: e.target.value })}\n />\n </label>\n <label className=\"space-y-1\">\n <span className=\"text-sm font-medium\">{t('cpq.priceRules.form.sortOrder', 'Sort Order')}</span>\n <NumberInput\n integer\n value={form.sortOrder === '' ? null : Number(form.sortOrder)}\n onChange={(n) => onFormChange({ ...form, sortOrder: n == null ? '' : String(n) })}\n />\n </label>\n <label className=\"space-y-1\">\n <span className=\"text-sm font-medium\">{t('cpq.priceRules.form.description', 'Description')}</span>\n <Input\n placeholder={t('cpq.priceRules.form.descriptionPlaceholder', 'Optional')}\n value={form.description}\n onChange={(e) => onFormChange({ ...form, description: e.target.value })}\n />\n </label>\n <label className=\"space-y-1 col-span-2\">\n <span className=\"text-sm font-medium\">{t('cpq.priceRules.form.productOffering', 'Product Offering')}</span>\n <Select\n value={form.productOfferingId || '__global__'}\n onValueChange={(value) =>\n onFormChange({ ...form, productOfferingId: value === '__global__' ? '' : value })\n }\n >\n <SelectTrigger>\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"__global__\">{t('cpq.priceRules.form.globalAllProducts', 'Global (all products)')}</SelectItem>\n {offerings.map((o) => (\n <SelectItem key={o.id} value={o.id}>\n {o.name} ({o.code})\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n <span className=\"text-xs text-muted-foreground\">\n {t('cpq.priceRules.form.productOfferingHint', 'Leave as \"Global\" to apply to all products, or select a specific offering')}\n </span>\n </label>\n <div className=\"col-span-2 space-y-1\">\n <span className=\"text-sm font-medium\">{t('cpq.priceRules.form.applicabilityCondition', 'Applicability Condition')}</span>\n <span className=\"ml-2 text-xs text-muted-foreground\">\n {t('cpq.priceRules.form.applicabilityConditionHint', '(optional \u2014 only apply when a product attribute matches)')}\n </span>\n <div className=\"grid grid-cols-3 gap-2\">\n <Input\n placeholder={t('cpq.priceRules.form.conditionAttributePlaceholder', 'Attribute (e.g. port_size)')}\n value={form.conditionAttribute}\n onChange={(e) => onFormChange({ ...form, conditionAttribute: e.target.value })}\n />\n <Select\n value={form.conditionOperator}\n onValueChange={(value) => onFormChange({ ...form, conditionOperator: value })}\n >\n <SelectTrigger>\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"eq\">{t('cpq.priceRules.form.operatorEq', 'equals (=)')}</SelectItem>\n <SelectItem value=\"neq\">{t('cpq.priceRules.form.operatorNeq', 'not equals (\u2260)')}</SelectItem>\n </SelectContent>\n </Select>\n <Input\n placeholder={t('cpq.priceRules.form.conditionValuePlaceholder', 'Value (e.g. 100G)')}\n value={form.conditionValue}\n onChange={(e) => onFormChange({ ...form, conditionValue: e.target.value })}\n />\n </div>\n </div>\n </div>\n <label className=\"flex items-center gap-2 text-sm\">\n <Checkbox\n checked={form.isActive}\n onCheckedChange={(checked) => onFormChange({ ...form, isActive: checked === true })}\n />\n {t('cpq.common.active', 'Active')}\n </label>\n <div className=\"flex gap-2\">\n <Button type=\"button\" onClick={onSave} disabled={saving}>\n {saving\n ? t('cpq.common.saving', 'Saving...')\n : editingId\n ? t('cpq.priceRules.form.update', 'Update')\n : t('cpq.priceRules.form.create', 'Create')}\n </Button>\n <Button type=\"button\" variant=\"outline\" onClick={onCancel}>\n {t('cpq.common.cancel', 'Cancel')}\n </Button>\n </div>\n </div>\n )\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|