/* global React */
// About, Certifications, Contact pages + ContactForm
function AboutPage({ t, navigate }) {
const a = t.about;
return (
{a.eyebrow}
{a.title}
{a.sub}
{/* Principles */}
{a.principlesEyebrow}
{a.principlesTitle}
{a.principles.map((p, i) => (
))}
{/* Team block */}
{a.teamEyebrow}
{a.teamTitle}
{a.teamSub}
{/* Timeline */}
{a.timelineEyebrow}
{a.timeline.map((ev, i) => (
{ev.y}
{ev.k}
{ev.d}
))}
);
}
function TeamGrid() {
// 14 abstract operator avatars (CSS placeholder tiles)
const tiles = Array.from({ length: 14 }).map((_, i) => {
const hue = 230 + ((i * 13) % 20);
const t = ['OS', 'MR', 'KV', 'JL', 'AP', 'DS', 'FC', 'NM', 'TB', 'ER', 'IG', 'LV', 'CP', 'RS'][i];
return { t, hue };
});
return (
{tiles.map((tile, i) => (
{tile.t}
))}
);
}
// ── Certifications page ──────────────────────────────────────
function CertificationsPage({ t, navigate }) {
const c = t.certifications;
return (
{c.eyebrow}
{c.title}
{c.sub}
{c.items.map((it, i) => (
e.currentTarget.style.background = 'var(--bg-1)'}
onMouseLeave={(e) => e.currentTarget.style.background = 'var(--bg-0)'}>
{it.k}
{it.d}
· {it.c}
))}
{c.complianceEyebrow}
{c.compliance.map((cp, i) => (
{cp}
))}
);
}
// ── Contact page ────────────────────────────────────────────
function ContactPage({ t }) {
const c = t.contact;
return (
{c.eyebrow}
{c.title}
{c.sub}
);
}
// ── Contact form (reusable, with validation + states) ───────
function ContactForm({ t, compact = false }) {
const f = t.contact.form;
const [values, setValues] = useState({
name: '', email: '', company: '', phone: '', service: '', message: '',
});
const [errors, setErrors] = useState({});
const [status, setStatus] = useState('idle'); // idle | submitting | success | error
const setField = (k, v) => {
setValues((o) => ({ ...o, [k]: v }));
if (errors[k]) setErrors((e) => ({ ...e, [k]: null }));
};
const validate = () => {
const e = {};
if (!values.name.trim()) e.name = f.required;
if (!values.email.trim()) e.email = f.required;
else if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(values.email)) e.email = f.invalidEmail;
if (!values.company.trim()) e.company = f.required;
if (!values.message.trim()) e.message = f.required;
return e;
};
const onSubmit = async (ev) => {
ev.preventDefault();
const e = validate();
if (Object.keys(e).length) { setErrors(e); return; }
setStatus('submitting');
try {
const resp = await fetch('/api/contact', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
name: values.name.trim(),
email: values.email.trim(),
company: values.company.trim(),
phone: values.phone.trim() || null,
service: values.service || null,
message: values.message.trim(),
}),
});
setStatus(resp.ok ? 'success' : 'error');
} catch {
setStatus('error');
}
};
const reset = () => {
setValues({ name: '', email: '', company: '', phone: '', service: '', message: '' });
setErrors({});
setStatus('idle');
};
return (
{compact && (
<>
{t.contact.eyebrow}
{t.contact.title}
{t.contact.sub}
>
)}
{status === 'success' ? (
) : (
)}
);
}
function FormField({ label, value, err, onChange, placeholder, required, type = 'text' }) {
return (
onChange(e.target.value)} />
);
}
function SuccessState({ t, onReset }) {
const f = t.contact.form;
return (
{f.success}
TICKET-{Math.random().toString(36).slice(2, 8).toUpperCase()} · QUEUED
);
}
function ContactSidebar({ t }) {
const c = t.contact;
return (
);
}
// Spinner helper
const spinnerCss = `
@keyframes spin { to { transform: rotate(360deg); } }
.spinner {
width: 12px; height: 12px;
border: 1.5px solid currentColor;
border-top-color: transparent;
border-radius: 50%;
display: inline-block;
animation: spin 720ms linear infinite;
}
`;
// Inject once
if (!document.getElementById('spinner-style')) {
const style = document.createElement('style');
style.id = 'spinner-style';
style.textContent = spinnerCss;
document.head.appendChild(style);
}
Object.assign(window, { AboutPage, CertificationsPage, ContactPage, ContactForm });