aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/client/sync/queue.ts
diff options
context:
space:
mode:
authornsfisis <nsfisis@gmail.com>2025-12-07 23:34:03 +0900
committernsfisis <nsfisis@gmail.com>2025-12-07 23:34:03 +0900
commit0c042ac89fc0822fcbe09c48702857faa5494ae1 (patch)
treeea1f1d180f747613343040d441a07f92b2760840 /src/client/sync/queue.ts
parentae5a0bb97fbf013417a6962f7e077f0408b2a951 (diff)
downloadkioku-0c042ac89fc0822fcbe09c48702857faa5494ae1.tar.gz
kioku-0c042ac89fc0822fcbe09c48702857faa5494ae1.tar.zst
kioku-0c042ac89fc0822fcbe09c48702857faa5494ae1.zip
feat(client): add sync status indicator component
Add SyncStatusIndicator component to display current sync state in the UI header. The component shows online/offline status, syncing progress, pending changes count, and sync errors. - Create SyncProvider context to wrap SyncManager for React components - Add SyncStatusIndicator component with visual status indicators - Integrate indicator into HomePage header - Add comprehensive tests for SyncStatusIndicator and SyncProvider - Update existing tests to include SyncProvider wrapper 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Diffstat (limited to 'src/client/sync/queue.ts')
-rw-r--r--src/client/sync/queue.ts71
1 files changed, 46 insertions, 25 deletions
diff --git a/src/client/sync/queue.ts b/src/client/sync/queue.ts
index f0b112a..01c62cc 100644
--- a/src/client/sync/queue.ts
+++ b/src/client/sync/queue.ts
@@ -1,4 +1,9 @@
-import { db, type LocalCard, type LocalDeck, type LocalReviewLog } from "../db/index";
+import {
+ db,
+ type LocalCard,
+ type LocalDeck,
+ type LocalReviewLog,
+} from "../db/index";
import {
localCardRepository,
localDeckRepository,
@@ -41,7 +46,10 @@ const SYNC_STATE_KEY = "kioku_sync_state";
/**
* Load sync state from localStorage
*/
-function loadSyncState(): Pick<SyncQueueState, "lastSyncVersion" | "lastSyncAt"> {
+function loadSyncState(): Pick<
+ SyncQueueState,
+ "lastSyncVersion" | "lastSyncAt"
+> {
const stored = localStorage.getItem(SYNC_STATE_KEY);
if (!stored) {
return { lastSyncVersion: 0, lastSyncAt: null };
@@ -137,7 +145,9 @@ export class SyncQueue {
*/
async getPendingCount(): Promise<number> {
const changes = await this.getPendingChanges();
- return changes.decks.length + changes.cards.length + changes.reviewLogs.length;
+ return (
+ changes.decks.length + changes.cards.length + changes.reviewLogs.length
+ );
}
/**
@@ -205,17 +215,24 @@ export class SyncQueue {
cards: { id: string; syncVersion: number }[];
reviewLogs: { id: string; syncVersion: number }[];
}): Promise<void> {
- await db.transaction("rw", [db.decks, db.cards, db.reviewLogs], async () => {
- for (const deck of results.decks) {
- await localDeckRepository.markSynced(deck.id, deck.syncVersion);
- }
- for (const card of results.cards) {
- await localCardRepository.markSynced(card.id, card.syncVersion);
- }
- for (const reviewLog of results.reviewLogs) {
- await localReviewLogRepository.markSynced(reviewLog.id, reviewLog.syncVersion);
- }
- });
+ await db.transaction(
+ "rw",
+ [db.decks, db.cards, db.reviewLogs],
+ async () => {
+ for (const deck of results.decks) {
+ await localDeckRepository.markSynced(deck.id, deck.syncVersion);
+ }
+ for (const card of results.cards) {
+ await localCardRepository.markSynced(card.id, card.syncVersion);
+ }
+ for (const reviewLog of results.reviewLogs) {
+ await localReviewLogRepository.markSynced(
+ reviewLog.id,
+ reviewLog.syncVersion,
+ );
+ }
+ },
+ );
await this.notifyListeners();
}
@@ -227,17 +244,21 @@ export class SyncQueue {
cards: LocalCard[];
reviewLogs: LocalReviewLog[];
}): Promise<void> {
- await db.transaction("rw", [db.decks, db.cards, db.reviewLogs], async () => {
- for (const deck of data.decks) {
- await localDeckRepository.upsertFromServer(deck);
- }
- for (const card of data.cards) {
- await localCardRepository.upsertFromServer(card);
- }
- for (const reviewLog of data.reviewLogs) {
- await localReviewLogRepository.upsertFromServer(reviewLog);
- }
- });
+ await db.transaction(
+ "rw",
+ [db.decks, db.cards, db.reviewLogs],
+ async () => {
+ for (const deck of data.decks) {
+ await localDeckRepository.upsertFromServer(deck);
+ }
+ for (const card of data.cards) {
+ await localCardRepository.upsertFromServer(card);
+ }
+ for (const reviewLog of data.reviewLogs) {
+ await localReviewLogRepository.upsertFromServer(reviewLog);
+ }
+ },
+ );
await this.notifyListeners();
}