// KineSuite landing — comparison table + roadmap notify form.
const { useState: useNotifyS } = React;
function CompStatusIcon({ kind }) {
const map = {
yes: { glyph: '✓', color: 'var(--semantic-green)', bg: 'var(--semantic-green-bg)' },
partial: { glyph: '~', color: 'var(--semantic-yellow)', bg: 'var(--semantic-yellow-bg)' },
no: { glyph: '×', color: 'var(--semantic-red)', bg: 'var(--semantic-red-bg)' },
};
const s = map[kind] || map.no;
return (
{s.glyph}
);
}
function CompHeaderCell({ name, muted, highlight }) {
return (
);
}
function CompareMobileCard({ row, t }) {
const cols = [
{ key: 'paper', label: t.compareColPaper },
{ key: 'excel', label: t.compareColExcel },
{ key: 'ks', label: 'KineSuite', highlight: true },
];
return (
{row.label}
{cols.map(({ key, label, highlight }) => {
const cell = row[key];
return (
{label}
{cell.label && (
{cell.label}
)}
);
})}
);
}
function ComparisonSection({ t }) {
const rows = t.compareRows;
return (
{t.compareEyebrow}
{t.compareTitle}
{t.compareSub}
{rows.map((row, i) => {
const last = i === rows.length - 1;
const border = last ? 'none' : '1px solid var(--gray-200)';
return (
{row.paper.label && {row.paper.label}}
{row.excel.label && {row.excel.label}}
{row.ks.label && {row.ks.label}}
);
})}
{rows.map((row, i) => (
))}
{t.compareFootnote}
);
}
// Replace FORMSPREE_ID with your Formspree form ID (https://formspree.io → new form → copy the id)
const FORMSPREE_ENDPOINT = 'https://formspree.io/f/mbdbdzgl';
function PriorityChip({ label, checked, disabled, onClick }) {
return (
);
}
function NotifySection({ t }) {
const [email, setEmail] = useNotifyS('');
const [priorities, setPriorities] = useNotifyS([]);
const [specialty, setSpecialty] = useNotifyS('');
const [missingScale, setMissingScale] = useNotifyS('');
const [done, setDone] = useNotifyS(false);
const [error, setError] = useNotifyS(false);
const [sending, setSending] = useNotifyS(false);
const MAX = 3;
const togglePriority = (id) => {
setPriorities((prev) => {
if (prev.includes(id)) return prev.filter((x) => x !== id);
if (prev.length >= MAX) return prev;
return [...prev, id];
});
};
const reset = () => {
setDone(false); setEmail(''); setPriorities([]);
setSpecialty(''); setMissingScale('');
};
const submit = async (e) => {
e.preventDefault();
const ok = /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email.trim());
if (!ok) { setError(true); return; }
setError(false);
setSending(true);
const payload = {
email: email.trim(),
prioridades: priorities.join(', ') || '—',
especialidad: specialty || '—',
escala_faltante: missingScale.trim() || '—',
};
try {
const res = await fetch(FORMSPREE_ENDPOINT, {
method: 'POST',
headers: { 'Content-Type': 'application/json', Accept: 'application/json' },
body: JSON.stringify(payload),
});
if (!res.ok) throw new Error('network');
} catch {
try {
localStorage.setItem('kinesuite-notify', JSON.stringify({ ...payload, at: Date.now() }));
} catch {}
} finally {
setSending(false);
}
setDone(true);
};
return (
{t.notifyEyebrow}
{t.notifyTitle}
{t.notifySub}
{done ? (
{t.notifyDoneTitle}
{t.notifyDoneBody}
) : (
)}
);
}
Object.assign(window, {
ComparisonSection, NotifySection,
});