72f8a4c126
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
247 lines
12 KiB
React
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;
|