@@ -44,6 +44,22 @@ export default function TodoPage() {
4444 const [ pomodoroActive , setPomodoroActive ] = useState ( false )
4545 const [ pomodoroMode , setPomodoroMode ] = useState < 'work' | 'break' > ( 'work' )
4646 const [ pomodoroSessions , setPomodoroSessions ] = useState ( 0 )
47+
48+ // Custom Settings State
49+ const [ workDuration , setWorkDuration ] = useState ( 25 )
50+ const [ breakDuration , setBreakDuration ] = useState ( 5 )
51+ const [ showSettings , setShowSettings ] = useState ( false )
52+
53+ // Sound Effect
54+ const playNotificationSound = useCallback ( ( ) => {
55+ try {
56+ const audio = new Audio ( 'https://assets.mixkit.co/active_storage/sfx/2869/2869-preview.mp3' )
57+ audio . volume = 0.5
58+ audio . play ( ) . catch ( e => console . log ( 'Audio play failed:' , e ) )
59+ } catch ( e ) {
60+ console . error ( 'Audio setup failed' , e )
61+ }
62+ } , [ ] )
4763
4864 const loadTasks = useCallback ( async ( ) => {
4965 const user = getCurrentUser ( )
@@ -99,27 +115,27 @@ export default function TodoPage() {
99115 } else if ( pomodoroTime === 0 ) {
100116 // Timer finished
101117 setPomodoroActive ( false )
118+ playNotificationSound ( )
102119
103120 if ( pomodoroMode === 'work' ) {
104121 // Work session completed
105122 setPomodoroSessions ( ( s ) => s + 1 )
106- // Notification sound/alert could be added here
107123 alert ( 'Work session completed! Time for a break.' )
108124 // Switch to break mode
109125 setPomodoroMode ( 'break' )
110- setPomodoroTime ( 5 * 60 ) // 5 minute break
126+ setPomodoroTime ( breakDuration * 60 )
111127 } else {
112128 // Break completed
113129 alert ( 'Break is over! Ready for another session?' )
114130 setPomodoroMode ( 'work' )
115- setPomodoroTime ( 25 * 60 ) // 25 minute work
131+ setPomodoroTime ( workDuration * 60 )
116132 }
117133 }
118134
119135 return ( ) => {
120136 if ( interval ) clearInterval ( interval )
121137 }
122- } , [ pomodoroActive , pomodoroTime , pomodoroMode ] )
138+ } , [ pomodoroActive , pomodoroTime , pomodoroMode , workDuration , breakDuration , playNotificationSound ] )
123139
124140 const startPomodoro = ( ) => {
125141 setPomodoroActive ( true )
@@ -132,9 +148,21 @@ export default function TodoPage() {
132148 const resetPomodoro = ( ) => {
133149 setPomodoroActive ( false )
134150 if ( pomodoroMode === 'work' ) {
135- setPomodoroTime ( 25 * 60 )
151+ setPomodoroTime ( workDuration * 60 )
136152 } else {
137- setPomodoroTime ( 5 * 60 )
153+ setPomodoroTime ( breakDuration * 60 )
154+ }
155+ }
156+
157+ const handleSettingsSave = ( ) => {
158+ setShowSettings ( false )
159+ // Update current timer if it matches the current mode
160+ if ( ! pomodoroActive ) {
161+ if ( pomodoroMode === 'work' ) {
162+ setPomodoroTime ( workDuration * 60 )
163+ } else {
164+ setPomodoroTime ( breakDuration * 60 )
165+ }
138166 }
139167 }
140168
@@ -255,15 +283,59 @@ export default function TodoPage() {
255283 < div className = "flex items-center gap-2 mb-6" >
256284 < Timer className = "h-5 w-5 text-primary" />
257285 < h2 className = "text-lg font-semibold" > Pomodoro Timer</ h2 >
258- < span className = { `ml-auto px-3 py-1 rounded-full text-xs font-medium ${
259- pomodoroMode === 'work'
260- ? 'bg-primary/10 text-primary'
261- : 'bg-green-500/10 text-green-600'
262- } `} >
263- { pomodoroMode === 'work' ? 'Focus' : 'Break' }
264- </ span >
286+ < div className = "ml-auto flex items-center gap-2" >
287+ < Button
288+ variant = "ghost"
289+ size = "icon"
290+ className = "h-8 w-8"
291+ onClick = { ( ) => setShowSettings ( ! showSettings ) }
292+ title = "Timer Settings"
293+ >
294+ < RotateCcw className = "h-4 w-4" />
295+ </ Button >
296+ < span className = { `px-3 py-1 rounded-full text-xs font-medium ${
297+ pomodoroMode === 'work'
298+ ? 'bg-primary/10 text-primary'
299+ : 'bg-green-500/10 text-green-600'
300+ } `} >
301+ { pomodoroMode === 'work' ? 'Focus' : 'Break' }
302+ </ span >
303+ </ div >
265304 </ div >
266305
306+ { showSettings && (
307+ < div className = "mb-6 p-4 border border-border bg-secondary/50 rounded-lg animate-fade-in-down" >
308+ < h3 className = "text-sm font-medium mb-3" > Timer Settings (minutes)</ h3 >
309+ < div className = "grid grid-cols-2 gap-4" >
310+ < div className = "space-y-2" >
311+ < label className = "text-xs text-muted-foreground" > Work Duration</ label >
312+ < Input
313+ type = "number"
314+ min = "1"
315+ max = "60"
316+ value = { workDuration }
317+ onChange = { ( e ) => setWorkDuration ( parseInt ( e . target . value ) || 25 ) }
318+ className = "bg-background"
319+ />
320+ </ div >
321+ < div className = "space-y-2" >
322+ < label className = "text-xs text-muted-foreground" > Break Duration</ label >
323+ < Input
324+ type = "number"
325+ min = "1"
326+ max = "30"
327+ value = { breakDuration }
328+ onChange = { ( e ) => setBreakDuration ( parseInt ( e . target . value ) || 5 ) }
329+ className = "bg-background"
330+ />
331+ </ div >
332+ </ div >
333+ < div className = "mt-4 flex justify-end" >
334+ < Button size = "sm" onClick = { handleSettingsSave } > Save Settings</ Button >
335+ </ div >
336+ </ div >
337+ ) }
338+
267339 < div className = "grid md:grid-cols-[1fr_auto] gap-8 items-center" >
268340 { /* Timer Display */ }
269341 < div className = "text-center space-y-6" >
0 commit comments