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 (
<>
{loading ? (
Loading...
) : !journal || journal.content === 'Generating...' ? (
No diary page written yet
) : (
Generated {new Date(journal.generatedAt).toLocaleString()} • {journal.eventCount} events
)}
{tasks.length > 0 && (
{tasks.slice(0, 3).map(task => (
{task.provider.charAt(0).toUpperCase() + task.provider.slice(1)}
{task.status}
))}
)}
>
);
}