w-funnel/src/components/admin/builder/AgeSelector.tsx
dev.daminik00 b57e99e472 merge
2025-09-28 04:41:13 +02:00

242 lines
9.5 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"use client";
import { useState } from "react";
import { Button } from "@/components/ui/button";
import { TextInput } from "@/components/ui/TextInput/TextInput";
import { AGE_GROUPS, GENERATION_GROUPS, parseAgeRange } from "@/lib/age-utils";
interface AgeSelectorProps {
selectedValues: string[];
onToggleValue: (value: string) => void;
onAddCustomValue: (value: string) => void;
}
export function AgeSelector({ selectedValues, onToggleValue, onAddCustomValue }: AgeSelectorProps) {
const [customValue, setCustomValue] = useState("");
const handleAddCustom = () => {
if (customValue.trim()) {
onAddCustomValue(customValue.trim());
setCustomValue("");
}
};
const isValueSelected = (value: string) => selectedValues.includes(value);
return (
<div className="space-y-4">
{/* 🎂 ВОЗРАСТНЫЕ ГРУППЫ */}
<div className="space-y-3">
<h4 className="text-sm font-medium text-foreground">🎂 Возрастные группы</h4>
<div className="grid grid-cols-2 gap-2">
{AGE_GROUPS.map((group) => {
const isSelected = isValueSelected(group.id);
return (
<button
key={group.id}
onClick={() => onToggleValue(group.id)}
className={`
relative group p-3 rounded-lg border-2 transition-all duration-200
hover:shadow-md text-left
${isSelected
? "border-primary bg-primary/10 shadow-md"
: "border-border hover:border-primary/50"
}
`}
title={group.description}
>
<div className="flex items-center gap-2">
{/* Возрастной диапазон */}
<span className="text-lg">🎂</span>
{/* Информация */}
<div className="flex-1 min-w-0">
<div className={`font-medium text-sm ${
isSelected ? "text-primary" : "text-foreground"
}`}>
{group.name}
</div>
<div className="text-xs text-muted-foreground truncate">
{group.description}
</div>
</div>
{/* Индикатор выбранного */}
{isSelected && (
<div className="w-4 h-4 bg-primary rounded-full flex items-center justify-center flex-shrink-0">
<span className="text-[10px] text-white"></span>
</div>
)}
</div>
</button>
);
})}
</div>
</div>
{/* 🚀 ПОКОЛЕНИЯ */}
<div className="space-y-3">
<h4 className="text-sm font-medium text-foreground">🚀 Поколения</h4>
<div className="grid grid-cols-1 gap-2">
{GENERATION_GROUPS.map((generation) => {
const isSelected = isValueSelected(generation.id);
return (
<button
key={generation.id}
onClick={() => onToggleValue(generation.id)}
className={`
relative group p-3 rounded-lg border-2 transition-all duration-200
hover:shadow-md text-left
${isSelected
? "border-primary bg-primary/10 shadow-md"
: "border-border hover:border-primary/50"
}
`}
title={`Родились ${generation.minYear}-${generation.maxYear}`}
>
<div className="flex items-center gap-2">
{/* Иконка поколения */}
<span className="text-lg">
{generation.id === 'gen-z' ? '📱' :
generation.id === 'millennials' ? '💻' :
generation.id === 'gen-x' ? '📺' :
generation.id === 'boomers' ? '📻' : '📰'}
</span>
{/* Информация */}
<div className="flex-1 min-w-0">
<div className={`font-medium text-sm ${
isSelected ? "text-primary" : "text-foreground"
}`}>
{generation.name}
</div>
<div className="text-xs text-muted-foreground">
{generation.minYear}-{generation.maxYear} {generation.description}
</div>
</div>
{/* Индикатор выбранного */}
{isSelected && (
<div className="w-4 h-4 bg-primary rounded-full flex items-center justify-center flex-shrink-0">
<span className="text-[10px] text-white"></span>
</div>
)}
</div>
</button>
);
})}
</div>
</div>
{/* 🎯 ДОБАВЛЕНИЕ КАСТОМНЫХ ЗНАЧЕНИЙ */}
<div className="space-y-2">
<label className="block text-sm font-medium text-foreground">
Или добавить точный возраст/диапазон:
</label>
<div className="flex gap-2">
<TextInput
placeholder="25, 18-21, 30-35, 60+ и т.д."
value={customValue}
onChange={(e) => setCustomValue(e.target.value)}
onKeyDown={(e) => {
if (e.key === "Enter") {
e.preventDefault();
handleAddCustom();
}
}}
/>
<Button
onClick={handleAddCustom}
disabled={!customValue.trim()}
className="text-sm px-3 py-1"
>
Добавить
</Button>
</div>
{/* Подсказки по форматам */}
<div className="text-xs text-muted-foreground">
<strong>Примеры:</strong> 25 (точный возраст), 18-21 (диапазон), 60+ (от 60 лет), age-25 (альтернативный формат)
</div>
</div>
{/* 📋 ВЫБРАННЫЕ ЗНАЧЕНИЯ */}
{selectedValues.length > 0 && (
<div className="space-y-2">
<label className="block text-sm font-medium text-foreground">
Выбранные возрастные условия:
</label>
<div className="flex flex-wrap gap-1">
{selectedValues.map((value) => {
// Ищем в возрастных группах
const ageGroup = AGE_GROUPS.find(group => group.id === value);
if (ageGroup) {
return (
<span
key={value}
className="inline-flex items-center gap-1 px-2 py-1 text-xs bg-primary/10 text-primary rounded-full"
>
🎂 {ageGroup.name}
<button
onClick={() => onToggleValue(value)}
className="ml-1 hover:text-red-500 transition-colors"
title="Удалить"
>
×
</button>
</span>
);
}
// Ищем в поколениях
const generation = GENERATION_GROUPS.find(gen => gen.id === value);
if (generation) {
return (
<span
key={value}
className="inline-flex items-center gap-1 px-2 py-1 text-xs bg-blue-100 text-blue-700 rounded-full"
>
🚀 {generation.name}
<button
onClick={() => onToggleValue(value)}
className="ml-1 hover:text-red-500 transition-colors"
title="Удалить"
>
×
</button>
</span>
);
}
// Кастомное значение
const range = parseAgeRange(value);
return (
<span
key={value}
className="inline-flex items-center gap-1 px-2 py-1 text-xs bg-green-100 text-green-700 rounded-full"
>
🎯 {range ? `${range.min}-${range.max === 120 ? '+' : range.max}` : value}
<button
onClick={() => onToggleValue(value)}
className="ml-1 hover:text-red-500 transition-colors"
title="Удалить"
>
×
</button>
</span>
);
})}
</div>
</div>
)}
{/* 💡 ПОДСКАЗКА */}
<div className="text-xs text-muted-foreground bg-muted/30 rounded-lg p-3">
<strong>💡 Как это работает:</strong> Система автоматически рассчитывает возраст из
даты рождения пользователя. Выберите возрастные группы или поколения, при которых
должен показываться этот вариант экрана. Можно комбинировать разные условия.
</div>
</div>
);
}