import { useRef, useEffect, useState } from "react"; import { Plus, X, Upload, Loader2, Link, ImageIcon, Calendar, AlertCircle, MapPin } from "lucide-react"; import { adminFetch } from "@/lib/csrf"; import type { RichListItem, VictoryItem } from "@/types/content"; interface InputFieldProps { label: string; value: string; onChange: (value: string) => void; placeholder?: string; 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, onChange, placeholder, type = "text", }: InputFieldProps) { return (
onChange(e.target.value)} placeholder={placeholder} className={inputCls} />
); } export function ParticipantLimits({ min, max, onMinChange, onMaxChange, }: { min: number; max: number; onMinChange: (v: number) => void; onMaxChange: (v: number) => void; }) { const [minStr, setMinStr] = useState(String(min)); const [maxStr, setMaxStr] = useState(String(max)); const minLocal = parseInt(minStr) || 0; const maxLocal = parseInt(maxStr) || 0; const minEmpty = minStr === ""; const maxEmpty = maxStr === ""; const maxError = (maxLocal > 0 && minLocal > 0 && maxLocal < minLocal) || minEmpty || maxEmpty; function handleMin(raw: string) { setMinStr(raw); if (raw === "") return; const v = parseInt(raw) || 0; const curMax = parseInt(maxStr) || 0; if (curMax > 0 && v > curMax) return; onMinChange(v); } function handleMax(raw: string) { setMaxStr(raw); if (raw === "") return; const v = parseInt(raw) || 0; const curMin = parseInt(minStr) || 0; if (v > 0 && v < curMin) return; onMaxChange(v); } const errorMsg = minEmpty || maxEmpty ? "Поле не может быть пустым" : maxLocal > 0 && minLocal > maxLocal ? "Макс. не может быть меньше мин." : null; return (
handleMin(e.target.value)} className={`${inputCls} ${minEmpty ? "!border-red-500/50" : ""}`} />

{minEmpty ? "Поле не может быть пустым" : "Если записей меньше — занятие можно отменить"}

handleMax(e.target.value)} className={`${inputCls} ${maxEmpty || (maxLocal > 0 && minLocal > maxLocal) ? "!border-red-500/50" : ""}`} />

{maxEmpty ? "Поле не может быть пустым" : maxLocal > 0 && minLocal > maxLocal ? "Макс. не может быть меньше мин." : "0 = без лимита. При заполнении — лист ожидания"}

); } interface TextareaFieldProps { label: string; value: string; onChange: (value: string) => void; placeholder?: string; rows?: number; } export function TextareaField({ label, value, onChange, placeholder, rows = 3, }: TextareaFieldProps) { const ref = useRef(null); useEffect(() => { const el = ref.current; if (!el) return; el.style.height = "auto"; el.style.height = el.scrollHeight + "px"; }, [value]); useEffect(() => { function onResize() { const el = ref.current; if (!el) return; el.style.height = "auto"; el.style.height = el.scrollHeight + "px"; } window.addEventListener("resize", onResize); return () => window.removeEventListener("resize", onResize); }, []); return (