File size: 3,403 Bytes
c09f67c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
import { create } from "zustand";

interface TimerState {
  // Timer state
  isRunning: boolean;
  elapsedTime: number;
  projectName: string | null;
  projectId: string | null;

  // Internal state
  _intervalId: NodeJS.Timeout | null;
  _originalTitle: string | null;

  // Actions
  setTimerStatus: (status: {
    isRunning: boolean;
    elapsedTime: number;
    projectName: string | null;
    projectId: string | null;
  }) => void;
  tick: () => void;
  startInterval: () => void;
  stopInterval: () => void;
  reset: () => void;
}

// Format time as HH:MM:SS for document title
const formatTime = (seconds: number): string => {
  const h = Math.floor(seconds / 3600);
  const m = Math.floor((seconds % 3600) / 60);
  const s = seconds % 60;
  return `${String(h).padStart(2, "0")}:${String(m).padStart(2, "0")}:${String(s).padStart(2, "0")}`;
};

// Update document title (called from single interval only)
const updateTitle = (elapsedTime: number, projectName: string | null) => {
  if (typeof window === "undefined") return;
  if (projectName) {
    document.title = `${formatTime(elapsedTime)}${projectName} | Midday`;
  }
};

// Restore original title
const restoreTitle = (originalTitle: string | null) => {
  if (typeof window === "undefined") return;
  if (originalTitle) {
    document.title = originalTitle;
  }
};

export const useTimerStore = create<TimerState>()((set, get) => ({
  // Initial state
  isRunning: false,
  elapsedTime: 0,
  projectName: null,
  projectId: null,
  _intervalId: null,
  _originalTitle: null,

  setTimerStatus: (status) => {
    const { isRunning: wasRunning } = get();
    const { isRunning, elapsedTime, projectName, projectId } = status;

    set({ isRunning, elapsedTime, projectName, projectId });

    // Handle interval start/stop based on running state change
    if (isRunning && !wasRunning) {
      get().startInterval();
    } else if (!isRunning && wasRunning) {
      get().stopInterval();
    }

    // Update title immediately when status changes
    if (isRunning && projectName) {
      updateTitle(elapsedTime, projectName);
    }
  },

  tick: () => {
    const { isRunning, elapsedTime, projectName } = get();
    if (!isRunning) return;

    const newElapsedTime = elapsedTime + 1;
    set({ elapsedTime: newElapsedTime });

    // Update document title (single update per second)
    updateTitle(newElapsedTime, projectName);
  },

  startInterval: () => {
    const { _intervalId } = get();

    // Don't start if already running
    if (_intervalId) return;

    // Store original title
    if (typeof window !== "undefined") {
      set({ _originalTitle: document.title });
    }

    // Start the single interval
    const intervalId = setInterval(() => {
      get().tick();
    }, 1000);

    set({ _intervalId: intervalId });
  },

  stopInterval: () => {
    const { _intervalId, _originalTitle } = get();

    if (_intervalId) {
      clearInterval(_intervalId);
      set({ _intervalId: null });
    }

    // Restore original title
    restoreTitle(_originalTitle);
  },

  reset: () => {
    const { _intervalId, _originalTitle } = get();

    if (_intervalId) {
      clearInterval(_intervalId);
    }

    restoreTitle(_originalTitle);

    set({
      isRunning: false,
      elapsedTime: 0,
      projectName: null,
      projectId: null,
      _intervalId: null,
      _originalTitle: null,
    });
  },
}));