feat: min/max participants — shared ParticipantLimits component

- New ParticipantLimits component in FormField.tsx (reusable)
- Used in both Open Day settings and MC editor — identical layout
- Open Day: event-level min/max (DB migration 15)
- MC: per-event min/max (JSON fields)
- Public: waiting list when full, spots counter, amber success modal
This commit is contained in:
2026-03-24 22:11:10 +03:00
parent 4acc88c1ab
commit d08905ee93
13 changed files with 484 additions and 50 deletions

View File

@@ -11,6 +11,8 @@ interface InputFieldProps {
type?: "text" | "url" | "tel";
}
const inputCls = "w-full rounded-lg border border-white/10 bg-neutral-800 px-4 py-2.5 text-white placeholder-neutral-500 outline-none focus:border-gold transition-colors";
export function InputField({
label,
value,
@@ -26,12 +28,39 @@ export function InputField({
value={value}
onChange={(e) => onChange(e.target.value)}
placeholder={placeholder}
className="w-full rounded-lg border border-white/10 bg-neutral-800 px-4 py-2.5 text-white placeholder-neutral-500 outline-none focus:border-gold transition-colors"
className={inputCls}
/>
</div>
);
}
export function ParticipantLimits({
min,
max,
onMinChange,
onMaxChange,
}: {
min: number;
max: number;
onMinChange: (v: number) => void;
onMaxChange: (v: number) => void;
}) {
return (
<div className="grid grid-cols-2 gap-3">
<div>
<label className="block text-sm text-neutral-400 mb-1.5">Мин. участников</label>
<input type="number" min={0} value={min} onChange={(e) => onMinChange(parseInt(e.target.value) || 0)} className={inputCls} />
<p className="text-[10px] text-neutral-600 mt-1">Если записей меньше занятие можно отменить</p>
</div>
<div>
<label className="block text-sm text-neutral-400 mb-1.5">Макс. участников</label>
<input type="number" min={0} value={max} onChange={(e) => onMaxChange(parseInt(e.target.value) || 0)} className={inputCls} />
<p className="text-[10px] text-neutral-600 mt-1">0 = без лимита. При заполнении лист ожидания</p>
</div>
</div>
);
}
interface TextareaFieldProps {
label: string;
value: string;