From 0c8c45dcd933d6907ee491186b7af2fea7ccff5e Mon Sep 17 00:00:00 2001 From: "diana.dolgolyova" Date: Tue, 10 Mar 2026 20:16:21 +0300 Subject: [PATCH] feat: booking modal with form + Instagram DM + phone link Co-Authored-By: Claude Opus 4.6 --- src/components/sections/Hero.tsx | 7 +- src/components/ui/BookingModal.tsx | 175 +++++++++++++++++++++++++++++ 2 files changed, 181 insertions(+), 1 deletion(-) create mode 100644 src/components/ui/BookingModal.tsx diff --git a/src/components/sections/Hero.tsx b/src/components/sections/Hero.tsx index e879f53..9cc286c 100644 --- a/src/components/sections/Hero.tsx +++ b/src/components/sections/Hero.tsx @@ -1,13 +1,16 @@ "use client"; +import { useState } from "react"; import { siteContent } from "@/data/content"; import { Button } from "@/components/ui/Button"; import { FloatingHearts } from "@/components/ui/FloatingHearts"; import { HeroLogo } from "@/components/ui/HeroLogo"; +import { BookingModal } from "@/components/ui/BookingModal"; import { ChevronDown } from "lucide-react"; export function Hero() { const { hero } = siteContent; + const [bookingOpen, setBookingOpen] = useState(false); return (
@@ -63,10 +66,12 @@ export function Hero() {

-
+ + setBookingOpen(false)} /> {/* Scroll indicator */} diff --git a/src/components/ui/BookingModal.tsx b/src/components/ui/BookingModal.tsx new file mode 100644 index 0000000..eab946e --- /dev/null +++ b/src/components/ui/BookingModal.tsx @@ -0,0 +1,175 @@ +"use client"; + +import { useState, useEffect, useCallback } from "react"; +import { X, Instagram, Send, CheckCircle, Phone } from "lucide-react"; +import { siteContent } from "@/data/content"; + +interface BookingModalProps { + open: boolean; + onClose: () => void; +} + +export function BookingModal({ open, onClose }: BookingModalProps) { + const { contact } = siteContent; + const [name, setName] = useState(""); + const [phone, setPhone] = useState(""); + const [submitted, setSubmitted] = useState(false); + + // Close on Escape + useEffect(() => { + if (!open) return; + function onKey(e: KeyboardEvent) { + if (e.key === "Escape") onClose(); + } + document.addEventListener("keydown", onKey); + return () => document.removeEventListener("keydown", onKey); + }, [open, onClose]); + + // Lock body scroll + useEffect(() => { + if (open) { + document.body.style.overflow = "hidden"; + } else { + document.body.style.overflow = ""; + } + return () => { + document.body.style.overflow = ""; + }; + }, [open]); + + const handleSubmit = useCallback( + (e: React.FormEvent) => { + e.preventDefault(); + // Build Instagram DM message with pre-filled text + const message = `Здравствуйте! Меня зовут ${name}, хочу записаться на занятие. Мой телефон: ${phone}`; + const instagramUrl = `https://ig.me/m/blackheartdancehouse?text=${encodeURIComponent(message)}`; + window.open(instagramUrl, "_blank"); + setSubmitted(true); + }, + [name, phone] + ); + + const handleClose = useCallback(() => { + onClose(); + // Reset after animation + setTimeout(() => { + setName(""); + setPhone(""); + setSubmitted(false); + }, 300); + }, [onClose]); + + if (!open) return null; + + return ( +
+ {/* Backdrop */} +
+ + {/* Modal */} +
e.stopPropagation()} + > + {/* Close button */} + + + {submitted ? ( + /* Success state */ +
+
+ +
+

Отлично!

+

+ Сообщение отправлено в Instagram. Мы свяжемся с вами в ближайшее время! +

+ +
+ ) : ( + <> + {/* Header */} +
+

Записаться

+

+ Оставьте данные и мы свяжемся с вами, или напишите нам напрямую +

+
+ + {/* Form */} +
+
+ 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-[#c9a96e]/40 focus:bg-white/[0.06]" + /> +
+
+ setPhone(e.target.value)} + placeholder="+375 (__) ___-__-__" + 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-[#c9a96e]/40 focus:bg-white/[0.06]" + /> +
+ + +
+ + {/* Divider */} +
+ + или напрямую + +
+ + {/* Direct links */} + + + )} +
+
+ ); +}