@bluecircuit/offer-calculator 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +674 -0
- package/README.md +473 -0
- package/dist/calculator.css +385 -0
- package/dist/index.css +305 -0
- package/dist/index.css.map +1 -0
- package/dist/index.d.mts +74 -0
- package/dist/index.d.ts +74 -0
- package/dist/index.js +1084 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +1062 -0
- package/dist/index.mjs.map +1 -0
- package/dist/types.d.mts +64 -0
- package/dist/types.d.ts +64 -0
- package/dist/types.js +4 -0
- package/dist/types.js.map +1 -0
- package/dist/types.mjs +3 -0
- package/dist/types.mjs.map +1 -0
- package/package.json +86 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/lib/calculator/pricing.ts","../src/lib/calculator/hooks.ts","../src/components/calculator/ConditionTabs.tsx","../src/components/calculator/DefectCheckbox.tsx","../src/components/calculator/PriceDisplay.tsx","../src/components/calculator/calculator.module.css","../src/components/calculator/OfferCalculator.tsx","../src/lib/calculator/validation.ts","../src/lib/cms/fetchCalculatorConfig.ts","../src/index.ts"],"names":["useState","useMemo","useCallback","jsxs","jsx","Fragment"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Pure Pricing Calculation Functions\n *\n * This module contains the core business logic for calculating device offers.\n * Uses multiplicative cascading for defect discounts (order-independent).\n *\n * ALGORITHM:\n * 1. Apply condition multiplier to base price\n * 2. Sort defects by severity (highest percent first)\n * 3. Apply each defect multiplicatively: price *= (1 - percent/100)\n * 4. Round to 2 decimal places\n * 5. Enforce minimum offer floor: max(minimumOffer, price)\n *\n * @module pricing\n */\n\nimport type {\n DefectAdjustment,\n CalculationResult,\n CalculationBreakdown,\n} from './types';\n\n/**\n * Calculate final offer using multiplicative cascading discounts.\n *\n * This is a pure function with no side effects - all calculations are deterministic\n * and order-independent (defects are sorted internally by severity).\n *\n * @param basePrice - Base price from CMS (before any adjustments)\n * @param conditionMultiplier - Condition tier multiplier (e.g., 0.85 for \"Fair\", 1.0 for \"Flawless\")\n * @param selectedDefects - Array of selected defects\n * @param minimumOffer - Minimum offer floor (default: 1.00)\n * @returns Calculation result with final price and detailed breakdown\n *\n * @example\n * // Base: $230, Condition: Flawless (1.0), Defects: 60%, 45%\n * const result = calculateOffer(230, 1.0, [\n * { id: 'check1', label: 'Motherboard', percent: 60 },\n * { id: 'check2', label: 'Screen', percent: 45 }\n * ], 1.00);\n * // result.finalPrice = 50.60\n * // Calculation: 230 * 1.0 * 0.4 * 0.55 = 50.60\n */\nexport function calculateOffer(\n basePrice: number,\n conditionMultiplier: number,\n selectedDefects: DefectAdjustment[],\n minimumOffer: number = 1.00\n): CalculationResult {\n // STEP 1: Validate inputs\n const parsedBasePrice = parseFloat(String(basePrice));\n const parsedConditionMultiplier = parseFloat(String(conditionMultiplier));\n const parsedMinimumOffer = parseFloat(String(minimumOffer));\n\n // Handle invalid base price\n if (\n isNaN(parsedBasePrice) ||\n parsedBasePrice <= 0 ||\n !isFinite(parsedBasePrice)\n ) {\n console.error(\n '[calculateOffer] Invalid base price:',\n basePrice,\n '| Returning minimum offer'\n );\n return createMinimumOfferResult(\n basePrice,\n parsedConditionMultiplier || 1.0,\n selectedDefects,\n parsedMinimumOffer\n );\n }\n\n // Handle invalid condition multiplier (fallback to 1.0)\n const validConditionMultiplier =\n isNaN(parsedConditionMultiplier) ||\n !isFinite(parsedConditionMultiplier) ||\n parsedConditionMultiplier <= 0\n ? 1.0\n : parsedConditionMultiplier;\n\n // Handle invalid minimum offer (fallback to 1.00)\n const validMinimumOffer =\n isNaN(parsedMinimumOffer) ||\n !isFinite(parsedMinimumOffer) ||\n parsedMinimumOffer <= 0\n ? 1.0\n : parsedMinimumOffer;\n\n // STEP 2: Apply condition multiplier\n let price = parsedBasePrice * validConditionMultiplier;\n const priceAfterCondition = price;\n\n // STEP 3: Sort defects by severity (DESC)\n // Filter out invalid defects\n const validDefects = selectedDefects.filter((d) => {\n const percent = parseFloat(String(d.percent));\n if (isNaN(percent) || !isFinite(percent) || percent < 0 || percent > 100) {\n console.warn('[calculateOffer] Invalid defect percent:', d);\n return false;\n }\n return true;\n });\n\n const sortedDefects = [...validDefects].sort(\n (a, b) => b.percent - a.percent\n );\n\n // STEP 4: Apply each defect multiplicatively\n for (const defect of sortedDefects) {\n const discountMultiplier = 1 - defect.percent / 100;\n price = price * discountMultiplier;\n }\n\n // STEP 5: Round to 2 decimal places\n const priceBeforeClamp = Math.round(price * 100) / 100;\n\n // STEP 6: Enforce minimum offer\n const finalPrice = Math.max(validMinimumOffer, priceBeforeClamp);\n const minimumEnforced = finalPrice === validMinimumOffer && priceBeforeClamp < validMinimumOffer;\n\n // Log warning if minimum was enforced\n if (minimumEnforced) {\n console.warn(\n `[calculateOffer] Minimum price enforced: $${priceBeforeClamp.toFixed(2)} → $${finalPrice.toFixed(2)}`\n );\n }\n\n // STEP 7: Calculate total discount percent (for display only)\n const totalDiscountPercent = sortedDefects.reduce(\n (sum, defect) => sum + defect.percent,\n 0\n );\n\n // STEP 8: Build breakdown\n const breakdown: CalculationBreakdown = {\n basePrice: parsedBasePrice,\n conditionMultiplier: validConditionMultiplier,\n priceAfterCondition,\n appliedDefects: sortedDefects,\n totalDiscountPercent,\n priceBeforeClamp,\n minimumEnforced,\n };\n\n return {\n finalPrice,\n breakdown,\n };\n}\n\n/**\n * Helper function to create a minimum offer result when inputs are invalid.\n * Used as a fallback when base price is invalid.\n *\n * @private\n */\nfunction createMinimumOfferResult(\n basePrice: number,\n conditionMultiplier: number,\n _selectedDefects: DefectAdjustment[],\n minimumOffer: number\n): CalculationResult {\n return {\n finalPrice: minimumOffer,\n breakdown: {\n basePrice: parseFloat(String(basePrice)) || 0,\n conditionMultiplier: conditionMultiplier || 1.0,\n priceAfterCondition: 0,\n appliedDefects: [],\n totalDiscountPercent: 0,\n priceBeforeClamp: 0,\n minimumEnforced: true,\n },\n };\n}\n\n/**\n * Format a price as currency string with 2 decimal places.\n *\n * @param price - Price to format\n * @param currency - ISO 4217 currency code (default: \"USD\")\n * @param locale - Locale for formatting (default: \"en-US\")\n * @returns Formatted currency string\n *\n * @example\n * formatCurrency(50.6, \"USD\") // \"$50.60\"\n * formatCurrency(1234.5, \"EUR\", \"de-DE\") // \"1.234,50 €\"\n */\nexport function formatCurrency(\n price: number,\n currency: string = 'USD',\n locale: string = 'en-US'\n): string {\n try {\n return new Intl.NumberFormat(locale, {\n style: 'currency',\n currency,\n minimumFractionDigits: 2,\n maximumFractionDigits: 2,\n }).format(price);\n } catch (error) {\n // Fallback if Intl fails\n console.error('[formatCurrency] Error formatting:', error);\n return `$${price.toFixed(2)}`;\n }\n}\n\n/**\n * Calculate the effective discount rate from multiplicative cascading.\n * This shows the actual discount percentage after applying all defects.\n *\n * @param selectedDefects - Array of selected defects\n * @returns Effective discount percentage (0-100)\n *\n * @example\n * // Two 50% defects = 75% effective discount (not 100%)\n * // Because: 1 * 0.5 * 0.5 = 0.25 → 75% off\n * calculateEffectiveDiscount([\n * { id: 'a', percent: 50 },\n * { id: 'b', percent: 50 }\n * ]) // Returns 75\n */\nexport function calculateEffectiveDiscount(\n selectedDefects: DefectAdjustment[]\n): number {\n let multiplier = 1.0;\n\n for (const defect of selectedDefects) {\n const discountMultiplier = 1 - defect.percent / 100;\n multiplier *= discountMultiplier;\n }\n\n // Effective discount = 1 - final_multiplier\n const effectiveDiscount = (1 - multiplier) * 100;\n\n return Math.round(effectiveDiscount * 100) / 100; // Round to 2 decimals\n}\n","/**\n * React Hooks for Offer Calculator\n *\n * This module contains custom React hooks for managing calculator state.\n * The main hook (useOfferCalculator) handles all state management and\n * calculation logic for the calculator component.\n *\n * @module hooks\n */\n\n'use client';\n\nimport { useState, useMemo, useCallback } from 'react';\nimport type {\n CalculatorConfig,\n DefectAdjustment,\n ConditionTier,\n UseOfferCalculatorResult,\n} from './types';\nimport { calculateOffer } from './pricing';\n\n/**\n * Custom hook for managing calculator state and calculations.\n *\n * This hook provides:\n * - State management for selected defects and condition\n * - Automatic recalculation when selections change\n * - Memoized derived values (no redundant state)\n * - Type-safe handlers for user interactions\n *\n * @param config - Calculator configuration from CMS\n * @returns State, handlers, and calculation result\n *\n * @example\n * function MyCalculator({ config }) {\n * const {\n * selectedDefectIds,\n * toggleDefect,\n * calculationResult,\n * currentCondition\n * } = useOfferCalculator(config);\n *\n * return (\n * <div>\n * <p>Price: ${calculationResult.finalPrice}</p>\n * <button onClick={() => toggleDefect('check1')}>\n * Toggle Defect\n * </button>\n * </div>\n * );\n * }\n */\nexport function useOfferCalculator(\n config: CalculatorConfig\n): UseOfferCalculatorResult {\n // =========================================================================\n // STATE\n // =========================================================================\n\n // Set of selected defect IDs (using Set for O(1) lookups)\n const [selectedDefectIds, setSelectedDefectIds] = useState<Set<string>>(\n new Set()\n );\n\n // Currently selected condition tier ID\n // Default to first condition marked as default, or first in array\n const [selectedConditionId, setSelectedConditionId] = useState<string>(() => {\n const defaultCondition = config.conditions.find((c) => c.isDefault);\n return defaultCondition?.id || config.conditions[0]?.id || '';\n });\n\n // Whether defects section is visible (user toggle)\n const [hasDefects, setHasDefects] = useState<boolean>(false);\n\n // =========================================================================\n // DERIVED VALUES (computed, not stored)\n // =========================================================================\n\n /**\n * Array of currently selected defects (filtered from config).\n * Memoized to prevent recalculation on every render.\n */\n const selectedDefects = useMemo<DefectAdjustment[]>(() => {\n return config.defects.filter((defect) => selectedDefectIds.has(defect.id));\n }, [config.defects, selectedDefectIds]);\n\n /**\n * Current condition tier object.\n * Fallback to first condition if selected ID is invalid.\n */\n const currentCondition = useMemo<ConditionTier>(() => {\n const found = config.conditions.find((c) => c.id === selectedConditionId);\n if (found) return found;\n\n // Fallback to first condition\n const firstCondition = config.conditions[0];\n if (!firstCondition) {\n // Last resort: create a default condition if config is invalid\n return {\n id: 'default',\n label: 'Default',\n percent: 100,\n multiplier: 1.0,\n description: 'Default condition',\n isDefault: true,\n };\n }\n return firstCondition;\n }, [config.conditions, selectedConditionId]);\n\n /**\n * Current calculation result.\n * Recalculates whenever base price, condition, or defects change.\n */\n const calculationResult = useMemo(() => {\n return calculateOffer(\n config.basePrice,\n currentCondition.multiplier,\n selectedDefects,\n config.minimumOffer\n );\n }, [\n config.basePrice,\n config.minimumOffer,\n currentCondition.multiplier,\n selectedDefects,\n ]);\n\n // =========================================================================\n // HANDLERS\n // =========================================================================\n\n /**\n * Toggle a defect selection on/off.\n * Uses functional update to ensure correct state.\n */\n const toggleDefect = useCallback((defectId: string) => {\n setSelectedDefectIds((prev) => {\n const next = new Set(prev);\n if (next.has(defectId)) {\n next.delete(defectId);\n } else {\n next.add(defectId);\n }\n return next;\n });\n }, []);\n\n /**\n * Select a condition tier.\n * Resets defects when changing condition (matching original behavior).\n */\n const selectCondition = useCallback((conditionId: string) => {\n setSelectedConditionId(conditionId);\n // Reset defects when changing condition\n setSelectedDefectIds(new Set());\n setHasDefects(false);\n }, []);\n\n /**\n * Toggle defects section visibility.\n * Clears all selected defects when hiding.\n */\n const toggleHasDefects = useCallback(() => {\n setHasDefects((prev) => {\n const newValue = !prev;\n // If hiding defects, clear selections\n if (!newValue) {\n setSelectedDefectIds(new Set());\n }\n return newValue;\n });\n }, []);\n\n /**\n * Clear all selected defects.\n * Useful for \"Reset\" button functionality.\n */\n const clearDefects = useCallback(() => {\n setSelectedDefectIds(new Set());\n }, []);\n\n // =========================================================================\n // RETURN\n // =========================================================================\n\n return {\n // State\n selectedDefectIds,\n selectedConditionId,\n hasDefects,\n // Handlers\n toggleDefect,\n selectCondition,\n toggleHasDefects,\n clearDefects,\n // Derived values\n calculationResult,\n selectedDefects,\n currentCondition,\n };\n}\n\n/**\n * Hook for managing individual defect checkbox state.\n * This is a micro-hook that can be used within DefectCheckbox component.\n *\n * @param defectId - ID of the defect\n * @param isSelected - Whether this defect is currently selected\n * @param onToggle - Callback when checkbox is toggled\n * @returns Checkbox props and handlers\n *\n * @example\n * function DefectCheckbox({ defect, isSelected, onToggle }) {\n * const { checked, handleChange } = useDefectCheckbox(\n * defect.id,\n * isSelected,\n * onToggle\n * );\n *\n * return <input type=\"checkbox\" checked={checked} onChange={handleChange} />;\n * }\n */\nexport function useDefectCheckbox(\n defectId: string,\n isSelected: boolean,\n onToggle: (defectId: string) => void\n) {\n const handleChange = useCallback(() => {\n onToggle(defectId);\n }, [defectId, onToggle]);\n\n return {\n checked: isSelected,\n handleChange,\n };\n}\n","/**\n * ConditionTabs Component\n *\n * Tab navigation for selecting device condition tiers.\n * Implements accessible tab pattern with ARIA roles.\n */\n\n'use client';\n\nimport { useCallback } from 'react';\nimport type { ConditionTier } from '@/lib/calculator/types';\n\ninterface ConditionTabsProps {\n /** Available condition tiers from CMS */\n conditions: ConditionTier[];\n\n /** Currently selected condition ID */\n selectedConditionId: string;\n\n /** Callback when condition is selected */\n onSelectCondition: (conditionId: string) => void;\n\n /** Additional CSS classes */\n className?: string;\n}\n\n/**\n * Tab navigation for selecting device condition.\n *\n * Features:\n * - Accessible tab pattern (ARIA tablist/tab/tabpanel roles)\n * - Keyboard navigation (Arrow keys, Home, End)\n * - Visual active state\n * - Condition descriptions as tooltips\n *\n * @example\n * <ConditionTabs\n * conditions={config.conditions}\n * selectedConditionId={selectedConditionId}\n * onSelectCondition={selectCondition}\n * />\n */\nexport function ConditionTabs({\n conditions,\n selectedConditionId,\n onSelectCondition,\n className = '',\n}: ConditionTabsProps) {\n // Handle keyboard navigation\n const handleKeyDown = useCallback(\n (event: React.KeyboardEvent, currentIndex: number) => {\n let newIndex = currentIndex;\n\n switch (event.key) {\n case 'ArrowRight':\n case 'ArrowDown':\n event.preventDefault();\n newIndex = (currentIndex + 1) % conditions.length;\n break;\n case 'ArrowLeft':\n case 'ArrowUp':\n event.preventDefault();\n newIndex =\n currentIndex === 0 ? conditions.length - 1 : currentIndex - 1;\n break;\n case 'Home':\n event.preventDefault();\n newIndex = 0;\n break;\n case 'End':\n event.preventDefault();\n newIndex = conditions.length - 1;\n break;\n default:\n return;\n }\n\n const nextCondition = conditions[newIndex];\n if (nextCondition) {\n onSelectCondition(nextCondition.id);\n }\n },\n [conditions, onSelectCondition]\n );\n\n return (\n <div className={`condition-tabs ${className}`}>\n <div\n role=\"tablist\"\n aria-label=\"Device condition\"\n className=\"condition-tabs__list\"\n >\n {conditions.map((condition, index) => {\n const isSelected = condition.id === selectedConditionId;\n\n return (\n <button\n key={condition.id}\n role=\"tab\"\n aria-selected={isSelected}\n aria-controls={`condition-panel-${condition.id}`}\n id={`condition-tab-${condition.id}`}\n tabIndex={isSelected ? 0 : -1}\n onClick={() => onSelectCondition(condition.id)}\n onKeyDown={(e) => handleKeyDown(e, index)}\n className={`condition-tabs__tab ${\n isSelected ? 'condition-tabs__tab--active' : ''\n }`}\n title={condition.description}\n >\n <span className=\"condition-tabs__tab-label\">\n {condition.label}\n </span>\n <span className=\"condition-tabs__tab-multiplier\">\n {condition.percent}%\n </span>\n </button>\n );\n })}\n </div>\n\n {/* Tab panels (descriptions) */}\n {conditions.map((condition) => {\n const isSelected = condition.id === selectedConditionId;\n\n return (\n <div\n key={condition.id}\n role=\"tabpanel\"\n id={`condition-panel-${condition.id}`}\n aria-labelledby={`condition-tab-${condition.id}`}\n hidden={!isSelected}\n className=\"condition-tabs__panel\"\n >\n <p className=\"condition-tabs__description\">\n {condition.description}\n </p>\n </div>\n );\n })}\n </div>\n );\n}\n\n/**\n * Compact condition selector (dropdown instead of tabs).\n * Useful for mobile or when space is limited.\n *\n * @example\n * <CompactConditionSelector\n * conditions={config.conditions}\n * selectedConditionId={selectedConditionId}\n * onSelectCondition={selectCondition}\n * />\n */\nexport function CompactConditionSelector({\n conditions,\n selectedConditionId,\n onSelectCondition,\n className = '',\n}: ConditionTabsProps) {\n const handleChange = (event: React.ChangeEvent<HTMLSelectElement>) => {\n onSelectCondition(event.target.value);\n };\n\n const selectedCondition = conditions.find(\n (c) => c.id === selectedConditionId\n );\n\n return (\n <div className={`condition-selector ${className}`}>\n <label htmlFor=\"condition-select\" className=\"condition-selector__label\">\n Device Condition:\n </label>\n\n <select\n id=\"condition-select\"\n value={selectedConditionId}\n onChange={handleChange}\n className=\"condition-selector__select\"\n aria-describedby=\"condition-description\"\n >\n {conditions.map((condition) => (\n <option key={condition.id} value={condition.id}>\n {condition.label} ({condition.percent}%)\n </option>\n ))}\n </select>\n\n {selectedCondition && (\n <p\n id=\"condition-description\"\n className=\"condition-selector__description\"\n >\n {selectedCondition.description}\n </p>\n )}\n </div>\n );\n}\n","/**\n * DefectCheckbox Component\n *\n * Individual defect checkbox with label, tooltip, and accessibility support.\n */\n\n'use client';\n\nimport { useState } from 'react';\nimport type { DefectAdjustment } from '@/lib/calculator/types';\nimport { useDefectCheckbox } from '@/lib/calculator/hooks';\n\ninterface DefectCheckboxProps {\n /** Defect data from CMS */\n defect: DefectAdjustment;\n\n /** Whether this defect is currently selected */\n isSelected: boolean;\n\n /** Callback when checkbox is toggled */\n onToggle: (defectId: string) => void;\n\n /** Whether the checkbox is disabled */\n disabled?: boolean;\n\n /** Additional CSS classes */\n className?: string;\n}\n\n/**\n * Individual defect checkbox with tooltip support.\n *\n * Features:\n * - Accessible checkbox with label\n * - Optional tooltip on hover\n * - Keyboard navigation support\n * - ARIA attributes for screen readers\n *\n * @example\n * <DefectCheckbox\n * defect={defect}\n * isSelected={selectedDefectIds.has(defect.id)}\n * onToggle={toggleDefect}\n * />\n */\nexport function DefectCheckbox({\n defect,\n isSelected,\n onToggle,\n disabled = false,\n className = '',\n}: DefectCheckboxProps) {\n const { checked, handleChange } = useDefectCheckbox(\n defect.id,\n isSelected,\n onToggle\n );\n\n // Tooltip visibility state\n const [tooltipVisible, setTooltipVisible] = useState(false);\n\n // Generate unique IDs for accessibility\n const checkboxId = `defect-${defect.id}`;\n const tooltipId = defect.description\n ? `defect-tooltip-${defect.id}`\n : undefined;\n\n return (\n <div className={`defect-checkbox ${className}`}>\n <label\n htmlFor={checkboxId}\n className=\"defect-checkbox__label\"\n onMouseEnter={() => setTooltipVisible(true)}\n onMouseLeave={() => setTooltipVisible(false)}\n onFocus={() => setTooltipVisible(true)}\n onBlur={() => setTooltipVisible(false)}\n >\n <input\n type=\"checkbox\"\n id={checkboxId}\n checked={checked}\n onChange={handleChange}\n disabled={disabled}\n aria-describedby={tooltipId}\n className=\"defect-checkbox__input\"\n />\n\n <span className=\"defect-checkbox__text\">\n {defect.label}\n <span className=\"defect-checkbox__percent\">\n {' '}\n ({defect.percent}% off)\n </span>\n </span>\n\n {/* Info icon for tooltip indicator */}\n {defect.description && (\n <span className=\"defect-checkbox__info-icon\" aria-hidden=\"true\">\n ℹ️\n </span>\n )}\n </label>\n\n {/* Tooltip */}\n {defect.description && tooltipVisible && (\n <div\n id={tooltipId}\n role=\"tooltip\"\n className=\"defect-checkbox__tooltip\"\n aria-hidden={!tooltipVisible}\n >\n {defect.description}\n </div>\n )}\n </div>\n );\n}\n\n/**\n * List of defect checkboxes grouped by category.\n * Useful for organizing many defects.\n *\n * @example\n * <DefectCheckboxList\n * defects={config.defects}\n * selectedDefectIds={selectedDefectIds}\n * onToggle={toggleDefect}\n * groupByCategory={true}\n * />\n */\nexport function DefectCheckboxList({\n defects,\n selectedDefectIds,\n onToggle,\n disabled = false,\n groupByCategory = false,\n className = '',\n}: {\n defects: DefectAdjustment[];\n selectedDefectIds: Set<string>;\n onToggle: (defectId: string) => void;\n disabled?: boolean;\n groupByCategory?: boolean;\n className?: string;\n}) {\n if (!groupByCategory) {\n // Simple flat list\n return (\n <div className={`defect-checkbox-list ${className}`}>\n {defects.map((defect) => (\n <DefectCheckbox\n key={defect.id}\n defect={defect}\n isSelected={selectedDefectIds.has(defect.id)}\n onToggle={onToggle}\n disabled={disabled}\n />\n ))}\n </div>\n );\n }\n\n // Group by category\n const grouped = defects.reduce(\n (acc, defect) => {\n const category = defect.category || 'other';\n if (!acc[category]) {\n acc[category] = [];\n }\n acc[category].push(defect);\n return acc;\n },\n {} as Record<string, DefectAdjustment[]>\n );\n\n return (\n <div className={`defect-checkbox-list defect-checkbox-list--grouped ${className}`}>\n {Object.entries(grouped).map(([category, categoryDefects]) => (\n <div key={category} className=\"defect-checkbox-list__group\">\n <h4 className=\"defect-checkbox-list__group-title\">\n {category.charAt(0).toUpperCase() + category.slice(1)}\n </h4>\n {categoryDefects.map((defect) => (\n <DefectCheckbox\n key={defect.id}\n defect={defect}\n isSelected={selectedDefectIds.has(defect.id)}\n onToggle={onToggle}\n disabled={disabled}\n />\n ))}\n </div>\n ))}\n </div>\n );\n}\n","/**\n * PriceDisplay Component\n *\n * Displays the calculated offer price with optional breakdown details.\n * Shows warning if minimum price was enforced.\n */\n\n'use client';\n\nimport type { CalculationResult } from '@/lib/calculator/types';\nimport { formatCurrency } from '@/lib/calculator/pricing';\n\ninterface PriceDisplayProps {\n /** Calculation result from calculateOffer */\n result: CalculationResult;\n\n /** ISO 4217 currency code (e.g., \"USD\") */\n currency?: string;\n\n /** Locale for number formatting (e.g., \"en-US\") */\n locale?: string;\n\n /** Whether to show detailed breakdown */\n showBreakdown?: boolean;\n\n /** Additional CSS classes */\n className?: string;\n}\n\n/**\n * Display the calculated offer price.\n *\n * Features:\n * - Formatted currency display\n * - Optional detailed breakdown\n * - Warning when minimum price enforced\n * - Accessibility (aria-live for price updates)\n *\n * @example\n * <PriceDisplay\n * result={calculationResult}\n * currency=\"USD\"\n * showBreakdown={true}\n * />\n */\nexport function PriceDisplay({\n result,\n currency = 'USD',\n locale = 'en-US',\n showBreakdown = false,\n className = '',\n}: PriceDisplayProps) {\n const { finalPrice, breakdown } = result;\n\n // Format the final price\n const formattedPrice = formatCurrency(finalPrice, currency, locale);\n\n return (\n <div className={`price-display ${className}`}>\n {/* Main Price Display */}\n <div className=\"price-display__main\">\n <span className=\"price-display__label\">Your Offer:</span>\n <span\n className=\"price-display__value\"\n aria-live=\"polite\"\n aria-atomic=\"true\"\n >\n {formattedPrice}\n </span>\n </div>\n\n {/* Minimum Price Warning */}\n {breakdown.minimumEnforced && (\n <div\n className=\"price-display__warning\"\n role=\"alert\"\n aria-live=\"assertive\"\n >\n ⚠️ Minimum offer of {formatCurrency(finalPrice, currency, locale)}{' '}\n enforced\n </div>\n )}\n\n {/* Optional Breakdown */}\n {showBreakdown && (\n <div className=\"price-display__breakdown\">\n <h4>Calculation Breakdown</h4>\n\n <dl className=\"price-display__breakdown-list\">\n <dt>Base Price:</dt>\n <dd>{formatCurrency(breakdown.basePrice, currency, locale)}</dd>\n\n <dt>Condition Multiplier:</dt>\n <dd>{breakdown.conditionMultiplier.toFixed(2)}x</dd>\n\n <dt>Price After Condition:</dt>\n <dd>\n {formatCurrency(breakdown.priceAfterCondition, currency, locale)}\n </dd>\n\n {breakdown.appliedDefects.length > 0 && (\n <>\n <dt>Applied Defects:</dt>\n <dd>\n <ul>\n {breakdown.appliedDefects.map((defect) => (\n <li key={defect.id}>\n {defect.label} ({defect.percent}%)\n </li>\n ))}\n </ul>\n </dd>\n\n <dt>Total Discount (additive):</dt>\n <dd>{breakdown.totalDiscountPercent.toFixed(2)}%</dd>\n </>\n )}\n\n <dt>Price Before Minimum:</dt>\n <dd>\n {formatCurrency(breakdown.priceBeforeClamp, currency, locale)}\n </dd>\n\n <dt>Final Offer:</dt>\n <dd>\n <strong>{formattedPrice}</strong>\n </dd>\n </dl>\n </div>\n )}\n </div>\n );\n}\n\n/**\n * Compact price display variant (just the number).\n * Useful for inline display or mobile views.\n */\nexport function CompactPriceDisplay({\n result,\n currency = 'USD',\n locale = 'en-US',\n className = '',\n}: Omit<PriceDisplayProps, 'showBreakdown'>) {\n const formattedPrice = formatCurrency(result.finalPrice, currency, locale);\n\n return (\n <span\n className={`price-display--compact ${className}`}\n aria-live=\"polite\"\n aria-atomic=\"true\"\n >\n {formattedPrice}\n </span>\n );\n}\n","/**\n * Offer Calculator Styles (CSS Module)\n *\n * This stylesheet provides base styles for the calculator component.\n * All styles are scoped to the component via CSS Modules.\n *\n * Customization:\n * - Override these styles by providing a className prop\n * - Use CSS custom properties (variables) for theming\n * - Import and extend in your own stylesheets\n */\n\n/* ============================================================================\n CALCULATOR CONTAINER\n ========================================================================= */\n\n.calculator {\n max-width: 800px;\n margin: 0 auto;\n padding: 2rem;\n font-family: system-ui, -apple-system, sans-serif;\n}\n\n.calculator__header {\n margin-bottom: 2rem;\n text-align: center;\n}\n\n.calculator__title {\n font-size: 1.75rem;\n font-weight: 700;\n margin: 0 0 0.5rem 0;\n color: #1a1a1a;\n}\n\n.calculator__subtitle {\n font-size: 1rem;\n color: #666;\n margin: 0;\n}\n\n.calculator__section {\n margin-bottom: 2rem;\n padding: 1.5rem;\n background: #f9f9f9;\n border-radius: 8px;\n border: 1px solid #e0e0e0;\n}\n\n.calculator__sectionTitle {\n font-size: 1.25rem;\n font-weight: 600;\n margin: 0 0 1rem 0;\n color: #333;\n}\n\n.calculator__hint {\n font-size: 0.875rem;\n color: #666;\n margin: 0 0 1rem 0;\n font-style: italic;\n}\n\n/* ============================================================================\n DEFECTS TOGGLE (Radio Buttons)\n ========================================================================= */\n\n.calculator__defectsToggle {\n display: flex;\n gap: 1.5rem;\n}\n\n.calculator__radioLabel {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n font-size: 1rem;\n cursor: pointer;\n padding: 0.75rem 1.25rem;\n border: 2px solid #ddd;\n border-radius: 6px;\n transition: all 0.2s ease;\n}\n\n.calculator__radioLabel:has(input:checked) {\n border-color: #007bff;\n background: #e7f3ff;\n}\n\n.calculator__radioLabel:hover {\n border-color: #999;\n}\n\n.calculator__radioInput {\n width: 1.25rem;\n height: 1.25rem;\n cursor: pointer;\n}\n\n/* ============================================================================\n ERROR STATES\n ========================================================================= */\n\n.calculator__error {\n padding: 2rem;\n background: #fee;\n border: 1px solid #fcc;\n border-radius: 8px;\n text-align: center;\n}\n\n.calculator__error h2 {\n color: #c00;\n margin: 0 0 1rem 0;\n}\n\n.calculator__error p {\n color: #666;\n margin: 0 0 1rem 0;\n}\n\n.calculator__errorButton {\n padding: 0.75rem 1.5rem;\n background: #007bff;\n color: white;\n border: none;\n border-radius: 6px;\n font-size: 1rem;\n cursor: pointer;\n transition: background 0.2s ease;\n}\n\n.calculator__errorButton:hover {\n background: #0056b3;\n}\n\n.calculator__errorDetails {\n margin-top: 1rem;\n text-align: left;\n background: #f5f5f5;\n padding: 1rem;\n border-radius: 4px;\n font-size: 0.875rem;\n}\n\n.calculator__errorDetails pre {\n margin: 0.5rem 0 0 0;\n overflow-x: auto;\n}\n\n/* ============================================================================\n RESPONSIVE DESIGN\n ========================================================================= */\n\n@media (max-width: 640px) {\n .calculator {\n padding: 1rem;\n }\n\n .calculator__title {\n font-size: 1.5rem;\n }\n\n .calculator__section {\n padding: 1rem;\n }\n\n .calculator__defectsToggle {\n flex-direction: column;\n gap: 0.75rem;\n }\n}\n\n/* ============================================================================\n GLOBAL COMPONENT STYLES (Non-scoped)\n Note: These are fallback styles for sub-components\n ========================================================================= */\n\n/* Condition Tabs */\n:global(.condition-tabs__list) {\n display: flex;\n gap: 0.5rem;\n flex-wrap: wrap;\n margin-bottom: 1rem;\n}\n\n:global(.condition-tabs__tab) {\n flex: 1;\n min-width: 120px;\n padding: 1rem;\n background: white;\n border: 2px solid #ddd;\n border-radius: 6px;\n cursor: pointer;\n transition: all 0.2s ease;\n font-size: 1rem;\n text-align: center;\n}\n\n:global(.condition-tabs__tab:hover) {\n border-color: #999;\n background: #f5f5f5;\n}\n\n:global(.condition-tabs__tab--active) {\n border-color: #007bff;\n background: #e7f3ff;\n font-weight: 600;\n}\n\n:global(.condition-tabs__tab-label) {\n display: block;\n font-weight: 600;\n margin-bottom: 0.25rem;\n}\n\n:global(.condition-tabs__tab-multiplier) {\n display: block;\n font-size: 0.875rem;\n color: #666;\n}\n\n:global(.condition-tabs__panel) {\n padding: 1rem;\n background: #f0f8ff;\n border-radius: 4px;\n border-left: 4px solid #007bff;\n}\n\n:global(.condition-tabs__description) {\n margin: 0;\n color: #555;\n font-size: 0.9375rem;\n}\n\n/* Defect Checkboxes */\n:global(.defect-checkbox) {\n position: relative;\n margin-bottom: 0.75rem;\n}\n\n:global(.defect-checkbox__label) {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n padding: 0.75rem;\n background: white;\n border: 1px solid #ddd;\n border-radius: 4px;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n:global(.defect-checkbox__label:hover) {\n background: #f9f9f9;\n border-color: #999;\n}\n\n:global(.defect-checkbox__input) {\n width: 1.25rem;\n height: 1.25rem;\n cursor: pointer;\n}\n\n:global(.defect-checkbox__text) {\n flex: 1;\n font-size: 0.9375rem;\n}\n\n:global(.defect-checkbox__percent) {\n color: #d9534f;\n font-weight: 600;\n}\n\n:global(.defect-checkbox__info-icon) {\n font-size: 1rem;\n opacity: 0.6;\n}\n\n:global(.defect-checkbox__tooltip) {\n position: absolute;\n top: 100%;\n left: 0;\n right: 0;\n margin-top: 0.5rem;\n padding: 0.75rem;\n background: #333;\n color: white;\n border-radius: 4px;\n font-size: 0.875rem;\n z-index: 10;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);\n}\n\n/* Price Display */\n:global(.price-display) {\n text-align: center;\n}\n\n:global(.price-display__main) {\n padding: 2rem;\n background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\n color: white;\n border-radius: 8px;\n margin-bottom: 1rem;\n}\n\n:global(.price-display__label) {\n display: block;\n font-size: 1rem;\n text-transform: uppercase;\n letter-spacing: 0.05em;\n margin-bottom: 0.5rem;\n opacity: 0.9;\n}\n\n:global(.price-display__value) {\n display: block;\n font-size: 3rem;\n font-weight: 700;\n}\n\n:global(.price-display__warning) {\n padding: 0.75rem;\n background: #fff3cd;\n border: 1px solid #ffc107;\n border-radius: 4px;\n color: #856404;\n font-size: 0.875rem;\n margin-bottom: 1rem;\n}\n\n:global(.price-display__breakdown) {\n background: #f9f9f9;\n border: 1px solid #ddd;\n border-radius: 4px;\n padding: 1rem;\n text-align: left;\n}\n\n:global(.price-display__breakdown h4) {\n margin: 0 0 1rem 0;\n font-size: 1rem;\n color: #333;\n}\n\n:global(.price-display__breakdown-list) {\n display: grid;\n grid-template-columns: auto 1fr;\n gap: 0.5rem 1rem;\n font-size: 0.875rem;\n}\n\n:global(.price-display__breakdown-list dt) {\n font-weight: 600;\n color: #555;\n}\n\n:global(.price-display__breakdown-list dd) {\n margin: 0;\n color: #333;\n}\n\n:global(.price-display__breakdown-list ul) {\n margin: 0;\n padding-left: 1.25rem;\n}\n\n:global(.price-display__breakdown-list li) {\n margin-bottom: 0.25rem;\n}\n\n@media (max-width: 640px) {\n :global(.price-display__value) {\n font-size: 2rem;\n }\n\n :global(.condition-tabs__list) {\n flex-direction: column;\n }\n\n :global(.condition-tabs__tab) {\n min-width: 0;\n }\n}\n","/**\n * OfferCalculator - Main Calculator Component\n *\n * Reusable React component for device offer calculation.\n * Integrates all sub-components and manages state via useOfferCalculator hook.\n *\n * Features:\n * - CMS-driven configuration\n * - Multiplicative cascading discounts\n * - Order-independent calculations\n * - Minimum price enforcement ($1.00)\n * - Accessible UI with ARIA support\n * - Hidden form inputs for backend submission\n */\n\n'use client';\n\nimport type { CalculatorConfig } from '@/lib/calculator/types';\nimport { useOfferCalculator } from '@/lib/calculator/hooks';\nimport { ConditionTabs } from './ConditionTabs';\nimport { DefectCheckboxList } from './DefectCheckbox';\nimport { PriceDisplay } from './PriceDisplay';\nimport styles from './calculator.module.css';\n\ninterface OfferCalculatorProps {\n /** Calculator configuration from CMS */\n config: CalculatorConfig;\n\n /** Whether to show calculation breakdown */\n showBreakdown?: boolean;\n\n /** Additional CSS classes */\n className?: string;\n\n /** Name for hidden form inputs (for backend submission) */\n formFieldPrefix?: string;\n}\n\n/**\n * Main Offer Calculator Component.\n *\n * This is the primary component that should be used in your pages.\n * It handles all state management internally via the useOfferCalculator hook.\n *\n * @example\n * // In your page component:\n * import { OfferCalculator } from '@/components/calculator/OfferCalculator';\n *\n * export default function CalculatorPage({ config }) {\n * return <OfferCalculator config={config} />;\n * }\n */\nexport function OfferCalculator({\n config,\n showBreakdown = false,\n className = '',\n formFieldPrefix = '',\n}: OfferCalculatorProps) {\n // =========================================================================\n // STATE & HANDLERS (via hook)\n // =========================================================================\n\n const {\n selectedDefectIds,\n selectedConditionId,\n hasDefects,\n toggleDefect,\n selectCondition,\n toggleHasDefects,\n calculationResult,\n currentCondition,\n } = useOfferCalculator(config);\n\n // =========================================================================\n // RENDER\n // =========================================================================\n\n return (\n <div className={`${styles.calculator} ${className}`}>\n {/* Device Info Header */}\n <div className={styles.calculator__header}>\n <h2 className={styles.calculator__title}>\n Get an Offer for Your {config.device.model}\n </h2>\n <p className={styles.calculator__subtitle}>\n Select your device condition and any defects to see your offer.\n </p>\n </div>\n\n {/* Condition Selection */}\n <section className={styles.calculator__section}>\n <h3 className={styles.calculator__sectionTitle}>\n 1. Select Device Condition\n </h3>\n <ConditionTabs\n conditions={config.conditions}\n selectedConditionId={selectedConditionId}\n onSelectCondition={selectCondition}\n />\n </section>\n\n {/* Defects Toggle */}\n <section className={styles.calculator__section}>\n <h3 className={styles.calculator__sectionTitle}>\n 2. Does Your Device Have Any Defects?\n </h3>\n\n <div className={styles.calculator__defectsToggle}>\n <label className={styles.calculator__radioLabel}>\n <input\n type=\"radio\"\n name=\"has_defects\"\n value=\"no\"\n checked={!hasDefects}\n onChange={() => {\n if (hasDefects) toggleHasDefects();\n }}\n className={styles.calculator__radioInput}\n />\n <span>No defects</span>\n </label>\n\n <label className={styles.calculator__radioLabel}>\n <input\n type=\"radio\"\n name=\"has_defects\"\n value=\"yes\"\n checked={hasDefects}\n onChange={() => {\n if (!hasDefects) toggleHasDefects();\n }}\n className={styles.calculator__radioInput}\n />\n <span>Yes, has defects</span>\n </label>\n </div>\n </section>\n\n {/* Defects List (conditional) */}\n {hasDefects && config.defects.length > 0 && (\n <section\n className={styles.calculator__section}\n data-testid=\"defects-section\"\n >\n <h3 className={styles.calculator__sectionTitle}>\n 3. Select All Defects\n </h3>\n <p className={styles.calculator__hint}>\n Select all that apply. Order doesn't matter.\n </p>\n\n <DefectCheckboxList\n defects={config.defects}\n selectedDefectIds={selectedDefectIds}\n onToggle={toggleDefect}\n groupByCategory={false}\n />\n </section>\n )}\n\n {/* Price Display */}\n <section className={styles.calculator__section}>\n <PriceDisplay\n result={calculationResult}\n currency={config.currency}\n showBreakdown={showBreakdown}\n />\n </section>\n\n {/* Hidden Form Inputs for Backend Submission */}\n <HiddenFormInputs\n finalPrice={calculationResult.finalPrice}\n conditionId={currentCondition.id}\n selectedDefectIds={Array.from(selectedDefectIds)}\n deviceId={String(config.device.id)}\n fieldPrefix={formFieldPrefix}\n />\n </div>\n );\n}\n\n/**\n * Hidden form inputs for backend submission.\n * These inputs are used when the calculator is part of a form.\n *\n * @private\n */\nfunction HiddenFormInputs({\n finalPrice,\n conditionId,\n selectedDefectIds,\n deviceId,\n fieldPrefix = '',\n}: {\n finalPrice: number;\n conditionId: string;\n selectedDefectIds: string[];\n deviceId: string;\n fieldPrefix?: string;\n}) {\n const prefix = fieldPrefix ? `${fieldPrefix}_` : '';\n\n return (\n <>\n {/* Final calculated price */}\n <input\n type=\"hidden\"\n name={`${prefix}device_price`}\n value={finalPrice.toFixed(2)}\n />\n\n {/* Selected condition */}\n <input\n type=\"hidden\"\n name={`${prefix}gadget_cosmetic_condition`}\n value={conditionId}\n />\n\n {/* Selected defects (as JSON array string) */}\n <input\n type=\"hidden\"\n name={`${prefix}selected_defects`}\n value={JSON.stringify(selectedDefectIds)}\n />\n\n {/* Device ID for reference */}\n <input type=\"hidden\" name={`${prefix}device_id`} value={deviceId} />\n </>\n );\n}\n\n/**\n * Error boundary component for calculator.\n * Displays user-friendly error message if calculator fails.\n */\nexport function CalculatorErrorBoundary({\n error,\n reset,\n}: {\n error: Error;\n reset?: () => void;\n}) {\n return (\n <div className={styles.calculator__error}>\n <h2>Calculator Error</h2>\n <p>\n We're sorry, but the calculator encountered an error. Please try\n again or contact support.\n </p>\n {reset && (\n <button onClick={reset} className={styles.calculator__errorButton}>\n Try Again\n </button>\n )}\n {process.env.NODE_ENV === 'development' && (\n <details className={styles.calculator__errorDetails}>\n <summary>Error Details (dev only)</summary>\n <pre>{error.message}</pre>\n <pre>{error.stack}</pre>\n </details>\n )}\n </div>\n );\n}\n","/**\n * Config Validation and Normalization\n *\n * This module validates and normalizes calculator configuration from CMS.\n * Handles missing fields, invalid data types, and edge cases gracefully.\n *\n * @module validation\n */\n\nimport type {\n CalculatorConfig,\n DefectAdjustment,\n ConditionTier,\n DeviceInfo,\n ValidationError,\n} from './types';\n\n/**\n * Normalize raw CMS data into a valid CalculatorConfig.\n *\n * This function is defensive and handles various edge cases:\n * - Missing or null fields (uses defaults)\n * - String numbers (parses to floats)\n * - Invalid arrays (filters out bad items)\n * - Out-of-range percentages (clamps to 0-100)\n *\n * @param raw - Raw data from CMS (unknown shape)\n * @returns Normalized and validated config\n *\n * @example\n * const raw = {\n * basePrice: \"230\",\n * defects: [{ id: \"check1\", label: \"Test\", percent: \"60\" }],\n * // ... other fields\n * };\n * const config = normalizeConfig(raw);\n * // config.basePrice is now a number: 230\n */\nexport function normalizeConfig(raw: any): CalculatorConfig {\n // Parse and validate base price\n const basePrice = parseFloat(raw?.basePrice);\n const validBasePrice =\n !isNaN(basePrice) && isFinite(basePrice) && basePrice > 0\n ? basePrice\n : 1.0;\n\n // Default currency\n const currency =\n typeof raw?.currency === 'string' && raw.currency.length > 0\n ? raw.currency\n : 'USD';\n\n // Normalize defects array\n const defects = normalizeDefects(raw?.defects);\n\n // Normalize conditions array\n const conditions = normalizeConditions(raw?.conditions);\n\n // Normalize device info\n const device = normalizeDeviceInfo(raw?.device);\n\n // Parse and validate minimum offer\n const minimumOffer = parseFloat(raw?.minimumOffer);\n const validMinimumOffer =\n !isNaN(minimumOffer) && isFinite(minimumOffer) && minimumOffer > 0\n ? minimumOffer\n : 1.0;\n\n return {\n basePrice: validBasePrice,\n currency,\n defects,\n conditions,\n device,\n minimumOffer: validMinimumOffer,\n };\n}\n\n/**\n * Normalize defects array from CMS.\n * Filters out invalid items and normalizes percentages.\n *\n * @private\n */\nfunction normalizeDefects(raw: any): DefectAdjustment[] {\n if (!Array.isArray(raw)) {\n console.warn('[normalizeConfig] Defects is not an array:', raw);\n return [];\n }\n\n return raw\n .filter((item) => {\n // Must have id and label\n if (!item?.id || typeof item.label !== 'string') {\n console.warn('[normalizeConfig] Invalid defect (missing id/label):', item);\n return false;\n }\n return true;\n })\n .map((item) => {\n // Parse and clamp percent to 0-100\n const percent = parseFloat(item.percent);\n const validPercent =\n !isNaN(percent) && isFinite(percent)\n ? Math.max(0, Math.min(100, percent))\n : 0;\n\n const defect: DefectAdjustment = {\n id: String(item.id),\n label: String(item.label),\n percent: validPercent,\n };\n\n // Only include optional properties if they exist\n if (item.description) {\n defect.description = String(item.description);\n }\n if (item.category) {\n defect.category = String(item.category);\n }\n\n return defect;\n });\n}\n\n/**\n * Normalize conditions array from CMS.\n * Computes multiplier from percent value.\n *\n * IMPORTANT: CMS stores \"percent\" as whole numbers (75, 85, 100, 120).\n * This function computes \"multiplier\" = percent / 100\n *\n * @private\n */\nfunction normalizeConditions(raw: any): ConditionTier[] {\n if (!Array.isArray(raw)) {\n console.warn('[normalizeConfig] Conditions is not an array:', raw);\n return createDefaultConditions();\n }\n\n const normalized = raw\n .filter((item) => {\n // Must have id and label\n if (!item?.id || !item?.label) {\n console.warn('[normalizeConfig] Invalid condition (missing id/label):', item);\n return false;\n }\n return true;\n })\n .map((item) => {\n // Parse percent value (e.g., 75, 85, 100, 120)\n const percent = parseFloat(item.percent);\n const validPercent =\n !isNaN(percent) && isFinite(percent) && percent > 0 ? percent : 100;\n\n // Compute multiplier: percent / 100\n const multiplier = validPercent / 100;\n\n const condition: ConditionTier = {\n id: String(item.id),\n label: String(item.label),\n percent: validPercent,\n multiplier,\n description: item.description ? String(item.description) : '',\n };\n\n // Only include isDefault if it's explicitly true\n if (item.isDefault) {\n condition.isDefault = true;\n }\n\n return condition;\n });\n\n // If no conditions were valid, return defaults\n if (normalized.length === 0) {\n return createDefaultConditions();\n }\n\n return normalized;\n}\n\n/**\n * Create default condition tiers when CMS data is missing.\n *\n * @private\n */\nfunction createDefaultConditions(): ConditionTier[] {\n return [\n {\n id: 'flawless',\n label: 'Flawless',\n percent: 100,\n multiplier: 1.0,\n description: 'Like New, no visible signs of previous usage.',\n isDefault: true,\n },\n ];\n}\n\n/**\n * Normalize device info from CMS.\n *\n * @private\n */\nfunction normalizeDeviceInfo(raw: any): DeviceInfo {\n return {\n id: raw?.id !== undefined ? String(raw.id) : 'unknown',\n model: raw?.model ? String(raw.model) : 'Unknown Device',\n type: raw?.type ? String(raw.type) : 'device',\n };\n}\n\n/**\n * Validate a normalized config and return any errors/warnings.\n *\n * This is run AFTER normalization to check for business logic issues.\n *\n * @param config - Normalized config to validate\n * @returns Array of validation errors (empty if valid)\n *\n * @example\n * const config = normalizeConfig(rawData);\n * const errors = validateConfig(config);\n * if (errors.length > 0) {\n * console.error('Config validation failed:', errors);\n * }\n */\nexport function validateConfig(config: CalculatorConfig): ValidationError[] {\n const errors: ValidationError[] = [];\n\n // Check base price\n if (config.basePrice <= 0) {\n errors.push({\n field: 'basePrice',\n message: 'Base price must be positive',\n severity: 'error',\n });\n }\n\n // Check minimum offer\n if (config.minimumOffer <= 0) {\n errors.push({\n field: 'minimumOffer',\n message: 'Minimum offer must be positive',\n severity: 'error',\n });\n }\n\n // Warn if no defects configured\n if (config.defects.length === 0) {\n errors.push({\n field: 'defects',\n message: 'No defects configured',\n severity: 'warning',\n });\n }\n\n // Warn if no conditions configured\n if (config.conditions.length === 0) {\n errors.push({\n field: 'conditions',\n message: 'No conditions configured',\n severity: 'error',\n });\n }\n\n // Check for duplicate defect IDs\n const defectIds = new Set<string>();\n for (const defect of config.defects) {\n if (defectIds.has(defect.id)) {\n errors.push({\n field: 'defects',\n message: `Duplicate defect ID: ${defect.id}`,\n severity: 'error',\n });\n }\n defectIds.add(defect.id);\n }\n\n // Check for duplicate condition IDs\n const conditionIds = new Set<string>();\n for (const condition of config.conditions) {\n if (conditionIds.has(condition.id)) {\n errors.push({\n field: 'conditions',\n message: `Duplicate condition ID: ${condition.id}`,\n severity: 'error',\n });\n }\n conditionIds.add(condition.id);\n }\n\n // Check that at least one condition is marked as default\n const hasDefault = config.conditions.some((c) => c.isDefault);\n if (!hasDefault && config.conditions.length > 0) {\n errors.push({\n field: 'conditions',\n message: 'No condition marked as default',\n severity: 'warning',\n });\n }\n\n return errors;\n}\n\n/**\n * Check if validation errors contain any errors (vs warnings).\n *\n * @param errors - Validation errors array\n * @returns True if there are any errors (not just warnings)\n */\nexport function hasErrors(errors: ValidationError[]): boolean {\n return errors.some((e) => e.severity === 'error');\n}\n\n/**\n * Format validation errors for display.\n *\n * @param errors - Validation errors array\n * @returns Formatted error message string\n */\nexport function formatValidationErrors(errors: ValidationError[]): string {\n if (errors.length === 0) {\n return '';\n }\n\n return errors\n .map((error) => {\n const prefix = error.severity === 'error' ? '❌' : '⚠️';\n return `${prefix} ${error.field}: ${error.message}`;\n })\n .join('\\n');\n}\n","/**\n * CMS Data Fetcher for Calculator Configuration\n *\n * This module handles fetching calculator configuration from the CMS.\n * It includes caching, error handling, and data normalization.\n *\n * @module cms/fetchCalculatorConfig\n */\n\nimport type { CalculatorConfig } from '../calculator/types';\nimport {\n normalizeConfig,\n validateConfig,\n hasErrors,\n formatValidationErrors,\n} from '../calculator/validation';\n\n/**\n * Fetch calculator configuration from CMS.\n *\n * This function:\n * 1. Fetches data from CMS API endpoint\n * 2. Normalizes the data (handles missing/invalid fields)\n * 3. Validates the normalized config\n * 4. Throws if critical errors found\n * 5. Returns normalized config\n *\n * Uses Next.js fetch caching (ISR) with 1-hour revalidation.\n *\n * @param deviceId - Device ID to fetch config for\n * @returns Normalized calculator config\n * @throws Error if fetch fails or data is critically invalid\n *\n * @example\n * // In a Server Component:\n * const config = await fetchCalculatorConfig(\"7885\");\n */\nexport async function fetchCalculatorConfig(\n deviceId: string\n): Promise<CalculatorConfig> {\n // Build API URL\n // TODO: Replace with your actual CMS API endpoint\n const apiUrl = process.env.CALCULATOR_API_URL || '/api/calculator/config';\n const url = `${apiUrl}?deviceId=${encodeURIComponent(deviceId)}`;\n\n try {\n // Fetch with optional Next.js caching\n // The 'next' property is a Next.js extension to fetch\n const response = await fetch(url, {\n next: {\n revalidate: 3600, // Cache for 1 hour\n tags: [`calculator-config-${deviceId}`], // For on-demand revalidation\n },\n });\n\n // Handle HTTP errors\n if (!response.ok) {\n throw new Error(\n `Failed to fetch calculator config: ${response.status} ${response.statusText}`\n );\n }\n\n // Parse JSON\n const rawData = await response.json();\n\n // Normalize data (defensive parsing)\n const config = normalizeConfig(rawData);\n\n // Validate normalized data\n const validationErrors = validateConfig(config);\n\n // Log warnings (non-critical)\n const warnings = validationErrors.filter((e) => e.severity === 'warning');\n if (warnings.length > 0) {\n console.warn(\n '[fetchCalculatorConfig] Validation warnings:',\n formatValidationErrors(warnings)\n );\n }\n\n // Throw on critical errors\n if (hasErrors(validationErrors)) {\n const errorMessage = formatValidationErrors(\n validationErrors.filter((e) => e.severity === 'error')\n );\n throw new Error(\n `Calculator config validation failed:\\n${errorMessage}`\n );\n }\n\n return config;\n } catch (error) {\n // Log error for monitoring\n console.error('[fetchCalculatorConfig] Error fetching config:', error);\n\n // Re-throw with context\n throw new Error(\n `Failed to load calculator configuration for device ${deviceId}: ${\n error instanceof Error ? error.message : 'Unknown error'\n }`\n );\n }\n}\n\n/**\n * Create mock calculator config for development/testing.\n * This is useful when CMS is not available or for local development.\n *\n * @param deviceId - Device ID (used in mock data)\n * @returns Mock calculator config\n *\n * @example\n * // In development:\n * const config = getMockCalculatorConfig(\"7885\");\n */\nexport function getMockCalculatorConfig(deviceId: string): CalculatorConfig {\n return {\n basePrice: 230.0,\n currency: 'USD',\n defects: [\n {\n id: 'check1',\n label: \"Motherboard issues/Doesn't power on\",\n percent: 60,\n description:\n 'Select if device has defective MB, BIOS locked, or won\\'t boot. Major discount.',\n category: 'critical',\n },\n {\n id: 'check2',\n label: 'Cracked/broken screen',\n percent: 45,\n description:\n 'Select if screen has cracks, dead pixels, or display issues.',\n category: 'critical',\n },\n {\n id: 'check3',\n label: 'Hard drive missing/defective',\n percent: 15,\n description: 'Select if HDD/SSD is missing or not working.',\n category: 'hardware',\n },\n {\n id: 'check5',\n label: 'Charger/adapter missing',\n percent: 15,\n description: 'Select if power adapter is not included.',\n category: 'accessories',\n },\n {\n id: 'check6',\n label: 'Battery issues',\n percent: 15,\n description: 'Select if battery doesn\\'t hold charge or is swollen.',\n category: 'hardware',\n },\n {\n id: 'check7',\n label: 'Keyboard/touchpad issues',\n percent: 20,\n description: 'Select if keys are missing or input devices not working.',\n category: 'hardware',\n },\n {\n id: 'check11',\n label: 'CPU/processor issues',\n percent: 30,\n description: 'Select if CPU is defective or underperforming.',\n category: 'hardware',\n },\n {\n id: 'check13',\n label: 'RAM issues',\n percent: 15,\n description: 'Select if memory is defective or missing.',\n category: 'hardware',\n },\n {\n id: 'check16',\n label: 'Damaged housing/case',\n percent: 30,\n description: 'Select if case has major dents, cracks, or damage.',\n category: 'cosmetic',\n },\n {\n id: 'check20',\n label: 'Graphics card issues',\n percent: 45,\n description: 'Select if GPU is defective or has display artifacts.',\n category: 'hardware',\n },\n {\n id: 'check4',\n label: 'Optical drive missing/defective',\n percent: 15,\n description: 'Select if CD/DVD drive is missing or not working.',\n category: 'hardware',\n },\n {\n id: 'check9',\n label: 'Overheating issues',\n percent: 30,\n description: 'Select if device overheats or fan doesn\\'t work.',\n category: 'hardware',\n },\n {\n id: 'check12',\n label: 'BIOS password locked',\n percent: 70,\n description:\n 'Select if device has BIOS password and cannot be reset. Major discount.',\n category: 'critical',\n },\n ],\n conditions: [\n {\n id: 'flawless',\n label: 'Flawless',\n percent: 100,\n multiplier: 1.0,\n description: 'Like New, no visible signs of previous usage.',\n isDefault: true,\n },\n {\n id: 'good',\n label: 'Good',\n percent: 85,\n multiplier: 0.85,\n description:\n 'Light signs of use, minor scratches, fully functional. No dents.',\n },\n {\n id: 'fair',\n label: 'Fair',\n percent: 75,\n multiplier: 0.75,\n description:\n 'Moderate wear, scratches, scuffs. May have small dents. Fully functional.',\n },\n {\n id: 'poor',\n label: 'Poor',\n percent: 60,\n multiplier: 0.6,\n description:\n 'Heavy wear, significant damage. Dents, deep scratches. May have issues.',\n },\n ],\n device: {\n id: deviceId,\n model: 'Dell G15 5510 Intel Core i5 10th Gen',\n type: 'laptop',\n },\n minimumOffer: 1.0,\n };\n}\n\n/**\n * Revalidate calculator config cache for a specific device.\n * Use this when CMS data changes and you need to refresh.\n *\n * This requires Next.js App Router with `revalidateTag` support.\n *\n * @param deviceId - Device ID to revalidate\n *\n * @example\n * // In an API route or webhook:\n * await revalidateCalculatorConfig(\"7885\");\n */\nexport async function revalidateCalculatorConfig(\n deviceId: string\n): Promise<void> {\n try {\n // Use Next.js revalidateTag (requires App Router)\n // @ts-expect-error - next/cache is an optional peer dependency\n const { revalidateTag } = await import('next/cache');\n revalidateTag(`calculator-config-${deviceId}`);\n console.log(`[revalidateCalculatorConfig] Cache cleared for ${deviceId}`);\n } catch (error) {\n console.error('[revalidateCalculatorConfig] Error:', error);\n throw error;\n }\n}\n","/**\n * Main entry point for @your-org/offer-calculator\n *\n * This package exports React components, hooks, and utilities for building\n * CMS-driven device offer calculators with multiplicative cascading discounts.\n *\n * @packageDocumentation\n */\n\n// ============================================================================\n// MAIN COMPONENT\n// ============================================================================\n\nexport { OfferCalculator, CalculatorErrorBoundary } from './components/calculator/OfferCalculator';\n\n// ============================================================================\n// SUB-COMPONENTS (for custom implementations)\n// ============================================================================\n\nexport { ConditionTabs, CompactConditionSelector } from './components/calculator/ConditionTabs';\nexport { DefectCheckbox, DefectCheckboxList } from './components/calculator/DefectCheckbox';\nexport { PriceDisplay, CompactPriceDisplay } from './components/calculator/PriceDisplay';\n\n// ============================================================================\n// HOOKS\n// ============================================================================\n\nexport { useOfferCalculator, useDefectCheckbox } from './lib/calculator/hooks';\n\n// ============================================================================\n// CORE CALCULATION LOGIC (for server-side or custom use)\n// ============================================================================\n\nexport {\n calculateOffer,\n formatCurrency,\n calculateEffectiveDiscount,\n} from './lib/calculator/pricing';\n\n// ============================================================================\n// VALIDATION & NORMALIZATION\n// ============================================================================\n\nexport {\n normalizeConfig,\n validateConfig,\n hasErrors,\n formatValidationErrors,\n} from './lib/calculator/validation';\n\n// ============================================================================\n// CMS INTEGRATION (optional - can be replaced)\n// ============================================================================\n\nexport {\n fetchCalculatorConfig,\n getMockCalculatorConfig,\n revalidateCalculatorConfig,\n} from './lib/cms/fetchCalculatorConfig';\n\n// ============================================================================\n// TYPE EXPORTS\n// ============================================================================\n\nexport type {\n // Main types\n CalculatorConfig,\n DefectAdjustment,\n ConditionTier,\n DeviceInfo,\n\n // Calculation types\n CalculationResult,\n CalculationBreakdown,\n\n // State types\n CalculatorState,\n CalculatorHandlers,\n UseOfferCalculatorResult,\n\n // Validation types\n ValidationError,\n} from './lib/calculator/types';\n\n// ============================================================================\n// VERSION\n// ============================================================================\n\nexport const VERSION = '2.0.0';\n"]}
|