Skip to content

Conversation

@ShivaGupta-14
Copy link
Contributor

Description

This PR implements a "local-first" architecture for task modifications. When a task is added, edited, completed, or deleted, the change is saved immediately to the local IndexedDB (Dexie) and reflected in the UI instantly, rather than waiting for the backend response.

Architecture Decision:
To ensure the main database schema remains pure and to avoid migration risks, this implementation uses localStorage to track the UUIDs of modified tasks. This ensures the "Unsynced" status persists across page reloads without polluting the core data model.

Key Changes

  • Optimistic Writes: handleAddTask, handleSaveClick, and other modification handlers now update the local DB and localStorage immediately before triggering the background API call.
  • State Management: Added getUnsyncedFromStorage and saveUnsyncedToStorage helpers to initialize React state and persist dirty items.
  • Visual Indicators:
    • Adds a red "Unsynced" badge to task rows found in the local storage set.
    • Adds a notification counter to the "Sync" button showing the exact number of pending items.
    • Displays a - in the ID column for newly created local tasks (hiding the temporary negative ID) for a cleaner look.
  • Sync Logic: Updated syncTasksWithTwAndDb to automatically clear the localStorage tracking upon a successful full sync.
  • Testing: Updated Tasks.test.tsx to mock localStorage and validate the badge visibility, ID formatting, and pagination logic.

Checklist

  • Ran npx prettier --write . (for formatting)
  • Ran gofmt -w . (for Go backend)
  • Ran npm test (for JS/TS testing)
  • Added unit tests, if applicable
  • Verified all tests pass
  • Updated documentation, if needed

Additional Notes

Video: Link to see changes

Adds visual indicators for tasks modified locally but not yet synced
with the backend.

Implementation details:
- Uses `localStorage` to track dirty UUIDs (keeps IndexedDB schema clean).
- Adds "Unsynced" badge to task rows.
- Adds a notification counter badge to the Sync button.
- Masks temporary negative IDs with a dash in the UI.
- Updates tasks optimistically for instant UI feedback.
- Clears unsynced status automatically upon successful sync.
Copy link
Collaborator

@its-me-abhishek its-me-abhishek left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Still, imho using IndexedDB, or any type of extra storage to store UUIDs of unsynced tasks is a waste of resources.
It would be just better if only a singular state is used inside the Tasks component to do this instead.
With just another addition that the tasks are automatically synced on the first load - which is yet to be done, as discussed.

} from './hooks';
import { debounce } from '@/components/utils/utils';

const STORAGE_KEY = 'ccsync_unsynced_uuids';
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this will fail in multi-user setups

@its-me-abhishek
Copy link
Collaborator

Please check it out and revert these changes

@ShivaGupta-14
Copy link
Contributor Author

@its-me-abhishek

Okay, thank you for the clarification, I completely understand the goal now. You're absolutely right about the localStorage key failing in multi-user setups. That's a bug I missed.

My goal was to make the 'Unsynced' badge persist on page refresh, but I see your point now: if the app will auto-sync on load, that persistence isn't necessary.

So, just to confirm the new plan:

  • I will remove all localStorage logic.
  • I will use only a simple React state (useState(new Set())) to track the unsynced UUIDs for the current session.
  • This means the 'Unsynced' badges will disappear on page refresh, which is now the expected behavior.

This is a much simpler change. Does this sound correct?

@its-me-abhishek
Copy link
Collaborator

yeah, this makes sense! please go ahead with it

@ShivaGupta-14
Copy link
Contributor Author

ShivaGupta-14 commented Nov 18, 2025

Hey! @its-me-abhishek

I'm closing this PR because it has become quite outdated and cluttered after the recent architectural changes.
To keep the review process clean and avoid confusion, I've opened a fresh PR with a much clearer and updated implementation: link to new PR.

This should make it easier to review without going through old or irrelevant changes.
(I also had a stacked PR on top of this, so reorganizing was the cleanest approach.)

Once this new PR is merged, I will open a separate PR for the fuzzy search feature as discussed, so each change stays well-scoped and easy to review.

Thanks for your understanding - trying to keep the contributions clean and maintainable!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Visual Indicator for Modified / Unsynced Tasks on Frontend

2 participants