import { useState, useEffect } from 'react'; import { useParams } from 'react-router-dom'; import { api, Journal, Task } from '../lib/api'; import { useTheme } from '../lib/ThemeContext'; const detailsStyles = ` details[open] .details-arrow { transform: rotate(90deg); } details summary::-webkit-details-marker { display: none; } `; function GeneratingModal({ isOpen, provider, model, step, response }: { isOpen: boolean; provider: string; model?: string; step: number; response?: string; }) { const { resolvedTheme } = useTheme(); if (!isOpen) return null; const steps = [ { label: 'Sending entries to AI...', done: step > 0 }, { label: 'Waiting for response...', done: step > 1 }, { label: 'Processing & formatting...', done: step > 2 }, ]; const formatResponse = (str: string | undefined): string | null => { if (!str) return null; try { const parsed = JSON.parse(str); if (parsed.content?.[0]?.text) { return parsed.content[0].text; } if (parsed.choices?.[0]?.message?.content) { return parsed.choices[0].message.content; } return JSON.stringify(parsed, null, 2); } catch { return str; } }; const output = formatResponse(response); return ( <>

Generating Journal

{steps.map((s, i) => (
{s.done ? '✓' : i + 1}
{s.label}
))}
Details (AI Output)
{output ? (
                {output}
              
) : (

Waiting for response...

)}
{provider.charAt(0).toUpperCase() + provider.slice(1)} {model && ` • ${model}`}
); } export default function JournalPage() { const { date } = useParams<{ date: string }>(); const [journal, setJournal] = useState(null); const [tasks, setTasks] = useState([]); const [loading, setLoading] = useState(true); const [generating, setGenerating] = useState(false); const [currentProvider, setCurrentProvider] = useState(''); const [currentModel, setCurrentModel] = useState(''); const [generatingStep, setGeneratingStep] = useState(0); const [currentResponse, setCurrentResponse] = useState(); useEffect(() => { if (date) { loadJournal(); loadTasks(); } }, [date]); const loadJournal = async () => { if (!date) return; setLoading(true); const res = await api.getJournal(date); if (res.data) { setJournal(res.data); } setLoading(false); }; const loadTasks = async () => { if (!date) return; const res = await api.getJournalTasks(date); if (res.data) { setTasks(res.data); } }; const handleGenerate = async () => { if (!date) return; setGenerating(true); setGeneratingStep(1); setCurrentProvider('ai'); setCurrentModel(''); setCurrentResponse(undefined); const res = await api.generateJournal(date); setGeneratingStep(3); if (res.data) { setCurrentResponse(res.data.task.response); setJournal(res.data.journal); setCurrentProvider(res.data.task.provider); setCurrentModel(res.data.task.model || ''); setTasks(prev => [res.data!.task, ...prev]); } setTimeout(() => setGenerating(false), 500); }; const formatDate = (dateStr: string) => { const d = new Date(dateStr + 'T12:00:00'); return d.toLocaleDateString('en-US', { weekday: 'long', month: 'long', day: 'numeric', year: 'numeric' }); }; if (!date) return null; return ( <>
← Back to day

Diary Page

{formatDate(date)}

{loading ? (
Loading...
) : !journal || journal.content === 'Generating...' ? (

No diary page written yet

) : (
Generated {new Date(journal.generatedAt).toLocaleString()} • {journal.eventCount} events
{journal.content}
View Tasks
)} {tasks.length > 0 && (

Generation Tasks

View all →
{tasks.slice(0, 3).map(task => (
{task.provider.charAt(0).toUpperCase() + task.provider.slice(1)}
{task.status}
))}
)}
); }