Files
glass/src/components/LeadForm.jsx
T
2026-05-07 20:33:01 +03:00

247 lines
12 KiB
React

import React, { useState } from 'react';
import { motion } from 'framer-motion';
import { Send, ShieldCheck } from 'lucide-react';
import { supabase } from '../lib/supabase';
const LeadForm = () => {
const [formData, setFormData] = useState({
name: '',
phone: '',
objectType: ''
});
const handleChange = (e) => {
setFormData({ ...formData, [e.target.name]: e.target.value });
};
const [isSubmitting, setIsSubmitting] = useState(false);
const handleSubmit = async (e) => {
e.preventDefault();
setIsSubmitting(true);
const botToken = import.meta.env.VITE_TG_BOT_TOKEN;
const chatId = import.meta.env.VITE_TG_CHAT_ID;
if (!botToken || !chatId) {
console.warn("Telegram bot token or chat ID is missing.");
alert("ВНИМАНИЕ: Не настроена интеграция с Telegram (отсутствуют ключи в .env). Заявка показана в консоли.");
console.log("Данные заявки:", formData);
setIsSubmitting(false);
return;
}
const text = `🚨 Новая заявка на замер и расчет!\n\n👤 Имя/Организация: ${formData.name}\n📞 Телефон: ${formData.phone}\n🏢 Тип объекта: ${formData.objectType}`;
try {
const response = await fetch(`https://api.telegram.org/bot${botToken}/sendMessage`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
chat_id: chatId,
text: text,
})
});
if (response.ok) {
// Write to Supabase (non-blocking — Telegram already succeeded)
try {
await supabase.from('orders').insert({
name: formData.name,
phone: formData.phone,
object_type: formData.objectType,
status: 'новая',
source: 'form',
});
} catch (dbErr) {
console.error('Supabase insert failed:', dbErr);
}
alert("Заявка успешно отправлена! Наши специалисты свяжутся с вами в ближайшее время для согласования замера.");
setFormData({ name: '', phone: '', objectType: '' });
} else {
alert("Произошла ошибка при отправке заявки. Пожалуйста, попробуйте позже или позвоните нам напрямую.");
}
} catch (error) {
console.error("Ошибка при отправке в Telegram:", error);
alert("Ошибка сети. Проверьте подключение к интернету и попробуйте снова.");
} finally {
setIsSubmitting(false);
}
};
return (
<section id="contact" style={{
position: 'relative',
background: 'linear-gradient(135deg, var(--bg-light) 0%, rgba(14, 165, 233, 0.05) 100%)',
padding: '120px 0'
}}>
{/* Decorative Light Elements */}
<div style={{
position: 'absolute', top: 0, left: 0, width: '100%', height: '100%',
backgroundImage: 'radial-gradient(circle at 15% 50%, rgba(245, 158, 11, 0.08), transparent 25%), radial-gradient(circle at 85% 30%, rgba(14, 165, 233, 0.08), transparent 25%)',
pointerEvents: 'none'
}} />
<div className="container" style={{ position: 'relative', zIndex: 1 }}>
<div style={{ display: 'flex', flexWrap: 'wrap', gap: '60px', justifyContent: 'center' }}>
<div style={{ flex: '1 1 400px', maxWidth: '550px' }}>
<motion.div
initial={{ opacity: 0, y: 30 }}
whileInView={{ opacity: 1, y: 0 }}
transition={{ duration: 0.6, type: "spring" }}
viewport={{ once: true }}
>
<h2 style={{ fontSize: '3.5rem', marginBottom: '25px', color: 'var(--text-main)' }}>
ЗАЯВКА НА <span className="text-accent-blue">ЗАМЕР</span>
</h2>
<p style={{ color: 'var(--text-muted)', fontSize: '1.25rem', marginBottom: '45px', lineHeight: '1.6' }}>
Оставьте заявку на бесплатный выезд инженера для замера и расчета предварительной стоимости бронирования ваших окон.
</p>
<ul style={{ listStyle: 'none', padding: 0, display: 'flex', flexDirection: 'column', gap: '25px' }}>
<motion.li whileHover={{ x: 10 }} style={{ display: 'flex', gap: '20px', alignItems: 'center' }}>
<div style={{ background: 'rgba(14, 165, 233, 0.1)', padding: '12px', borderRadius: '50%' }}>
<ShieldCheck className="text-accent-blue" size={24} />
</div>
<span style={{ fontSize: '1.2rem', fontWeight: 600, color: 'var(--text-main)' }}>Анализ векторов угроз</span>
</motion.li>
<motion.li whileHover={{ x: 10 }} style={{ display: 'flex', gap: '20px', alignItems: 'center' }}>
<div style={{ background: 'rgba(14, 165, 233, 0.1)', padding: '12px', borderRadius: '50%' }}>
<ShieldCheck className="text-accent-blue" size={24} />
</div>
<span style={{ fontSize: '1.2rem', fontWeight: 600, color: 'var(--text-main)' }}>Расчет необходимых материалов</span>
</motion.li>
<motion.li whileHover={{ x: 10 }} style={{ display: 'flex', gap: '20px', alignItems: 'center' }}>
<div style={{ background: 'rgba(14, 165, 233, 0.1)', padding: '12px', borderRadius: '50%' }}>
<ShieldCheck className="text-accent-blue" size={24} />
</div>
<span style={{ fontSize: '1.2rem', fontWeight: 600, color: 'var(--text-main)' }}>Планирование логистики монтажа</span>
</motion.li>
</ul>
</motion.div>
</div>
<div style={{ flex: '1 1 400px', maxWidth: '500px' }}>
<motion.div
initial={{ opacity: 0, y: 30 }}
whileInView={{ opacity: 1, y: 0 }}
transition={{ duration: 0.6, delay: 0.2, type: "spring" }}
viewport={{ once: true }}
className="glass-panel"
style={{ padding: '45px', border: '1px solid var(--border-light)', boxShadow: '0 25px 50px rgba(15, 23, 42, 0.05)' }}
>
<form onSubmit={handleSubmit} style={{ display: 'flex', flexDirection: 'column', gap: '25px' }}>
<div>
<label style={{ display: 'block', marginBottom: '10px', fontSize: '0.95rem', fontWeight: 700, color: 'var(--text-muted)', textTransform: 'uppercase' }}>ФИО / Название организации</label>
<input
type="text"
name="name"
value={formData.name}
onChange={handleChange}
required
style={{
width: '100%', padding: '16px',
background: 'var(--bg-lighter)',
border: '2px solid var(--border-light)',
borderRadius: '8px',
color: 'var(--text-main)',
fontSize: '1.05rem',
outline: 'none',
transition: 'border-color 0.3s'
}}
onFocus={(e) => e.target.style.borderColor = 'var(--accent-blue)'}
onBlur={(e) => e.target.style.borderColor = 'var(--border-light)'}
/>
</div>
<div>
<label style={{ display: 'block', marginBottom: '10px', fontSize: '0.95rem', fontWeight: 700, color: 'var(--text-muted)', textTransform: 'uppercase' }}>Контактный телефон</label>
<input
type="tel"
name="phone"
value={formData.phone}
onChange={handleChange}
required
style={{
width: '100%', padding: '16px',
background: 'var(--bg-lighter)',
border: '2px solid var(--border-light)',
borderRadius: '8px',
color: 'var(--text-main)',
fontSize: '1.05rem',
outline: 'none',
transition: 'border-color 0.3s'
}}
onFocus={(e) => e.target.style.borderColor = 'var(--accent-blue)'}
onBlur={(e) => e.target.style.borderColor = 'var(--border-light)'}
/>
</div>
<div>
<label style={{ display: 'block', marginBottom: '10px', fontSize: '0.95rem', fontWeight: 700, color: 'var(--text-muted)', textTransform: 'uppercase' }}>Тип объекта</label>
<select
name="objectType"
value={formData.objectType}
onChange={handleChange}
required
style={{
width: '100%', padding: '16px',
background: 'var(--bg-lighter)',
border: '2px solid var(--border-light)',
borderRadius: '8px',
color: 'var(--text-main)',
fontSize: '1.05rem',
outline: 'none',
appearance: 'none',
transition: 'border-color 0.3s',
cursor: 'pointer'
}}
onFocus={(e) => e.target.style.borderColor = 'var(--accent-blue)'}
onBlur={(e) => e.target.style.borderColor = 'var(--border-light)'}
>
<option value="" disabled>Выберите тип объекта</option>
<option value="industrial">Промышленный объект</option>
<option value="commercial">Коммерческая штаб-квартира</option>
<option value="infrastructure">Критическая инфраструктура</option>
<option value="residential">Частная резиденция</option>
<option value="other">Другое</option>
</select>
</div>
<motion.button
whileHover={{ scale: 1.02 }}
whileTap={{ scale: 0.98 }}
type="submit"
disabled={isSubmitting}
className="btn-primary"
style={{
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
gap: '12px',
marginTop: '15px',
opacity: isSubmitting ? 0.7 : 1,
cursor: isSubmitting ? 'not-allowed' : 'pointer'
}}
>
<span>{isSubmitting ? 'Отправка...' : 'Оставить заявку'}</span>
<Send size={20} />
</motion.button>
</form>
</motion.div>
</div>
</div>
</div>
</section>
);
};
export default LeadForm;