PageSourceSearch

https://roxima.io/shared/store_pomodoro.js

js roxima.io collected 2026-10-02 01:57:55 UTC 4,138 bytes, 150 lines download raw bytes

1/**
2 * Pomodoro Store - LocalStorage Wrapper & State Management
3 * Handles history, settings, and day closure.
4 */
5
6import {
7    getProtectedStreak,
8    recordProtectedDayClosure,
9    shouldClearDayClosure
10} from './day_closure.mjs';
11
12const HISTORY_KEY = 'rox_pomo_history';
13const SETTINGS_KEY = 'rox_pomo_settings';
14const CLOSURE_KEY = 'rox_day_closure';
15const CLOSURE_HISTORY_KEY = 'rox_day_closure_history';
16
17const DEFAULT_SETTINGS = {
18    focusTime: 25,
19    shortBreakTime: 5,
20    longBreakTime: 15,
21    longBreakInterval: 4,
22    dailyGoalMin: 120,
23    volume: 50,
24    autoStartPomodoros: false,
25    autoStartBreaks: false,
26    startShortcut: 'space',
27    sleepBedtime: "23:00",
28    sleepWakeup: "07:00"
29};
30
31class PomodoroStore {
32    constructor() {
33        this.bus = null;
34        this.history = this._loadJSON(HISTORY_KEY, []);
35        this.settings = { ...DEFAULT_SETTINGS, ...this._loadJSON(SETTINGS_KEY, {}) };
36        this.dayClosure = this._loadJSON(CLOSURE_KEY, null);
37        this.dayClosureHistory = this._loadJSON(CLOSURE_HISTORY_KEY, []);
38    }
39
40    _loadJSON(key, defaultVal) {
41        try {
42            const raw = localStorage.getItem(key);
43            return raw ? JSON.parse(raw) : defaultVal;
44        } catch (e) {
45            console.error(`PomodoroStore load failed for ${key}`, e);
46            return defaultVal;
47        }
48    }
49
50    _saveJSON(key, value) {
51        try {
52            if (value === null) {
53                localStorage.removeItem(key);
54            } else {
55                localStorage.setItem(key, JSON.stringify(value));
56            }
57        } catch (e) {
58            console.error(`PomodoroStore save failed for ${key}`, e);
59        }
60    }
61
62    setBus(bus) {
63        this.bus = bus;
64    }
65
66    /* History */
67    getHistory() {
68        return this.history;
69    }
70
71    addSession(session) {
72        this.history.push(session);
73        this._saveJSON(HISTORY_KEY, this.history);
74        if (this.bus) this.bus.emit('history:changed', { history: this.history });
75    }
76
77    updateHistory(newHistory) {
78        this.history = newHistory;
79        this._saveJSON(HISTORY_KEY, this.history);
80        if (this.bus) this.bus.emit('history:changed', { history: this.history });
81    }
82
83    /* Settings */
84    getSettings() {
85        return this.settings;
86    }
87
88    updateSettings(newSettings) {
89        this.settings = { ...this.settings, ...newSettings };
90        this._saveJSON(SETTINGS_KEY, this.settings);
91        if (this.bus) this.bus.emit('settings:changed', { settings: this.settings });
92    }
93
94    /* Day Closure */
95    getDayClosure() {
96        this.checkAndClearOldClosure();
97        return this.dayClosure;
98    }
99
100    isDayClosed() {
101        this.checkAndClearOldClosure();
102        return this.dayClosure !== null;
103    }
104
105    checkAndClearOldClosure() {
106        if (shouldClearDayClosure(this.dayClosure)) {
107            this.clearDayClosure();
108        }
109    }
110
111    setDayClosure(closureData) {
112        const result = recordProtectedDayClosure({
113            closure: closureData,
114            closureHistory: this.dayClosureHistory,
115            focusHistory: this.history
116        });
117        this.dayClosure = result.closure;
118        this.dayClosureHistory = result.closureHistory;
119        this._saveJSON(CLOSURE_KEY, this.dayClosure);
120        this._saveJSON(CLOSURE_HISTORY_KEY, this.dayClosureHistory);
121        if (this.bus) {
122            this.bus.emit('closure:changed', {
123                closure: this.dayClosure,
124                protectedStreak: this.getProtectedStreak(),
125                streakAdded: result.streakAdded
126            });
127        }
128        return result;
129    }
130
131    getDayClosureHistory() {
132        return Array.isArray(this.dayClosureHistory) ? [...this.dayClosureHistory] : [];
133    }
134
135    getProtectedStreak() {
136        return getProtectedStreak(this.dayClosureHistory);
137    }
138
139    startNewDay() {
140        this.clearDayClosure();
141    }
142
143    clearDayClosure() {
144        this.dayClosure = null;
145        this._saveJSON(CLOSURE_KEY, null);
146        if (this.bus) this.bus.emit('closure:changed', { closure: null });
147    }
148}
149
150export const pomodoroStore = new PomodoroStore();

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.