import { useState, useEffect, useRef, useMemo } from 'react'; import { FaUndo, FaPlay, FaPause } from 'react-icons/fa/index'; import { IoMdSettings } from 'react-icons/io/index'; import { Modal } from '@/components/modal'; import { Button } from '../generics/button'; import { Timer } from './timer'; import { Tabs } from './tabs'; import { Setting } from './setting'; import { useLocalStorage } from '@/hooks/use-local-storage'; import { useSoundEffect } from '@/hooks/use-sound-effect'; import { usePomodoroStore } from '@/stores/pomodoro'; import { useCloseListener } from '@/hooks/use-close-listener'; import styles from './pomodoro.module.css'; // 安全地获取localStorage function getLocalStorageItem(key: string, defaultValue: string = 'en'): string { if (typeof window !== 'undefined' && window.localStorage) { try { return localStorage.getItem(key) || defaultValue; } catch { return defaultValue; } } return defaultValue; } interface PomodoroProps { onClose: () => void; open: () => void; show: boolean; } export function Pomodoro({ onClose, open, show }: PomodoroProps) { const [currentLang, setCurrentLang] = useState('en'); const [showSetting, setShowSetting] = useState(false); // 在客户端初始化语言 useEffect(() => { const lang = getLocalStorageItem('moodist-language'); setCurrentLang(lang); // 监听语言变化 const handleLanguageChange = (event: CustomEvent) => { setCurrentLang(event.detail.language); }; window.addEventListener('languageChanged', handleLanguageChange as EventListener); return () => { window.removeEventListener('languageChanged', handleLanguageChange as EventListener); }; }, []); // 获取本地化文本 const titleText = currentLang === 'zh' ? '番茄钟定时器' : 'Pomodoro Timer'; const changeTimesTooltip = currentLang === 'zh' ? '更改时间' : 'Change Times'; const completedText = currentLang === 'zh' ? '已完成' : 'completed'; const restartTooltip = currentLang === 'zh' ? '重新开始' : 'Restart'; const pauseTooltip = currentLang === 'zh' ? '暂停' : 'Pause'; const startTooltip = currentLang === 'zh' ? '开始' : 'Start'; const [selectedTab, setSelectedTab] = useState('pomodoro'); const running = usePomodoroStore(state => state.running); const setRunning = usePomodoroStore(state => state.setRunning); const [timer, setTimer] = useState(0); const interval = useRef | null>(null); const alarm = useSoundEffect('/sounds/alarm.mp3'); const defaultTimes = useMemo( () => ({ long: 15 * 60, pomodoro: 25 * 60, short: 5 * 60, }), [], ); const [times, setTimes] = useLocalStorage>( 'moodist-pomodoro-setting', defaultTimes, ); const [completions, setCompletions] = useState>({ long: 0, pomodoro: 0, short: 0, }); const tabs = useMemo( () => [ { id: 'pomodoro', label: currentLang === 'zh' ? '番茄钟' : 'Pomodoro' }, { id: 'short', label: currentLang === 'zh' ? '短休息' : 'Break' }, { id: 'long', label: currentLang === 'zh' ? '长休息' : 'Long Break' }, ], [currentLang], ); useCloseListener(() => setShowSetting(false)); useEffect(() => { if (running) { if (interval.current) clearInterval(interval.current); interval.current = setInterval(() => { setTimer(prev => prev - 1); }, 1000); } else { if (interval.current) clearInterval(interval.current); } }, [running]); useEffect(() => { if (timer <= 0 && running) { if (interval.current) clearInterval(interval.current); alarm.play(); setRunning(false); setCompletions(prev => ({ ...prev, [selectedTab]: prev[selectedTab] + 1, })); } }, [timer, selectedTab, running, setRunning, alarm]); useEffect(() => { const time = times[selectedTab] || 10; if (interval.current) clearInterval(interval.current); setRunning(false); setTimer(time); }, [selectedTab, times, setRunning]); const toggleRunning = () => { if (running) setRunning(false); else if (timer <= 0) { const time = times[selectedTab] || 10; setTimer(time); setRunning(true); } else setRunning(true); }; const restart = () => { if (interval.current) clearInterval(interval.current); const time = times[selectedTab] || 10; setRunning(false); setTimer(time); }; return ( <>

{titleText}

{completions[selectedTab] || 0} {completedText}

{ setShowSetting(false); setTimes(times); open(); }} onClose={() => { setShowSetting(false); open(); }} /> ); }