From 0f83799cff294541ae6c42096c8523105c54576c Mon Sep 17 00:00:00 2001 From: Flatlogic Bot Date: Wed, 4 Mar 2026 09:31:22 +0000 Subject: [PATCH] Edit app-9xzmfic2e4g1/src/components/planner/BudgetSelector.tsx via Editor --- .../src/components/planner/BudgetSelector.tsx | 106 ++++++++++++++++++ 1 file changed, 106 insertions(+) create mode 100644 app-9xzmfic2e4g1/src/components/planner/BudgetSelector.tsx diff --git a/app-9xzmfic2e4g1/src/components/planner/BudgetSelector.tsx b/app-9xzmfic2e4g1/src/components/planner/BudgetSelector.tsx new file mode 100644 index 0000000..8d09834 --- /dev/null +++ b/app-9xzmfic2e4g1/src/components/planner/BudgetSelector.tsx @@ -0,0 +1,106 @@ +import { memo } from 'react'; +import { BUDGET_OPTIONS } from '@/constants/planner'; +import { cn } from '@/lib/utils'; +import { motion } from 'framer-motion'; + +interface BudgetSelectorProps { + selectedId: string; + onSelect: (id: string) => void; +} + +export const BudgetSelector = memo(({ selectedId, onSelect }: BudgetSelectorProps) => { + const selectedIndex = BUDGET_OPTIONS.findIndex(o => o.id === selectedId); + + return ( +
+ {/* Visual tier bar */} +
+ {BUDGET_OPTIONS.map((option, i) => ( + + ))} +
+ +
+ {BUDGET_OPTIONS.map((option, index) => { + const Icon = option.icon; + const isSelected = selectedId === option.id; + + return ( + onSelect(option.id)} + className={cn( + 'relative group flex items-center gap-4 px-5 py-4 rounded-2xl border-2 text-left transition-all duration-200 w-full overflow-hidden', + isSelected + ? `${option.activeBorder} ${option.activeBg} shadow-md` + : 'border-gray-100 bg-gray-50/60 hover:border-gray-200 hover:bg-white hover:shadow-sm' + )} + > + {/* Tier dots */} +
+ {Array.from({ length: 4 }).map((_, i) => ( +
+ ))} +
+ + {/* Icon */} +
+ +
+ + {/* Text */} +
+

+ {option.label} +

+

+ {option.description} +

+
+ + {/* Price range */} +
+ {option.range} +
+ + ); + })} +
+
+ ); +}); + +BudgetSelector.displayName = 'BudgetSelector'; \ No newline at end of file