// Блок «Контакты» — финальная секция главной. Форма заявки по центру.
// Стиль главной: бежевый фон, чёрный гротеск, терракотовый акцент.
const labelCss = {
display: 'block', marginBottom: 8,
fontFamily: 'JetBrains Mono,monospace', fontSize: 10.5, fontWeight: 700,
letterSpacing: '0.18em', textTransform: 'uppercase', color: 'rgba(26,26,30,0.5)',
};
function Field({ label, placeholder, multiline, type = 'text', name, autoComplete, value, onChange, disabled }) {
const base = {
width: '100%', boxSizing: 'border-box',
padding: multiline ? '14px 16px' : '0 16px',
height: multiline ? 112 : 48,
border: '1.5px solid rgba(26,26,30,0.25)', borderRadius: 8,
background: '#fff', color: 'var(--ink)',
fontFamily: 'Inter Tight,sans-serif', fontSize: 16,
outline: 'none', transition: 'border-color .2s',
resize: 'none', lineHeight: multiline ? 1.5 : undefined,
opacity: disabled ? 0.6 : 1,
};
const onFocus = (e) => { e.target.style.borderColor = 'var(--accent)'; };
const onBlur = (e) => { e.target.style.borderColor = 'rgba(26,26,30,0.25)'; };
const handle = (e) => { if (onChange) onChange(e.target.value); };
return (
{label}
{multiline
?
: }
);
}
// Нормализация ошибок: pydantic-валидация шлёт массив, http-ошибки — строку
// (как formatError в auth.jsx). Возвращает читабельный текст.
function formatError(detail) {
if (!detail) return '';
if (typeof detail === 'string') return detail;
if (Array.isArray(detail)) {
return detail.map((e) => (e && e.msg) ? e.msg : String(e)).join('; ');
}
return 'Что-то пошло не так.';
}
// ── Форма заявки: state/handler/состояния, визуал прежний ────────────
function LeadForm() {
const [name, setName] = React.useState('');
const [contact, setContact] = React.useState('');
const [message, setMessage] = React.useState('');
const [loading, setLoading] = React.useState(false);
const [error, setError] = React.useState('');
const [done, setDone] = React.useState(false);
const disabled = !name.trim() || !contact.trim() || loading;
const handleSubmit = async (e) => {
e.preventDefault();
if (disabled) return;
setError('');
setLoading(true);
try {
// /api/leads — публичный, без токена; обычный fetch (не apiFetch).
const res = await fetch('/api/leads', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
name: name.trim(),
contact: contact.trim(),
message: message.trim() || null,
source: 'home_contacts',
}),
});
const data = await res.json().catch(() => ({}));
if (!res.ok) {
setError(formatError(data && data.detail) || 'Не удалось отправить заявку.');
setLoading(false);
return;
}
setDone(true);
} catch (err) {
setError('Сетевая ошибка. Попробуйте ещё раз.');
setLoading(false);
}
};
if (done) {
return (
● заявка отправлена
Свяжемся с вами в течение дня.
);
}
return (
);
}
function Contacts({ minH }) {
const isMobile = window.useIsMobile ? window.useIsMobile() : false;
return (
);
}
window.Contacts = Contacts;