Component: Pomodoro
Relevant source files
The following files were used as context for generating this wiki page:
The Pomodoro component is the core time-tracking engine of the Endfield-Pomodoro application. It encapsulates the logic for the Pomodoro Technique, managing work, short break, and long break cycles. It is responsible for the timer's state, including the current mode, time remaining, and active status.
This component is designed to be highly resilient, featuring state persistence to localStorage, which allows the timer to be restored to its previous state even after a page refresh. It communicates with its parent component, App.tsx, to receive settings, report session completions, and provide real-time updates on the timer's status for global UI elements like the document title and total study time calculation.
Architecture and Props
The Pomodoro component is a child of the main App component. It receives configuration and state from App and reports back key events and state changes through callback props.
Sources: src/App.tsx:613-667, src/components/Pomodoro.tsx:14-19
The following diagram illustrates the relationship between App and Pomodoro.
Component Props
The component accepts the following props to function:
| Prop | Type | Description |
|---|---|---|
settings | Settings | An object containing user-defined settings like durations for work/breaks, auto-start options, sound settings, and notification status. |
sessionCount | number | The current number of completed work sessions. |
onSessionsUpdate | (count: number) => void | Callback function invoked when a work session completes or when the user resets the session count. |
onTick | (timeLeft: number, mode: TimerMode, isActive: boolean) => void | Callback function invoked on every timer tick, start, pause, or reset, to synchronize the parent component's state. |
Sources: src/components/Pomodoro.tsx:14-19, src/App.tsx:615-667
State Management
The component manages its core logic through three primary internal state variables.
mode: TimerMode: The current timer mode (WORK,SHORT_BREAK, orLONG_BREAK).timeLeft: number: The remaining time in seconds for the current mode.isActive: boolean: A boolean indicating whether the timer is currently running.
Sources: src/components/Pomodoro.tsx:37-39
State Persistence
A key feature of the Pomodoro component is its ability to persist and restore its state across browser sessions. This is achieved using the localStorage API.
Timer Payload
When the timer's state changes, it is serialized into a TimerPayload object and saved to localStorage under the key origin_terminal_timer.
| Field | Type | Description |
|---|---|---|
mode | TimerMode | The current timer mode. |
timeLeft | number | The remaining seconds at the moment of saving. |
isActive | boolean | The active status of the timer. |
startTs | number | (Optional) A timestamp of when the current active session started, used to calculate elapsed time after a refresh. |
Sources: src/components/Pomodoro.tsx:22-27, src/components/Pomodoro.tsx:103-112
Restoration and Persistence Flow
The following sequence diagram shows how the state is restored on component mount and persisted on updates.
The restoration logic is robust, handling cases where the timer was active during a page refresh. It calculates the time elapsed since the session started (startTs) and subtracts it from the timeLeft to ensure accuracy.
Sources: src/components/Pomodoro.tsx:62-66
Timer Logic
Accurate Timing Mechanism
To prevent timing drift that can occur with setInterval, the component uses a more reliable method. When the timer starts, it calculates the expectedEndTime. The setInterval callback then repeatedly calculates the remaining time by subtracting the current timestamp (Date.now()) from the expectedEndTime. This ensures the countdown remains accurate even if the browser throttles the interval callback.
// src/components/Pomodoro.tsx:165-179
const startTime = Date.now();
const expectedEndTime = startTime + timeLeft * MS_PER_SECOND;
const interval = window.setInterval(() => {
const now = Date.now();
const remaining = Math.ceil((expectedEndTime - now) / MS_PER_SECOND);
if (remaining <= 0) {
setTimeLeft(0);
if (onTick) onTick(0, mode, true);
} else if (remaining !== timeLeft) {
setTimeLeft(remaining);
if (onTick) onTick(remaining, mode, true);
}
}, TIMER_CHECK_INTERVAL_MS);
Sources: src/components/Pomodoro.tsx:165-179
Mode Transitions
When a timer completes, the handleComplete function is called. This function is responsible for playing a sound, sending a notification, and transitioning to the next mode in the cycle.
The following flowchart illustrates the mode transition logic.
Sources: src/components/Pomodoro.tsx:201-218
The component also respects the autoStartBreaks and autoStartWork settings from the Settings prop to determine if the next timer should begin automatically.
Sources: src/components/Pomodoro.tsx:208, 216
UI and Visuals
The Pomodoro component is rendered inside a Panel and displays the timer's status, session count, and a large circular progress indicator.
Circular Progress Bar
The timer's progress is visualized using an SVG circle with its strokeDashoffset property animated based on the percentage of time elapsed.
- Track: A faint circle represents the full duration.
- Progress: A thicker, colored circle animates to show the remaining time. The color changes based on the timer mode (primary for work, accent for breaks).
- Glow Tip: A small circle at the end of the progress arc provides a visual focal point.
The progress percentage is calculated as: ((total - timeLeft) / total) * 100.
Sources: src/components/Pomodoro.tsx:265-271, src/components/Pomodoro.tsx:300-329
Status and Controls
The UI provides clear feedback on the timer's state and offers several controls.
| UI Element | Description - Status Text: Displays the current status (OPERATIONAL, COOLDOWN, PAUSED, etc.) using translations from i18n.ts.
- Session Counter: Shows the number of completed work cycles.
- Control Buttons:
- Initialize/Halt: Toggles the timer's
isActivestate. - Reset: Resets the current timer to its full duration.
- Skip: Immediately completes the current phase and moves to the next.
- Reset Sessions: Resets the
sessionCountto 0.
- Initialize/Halt: Toggles the timer's
Sources: src/components/Pomodoro.tsx:275-296, src/components/Pomodoro.tsx:364-382, src/utils/i18n.ts:39-47
Side Effects
Sound Feedback
The component uses the useSound hook (from SoundManager) to provide audio feedback for timer start and end events. This feature can be enabled or disabled via the soundEnabled setting.
Sources: src/components/Pomodoro.tsx:29, src/components/Pomodoro.tsx:202, src/components/Pomodoro.tsx:220
Desktop Notifications
If enabled via the notificationsEnabled setting and granted permission by the user, the component will send a desktop notification when a work or break cycle is complete. The notification content is localized using i18n.ts.
// src/components/Pomodoro.tsx:186-198
const sendNotification = (title: string, body: string) => {
if (!settingsRef.current.notificationsEnabled) return;
if ('Notification' in window && Notification.permission === 'granted') {
try {
const n = new Notification(title, {
body,
icon: '/pwa-192x192.png',
requireInteraction: true,
silent: false
});
n.onclick = () => { window.focus(); n.close(); };
} catch (e) {
console.error('Notification error:', e);
}
}
};
Sources: src/components/Pomodoro.tsx:186-198, src/App.tsx:502-523
Conclusion
The Pomodoro component is a self-contained and robust module that serves as the heart of the application's time-management functionality. Its thoughtful design, including accurate timing, state persistence, and clear communication with its parent, makes it a reliable and central piece of the user experience. Its configurability through props allows it to adapt to user preferences seamlessly, while its visual and auditory feedback mechanisms create an immersive and informative environment.