Skip to content

Refactor data services and extract utility functions#60

Merged
AdamJ merged 14 commits intomainfrom
claude/project-improvement-recommendations-aoIS5
Mar 22, 2026
Merged

Refactor data services and extract utility functions#60
AdamJ merged 14 commits intomainfrom
claude/project-improvement-recommendations-aoIS5

Conversation

@AdamJ
Copy link
Owner

@AdamJ AdamJ commented Mar 20, 2026

Summary

This PR refactors the monolithic dataService.ts file by extracting service implementations and utility functions into separate, focused modules. The changes improve code organization, maintainability, and reusability without altering functionality.

Key Changes

Service Layer Refactoring

  • Split dataService.ts: Extracted LocalStorageService and SupabaseService implementations into dedicated files (localStorageService.ts and supabaseService.ts)
  • Simplified main service file: dataService.ts now serves as a clean interface/facade, exporting only the DataService interface and CurrentDayData type
  • Maintained backward compatibility: All exports remain available through the main service file

Utility Function Extraction

  • Created calculationUtils.ts: Extracted calculation functions for hours and revenue:

    • getHoursWorkedForDay()
    • getRevenueForDay()
    • getBillableHoursForDay()
    • getNonBillableHoursForDay()
    • getTotalHoursForPeriod()
    • getRevenueForPeriod()
  • Created exportUtils.ts: Extracted export and invoice generation functions:

    • exportToCSV()
    • exportToJSON()
    • generateInvoiceData()
    • parseCSVImport()

Component Refactoring

  • Extracted TaskEditInArchiveDialog: Moved from ArchiveEditDialog.tsx to its own component file for better separation of concerns
  • Updated imports: ArchiveEditDialog.tsx now imports the extracted component

Context Updates

  • Updated TimeTrackingContext.tsx: Refactored to use extracted utility functions instead of inline implementations
  • Cleaner context code: Calculation logic now delegates to utility functions, reducing context complexity

Implementation Details

  • All extracted functions maintain their original logic and behavior
  • Utility functions are pure and accept necessary data as parameters
  • Service classes remain unchanged in functionality, only relocated
  • Storage keys are now exported from localStorageService.ts for centralized management

https://claude.ai/code/session_012AmNjF3Ju9VJwSWybJqBEw

claude added 10 commits March 20, 2026 19:46
Extract LocalStorageService and SupabaseService classes into their own
files, reducing dataService.ts from 1,267 lines to a thin interface +
factory module (~45 lines). All public exports remain backward compatible.

https://claude.ai/code/session_012AmNjF3Ju9VJwSWybJqBEw
Move all billing/duration calculation functions into a dedicated
calculationUtils.ts as pure functions, removing ~100 lines from
TimeTrackingContext. Context methods now delegate to these utilities.

https://claude.ai/code/session_012AmNjF3Ju9VJwSWybJqBEw
Move exportToCSV, exportToJSON, generateInvoiceData, and CSV parsing
logic into exportUtils.ts as pure functions, removing ~350 lines from
TimeTrackingContext. Context methods now delegate to these utilities.

https://claude.ai/code/session_012AmNjF3Ju9VJwSWybJqBEw
Move the task-editing dialog from ArchiveEditDialog.tsx into a dedicated
TaskEditInArchiveDialog.tsx, reducing ArchiveEditDialog from 850 to ~270
lines. Unused Select imports are removed from ArchiveEditDialog.

https://claude.ai/code/session_012AmNjF3Ju9VJwSWybJqBEw
OfflineContext.processQueue was a stub that looped over queued actions
without executing any of them, silently dropping all offline changes.

Fix: when the app comes back online, processQueue now dispatches a
'timetracker:sync-required' custom DOM event and clears the queue.
TimeTrackingContext listens for this event and calls forceSyncToDatabase,
pushing all in-memory React state to Supabase. Only triggers when the
user is authenticated (Supabase mode).

Also fixes the eslint-disable comment on the online/offline effect that
was masking a legitimate missing dependency (processQueue).

https://claude.ai/code/session_012AmNjF3Ju9VJwSWybJqBEw
…rites

In saveCurrentDay, saveArchivedDays, and updateArchivedDay, the project_id
field was set as `project?.id || task.project || null`. When a project
wasn't found by name (e.g. after renaming or deletion), this fell back to
writing the project *name string* into a UUID column, silently corrupting
the database record.

Fix: use `project?.id || null` — if the project can't be resolved, store
null rather than an invalid value. project_name already preserves the
display name for historical reference.

https://claude.ai/code/session_012AmNjF3Ju9VJwSWybJqBEw
…abaseService

Remove debug logging from the two highest-volume files (40 and 65 logs
respectively). console.error and console.warn calls are preserved.

https://claude.ai/code/session_012AmNjF3Ju9VJwSWybJqBEw
Remove debug logging from AuthContext, OfflineContext, dataService,
supabase lib, useRealtimeSync, Index, UpdateNotification, and
InstallPrompt. Empty if/else blocks that contained only a console.log
are also removed. console.error and console.warn are preserved throughout.

https://claude.ai/code/session_012AmNjF3Ju9VJwSWybJqBEw
Remove stray `});` in supabaseService.ts getArchivedDays (leftover from
removed multi-line console.log call) and empty else blocks in
TimeTrackingContext.tsx and supabaseService.ts that triggered no-empty
lint errors.

https://claude.ai/code/session_012AmNjF3Ju9VJwSWybJqBEw
@cloudflare-workers-and-pages
Copy link

cloudflare-workers-and-pages bot commented Mar 22, 2026

Deploying timetrackerpro with  Cloudflare Pages  Cloudflare Pages

Latest commit: b3d577d
Status: ✅  Deploy successful!
Preview URL: https://6058dd28.timetrackerpro.pages.dev
Branch Preview URL: https://claude-project-improvement-r.timetrackerpro.pages.dev

View logs

@AdamJ AdamJ self-assigned this Mar 22, 2026
@AdamJ AdamJ added the enhancement New feature or request label Mar 22, 2026
claude added 4 commits March 22, 2026 14:16
- Delete src/hooks/.useReportSummary-Claude.ts (unused, exposed API key)
- Delete src/utils/supabase.ts (duplicate Supabase client, never imported)
- Delete src/hooks/useRealtimeSync.ts (body fully disabled, never called)
- Delete src/hooks/useOffline.tsx (hook never called anywhere)
- Remove saveCurrentDayRef from TimeTrackingContext (useRef never assigned)
- Remove useRealtimeSync import and commented-out call from TimeTrackingContext
- Remove SYNC_REQUIRED_EVENT import and dead listener from TimeTrackingContext
- Strip OfflineContext down to isOnline + online/offline toasts; remove
  addToQueue, offlineQueue, processQueue, and SYNC_REQUIRED_EVENT which
  were never wired up to any data operations

https://claude.ai/code/session_012AmNjF3Ju9VJwSWybJqBEw
- Add [Unreleased] Removed section listing all six deleted/stripped items
- Correct stale "real-time sync" feature claim in [0.21.1] entry
- Remove deleted useRealtimeSync() entry from custom hooks list in architecture.md

https://claude.ai/code/session_012AmNjF3Ju9VJwSWybJqBEw
…fety

1. Online reconnection no longer triggers sync (TimeTrackingContext)
   - After the offline-queue dead code removal, no mechanism remained to
     call forceSyncToDatabase() when the browser comes back online.
   - Add a 'online' window event listener in TimeTrackingContext that calls
     forceSyncToDatabase() when the user is authenticated. Mirrors the
     existing 'beforeunload' handler pattern.

2. trackAuthCall stores no log details (src/lib/supabase.ts)
   - The function incremented authCallCount but created a timestamp variable
     it never used and pushed nothing to dbCallLog, making auth call
     debugging impossible.
   - Complete the implementation to match trackDbCall: push a log entry to
     dbCallLog with timestamp, operation, and stack-derived source.

3. data.tasks crash on malformed localStorage record (localStorageService.ts)
   - getCurrentDay() called data.tasks.map() without a null guard. When a
     stored record is missing the tasks field the call throws and the outer
     try-catch silently swallows the entire day, returning null.
   - Replace with (data.tasks ?? []).map() so a missing field produces an
     empty task list instead of an exception.

https://claude.ai/code/session_012AmNjF3Ju9VJwSWybJqBEw
@AdamJ AdamJ merged commit 453a165 into main Mar 22, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants