Feature: Pomodoro Timer
Relevant source files
The following files were used as context for generating this wiki page:The Pomodoro Timer is a core feature of the Endfield-Pomodoro application, providing a configurable and immersive time management tool. It implements the Pomodoro Technique, cycling through focused work sessions and short/long breaks. The system is designed to be robust, featuring state persistence across browser refreshes, accurate timekeeping, and user-configurable behavior.
The timer is encapsulated within the Pomodoro.tsx component, which is managed by the main App.tsx component. This architecture allows for a clear separation of concerns, where App.tsx handles global settings and statistics, while Pomodoro.tsx focuses exclusively on the timer's lifecycle, state, and UI representation.
Architecture and Component Interaction
The Pomodoro timer functionality is primarily driven by two components: App and Pomodoro. The App component acts as the parent controller, managing global state and settings, while the Pomodoro component is the specialized child responsible for the timer's core logic.
App.tsx: Manages user-definedSettings,sessionCount, and total accumulated study time. It passes these down toPomodoroas props. It also listens for events fromPomodorovia callbacks likeonSessionsUpdateandonTickto update global state and the browser tab title.Pomodoro.tsx: Contains the main timer logic, including the countdown mechanism, state transitions between work and break modes, and handling user interactions like start, pause, and skip. It maintains its own internal state (mode,timeLeft,isActive) and persists it tolocalStorage.
This diagram illustrates the component hierarchy and data flow between the parent App and the child Pomodoro component.
State Management and Data Flow
The timer's state is distributed between the App and Pomodoro components.
Pomodoro Component State
The Pomodoro component manages the immediate state of the timer.
| State | Type | Description |
|---|---|---|
mode | TimerMode | The current timer mode: WORK, SHORT_BREAK, or LONG_BREAK. |
timeLeft | number | The remaining time in seconds for the current mode. |
isActive | boolean | A flag indicating whether the timer is currently running or paused. |
Sources: src/components/Pomodoro.tsx:37-39, src/types.ts:1-5
App Component State (Timer-Related)
The App component manages higher-level state that persists across sessions and influences the timer's behavior.
| State | Type | Description |
|---|---|---|
settings | Settings | User-configurable values like durations, auto-start behavior, and notifications. |
sessionCount | number | The number of completed work sessions. |
persistedTotalSeconds | number | The total accumulated study time in seconds, saved in localStorage. |
currentSessionStart | number | A timestamp for when the current work session started, used for calculating elapsed time across reloads. |
Sources: src/App.tsx:63-90
Data Flow on Timer Tick
The onTick callback is crucial for synchronizing state between Pomodoro and App.
This sequence shows how the Pomodoro component notifies the App component on each time update, allowing the parent to update the document title and track study time.
Sources: src/App.tsx:650-668, src/components/Pomodoro.tsx:195-201
Timer Logic and Lifecycle
The timer's lifecycle is managed by a series of useEffect hooks and handler functions within Pomodoro.tsx.
Countdown Mechanism
The timer does not rely on a simple setInterval decrementing a counter, which can be inaccurate. Instead, it calculates the elapsed time since the timer started to ensure precision.
- When the timer becomes active (
isActiveis true), the current time (startTime) and theexpectedEndTimeare recorded. - A
setIntervalruns every100ms(TIMER_CHECK_INTERVAL_MS). - Inside the interval, it calculates the
remainingtime by subtracting the currentDate.now()from theexpectedEndTime. - The
timeLeftstate is updated with this newly calculated remaining time. This corrects for any drift or lag caused by the browser.
Sources: src/components/Pomodoro.tsx:189-204, src/constants.ts:77
State Transitions
The handleComplete function orchestrates the transition between timer modes.
This flow demonstrates how the application automatically cycles between work, short breaks, and long breaks based on the number of completed sessions.
Sources: src/components/Pomodoro.tsx:226-246, src/constants.ts:78
Data Persistence
To provide a seamless user experience, the timer's state is persisted to localStorage, allowing it to be restored after a page refresh or browser restart.
Persisted Data
A TimerPayload object is saved to localStorage under the key origin_terminal_timer.
// src/components/Pomodoro.tsx:20-25
type TimerPayload = {
mode: TimerMode;
timeLeft: number;
isActive: boolean;
startTs?: number;
};
If the timer is active (isActive), a startTs timestamp is calculated and stored. This timestamp represents when the current countdown began, allowing the application to calculate the time elapsed while the tab was closed.
Sources: src/components/Pomodoro.tsx:20-25, 110-123, src/constants.ts:16
Restoration Flow
On component mount, Pomodoro.tsx attempts to load and parse this data.
This diagram shows the process of restoring the timer state, including calculating offline progress if the timer was running when the page was last closed.
Sources: src/components/Pomodoro.tsx:44-90
Configuration
The timer's behavior is highly configurable through the settings panel. These settings are defined in the Settings interface and managed in the App component.
| Setting | Type | Default Value | Description |
|---|---|---|---|
workDuration | number | 25 | Duration of a work session in minutes. |
shortBreakDuration | number | 5 | Duration of a short break in minutes. |
longBreakDuration | number | 15 | Duration of a long break in minutes. |
autoStartBreaks | boolean | true | Automatically start break timers after a work session completes. |
autoStartWork | boolean | true | Automatically start work timers after a break completes. |
notificationsEnabled | boolean | false | Enable browser notifications upon session completion. Permission is requested when this is enabled. |
Sources: src/App.tsx:21-36, src/types.ts:46-54
Key Constants
Several hardcoded constants govern the timer's fundamental behavior.
| Constant | Value | File | Description |
|---|---|---|---|
SECONDS_PER_MINUTE | 60 | src/constants.ts | Conversion factor for minutes to seconds. |
LONG_BREAK_INTERVAL | 4 | src/constants.ts | Number of work sessions to complete before a long break is triggered. |
TIMER_CHECK_INTERVAL_MS | 100 | src/constants.ts | The interval (in ms) at which the timer's remaining time is recalculated. |
MS_PER_SECOND | 1000 | src/constants.ts | Conversion factor for seconds to milliseconds. |
Sources: src/constants.ts:69-78
UI and User Feedback
The timer provides rich visual and auditory feedback.
- Circular Progress Bar: A primary SVG-based circle visually represents the time elapsed. The progress is calculated as
((total - timeLeft) / total) * 100. - Status Display: Text indicates the current mode (
OPERATIONAL,COOLDOWN,HIBERNATION) and state (STANDBY,PAUSED). - Browser Tab Title: When the tab is not visible, the
Appcomponent updates thedocument.titleto show the remaining time, providing at-a-glance status. - Notifications: If enabled, the
sendNotificationfunction uses the browser's Notification API to alert the user when a work or break cycle is complete. - Sound: A
SoundManagerplays distinct sounds for timer start and end events, if enabled in settings.
Sources: src/components/Pomodoro.tsx:273-311, 206-224, src/App.tsx:141-167, src/utils/i18n.ts:80-82
Summary
The Pomodoro Timer is a well-architected, stateful feature that effectively separates its core logic from global application concerns. It uses modern React hooks for lifecycle and state management, ensures timer accuracy by compensating for browser lag, and provides a robust user experience through state persistence and rich feedback mechanisms. Its configurability allows users to tailor the experience to their specific workflow, making it a central and powerful part of the application.