feat(web): wire routine export/import into history page UI

This commit is contained in:
saravanakumardb1 2026-02-28 19:28:37 -08:00
parent 77254b751e
commit 141fcc2a38

View File

@ -7,7 +7,8 @@ import { computeStreak } from '@/lib/stats';
import { StatsView } from '@/components/StatsView';
import { StreakCard } from '@/components/StreakCard';
import { TimerCard } from '@/components/TimerCard';
import { downloadExport, readFileAsText, parseImportData, importTimers } from '@/lib/export';
import { downloadExportAll, readFileAsText, parseImportData, importTimers, importRoutines } from '@/lib/export';
import { useRoutineStore } from '@/lib/routine-store';
import { importCalendar } from '@/lib/calendar-import';
import { ArrowLeft, Download, Upload, Calendar, Search, Filter, RotateCcw, FileSpreadsheet, Eye, Check, X } from 'lucide-react';
import { getCategoryById, getAllCategories } from '@/lib/categories';
@ -17,6 +18,7 @@ import type { Timer } from '@/lib/timer-engine';
export default function HistoryPage() {
const timers = useTimerStore((s) => s.timers);
const now = useTimerStore((s) => s.now);
const routines = useRoutineStore((s) => s.routines);
const [mounted, setMounted] = useState(false);
const [search, setSearch] = useState('');
const [filterCategory, setFilterCategory] = useState<string | ''>('');
@ -50,7 +52,7 @@ export default function HistoryPage() {
if (!mounted) return null;
const handleExport = () => downloadExport(timers);
const handleExport = () => downloadExportAll(timers, routines);
const handleJsonImport = async (e: React.ChangeEvent<HTMLInputElement>) => {
const file = e.target.files?.[0];
@ -62,14 +64,28 @@ export default function HistoryPage() {
setImportStatus('Invalid file format. Expected a ChronoMind export JSON.');
return;
}
const result = importTimers(data, timers);
const timerResult = importTimers(data, timers);
// Add the imported timers to the store
const existingIds = new Set(timers.map((t) => t.id));
const newTimers = data.timers.filter((t) => !existingIds.has(t.id));
if (newTimers.length > 0) {
useTimerStore.setState((s) => ({ timers: [...s.timers, ...newTimers] }));
}
setImportStatus(`Imported ${result.imported} timers. ${result.skipped} skipped.${result.errors.length > 0 ? ` Errors: ${result.errors.join(', ')}` : ''}`);
// Import routines if present
const routineResult = importRoutines(data, routines);
if (data.routines && data.routines.length > 0) {
const existingRoutineIds = new Set(routines.map((r) => r.id));
const newRoutines = data.routines.filter((r) => !existingRoutineIds.has(r.id));
if (newRoutines.length > 0) {
useRoutineStore.setState((s) => ({ routines: [...s.routines, ...newRoutines] }));
}
}
const parts = [`Imported ${timerResult.imported} timers`];
if (routineResult.imported > 0) parts.push(`${routineResult.imported} routines`);
const totalSkipped = timerResult.skipped + routineResult.skipped;
if (totalSkipped > 0) parts.push(`${totalSkipped} skipped`);
const allErrors = [...timerResult.errors, ...routineResult.errors];
setImportStatus(`${parts.join(', ')}.${allErrors.length > 0 ? ` Errors: ${allErrors.join(', ')}` : ''}`);
} catch {
setImportStatus('Failed to read file.');
}
@ -300,15 +316,15 @@ export default function HistoryPage() {
style={{ backgroundColor: 'var(--cm-surface-card)', borderColor: 'var(--cm-border)' }}
>
<h3 className="text-sm font-semibold mb-2 flex items-center gap-2" style={{ color: 'var(--cm-text-primary)' }}>
<Download size={16} /> Export Timers
<Download size={16} /> Export Data
</h3>
<p className="text-xs mb-3" style={{ color: 'var(--cm-text-tertiary)' }}>
Download all {timers.length} timers as a JSON file.
Download all {timers.length} timers and {routines.length} routines as a JSON file.
</p>
<div className="flex gap-2">
<button
onClick={handleExport}
disabled={timers.length === 0}
disabled={timers.length === 0 && routines.length === 0}
className="flex items-center gap-1.5 px-4 py-2 rounded-lg text-sm font-medium cursor-pointer disabled:opacity-30"
style={{ backgroundColor: 'var(--cm-accent)', color: '#fff' }}
>
@ -331,10 +347,10 @@ export default function HistoryPage() {
style={{ backgroundColor: 'var(--cm-surface-card)', borderColor: 'var(--cm-border)' }}
>
<h3 className="text-sm font-semibold mb-2 flex items-center gap-2" style={{ color: 'var(--cm-text-primary)' }}>
<Upload size={16} /> Import Timers (JSON)
<Upload size={16} /> Import Data (JSON)
</h3>
<p className="text-xs mb-3" style={{ color: 'var(--cm-text-tertiary)' }}>
Restore timers from a previously exported ChronoMind JSON file.
Restore timers and routines from a previously exported ChronoMind JSON file.
</p>
<label
className="inline-block px-4 py-2 rounded-lg text-sm font-medium cursor-pointer"