"use client"; import { useState, useEffect, useCallback } from "react"; import { createPortal } from "react-dom"; import { X, CheckCircle, Send, Phone as PhoneIcon, Instagram } from "lucide-react"; import { BRAND } from "@/lib/constants"; interface SignupModalProps { open: boolean; onClose: () => void; title?: string; subtitle?: string; /** API endpoint to POST to */ endpoint: string; /** Extra fields merged into the POST body (e.g. masterClassTitle, classId, eventId, groupInfo) */ extraBody?: Record; /** Custom success message */ successMessage?: string; /** Callback with API response data on success */ onSuccess?: (data: Record) => void; } export function SignupModal({ open, onClose, title = "Записаться", subtitle, endpoint, extraBody, successMessage, onSuccess, }: SignupModalProps) { const [name, setName] = useState(""); const [phone, setPhone] = useState("+375 "); const [instagram, setInstagram] = useState(""); const [telegram, setTelegram] = useState(""); const [submitting, setSubmitting] = useState(false); const [error, setError] = useState(""); const [success, setSuccess] = useState(false); const [successData, setSuccessData] = useState | null>(null); function handlePhoneChange(raw: string) { let digits = raw.replace(/\D/g, ""); if (!digits.startsWith("375")) { digits = "375" + digits.replace(/^375?/, ""); } digits = digits.slice(0, 12); let formatted = "+375"; const rest = digits.slice(3); if (rest.length > 0) formatted += " (" + rest.slice(0, 2); if (rest.length >= 2) formatted += ") "; if (rest.length > 2) formatted += rest.slice(2, 5); if (rest.length > 5) formatted += "-" + rest.slice(5, 7); if (rest.length > 7) formatted += "-" + rest.slice(7, 9); setPhone(formatted); } useEffect(() => { if (!open) return; function onKey(e: KeyboardEvent) { if (e.key === "Escape") onClose(); } document.addEventListener("keydown", onKey); return () => document.removeEventListener("keydown", onKey); }, [open, onClose]); useEffect(() => { if (open) document.body.style.overflow = "hidden"; else document.body.style.overflow = ""; return () => { document.body.style.overflow = ""; }; }, [open]); const handleSubmit = useCallback(async (e: React.FormEvent) => { e.preventDefault(); setError(""); const cleanPhone = phone.replace(/\D/g, ""); if (cleanPhone.length < 12) { setError("Введите корректный номер телефона"); return; } setSubmitting(true); try { const body: Record = { name: name.trim(), phone: cleanPhone, ...extraBody, }; if (instagram.trim()) body.instagram = `@${instagram.trim()}`; if (telegram.trim()) body.telegram = `@${telegram.trim()}`; const res = await fetch(endpoint, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(body), }); const data = await res.json(); if (!res.ok) { setError(data.error || "Ошибка при записи"); return; } setSuccess(true); setSuccessData(data); onSuccess?.(data); } catch { setError("network"); } finally { setSubmitting(false); } }, [name, phone, instagram, telegram, endpoint, extraBody, onSuccess]); const handleClose = useCallback(() => { onClose(); setTimeout(() => { setName(""); setPhone("+375 "); setInstagram(""); setTelegram(""); setError(""); setSuccess(false); setSuccessData(null); }, 300); }, [onClose]); function openInstagramDM() { const text = `Здравствуйте! Меня зовут ${name}. Хочу записаться${subtitle ? ` (${subtitle})` : ""}. Мой телефон: ${phone}`; window.open(`https://ig.me/m/blackheartdancehouse?text=${encodeURIComponent(text)}`, "_blank"); handleClose(); } if (!open) return null; return createPortal(
e.stopPropagation()} > {success ? (

{successMessage || "Вы записаны!"}

{subtitle &&

{subtitle}

} {successData?.totalBookings !== undefined && (

Вы записаны на {String(successData.totalBookings)} занятий.
Стоимость: {String(successData.pricePerClass)} BYN за занятие

)}
) : error === "network" ? ( /* Network error — fallback to Instagram DM */

Что-то пошло не так

Не удалось отправить заявку. Свяжитесь с нами через Instagram — мы запишем вас!

) : ( <>

{title}

{subtitle &&

{subtitle}

}
setName(e.target.value)} placeholder="Ваше имя" required className="w-full rounded-xl border border-white/[0.08] bg-white/[0.04] px-4 py-3 text-sm text-white placeholder-neutral-500 outline-none transition-colors focus:border-gold/40 focus:bg-white/[0.06]" />
handlePhoneChange(e.target.value)} placeholder="+375 (__) ___-__-__" required className="w-full rounded-xl border border-white/[0.08] bg-white/[0.04] pl-9 pr-4 py-3 text-sm text-white placeholder-neutral-500 outline-none transition-colors focus:border-gold/40 focus:bg-white/[0.06]" />
@ setInstagram(e.target.value.replace(/^@/, ""))} placeholder="Instagram" className="w-full rounded-xl border border-white/[0.08] bg-white/[0.04] pl-7 pr-3 py-3 text-sm text-white placeholder-neutral-500 outline-none transition-colors focus:border-gold/40 focus:bg-white/[0.06]" />
@ setTelegram(e.target.value.replace(/^@/, ""))} placeholder="Telegram" className="w-full rounded-xl border border-white/[0.08] bg-white/[0.04] pl-7 pr-3 py-3 text-sm text-white placeholder-neutral-500 outline-none transition-colors focus:border-gold/40 focus:bg-white/[0.06]" />
{error && error !== "network" && (

{error}

)}
)}
, document.body ); }