FocusBubble automatically saves all your focus sessions to your browser's localStorage. This means your data persists across browser sessions without requiring a backend server or database.
Each completed focus session stores:
- Duration - Total time focused (in seconds)
- Date - ISO timestamp of when the session was completed
- Distractions - Number of times you switched tabs/minimized the window
- Unique ID - Auto-generated timestamp-based identifier
{
id: 1728936420000,
date: "2025-10-14T10:27:00.000Z",
duration: 1500, // 25 minutes in seconds
distractions: 2
}Both timer interfaces (FocusBubble & Traditional Timer) automatically track sessions:
Timer.jsx:
const { addSession } = useFocusStats();
const sessionStartTimeRef = useRef(null);
const sessionDistractionsRef = useRef(0);
// Save session when timer completes
useEffect(() => {
if (time === 0 && sessionStartTimeRef.current !== null) {
const sessionDuration = duration;
const sessionDistractions = sessionDistractionsRef.current;
// Save the session
addSession(sessionDuration, sessionDistractions);
}
}, [time, duration, addSession]);FocusBubble.jsx:
useEffect(() => {
if (time === 0 && sessionStarted) {
// Session completed!
addSession(duration, distractionCount);
setSessionStarted(false);
setCompletionCelebration(true);
}
}, [time, isRunning, sessionStarted, duration, distractionCount, addSession]);Basic localStorage wrapper with JSON parsing:
export function useLocalStorage(key, initialValue) {
const [storedValue, setStoredValue] = useState(() => {
try {
const item = window.localStorage.getItem(key);
return item ? JSON.parse(item) : initialValue;
} catch (error) {
console.log(error);
return initialValue;
}
});
const setValue = (value) => {
try {
setStoredValue(value);
window.localStorage.setItem(key, JSON.stringify(value));
} catch (error) {
console.log(error);
}
};
return [storedValue, setValue];
}Manages sessions and calculates statistics:
export function useFocusStats() {
const [sessions, setSessions] = useLocalStorage('focusSessions', []);
const [stats, setStats] = useState({
totalFocusTime: 0,
totalSessions: 0,
totalDistractions: 0,
averageSessionLength: 0,
last7Days: []
});
// Calculate statistics from sessions
useEffect(() => {
// ... calculates stats from last 7 days
}, [sessions]);
const addSession = useCallback((duration, distractions) => {
const newSession = {
id: Date.now(),
date: new Date().toISOString(),
duration,
distractions
};
setSessions(prev => [...prev, newSession]);
}, [setSessions]);
return { stats, sessions, addSession, clearSessions };
}The Dashboard component automatically loads and displays sessions:
export default function Dashboard() {
const { stats } = useFocusStats(); // Automatically loads from localStorage
return (
// Display stats.totalFocusTime, stats.totalSessions, etc.
// Render charts using stats.last7Days data
);
}┌─────────────────────┐
│ User Completes │
│ Focus Session │
└──────────┬──────────┘
│
▼
┌─────────────────────┐
│ Timer Component │
│ calls addSession() │
└──────────┬──────────┘
│
▼
┌─────────────────────┐
│ useFocusStats() │
│ creates session │
│ object with data │
└──────────┬──────────┘
│
▼
┌─────────────────────┐
│ useLocalStorage() │
│ saves to browser │
│ localStorage │
└──────────┬──────────┘
│
▼
┌─────────────────────┐
│ Browser Storage │
│ key: focusSessions │
│ value: JSON array │
└──────────┬──────────┘
│
▼
┌─────────────────────┐
│ Dashboard Reads │
│ from localStorage │
│ on page load │
└─────────────────────┘
- Open Chrome/Edge DevTools (F12)
- Go to Application tab
- Expand Local Storage
- Click on your domain (e.g.,
http://localhost:3000) - Find key:
focusSessions - View the JSON array of all sessions
// View all sessions
JSON.parse(localStorage.getItem('focusSessions'))
// Count sessions
JSON.parse(localStorage.getItem('focusSessions')).length
// View latest session
const sessions = JSON.parse(localStorage.getItem('focusSessions'));
sessions[sessions.length - 1];- Start the app:
npm start - Navigate to Focus Bubble or Focus Timer
- Select 25 minutes (or use shorter duration for testing)
- Click Start
- Wait for timer to complete (or manually adjust for testing)
- Go to Dashboard tab
- ✅ Verify session appears in statistics
- Complete a session as above
- Refresh the page (Cmd+R / Ctrl+R)
- Navigate to Dashboard
- ✅ Verify data persists after refresh
- Complete a session
- Close the browser tab/window
- Reopen
http://localhost:3000 - Navigate to Dashboard
- ✅ Verify data persists after closing
- Complete 3-5 different sessions
- Go to Dashboard
- ✅ Verify all sessions are tracked
- ✅ Check charts update with multiple data points
The Dashboard automatically displays:
- Total Focus Time - Sum of all session durations (last 7 days)
- Total Sessions - Count of completed sessions
- Average Session - Mean duration per session
- Total Distractions - Sum of all distraction counts
- Area Chart - Daily focus time trend
- Bar Chart - Sessions completed per day
- Line Chart - Distraction patterns over time
All data is automatically filtered to show last 7 days only.
import { useFocusStats } from './hooks/useFocusStats';
function MyComponent() {
const { addSession } = useFocusStats();
const addTestSession = () => {
addSession(1500, 2); // 25 min session with 2 distractions
};
return <button onClick={addTestSession}>Add Session</button>;
}const { clearSessions } = useFocusStats();
// Remove all stored sessions
clearSessions();const { sessions } = useFocusStats();
// Get sessions from specific date
const todaySessions = sessions.filter(session => {
const sessionDate = new Date(session.date).toDateString();
const today = new Date().toDateString();
return sessionDate === today;
});
// Get sessions longer than 30 minutes
const longSessions = sessions.filter(s => s.duration >= 1800);
// Get sessions with no distractions
const perfectSessions = sessions.filter(s => s.distractions === 0);Use the built-in Dev Tools tab to test with sample data:
- Navigate to Dev Tools tab (if available)
- Click Generate Sample Data
- View automatically generated sessions in Dashboard
- Click Clear All Data to reset
- localStorage is per-domain - Data only available on the same domain/port
- Data is per-browser - Different browsers have separate storage
- Incognito mode - Data clears when incognito session ends
- Storage limit - ~5-10MB per domain (thousands of sessions)
- All data stored locally in your browser
- No server uploads - Your data never leaves your device
- No tracking - No analytics or external services
- Clear data anytime via Dev Tools or browser settings
Option 1: Via App
const { clearSessions } = useFocusStats();
clearSessions();Option 2: Via Console
localStorage.removeItem('focusSessions');Option 3: Browser Settings
- Chrome: Settings → Privacy → Clear browsing data → Cookies and site data
- Firefox: Settings → Privacy → Clear Data → Cookies and Site Data
[
{
"id": 1728936420000,
"date": "2025-10-14T10:27:00.000Z",
"duration": 1500,
"distractions": 0
},
{
"id": 1728937320000,
"date": "2025-10-14T10:42:00.000Z",
"duration": 3000,
"distractions": 1
},
{
"id": 1728938220000,
"date": "2025-10-14T10:57:00.000Z",
"duration": 5400,
"distractions": 3
}
]✅ Automatic - Sessions save without user action
✅ Persistent - Data survives browser restarts
✅ Private - All data stays on your device
✅ Fast - Instant read/write operations
✅ Simple - No configuration required
✅ Reliable - Uses browser's native storage API
Start focusing, and your progress will be tracked automatically! 🚀
/src/hooks/useLocalStorage.js- localStorage wrapper/src/hooks/useFocusStats.js- Session management & stats/src/components/Timer.jsx- Traditional timer with persistence/src/components/FocusBubble.jsx- Minimal timer with persistence/src/components/Dashboard.jsx- Data visualization
Last Updated: October 14, 2025
Version: 1.0.0