'use client';
import { useState, useEffect, useCallback } from 'react';
import { useTimerStore } from '@/lib/store';
import { useTickLoop } from '@/lib/use-tick';
import { useKeyboardShortcuts, SHORTCUT_MAP } from '@/lib/use-keyboard-shortcuts';
import { TimerCard } from './TimerCard';
import { PomodoroView } from './PomodoroView';
import { QuickTimerBar } from './QuickTimerBar';
import { CreateTimerModal } from './CreateTimerModal';
import { AlarmOverlay } from './AlarmOverlay';
import { requestNotificationPermission } from '@/lib/notifications';
import { formatTime, formatDate } from '@/lib/format';
import { Plus, Clock, Bell, Keyboard } from 'lucide-react';
export function Dashboard() {
const [isCreateOpen, setIsCreateOpen] = useState(false);
const [showShortcuts, setShowShortcuts] = useState(false);
const [mounted, setMounted] = useState(false);
const timers = useTimerStore((s) => s.timers);
const now = useTimerStore((s) => s.now);
const { pause, resume } = useTimerStore();
// Start the tick loop
useTickLoop();
// Keyboard shortcuts
const getFirstActiveTimer = useCallback(() => {
return timers.find((t) => ['active', 'warning', 'paused'].includes(t.state));
}, [timers]);
useKeyboardShortcuts({
onNewTimer: () => setIsCreateOpen(true),
onQuickTimer: () => setIsCreateOpen(true),
onTogglePause: () => {
const t = getFirstActiveTimer();
if (!t) return;
if (t.state === 'paused') resume(t.id);
else if (t.type !== 'alarm') pause(t.id);
},
onDismiss: () => {
if (isCreateOpen) setIsCreateOpen(false);
else if (showShortcuts) setShowShortcuts(false);
},
onShowHelp: () => setShowShortcuts((p) => !p),
});
// Hydration guard
useEffect(() => {
setMounted(true);
requestNotificationPermission();
}, []);
if (!mounted) {
return (
);
}
const activeTimers = timers.filter((t) =>
['active', 'warning', 'snoozed', 'firing', 'paused'].includes(t.state)
);
const completedTimers = timers
.filter((t) => ['dismissed', 'completed'].includes(t.state))
.slice(-10)
.reverse();
// Tab title update
useEffect(() => {
const next = activeTimers
.filter((t) => ['active', 'warning'].includes(t.state))
.sort((a, b) => a.targetTime - b.targetTime)[0];
if (next) {
const remaining = Math.max(0, next.targetTime - now);
const mins = Math.floor(remaining / 60000);
const secs = Math.floor((remaining % 60000) / 1000);
document.title = `${String(mins).padStart(2, '0')}:${String(secs).padStart(2, '0')} โ ${next.label} | ChronoMind`;
} else {
document.title = 'ChronoMind โ Smart Pre-Warning Timer';
}
}, [now, activeTimers]);
return (
{/* Alarm overlay for firing timers */}
{/* Header */}
ChronoMind
{formatTime(now)} ยท {formatDate(now)}
{/* Keyboard shortcuts overlay */}
{showShortcuts && (
setShowShortcuts(false)} />
Keyboard Shortcuts
{SHORTCUT_MAP.map((s) => (
{s.description}
{s.key}
))}
)}
{/* Main content */}
{/* Quick timer bar */}
{/* Active timers */}
{activeTimers.length > 0 ? (
Active ({activeTimers.length})
{activeTimers
.sort((a, b) => a.targetTime - b.targetTime)
.map((timer) =>
timer.type === 'pomodoro' ? (
) : (
)
)}
) : (
/* Empty state */
No active timers
Create your first timer and never be caught off-guard again.
)}
{/* Completed timers */}
{completedTimers.length > 0 && (
Recent ({completedTimers.length})
{completedTimers.map((timer) => (
))}
)}
{/* Create Timer Modal */}
setIsCreateOpen(false)} />
{/* Footer */}
);
}