@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
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../../../../src/modules/cpq/backend/cpq/quotes/%5Bid%5D/_components/ArcQuoteConfigurator.tsx"],
4
- "sourcesContent": ["\"use client\"\nimport * as React from 'react'\nimport { Alert } from '@open-mercato/ui/primitives/alert'\nimport { NumberInput as BaseNumberInput } from '../../../../../components/NumberInput'\n\n// XD-250 \u2014 ARC configurator drawer.\n//\n// Self-contained right-side drawer: action selection \u2192 target picker \u2192\n// renew/cancel config \u2192 review \u2192 submit. The host quote detail page renders\n// it on demand and refetches when the drawer reports `onChanged`.\n\ntype ArcType = 'amend' | 'renew' | 'cancel'\ntype Step =\n | 'pick-action'\n | 'pick-targets'\n | 'config-renew'\n | 'config-cancel'\n | 'review'\n | 'submitting'\n | 'done'\n\ntype EligibleSub = {\n id: string\n code: string\n name: string\n status: string\n currencyCode: string\n billingCycle: string\n currentTermEnd: string | null\n mrcAmount: number\n}\n\nexport type AttachedTarget = {\n id: string\n subscriptionId: string\n quoteType: string\n mergeAction: string | null\n newTermStart: string | null\n newTermEnd: string | null\n newTermMonths: number | null\n subscription: {\n code: string\n name: string\n currencyCode: string\n billingCycle: string\n mrcAmount: number\n } | null\n}\n\nexport interface ArcQuoteConfiguratorProps {\n quoteId: string\n customerId: string\n customerName: string | null\n currencyCode: string\n initialType: 'new' | ArcType\n initialTargets: AttachedTarget[]\n editable: boolean\n onClose: () => void\n onChanged: () => void | Promise<void>\n}\n\nconst REASON_CODES = [\n { value: 'upgrade', label: 'Upgrade' },\n { value: 'downgrade', label: 'Downgrade' },\n { value: 'config-change', label: 'Configuration change' },\n { value: 'price-adjustment', label: 'Price adjustment' },\n { value: 'term-extension', label: 'Term extension' },\n { value: 'term-reduction', label: 'Term reduction' },\n { value: 'consolidation', label: 'Consolidation' },\n { value: 'customer-request', label: 'Customer request' },\n { value: 'non-payment', label: 'Non-payment' },\n { value: 'contract-breach', label: 'Contract breach' },\n { value: 'other', label: 'Other' },\n] as const\n\nexport default function ArcQuoteConfigurator(\n props: ArcQuoteConfiguratorProps,\n): React.ReactElement {\n const {\n quoteId,\n customerId,\n customerName,\n currencyCode,\n initialType,\n initialTargets,\n editable,\n onClose,\n onChanged,\n } = props\n\n const [step, setStep] = React.useState<Step>(\n initialType === 'new' ? 'pick-action' : 'pick-targets',\n )\n const [type, setType] = React.useState<ArcType | null>(\n initialType === 'new' ? null : (initialType as ArcType),\n )\n const [eligible, setEligible] = React.useState<EligibleSub[]>([])\n const [eligibleLoading, setEligibleLoading] = React.useState(false)\n const [picked, setPicked] = React.useState<Record<string, EligibleSub>>(() => {\n const seed: Record<string, EligibleSub> = {}\n for (const t of initialTargets) {\n if (t.subscription) {\n seed[t.subscriptionId] = {\n id: t.subscriptionId,\n code: t.subscription.code,\n name: t.subscription.name,\n status: 'active',\n currencyCode: t.subscription.currencyCode,\n billingCycle: t.subscription.billingCycle,\n currentTermEnd: null,\n mrcAmount: t.subscription.mrcAmount,\n }\n }\n }\n return seed\n })\n // Renew config (per-target term for standalone, quote-level for merge).\n const [singleTerm, setSingleTerm] = React.useState<{ start: string; end: string; months: string }>(() => ({\n start: initialTargets[0]?.newTermStart?.slice(0, 10) ?? '',\n end: initialTargets[0]?.newTermEnd?.slice(0, 10) ?? '',\n months: initialTargets[0]?.newTermMonths != null ? String(initialTargets[0].newTermMonths) : '',\n }))\n const [mergeTerm, setMergeTerm] = React.useState({\n start: '',\n end: '',\n months: '',\n code: '',\n name: '',\n })\n // Cancel config.\n const [cancelMeta, setCancelMeta] = React.useState({\n reasonCode: '',\n reasonText: '',\n etfAmount: '',\n etfCurrency: currencyCode,\n })\n const [submitError, setSubmitError] = React.useState<string | null>(null)\n\n // ESC closes the drawer.\n React.useEffect(() => {\n function onKey(e: KeyboardEvent) {\n if (e.key === 'Escape') onClose()\n }\n window.addEventListener('keydown', onKey)\n return () => window.removeEventListener('keydown', onKey)\n }, [onClose])\n\n // Fetch eligible subscriptions when step requires it.\n React.useEffect(() => {\n if (step !== 'pick-targets') return\n setEligibleLoading(true)\n fetch(`/api/cpq/inventory/subscriptions?customerId=${customerId}&pageSize=100`)\n .then((r) => r.json())\n .then((data) => {\n const items: EligibleSub[] = (data.items ?? []).map((s: EligibleSub) => ({\n ...s,\n mrcAmount: Number(s.mrcAmount ?? 0),\n }))\n setEligible(items)\n })\n .catch(() => setEligible([]))\n .finally(() => setEligibleLoading(false))\n }, [step, customerId])\n\n const pickedList = Object.values(picked)\n const isMergeRenew = type === 'renew' && pickedList.length >= 2\n const billingCycles = new Set(pickedList.map((s) => s.billingCycle))\n const cyclesMatch = billingCycles.size <= 1\n const currenciesMatch = pickedList.every((s) => s.currencyCode === currencyCode)\n\n // Validation gates.\n const canProceedFromTargets = pickedList.length > 0 && currenciesMatch\n const canProceedFromRenew =\n isMergeRenew\n ? !!mergeTerm.start && !!mergeTerm.end && mergeTerm.start < mergeTerm.end && cyclesMatch\n : !!singleTerm.start && !!singleTerm.end && singleTerm.start < singleTerm.end\n const canProceedFromCancel = !!cancelMeta.reasonCode\n\n const submit = React.useCallback(async () => {\n setStep('submitting')\n setSubmitError(null)\n try {\n // Step 1 \u2014 set quote type when transitioning from 'new'.\n if (initialType === 'new' && type) {\n const r = await fetch(`/api/cpq/quotes/${quoteId}`, {\n method: 'PATCH',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ quoteType: type }),\n })\n if (!r.ok) {\n const body = await r.json().catch(() => ({}))\n throw new Error(body.error ?? `PATCH /quotes/${quoteId} failed`)\n }\n }\n\n // Step 2 \u2014 detach removed targets.\n const initialTargetIds = new Set(initialTargets.map((t) => t.subscriptionId))\n const pickedIds = new Set(pickedList.map((s) => s.id))\n for (const t of initialTargets) {\n if (!pickedIds.has(t.subscriptionId)) {\n await fetch(`/api/cpq/quotes/${quoteId}/target-subscriptions/${t.id}`, { method: 'DELETE' })\n }\n }\n\n // Step 3 \u2014 attach new targets.\n for (const s of pickedList) {\n if (!initialTargetIds.has(s.id) && type) {\n const body: Record<string, unknown> = {\n subscriptionId: s.id,\n quoteType: type,\n }\n if (type === 'renew' && !isMergeRenew) {\n body.mergeAction = 'standalone'\n body.newTermStart = singleTerm.start\n body.newTermEnd = singleTerm.end\n if (singleTerm.months) body.newTermMonths = Number(singleTerm.months)\n } else if (type === 'renew' && isMergeRenew) {\n body.mergeAction = 'absorb'\n }\n const r = await fetch(`/api/cpq/quotes/${quoteId}/target-subscriptions`, {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(body),\n })\n if (!r.ok) {\n const errBody = await r.json().catch(() => ({}))\n throw new Error(errBody.error ?? `POST /target-subscriptions failed`)\n }\n }\n }\n\n // Step 4 \u2014 for merge renew, stamp quote-level merge meta.\n if (type === 'renew' && isMergeRenew) {\n const body: Record<string, unknown> = {\n newTermStart: mergeTerm.start,\n newTermEnd: mergeTerm.end,\n }\n if (mergeTerm.months) body.newTermMonths = Number(mergeTerm.months)\n if (mergeTerm.code) body.newSubCode = mergeTerm.code\n if (mergeTerm.name) body.newSubName = mergeTerm.name\n const r = await fetch(`/api/cpq/quotes/${quoteId}/merge-meta`, {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(body),\n })\n if (!r.ok) {\n const errBody = await r.json().catch(() => ({}))\n throw new Error(errBody.error ?? `POST /merge-meta failed`)\n }\n }\n\n // Step 5 \u2014 for cancel, stamp meta.\n if (type === 'cancel') {\n const body: Record<string, unknown> = { reasonCode: cancelMeta.reasonCode }\n if (cancelMeta.reasonText) body.reasonText = cancelMeta.reasonText\n if (cancelMeta.etfAmount) body.etfAmount = cancelMeta.etfAmount\n if (cancelMeta.etfCurrency) body.etfCurrency = cancelMeta.etfCurrency\n const r = await fetch(`/api/cpq/quotes/${quoteId}/cancel-meta`, {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(body),\n })\n if (!r.ok) {\n const errBody = await r.json().catch(() => ({}))\n throw new Error(errBody.error ?? `POST /cancel-meta failed`)\n }\n }\n\n await onChanged()\n setStep('done')\n } catch (err) {\n setSubmitError(err instanceof Error ? err.message : String(err))\n setStep('review')\n }\n }, [\n quoteId,\n type,\n initialType,\n initialTargets,\n pickedList,\n isMergeRenew,\n singleTerm,\n mergeTerm,\n cancelMeta,\n onChanged,\n ])\n\n return (\n <div className=\"fixed inset-0 z-50 flex\" role=\"dialog\" aria-modal=\"true\">\n {/* Overlay */}\n <button\n aria-label=\"Close drawer\"\n className=\"absolute inset-0 bg-black/40\"\n onClick={onClose}\n />\n {/* Drawer */}\n <div className=\"ml-auto h-full w-full max-w-2xl bg-card shadow-xl border-l overflow-y-auto relative flex flex-col\">\n <header className=\"border-b px-5 py-4 flex items-start justify-between\">\n <div>\n <h2 className=\"text-lg font-semibold\">Modify subscription</h2>\n <p className=\"text-xs text-muted-foreground mt-0.5\">\n {customerName ?? customerId.slice(0, 12) + '\u2026'} \u2022 {currencyCode}\n </p>\n </div>\n <button\n onClick={onClose}\n className=\"text-sm text-muted-foreground hover:text-foreground\"\n >\n \u2715\n </button>\n </header>\n\n <div className=\"flex-1 px-5 py-4 space-y-4\">\n {/* Step indicator */}\n <p className=\"text-xs text-muted-foreground\">\n Step: <span className=\"font-mono\">{step}</span>\n {type && <span> \u2022 {type}</span>}\n {pickedList.length > 0 && <span> \u2022 {pickedList.length} target(s)</span>}\n </p>\n\n {step === 'pick-action' && (\n <div className=\"space-y-3\">\n <p className=\"text-sm\">Pick the kind of change you want to make:</p>\n {(['amend', 'renew', 'cancel'] as const).map((opt) => (\n <button\n key={opt}\n onClick={() => {\n setType(opt)\n setStep('pick-targets')\n }}\n className=\"block w-full text-left rounded-md border border-input px-4 py-3 hover:bg-muted\"\n >\n <span className=\"font-medium capitalize\">{opt}</span>\n <span className=\"block text-xs text-muted-foreground mt-0.5\">\n {opt === 'amend' && 'Add or remove items on existing subscriptions. Term untouched.'}\n {opt === 'renew' && 'Extend term. With 2+ targets, merges them into a new contract.'}\n {opt === 'cancel' && 'Terminate one or more subscriptions.'}\n </span>\n </button>\n ))}\n </div>\n )}\n\n {step === 'pick-targets' && type && (\n <div className=\"space-y-3\">\n {eligibleLoading ? (\n <div className=\"text-sm text-muted-foreground\">Loading subscriptions\u2026</div>\n ) : eligible.length === 0 ? (\n <div className=\"text-sm text-muted-foreground\">No subscriptions for this customer.</div>\n ) : (\n <div className=\"space-y-1\">\n {eligible.map((s) => {\n const currencyMismatch = s.currencyCode !== currencyCode\n const isPicked = !!picked[s.id]\n return (\n <label\n key={s.id}\n className={`flex items-start gap-2 rounded-md border px-3 py-2 ${\n currencyMismatch\n ? 'opacity-50 border-dashed'\n : isPicked\n ? 'border-primary bg-primary/5'\n : 'border-input hover:bg-muted'\n }`}\n >\n <input\n type=\"checkbox\"\n disabled={currencyMismatch}\n checked={isPicked}\n onChange={(e) => {\n setPicked((prev) => {\n const next = { ...prev }\n if (e.target.checked) next[s.id] = s\n else delete next[s.id]\n return next\n })\n }}\n />\n <div className=\"flex-1 min-w-0\">\n <div className=\"text-sm font-medium\">\n {s.name}{' '}\n <span className=\"text-xs font-mono text-muted-foreground\">{s.code}</span>\n </div>\n <div className=\"text-xs text-muted-foreground\">\n {s.status} \u2022 {s.billingCycle} \u2022 MRC {s.mrcAmount.toFixed(2)} {s.currencyCode}\n {s.currentTermEnd\n ? ` \u2022 Term ends ${new Date(s.currentTermEnd).toLocaleDateString()}`\n : ''}\n </div>\n {currencyMismatch && (\n <div className=\"text-xs text-status-warning-text mt-1\">\n Currency mismatch ({s.currencyCode} vs {currencyCode}) \u2014 cannot include\n </div>\n )}\n </div>\n </label>\n )\n })}\n </div>\n )}\n {!cyclesMatch && (\n <Alert variant=\"warning\" className=\"text-xs\">\n Picked targets have different billing cycles \u2014 merge requires matching cycles.\n </Alert>\n )}\n {isMergeRenew && (\n <Alert variant=\"warning\" className=\"text-xs\">\n Merging {pickedList.length} contracts into a new one \u2014 sources will be marked Merged at activation.\n </Alert>\n )}\n </div>\n )}\n\n {step === 'config-renew' && type === 'renew' && !isMergeRenew && (\n <div className=\"space-y-3\">\n <p className=\"text-sm\">New contract term for {pickedList[0]?.name}:</p>\n <p className=\"text-xs text-muted-foreground\">\n Pre-filled with same length as the current term, starting at the\n current term end. Type a new value in <span className=\"font-medium\">Months</span> to\n auto-shift the end date, or edit start/end directly.\n </p>\n <div className=\"grid grid-cols-3 gap-3\">\n <DateInput\n label=\"Start\"\n value={singleTerm.start}\n onChange={(v) => {\n // If months is set, slide end too so the contract length stays.\n const months = singleTerm.months ? Number(singleTerm.months) : null\n const end = months && v ? addMonthsToIso(v, months) : singleTerm.end\n setSingleTerm({ ...singleTerm, start: v, end })\n }}\n />\n <DateInput\n label=\"End\"\n value={singleTerm.end}\n onChange={(v) => setSingleTerm({ ...singleTerm, end: v })}\n />\n <NumberInput\n label=\"Months\"\n value={singleTerm.months}\n onChange={(v) => {\n // Recompute end = start + months when both are present.\n const months = v ? Number(v) : null\n const end = months && singleTerm.start\n ? addMonthsToIso(singleTerm.start, months)\n : singleTerm.end\n setSingleTerm({ ...singleTerm, months: v, end })\n }}\n />\n </div>\n </div>\n )}\n\n {step === 'config-renew' && type === 'renew' && isMergeRenew && (\n <div className=\"space-y-3\">\n <p className=\"text-sm\">\n New contract details (merge of {pickedList.length} subscriptions):\n </p>\n <p className=\"text-xs text-muted-foreground\">\n Type a value into <span className=\"font-medium\">Months</span> to\n auto-fill both dates \u2014 start defaults to today, end is start + months.\n </p>\n <div className=\"grid grid-cols-3 gap-3\">\n <DateInput\n label=\"Start\"\n value={mergeTerm.start}\n onChange={(v) => {\n const months = mergeTerm.months ? Number(mergeTerm.months) : null\n const end = months && v ? addMonthsToIso(v, months) : mergeTerm.end\n setMergeTerm({ ...mergeTerm, start: v, end })\n }}\n />\n <DateInput\n label=\"End\"\n value={mergeTerm.end}\n onChange={(v) => setMergeTerm({ ...mergeTerm, end: v })}\n />\n <NumberInput\n label=\"Months\"\n value={mergeTerm.months}\n onChange={(v) => {\n const months = v ? Number(v) : null\n const start = mergeTerm.start || todayIso()\n const end = months ? addMonthsToIso(start, months) : mergeTerm.end\n setMergeTerm({ ...mergeTerm, months: v, start, end })\n }}\n />\n </div>\n <div className=\"grid grid-cols-2 gap-3\">\n <TextInput\n label=\"New contract code (optional \u2014 auto-generated if blank)\"\n value={mergeTerm.code}\n onChange={(v) => setMergeTerm({ ...mergeTerm, code: v })}\n />\n <TextInput\n label=\"New contract name (optional)\"\n value={mergeTerm.name}\n onChange={(v) => setMergeTerm({ ...mergeTerm, name: v })}\n />\n </div>\n </div>\n )}\n\n {step === 'config-cancel' && type === 'cancel' && (\n <div className=\"space-y-3\">\n <p className=\"text-sm\">Reason for cancellation:</p>\n <div className=\"space-y-2\">\n <label className=\"block text-xs text-muted-foreground\">Reason code</label>\n <select\n value={cancelMeta.reasonCode}\n onChange={(e) => setCancelMeta({ ...cancelMeta, reasonCode: e.target.value })}\n className=\"w-full rounded-md border border-input bg-background px-2 py-1.5 text-sm\"\n >\n <option value=\"\">\u2014 pick one \u2014</option>\n {REASON_CODES.map((r) => (\n <option key={r.value} value={r.value}>\n {r.label}\n </option>\n ))}\n </select>\n </div>\n <TextInput\n label=\"Free text (optional)\"\n value={cancelMeta.reasonText}\n onChange={(v) => setCancelMeta({ ...cancelMeta, reasonText: v })}\n />\n <div className=\"grid grid-cols-2 gap-3\">\n <TextInput\n label=\"ETF amount (optional)\"\n value={cancelMeta.etfAmount}\n onChange={(v) => setCancelMeta({ ...cancelMeta, etfAmount: v })}\n />\n <TextInput\n label=\"ETF currency\"\n value={cancelMeta.etfCurrency}\n onChange={(v) => setCancelMeta({ ...cancelMeta, etfCurrency: v })}\n />\n </div>\n </div>\n )}\n\n {step === 'review' && (\n <div className=\"space-y-3\">\n <p className=\"text-sm\">Review and submit:</p>\n <ul className=\"text-sm space-y-1 list-disc pl-5\">\n <li>Action: {type}</li>\n <li>Targets: {pickedList.length}</li>\n {pickedList.map((s) => (\n <li key={s.id} className=\"text-muted-foreground\">\n {s.code} \u2014 {s.name}\n </li>\n ))}\n {type === 'renew' && !isMergeRenew && (\n <li>\n Term: {singleTerm.start} \u2192 {singleTerm.end}\n {singleTerm.months ? ` (${singleTerm.months}m)` : ''}\n </li>\n )}\n {type === 'renew' && isMergeRenew && (\n <li>\n Merge term: {mergeTerm.start} \u2192 {mergeTerm.end}\n {mergeTerm.code ? ` \u2022 code=${mergeTerm.code}` : ''}\n {mergeTerm.name ? ` \u2022 name=${mergeTerm.name}` : ''}\n </li>\n )}\n {type === 'cancel' && (\n <li>\n Reason: {cancelMeta.reasonCode}\n {cancelMeta.etfAmount\n ? ` \u2022 ETF ${cancelMeta.etfAmount} ${cancelMeta.etfCurrency}`\n : ''}\n </li>\n )}\n </ul>\n <Alert variant=\"warning\" className=\"text-xs\">\n Submitting locks the quote type. Lines will be edited on the host page after this completes.\n </Alert>\n {submitError && (\n <Alert variant=\"destructive\" className=\"text-xs\">{submitError}</Alert>\n )}\n </div>\n )}\n\n {step === 'submitting' && (\n <div className=\"text-sm text-muted-foreground\">Submitting\u2026</div>\n )}\n\n {step === 'done' && (\n <div className=\"text-sm text-status-success-text\">\n Done \u2014 close to return to the quote.\n </div>\n )}\n </div>\n\n <footer className=\"border-t px-5 pt-3 pb-20 flex items-center justify-between\">\n <button\n onClick={() => {\n if (step === 'pick-action') return\n if (step === 'pick-targets') {\n setStep(initialType === 'new' ? 'pick-action' : 'pick-targets')\n } else if (step === 'config-renew' || step === 'config-cancel') {\n setStep('pick-targets')\n } else if (step === 'review') {\n if (type === 'renew') setStep('config-renew')\n else if (type === 'cancel') setStep('config-cancel')\n else setStep('pick-targets')\n }\n }}\n disabled={\n step === 'pick-action' ||\n step === 'submitting' ||\n step === 'done' ||\n (step === 'pick-targets' && initialType !== 'new')\n }\n className=\"text-sm text-muted-foreground hover:text-foreground disabled:opacity-30\"\n >\n \u2190 Back\n </button>\n <div className=\"flex gap-2\">\n <button\n onClick={onClose}\n className=\"rounded-md border border-input px-3 py-1.5 text-sm hover:bg-muted\"\n >\n Cancel\n </button>\n {step === 'pick-targets' && (\n <button\n disabled={!canProceedFromTargets || !editable}\n onClick={() => {\n if (type === 'renew') setStep('config-renew')\n else if (type === 'cancel') setStep('config-cancel')\n else setStep('review')\n }}\n className=\"rounded-md bg-primary px-3 py-1.5 text-sm text-primary-foreground hover:bg-primary/90 disabled:opacity-50\"\n >\n Next\n </button>\n )}\n {(step === 'config-renew' || step === 'config-cancel') && (\n <button\n disabled={\n (step === 'config-renew' && !canProceedFromRenew) ||\n (step === 'config-cancel' && !canProceedFromCancel)\n }\n onClick={() => setStep('review')}\n className=\"rounded-md bg-primary px-3 py-1.5 text-sm text-primary-foreground hover:bg-primary/90 disabled:opacity-50\"\n >\n Next\n </button>\n )}\n {step === 'review' && (\n <button\n disabled={!editable}\n onClick={submit}\n className=\"rounded-md bg-primary px-3 py-1.5 text-sm text-primary-foreground hover:bg-primary/90 disabled:opacity-50\"\n >\n Submit\n </button>\n )}\n {step === 'done' && (\n <button\n onClick={onClose}\n className=\"rounded-md bg-primary px-3 py-1.5 text-sm text-primary-foreground hover:bg-primary/90\"\n >\n Close\n </button>\n )}\n </div>\n </footer>\n </div>\n </div>\n )\n}\n\nfunction DateInput(props: { label: string; value: string; onChange: (v: string) => void }) {\n return (\n <div>\n <label className=\"block text-xs text-muted-foreground mb-1\">{props.label}</label>\n <input\n type=\"date\"\n value={props.value}\n onChange={(e) => props.onChange(e.target.value)}\n className=\"w-full rounded-md border border-input bg-background px-2 py-1.5 text-sm\"\n />\n </div>\n )\n}\n\n// Local \"labelled number\" wrapper kept as a string-in/string-out facade so\n// the surrounding code (which threads `value` through `mergeTerm.months` as\n// a string) doesn't have to change. The actual input behaviour comes from\n// the shared `NumberInput` component (select-on-focus + internal string\n// state \u2014 see components/NumberInput.tsx for the rationale).\nfunction NumberInput(props: { label: string; value: string; onChange: (v: string) => void }) {\n return (\n <div>\n <label className=\"block text-xs text-muted-foreground mb-1\">{props.label}</label>\n <BaseNumberInput\n integer\n min={1}\n value={props.value === '' ? null : Number(props.value)}\n onChange={(n) => props.onChange(n == null ? '' : String(n))}\n />\n </div>\n )\n}\n\nfunction TextInput(props: { label: string; value: string; onChange: (v: string) => void }) {\n return (\n <div>\n <label className=\"block text-xs text-muted-foreground mb-1\">{props.label}</label>\n <input\n type=\"text\"\n value={props.value}\n onChange={(e) => props.onChange(e.target.value)}\n className=\"w-full rounded-md border border-input bg-background px-2 py-1.5 text-sm\"\n />\n </div>\n )\n}\n\n// Add `months` whole calendar months to an ISO date string (YYYY-MM-DD) and\n// return the result in the same format. Used by the renew config step so the\n// operator can edit just the months field and have the end date auto-update.\nfunction addMonthsToIso(iso: string, months: number): string {\n if (!iso) return iso\n const d = new Date(iso)\n if (Number.isNaN(d.getTime())) return iso\n d.setMonth(d.getMonth() + months)\n return d.toISOString().split('T')[0]\n}\n\n// Today as YYYY-MM-DD \u2014 used as the default `Start` when the operator types\n// a `Months` value first on a brand-new merge contract.\nfunction todayIso(): string {\n return new Date().toISOString().split('T')[0]\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["\"use client\"\nimport * as React from 'react'\nimport { Alert } from '@open-mercato/ui/primitives/alert'\nimport { useT, type TranslateFn } from '@open-mercato/shared/lib/i18n/context'\nimport { NumberInput as BaseNumberInput } from '../../../../../components/NumberInput'\n\n// XD-250 \u2014 ARC configurator drawer.\n//\n// Self-contained right-side drawer: action selection \u2192 target picker \u2192\n// renew/cancel config \u2192 review \u2192 submit. The host quote detail page renders\n// it on demand and refetches when the drawer reports `onChanged`.\n\ntype ArcType = 'amend' | 'renew' | 'cancel'\ntype Step =\n | 'pick-action'\n | 'pick-targets'\n | 'config-renew'\n | 'config-cancel'\n | 'review'\n | 'submitting'\n | 'done'\n\ntype EligibleSub = {\n id: string\n code: string\n name: string\n status: string\n currencyCode: string\n billingCycle: string\n currentTermEnd: string | null\n mrcAmount: number\n}\n\nexport type AttachedTarget = {\n id: string\n subscriptionId: string\n quoteType: string\n mergeAction: string | null\n newTermStart: string | null\n newTermEnd: string | null\n newTermMonths: number | null\n subscription: {\n code: string\n name: string\n currencyCode: string\n billingCycle: string\n mrcAmount: number\n } | null\n}\n\nexport interface ArcQuoteConfiguratorProps {\n quoteId: string\n customerId: string\n customerName: string | null\n currencyCode: string\n initialType: 'new' | ArcType\n initialTargets: AttachedTarget[]\n editable: boolean\n onClose: () => void\n onChanged: () => void | Promise<void>\n}\n\nfunction buildReasonCodes(t: TranslateFn): Array<{ value: string; label: string }> {\n return [\n { value: 'upgrade', label: t('cpq.quotes.arc.drawer.reasons.upgrade', 'Upgrade') },\n { value: 'downgrade', label: t('cpq.quotes.arc.drawer.reasons.downgrade', 'Downgrade') },\n { value: 'config-change', label: t('cpq.quotes.arc.drawer.reasons.configChange', 'Configuration change') },\n { value: 'price-adjustment', label: t('cpq.quotes.arc.drawer.reasons.priceAdjustment', 'Price adjustment') },\n { value: 'term-extension', label: t('cpq.quotes.arc.drawer.reasons.termExtension', 'Term extension') },\n { value: 'term-reduction', label: t('cpq.quotes.arc.drawer.reasons.termReduction', 'Term reduction') },\n { value: 'consolidation', label: t('cpq.quotes.arc.drawer.reasons.consolidation', 'Consolidation') },\n { value: 'customer-request', label: t('cpq.quotes.arc.drawer.reasons.customerRequest', 'Customer request') },\n { value: 'non-payment', label: t('cpq.quotes.arc.drawer.reasons.nonPayment', 'Non-payment') },\n { value: 'contract-breach', label: t('cpq.quotes.arc.drawer.reasons.contractBreach', 'Contract breach') },\n { value: 'other', label: t('cpq.quotes.arc.drawer.reasons.other', 'Other') },\n ]\n}\n\nfunction arcTypeLabel(t: TranslateFn, type: ArcType): string {\n switch (type) {\n case 'amend':\n return t('cpq.quotes.type.amend', 'amend')\n case 'renew':\n return t('cpq.quotes.type.renew', 'renew')\n case 'cancel':\n return t('cpq.quotes.type.cancel', 'cancel')\n }\n}\n\nexport default function ArcQuoteConfigurator(\n props: ArcQuoteConfiguratorProps,\n): React.ReactElement {\n const {\n quoteId,\n customerId,\n customerName,\n currencyCode,\n initialType,\n initialTargets,\n editable,\n onClose,\n onChanged,\n } = props\n\n const t = useT()\n const reasonCodes = React.useMemo(() => buildReasonCodes(t), [t])\n const [step, setStep] = React.useState<Step>(\n initialType === 'new' ? 'pick-action' : 'pick-targets',\n )\n const [type, setType] = React.useState<ArcType | null>(\n initialType === 'new' ? null : (initialType as ArcType),\n )\n const [eligible, setEligible] = React.useState<EligibleSub[]>([])\n const [eligibleLoading, setEligibleLoading] = React.useState(false)\n const [picked, setPicked] = React.useState<Record<string, EligibleSub>>(() => {\n const seed: Record<string, EligibleSub> = {}\n for (const target of initialTargets) {\n if (target.subscription) {\n seed[target.subscriptionId] = {\n id: target.subscriptionId,\n code: target.subscription.code,\n name: target.subscription.name,\n status: 'active',\n currencyCode: target.subscription.currencyCode,\n billingCycle: target.subscription.billingCycle,\n currentTermEnd: null,\n mrcAmount: target.subscription.mrcAmount,\n }\n }\n }\n return seed\n })\n // Renew config (per-target term for standalone, quote-level for merge).\n const [singleTerm, setSingleTerm] = React.useState<{ start: string; end: string; months: string }>(() => ({\n start: initialTargets[0]?.newTermStart?.slice(0, 10) ?? '',\n end: initialTargets[0]?.newTermEnd?.slice(0, 10) ?? '',\n months: initialTargets[0]?.newTermMonths != null ? String(initialTargets[0].newTermMonths) : '',\n }))\n const [mergeTerm, setMergeTerm] = React.useState({\n start: '',\n end: '',\n months: '',\n code: '',\n name: '',\n })\n // Cancel config.\n const [cancelMeta, setCancelMeta] = React.useState({\n reasonCode: '',\n reasonText: '',\n etfAmount: '',\n etfCurrency: currencyCode,\n })\n const [submitError, setSubmitError] = React.useState<string | null>(null)\n\n // ESC closes the drawer.\n React.useEffect(() => {\n function onKey(e: KeyboardEvent) {\n if (e.key === 'Escape') onClose()\n }\n window.addEventListener('keydown', onKey)\n return () => window.removeEventListener('keydown', onKey)\n }, [onClose])\n\n // Fetch eligible subscriptions when step requires it.\n React.useEffect(() => {\n if (step !== 'pick-targets') return\n setEligibleLoading(true)\n fetch(`/api/cpq/inventory/subscriptions?customerId=${customerId}&pageSize=100`)\n .then((r) => r.json())\n .then((data) => {\n const items: EligibleSub[] = (data.items ?? []).map((s: EligibleSub) => ({\n ...s,\n mrcAmount: Number(s.mrcAmount ?? 0),\n }))\n setEligible(items)\n })\n .catch(() => setEligible([]))\n .finally(() => setEligibleLoading(false))\n }, [step, customerId])\n\n const pickedList = Object.values(picked)\n const isMergeRenew = type === 'renew' && pickedList.length >= 2\n const billingCycles = new Set(pickedList.map((s) => s.billingCycle))\n const cyclesMatch = billingCycles.size <= 1\n const currenciesMatch = pickedList.every((s) => s.currencyCode === currencyCode)\n\n // Validation gates.\n const canProceedFromTargets = pickedList.length > 0 && currenciesMatch\n const canProceedFromRenew =\n isMergeRenew\n ? !!mergeTerm.start && !!mergeTerm.end && mergeTerm.start < mergeTerm.end && cyclesMatch\n : !!singleTerm.start && !!singleTerm.end && singleTerm.start < singleTerm.end\n const canProceedFromCancel = !!cancelMeta.reasonCode\n\n const submit = React.useCallback(async () => {\n setStep('submitting')\n setSubmitError(null)\n try {\n // Step 1 \u2014 set quote type when transitioning from 'new'.\n if (initialType === 'new' && type) {\n const r = await fetch(`/api/cpq/quotes/${quoteId}`, {\n method: 'PATCH',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ quoteType: type }),\n })\n if (!r.ok) {\n const body = await r.json().catch(() => ({}))\n throw new Error(body.error ?? t('cpq.quotes.arc.drawer.errors.patchFailed', 'PATCH /quotes/{quoteId} failed', { quoteId }))\n }\n }\n\n // Step 2 \u2014 detach removed targets.\n const initialTargetIds = new Set(initialTargets.map((target) => target.subscriptionId))\n const pickedIds = new Set(pickedList.map((s) => s.id))\n for (const target of initialTargets) {\n if (!pickedIds.has(target.subscriptionId)) {\n await fetch(`/api/cpq/quotes/${quoteId}/target-subscriptions/${target.id}`, { method: 'DELETE' })\n }\n }\n\n // Step 3 \u2014 attach new targets.\n for (const s of pickedList) {\n if (!initialTargetIds.has(s.id) && type) {\n const body: Record<string, unknown> = {\n subscriptionId: s.id,\n quoteType: type,\n }\n if (type === 'renew' && !isMergeRenew) {\n body.mergeAction = 'standalone'\n body.newTermStart = singleTerm.start\n body.newTermEnd = singleTerm.end\n if (singleTerm.months) body.newTermMonths = Number(singleTerm.months)\n } else if (type === 'renew' && isMergeRenew) {\n body.mergeAction = 'absorb'\n }\n const r = await fetch(`/api/cpq/quotes/${quoteId}/target-subscriptions`, {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(body),\n })\n if (!r.ok) {\n const errBody = await r.json().catch(() => ({}))\n throw new Error(errBody.error ?? t('cpq.quotes.arc.drawer.errors.attachFailed', 'POST /target-subscriptions failed'))\n }\n }\n }\n\n // Step 4 \u2014 for merge renew, stamp quote-level merge meta.\n if (type === 'renew' && isMergeRenew) {\n const body: Record<string, unknown> = {\n newTermStart: mergeTerm.start,\n newTermEnd: mergeTerm.end,\n }\n if (mergeTerm.months) body.newTermMonths = Number(mergeTerm.months)\n if (mergeTerm.code) body.newSubCode = mergeTerm.code\n if (mergeTerm.name) body.newSubName = mergeTerm.name\n const r = await fetch(`/api/cpq/quotes/${quoteId}/merge-meta`, {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(body),\n })\n if (!r.ok) {\n const errBody = await r.json().catch(() => ({}))\n throw new Error(errBody.error ?? t('cpq.quotes.arc.drawer.errors.mergeMetaFailed', 'POST /merge-meta failed'))\n }\n }\n\n // Step 5 \u2014 for cancel, stamp meta.\n if (type === 'cancel') {\n const body: Record<string, unknown> = { reasonCode: cancelMeta.reasonCode }\n if (cancelMeta.reasonText) body.reasonText = cancelMeta.reasonText\n if (cancelMeta.etfAmount) body.etfAmount = cancelMeta.etfAmount\n if (cancelMeta.etfCurrency) body.etfCurrency = cancelMeta.etfCurrency\n const r = await fetch(`/api/cpq/quotes/${quoteId}/cancel-meta`, {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(body),\n })\n if (!r.ok) {\n const errBody = await r.json().catch(() => ({}))\n throw new Error(errBody.error ?? t('cpq.quotes.arc.drawer.errors.cancelMetaFailed', 'POST /cancel-meta failed'))\n }\n }\n\n await onChanged()\n setStep('done')\n } catch (err) {\n setSubmitError(err instanceof Error ? err.message : String(err))\n setStep('review')\n }\n }, [\n quoteId,\n type,\n initialType,\n initialTargets,\n pickedList,\n isMergeRenew,\n singleTerm,\n mergeTerm,\n cancelMeta,\n onChanged,\n t,\n ])\n\n return (\n <div className=\"fixed inset-0 z-50 flex\" role=\"dialog\" aria-modal=\"true\">\n {/* Overlay */}\n <button\n aria-label={t('cpq.quotes.arc.drawer.close', 'Close drawer')}\n className=\"absolute inset-0 bg-black/40\"\n onClick={onClose}\n />\n {/* Drawer */}\n <div className=\"ml-auto h-full w-full max-w-2xl bg-card shadow-xl border-l overflow-y-auto relative flex flex-col\">\n <header className=\"border-b px-5 py-4 flex items-start justify-between\">\n <div>\n <h2 className=\"text-lg font-semibold\">{t('cpq.quotes.arc.drawer.title', 'Modify subscription')}</h2>\n <p className=\"text-xs text-muted-foreground mt-0.5\">\n {customerName ?? customerId.slice(0, 12) + '\u2026'} \u2022 {currencyCode}\n </p>\n </div>\n <button\n onClick={onClose}\n className=\"text-sm text-muted-foreground hover:text-foreground\"\n >\n \u2715\n </button>\n </header>\n\n <div className=\"flex-1 px-5 py-4 space-y-4\">\n {/* Step indicator */}\n <p className=\"text-xs text-muted-foreground\">\n {t('cpq.quotes.arc.drawer.stepLabel', 'Step:')} <span className=\"font-mono\">{step}</span>\n {type && <span> \u2022 {arcTypeLabel(t, type)}</span>}\n {pickedList.length > 0 && <span> \u2022 {t('cpq.quotes.arc.drawer.targetCount', '{count} target(s)', { count: pickedList.length })}</span>}\n </p>\n\n {step === 'pick-action' && (\n <div className=\"space-y-3\">\n <p className=\"text-sm\">{t('cpq.quotes.arc.drawer.pickAction', 'Pick the kind of change you want to make:')}</p>\n {(['amend', 'renew', 'cancel'] as const).map((opt) => (\n <button\n key={opt}\n onClick={() => {\n setType(opt)\n setStep('pick-targets')\n }}\n className=\"block w-full text-left rounded-md border border-input px-4 py-3 hover:bg-muted\"\n >\n <span className=\"font-medium capitalize\">{arcTypeLabel(t, opt)}</span>\n <span className=\"block text-xs text-muted-foreground mt-0.5\">\n {opt === 'amend' && t('cpq.quotes.arc.drawer.actions.amendHint', 'Add or remove items on existing subscriptions. Term untouched.')}\n {opt === 'renew' && t('cpq.quotes.arc.drawer.actions.renewHint', 'Extend term. With 2+ targets, merges them into a new contract.')}\n {opt === 'cancel' && t('cpq.quotes.arc.drawer.actions.cancelHint', 'Terminate one or more subscriptions.')}\n </span>\n </button>\n ))}\n </div>\n )}\n\n {step === 'pick-targets' && type && (\n <div className=\"space-y-3\">\n {eligibleLoading ? (\n <div className=\"text-sm text-muted-foreground\">{t('cpq.quotes.arc.drawer.loadingSubscriptions', 'Loading subscriptions\u2026')}</div>\n ) : eligible.length === 0 ? (\n <div className=\"text-sm text-muted-foreground\">{t('cpq.quotes.arc.drawer.noSubscriptions', 'No subscriptions for this customer.')}</div>\n ) : (\n <div className=\"space-y-1\">\n {eligible.map((s) => {\n const currencyMismatch = s.currencyCode !== currencyCode\n const isPicked = !!picked[s.id]\n return (\n <label\n key={s.id}\n className={`flex items-start gap-2 rounded-md border px-3 py-2 ${\n currencyMismatch\n ? 'opacity-50 border-dashed'\n : isPicked\n ? 'border-primary bg-primary/5'\n : 'border-input hover:bg-muted'\n }`}\n >\n <input\n type=\"checkbox\"\n disabled={currencyMismatch}\n checked={isPicked}\n onChange={(e) => {\n setPicked((prev) => {\n const next = { ...prev }\n if (e.target.checked) next[s.id] = s\n else delete next[s.id]\n return next\n })\n }}\n />\n <div className=\"flex-1 min-w-0\">\n <div className=\"text-sm font-medium\">\n {s.name}{' '}\n <span className=\"text-xs font-mono text-muted-foreground\">{s.code}</span>\n </div>\n <div className=\"text-xs text-muted-foreground\">\n {s.status} \u2022 {s.billingCycle} \u2022 {t('cpq.lines.mrc', 'MRC')} {s.mrcAmount.toFixed(2)} {s.currencyCode}\n {s.currentTermEnd ? ' \u2022 ' : ''}\n {s.currentTermEnd\n ? t('cpq.quotes.arc.drawer.termEnds', 'Term ends {date}', { date: new Date(s.currentTermEnd).toLocaleDateString() })\n : ''}\n </div>\n {currencyMismatch && (\n <div className=\"text-xs text-status-warning-text mt-1\">\n {t('cpq.quotes.arc.drawer.currencyMismatch', 'Currency mismatch ({subscriptionCurrency} vs {quoteCurrency}) \u2014 cannot include', { subscriptionCurrency: s.currencyCode, quoteCurrency: currencyCode })}\n </div>\n )}\n </div>\n </label>\n )\n })}\n </div>\n )}\n {!cyclesMatch && (\n <Alert variant=\"warning\" className=\"text-xs\">\n {t('cpq.quotes.arc.drawer.cyclesMismatch', 'Picked targets have different billing cycles \u2014 merge requires matching cycles.')}\n </Alert>\n )}\n {isMergeRenew && (\n <Alert variant=\"warning\" className=\"text-xs\">\n {t('cpq.quotes.arc.drawer.mergeWarning', 'Merging {count} contracts into a new one \u2014 sources will be marked Merged at activation.', { count: pickedList.length })}\n </Alert>\n )}\n </div>\n )}\n\n {step === 'config-renew' && type === 'renew' && !isMergeRenew && (\n <div className=\"space-y-3\">\n <p className=\"text-sm\">{t('cpq.quotes.arc.drawer.renew.singleTitle', 'New contract term for {name}:', { name: pickedList[0]?.name ?? '' })}</p>\n <p className=\"text-xs text-muted-foreground\">\n {t('cpq.quotes.arc.drawer.renew.singleHintBefore', 'Pre-filled with same length as the current term, starting at the current term end. Type a new value in')}{' '}\n <span className=\"font-medium\">{t('cpq.quotes.arc.drawer.fields.months', 'Months')}</span>{' '}\n {t('cpq.quotes.arc.drawer.renew.singleHintAfter', 'to auto-shift the end date, or edit start/end directly.')}\n </p>\n <div className=\"grid grid-cols-3 gap-3\">\n <DateInput\n label={t('cpq.quotes.arc.drawer.fields.start', 'Start')}\n value={singleTerm.start}\n onChange={(v) => {\n // If months is set, slide end too so the contract length stays.\n const months = singleTerm.months ? Number(singleTerm.months) : null\n const end = months && v ? addMonthsToIso(v, months) : singleTerm.end\n setSingleTerm({ ...singleTerm, start: v, end })\n }}\n />\n <DateInput\n label={t('cpq.quotes.arc.drawer.fields.end', 'End')}\n value={singleTerm.end}\n onChange={(v) => setSingleTerm({ ...singleTerm, end: v })}\n />\n <NumberInput\n label={t('cpq.quotes.arc.drawer.fields.months', 'Months')}\n value={singleTerm.months}\n onChange={(v) => {\n // Recompute end = start + months when both are present.\n const months = v ? Number(v) : null\n const end = months && singleTerm.start\n ? addMonthsToIso(singleTerm.start, months)\n : singleTerm.end\n setSingleTerm({ ...singleTerm, months: v, end })\n }}\n />\n </div>\n </div>\n )}\n\n {step === 'config-renew' && type === 'renew' && isMergeRenew && (\n <div className=\"space-y-3\">\n <p className=\"text-sm\">\n {t('cpq.quotes.arc.drawer.renew.mergeTitle', 'New contract details (merge of {count} subscriptions):', { count: pickedList.length })}\n </p>\n <p className=\"text-xs text-muted-foreground\">\n {t('cpq.quotes.arc.drawer.renew.mergeHintBefore', 'Type a value into')}{' '}\n <span className=\"font-medium\">{t('cpq.quotes.arc.drawer.fields.months', 'Months')}</span>{' '}\n {t('cpq.quotes.arc.drawer.renew.mergeHintAfter', 'to auto-fill both dates \u2014 start defaults to today, end is start + months.')}\n </p>\n <div className=\"grid grid-cols-3 gap-3\">\n <DateInput\n label={t('cpq.quotes.arc.drawer.fields.start', 'Start')}\n value={mergeTerm.start}\n onChange={(v) => {\n const months = mergeTerm.months ? Number(mergeTerm.months) : null\n const end = months && v ? addMonthsToIso(v, months) : mergeTerm.end\n setMergeTerm({ ...mergeTerm, start: v, end })\n }}\n />\n <DateInput\n label={t('cpq.quotes.arc.drawer.fields.end', 'End')}\n value={mergeTerm.end}\n onChange={(v) => setMergeTerm({ ...mergeTerm, end: v })}\n />\n <NumberInput\n label={t('cpq.quotes.arc.drawer.fields.months', 'Months')}\n value={mergeTerm.months}\n onChange={(v) => {\n const months = v ? Number(v) : null\n const start = mergeTerm.start || todayIso()\n const end = months ? addMonthsToIso(start, months) : mergeTerm.end\n setMergeTerm({ ...mergeTerm, months: v, start, end })\n }}\n />\n </div>\n <div className=\"grid grid-cols-2 gap-3\">\n <TextInput\n label={t('cpq.quotes.arc.drawer.fields.newCode', 'New contract code (optional \u2014 auto-generated if blank)')}\n value={mergeTerm.code}\n onChange={(v) => setMergeTerm({ ...mergeTerm, code: v })}\n />\n <TextInput\n label={t('cpq.quotes.arc.drawer.fields.newName', 'New contract name (optional)')}\n value={mergeTerm.name}\n onChange={(v) => setMergeTerm({ ...mergeTerm, name: v })}\n />\n </div>\n </div>\n )}\n\n {step === 'config-cancel' && type === 'cancel' && (\n <div className=\"space-y-3\">\n <p className=\"text-sm\">{t('cpq.quotes.arc.drawer.cancel.title', 'Reason for cancellation:')}</p>\n <div className=\"space-y-2\">\n <label className=\"block text-xs text-muted-foreground\">{t('cpq.quotes.arc.drawer.cancel.reasonCode', 'Reason code')}</label>\n <select\n value={cancelMeta.reasonCode}\n onChange={(e) => setCancelMeta({ ...cancelMeta, reasonCode: e.target.value })}\n className=\"w-full rounded-md border border-input bg-background px-2 py-1.5 text-sm\"\n >\n <option value=\"\">{t('cpq.quotes.arc.drawer.cancel.pickOne', '\u2014 pick one \u2014')}</option>\n {reasonCodes.map((r) => (\n <option key={r.value} value={r.value}>\n {r.label}\n </option>\n ))}\n </select>\n </div>\n <TextInput\n label={t('cpq.quotes.arc.drawer.cancel.freeText', 'Free text (optional)')}\n value={cancelMeta.reasonText}\n onChange={(v) => setCancelMeta({ ...cancelMeta, reasonText: v })}\n />\n <div className=\"grid grid-cols-2 gap-3\">\n <TextInput\n label={t('cpq.quotes.arc.drawer.cancel.etfAmount', 'ETF amount (optional)')}\n value={cancelMeta.etfAmount}\n onChange={(v) => setCancelMeta({ ...cancelMeta, etfAmount: v })}\n />\n <TextInput\n label={t('cpq.quotes.arc.drawer.cancel.etfCurrency', 'ETF currency')}\n value={cancelMeta.etfCurrency}\n onChange={(v) => setCancelMeta({ ...cancelMeta, etfCurrency: v })}\n />\n </div>\n </div>\n )}\n\n {step === 'review' && (\n <div className=\"space-y-3\">\n <p className=\"text-sm\">{t('cpq.quotes.arc.drawer.review.title', 'Review and submit:')}</p>\n <ul className=\"text-sm space-y-1 list-disc pl-5\">\n <li>{t('cpq.quotes.arc.drawer.review.action', 'Action: {type}', { type: type ? arcTypeLabel(t, type) : '' })}</li>\n <li>{t('cpq.quotes.arc.drawer.review.targets', 'Targets: {count}', { count: pickedList.length })}</li>\n {pickedList.map((s) => (\n <li key={s.id} className=\"text-muted-foreground\">\n {s.code} \u2014 {s.name}\n </li>\n ))}\n {type === 'renew' && !isMergeRenew && (\n <li>\n {singleTerm.months\n ? t('cpq.quotes.arc.drawer.review.termWithMonths', 'Term: {start} \u2192 {end} ({months}m)', { start: singleTerm.start, end: singleTerm.end, months: singleTerm.months })\n : t('cpq.quotes.arc.drawer.review.term', 'Term: {start} \u2192 {end}', { start: singleTerm.start, end: singleTerm.end })}\n </li>\n )}\n {type === 'renew' && isMergeRenew && (\n <li>\n {t('cpq.quotes.arc.drawer.review.mergeTerm', 'Merge term: {start} \u2192 {end}', { start: mergeTerm.start, end: mergeTerm.end })}\n {mergeTerm.code ? ' \u2022 ' : ''}\n {mergeTerm.code ? t('cpq.quotes.arc.drawer.review.mergeCode', 'code={code}', { code: mergeTerm.code }) : ''}\n {mergeTerm.name ? ' \u2022 ' : ''}\n {mergeTerm.name ? t('cpq.quotes.arc.drawer.review.mergeName', 'name={name}', { name: mergeTerm.name }) : ''}\n </li>\n )}\n {type === 'cancel' && (\n <li>\n {t('cpq.quotes.arc.drawer.review.reason', 'Reason: {reason}', { reason: cancelMeta.reasonCode })}\n {cancelMeta.etfAmount ? ' \u2022 ' : ''}\n {cancelMeta.etfAmount\n ? t('cpq.quotes.arc.drawer.review.etf', 'ETF {amount} {currency}', { amount: cancelMeta.etfAmount, currency: cancelMeta.etfCurrency })\n : ''}\n </li>\n )}\n </ul>\n <Alert variant=\"warning\" className=\"text-xs\">\n {t('cpq.quotes.arc.drawer.review.lockWarning', 'Submitting locks the quote type. Lines will be edited on the host page after this completes.')}\n </Alert>\n {submitError && (\n <Alert variant=\"destructive\" className=\"text-xs\">{submitError}</Alert>\n )}\n </div>\n )}\n\n {step === 'submitting' && (\n <div className=\"text-sm text-muted-foreground\">{t('cpq.quotes.arc.drawer.submitting', 'Submitting\u2026')}</div>\n )}\n\n {step === 'done' && (\n <div className=\"text-sm text-status-success-text\">\n {t('cpq.quotes.arc.drawer.done', 'Done \u2014 close to return to the quote.')}\n </div>\n )}\n </div>\n\n <footer className=\"border-t px-5 pt-3 pb-20 flex items-center justify-between\">\n <button\n onClick={() => {\n if (step === 'pick-action') return\n if (step === 'pick-targets') {\n setStep(initialType === 'new' ? 'pick-action' : 'pick-targets')\n } else if (step === 'config-renew' || step === 'config-cancel') {\n setStep('pick-targets')\n } else if (step === 'review') {\n if (type === 'renew') setStep('config-renew')\n else if (type === 'cancel') setStep('config-cancel')\n else setStep('pick-targets')\n }\n }}\n disabled={\n step === 'pick-action' ||\n step === 'submitting' ||\n step === 'done' ||\n (step === 'pick-targets' && initialType !== 'new')\n }\n className=\"text-sm text-muted-foreground hover:text-foreground disabled:opacity-30\"\n >\n {t('cpq.quotes.arc.drawer.back', '\u2190 Back')}\n </button>\n <div className=\"flex gap-2\">\n <button\n onClick={onClose}\n className=\"rounded-md border border-input px-3 py-1.5 text-sm hover:bg-muted\"\n >\n {t('cpq.common.cancel', 'Cancel')}\n </button>\n {step === 'pick-targets' && (\n <button\n disabled={!canProceedFromTargets || !editable}\n onClick={() => {\n if (type === 'renew') setStep('config-renew')\n else if (type === 'cancel') setStep('config-cancel')\n else setStep('review')\n }}\n className=\"rounded-md bg-primary px-3 py-1.5 text-sm text-primary-foreground hover:bg-primary/90 disabled:opacity-50\"\n >\n {t('cpq.quotes.arc.drawer.next', 'Next')}\n </button>\n )}\n {(step === 'config-renew' || step === 'config-cancel') && (\n <button\n disabled={\n (step === 'config-renew' && !canProceedFromRenew) ||\n (step === 'config-cancel' && !canProceedFromCancel)\n }\n onClick={() => setStep('review')}\n className=\"rounded-md bg-primary px-3 py-1.5 text-sm text-primary-foreground hover:bg-primary/90 disabled:opacity-50\"\n >\n {t('cpq.quotes.arc.drawer.next', 'Next')}\n </button>\n )}\n {step === 'review' && (\n <button\n disabled={!editable}\n onClick={submit}\n className=\"rounded-md bg-primary px-3 py-1.5 text-sm text-primary-foreground hover:bg-primary/90 disabled:opacity-50\"\n >\n {t('cpq.quotes.arc.drawer.submit', 'Submit')}\n </button>\n )}\n {step === 'done' && (\n <button\n onClick={onClose}\n className=\"rounded-md bg-primary px-3 py-1.5 text-sm text-primary-foreground hover:bg-primary/90\"\n >\n {t('cpq.quotes.arc.drawer.closeButton', 'Close')}\n </button>\n )}\n </div>\n </footer>\n </div>\n </div>\n )\n}\n\nfunction DateInput(props: { label: string; value: string; onChange: (v: string) => void }) {\n return (\n <div>\n <label className=\"block text-xs text-muted-foreground mb-1\">{props.label}</label>\n <input\n type=\"date\"\n value={props.value}\n onChange={(e) => props.onChange(e.target.value)}\n className=\"w-full rounded-md border border-input bg-background px-2 py-1.5 text-sm\"\n />\n </div>\n )\n}\n\n// Local \"labelled number\" wrapper kept as a string-in/string-out facade so\n// the surrounding code (which threads `value` through `mergeTerm.months` as\n// a string) doesn't have to change. The actual input behaviour comes from\n// the shared `NumberInput` component (select-on-focus + internal string\n// state \u2014 see components/NumberInput.tsx for the rationale).\nfunction NumberInput(props: { label: string; value: string; onChange: (v: string) => void }) {\n return (\n <div>\n <label className=\"block text-xs text-muted-foreground mb-1\">{props.label}</label>\n <BaseNumberInput\n integer\n min={1}\n value={props.value === '' ? null : Number(props.value)}\n onChange={(n) => props.onChange(n == null ? '' : String(n))}\n />\n </div>\n )\n}\n\nfunction TextInput(props: { label: string; value: string; onChange: (v: string) => void }) {\n return (\n <div>\n <label className=\"block text-xs text-muted-foreground mb-1\">{props.label}</label>\n <input\n type=\"text\"\n value={props.value}\n onChange={(e) => props.onChange(e.target.value)}\n className=\"w-full rounded-md border border-input bg-background px-2 py-1.5 text-sm\"\n />\n </div>\n )\n}\n\n// Add `months` whole calendar months to an ISO date string (YYYY-MM-DD) and\n// return the result in the same format. Used by the renew config step so the\n// operator can edit just the months field and have the end date auto-update.\nfunction addMonthsToIso(iso: string, months: number): string {\n if (!iso) return iso\n const d = new Date(iso)\n if (Number.isNaN(d.getTime())) return iso\n d.setMonth(d.getMonth() + months)\n return d.toISOString().split('T')[0]\n}\n\n// Today as YYYY-MM-DD \u2014 used as the default `Start` when the operator types\n// a `Months` value first on a brand-new merge contract.\nfunction todayIso(): string {\n return new Date().toISOString().split('T')[0]\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -178,10 +178,13 @@ function PriceAdjustmentDialog(props) {
178
178
  ] }),
179
179
  draftKey && !previewing && !previewCharge && previewLine && /* @__PURE__ */ jsxs("span", { children: [
180
180
  t("cpq.priceAdjustments.dialog.previewLine", "Line totals"),
181
- ": MRC ",
181
+ ": ",
182
+ t("cpq.lines.mrc", "MRC"),
183
+ " ",
182
184
  /* @__PURE__ */ jsx("span", { className: "font-mono font-medium", children: money(previewLine.mrcTotal, currency) }),
183
185
  " \xB7 ",
184
- "NRC ",
186
+ t("cpq.lines.nrc", "NRC"),
187
+ " ",
185
188
  /* @__PURE__ */ jsx("span", { className: "font-mono font-medium", children: money(previewLine.nrcTotal, currency) })
186
189
  ] })
187
190
  ] }),
@@ -195,7 +198,7 @@ function PriceAdjustmentDialog(props) {
195
198
  ] }),
196
199
  /* @__PURE__ */ jsxs(DialogFooter, { children: [
197
200
  /* @__PURE__ */ jsx(Button, { variant: "outline", onClick: onClose, children: t("cpq.priceAdjustments.dialog.cancel", "Cancel") }),
198
- /* @__PURE__ */ jsx(Button, { onClick: () => void save(), disabled: !canSave, title: "Ctrl/Cmd+Enter", children: saving ? t("cpq.priceAdjustments.dialog.saving", "Saving\u2026") : t("cpq.priceAdjustments.dialog.save", "Save") })
201
+ /* @__PURE__ */ jsx(Button, { onClick: () => void save(), disabled: !canSave, title: t("cpq.priceAdjustments.dialog.saveShortcut", "Ctrl/Cmd+Enter"), children: saving ? t("cpq.priceAdjustments.dialog.saving", "Saving\u2026") : t("cpq.priceAdjustments.dialog.save", "Save") })
199
202
  ] })
200
203
  ] }) });
201
204
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../../../../src/modules/cpq/backend/cpq/quotes/%5Bid%5D/_components/PriceAdjustmentDialog.tsx"],
4
- "sourcesContent": ["'use client'\n\nimport * as React from 'react'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { apiCall } from '@open-mercato/ui/backend/utils/apiCall'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { Input } from '@open-mercato/ui/primitives/input'\nimport { Textarea } from '@open-mercato/ui/primitives/textarea'\nimport { Alert, AlertDescription } from '@open-mercato/ui/primitives/alert'\nimport { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from '@open-mercato/ui/primitives/dialog'\nimport { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@open-mercato/ui/primitives/select'\nimport {\n ADJUSTMENT_ERROR_FALLBACKS,\n adjustmentErrorCode,\n allowedAdjustmentTypes,\n buildAdjustmentDraft,\n formatDepth,\n discountDepth,\n toAdjustmentPatch,\n type AdjustmentForm,\n type AdjustmentTarget,\n type AdjustmentType,\n type WaterfallChargeInput,\n} from '../../../../../lib/priceAdjustmentView'\n\nexport type AdjustmentReason = { value: string; label: string }\n\n/** Minimal view of the quote the dialog needs, kept local so the page owns the full type. */\ntype PreviewQuote = {\n pricingRevision?: number\n lines: Array<{ lineId: string; mrcTotal: number; nrcTotal: number; charges: Array<WaterfallChargeInput & { chargeCode: string; adjustmentErrors?: Array<{ adjustmentId: string; code: string }> }> }>\n}\n\nexport type ExistingAdjustment = {\n id: string\n adjustmentType: AdjustmentType\n value: number\n reasonCode: string\n reasonNote?: string | null\n chargeTypeFilter?: 'nrc' | 'mrc' | null\n}\n\nexport type PriceAdjustmentDialogProps<Q extends PreviewQuote> = {\n open: boolean\n quoteId: string\n currency: string\n pricingRevision: number\n target: AdjustmentTarget\n /** Display name of the line / charge being adjusted. */\n targetLabel: string\n /** The charge for charge-level targets (drives type options and the current price). */\n charge?: WaterfallChargeInput & { chargeCode: string; chargeName: string }\n existing?: ExistingAdjustment | null\n /** Ids of adjustments already stored on the quote; their errors don't block this draft. */\n storedAdjustmentIds: string[]\n reasons: AdjustmentReason[]\n onClose: () => void\n onSaved: (quote: Q) => void\n /** Called when the server reports a stale revision; the page reloads the quote. */\n onStale: () => void\n}\n\nconst TYPE_FALLBACKS: Record<AdjustmentType, string> = {\n price_override: 'Set a new unit price',\n discount_percent: 'Percentage discount',\n discount_absolute: 'Amount off the charge total',\n}\n\nfunction money(amount: number, currency: string) {\n return new Intl.NumberFormat('en-US', { style: 'currency', currency }).format(amount)\n}\n\nexport function PriceAdjustmentDialog<Q extends PreviewQuote>(props: PriceAdjustmentDialogProps<Q>) {\n const { open, quoteId, currency, pricingRevision, target, targetLabel, charge, existing, storedAdjustmentIds, reasons, onClose, onSaved, onStale } = props\n const t = useT()\n const types = allowedAdjustmentTypes(target.level, charge)\n const initialForm = React.useCallback((): AdjustmentForm => ({\n adjustmentType: existing?.adjustmentType ?? types[0] ?? 'discount_percent',\n value: existing ? String(existing.value) : '',\n reasonCode: existing?.reasonCode ?? '',\n reasonNote: existing?.reasonNote ?? '',\n chargeTypeFilter: existing?.chargeTypeFilter ?? '',\n }), [existing, types])\n const [form, setForm] = React.useState<AdjustmentForm>(initialForm)\n const [preview, setPreview] = React.useState<{ quote: Q; errors: Array<{ adjustmentId: string; code: string }> } | null>(null)\n const [previewing, setPreviewing] = React.useState(false)\n const [errorCode, setErrorCode] = React.useState<string | null>(null)\n const [saving, setSaving] = React.useState(false)\n\n React.useEffect(() => {\n if (open) { setForm(initialForm()); setPreview(null); setErrorCode(null) }\n // Reset only when the dialog (re)opens.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [open])\n\n const draft = buildAdjustmentDraft(form, target, currency, pricingRevision)\n const draftKey = draft && form.reasonCode ? JSON.stringify(draft) : null\n const message = (code: string) => t(`cpq.priceAdjustments.errors.${code}`, ADJUSTMENT_ERROR_FALLBACKS[code] ?? code)\n\n // Debounced, side-effect-free preview of the draft.\n React.useEffect(() => {\n if (!open || !draftKey) { setPreview(null); return }\n let cancelled = false\n const timer = window.setTimeout(async () => {\n setPreviewing(true)\n const call = await apiCall<{ quote: Q; errors: Array<{ adjustmentId: string; code: string }> }>(\n `/api/cpq/quotes/${quoteId}/price-adjustments/preview`,\n { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ draft: JSON.parse(draftKey), ...(existing ? { replaceAdjustmentId: existing.id } : {}) }) },\n )\n if (cancelled) return\n setPreviewing(false)\n if (call.ok && call.result) { setPreview(call.result); setErrorCode(null) }\n else { setPreview(null); setErrorCode(adjustmentErrorCode(call.status, call.result)) }\n }, 400)\n return () => { cancelled = true; window.clearTimeout(timer) }\n }, [open, draftKey, quoteId, existing])\n\n const previewLine = preview?.quote.lines.find((line) => line.lineId === target.quoteLineId)\n const previewCharge = target.level === 'charge' ? previewLine?.charges.find((entry) => entry.chargeCode === target.chargeCode) : undefined\n // The draft's id is server-generated on create, so \"not stored\" identifies it; on edit it keeps its id.\n const previewErrors = preview?.errors.filter((error) => existing ? error.adjustmentId === existing.id : !storedAdjustmentIds.includes(error.adjustmentId)) ?? []\n const noteRequired = form.reasonCode === 'other' && !form.reasonNote.trim()\n const canSave = !!draft && !!form.reasonCode && !noteRequired && !saving && previewErrors.length === 0\n\n const save = async () => {\n if (!draft || !canSave) return\n setSaving(true); setErrorCode(null)\n const call = existing\n ? await apiCall<{ quote: Q }>(`/api/cpq/quotes/${quoteId}/price-adjustments/${existing.id}`, {\n method: 'PATCH', headers: { 'content-type': 'application/json' }, body: JSON.stringify(toAdjustmentPatch(draft)),\n })\n : await apiCall<{ quote: Q }>(`/api/cpq/quotes/${quoteId}/price-adjustments`, {\n method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify(draft),\n })\n setSaving(false)\n if (call.ok && call.result?.quote) { onSaved(call.result.quote); onClose(); return }\n setErrorCode(adjustmentErrorCode(call.status, call.result))\n }\n\n const onKeyDown = (event: React.KeyboardEvent) => {\n if ((event.metaKey || event.ctrlKey) && event.key === 'Enter') { event.preventDefault(); void save() }\n }\n\n const standardUnit = charge?.standardUnitPrice ?? charge?.unitPrice\n const valueHint = form.adjustmentType === 'discount_percent'\n ? t('cpq.priceAdjustments.dialog.percentHint', 'Percent off the standard price (0\u2013100)')\n : form.adjustmentType === 'price_override'\n ? t('cpq.priceAdjustments.dialog.overrideHint', 'New unit price, at most the standard price')\n : t('cpq.priceAdjustments.dialog.absoluteHint', 'Amount taken off this charge\u2019s total')\n\n return (\n <Dialog open={open} onOpenChange={(next) => { if (!next) onClose() }}>\n <DialogContent onKeyDown={onKeyDown} data-testid=\"cpq-price-adjustment-dialog\">\n <DialogHeader>\n <DialogTitle>\n {existing\n ? t('cpq.priceAdjustments.dialog.editTitle', 'Edit price adjustment')\n : target.level === 'line'\n ? t('cpq.priceAdjustments.dialog.lineTitle', 'Discount line')\n : t('cpq.priceAdjustments.dialog.chargeTitle', 'Adjust price')}\n </DialogTitle>\n <DialogDescription>\n {targetLabel}\n {charge && standardUnit !== undefined && (\n <> \u00B7 {t('cpq.priceAdjustments.dialog.standard', 'Standard')} {money(standardUnit, currency)}</>\n )}\n </DialogDescription>\n </DialogHeader>\n\n <div className=\"space-y-3 text-sm\">\n <label className=\"block space-y-1\">\n <span className=\"text-xs font-medium\">{t('cpq.priceAdjustments.dialog.type', 'Adjustment')}</span>\n <Select value={form.adjustmentType} onValueChange={(value) => setForm({ ...form, adjustmentType: value as AdjustmentType })}>\n <SelectTrigger><SelectValue /></SelectTrigger>\n <SelectContent>\n {types.map((type) => (\n <SelectItem key={type} value={type}>{t(`cpq.priceAdjustments.dialog.types.${type}`, TYPE_FALLBACKS[type])}</SelectItem>\n ))}\n </SelectContent>\n </Select>\n </label>\n\n {target.level === 'line' && (\n <label className=\"block space-y-1\">\n <span className=\"text-xs font-medium\">{t('cpq.priceAdjustments.dialog.appliesTo', 'Applies to')}</span>\n <Select value={form.chargeTypeFilter || 'all'} onValueChange={(value) => setForm({ ...form, chargeTypeFilter: value === 'all' ? '' : value as 'nrc' | 'mrc' })}>\n <SelectTrigger><SelectValue /></SelectTrigger>\n <SelectContent>\n <SelectItem value=\"all\">{t('cpq.priceAdjustments.dialog.allCharges', 'All one-time and recurring charges')}</SelectItem>\n <SelectItem value=\"mrc\">{t('cpq.priceAdjustments.dialog.mrcOnly', 'Recurring charges only')}</SelectItem>\n <SelectItem value=\"nrc\">{t('cpq.priceAdjustments.dialog.nrcOnly', 'One-time charges only')}</SelectItem>\n </SelectContent>\n </Select>\n </label>\n )}\n\n <label className=\"block space-y-1\">\n <span className=\"text-xs font-medium\">{t('cpq.priceAdjustments.dialog.value', 'Value')}</span>\n <Input inputMode=\"decimal\" autoFocus value={form.value} onChange={(event) => setForm({ ...form, value: event.target.value })} aria-describedby=\"cpq-adjustment-value-hint\" />\n <span id=\"cpq-adjustment-value-hint\" className=\"block text-xs text-muted-foreground\">{valueHint}</span>\n </label>\n\n <label className=\"block space-y-1\">\n <span className=\"text-xs font-medium\">{t('cpq.priceAdjustments.dialog.reason', 'Reason')}</span>\n <Select value={form.reasonCode} onValueChange={(value) => setForm({ ...form, reasonCode: value })}>\n <SelectTrigger><SelectValue placeholder={t('cpq.priceAdjustments.dialog.reasonPlaceholder', 'Pick a reason')} /></SelectTrigger>\n <SelectContent>\n {reasons.map((reason) => <SelectItem key={reason.value} value={reason.value}>{reason.label}</SelectItem>)}\n </SelectContent>\n </Select>\n </label>\n\n <label className=\"block space-y-1\">\n <span className=\"text-xs font-medium\">\n {t('cpq.priceAdjustments.dialog.note', 'Note')}{form.reasonCode === 'other' ? ' *' : ''}\n </span>\n <Textarea rows={2} maxLength={500} value={form.reasonNote} onChange={(event) => setForm({ ...form, reasonNote: event.target.value })} />\n </label>\n\n <div className=\"rounded border bg-muted/20 p-2 text-xs\" aria-live=\"polite\" data-testid=\"cpq-adjustment-preview\">\n {!draftKey && <span className=\"text-muted-foreground\">{t('cpq.priceAdjustments.dialog.previewEmpty', 'Enter a value and reason to preview the new price.')}</span>}\n {draftKey && previewing && <span className=\"text-muted-foreground\">{t('cpq.priceAdjustments.dialog.previewing', 'Calculating\u2026')}</span>}\n {draftKey && !previewing && previewCharge && (\n <span>\n {t('cpq.priceAdjustments.dialog.previewCharge', 'New offer price')}: <span className=\"font-mono font-medium\">{money(previewCharge.unitPrice, currency)}</span>\n {' '}{formatDepth(discountDepth(previewCharge.standardUnitPrice ?? standardUnit, previewCharge.unitPrice)) ?? ''}\n </span>\n )}\n {draftKey && !previewing && !previewCharge && previewLine && (\n <span>\n {t('cpq.priceAdjustments.dialog.previewLine', 'Line totals')}: MRC <span className=\"font-mono font-medium\">{money(previewLine.mrcTotal, currency)}</span>\n {' \u00B7 '}NRC <span className=\"font-mono font-medium\">{money(previewLine.nrcTotal, currency)}</span>\n </span>\n )}\n </div>\n\n {(errorCode || previewErrors.length > 0 || noteRequired) && (\n <Alert variant=\"warning\">\n <AlertDescription>\n {errorCode ? message(errorCode) : previewErrors.length > 0 ? message(previewErrors[0].code) : message('REASON_NOTE_REQUIRED')}\n {errorCode === 'STALE_REVISION' && (\n <Button variant=\"outline\" size=\"sm\" className=\"ml-2\" onClick={() => { onStale(); onClose() }}>\n {t('cpq.priceAdjustments.dialog.reload', 'Reload')}\n </Button>\n )}\n </AlertDescription>\n </Alert>\n )}\n </div>\n\n <DialogFooter>\n <Button variant=\"outline\" onClick={onClose}>{t('cpq.priceAdjustments.dialog.cancel', 'Cancel')}</Button>\n <Button onClick={() => void save()} disabled={!canSave} title=\"Ctrl/Cmd+Enter\">\n {saving ? t('cpq.priceAdjustments.dialog.saving', 'Saving\u2026') : t('cpq.priceAdjustments.dialog.save', 'Save')}\n </Button>\n </DialogFooter>\n </DialogContent>\n </Dialog>\n )\n}\n"],
5
- "mappings": ";AA0JU,SAUI,UAVJ,KAUI,YAVJ;AAxJV,YAAY,WAAW;AACvB,SAAS,YAAY;AACrB,SAAS,eAAe;AACxB,SAAS,cAAc;AACvB,SAAS,aAAa;AACtB,SAAS,gBAAgB;AACzB,SAAS,OAAO,wBAAwB;AACxC,SAAS,QAAQ,eAAe,mBAAmB,cAAc,cAAc,mBAAmB;AAClG,SAAS,QAAQ,eAAe,YAAY,eAAe,mBAAmB;AAC9E;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAKK;AAuCP,MAAM,iBAAiD;AAAA,EACrD,gBAAgB;AAAA,EAChB,kBAAkB;AAAA,EAClB,mBAAmB;AACrB;AAEA,SAAS,MAAM,QAAgB,UAAkB;AAC/C,SAAO,IAAI,KAAK,aAAa,SAAS,EAAE,OAAO,YAAY,SAAS,CAAC,EAAE,OAAO,MAAM;AACtF;AAEO,SAAS,sBAA8C,OAAsC;AAClG,QAAM,EAAE,MAAM,SAAS,UAAU,iBAAiB,QAAQ,aAAa,QAAQ,UAAU,qBAAqB,SAAS,SAAS,SAAS,QAAQ,IAAI;AACrJ,QAAM,IAAI,KAAK;AACf,QAAM,QAAQ,uBAAuB,OAAO,OAAO,MAAM;AACzD,QAAM,cAAc,MAAM,YAAY,OAAuB;AAAA,IAC3D,gBAAgB,UAAU,kBAAkB,MAAM,CAAC,KAAK;AAAA,IACxD,OAAO,WAAW,OAAO,SAAS,KAAK,IAAI;AAAA,IAC3C,YAAY,UAAU,cAAc;AAAA,IACpC,YAAY,UAAU,cAAc;AAAA,IACpC,kBAAkB,UAAU,oBAAoB;AAAA,EAClD,IAAI,CAAC,UAAU,KAAK,CAAC;AACrB,QAAM,CAAC,MAAM,OAAO,IAAI,MAAM,SAAyB,WAAW;AAClE,QAAM,CAAC,SAAS,UAAU,IAAI,MAAM,SAAqF,IAAI;AAC7H,QAAM,CAAC,YAAY,aAAa,IAAI,MAAM,SAAS,KAAK;AACxD,QAAM,CAAC,WAAW,YAAY,IAAI,MAAM,SAAwB,IAAI;AACpE,QAAM,CAAC,QAAQ,SAAS,IAAI,MAAM,SAAS,KAAK;AAEhD,QAAM,UAAU,MAAM;AACpB,QAAI,MAAM;AAAE,cAAQ,YAAY,CAAC;AAAG,iBAAW,IAAI;AAAG,mBAAa,IAAI;AAAA,IAAE;AAAA,EAG3E,GAAG,CAAC,IAAI,CAAC;AAET,QAAM,QAAQ,qBAAqB,MAAM,QAAQ,UAAU,eAAe;AAC1E,QAAM,WAAW,SAAS,KAAK,aAAa,KAAK,UAAU,KAAK,IAAI;AACpE,QAAM,UAAU,CAAC,SAAiB,EAAE,+BAA+B,IAAI,IAAI,2BAA2B,IAAI,KAAK,IAAI;AAGnH,QAAM,UAAU,MAAM;AACpB,QAAI,CAAC,QAAQ,CAAC,UAAU;AAAE,iBAAW,IAAI;AAAG;AAAA,IAAO;AACnD,QAAI,YAAY;AAChB,UAAM,QAAQ,OAAO,WAAW,YAAY;AAC1C,oBAAc,IAAI;AAClB,YAAM,OAAO,MAAM;AAAA,QACjB,mBAAmB,OAAO;AAAA,QAC1B,EAAE,QAAQ,QAAQ,SAAS,EAAE,gBAAgB,mBAAmB,GAAG,MAAM,KAAK,UAAU,EAAE,OAAO,KAAK,MAAM,QAAQ,GAAG,GAAI,WAAW,EAAE,qBAAqB,SAAS,GAAG,IAAI,CAAC,EAAG,CAAC,EAAE;AAAA,MACtL;AACA,UAAI,UAAW;AACf,oBAAc,KAAK;AACnB,UAAI,KAAK,MAAM,KAAK,QAAQ;AAAE,mBAAW,KAAK,MAAM;AAAG,qBAAa,IAAI;AAAA,MAAE,OACrE;AAAE,mBAAW,IAAI;AAAG,qBAAa,oBAAoB,KAAK,QAAQ,KAAK,MAAM,CAAC;AAAA,MAAE;AAAA,IACvF,GAAG,GAAG;AACN,WAAO,MAAM;AAAE,kBAAY;AAAM,aAAO,aAAa,KAAK;AAAA,IAAE;AAAA,EAC9D,GAAG,CAAC,MAAM,UAAU,SAAS,QAAQ,CAAC;AAEtC,QAAM,cAAc,SAAS,MAAM,MAAM,KAAK,CAAC,SAAS,KAAK,WAAW,OAAO,WAAW;AAC1F,QAAM,gBAAgB,OAAO,UAAU,WAAW,aAAa,QAAQ,KAAK,CAAC,UAAU,MAAM,eAAe,OAAO,UAAU,IAAI;AAEjI,QAAM,gBAAgB,SAAS,OAAO,OAAO,CAAC,UAAU,WAAW,MAAM,iBAAiB,SAAS,KAAK,CAAC,oBAAoB,SAAS,MAAM,YAAY,CAAC,KAAK,CAAC;AAC/J,QAAM,eAAe,KAAK,eAAe,WAAW,CAAC,KAAK,WAAW,KAAK;AAC1E,QAAM,UAAU,CAAC,CAAC,SAAS,CAAC,CAAC,KAAK,cAAc,CAAC,gBAAgB,CAAC,UAAU,cAAc,WAAW;AAErG,QAAM,OAAO,YAAY;AACvB,QAAI,CAAC,SAAS,CAAC,QAAS;AACxB,cAAU,IAAI;AAAG,iBAAa,IAAI;AAClC,UAAM,OAAO,WACT,MAAM,QAAsB,mBAAmB,OAAO,sBAAsB,SAAS,EAAE,IAAI;AAAA,MAC3F,QAAQ;AAAA,MAAS,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,MAAG,MAAM,KAAK,UAAU,kBAAkB,KAAK,CAAC;AAAA,IACjH,CAAC,IACC,MAAM,QAAsB,mBAAmB,OAAO,sBAAsB;AAAA,MAC5E,QAAQ;AAAA,MAAQ,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,MAAG,MAAM,KAAK,UAAU,KAAK;AAAA,IAC7F,CAAC;AACH,cAAU,KAAK;AACf,QAAI,KAAK,MAAM,KAAK,QAAQ,OAAO;AAAE,cAAQ,KAAK,OAAO,KAAK;AAAG,cAAQ;AAAG;AAAA,IAAO;AACnF,iBAAa,oBAAoB,KAAK,QAAQ,KAAK,MAAM,CAAC;AAAA,EAC5D;AAEA,QAAM,YAAY,CAAC,UAA+B;AAChD,SAAK,MAAM,WAAW,MAAM,YAAY,MAAM,QAAQ,SAAS;AAAE,YAAM,eAAe;AAAG,WAAK,KAAK;AAAA,IAAE;AAAA,EACvG;AAEA,QAAM,eAAe,QAAQ,qBAAqB,QAAQ;AAC1D,QAAM,YAAY,KAAK,mBAAmB,qBACtC,EAAE,2CAA2C,6CAAwC,IACrF,KAAK,mBAAmB,mBACtB,EAAE,4CAA4C,4CAA4C,IAC1F,EAAE,4CAA4C,2CAAsC;AAE1F,SACE,oBAAC,UAAO,MAAY,cAAc,CAAC,SAAS;AAAE,QAAI,CAAC,KAAM,SAAQ;AAAA,EAAE,GACjE,+BAAC,iBAAc,WAAsB,eAAY,+BAC/C;AAAA,yBAAC,gBACC;AAAA,0BAAC,eACE,qBACG,EAAE,yCAAyC,uBAAuB,IAClE,OAAO,UAAU,SACf,EAAE,yCAAyC,eAAe,IAC1D,EAAE,2CAA2C,cAAc,GACnE;AAAA,MACA,qBAAC,qBACE;AAAA;AAAA,QACA,UAAU,iBAAiB,UAC1B,iCAAE;AAAA;AAAA,UAAI,EAAE,wCAAwC,UAAU;AAAA,UAAE;AAAA,UAAE,MAAM,cAAc,QAAQ;AAAA,WAAE;AAAA,SAEhG;AAAA,OACF;AAAA,IAEA,qBAAC,SAAI,WAAU,qBACb;AAAA,2BAAC,WAAM,WAAU,mBACf;AAAA,4BAAC,UAAK,WAAU,uBAAuB,YAAE,oCAAoC,YAAY,GAAE;AAAA,QAC3F,qBAAC,UAAO,OAAO,KAAK,gBAAgB,eAAe,CAAC,UAAU,QAAQ,EAAE,GAAG,MAAM,gBAAgB,MAAwB,CAAC,GACxH;AAAA,8BAAC,iBAAc,8BAAC,eAAY,GAAE;AAAA,UAC9B,oBAAC,iBACE,gBAAM,IAAI,CAAC,SACV,oBAAC,cAAsB,OAAO,MAAO,YAAE,qCAAqC,IAAI,IAAI,eAAe,IAAI,CAAC,KAAvF,IAAyF,CAC3G,GACH;AAAA,WACF;AAAA,SACF;AAAA,MAEC,OAAO,UAAU,UAChB,qBAAC,WAAM,WAAU,mBACf;AAAA,4BAAC,UAAK,WAAU,uBAAuB,YAAE,yCAAyC,YAAY,GAAE;AAAA,QAChG,qBAAC,UAAO,OAAO,KAAK,oBAAoB,OAAO,eAAe,CAAC,UAAU,QAAQ,EAAE,GAAG,MAAM,kBAAkB,UAAU,QAAQ,KAAK,MAAuB,CAAC,GAC3J;AAAA,8BAAC,iBAAc,8BAAC,eAAY,GAAE;AAAA,UAC9B,qBAAC,iBACC;AAAA,gCAAC,cAAW,OAAM,OAAO,YAAE,0CAA0C,oCAAoC,GAAE;AAAA,YAC3G,oBAAC,cAAW,OAAM,OAAO,YAAE,uCAAuC,wBAAwB,GAAE;AAAA,YAC5F,oBAAC,cAAW,OAAM,OAAO,YAAE,uCAAuC,uBAAuB,GAAE;AAAA,aAC7F;AAAA,WACF;AAAA,SACF;AAAA,MAGF,qBAAC,WAAM,WAAU,mBACf;AAAA,4BAAC,UAAK,WAAU,uBAAuB,YAAE,qCAAqC,OAAO,GAAE;AAAA,QACvF,oBAAC,SAAM,WAAU,WAAU,WAAS,MAAC,OAAO,KAAK,OAAO,UAAU,CAAC,UAAU,QAAQ,EAAE,GAAG,MAAM,OAAO,MAAM,OAAO,MAAM,CAAC,GAAG,oBAAiB,6BAA4B;AAAA,QAC3K,oBAAC,UAAK,IAAG,6BAA4B,WAAU,uCAAuC,qBAAU;AAAA,SAClG;AAAA,MAEA,qBAAC,WAAM,WAAU,mBACf;AAAA,4BAAC,UAAK,WAAU,uBAAuB,YAAE,sCAAsC,QAAQ,GAAE;AAAA,QACzF,qBAAC,UAAO,OAAO,KAAK,YAAY,eAAe,CAAC,UAAU,QAAQ,EAAE,GAAG,MAAM,YAAY,MAAM,CAAC,GAC9F;AAAA,8BAAC,iBAAc,8BAAC,eAAY,aAAa,EAAE,iDAAiD,eAAe,GAAG,GAAE;AAAA,UAChH,oBAAC,iBACE,kBAAQ,IAAI,CAAC,WAAW,oBAAC,cAA8B,OAAO,OAAO,OAAQ,iBAAO,SAA3C,OAAO,KAA0C,CAAa,GAC1G;AAAA,WACF;AAAA,SACF;AAAA,MAEA,qBAAC,WAAM,WAAU,mBACf;AAAA,6BAAC,UAAK,WAAU,uBACb;AAAA,YAAE,oCAAoC,MAAM;AAAA,UAAG,KAAK,eAAe,UAAU,OAAO;AAAA,WACvF;AAAA,QACA,oBAAC,YAAS,MAAM,GAAG,WAAW,KAAK,OAAO,KAAK,YAAY,UAAU,CAAC,UAAU,QAAQ,EAAE,GAAG,MAAM,YAAY,MAAM,OAAO,MAAM,CAAC,GAAG;AAAA,SACxI;AAAA,MAEA,qBAAC,SAAI,WAAU,0CAAyC,aAAU,UAAS,eAAY,0BACpF;AAAA,SAAC,YAAY,oBAAC,UAAK,WAAU,yBAAyB,YAAE,4CAA4C,oDAAoD,GAAE;AAAA,QAC1J,YAAY,cAAc,oBAAC,UAAK,WAAU,yBAAyB,YAAE,0CAA0C,mBAAc,GAAE;AAAA,QAC/H,YAAY,CAAC,cAAc,iBAC1B,qBAAC,UACE;AAAA,YAAE,6CAA6C,iBAAiB;AAAA,UAAE;AAAA,UAAE,oBAAC,UAAK,WAAU,yBAAyB,gBAAM,cAAc,WAAW,QAAQ,GAAE;AAAA,UACtJ;AAAA,UAAK,YAAY,cAAc,cAAc,qBAAqB,cAAc,cAAc,SAAS,CAAC,KAAK;AAAA,WAChH;AAAA,QAED,YAAY,CAAC,cAAc,CAAC,iBAAiB,eAC5C,qBAAC,UACE;AAAA,YAAE,2CAA2C,aAAa;AAAA,UAAE;AAAA,UAAM,oBAAC,UAAK,WAAU,yBAAyB,gBAAM,YAAY,UAAU,QAAQ,GAAE;AAAA,UACjJ;AAAA,UAAM;AAAA,UAAI,oBAAC,UAAK,WAAU,yBAAyB,gBAAM,YAAY,UAAU,QAAQ,GAAE;AAAA,WAC5F;AAAA,SAEJ;AAAA,OAEE,aAAa,cAAc,SAAS,KAAK,iBACzC,oBAAC,SAAM,SAAQ,WACb,+BAAC,oBACE;AAAA,oBAAY,QAAQ,SAAS,IAAI,cAAc,SAAS,IAAI,QAAQ,cAAc,CAAC,EAAE,IAAI,IAAI,QAAQ,sBAAsB;AAAA,QAC3H,cAAc,oBACb,oBAAC,UAAO,SAAQ,WAAU,MAAK,MAAK,WAAU,QAAO,SAAS,MAAM;AAAE,kBAAQ;AAAG,kBAAQ;AAAA,QAAE,GACxF,YAAE,sCAAsC,QAAQ,GACnD;AAAA,SAEJ,GACF;AAAA,OAEJ;AAAA,IAEA,qBAAC,gBACC;AAAA,0BAAC,UAAO,SAAQ,WAAU,SAAS,SAAU,YAAE,sCAAsC,QAAQ,GAAE;AAAA,MAC/F,oBAAC,UAAO,SAAS,MAAM,KAAK,KAAK,GAAG,UAAU,CAAC,SAAS,OAAM,kBAC3D,mBAAS,EAAE,sCAAsC,cAAS,IAAI,EAAE,oCAAoC,MAAM,GAC7G;AAAA,OACF;AAAA,KACF,GACF;AAEJ;",
4
+ "sourcesContent": ["'use client'\n\nimport * as React from 'react'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { apiCall } from '@open-mercato/ui/backend/utils/apiCall'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { Input } from '@open-mercato/ui/primitives/input'\nimport { Textarea } from '@open-mercato/ui/primitives/textarea'\nimport { Alert, AlertDescription } from '@open-mercato/ui/primitives/alert'\nimport { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from '@open-mercato/ui/primitives/dialog'\nimport { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@open-mercato/ui/primitives/select'\nimport {\n ADJUSTMENT_ERROR_FALLBACKS,\n adjustmentErrorCode,\n allowedAdjustmentTypes,\n buildAdjustmentDraft,\n formatDepth,\n discountDepth,\n toAdjustmentPatch,\n type AdjustmentForm,\n type AdjustmentTarget,\n type AdjustmentType,\n type WaterfallChargeInput,\n} from '../../../../../lib/priceAdjustmentView'\n\nexport type AdjustmentReason = { value: string; label: string }\n\n/** Minimal view of the quote the dialog needs, kept local so the page owns the full type. */\ntype PreviewQuote = {\n pricingRevision?: number\n lines: Array<{ lineId: string; mrcTotal: number; nrcTotal: number; charges: Array<WaterfallChargeInput & { chargeCode: string; adjustmentErrors?: Array<{ adjustmentId: string; code: string }> }> }>\n}\n\nexport type ExistingAdjustment = {\n id: string\n adjustmentType: AdjustmentType\n value: number\n reasonCode: string\n reasonNote?: string | null\n chargeTypeFilter?: 'nrc' | 'mrc' | null\n}\n\nexport type PriceAdjustmentDialogProps<Q extends PreviewQuote> = {\n open: boolean\n quoteId: string\n currency: string\n pricingRevision: number\n target: AdjustmentTarget\n /** Display name of the line / charge being adjusted. */\n targetLabel: string\n /** The charge for charge-level targets (drives type options and the current price). */\n charge?: WaterfallChargeInput & { chargeCode: string; chargeName: string }\n existing?: ExistingAdjustment | null\n /** Ids of adjustments already stored on the quote; their errors don't block this draft. */\n storedAdjustmentIds: string[]\n reasons: AdjustmentReason[]\n onClose: () => void\n onSaved: (quote: Q) => void\n /** Called when the server reports a stale revision; the page reloads the quote. */\n onStale: () => void\n}\n\nconst TYPE_FALLBACKS: Record<AdjustmentType, string> = {\n price_override: 'Set a new unit price',\n discount_percent: 'Percentage discount',\n discount_absolute: 'Amount off the charge total',\n}\n\nfunction money(amount: number, currency: string) {\n return new Intl.NumberFormat('en-US', { style: 'currency', currency }).format(amount)\n}\n\nexport function PriceAdjustmentDialog<Q extends PreviewQuote>(props: PriceAdjustmentDialogProps<Q>) {\n const { open, quoteId, currency, pricingRevision, target, targetLabel, charge, existing, storedAdjustmentIds, reasons, onClose, onSaved, onStale } = props\n const t = useT()\n const types = allowedAdjustmentTypes(target.level, charge)\n const initialForm = React.useCallback((): AdjustmentForm => ({\n adjustmentType: existing?.adjustmentType ?? types[0] ?? 'discount_percent',\n value: existing ? String(existing.value) : '',\n reasonCode: existing?.reasonCode ?? '',\n reasonNote: existing?.reasonNote ?? '',\n chargeTypeFilter: existing?.chargeTypeFilter ?? '',\n }), [existing, types])\n const [form, setForm] = React.useState<AdjustmentForm>(initialForm)\n const [preview, setPreview] = React.useState<{ quote: Q; errors: Array<{ adjustmentId: string; code: string }> } | null>(null)\n const [previewing, setPreviewing] = React.useState(false)\n const [errorCode, setErrorCode] = React.useState<string | null>(null)\n const [saving, setSaving] = React.useState(false)\n\n React.useEffect(() => {\n if (open) { setForm(initialForm()); setPreview(null); setErrorCode(null) }\n // Reset only when the dialog (re)opens.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [open])\n\n const draft = buildAdjustmentDraft(form, target, currency, pricingRevision)\n const draftKey = draft && form.reasonCode ? JSON.stringify(draft) : null\n const message = (code: string) => t(`cpq.priceAdjustments.errors.${code}`, ADJUSTMENT_ERROR_FALLBACKS[code] ?? code)\n\n // Debounced, side-effect-free preview of the draft.\n React.useEffect(() => {\n if (!open || !draftKey) { setPreview(null); return }\n let cancelled = false\n const timer = window.setTimeout(async () => {\n setPreviewing(true)\n const call = await apiCall<{ quote: Q; errors: Array<{ adjustmentId: string; code: string }> }>(\n `/api/cpq/quotes/${quoteId}/price-adjustments/preview`,\n { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ draft: JSON.parse(draftKey), ...(existing ? { replaceAdjustmentId: existing.id } : {}) }) },\n )\n if (cancelled) return\n setPreviewing(false)\n if (call.ok && call.result) { setPreview(call.result); setErrorCode(null) }\n else { setPreview(null); setErrorCode(adjustmentErrorCode(call.status, call.result)) }\n }, 400)\n return () => { cancelled = true; window.clearTimeout(timer) }\n }, [open, draftKey, quoteId, existing])\n\n const previewLine = preview?.quote.lines.find((line) => line.lineId === target.quoteLineId)\n const previewCharge = target.level === 'charge' ? previewLine?.charges.find((entry) => entry.chargeCode === target.chargeCode) : undefined\n // The draft's id is server-generated on create, so \"not stored\" identifies it; on edit it keeps its id.\n const previewErrors = preview?.errors.filter((error) => existing ? error.adjustmentId === existing.id : !storedAdjustmentIds.includes(error.adjustmentId)) ?? []\n const noteRequired = form.reasonCode === 'other' && !form.reasonNote.trim()\n const canSave = !!draft && !!form.reasonCode && !noteRequired && !saving && previewErrors.length === 0\n\n const save = async () => {\n if (!draft || !canSave) return\n setSaving(true); setErrorCode(null)\n const call = existing\n ? await apiCall<{ quote: Q }>(`/api/cpq/quotes/${quoteId}/price-adjustments/${existing.id}`, {\n method: 'PATCH', headers: { 'content-type': 'application/json' }, body: JSON.stringify(toAdjustmentPatch(draft)),\n })\n : await apiCall<{ quote: Q }>(`/api/cpq/quotes/${quoteId}/price-adjustments`, {\n method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify(draft),\n })\n setSaving(false)\n if (call.ok && call.result?.quote) { onSaved(call.result.quote); onClose(); return }\n setErrorCode(adjustmentErrorCode(call.status, call.result))\n }\n\n const onKeyDown = (event: React.KeyboardEvent) => {\n if ((event.metaKey || event.ctrlKey) && event.key === 'Enter') { event.preventDefault(); void save() }\n }\n\n const standardUnit = charge?.standardUnitPrice ?? charge?.unitPrice\n const valueHint = form.adjustmentType === 'discount_percent'\n ? t('cpq.priceAdjustments.dialog.percentHint', 'Percent off the standard price (0\u2013100)')\n : form.adjustmentType === 'price_override'\n ? t('cpq.priceAdjustments.dialog.overrideHint', 'New unit price, at most the standard price')\n : t('cpq.priceAdjustments.dialog.absoluteHint', 'Amount taken off this charge\u2019s total')\n\n return (\n <Dialog open={open} onOpenChange={(next) => { if (!next) onClose() }}>\n <DialogContent onKeyDown={onKeyDown} data-testid=\"cpq-price-adjustment-dialog\">\n <DialogHeader>\n <DialogTitle>\n {existing\n ? t('cpq.priceAdjustments.dialog.editTitle', 'Edit price adjustment')\n : target.level === 'line'\n ? t('cpq.priceAdjustments.dialog.lineTitle', 'Discount line')\n : t('cpq.priceAdjustments.dialog.chargeTitle', 'Adjust price')}\n </DialogTitle>\n <DialogDescription>\n {targetLabel}\n {charge && standardUnit !== undefined && (\n <> \u00B7 {t('cpq.priceAdjustments.dialog.standard', 'Standard')} {money(standardUnit, currency)}</>\n )}\n </DialogDescription>\n </DialogHeader>\n\n <div className=\"space-y-3 text-sm\">\n <label className=\"block space-y-1\">\n <span className=\"text-xs font-medium\">{t('cpq.priceAdjustments.dialog.type', 'Adjustment')}</span>\n <Select value={form.adjustmentType} onValueChange={(value) => setForm({ ...form, adjustmentType: value as AdjustmentType })}>\n <SelectTrigger><SelectValue /></SelectTrigger>\n <SelectContent>\n {types.map((type) => (\n <SelectItem key={type} value={type}>{t(`cpq.priceAdjustments.dialog.types.${type}`, TYPE_FALLBACKS[type])}</SelectItem>\n ))}\n </SelectContent>\n </Select>\n </label>\n\n {target.level === 'line' && (\n <label className=\"block space-y-1\">\n <span className=\"text-xs font-medium\">{t('cpq.priceAdjustments.dialog.appliesTo', 'Applies to')}</span>\n <Select value={form.chargeTypeFilter || 'all'} onValueChange={(value) => setForm({ ...form, chargeTypeFilter: value === 'all' ? '' : value as 'nrc' | 'mrc' })}>\n <SelectTrigger><SelectValue /></SelectTrigger>\n <SelectContent>\n <SelectItem value=\"all\">{t('cpq.priceAdjustments.dialog.allCharges', 'All one-time and recurring charges')}</SelectItem>\n <SelectItem value=\"mrc\">{t('cpq.priceAdjustments.dialog.mrcOnly', 'Recurring charges only')}</SelectItem>\n <SelectItem value=\"nrc\">{t('cpq.priceAdjustments.dialog.nrcOnly', 'One-time charges only')}</SelectItem>\n </SelectContent>\n </Select>\n </label>\n )}\n\n <label className=\"block space-y-1\">\n <span className=\"text-xs font-medium\">{t('cpq.priceAdjustments.dialog.value', 'Value')}</span>\n <Input inputMode=\"decimal\" autoFocus value={form.value} onChange={(event) => setForm({ ...form, value: event.target.value })} aria-describedby=\"cpq-adjustment-value-hint\" />\n <span id=\"cpq-adjustment-value-hint\" className=\"block text-xs text-muted-foreground\">{valueHint}</span>\n </label>\n\n <label className=\"block space-y-1\">\n <span className=\"text-xs font-medium\">{t('cpq.priceAdjustments.dialog.reason', 'Reason')}</span>\n <Select value={form.reasonCode} onValueChange={(value) => setForm({ ...form, reasonCode: value })}>\n <SelectTrigger><SelectValue placeholder={t('cpq.priceAdjustments.dialog.reasonPlaceholder', 'Pick a reason')} /></SelectTrigger>\n <SelectContent>\n {reasons.map((reason) => <SelectItem key={reason.value} value={reason.value}>{reason.label}</SelectItem>)}\n </SelectContent>\n </Select>\n </label>\n\n <label className=\"block space-y-1\">\n <span className=\"text-xs font-medium\">\n {t('cpq.priceAdjustments.dialog.note', 'Note')}{form.reasonCode === 'other' ? ' *' : ''}\n </span>\n <Textarea rows={2} maxLength={500} value={form.reasonNote} onChange={(event) => setForm({ ...form, reasonNote: event.target.value })} />\n </label>\n\n <div className=\"rounded border bg-muted/20 p-2 text-xs\" aria-live=\"polite\" data-testid=\"cpq-adjustment-preview\">\n {!draftKey && <span className=\"text-muted-foreground\">{t('cpq.priceAdjustments.dialog.previewEmpty', 'Enter a value and reason to preview the new price.')}</span>}\n {draftKey && previewing && <span className=\"text-muted-foreground\">{t('cpq.priceAdjustments.dialog.previewing', 'Calculating\u2026')}</span>}\n {draftKey && !previewing && previewCharge && (\n <span>\n {t('cpq.priceAdjustments.dialog.previewCharge', 'New offer price')}: <span className=\"font-mono font-medium\">{money(previewCharge.unitPrice, currency)}</span>\n {' '}{formatDepth(discountDepth(previewCharge.standardUnitPrice ?? standardUnit, previewCharge.unitPrice)) ?? ''}\n </span>\n )}\n {draftKey && !previewing && !previewCharge && previewLine && (\n <span>\n {t('cpq.priceAdjustments.dialog.previewLine', 'Line totals')}: {t('cpq.lines.mrc', 'MRC')} <span className=\"font-mono font-medium\">{money(previewLine.mrcTotal, currency)}</span>\n {' \u00B7 '}{t('cpq.lines.nrc', 'NRC')} <span className=\"font-mono font-medium\">{money(previewLine.nrcTotal, currency)}</span>\n </span>\n )}\n </div>\n\n {(errorCode || previewErrors.length > 0 || noteRequired) && (\n <Alert variant=\"warning\">\n <AlertDescription>\n {errorCode ? message(errorCode) : previewErrors.length > 0 ? message(previewErrors[0].code) : message('REASON_NOTE_REQUIRED')}\n {errorCode === 'STALE_REVISION' && (\n <Button variant=\"outline\" size=\"sm\" className=\"ml-2\" onClick={() => { onStale(); onClose() }}>\n {t('cpq.priceAdjustments.dialog.reload', 'Reload')}\n </Button>\n )}\n </AlertDescription>\n </Alert>\n )}\n </div>\n\n <DialogFooter>\n <Button variant=\"outline\" onClick={onClose}>{t('cpq.priceAdjustments.dialog.cancel', 'Cancel')}</Button>\n <Button onClick={() => void save()} disabled={!canSave} title={t('cpq.priceAdjustments.dialog.saveShortcut', 'Ctrl/Cmd+Enter')}>\n {saving ? t('cpq.priceAdjustments.dialog.saving', 'Saving\u2026') : t('cpq.priceAdjustments.dialog.save', 'Save')}\n </Button>\n </DialogFooter>\n </DialogContent>\n </Dialog>\n )\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }