@dainamite/cpq 0.2.2 → 0.4.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 (59) hide show
  1. package/CHANGELOG.md +62 -0
  2. package/MIGRATION.md +34 -1
  3. package/README.md +17 -12
  4. package/dist/modules/cpq/api/product-attributes/route.js +28 -53
  5. package/dist/modules/cpq/api/product-attributes/route.js.map +2 -2
  6. package/dist/modules/cpq/api/product-charges/route.js +12 -2
  7. package/dist/modules/cpq/api/product-charges/route.js.map +2 -2
  8. package/dist/modules/cpq/api/product-offerings/route.js +2 -0
  9. package/dist/modules/cpq/api/product-offerings/route.js.map +2 -2
  10. package/dist/modules/cpq/backend/cpq/offerings/[id]/page.js +128 -59
  11. package/dist/modules/cpq/backend/cpq/offerings/[id]/page.js.map +2 -2
  12. package/dist/modules/cpq/backend/cpq/pricing/[id]/EntriesEditor.js +11 -11
  13. package/dist/modules/cpq/backend/cpq/pricing/[id]/EntriesEditor.js.map +2 -2
  14. package/dist/modules/cpq/backend/cpq/specifications/[id]/page.js +55 -1
  15. package/dist/modules/cpq/backend/cpq/specifications/[id]/page.js.map +2 -2
  16. package/dist/modules/cpq/cli.js +58 -4
  17. package/dist/modules/cpq/cli.js.map +3 -3
  18. package/dist/modules/cpq/data/charge-pricing.js +12 -0
  19. package/dist/modules/cpq/data/charge-pricing.js.map +7 -0
  20. package/dist/modules/cpq/data/entities.js +3 -0
  21. package/dist/modules/cpq/data/entities.js.map +2 -2
  22. package/dist/modules/cpq/data/validators.js +36 -15
  23. package/dist/modules/cpq/data/validators.js.map +2 -2
  24. package/dist/modules/cpq/events.js +7 -0
  25. package/dist/modules/cpq/events.js.map +2 -2
  26. package/dist/modules/cpq/lib/seeds/demo.js +103 -0
  27. package/dist/modules/cpq/lib/seeds/demo.js.map +7 -0
  28. package/dist/modules/cpq/migrations/Migration20260602000000_cpq_charge_model_split.js +28 -0
  29. package/dist/modules/cpq/migrations/Migration20260602000000_cpq_charge_model_split.js.map +7 -0
  30. package/dist/modules/cpq/services/cpqOrderService.js +130 -76
  31. package/dist/modules/cpq/services/cpqOrderService.js.map +2 -2
  32. package/dist/modules/cpq/services/cpqPricingService.js +53 -29
  33. package/dist/modules/cpq/services/cpqPricingService.js.map +3 -3
  34. package/dist/modules/cpq/services/types.js.map +2 -2
  35. package/package.json +11 -9
  36. package/src/modules/cpq/__integration__/TC-CPQ-012.spec.ts +34 -4
  37. package/src/modules/cpq/__tests__/package-isolation.test.ts +8 -3
  38. package/src/modules/cpq/api/product-attributes/__tests__/serializeAttribute.test.ts +62 -0
  39. package/src/modules/cpq/api/product-attributes/route.ts +34 -52
  40. package/src/modules/cpq/api/product-charges/route.ts +23 -2
  41. package/src/modules/cpq/api/product-offerings/route.ts +2 -0
  42. package/src/modules/cpq/backend/cpq/offerings/[id]/page.tsx +151 -62
  43. package/src/modules/cpq/backend/cpq/pricing/[id]/EntriesEditor.tsx +24 -22
  44. package/src/modules/cpq/backend/cpq/specifications/[id]/page.tsx +73 -1
  45. package/src/modules/cpq/cli.ts +83 -4
  46. package/src/modules/cpq/data/__tests__/charge-pricing.test.ts +49 -0
  47. package/src/modules/cpq/data/__tests__/validators.test.ts +60 -5
  48. package/src/modules/cpq/data/charge-pricing.ts +48 -0
  49. package/src/modules/cpq/data/entities.ts +10 -0
  50. package/src/modules/cpq/data/validators.ts +56 -26
  51. package/src/modules/cpq/events.ts +11 -3
  52. package/src/modules/cpq/lib/seeds/__tests__/demo.test.ts +78 -0
  53. package/src/modules/cpq/lib/seeds/demo.ts +145 -0
  54. package/src/modules/cpq/migrations/.snapshot-open-mercato.json +16 -0
  55. package/src/modules/cpq/migrations/Migration20260602000000_cpq_charge_model_split.ts +57 -0
  56. package/src/modules/cpq/services/__tests__/cpqPricingService.test.ts +172 -1
  57. package/src/modules/cpq/services/cpqOrderService.ts +214 -103
  58. package/src/modules/cpq/services/cpqPricingService.ts +82 -34
  59. package/src/modules/cpq/services/types.ts +4 -1
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../../../src/modules/cpq/backend/cpq/offerings/%5Bid%5D/page.tsx"],
4
- "sourcesContent": ["\"use client\"\nimport * as React from 'react'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { useParams, useRouter } from 'next/navigation'\nimport { Alert } from '@open-mercato/ui/primitives/alert'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { Tag } from '@open-mercato/ui/primitives/tag'\nimport { NumberInput } from '../../../../components/NumberInput'\nimport {\n chargeTypeMap,\n formatStatusLabel,\n lifecycleStatusMap,\n type ChargeType,\n type LifecycleStatus,\n} from '../../../../components/statusMaps'\n\n// \u2500\u2500\u2500 Types \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\ntype OfferingComponent = {\n id: string\n slotId: string\n slot: { id: string; componentGroup: string; name: string; cardinalityMin: number; cardinalityMax: number | null } | null\n childOfferingId: string\n childOffering: { id: string; code: string; name: string; offeringType: string; specId: string } | null\n isDefault: boolean\n sortOrder: number\n isActive: boolean\n}\n\ntype BundleSlot = {\n id: string\n componentGroup: string\n name: string\n targetSpecId: string\n targetSpec: { id: string; code: string; name: string; specType: string } | null\n cardinalityMin: number\n cardinalityMax: number | null\n sortOrder: number\n}\n\ntype Offering = {\n id: string\n specId: string\n catalogOfferId: string | null\n code: string\n name: string\n description: string | null\n offeringType: string\n designTimeValues: Record<string, unknown>\n lifecycleStatus: string\n effectiveFrom: string | null\n effectiveTo: string | null\n metadata: Record<string, unknown> | null\n isActive: boolean\n specification: { id: string; code: string; name: string; productId: string; specType?: string } | null\n charges: Charge[]\n components?: OfferingComponent[]\n}\n\ntype Charge = {\n id: string\n code: string\n name: string\n description: string | null\n chargeType: string\n pricingMethod: string\n pricingTableId: string | null\n priceColumnKey: string | null\n fixedPrice: string | null\n currencyCode: string | null\n quantityAttributeCode: string | null\n applicabilityCondition: Record<string, unknown> | null\n sortOrder: number\n isActive: boolean\n}\n\ntype Attribute = {\n id: string\n code: string\n name: string\n attributeType: string\n resolutionTime: string\n options: Array<{ value: string; label: string }> | null\n constraints: Record<string, unknown> | null\n defaultValue: unknown | null\n helpText: string | null\n sortOrder: number\n isRequired: boolean\n isActive: boolean\n}\n\ntype Specification = {\n id: string\n code: string\n name: string\n productId: string\n}\n\ntype PricingTableRef = { id: string; code: string; name: string; dimensions: Array<{ key: string; label: string }>; priceColumns: Array<{ key: string; label: string }> }\n\ntype EditingCharge = Omit<Charge, 'id'> & { id?: string }\n\n// \u2500\u2500\u2500 Defaults \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nconst EMPTY_FORM = {\n code: '',\n name: '',\n description: '',\n offeringType: 'simple' as string,\n lifecycleStatus: 'draft',\n effectiveFrom: null as string | null,\n effectiveTo: null as string | null,\n isActive: true,\n specId: '',\n}\n\nconst EMPTY_CHARGE: EditingCharge = {\n code: '',\n name: '',\n description: null,\n chargeType: 'mrc',\n pricingMethod: 'flat',\n pricingTableId: null,\n priceColumnKey: null,\n fixedPrice: null,\n currencyCode: 'USD',\n quantityAttributeCode: null,\n applicabilityCondition: null,\n sortOrder: 0,\n isActive: true,\n}\n\n\nconst PRICING_METHOD_LABELS: Record<string, string> = {\n flat: 'flat price',\n fixed: 'flat price', // legacy alias \u2014 see validators.ts\n per_unit: 'per unit',\n tiered: 'tiered',\n}\n\n// V-CHG-1 in `validators.ts`: per_unit/tiered need table + column + qty\n// attribute; flat needs fixedPrice + currencyCode. Mirror it in the UI so\n// users see what's missing without round-tripping to the server.\ntype ChargeShape = {\n pricingMethod: string\n pricingTableId: string | null\n priceColumnKey: string | null\n fixedPrice: string | null\n currencyCode: string | null\n quantityAttributeCode: string | null\n}\n\nfunction isChargeComplete(charge: ChargeShape): boolean {\n return chargeMissingFields(charge).length === 0\n}\n\nfunction chargeMissingFields(charge: ChargeShape): string[] {\n const method = charge.pricingMethod === 'fixed' ? 'flat' : charge.pricingMethod\n const missing: string[] = []\n if (method === 'flat') {\n if (!charge.fixedPrice) missing.push('Fixed Price')\n if (!charge.currencyCode) missing.push('Currency')\n } else if (method === 'per_unit' || method === 'tiered') {\n if (!charge.pricingTableId) missing.push('Pricing Table')\n if (!charge.priceColumnKey) missing.push('Price Column')\n if (!charge.quantityAttributeCode) missing.push('Quantity Attribute')\n }\n return missing\n}\n\n// \u2500\u2500\u2500 Component \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport default function OfferingDetailPage(props: { params?: { id?: string } }) {\n const t = useT()\n const router = useRouter()\n const urlParams = useParams()\n const offeringId = (props.params?.id ?? urlParams?.id) as string\n const isNew = offeringId === 'new'\n\n // \u2500\u2500\u2500 State \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n const [tab, setTab] = React.useState<'general' | 'charges' | 'components'>('general')\n const [form, setForm] = React.useState(EMPTY_FORM)\n const [designTimeValues, setDesignTimeValues] = React.useState<Record<string, unknown>>({})\n const [charges, setCharges] = React.useState<Charge[]>([])\n const [attributes, setAttributes] = React.useState<Attribute[]>([])\n const [specs, setSpecs] = React.useState<Specification[]>([])\n const [specDetail, setSpecDetail] = React.useState<{ id: string; code: string; name: string; specType?: string } | null>(null)\n const [pricingTables, setPricingTables] = React.useState<PricingTableRef[]>([])\n const [components, setComponents] = React.useState<OfferingComponent[]>([])\n const [bundleSlots, setBundleSlots] = React.useState<BundleSlot[]>([])\n const [addingComponent, setAddingComponent] = React.useState<{ slotId: string; childOfferingId: string; isDefault: boolean } | null>(null)\n const [slotOfferings, setSlotOfferings] = React.useState<Record<string, Array<{ id: string; code: string; name: string; offeringType: string }>>>({})\n\n const [loading, setLoading] = React.useState(!isNew)\n const [saving, setSaving] = React.useState(false)\n const [error, setError] = React.useState<string | null>(null)\n\n const [editingCharge, setEditingCharge] = React.useState<EditingCharge | null>(null)\n\n // OM-standard detail page: existing offerings open read-only and require\n // an explicit Edit click to allow changes. New offerings skip view mode.\n const [generalMode, setGeneralMode] = React.useState<'view' | 'edit'>(isNew ? 'edit' : 'view')\n const [formSnapshot, setFormSnapshot] = React.useState<typeof EMPTY_FORM | null>(null)\n const [designTimeSnapshot, setDesignTimeSnapshot] = React.useState<Record<string, unknown> | null>(null)\n\n // \u2500\u2500\u2500 Load data \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n React.useEffect(() => {\n let cancelled = false\n\n async function load() {\n try {\n // Load specs for dropdown (needed for new + showing spec name)\n const specsRes = await fetch('/api/cpq/product-specifications?pageSize=200')\n if (specsRes.ok) {\n const d = await specsRes.json()\n if (!cancelled) setSpecs(d.items ?? [])\n }\n\n if (isNew) return\n\n // Load offering detail\n const res = await fetch(`/api/cpq/product-offerings?id=${encodeURIComponent(offeringId)}`)\n if (!res.ok) {\n if (!cancelled) setError('Failed to load offering')\n return\n }\n\n const data: Offering = await res.json()\n if (!cancelled) {\n setForm({\n code: data.code,\n name: data.name,\n description: data.description ?? '',\n offeringType: data.offeringType ?? 'simple',\n lifecycleStatus: data.lifecycleStatus,\n effectiveFrom: data.effectiveFrom,\n effectiveTo: data.effectiveTo,\n isActive: data.isActive,\n specId: data.specId,\n })\n setDesignTimeValues(data.designTimeValues ?? {})\n setCharges(data.charges ?? [])\n setSpecDetail(data.specification ?? null)\n setComponents(data.components ?? [])\n\n // Load attributes for the spec\n if (data.specId) {\n const attrRes = await fetch(`/api/cpq/product-attributes?specId=${encodeURIComponent(data.specId)}&pageSize=200`)\n if (attrRes.ok) {\n const attrData = await attrRes.json()\n if (!cancelled) setAttributes(attrData.items ?? [])\n }\n }\n\n // Load bundle slots if this is a bundle offering\n if (data.offeringType === 'bundle' && data.specId) {\n const slotsRes = await fetch(`/api/cpq/bundle-slots?specId=${encodeURIComponent(data.specId)}`)\n if (slotsRes.ok) {\n const slotsData = await slotsRes.json()\n if (!cancelled) setBundleSlots(slotsData.items ?? [])\n }\n }\n }\n } catch (err) {\n console.error('Failed to load', err)\n if (!cancelled) setError('Failed to load')\n } finally {\n if (!cancelled) setLoading(false)\n }\n }\n\n load()\n return () => { cancelled = true }\n }, [offeringId, isNew])\n\n // Load attributes when spec changes (for new offering)\n const loadSpecAttributes = async (specId: string) => {\n if (!specId) { setAttributes([]); return }\n try {\n const res = await fetch(`/api/cpq/product-attributes?specId=${encodeURIComponent(specId)}&pageSize=200`)\n if (res.ok) {\n const data = await res.json()\n setAttributes(data.items ?? [])\n }\n } catch {\n console.error('Failed to load spec attributes')\n }\n }\n\n // \u2500\u2500\u2500 Save offering \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n const saveOffering = async () => {\n setSaving(true)\n setError(null)\n try {\n const payload = isNew\n ? { ...form, description: form.description || null, designTimeValues, specId: form.specId }\n : { id: offeringId, ...form, description: form.description || null, designTimeValues }\n\n const res = await fetch('/api/cpq/product-offerings', {\n method: isNew ? 'POST' : 'PUT',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(payload),\n })\n\n if (!res.ok) {\n const d = await res.json()\n setError(d.error ?? 'Failed to save')\n return\n }\n\n const saved = await res.json()\n if (isNew) {\n router.push(`/backend/cpq/offerings/${saved.id}`)\n } else {\n setForm({\n code: saved.code,\n name: saved.name,\n description: saved.description ?? '',\n offeringType: saved.offeringType ?? form.offeringType,\n lifecycleStatus: saved.lifecycleStatus,\n effectiveFrom: saved.effectiveFrom,\n effectiveTo: saved.effectiveTo,\n isActive: saved.isActive,\n specId: saved.specId,\n })\n setDesignTimeValues(saved.designTimeValues ?? {})\n // Save succeeded \u2014 drop snapshots and flip back to read-only.\n setFormSnapshot(null)\n setDesignTimeSnapshot(null)\n setGeneralMode('view')\n }\n } catch {\n setError('Failed to save')\n } finally {\n setSaving(false)\n }\n }\n\n const deleteOffering = async () => {\n if (!confirm(t('cpq.offerings.confirmDelete', 'Delete this offering and all its charges?'))) return\n try {\n const res = await fetch('/api/cpq/product-offerings', {\n method: 'DELETE',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ id: offeringId }),\n })\n if (res.ok) {\n router.push('/backend/cpq/offerings')\n } else {\n const d = await res.json()\n setError(d.error ?? 'Failed to delete')\n }\n } catch {\n setError('Failed to delete')\n }\n }\n\n // \u2500\u2500\u2500 Charge CRUD \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n const loadPricingTables = async () => {\n if (pricingTables.length > 0) return\n const res = await fetch('/api/cpq/pricing-tables?pageSize=200')\n if (res.ok) {\n const data = await res.json()\n setPricingTables(data.items ?? [])\n }\n }\n\n const startEditCharge = (charge?: Charge) => {\n const editing = charge ? { ...charge } : { ...EMPTY_CHARGE }\n setEditingCharge(editing)\n loadPricingTables()\n }\n\n const saveCharge = async () => {\n if (!editingCharge) return\n setSaving(true)\n setError(null)\n try {\n const isEdit = !!editingCharge.id\n const payload = {\n ...editingCharge,\n offeringId,\n }\n const res = await fetch('/api/cpq/product-charges', {\n method: isEdit ? 'PUT' : 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(payload),\n })\n if (!res.ok) {\n const d = await res.json()\n setError(d.error ?? 'Failed to save charge')\n return\n }\n // Reload offering to get updated charges\n const offeringRes = await fetch(`/api/cpq/product-offerings?id=${encodeURIComponent(offeringId)}`)\n if (offeringRes.ok) {\n const data = await offeringRes.json()\n setCharges(data.charges ?? [])\n }\n setEditingCharge(null)\n } catch {\n setError('Failed to save charge')\n } finally {\n setSaving(false)\n }\n }\n\n const deleteCharge = async (chargeId: string) => {\n if (!confirm('Delete this charge?')) return\n try {\n const res = await fetch('/api/cpq/product-charges', {\n method: 'DELETE',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ id: chargeId }),\n })\n if (res.ok) setCharges((prev) => prev.filter((c) => c.id !== chargeId))\n } catch {\n setError('Failed to delete charge')\n }\n }\n\n const selectedPricingTable = editingCharge?.pricingTableId\n ? pricingTables.find((pt) => pt.id === editingCharge.pricingTableId)\n : null\n\n // \u2500\u2500\u2500 Helpers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n const designTimeAttrs = attributes.filter((a) => a.resolutionTime === 'design_time')\n\n // \u2500\u2500\u2500 Render \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n if (loading) {\n return <div className=\"text-sm text-muted-foreground\">{t('common.loading', 'Loading...')}</div>\n }\n\n return (\n <div className=\"space-y-6\">\n {/* Header */}\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center gap-3\">\n <button\n onClick={() => router.push('/backend/cpq/offerings')}\n className=\"text-sm text-muted-foreground hover:text-foreground\"\n >\n \u2190 {t('common.back', 'Back')}\n </button>\n <h1 className=\"text-2xl font-bold\">\n {isNew ? t('cpq.offerings.new', 'New Offering') : form.name}\n </h1>\n {!isNew && (\n <Tag variant={lifecycleStatusMap[form.lifecycleStatus as LifecycleStatus] ?? 'neutral'} dot>\n {formatStatusLabel(form.lifecycleStatus)}\n </Tag>\n )}\n {specDetail && (\n <span className=\"text-sm text-muted-foreground\">\n Spec: <button onClick={() => router.push(`/backend/cpq/specifications/${specDetail.id}`)} className=\"text-primary hover:underline\">{specDetail.name}</button>\n </span>\n )}\n </div>\n {!isNew && (\n <div className=\"flex items-center gap-2\">\n {generalMode === 'view' && tab === 'general' && (\n <Button\n type=\"button\"\n onClick={() => {\n setFormSnapshot(form)\n setDesignTimeSnapshot(designTimeValues)\n setGeneralMode('edit')\n }}\n >\n {t('common.edit', 'Edit')}\n </Button>\n )}\n <Button type=\"button\" variant=\"destructive\" onClick={deleteOffering}>\n {t('common.delete', 'Delete')}\n </Button>\n </div>\n )}\n </div>\n\n {error && (\n <Alert variant=\"destructive\">{error}</Alert>\n )}\n\n {/* Tabs */}\n {!isNew && (\n <div className=\"flex gap-1 border-b\">\n {([\n 'general',\n 'charges',\n ...(form.offeringType === 'bundle' ? ['components' as const] : []),\n ] as const).map((t_) => (\n <button\n key={t_}\n onClick={() => setTab(t_ as typeof tab)}\n className={`px-4 py-2 text-sm font-medium border-b-2 transition-colors ${\n tab === t_ ? 'border-primary text-primary' : 'border-transparent text-muted-foreground hover:text-foreground'\n }`}\n >\n {t_ === 'general' && 'General'}\n {t_ === 'charges' && `Charges (${charges.length})`}\n {t_ === 'components' && `Components (${components.length})`}\n </button>\n ))}\n </div>\n )}\n\n {/* \u2500\u2500\u2500 General Tab / New Form \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */}\n {(isNew || tab === 'general') && (\n <div className=\"rounded-lg border bg-card p-6 space-y-4\">\n {isNew && (\n <div>\n <label className=\"block text-sm font-medium mb-1\">Specification</label>\n <select\n value={form.specId}\n onChange={(e) => {\n setForm({ ...form, specId: e.target.value })\n loadSpecAttributes(e.target.value)\n setDesignTimeValues({})\n }}\n className=\"w-full rounded-md border px-3 py-2 text-sm\"\n >\n <option value=\"\">Select a specification...</option>\n {specs.map((s) => (\n <option key={s.id} value={s.id}>{s.name} ({s.code})</option>\n ))}\n </select>\n </div>\n )}\n\n <div className=\"grid grid-cols-2 gap-4\">\n <div>\n <label className=\"block text-sm font-medium mb-1\">{t('cpq.offerings.code', 'Code')}</label>\n {generalMode === 'view' && !isNew ? (\n <p className=\"text-sm font-mono py-2\">{form.code || '\u2014'}</p>\n ) : (\n <input\n type=\"text\"\n value={form.code}\n onChange={(e) => setForm({ ...form, code: e.target.value })}\n placeholder=\"e.g. gix-cloud-connect-aws\"\n className=\"w-full rounded-md border px-3 py-2 text-sm\"\n />\n )}\n </div>\n <div>\n <label className=\"block text-sm font-medium mb-1\">{t('cpq.offerings.name', 'Name')}</label>\n {generalMode === 'view' && !isNew ? (\n <p className=\"text-sm py-2\">{form.name || '\u2014'}</p>\n ) : (\n <input\n type=\"text\"\n value={form.name}\n onChange={(e) => setForm({ ...form, name: e.target.value })}\n className=\"w-full rounded-md border px-3 py-2 text-sm\"\n />\n )}\n </div>\n <div>\n <label className=\"block text-sm font-medium mb-1\">{t('cpq.offerings.lifecycleStatus', 'Lifecycle Status')}</label>\n {generalMode === 'view' && !isNew ? (\n <div className=\"py-2\">\n <Tag variant={lifecycleStatusMap[form.lifecycleStatus as LifecycleStatus] ?? 'neutral'} dot>\n {formatStatusLabel(form.lifecycleStatus)}\n </Tag>\n </div>\n ) : (\n <select\n value={form.lifecycleStatus}\n onChange={(e) => setForm({ ...form, lifecycleStatus: e.target.value })}\n className=\"w-full rounded-md border px-3 py-2 text-sm\"\n >\n <option value=\"draft\">Draft</option>\n <option value=\"active\">Active</option>\n <option value=\"deprecated\">Deprecated</option>\n </select>\n )}\n </div>\n <div>\n <label className=\"block text-sm font-medium mb-1\">{t('cpq.offerings.isActive', 'Is Active?')}</label>\n <div className=\"flex items-center h-[38px]\">\n {generalMode === 'view' && !isNew ? (\n <Tag variant={form.isActive ? 'success' : 'neutral'} dot>\n {form.isActive ? t('common.yes', 'Yes') : t('common.no', 'No')}\n </Tag>\n ) : (\n <input\n type=\"checkbox\"\n checked={form.isActive}\n onChange={(e) => setForm({ ...form, isActive: e.target.checked })}\n className=\"rounded border\"\n />\n )}\n </div>\n </div>\n </div>\n <div>\n <label className=\"block text-sm font-medium mb-1\">{t('cpq.offerings.description', 'Description')}</label>\n {generalMode === 'view' && !isNew ? (\n <p className=\"text-sm text-muted-foreground py-2 whitespace-pre-wrap\">{form.description || '\u2014'}</p>\n ) : (\n <textarea\n value={form.description ?? ''}\n onChange={(e) => setForm({ ...form, description: e.target.value })}\n rows={3}\n className=\"w-full rounded-md border px-3 py-2 text-sm\"\n />\n )}\n </div>\n\n {/* Design-time values */}\n {designTimeAttrs.length > 0 && (\n <div className=\"space-y-3\">\n <label className=\"block text-sm font-medium\">Design-Time Values</label>\n <div className=\"grid grid-cols-2 gap-3\">\n {designTimeAttrs.map((attr) => {\n const value = designTimeValues[attr.code]\n const isViewing = generalMode === 'view' && !isNew\n // Lookup the human label for select-type values so the\n // read-only view doesn't show raw codes.\n const optionLabel =\n (attr.attributeType === 'select' || attr.attributeType === 'enum') && attr.options\n ? attr.options.find((o) => o.value === value)?.label\n : undefined\n return (\n <div key={attr.code}>\n <label className=\"block text-xs font-medium mb-1\">\n {attr.name}\n {attr.isRequired && <span className=\"text-destructive ml-0.5\">*</span>}\n </label>\n {isViewing ? (\n <p className=\"text-sm py-2\">\n {value == null || value === '' ? (\n <span className=\"text-muted-foreground\">\u2014</span>\n ) : attr.attributeType === 'boolean' ? (\n <Tag variant={value ? 'success' : 'neutral'} dot>\n {value ? t('common.yes', 'Yes') : t('common.no', 'No')}\n </Tag>\n ) : (\n optionLabel ?? String(value)\n )}\n </p>\n ) : (attr.attributeType === 'select' || attr.attributeType === 'enum') && attr.options ? (\n <select\n value={String(value ?? '')}\n onChange={(e) => setDesignTimeValues({ ...designTimeValues, [attr.code]: e.target.value || null })}\n className=\"w-full rounded-md border px-2 py-1.5 text-sm\"\n >\n <option value=\"\">Select {attr.name}...</option>\n {attr.options.map((opt) => (\n <option key={opt.value} value={opt.value}>{opt.label}</option>\n ))}\n </select>\n ) : attr.attributeType === 'number' ? (\n <NumberInput\n value={typeof value === 'number' ? (value as number) : null}\n onChange={(n) => setDesignTimeValues({ ...designTimeValues, [attr.code]: n })}\n />\n ) : attr.attributeType === 'boolean' ? (\n <div className=\"pt-1\">\n <label className=\"flex items-center gap-1.5 text-sm\">\n <input\n type=\"checkbox\"\n checked={!!value}\n onChange={(e) => setDesignTimeValues({ ...designTimeValues, [attr.code]: e.target.checked })}\n className=\"rounded border\"\n />\n {attr.name}\n </label>\n </div>\n ) : (\n <input\n type=\"text\"\n value={String(value ?? '')}\n onChange={(e) => setDesignTimeValues({ ...designTimeValues, [attr.code]: e.target.value || null })}\n className=\"w-full rounded-md border px-2 py-1.5 text-sm\"\n placeholder={attr.helpText ?? undefined}\n />\n )}\n {attr.helpText && <p className=\"text-xs text-muted-foreground mt-0.5\">{attr.helpText}</p>}\n </div>\n )\n })}\n </div>\n </div>\n )}\n\n {/* In view mode the Edit button lives in the page header next to\n Delete (OM standard). Here we only render the Save/Cancel\n pair when actually editing. */}\n {!(generalMode === 'view' && !isNew) && (\n <div className=\"flex gap-3\">\n <Button\n type=\"button\"\n onClick={saveOffering}\n disabled={saving || !form.code || !form.name || (isNew && !form.specId)}\n >\n {saving ? t('common.saving', 'Saving...') : t('common.save', 'Save')}\n </Button>\n <Button\n type=\"button\"\n variant=\"outline\"\n onClick={() => {\n if (isNew) {\n router.push('/backend/cpq/offerings')\n return\n }\n if (formSnapshot) setForm(formSnapshot)\n if (designTimeSnapshot) setDesignTimeValues(designTimeSnapshot)\n setFormSnapshot(null)\n setDesignTimeSnapshot(null)\n setGeneralMode('view')\n }}\n >\n {t('common.cancel', 'Cancel')}\n </Button>\n </div>\n )}\n </div>\n )}\n\n {/* \u2500\u2500\u2500 Charges Tab \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */}\n {tab === 'charges' && !isNew && (\n <div className=\"space-y-4\">\n <div className=\"flex justify-end\">\n <button\n onClick={() => startEditCharge()}\n className=\"inline-flex items-center justify-center rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground hover:bg-primary/90\"\n >\n {t('cpq.offerings.addCharge', 'Add Charge')}\n </button>\n </div>\n\n {/* Charge edit form */}\n {editingCharge && (\n <div className=\"rounded-lg border bg-card p-4 space-y-3\">\n <h3 className=\"font-medium text-sm\">\n {editingCharge.id ? 'Edit Charge' : 'New Charge'}\n </h3>\n <div className=\"grid grid-cols-3 gap-3\">\n <div>\n <label className=\"block text-xs font-medium mb-1\">Code</label>\n <input type=\"text\" value={editingCharge.code} onChange={(e) => setEditingCharge({ ...editingCharge, code: e.target.value })} placeholder=\"e.g. mrc-monthly\" className=\"w-full rounded-md border px-2 py-1.5 text-sm\" />\n </div>\n <div>\n <label className=\"block text-xs font-medium mb-1\">Name</label>\n <input type=\"text\" value={editingCharge.name} onChange={(e) => setEditingCharge({ ...editingCharge, name: e.target.value })} className=\"w-full rounded-md border px-2 py-1.5 text-sm\" />\n </div>\n <div>\n <label className=\"block text-xs font-medium mb-1\">Charge Type</label>\n <select value={editingCharge.chargeType} onChange={(e) => setEditingCharge({ ...editingCharge, chargeType: e.target.value })} className=\"w-full rounded-md border px-2 py-1.5 text-sm\">\n <option value=\"mrc\">MRC (Monthly Recurring)</option>\n <option value=\"nrc\">NRC (Non-Recurring)</option>\n <option value=\"usage\">Usage</option>\n </select>\n </div>\n <div>\n <label className=\"block text-xs font-medium mb-1\">Pricing Method</label>\n <select value={editingCharge.pricingMethod} onChange={(e) => {\n const method = e.target.value\n if (method === 'flat') {\n setEditingCharge({ ...editingCharge, pricingMethod: method, pricingTableId: null, priceColumnKey: null, quantityAttributeCode: null })\n } else {\n setEditingCharge({ ...editingCharge, pricingMethod: method, fixedPrice: null })\n }\n }} className=\"w-full rounded-md border px-2 py-1.5 text-sm\">\n <option value=\"flat\">Flat Price</option>\n <option value=\"per_unit\">Per Unit (table lookup)</option>\n <option value=\"tiered\">Tiered (table lookup)</option>\n </select>\n </div>\n {(editingCharge.pricingMethod === 'flat' || editingCharge.pricingMethod === 'fixed') ? (\n <>\n <div>\n <label className=\"block text-xs font-medium mb-1\">Fixed Price <span className=\"text-destructive\">*</span></label>\n <input type=\"text\" value={editingCharge.fixedPrice ?? ''} onChange={(e) => setEditingCharge({ ...editingCharge, fixedPrice: e.target.value || null })} placeholder=\"0.00\" className=\"w-full rounded-md border px-2 py-1.5 text-sm\" />\n </div>\n <div>\n <label className=\"block text-xs font-medium mb-1\">Currency <span className=\"text-destructive\">*</span></label>\n <input type=\"text\" value={editingCharge.currencyCode ?? 'USD'} onChange={(e) => setEditingCharge({ ...editingCharge, currencyCode: e.target.value || null })} className=\"w-full rounded-md border px-2 py-1.5 text-sm\" />\n </div>\n </>\n ) : (\n <>\n <div>\n <label className=\"block text-xs font-medium mb-1\">Pricing Table <span className=\"text-destructive\">*</span></label>\n <select value={editingCharge.pricingTableId ?? ''} onChange={(e) => setEditingCharge({ ...editingCharge, pricingTableId: e.target.value || null, priceColumnKey: null })} className=\"w-full rounded-md border px-2 py-1.5 text-sm\">\n <option value=\"\">Select table...</option>\n {pricingTables.map((pt) => (\n <option key={pt.id} value={pt.id}>{pt.name} ({pt.code})</option>\n ))}\n </select>\n {pricingTables.length === 0 && (\n <p className=\"text-xs text-warning mt-0.5\">\n No pricing tables yet \u2014{' '}\n <a href=\"/backend/cpq/pricing-tables\" className=\"text-primary hover:underline\">create one</a>{' '}\n before using {editingCharge.pricingMethod} pricing.\n </p>\n )}\n </div>\n <div>\n <label className=\"block text-xs font-medium mb-1\">Price Column <span className=\"text-destructive\">*</span></label>\n <select value={editingCharge.priceColumnKey ?? ''} onChange={(e) => setEditingCharge({ ...editingCharge, priceColumnKey: e.target.value || null })} className=\"w-full rounded-md border px-2 py-1.5 text-sm\" disabled={!selectedPricingTable}>\n <option value=\"\">Select column...</option>\n {selectedPricingTable?.priceColumns.map((col) => (\n <option key={col.key} value={col.key}>{col.label}</option>\n ))}\n </select>\n </div>\n <div>\n <label className=\"block text-xs font-medium mb-1\">Quantity Attribute <span className=\"text-destructive\">*</span></label>\n <select value={editingCharge.quantityAttributeCode ?? ''} onChange={(e) => setEditingCharge({ ...editingCharge, quantityAttributeCode: e.target.value || null })} className=\"w-full rounded-md border px-2 py-1.5 text-sm\">\n <option value=\"\">Select attribute...</option>\n {attributes.filter((a) => a.attributeType === 'number').map((a) => (\n <option key={a.code} value={a.code}>{a.name} ({a.code})</option>\n ))}\n </select>\n <p className=\"text-xs text-muted-foreground mt-0.5\">Attribute whose value drives the quantity for pricing</p>\n {attributes.filter((a) => a.attributeType === 'number').length === 0 && form.specId && (\n <p className=\"text-xs text-warning mt-0.5\">\n Spec has no number attributes \u2014{' '}\n <a href={`/backend/cpq/specifications/${form.specId}`} className=\"text-primary hover:underline\">\n add one to the spec\n </a>{' '}\n first.\n </p>\n )}\n </div>\n </>\n )}\n <div>\n <label className=\"block text-xs font-medium mb-1\">Sort Order</label>\n <NumberInput\n integer\n value={editingCharge.sortOrder}\n onChange={(n) => setEditingCharge({ ...editingCharge, sortOrder: n ?? 0 })}\n />\n </div>\n </div>\n <div>\n <label className=\"block text-xs font-medium mb-1\">Description</label>\n <input type=\"text\" value={editingCharge.description ?? ''} onChange={(e) => setEditingCharge({ ...editingCharge, description: e.target.value || null })} className=\"w-full rounded-md border px-2 py-1.5 text-sm\" />\n </div>\n <div className=\"flex items-end gap-4\">\n <label className=\"flex items-center gap-1.5 text-sm\">\n <input type=\"checkbox\" checked={editingCharge.isActive} onChange={(e) => setEditingCharge({ ...editingCharge, isActive: e.target.checked })} className=\"rounded border\" />\n Active\n </label>\n </div>\n {(() => {\n const missing = chargeMissingFields(editingCharge)\n const blocked = saving || !editingCharge.code || !editingCharge.name || missing.length > 0\n return (\n <>\n {missing.length > 0 && (\n <Alert variant=\"destructive\">\n Missing required field{missing.length > 1 ? 's' : ''} for {editingCharge.pricingMethod} pricing: {missing.join(', ')}\n </Alert>\n )}\n <div className=\"flex gap-2\">\n <button onClick={saveCharge} disabled={blocked} className=\"inline-flex items-center rounded-md bg-primary px-3 py-1.5 text-sm font-medium text-primary-foreground hover:bg-primary/90 disabled:opacity-50 disabled:cursor-not-allowed\">\n {saving ? 'Saving...' : 'Save'}\n </button>\n <button onClick={() => setEditingCharge(null)} className=\"inline-flex items-center rounded-md border px-3 py-1.5 text-sm font-medium hover:bg-muted\">Cancel</button>\n </div>\n </>\n )\n })()}\n </div>\n )}\n\n {/* Charges table */}\n {charges.length === 0 ? (\n <div className=\"rounded-lg border bg-card p-6 text-center text-sm text-muted-foreground\">\n No charges defined. Add recurring, non-recurring, or usage charges to this offering.\n </div>\n ) : (\n <div className=\"rounded-lg border\">\n <table className=\"w-full text-sm\">\n <thead>\n <tr className=\"border-b bg-muted/50\">\n <th className=\"px-4 py-3 text-left font-medium\">Code</th>\n <th className=\"px-4 py-3 text-left font-medium\">Name</th>\n <th className=\"px-4 py-3 text-left font-medium\">Type</th>\n <th className=\"px-4 py-3 text-left font-medium\">Pricing</th>\n <th className=\"px-4 py-3 text-left font-medium\">Price</th>\n <th className=\"px-4 py-3 text-left font-medium\">Active</th>\n <th className=\"px-4 py-3 text-right font-medium\">Actions</th>\n </tr>\n </thead>\n <tbody>\n {charges.map((charge) => {\n const incomplete = !isChargeComplete(charge)\n const tableRef = charge.pricingTableId\n ? pricingTables.find((pt) => pt.id === charge.pricingTableId)\n : null\n const qtyAttr = charge.quantityAttributeCode\n ? attributes.find((a) => a.code === charge.quantityAttributeCode)\n : null\n const isFlat = charge.pricingMethod === 'flat' || charge.pricingMethod === 'fixed'\n return (\n <tr key={charge.id} className=\"border-b\">\n <td className=\"px-4 py-3 font-mono text-xs\">{charge.code}</td>\n <td className=\"px-4 py-3\">\n {charge.name}\n {incomplete && (\n <Tag variant=\"error\" className=\"ml-2 px-2 text-[10px]\" dot>Incomplete</Tag>\n )}\n </td>\n <td className=\"px-4 py-3\">\n <Tag variant={chargeTypeMap[charge.chargeType as ChargeType] ?? 'neutral'} className=\"px-2 text-xs\">\n {charge.chargeType.toUpperCase()}\n </Tag>\n </td>\n <td className=\"px-4 py-3 text-xs\">{PRICING_METHOD_LABELS[charge.pricingMethod] ?? charge.pricingMethod}</td>\n <td className=\"px-4 py-3 text-xs\">\n {isFlat ? (\n charge.fixedPrice != null\n ? `${charge.currencyCode ?? 'USD'} ${charge.fixedPrice}`\n : <span className=\"text-muted-foreground\">\u2014</span>\n ) : (\n <div className=\"flex flex-col gap-0.5\">\n <span>\n <span className=\"text-muted-foreground\">Table:</span>{' '}\n {tableRef ? `${tableRef.name} \u2192 ${charge.priceColumnKey ?? '?'}` : <span className=\"text-destructive\">missing</span>}\n </span>\n <span>\n <span className=\"text-muted-foreground\">\u00D7 Qty:</span>{' '}\n {qtyAttr ? `${qtyAttr.name} (${qtyAttr.code})` : <span className=\"text-destructive\">missing</span>}\n </span>\n </div>\n )}\n </td>\n <td className=\"px-4 py-3\">{charge.isActive ? 'Yes' : 'No'}</td>\n <td className=\"px-4 py-3 text-right\">\n <button onClick={() => startEditCharge(charge)} className=\"text-xs text-primary hover:underline mr-2\">Edit</button>\n <button onClick={() => deleteCharge(charge.id)} className=\"text-xs text-destructive hover:underline\">Delete</button>\n </td>\n </tr>\n )\n })}\n </tbody>\n </table>\n </div>\n )}\n </div>\n )}\n\n {/* \u2500\u2500\u2500 Components Tab (bundle offerings) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */}\n {tab === 'components' && !isNew && form.offeringType === 'bundle' && (\n <div className=\"space-y-4\">\n {bundleSlots.length === 0 ? (\n <div className=\"rounded-lg border bg-card p-6 text-center text-sm text-muted-foreground\">\n No bundle slots defined on this specification. Add slots on the specification first.\n </div>\n ) : (\n <>\n {/* Group components by slot */}\n {bundleSlots.map((slot) => {\n const slotComponents = components.filter((c) => c.slotId === slot.id)\n return (\n <div key={slot.id} className=\"rounded-lg border bg-card overflow-hidden\">\n <div className=\"bg-muted/50 px-4 py-3 border-b flex items-center justify-between\">\n <div>\n <span className=\"font-medium text-sm\">{slot.name}</span>\n <Tag variant=\"info\" className=\"ml-2 px-2 text-[10px]\">\n {slot.componentGroup}\n </Tag>\n <span className=\"ml-2 text-xs text-muted-foreground\">\n {slot.cardinalityMin}..{slot.cardinalityMax ?? '\u221E'}\n </span>\n {slot.targetSpec && (\n <span className=\"ml-2 text-xs text-muted-foreground\">\u2192 {slot.targetSpec.name}</span>\n )}\n </div>\n <button\n onClick={async () => {\n setAddingComponent({ slotId: slot.id, childOfferingId: '', isDefault: false })\n if (!slotOfferings[slot.targetSpecId]) {\n const res = await fetch(`/api/cpq/product-offerings?specId=${encodeURIComponent(slot.targetSpecId)}&pageSize=100`)\n if (res.ok) {\n const d = await res.json()\n setSlotOfferings((prev) => ({ ...prev, [slot.targetSpecId]: d.items ?? [] }))\n }\n }\n }}\n className=\"inline-flex items-center justify-center rounded-md bg-primary px-3 py-1.5 text-xs font-medium text-primary-foreground hover:bg-primary/90\"\n >\n + Add Component\n </button>\n </div>\n\n {addingComponent?.slotId === slot.id && (\n <div className=\"p-4 border-b bg-muted/20 space-y-3\">\n <div className=\"grid grid-cols-3 gap-3\">\n <div className=\"col-span-2\">\n <label className=\"block text-xs font-medium mb-1\">Component Offering</label>\n <select\n value={addingComponent.childOfferingId}\n onChange={(e) => setAddingComponent({ ...addingComponent, childOfferingId: e.target.value })}\n className=\"w-full rounded-md border px-3 py-2 text-sm\"\n >\n <option value=\"\">\u2014 Select offering \u2014</option>\n {(slotOfferings[slot.targetSpecId] ?? []).map((o) => (\n <option key={o.id} value={o.id}>{o.name} ({o.code}){o.offeringType === 'bundle' ? ' [bundle]' : ''}</option>\n ))}\n </select>\n </div>\n <div>\n <label className=\"block text-xs font-medium mb-1\">Default?</label>\n <div className=\"flex items-center h-[38px]\">\n <input\n type=\"checkbox\"\n checked={addingComponent.isDefault}\n onChange={(e) => setAddingComponent({ ...addingComponent, isDefault: e.target.checked })}\n className=\"rounded border\"\n />\n <span className=\"ml-2 text-xs text-muted-foreground\">Pre-selected in quote</span>\n </div>\n </div>\n </div>\n <div className=\"flex gap-2\">\n <button\n disabled={saving || !addingComponent.childOfferingId}\n onClick={async () => {\n setSaving(true)\n setError(null)\n try {\n const res = await fetch('/api/cpq/offering-components', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n offeringId,\n slotId: addingComponent.slotId,\n childOfferingId: addingComponent.childOfferingId,\n isDefault: addingComponent.isDefault,\n }),\n })\n if (!res.ok) {\n const d = await res.json()\n setError(d.error ?? 'Failed to add component')\n return\n }\n setAddingComponent(null)\n const compRes = await fetch(`/api/cpq/offering-components?offeringId=${offeringId}`)\n if (compRes.ok) {\n const d = await compRes.json()\n setComponents(d.items ?? [])\n }\n } catch {\n setError('Failed to add component')\n } finally {\n setSaving(false)\n }\n }}\n className=\"inline-flex items-center justify-center rounded-md bg-primary px-3 py-1.5 text-xs font-medium text-primary-foreground hover:bg-primary/90 disabled:opacity-50\"\n >\n {saving ? 'Adding...' : 'Add'}\n </button>\n <button\n onClick={() => setAddingComponent(null)}\n className=\"inline-flex items-center justify-center rounded-md border px-3 py-1.5 text-xs font-medium hover:bg-muted\"\n >\n Cancel\n </button>\n </div>\n </div>\n )}\n\n {slotComponents.length === 0 ? (\n <div className=\"p-4 text-center text-xs text-muted-foreground\">\n No components assigned to this slot\n {slot.cardinalityMin > 0 && (\n <span className=\"ml-1 text-status-warning-text font-medium\">(required: min {slot.cardinalityMin})</span>\n )}\n </div>\n ) : (\n <table className=\"w-full text-sm\">\n <thead>\n <tr className=\"border-b bg-muted/30\">\n <th className=\"px-4 py-2 text-left text-xs font-medium\">Offering</th>\n <th className=\"px-4 py-2 text-left text-xs font-medium\">Code</th>\n <th className=\"px-4 py-2 text-left text-xs font-medium\">Type</th>\n <th className=\"px-4 py-2 text-left text-xs font-medium\">Default</th>\n <th className=\"px-4 py-2 text-right text-xs font-medium\">Actions</th>\n </tr>\n </thead>\n <tbody>\n {slotComponents.map((comp) => (\n <tr key={comp.id} className=\"border-b last:border-0\">\n <td className=\"px-4 py-2.5 font-medium\">{comp.childOffering?.name ?? 'Unknown'}</td>\n <td className=\"px-4 py-2.5 text-muted-foreground text-xs\">{comp.childOffering?.code ?? '\u2014'}</td>\n <td className=\"px-4 py-2.5\">\n {comp.childOffering?.offeringType === 'bundle' ? (\n <Tag variant=\"brand\" className=\"px-2 text-[10px]\">bundle</Tag>\n ) : (\n <Tag variant=\"neutral\" className=\"px-2 text-[10px]\">simple</Tag>\n )}\n </td>\n <td className=\"px-4 py-2.5\">\n <button\n onClick={async () => {\n try {\n const res = await fetch('/api/cpq/offering-components', {\n method: 'PUT',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ id: comp.id, isDefault: !comp.isDefault }),\n })\n if (res.ok) {\n setComponents((prev) => prev.map((c) => c.id === comp.id ? { ...c, isDefault: !c.isDefault } : c))\n }\n } catch { /* ignore */ }\n }}\n className=\"cursor-pointer\"\n >\n <Tag variant={comp.isDefault ? 'success' : 'neutral'} className=\"px-2 text-[10px]\">\n {comp.isDefault ? 'Yes' : 'No'}\n </Tag>\n </button>\n </td>\n <td className=\"px-4 py-2.5 text-right\">\n <button\n onClick={async () => {\n if (!confirm('Remove this component from the bundle?')) return\n try {\n const res = await fetch('/api/cpq/offering-components', {\n method: 'DELETE',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ id: comp.id }),\n })\n if (res.ok) {\n setComponents((prev) => prev.filter((c) => c.id !== comp.id))\n } else {\n const d = await res.json()\n setError(d.error ?? 'Failed to remove')\n }\n } catch {\n setError('Failed to remove component')\n }\n }}\n className=\"text-xs text-destructive hover:underline\"\n >\n Remove\n </button>\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n )}\n </div>\n )\n })}\n </>\n )}\n </div>\n )}\n </div>\n )\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["\"use client\"\nimport * as React from 'react'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { useParams, useRouter } from 'next/navigation'\nimport { Alert } from '@open-mercato/ui/primitives/alert'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { Tag } from '@open-mercato/ui/primitives/tag'\nimport { apiCall } from '@open-mercato/ui/backend/utils/apiCall'\nimport { NumberInput } from '../../../../components/NumberInput'\nimport { normalizeChargePricing } from '../../../../data/charge-pricing'\nimport {\n chargeTypeMap,\n formatStatusLabel,\n lifecycleStatusMap,\n type ChargeType,\n type LifecycleStatus,\n} from '../../../../components/statusMaps'\n\n// \u2500\u2500\u2500 Types \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\ntype OfferingComponent = {\n id: string\n slotId: string\n slot: { id: string; componentGroup: string; name: string; cardinalityMin: number; cardinalityMax: number | null } | null\n childOfferingId: string\n childOffering: { id: string; code: string; name: string; offeringType: string; specId: string } | null\n isDefault: boolean\n sortOrder: number\n isActive: boolean\n}\n\ntype BundleSlot = {\n id: string\n componentGroup: string\n name: string\n targetSpecId: string\n targetSpec: { id: string; code: string; name: string; specType: string } | null\n cardinalityMin: number\n cardinalityMax: number | null\n sortOrder: number\n}\n\ntype Offering = {\n id: string\n specId: string\n catalogOfferId: string | null\n code: string\n name: string\n description: string | null\n offeringType: string\n designTimeValues: Record<string, unknown>\n lifecycleStatus: string\n effectiveFrom: string | null\n effectiveTo: string | null\n metadata: Record<string, unknown> | null\n isActive: boolean\n specification: { id: string; code: string; name: string; productId: string; specType?: string } | null\n charges: Charge[]\n components?: OfferingComponent[]\n}\n\ntype Charge = {\n id: string\n code: string\n name: string\n description: string | null\n chargeType: string\n chargeModel: string | null\n pricingMethod: string\n pricingTableId: string | null\n priceColumnKey: string | null\n fixedPrice: string | null\n currencyCode: string | null\n quantityAttributeCode: string | null\n applicabilityCondition: Record<string, unknown> | null\n sortOrder: number\n isActive: boolean\n}\n\ntype Attribute = {\n id: string\n code: string\n name: string\n attributeType: string\n resolutionTime: string\n options: Array<{ value: string; label: string }> | null\n constraints: Record<string, unknown> | null\n defaultValue: unknown | null\n helpText: string | null\n sortOrder: number\n isRequired: boolean\n isActive: boolean\n}\n\ntype Specification = {\n id: string\n code: string\n name: string\n productId: string\n}\n\ntype PricingTableRef = { id: string; code: string; name: string; dimensions: Array<{ key: string; label: string }>; priceColumns: Array<{ key: string; label: string }> }\n\n// Shared by the eager mount-load and the lazy editor dropdown. Returns [] on\n// failure so a transient error degrades gracefully instead of blanking the page.\nasync function fetchPricingTables(): Promise<PricingTableRef[]> {\n try {\n const { ok, result } = await apiCall<{ items?: PricingTableRef[] }>('/api/cpq/pricing-tables?pageSize=100')\n if (!ok) {\n console.warn('[cpq] Failed to load pricing tables for the charges list')\n return []\n }\n return result?.items ?? []\n } catch (err) {\n console.warn('[cpq] Failed to load pricing tables for the charges list:', err)\n return []\n }\n}\n\ntype EditingCharge = Omit<Charge, 'id'> & { id?: string }\n\n// \u2500\u2500\u2500 Defaults \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nconst EMPTY_FORM = {\n code: '',\n name: '',\n description: '',\n offeringType: 'simple' as string,\n lifecycleStatus: 'draft',\n effectiveFrom: null as string | null,\n effectiveTo: null as string | null,\n isActive: true,\n specId: '',\n}\n\nconst EMPTY_CHARGE: EditingCharge = {\n code: '',\n name: '',\n description: null,\n chargeType: 'mrc',\n chargeModel: 'flat',\n pricingMethod: 'fixed',\n pricingTableId: null,\n priceColumnKey: null,\n fixedPrice: null,\n currencyCode: 'USD',\n quantityAttributeCode: null,\n applicabilityCondition: null,\n sortOrder: 0,\n isActive: true,\n}\n\n\n// XD-297: the charge \"shape\" is two axes \u2014 Charge Model (how quantity drives\n// the charge) and Pricing Method (where the unit price comes from).\nconst CHARGE_MODEL_LABELS: Record<string, string> = {\n flat: 'Flat Fee',\n per_unit: 'Per Unit',\n volume: 'Volume-based',\n tiered: 'Tiered',\n}\n\nconst PRICING_SOURCE_LABELS: Record<string, string> = {\n fixed: 'Fixed Price',\n table: 'Table Lookup',\n}\n\n// V-CHG-1 in `validators.ts`: mirror the (chargeModel \u00D7 pricingMethod) rules in\n// the UI so users see what's missing without round-tripping to the server.\ntype ChargeShape = {\n chargeModel: string | null\n pricingMethod: string\n pricingTableId: string | null\n priceColumnKey: string | null\n fixedPrice: string | null\n currencyCode: string | null\n quantityAttributeCode: string | null\n}\n\nfunction isChargeComplete(charge: ChargeShape): boolean {\n return chargeMissingFields(charge).length === 0\n}\n\nfunction chargeMissingFields(charge: ChargeShape): string[] {\n const { model, source } = normalizeChargePricing(charge)\n const missing: string[] = []\n if (source === 'fixed') {\n if (!charge.fixedPrice) missing.push('Fixed Price')\n if (!charge.currencyCode) missing.push('Currency')\n if (model === 'per_unit' && !charge.quantityAttributeCode) missing.push('Quantity Attribute')\n } else {\n if (!charge.pricingTableId) missing.push('Pricing Table')\n if (!charge.priceColumnKey) missing.push('Price Column')\n if (model !== 'flat' && !charge.quantityAttributeCode) missing.push('Quantity Attribute')\n }\n return missing\n}\n\n// \u2500\u2500\u2500 Component \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport default function OfferingDetailPage(props: { params?: { id?: string } }) {\n const t = useT()\n const router = useRouter()\n const urlParams = useParams()\n const offeringId = (props.params?.id ?? urlParams?.id) as string\n const isNew = offeringId === 'new'\n\n // \u2500\u2500\u2500 State \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n const [tab, setTab] = React.useState<'general' | 'charges' | 'components'>('general')\n const [form, setForm] = React.useState(EMPTY_FORM)\n const [designTimeValues, setDesignTimeValues] = React.useState<Record<string, unknown>>({})\n const [charges, setCharges] = React.useState<Charge[]>([])\n const [attributes, setAttributes] = React.useState<Attribute[]>([])\n const [specs, setSpecs] = React.useState<Specification[]>([])\n const [specDetail, setSpecDetail] = React.useState<{ id: string; code: string; name: string; specType?: string } | null>(null)\n const [pricingTables, setPricingTables] = React.useState<PricingTableRef[]>([])\n const [components, setComponents] = React.useState<OfferingComponent[]>([])\n const [bundleSlots, setBundleSlots] = React.useState<BundleSlot[]>([])\n const [addingComponent, setAddingComponent] = React.useState<{ slotId: string; childOfferingId: string; isDefault: boolean } | null>(null)\n const [slotOfferings, setSlotOfferings] = React.useState<Record<string, Array<{ id: string; code: string; name: string; offeringType: string }>>>({})\n\n const [loading, setLoading] = React.useState(!isNew)\n const [saving, setSaving] = React.useState(false)\n const [error, setError] = React.useState<string | null>(null)\n\n const [editingCharge, setEditingCharge] = React.useState<EditingCharge | null>(null)\n\n // OM-standard detail page: existing offerings open read-only and require\n // an explicit Edit click to allow changes. New offerings skip view mode.\n const [generalMode, setGeneralMode] = React.useState<'view' | 'edit'>(isNew ? 'edit' : 'view')\n const [formSnapshot, setFormSnapshot] = React.useState<typeof EMPTY_FORM | null>(null)\n const [designTimeSnapshot, setDesignTimeSnapshot] = React.useState<Record<string, unknown> | null>(null)\n\n // \u2500\u2500\u2500 Load data \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n React.useEffect(() => {\n let cancelled = false\n\n async function load() {\n try {\n // Load specs for dropdown (needed for new + showing spec name)\n const specsRes = await fetch('/api/cpq/product-specifications?pageSize=200')\n if (specsRes.ok) {\n const d = await specsRes.json()\n if (!cancelled) setSpecs(d.items ?? [])\n }\n\n if (isNew) return\n\n // Load offering detail\n const res = await fetch(`/api/cpq/product-offerings?id=${encodeURIComponent(offeringId)}`)\n if (!res.ok) {\n if (!cancelled) setError('Failed to load offering')\n return\n }\n\n const data: Offering = await res.json()\n if (!cancelled) {\n setForm({\n code: data.code,\n name: data.name,\n description: data.description ?? '',\n offeringType: data.offeringType ?? 'simple',\n lifecycleStatus: data.lifecycleStatus,\n effectiveFrom: data.effectiveFrom,\n effectiveTo: data.effectiveTo,\n isActive: data.isActive,\n specId: data.specId,\n })\n setDesignTimeValues(data.designTimeValues ?? {})\n setCharges(data.charges ?? [])\n setSpecDetail(data.specification ?? null)\n setComponents(data.components ?? [])\n\n // Charges reference pricing tables by id; load the tables up front so\n // the list renders their names instead of \"missing\". The charge editor\n // also lazy-loads them, but the read view needs them on mount/refresh.\n if ((data.charges ?? []).some((c) => c.pricingTableId)) {\n const tables = await fetchPricingTables()\n if (!cancelled) setPricingTables(tables)\n }\n\n // Load attributes for the spec\n if (data.specId) {\n const attrRes = await fetch(`/api/cpq/product-attributes?specId=${encodeURIComponent(data.specId)}&pageSize=200`)\n if (attrRes.ok) {\n const attrData = await attrRes.json()\n if (!cancelled) setAttributes(attrData.items ?? [])\n }\n }\n\n // Load bundle slots if this is a bundle offering\n if (data.offeringType === 'bundle' && data.specId) {\n const slotsRes = await fetch(`/api/cpq/bundle-slots?specId=${encodeURIComponent(data.specId)}`)\n if (slotsRes.ok) {\n const slotsData = await slotsRes.json()\n if (!cancelled) setBundleSlots(slotsData.items ?? [])\n }\n }\n }\n } catch (err) {\n console.error('Failed to load', err)\n if (!cancelled) setError('Failed to load')\n } finally {\n if (!cancelled) setLoading(false)\n }\n }\n\n load()\n return () => { cancelled = true }\n }, [offeringId, isNew])\n\n // Load attributes when spec changes (for new offering)\n const loadSpecAttributes = async (specId: string) => {\n if (!specId) { setAttributes([]); return }\n try {\n const res = await fetch(`/api/cpq/product-attributes?specId=${encodeURIComponent(specId)}&pageSize=200`)\n if (res.ok) {\n const data = await res.json()\n setAttributes(data.items ?? [])\n }\n } catch {\n console.error('Failed to load spec attributes')\n }\n }\n\n // \u2500\u2500\u2500 Save offering \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n const saveOffering = async () => {\n setSaving(true)\n setError(null)\n try {\n const payload = isNew\n ? { ...form, description: form.description || null, designTimeValues, specId: form.specId }\n : { id: offeringId, ...form, description: form.description || null, designTimeValues }\n\n const res = await fetch('/api/cpq/product-offerings', {\n method: isNew ? 'POST' : 'PUT',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(payload),\n })\n\n if (!res.ok) {\n const d = await res.json()\n setError(d.error ?? 'Failed to save')\n return\n }\n\n const saved = await res.json()\n if (isNew) {\n router.push(`/backend/cpq/offerings/${saved.id}`)\n } else {\n setForm({\n code: saved.code,\n name: saved.name,\n description: saved.description ?? '',\n offeringType: saved.offeringType ?? form.offeringType,\n lifecycleStatus: saved.lifecycleStatus,\n effectiveFrom: saved.effectiveFrom,\n effectiveTo: saved.effectiveTo,\n isActive: saved.isActive,\n specId: saved.specId,\n })\n setDesignTimeValues(saved.designTimeValues ?? {})\n // Save succeeded \u2014 drop snapshots and flip back to read-only.\n setFormSnapshot(null)\n setDesignTimeSnapshot(null)\n setGeneralMode('view')\n }\n } catch {\n setError('Failed to save')\n } finally {\n setSaving(false)\n }\n }\n\n const deleteOffering = async () => {\n if (!confirm(t('cpq.offerings.confirmDelete', 'Delete this offering and all its charges?'))) return\n try {\n const res = await fetch('/api/cpq/product-offerings', {\n method: 'DELETE',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ id: offeringId }),\n })\n if (res.ok) {\n router.push('/backend/cpq/offerings')\n } else {\n const d = await res.json()\n setError(d.error ?? 'Failed to delete')\n }\n } catch {\n setError('Failed to delete')\n }\n }\n\n // \u2500\u2500\u2500 Charge CRUD \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n const loadPricingTables = async () => {\n if (pricingTables.length > 0) return\n setPricingTables(await fetchPricingTables())\n }\n\n const startEditCharge = (charge?: Charge) => {\n if (charge) {\n // Normalise legacy rows (chargeModel null, combined pricingMethod) into\n // the split shape the form's two dropdowns expect.\n const { model, source } = normalizeChargePricing(charge)\n setEditingCharge({ ...charge, chargeModel: model, pricingMethod: source })\n } else {\n setEditingCharge({ ...EMPTY_CHARGE })\n }\n loadPricingTables()\n }\n\n const saveCharge = async () => {\n if (!editingCharge) return\n setSaving(true)\n setError(null)\n try {\n const isEdit = !!editingCharge.id\n const payload = {\n ...editingCharge,\n offeringId,\n }\n const res = await fetch('/api/cpq/product-charges', {\n method: isEdit ? 'PUT' : 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(payload),\n })\n if (!res.ok) {\n const d = await res.json()\n setError(d.error ?? 'Failed to save charge')\n return\n }\n // Reload offering to get updated charges\n const offeringRes = await fetch(`/api/cpq/product-offerings?id=${encodeURIComponent(offeringId)}`)\n if (offeringRes.ok) {\n const data = await offeringRes.json()\n setCharges(data.charges ?? [])\n }\n setEditingCharge(null)\n } catch {\n setError('Failed to save charge')\n } finally {\n setSaving(false)\n }\n }\n\n const deleteCharge = async (chargeId: string) => {\n if (!confirm('Delete this charge?')) return\n try {\n const res = await fetch('/api/cpq/product-charges', {\n method: 'DELETE',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ id: chargeId }),\n })\n if (res.ok) setCharges((prev) => prev.filter((c) => c.id !== chargeId))\n } catch {\n setError('Failed to delete charge')\n }\n }\n\n const selectedPricingTable = editingCharge?.pricingTableId\n ? pricingTables.find((pt) => pt.id === editingCharge.pricingTableId)\n : null\n\n // \u2500\u2500\u2500 Helpers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n const designTimeAttrs = attributes.filter((a) => a.resolutionTime === 'design_time')\n\n // \u2500\u2500\u2500 Render \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n if (loading) {\n return <div className=\"text-sm text-muted-foreground\">{t('common.loading', 'Loading...')}</div>\n }\n\n return (\n <div className=\"space-y-6\">\n {/* Header */}\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center gap-3\">\n <button\n onClick={() => router.push('/backend/cpq/offerings')}\n className=\"text-sm text-muted-foreground hover:text-foreground\"\n >\n \u2190 {t('common.back', 'Back')}\n </button>\n <h1 className=\"text-2xl font-bold\">\n {isNew ? t('cpq.offerings.new', 'New Offering') : form.name}\n </h1>\n {!isNew && (\n <Tag variant={lifecycleStatusMap[form.lifecycleStatus as LifecycleStatus] ?? 'neutral'} dot>\n {formatStatusLabel(form.lifecycleStatus)}\n </Tag>\n )}\n {specDetail && (\n <span className=\"text-sm text-muted-foreground\">\n Spec: <button onClick={() => router.push(`/backend/cpq/specifications/${specDetail.id}`)} className=\"text-primary hover:underline\">{specDetail.name}</button>\n </span>\n )}\n </div>\n {!isNew && (\n <div className=\"flex items-center gap-2\">\n {generalMode === 'view' && tab === 'general' && (\n <Button\n type=\"button\"\n onClick={() => {\n setFormSnapshot(form)\n setDesignTimeSnapshot(designTimeValues)\n setGeneralMode('edit')\n }}\n >\n {t('common.edit', 'Edit')}\n </Button>\n )}\n <Button type=\"button\" variant=\"destructive\" onClick={deleteOffering}>\n {t('common.delete', 'Delete')}\n </Button>\n </div>\n )}\n </div>\n\n {error && (\n <Alert variant=\"destructive\">{error}</Alert>\n )}\n\n {/* Tabs */}\n {!isNew && (\n <div className=\"flex gap-1 border-b\">\n {([\n 'general',\n 'charges',\n ...(form.offeringType === 'bundle' ? ['components' as const] : []),\n ] as const).map((t_) => (\n <button\n key={t_}\n onClick={() => setTab(t_ as typeof tab)}\n className={`px-4 py-2 text-sm font-medium border-b-2 transition-colors ${\n tab === t_ ? 'border-primary text-primary' : 'border-transparent text-muted-foreground hover:text-foreground'\n }`}\n >\n {t_ === 'general' && 'General'}\n {t_ === 'charges' && `Charges (${charges.length})`}\n {t_ === 'components' && `Components (${components.length})`}\n </button>\n ))}\n </div>\n )}\n\n {/* \u2500\u2500\u2500 General Tab / New Form \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */}\n {(isNew || tab === 'general') && (\n <div className=\"rounded-lg border bg-card p-6 space-y-4\">\n {isNew && (\n <div>\n <label className=\"block text-sm font-medium mb-1\">Specification</label>\n <select\n value={form.specId}\n onChange={(e) => {\n setForm({ ...form, specId: e.target.value })\n loadSpecAttributes(e.target.value)\n setDesignTimeValues({})\n }}\n className=\"w-full rounded-md border px-3 py-2 text-sm\"\n >\n <option value=\"\">Select a specification...</option>\n {specs.map((s) => (\n <option key={s.id} value={s.id}>{s.name} ({s.code})</option>\n ))}\n </select>\n </div>\n )}\n\n <div className=\"grid grid-cols-2 gap-4\">\n <div>\n <label className=\"block text-sm font-medium mb-1\">{t('cpq.offerings.code', 'Code')}</label>\n {generalMode === 'view' && !isNew ? (\n <p className=\"text-sm font-mono py-2\">{form.code || '\u2014'}</p>\n ) : (\n <input\n type=\"text\"\n value={form.code}\n onChange={(e) => setForm({ ...form, code: e.target.value })}\n placeholder=\"e.g. gix-cloud-connect-aws\"\n className=\"w-full rounded-md border px-3 py-2 text-sm\"\n />\n )}\n </div>\n <div>\n <label className=\"block text-sm font-medium mb-1\">{t('cpq.offerings.name', 'Name')}</label>\n {generalMode === 'view' && !isNew ? (\n <p className=\"text-sm py-2\">{form.name || '\u2014'}</p>\n ) : (\n <input\n type=\"text\"\n value={form.name}\n onChange={(e) => setForm({ ...form, name: e.target.value })}\n className=\"w-full rounded-md border px-3 py-2 text-sm\"\n />\n )}\n </div>\n <div>\n <label className=\"block text-sm font-medium mb-1\">{t('cpq.offerings.lifecycleStatus', 'Lifecycle Status')}</label>\n {generalMode === 'view' && !isNew ? (\n <div className=\"py-2\">\n <Tag variant={lifecycleStatusMap[form.lifecycleStatus as LifecycleStatus] ?? 'neutral'} dot>\n {formatStatusLabel(form.lifecycleStatus)}\n </Tag>\n </div>\n ) : (\n <select\n value={form.lifecycleStatus}\n onChange={(e) => setForm({ ...form, lifecycleStatus: e.target.value })}\n className=\"w-full rounded-md border px-3 py-2 text-sm\"\n >\n <option value=\"draft\">Draft</option>\n <option value=\"active\">Active</option>\n <option value=\"deprecated\">Deprecated</option>\n </select>\n )}\n </div>\n <div>\n <label className=\"block text-sm font-medium mb-1\">{t('cpq.offerings.isActive', 'Is Active?')}</label>\n <div className=\"flex items-center h-[38px]\">\n {generalMode === 'view' && !isNew ? (\n <Tag variant={form.isActive ? 'success' : 'neutral'} dot>\n {form.isActive ? t('common.yes', 'Yes') : t('common.no', 'No')}\n </Tag>\n ) : (\n <input\n type=\"checkbox\"\n checked={form.isActive}\n onChange={(e) => setForm({ ...form, isActive: e.target.checked })}\n className=\"rounded border\"\n />\n )}\n </div>\n </div>\n </div>\n <div>\n <label className=\"block text-sm font-medium mb-1\">{t('cpq.offerings.description', 'Description')}</label>\n {generalMode === 'view' && !isNew ? (\n <p className=\"text-sm text-muted-foreground py-2 whitespace-pre-wrap\">{form.description || '\u2014'}</p>\n ) : (\n <textarea\n value={form.description ?? ''}\n onChange={(e) => setForm({ ...form, description: e.target.value })}\n rows={3}\n className=\"w-full rounded-md border px-3 py-2 text-sm\"\n />\n )}\n </div>\n\n {/* Design-time values */}\n {designTimeAttrs.length > 0 && (\n <div className=\"space-y-3\">\n <label className=\"block text-sm font-medium\">Design-Time Values</label>\n <div className=\"grid grid-cols-2 gap-3\">\n {designTimeAttrs.map((attr) => {\n const value = designTimeValues[attr.code]\n const isViewing = generalMode === 'view' && !isNew\n // Lookup the human label for select-type values so the\n // read-only view doesn't show raw codes.\n const optionLabel =\n (attr.attributeType === 'select' || attr.attributeType === 'enum') && attr.options\n ? attr.options.find((o) => o.value === value)?.label\n : undefined\n return (\n <div key={attr.code}>\n <label className=\"block text-xs font-medium mb-1\">\n {attr.name}\n {attr.isRequired && <span className=\"text-destructive ml-0.5\">*</span>}\n </label>\n {isViewing ? (\n <p className=\"text-sm py-2\">\n {value == null || value === '' ? (\n <span className=\"text-muted-foreground\">\u2014</span>\n ) : attr.attributeType === 'boolean' ? (\n <Tag variant={value ? 'success' : 'neutral'} dot>\n {value ? t('common.yes', 'Yes') : t('common.no', 'No')}\n </Tag>\n ) : (\n optionLabel ?? String(value)\n )}\n </p>\n ) : (attr.attributeType === 'select' || attr.attributeType === 'enum') && attr.options ? (\n <select\n value={String(value ?? '')}\n onChange={(e) => setDesignTimeValues({ ...designTimeValues, [attr.code]: e.target.value || null })}\n className=\"w-full rounded-md border px-2 py-1.5 text-sm\"\n >\n <option value=\"\">Select {attr.name}...</option>\n {attr.options.map((opt) => (\n <option key={opt.value} value={opt.value}>{opt.label}</option>\n ))}\n </select>\n ) : attr.attributeType === 'number' ? (\n <NumberInput\n value={typeof value === 'number' ? (value as number) : null}\n onChange={(n) => setDesignTimeValues({ ...designTimeValues, [attr.code]: n })}\n />\n ) : attr.attributeType === 'boolean' ? (\n <div className=\"pt-1\">\n <label className=\"flex items-center gap-1.5 text-sm\">\n <input\n type=\"checkbox\"\n checked={!!value}\n onChange={(e) => setDesignTimeValues({ ...designTimeValues, [attr.code]: e.target.checked })}\n className=\"rounded border\"\n />\n {attr.name}\n </label>\n </div>\n ) : (\n <input\n type=\"text\"\n value={String(value ?? '')}\n onChange={(e) => setDesignTimeValues({ ...designTimeValues, [attr.code]: e.target.value || null })}\n className=\"w-full rounded-md border px-2 py-1.5 text-sm\"\n placeholder={attr.helpText ?? undefined}\n />\n )}\n {attr.helpText && <p className=\"text-xs text-muted-foreground mt-0.5\">{attr.helpText}</p>}\n </div>\n )\n })}\n </div>\n </div>\n )}\n\n {/* In view mode the Edit button lives in the page header next to\n Delete (OM standard). Here we only render the Save/Cancel\n pair when actually editing. */}\n {!(generalMode === 'view' && !isNew) && (\n <div className=\"flex gap-3\">\n <Button\n type=\"button\"\n onClick={saveOffering}\n disabled={saving || !form.code || !form.name || (isNew && !form.specId)}\n >\n {saving ? t('common.saving', 'Saving...') : t('common.save', 'Save')}\n </Button>\n <Button\n type=\"button\"\n variant=\"outline\"\n onClick={() => {\n if (isNew) {\n router.push('/backend/cpq/offerings')\n return\n }\n if (formSnapshot) setForm(formSnapshot)\n if (designTimeSnapshot) setDesignTimeValues(designTimeSnapshot)\n setFormSnapshot(null)\n setDesignTimeSnapshot(null)\n setGeneralMode('view')\n }}\n >\n {t('common.cancel', 'Cancel')}\n </Button>\n </div>\n )}\n </div>\n )}\n\n {/* \u2500\u2500\u2500 Charges Tab \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */}\n {tab === 'charges' && !isNew && (\n <div className=\"space-y-4\">\n <div className=\"flex justify-end\">\n <button\n onClick={() => startEditCharge()}\n className=\"inline-flex items-center justify-center rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground hover:bg-primary/90\"\n >\n {t('cpq.offerings.addCharge', 'Add Charge')}\n </button>\n </div>\n\n {/* Charge edit form */}\n {editingCharge && (\n <div className=\"rounded-lg border bg-card p-4 space-y-3\">\n <h3 className=\"font-medium text-sm\">\n {editingCharge.id ? 'Edit Charge' : 'New Charge'}\n </h3>\n <div className=\"grid grid-cols-3 gap-3\">\n <div>\n <label className=\"block text-xs font-medium mb-1\">Code</label>\n <input type=\"text\" value={editingCharge.code} onChange={(e) => setEditingCharge({ ...editingCharge, code: e.target.value })} placeholder=\"e.g. mrc-monthly\" className=\"w-full rounded-md border px-2 py-1.5 text-sm\" />\n </div>\n <div>\n <label className=\"block text-xs font-medium mb-1\">Name</label>\n <input type=\"text\" value={editingCharge.name} onChange={(e) => setEditingCharge({ ...editingCharge, name: e.target.value })} className=\"w-full rounded-md border px-2 py-1.5 text-sm\" />\n </div>\n <div>\n <label className=\"block text-xs font-medium mb-1\">Charge Type</label>\n <select value={editingCharge.chargeType} onChange={(e) => setEditingCharge({ ...editingCharge, chargeType: e.target.value })} className=\"w-full rounded-md border px-2 py-1.5 text-sm\">\n <option value=\"mrc\">MRC (Monthly Recurring)</option>\n <option value=\"nrc\">NRC (Non-Recurring)</option>\n <option value=\"usage\">Usage</option>\n </select>\n </div>\n <div>\n <label className=\"block text-xs font-medium mb-1\">Charge Model</label>\n <select\n value={editingCharge.chargeModel ?? 'flat'}\n onChange={(e) => {\n const model = e.target.value\n const next = { ...editingCharge, chargeModel: model }\n // Volume / tiered are graduated over table ranges \u2014 they can't use a fixed price.\n if ((model === 'volume' || model === 'tiered') && editingCharge.pricingMethod !== 'table') {\n next.pricingMethod = 'table'\n next.fixedPrice = null\n }\n // Flat never takes a quantity attribute.\n if (model === 'flat') next.quantityAttributeCode = null\n setEditingCharge(next)\n }}\n className=\"w-full rounded-md border px-2 py-1.5 text-sm\"\n >\n <option value=\"flat\">Flat Fee</option>\n <option value=\"per_unit\">Per Unit</option>\n <option value=\"volume\">Volume-based</option>\n <option value=\"tiered\">Tiered</option>\n </select>\n </div>\n <div>\n <label className=\"block text-xs font-medium mb-1\">Pricing Method</label>\n <select\n value={editingCharge.pricingMethod}\n onChange={(e) => {\n const source = e.target.value\n if (source === 'fixed') {\n // Only per_unit keeps the quantity attribute under a fixed\n // price; flat must drop it (V-CHG-1 forbids it).\n const keepQty = editingCharge.chargeModel === 'per_unit'\n setEditingCharge({ ...editingCharge, pricingMethod: source, pricingTableId: null, priceColumnKey: null, ...(keepQty ? {} : { quantityAttributeCode: null }) })\n } else {\n setEditingCharge({ ...editingCharge, pricingMethod: source, fixedPrice: null })\n }\n }}\n className=\"w-full rounded-md border px-2 py-1.5 text-sm\"\n >\n {/* Volume / tiered are graduated over table ranges \u2014 a fixed price isn't applicable. */}\n {editingCharge.chargeModel !== 'volume' && editingCharge.chargeModel !== 'tiered' && (\n <option value=\"fixed\">Fixed Price</option>\n )}\n <option value=\"table\">Table Lookup</option>\n </select>\n </div>\n {editingCharge.pricingMethod === 'fixed' ? (\n <>\n <div>\n <label className=\"block text-xs font-medium mb-1\">Fixed Price <span className=\"text-destructive\">*</span></label>\n <input type=\"text\" value={editingCharge.fixedPrice ?? ''} onChange={(e) => setEditingCharge({ ...editingCharge, fixedPrice: e.target.value || null })} placeholder=\"0.00\" className=\"w-full rounded-md border px-2 py-1.5 text-sm\" />\n </div>\n <div>\n <label className=\"block text-xs font-medium mb-1\">Currency <span className=\"text-destructive\">*</span></label>\n <input type=\"text\" value={editingCharge.currencyCode ?? 'USD'} onChange={(e) => setEditingCharge({ ...editingCharge, currencyCode: e.target.value || null })} className=\"w-full rounded-md border px-2 py-1.5 text-sm\" />\n </div>\n </>\n ) : (\n <>\n <div>\n <label className=\"block text-xs font-medium mb-1\">Pricing Table <span className=\"text-destructive\">*</span></label>\n <select value={editingCharge.pricingTableId ?? ''} onChange={(e) => setEditingCharge({ ...editingCharge, pricingTableId: e.target.value || null, priceColumnKey: null })} className=\"w-full rounded-md border px-2 py-1.5 text-sm\">\n <option value=\"\">Select table...</option>\n {pricingTables.map((pt) => (\n <option key={pt.id} value={pt.id}>{pt.name} ({pt.code})</option>\n ))}\n </select>\n {pricingTables.length === 0 && (\n <p className=\"text-xs text-warning mt-0.5\">\n No pricing tables yet \u2014{' '}\n <a href=\"/backend/cpq/pricing-tables\" className=\"text-primary hover:underline\">create one</a>{' '}\n before using Table Lookup pricing.\n </p>\n )}\n </div>\n <div>\n <label className=\"block text-xs font-medium mb-1\">Price Column <span className=\"text-destructive\">*</span></label>\n <select value={editingCharge.priceColumnKey ?? ''} onChange={(e) => setEditingCharge({ ...editingCharge, priceColumnKey: e.target.value || null })} className=\"w-full rounded-md border px-2 py-1.5 text-sm\" disabled={!selectedPricingTable}>\n <option value=\"\">Select column...</option>\n {selectedPricingTable?.priceColumns.map((col) => (\n <option key={col.key} value={col.key}>{col.label}</option>\n ))}\n </select>\n </div>\n </>\n )}\n {/* Quantity attribute drives the unit count \u2014 needed for per-unit\n (any source) and for volume / tiered table lookups. */}\n {((editingCharge.pricingMethod === 'table' && editingCharge.chargeModel !== 'flat') ||\n (editingCharge.pricingMethod === 'fixed' && editingCharge.chargeModel === 'per_unit')) && (\n <div>\n <label className=\"block text-xs font-medium mb-1\">Quantity Attribute <span className=\"text-destructive\">*</span></label>\n <select value={editingCharge.quantityAttributeCode ?? ''} onChange={(e) => setEditingCharge({ ...editingCharge, quantityAttributeCode: e.target.value || null })} className=\"w-full rounded-md border px-2 py-1.5 text-sm\">\n <option value=\"\">Select attribute...</option>\n {attributes.filter((a) => a.attributeType === 'number').map((a) => (\n <option key={a.code} value={a.code}>{a.name} ({a.code})</option>\n ))}\n </select>\n <p className=\"text-xs text-muted-foreground mt-0.5\">Attribute whose value drives the quantity for pricing</p>\n {attributes.filter((a) => a.attributeType === 'number').length === 0 && form.specId && (\n <p className=\"text-xs text-warning mt-0.5\">\n Spec has no number attributes \u2014{' '}\n <a href={`/backend/cpq/specifications/${form.specId}`} className=\"text-primary hover:underline\">\n add one to the spec\n </a>{' '}\n first.\n </p>\n )}\n </div>\n )}\n <div>\n <label className=\"block text-xs font-medium mb-1\">Sort Order</label>\n <NumberInput\n integer\n value={editingCharge.sortOrder}\n onChange={(n) => setEditingCharge({ ...editingCharge, sortOrder: n ?? 0 })}\n />\n </div>\n </div>\n <div>\n <label className=\"block text-xs font-medium mb-1\">Description</label>\n <input type=\"text\" value={editingCharge.description ?? ''} onChange={(e) => setEditingCharge({ ...editingCharge, description: e.target.value || null })} className=\"w-full rounded-md border px-2 py-1.5 text-sm\" />\n </div>\n <div className=\"flex items-end gap-4\">\n <label className=\"flex items-center gap-1.5 text-sm\">\n <input type=\"checkbox\" checked={editingCharge.isActive} onChange={(e) => setEditingCharge({ ...editingCharge, isActive: e.target.checked })} className=\"rounded border\" />\n Active\n </label>\n </div>\n {(() => {\n const missing = chargeMissingFields(editingCharge)\n const blocked = saving || !editingCharge.code || !editingCharge.name || missing.length > 0\n return (\n <>\n {missing.length > 0 && (\n <Alert variant=\"destructive\">\n Missing required field{missing.length > 1 ? 's' : ''} for {editingCharge.pricingMethod} pricing: {missing.join(', ')}\n </Alert>\n )}\n <div className=\"flex gap-2\">\n <button onClick={saveCharge} disabled={blocked} className=\"inline-flex items-center rounded-md bg-primary px-3 py-1.5 text-sm font-medium text-primary-foreground hover:bg-primary/90 disabled:opacity-50 disabled:cursor-not-allowed\">\n {saving ? 'Saving...' : 'Save'}\n </button>\n <button onClick={() => setEditingCharge(null)} className=\"inline-flex items-center rounded-md border px-3 py-1.5 text-sm font-medium hover:bg-muted\">Cancel</button>\n </div>\n </>\n )\n })()}\n </div>\n )}\n\n {/* Charges table */}\n {charges.length === 0 ? (\n <div className=\"rounded-lg border bg-card p-6 text-center text-sm text-muted-foreground\">\n No charges defined. Add recurring, non-recurring, or usage charges to this offering.\n </div>\n ) : (\n <div className=\"rounded-lg border\">\n <table className=\"w-full text-sm\">\n <thead>\n <tr className=\"border-b bg-muted/50\">\n <th className=\"px-4 py-3 text-left font-medium\">Code</th>\n <th className=\"px-4 py-3 text-left font-medium\">Name</th>\n <th className=\"px-4 py-3 text-left font-medium\">Type</th>\n <th className=\"px-4 py-3 text-left font-medium\">Pricing</th>\n <th className=\"px-4 py-3 text-left font-medium\">Price</th>\n <th className=\"px-4 py-3 text-left font-medium\">Active</th>\n <th className=\"px-4 py-3 text-right font-medium\">Actions</th>\n </tr>\n </thead>\n <tbody>\n {charges.map((charge) => {\n const incomplete = !isChargeComplete(charge)\n const tableRef = charge.pricingTableId\n ? pricingTables.find((pt) => pt.id === charge.pricingTableId)\n : null\n const qtyAttr = charge.quantityAttributeCode\n ? attributes.find((a) => a.code === charge.quantityAttributeCode)\n : null\n const { model, source } = normalizeChargePricing(charge)\n return (\n <tr key={charge.id} className=\"border-b\">\n <td className=\"px-4 py-3 font-mono text-xs\">{charge.code}</td>\n <td className=\"px-4 py-3\">\n {charge.name}\n {incomplete && (\n <Tag variant=\"error\" className=\"ml-2 px-2 text-[10px]\" dot>Incomplete</Tag>\n )}\n </td>\n <td className=\"px-4 py-3\">\n <Tag variant={chargeTypeMap[charge.chargeType as ChargeType] ?? 'neutral'} className=\"px-2 text-xs\">\n {charge.chargeType.toUpperCase()}\n </Tag>\n </td>\n <td className=\"px-4 py-3 text-xs\">\n {CHARGE_MODEL_LABELS[model] ?? model}\n <span className=\"text-muted-foreground\"> \u00B7 {PRICING_SOURCE_LABELS[source] ?? source}</span>\n </td>\n <td className=\"px-4 py-3 text-xs\">\n {source === 'fixed' ? (\n <div className=\"flex flex-col gap-0.5\">\n {charge.fixedPrice != null\n ? <span>{`${charge.currencyCode ?? 'USD'} ${charge.fixedPrice}`}</span>\n : <span className=\"text-muted-foreground\">\u2014</span>}\n {model === 'per_unit' && (\n <span>\n <span className=\"text-muted-foreground\">\u00D7 Qty:</span>{' '}\n {qtyAttr ? `${qtyAttr.name} (${qtyAttr.code})` : <span className=\"text-destructive\">missing</span>}\n </span>\n )}\n </div>\n ) : (\n <div className=\"flex flex-col gap-0.5\">\n <span>\n <span className=\"text-muted-foreground\">Table:</span>{' '}\n {tableRef ? `${tableRef.name} \u2192 ${charge.priceColumnKey ?? '?'}` : <span className=\"text-destructive\">missing</span>}\n </span>\n {model !== 'flat' && (\n <span>\n <span className=\"text-muted-foreground\">\u00D7 Qty:</span>{' '}\n {qtyAttr ? `${qtyAttr.name} (${qtyAttr.code})` : <span className=\"text-destructive\">missing</span>}\n </span>\n )}\n </div>\n )}\n </td>\n <td className=\"px-4 py-3\">{charge.isActive ? 'Yes' : 'No'}</td>\n <td className=\"px-4 py-3 text-right\">\n <button onClick={() => startEditCharge(charge)} className=\"text-xs text-primary hover:underline mr-2\">Edit</button>\n <button onClick={() => deleteCharge(charge.id)} className=\"text-xs text-destructive hover:underline\">Delete</button>\n </td>\n </tr>\n )\n })}\n </tbody>\n </table>\n </div>\n )}\n </div>\n )}\n\n {/* \u2500\u2500\u2500 Components Tab (bundle offerings) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */}\n {tab === 'components' && !isNew && form.offeringType === 'bundle' && (\n <div className=\"space-y-4\">\n {bundleSlots.length === 0 ? (\n <div className=\"rounded-lg border bg-card p-6 text-center text-sm text-muted-foreground\">\n No bundle slots defined on this specification. Add slots on the specification first.\n </div>\n ) : (\n <>\n {/* Group components by slot */}\n {bundleSlots.map((slot) => {\n const slotComponents = components.filter((c) => c.slotId === slot.id)\n return (\n <div key={slot.id} className=\"rounded-lg border bg-card overflow-hidden\">\n <div className=\"bg-muted/50 px-4 py-3 border-b flex items-center justify-between\">\n <div>\n <span className=\"font-medium text-sm\">{slot.name}</span>\n <Tag variant=\"info\" className=\"ml-2 px-2 text-[10px]\">\n {slot.componentGroup}\n </Tag>\n <span className=\"ml-2 text-xs text-muted-foreground\">\n {slot.cardinalityMin}..{slot.cardinalityMax ?? '\u221E'}\n </span>\n {slot.targetSpec && (\n <span className=\"ml-2 text-xs text-muted-foreground\">\u2192 {slot.targetSpec.name}</span>\n )}\n </div>\n <button\n onClick={async () => {\n setAddingComponent({ slotId: slot.id, childOfferingId: '', isDefault: false })\n if (!slotOfferings[slot.targetSpecId]) {\n const res = await fetch(`/api/cpq/product-offerings?specId=${encodeURIComponent(slot.targetSpecId)}&pageSize=100`)\n if (res.ok) {\n const d = await res.json()\n setSlotOfferings((prev) => ({ ...prev, [slot.targetSpecId]: d.items ?? [] }))\n }\n }\n }}\n className=\"inline-flex items-center justify-center rounded-md bg-primary px-3 py-1.5 text-xs font-medium text-primary-foreground hover:bg-primary/90\"\n >\n + Add Component\n </button>\n </div>\n\n {addingComponent?.slotId === slot.id && (\n <div className=\"p-4 border-b bg-muted/20 space-y-3\">\n <div className=\"grid grid-cols-3 gap-3\">\n <div className=\"col-span-2\">\n <label className=\"block text-xs font-medium mb-1\">Component Offering</label>\n <select\n value={addingComponent.childOfferingId}\n onChange={(e) => setAddingComponent({ ...addingComponent, childOfferingId: e.target.value })}\n className=\"w-full rounded-md border px-3 py-2 text-sm\"\n >\n <option value=\"\">\u2014 Select offering \u2014</option>\n {(slotOfferings[slot.targetSpecId] ?? []).map((o) => (\n <option key={o.id} value={o.id}>{o.name} ({o.code}){o.offeringType === 'bundle' ? ' [bundle]' : ''}</option>\n ))}\n </select>\n </div>\n <div>\n <label className=\"block text-xs font-medium mb-1\">Default?</label>\n <div className=\"flex items-center h-[38px]\">\n <input\n type=\"checkbox\"\n checked={addingComponent.isDefault}\n onChange={(e) => setAddingComponent({ ...addingComponent, isDefault: e.target.checked })}\n className=\"rounded border\"\n />\n <span className=\"ml-2 text-xs text-muted-foreground\">Pre-selected in quote</span>\n </div>\n </div>\n </div>\n <div className=\"flex gap-2\">\n <button\n disabled={saving || !addingComponent.childOfferingId}\n onClick={async () => {\n setSaving(true)\n setError(null)\n try {\n const res = await fetch('/api/cpq/offering-components', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n offeringId,\n slotId: addingComponent.slotId,\n childOfferingId: addingComponent.childOfferingId,\n isDefault: addingComponent.isDefault,\n }),\n })\n if (!res.ok) {\n const d = await res.json()\n setError(d.error ?? 'Failed to add component')\n return\n }\n setAddingComponent(null)\n const compRes = await fetch(`/api/cpq/offering-components?offeringId=${offeringId}`)\n if (compRes.ok) {\n const d = await compRes.json()\n setComponents(d.items ?? [])\n }\n } catch {\n setError('Failed to add component')\n } finally {\n setSaving(false)\n }\n }}\n className=\"inline-flex items-center justify-center rounded-md bg-primary px-3 py-1.5 text-xs font-medium text-primary-foreground hover:bg-primary/90 disabled:opacity-50\"\n >\n {saving ? 'Adding...' : 'Add'}\n </button>\n <button\n onClick={() => setAddingComponent(null)}\n className=\"inline-flex items-center justify-center rounded-md border px-3 py-1.5 text-xs font-medium hover:bg-muted\"\n >\n Cancel\n </button>\n </div>\n </div>\n )}\n\n {slotComponents.length === 0 ? (\n <div className=\"p-4 text-center text-xs text-muted-foreground\">\n No components assigned to this slot\n {slot.cardinalityMin > 0 && (\n <span className=\"ml-1 text-status-warning-text font-medium\">(required: min {slot.cardinalityMin})</span>\n )}\n </div>\n ) : (\n <table className=\"w-full text-sm\">\n <thead>\n <tr className=\"border-b bg-muted/30\">\n <th className=\"px-4 py-2 text-left text-xs font-medium\">Offering</th>\n <th className=\"px-4 py-2 text-left text-xs font-medium\">Code</th>\n <th className=\"px-4 py-2 text-left text-xs font-medium\">Type</th>\n <th className=\"px-4 py-2 text-left text-xs font-medium\">Default</th>\n <th className=\"px-4 py-2 text-right text-xs font-medium\">Actions</th>\n </tr>\n </thead>\n <tbody>\n {slotComponents.map((comp) => (\n <tr key={comp.id} className=\"border-b last:border-0\">\n <td className=\"px-4 py-2.5 font-medium\">{comp.childOffering?.name ?? 'Unknown'}</td>\n <td className=\"px-4 py-2.5 text-muted-foreground text-xs\">{comp.childOffering?.code ?? '\u2014'}</td>\n <td className=\"px-4 py-2.5\">\n {comp.childOffering?.offeringType === 'bundle' ? (\n <Tag variant=\"brand\" className=\"px-2 text-[10px]\">bundle</Tag>\n ) : (\n <Tag variant=\"neutral\" className=\"px-2 text-[10px]\">simple</Tag>\n )}\n </td>\n <td className=\"px-4 py-2.5\">\n <button\n onClick={async () => {\n try {\n const res = await fetch('/api/cpq/offering-components', {\n method: 'PUT',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ id: comp.id, isDefault: !comp.isDefault }),\n })\n if (res.ok) {\n setComponents((prev) => prev.map((c) => c.id === comp.id ? { ...c, isDefault: !c.isDefault } : c))\n }\n } catch { /* ignore */ }\n }}\n className=\"cursor-pointer\"\n >\n <Tag variant={comp.isDefault ? 'success' : 'neutral'} className=\"px-2 text-[10px]\">\n {comp.isDefault ? 'Yes' : 'No'}\n </Tag>\n </button>\n </td>\n <td className=\"px-4 py-2.5 text-right\">\n <button\n onClick={async () => {\n if (!confirm('Remove this component from the bundle?')) return\n try {\n const res = await fetch('/api/cpq/offering-components', {\n method: 'DELETE',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ id: comp.id }),\n })\n if (res.ok) {\n setComponents((prev) => prev.filter((c) => c.id !== comp.id))\n } else {\n const d = await res.json()\n setError(d.error ?? 'Failed to remove')\n }\n } catch {\n setError('Failed to remove component')\n }\n }}\n className=\"text-xs text-destructive hover:underline\"\n >\n Remove\n </button>\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n )}\n </div>\n )\n })}\n </>\n )}\n </div>\n )}\n </div>\n )\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -155,12 +155,12 @@ function EntriesEditor({
155
155
  error && /* @__PURE__ */ jsx(Alert, { variant: "destructive", children: error }),
156
156
  visibleDrafts.length === 0 ? /* @__PURE__ */ jsx("div", { className: "rounded-lg border bg-card p-6 text-center text-sm text-muted-foreground", children: mode === "edit" ? 'No entries yet \u2014 use "+ Add Row" (dimensions lookup) or "+ Add Tier" (range lookup).' : "No entries in this pricing table." }) : /* @__PURE__ */ jsx("div", { className: "rounded-lg border overflow-x-auto", children: /* @__PURE__ */ jsxs("table", { className: "w-full text-sm", children: [
157
157
  /* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsxs("tr", { className: "border-b bg-muted/50", children: [
158
+ table.dimensions.map((dim) => /* @__PURE__ */ jsx("th", { className: "px-3 py-3 text-left font-medium whitespace-nowrap", children: dim.label }, dim.key)),
158
159
  hasTieredEntries && /* @__PURE__ */ jsxs(Fragment, { children: [
159
160
  /* @__PURE__ */ jsx("th", { className: "px-3 py-3 text-left font-medium whitespace-nowrap", children: "Tier #" }),
160
161
  /* @__PURE__ */ jsx("th", { className: "px-3 py-3 text-left font-medium whitespace-nowrap", children: "Range From" }),
161
162
  /* @__PURE__ */ jsx("th", { className: "px-3 py-3 text-left font-medium whitespace-nowrap", children: "Range To" })
162
163
  ] }),
163
- table.dimensions.map((dim) => /* @__PURE__ */ jsx("th", { className: "px-3 py-3 text-left font-medium whitespace-nowrap", children: dim.label }, dim.key)),
164
164
  table.priceColumns.map((col) => /* @__PURE__ */ jsx("th", { className: "px-3 py-3 text-right font-medium whitespace-nowrap", children: col.label }, col.key)),
165
165
  /* @__PURE__ */ jsx("th", { className: "px-3 py-3 text-left font-medium", children: "Currency" }),
166
166
  mode === "edit" && /* @__PURE__ */ jsx("th", { className: "px-3 py-3 w-8", "aria-label": "Actions" })
@@ -191,6 +191,16 @@ function EntryRow({
191
191
  const readOnly = mode === "view";
192
192
  const rowBg = entry._state === "new" ? "bg-success/5" : entry._state === "modified" ? "bg-warning/5" : "";
193
193
  return /* @__PURE__ */ jsxs("tr", { className: `border-b hover:bg-muted/30 ${rowBg}`, children: [
194
+ table.dimensions.map((dim) => /* @__PURE__ */ jsx("td", { className: "px-3 py-2", children: readOnly ? entry.dimensionValues?.[dim.key] ?? "\u2014" : /* @__PURE__ */ jsx(
195
+ Input,
196
+ {
197
+ value: entry.dimensionValues?.[dim.key] ?? "",
198
+ onChange: (e) => onChange({
199
+ dimensionValues: { ...entry.dimensionValues, [dim.key]: e.target.value }
200
+ }),
201
+ className: "w-28 h-8"
202
+ }
203
+ ) }, dim.key)),
194
204
  hasTieredEntries && /* @__PURE__ */ jsxs(Fragment, { children: [
195
205
  /* @__PURE__ */ jsx("td", { className: "px-3 py-2", children: readOnly ? entry.tierNumber ?? "\u2014" : /* @__PURE__ */ jsx(
196
206
  Input,
@@ -221,16 +231,6 @@ function EntryRow({
221
231
  }
222
232
  ) })
223
233
  ] }),
224
- table.dimensions.map((dim) => /* @__PURE__ */ jsx("td", { className: "px-3 py-2", children: readOnly ? entry.dimensionValues?.[dim.key] ?? "\u2014" : /* @__PURE__ */ jsx(
225
- Input,
226
- {
227
- value: entry.dimensionValues?.[dim.key] ?? "",
228
- onChange: (e) => onChange({
229
- dimensionValues: { ...entry.dimensionValues, [dim.key]: e.target.value }
230
- }),
231
- className: "w-28 h-8"
232
- }
233
- ) }, dim.key)),
234
234
  table.priceColumns.map((col) => /* @__PURE__ */ jsx("td", { className: "px-3 py-2 text-right font-mono", children: readOnly ? entry.prices?.[col.key] != null ? Number(entry.prices[col.key]).toFixed(2) : "\u2014" : /* @__PURE__ */ jsx(
235
235
  Input,
236
236
  {