// Capture sheet — quick-capture modal triggered by pull-down on Today or from FAB.
function CaptureSheet({ visible, onClose }) {
const [mode, setMode] = React.useState(null);
const [text, setText] = React.useState('');
const [saving, setSaving] = React.useState(false);
React.useEffect(() => {
if (!visible) {
setMode(null);
setText('');
}
}, [visible]);
if (!visible) return null;
const modes = [
{ id: 'journal', icon: , label: 'Journal', sub: 'Mood + entities · local only', color: T.indigo },
{ id: 'memory', icon: , label: 'Memory', sub: 'Save a fact for context', color: T.purple },
{ id: 'task', icon: , label: 'Task', sub: 'With smart reminder', color: T.green },
{ id: 'bill', icon: , label: 'Bill photo', sub: 'Auto-extract amount + due', color: T.red },
{ id: 'voice', icon: , label: 'Voice note', sub: 'Transcribed locally', color: T.orange },
{ id: 'remind', icon: , label: 'Remind me', sub: '"…when I get home"', color: T.blue },
];
const activeMode = modes.find(m => m.id === mode);
const handleSave = async () => {
if (!text.trim() || saving) return;
setSaving(true);
try {
if (mode === 'memory') {
await fetch('/api/capture/memory', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ fact: text, user: LifeData.user, category: 'note' }),
});
} else if (mode === 'task') {
await fetch('/api/capture/task', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ description: text, user: LifeData.user }),
});
}
// journal stays local-only for now (no cloud endpoint)
} catch (err) {
console.error('Capture save failed:', err);
} finally {
setSaving(false);
onClose();
}
};
return (
e.stopPropagation()} style={{
background: T.bg, width: '100%',
borderTopLeftRadius: 28, borderTopRightRadius: 28,
padding: '8px 0 28px',
maxHeight: '86%', overflowY: 'auto',
boxShadow: '0 -8px 32px rgba(0,0,0,0.16)',
animation: 'slideUp 0.3s cubic-bezier(.2,.8,.2,1)',
}}>
{mode === null && (
<>
{modes.map(m => (
))}
Journal, bills & voice transcribed locally · never leave the Thinkpad
>
)}
{mode && (
<>
{activeMode.icon}
{activeMode.label}
{activeMode.sub}
{mode === 'journal' && (
{['🙂 OK', '😴 tired', '😤 frustrated', '🔥 energetic', '😌 calm', '😔 low'].map(m => (
setText(t => t + (t ? ' ' : '') + m)}>{m}
))}
)}
{mode === 'memory' && (
Category
{['routine', 'diet', 'work', 'partner', 'location', 'preference'].map(c => (
{c}
))}
)}
>
)}
);
}
window.CaptureSheet = CaptureSheet;