import { getTimerState, getEntries, getSettings, getTodayEntries, formatDurationShort, formatDuration, formatTime, } from '../storage.js' import type { TimerState } from '../types.js' let timerInterval: ReturnType | null = null let currentState: TimerState | null = null const els = { display: document.getElementById('timer-display') as HTMLDivElement, toggleBtn: document.getElementById('toggle-btn') as HTMLButtonElement, descInput: document.getElementById('desc-input') as HTMLInputElement, clientInput: document.getElementById('client-input') as HTMLInputElement, projectInput: document.getElementById('project-input') as HTMLInputElement, entriesList: document.getElementById('entries-list') as HTMLDivElement, todayTotal: document.getElementById('today-total') as HTMLDivElement, } async function init(): Promise { const [state, settings] = await Promise.all([getTimerState(), getSettings()]) currentState = state // Pre-fill inputs with defaults els.clientInput.value = state.client || settings.defaultClient els.projectInput.value = state.project || settings.defaultProject els.descInput.value = state.description || '' updateUI(state) await renderEntries() // Auto-save inputs to timer state els.descInput.addEventListener('input', debounce(saveInputs, 300)) els.clientInput.addEventListener('input', debounce(saveInputs, 300)) els.projectInput.addEventListener('input', debounce(saveInputs, 300)) els.toggleBtn.addEventListener('click', onToggle) } function updateUI(state: TimerState): void { if (state.running && state.startTime) { els.display.classList.add('running') els.toggleBtn.textContent = 'Stop Timer' els.toggleBtn.classList.add('stop') startTicking(state.startTime) } else { els.display.classList.remove('running') els.toggleBtn.textContent = 'Start Timer' els.toggleBtn.classList.remove('stop') stopTicking() els.display.textContent = '0:00' } } function startTicking(startTime: number): void { stopTicking() const tick = () => { const elapsed = Date.now() - startTime els.display.textContent = formatDurationShort(elapsed) } tick() timerInterval = setInterval(tick, 1000) } function stopTicking(): void { if (timerInterval) { clearInterval(timerInterval) timerInterval = null } } async function saveInputs(): Promise { if (!currentState) return await chrome.runtime.sendMessage({ type: 'UPDATE_TIMER_DESCRIPTION', payload: { description: els.descInput.value, client: els.clientInput.value, project: els.projectInput.value, }, }) } async function onToggle(): Promise { if (!currentState) return if (currentState.running) { // Stop els.toggleBtn.disabled = true const result = await chrome.runtime.sendMessage({ type: 'STOP_TIMER' }) if (result.error) { console.error(result.error) els.toggleBtn.disabled = false return } currentState = result.state if (!currentState) return updateUI(currentState) await renderEntries() els.toggleBtn.disabled = false } else { // Start els.toggleBtn.disabled = true const result = await chrome.runtime.sendMessage({ type: 'START_TIMER', payload: { description: els.descInput.value, client: els.clientInput.value, project: els.projectInput.value, }, }) if (result.error) { console.error(result.error) els.toggleBtn.disabled = false return } currentState = result if (!currentState) return updateUI(currentState) els.toggleBtn.disabled = false } } async function renderEntries(): Promise { const allEntries = await getEntries() const today = getTodayEntries(allEntries) if (today.length === 0) { els.entriesList.innerHTML = '

No time tracked yet today.

' els.todayTotal.textContent = '' return } const totalMs = today.reduce((sum, e) => sum + e.duration, 0) els.entriesList.innerHTML = today.map((entry) => `
${formatDurationShort(entry.duration)}
`).join('') els.todayTotal.textContent = `Total: ${formatDuration(totalMs)}` } function escapeHtml(text: string): string { const div = document.createElement('div') div.textContent = text return div.innerHTML } function debounce void>(fn: T, ms: number): (...args: Parameters) => void { let timeout: ReturnType return (...args: Parameters) => { clearTimeout(timeout) timeout = setTimeout(() => fn(...args), ms) } } init().catch(console.error)