From b074a4901c630ee5c5f7dcff79fa6ff911a14ded Mon Sep 17 00:00:00 2001 From: nsfisis Date: Wed, 31 Dec 2025 14:19:22 +0900 Subject: feat(schema): make note_id and is_reversed NOT NULL MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit All cards now require note association - legacy card support removed. This aligns with the note-based card architecture introduced in Phase 8. - Add database migration for NOT NULL constraints - Update client Dexie schema to version 3 - Remove LegacyCardItem component and legacy card handling - Update sync schemas and type definitions - Update all tests to use note-based cards ๐Ÿค– Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- src/client/components/DeleteNoteModal.test.tsx | 24 ++-- src/client/db/index.test.ts | 4 +- src/client/db/index.ts | 16 ++- src/client/db/repositories.test.ts | 26 ++++- src/client/db/repositories.ts | 7 +- src/client/pages/DeckDetailPage.test.tsx | 73 ++++-------- src/client/pages/DeckDetailPage.tsx | 156 ++++--------------------- src/client/pages/StudyPage.tsx | 8 +- src/client/sync/conflict.test.ts | 12 ++ src/client/sync/conflict.ts | 4 +- src/client/sync/pull.test.ts | 16 ++- src/client/sync/pull.ts | 8 +- src/client/sync/push.test.ts | 18 ++- src/client/sync/push.ts | 4 +- src/client/sync/queue.test.ts | 18 ++- 15 files changed, 155 insertions(+), 239 deletions(-) (limited to 'src/client') diff --git a/src/client/components/DeleteNoteModal.test.tsx b/src/client/components/DeleteNoteModal.test.tsx index 85aaa14..a17323a 100644 --- a/src/client/components/DeleteNoteModal.test.tsx +++ b/src/client/components/DeleteNoteModal.test.tsx @@ -175,7 +175,7 @@ describe("DeleteNoteModal", () => { const user = userEvent.setup(); // Create a promise that we can control - let resolveDelete: (value: unknown) => void; + let resolveDelete: ((value: unknown) => void) | undefined; const deletePromise = new Promise((resolve) => { resolveDelete = resolve; }); @@ -190,19 +190,17 @@ describe("DeleteNoteModal", () => { expect(screen.getByText("Deleting...")).toBeDefined(); // Resolve the delete request to cleanup - if (resolveDelete) { - resolveDelete({ - ok: true, - json: async () => ({ success: true }), - }); - } + resolveDelete?.({ + ok: true, + json: async () => ({ success: true }), + }); }); it("disables buttons while deleting", async () => { const user = userEvent.setup(); // Create a promise that we can control - let resolveDelete: (value: unknown) => void; + let resolveDelete: ((value: unknown) => void) | undefined; const deletePromise = new Promise((resolve) => { resolveDelete = resolve; }); @@ -224,11 +222,9 @@ describe("DeleteNoteModal", () => { ); // Resolve the delete request to cleanup - if (resolveDelete) { - resolveDelete({ - ok: true, - json: async () => ({ success: true }), - }); - } + resolveDelete?.({ + ok: true, + json: async () => ({ success: true }), + }); }); }); diff --git a/src/client/db/index.test.ts b/src/client/db/index.test.ts index a30f94b..0a4882d 100644 --- a/src/client/db/index.test.ts +++ b/src/client/db/index.test.ts @@ -132,8 +132,8 @@ describe("KiokuDatabase", () => { const testCard: LocalCard = { id: "card-1", deckId: "deck-1", - noteId: null, - isReversed: null, + noteId: "test-note-id", + isReversed: false, front: "Question", back: "Answer", state: CardState.New, diff --git a/src/client/db/index.ts b/src/client/db/index.ts index 5318b17..53df476 100644 --- a/src/client/db/index.ts +++ b/src/client/db/index.ts @@ -122,8 +122,8 @@ export interface LocalNoteFieldValue { export interface LocalCard { id: string; deckId: string; - noteId: string | null; - isReversed: boolean | null; + noteId: string; + isReversed: boolean; front: string; back: string; @@ -241,6 +241,18 @@ export class KiokuDatabase extends Dexie { } }); }); + + // Version 3: noteId and isReversed are now required (NOT NULL) + // No migration needed as production has no legacy data without notes + this.version(3).stores({ + decks: "id, userId, updatedAt", + cards: "id, deckId, noteId, updatedAt, due, state", + reviewLogs: "id, cardId, userId, reviewedAt", + noteTypes: "id, userId, updatedAt", + noteFieldTypes: "id, noteTypeId, updatedAt", + notes: "id, deckId, noteTypeId, updatedAt", + noteFieldValues: "id, noteId, noteFieldTypeId, updatedAt", + }); } } diff --git a/src/client/db/repositories.test.ts b/src/client/db/repositories.test.ts index 2fca210..da0f0d3 100644 --- a/src/client/db/repositories.test.ts +++ b/src/client/db/repositories.test.ts @@ -240,6 +240,8 @@ describe("localCardRepository", () => { it("should create a card with FSRS defaults", async () => { const card = await localCardRepository.create({ deckId, + noteId: "test-note-id", + isReversed: false, front: "Question", back: "Answer", }); @@ -260,8 +262,8 @@ describe("localCardRepository", () => { describe("findByDeckId", () => { it("should return all cards for a deck", async () => { - await localCardRepository.create({ deckId, front: "Q1", back: "A1" }); - await localCardRepository.create({ deckId, front: "Q2", back: "A2" }); + await localCardRepository.create({ deckId, noteId: "test-note-id", isReversed: false, front: "Q1", back: "A1" }); + await localCardRepository.create({ deckId, noteId: "test-note-id-2", isReversed: false, front: "Q2", back: "A2" }); const cards = await localCardRepository.findByDeckId(deckId); expect(cards).toHaveLength(2); @@ -270,6 +272,8 @@ describe("localCardRepository", () => { it("should exclude soft-deleted cards", async () => { const card = await localCardRepository.create({ deckId, + noteId: "test-note-id", + isReversed: false, front: "Q", back: "A", }); @@ -287,6 +291,8 @@ describe("localCardRepository", () => { const card1 = await localCardRepository.create({ deckId, + noteId: "test-note-id", + isReversed: false, front: "Due", back: "A", }); @@ -294,6 +300,8 @@ describe("localCardRepository", () => { const card2 = await localCardRepository.create({ deckId, + noteId: "test-note-id-2", + isReversed: false, front: "Not Due", back: "B", }); @@ -308,6 +316,8 @@ describe("localCardRepository", () => { for (let i = 0; i < 5; i++) { await localCardRepository.create({ deckId, + noteId: `test-note-id-${i}`, + isReversed: false, front: `Q${i}`, back: `A${i}`, }); @@ -322,12 +332,16 @@ describe("localCardRepository", () => { it("should return only new cards", async () => { await localCardRepository.create({ deckId, + noteId: "test-note-id", + isReversed: false, front: "New", back: "A", }); const reviewedCard = await localCardRepository.create({ deckId, + noteId: "test-note-id-2", + isReversed: false, front: "Reviewed", back: "B", }); @@ -343,6 +357,8 @@ describe("localCardRepository", () => { it("should update card content", async () => { const card = await localCardRepository.create({ deckId, + noteId: "test-note-id", + isReversed: false, front: "Original", back: "Original", }); @@ -362,6 +378,8 @@ describe("localCardRepository", () => { it("should update FSRS scheduling data", async () => { const card = await localCardRepository.create({ deckId, + noteId: "test-note-id", + isReversed: false, front: "Q", back: "A", }); @@ -391,6 +409,8 @@ describe("localCardRepository", () => { it("should soft delete a card", async () => { const card = await localCardRepository.create({ deckId, + noteId: "test-note-id", + isReversed: false, front: "Q", back: "A", }); @@ -423,6 +443,8 @@ describe("localReviewLogRepository", () => { const card = await localCardRepository.create({ deckId, + noteId: "test-note-id", + isReversed: false, front: "Q", back: "A", }); diff --git a/src/client/db/repositories.ts b/src/client/db/repositories.ts index 104f026..e01254e 100644 --- a/src/client/db/repositories.ts +++ b/src/client/db/repositories.ts @@ -176,8 +176,6 @@ export const localCardRepository = { data: Omit< LocalCard, | "id" - | "noteId" - | "isReversed" | "state" | "due" | "stability" @@ -192,14 +190,11 @@ export const localCardRepository = { | "deletedAt" | "syncVersion" | "_synced" - > & - Partial>, + >, ): Promise { const now = new Date(); const card: LocalCard = { id: uuidv4(), - noteId: null, - isReversed: null, ...data, state: CardState.New, due: now, diff --git a/src/client/pages/DeckDetailPage.test.tsx b/src/client/pages/DeckDetailPage.test.tsx index 35303d9..e02302f 100644 --- a/src/client/pages/DeckDetailPage.test.tsx +++ b/src/client/pages/DeckDetailPage.test.tsx @@ -51,13 +51,13 @@ const mockDeck = { updatedAt: "2024-01-01T00:00:00Z", }; -// Legacy cards (no noteId) for backward compatibility testing -const mockLegacyCards = [ +// Basic note-based cards (each with its own note) +const mockBasicCards = [ { id: "card-1", deckId: "deck-1", - noteId: null, - isReversed: null, + noteId: "note-1", + isReversed: false, front: "Hello", back: "ใ“ใ‚“ใซใกใฏ", state: 0, @@ -77,8 +77,8 @@ const mockLegacyCards = [ { id: "card-2", deckId: "deck-1", - noteId: null, - isReversed: null, + noteId: "note-2", + isReversed: false, front: "Goodbye", back: "ใ•ใ‚ˆใ†ใชใ‚‰", state: 2, @@ -143,11 +143,8 @@ const mockNoteBasedCards = [ }, ]; -// Mixed cards (both legacy and note-based) -const mockMixedCards = [...mockLegacyCards, ...mockNoteBasedCards]; - -// Alias for backward compatibility in existing tests -const mockCards = mockLegacyCards; +// Alias for existing tests +const mockCards = mockBasicCards; function renderWithProviders(path = "/decks/deck-1") { const { hook } = memoryLocation({ path, static: true }); @@ -430,8 +427,8 @@ describe("DeckDetailPage", () => { expect(screen.queryByText("Common Japanese words")).toBeNull(); }); - describe("Delete Card", () => { - it("shows Delete button for each card", async () => { + describe("Delete Note", () => { + it("shows Delete button for each note", async () => { mockFetch .mockResolvedValueOnce({ ok: true, @@ -449,7 +446,7 @@ describe("DeckDetailPage", () => { }); const deleteButtons = screen.getAllByRole("button", { - name: "Delete card", + name: "Delete note", }); expect(deleteButtons.length).toBe(2); }); @@ -474,7 +471,7 @@ describe("DeckDetailPage", () => { }); const deleteButtons = screen.getAllByRole("button", { - name: "Delete card", + name: "Delete note", }); const firstDeleteButton = deleteButtons[0]; if (firstDeleteButton) { @@ -483,7 +480,7 @@ describe("DeckDetailPage", () => { expect(screen.getByRole("dialog")).toBeDefined(); expect( - screen.getByRole("heading", { name: "Delete Card" }), + screen.getByRole("heading", { name: "Delete Note" }), ).toBeDefined(); }); @@ -507,7 +504,7 @@ describe("DeckDetailPage", () => { }); const deleteButtons = screen.getAllByRole("button", { - name: "Delete card", + name: "Delete note", }); const firstDeleteButton = deleteButtons[0]; if (firstDeleteButton) { @@ -521,7 +518,7 @@ describe("DeckDetailPage", () => { expect(screen.queryByRole("dialog")).toBeNull(); }); - it("deletes card and refreshes list on confirmation", async () => { + it("deletes note and refreshes list on confirmation", async () => { const user = userEvent.setup(); mockFetch @@ -537,7 +534,7 @@ describe("DeckDetailPage", () => { // Delete request .mockResolvedValueOnce({ ok: true, - json: async () => ({}), + json: async () => ({ success: true }), }) // Refresh cards after deletion .mockResolvedValueOnce({ @@ -552,7 +549,7 @@ describe("DeckDetailPage", () => { }); const deleteButtons = screen.getAllByRole("button", { - name: "Delete card", + name: "Delete note", }); const firstDeleteButton = deleteButtons[0]; if (firstDeleteButton) { @@ -575,8 +572,8 @@ describe("DeckDetailPage", () => { expect(screen.queryByRole("dialog")).toBeNull(); }); - // Verify DELETE request was made - expect(mockFetch).toHaveBeenCalledWith("/api/decks/deck-1/cards/card-1", { + // Verify DELETE request was made to notes endpoint + expect(mockFetch).toHaveBeenCalledWith("/api/decks/deck-1/notes/note-1", { method: "DELETE", headers: { Authorization: "Bearer access-token" }, }); @@ -604,7 +601,7 @@ describe("DeckDetailPage", () => { .mockResolvedValueOnce({ ok: false, status: 500, - json: async () => ({ error: "Failed to delete card" }), + json: async () => ({ error: "Failed to delete note" }), }); renderWithProviders(); @@ -614,7 +611,7 @@ describe("DeckDetailPage", () => { }); const deleteButtons = screen.getAllByRole("button", { - name: "Delete card", + name: "Delete note", }); const firstDeleteButton = deleteButtons[0]; if (firstDeleteButton) { @@ -635,7 +632,7 @@ describe("DeckDetailPage", () => { // Error should be displayed in the modal await waitFor(() => { expect(screen.getByRole("alert").textContent).toContain( - "Failed to delete card", + "Failed to delete note", ); }); }); @@ -665,32 +662,6 @@ describe("DeckDetailPage", () => { expect(noteCards.length).toBe(2); }); - it("displays legacy cards separately from note groups", async () => { - mockFetch - .mockResolvedValueOnce({ - ok: true, - json: async () => ({ deck: mockDeck }), - }) - .mockResolvedValueOnce({ - ok: true, - json: async () => ({ cards: mockMixedCards }), - }); - - renderWithProviders(); - - await waitFor(() => { - // Should show both note groups and legacy cards - expect(screen.getByTestId("note-group")).toBeDefined(); - }); - - const legacyCards = screen.getAllByTestId("legacy-card"); - expect(legacyCards.length).toBe(2); // 2 legacy cards - - // Should show "Legacy" badge for legacy cards - const legacyBadges = screen.getAllByText("Legacy"); - expect(legacyBadges.length).toBe(2); - }); - it("shows Normal and Reversed badges for note-based cards", async () => { mockFetch .mockResolvedValueOnce({ diff --git a/src/client/pages/DeckDetailPage.tsx b/src/client/pages/DeckDetailPage.tsx index 87f9dc3..d018d1f 100644 --- a/src/client/pages/DeckDetailPage.tsx +++ b/src/client/pages/DeckDetailPage.tsx @@ -21,8 +21,8 @@ import { EditNoteModal } from "../components/EditNoteModal"; interface Card { id: string; deckId: string; - noteId: string | null; - isReversed: boolean | null; + noteId: string; + isReversed: boolean; front: string; back: string; state: number; @@ -33,10 +33,8 @@ interface Card { updatedAt: string; } -/** Combined type for display: either a note group or a legacy card */ -type CardDisplayItem = - | { type: "note"; noteId: string; cards: Card[] } - | { type: "legacy"; card: Card }; +/** Combined type for display: note group */ +type CardDisplayItem = { type: "note"; noteId: string; cards: Card[] }; interface Deck { id: string; @@ -178,95 +176,6 @@ function NoteGroupCard({ ); } -/** Component for displaying a legacy card (without note association) */ -function LegacyCardItem({ - card, - index, - onEdit, - onDelete, -}: { - card: Card; - index: number; - onEdit: () => void; - onDelete: () => void; -}) { - return ( -
-
-
- {/* Front/Back Preview */} -
-
- - Front - -

- {card.front} -

-
-
- - Back - -

- {card.back} -

-
-
- - {/* Card Stats */} -
- - {CardStateLabels[card.state] || "Unknown"} - - - Legacy - - {card.reps} reviews - {card.lapses > 0 && ( - {card.lapses} lapses - )} -
-
- - {/* Actions */} -
- - -
-
-
- ); -} - export function DeckDetailPage() { const { deckId } = useParams<{ deckId: string }>(); const [deck, setDeck] = useState(null); @@ -282,24 +191,17 @@ export function DeckDetailPage() { // Group cards by note for display const displayItems = useMemo((): CardDisplayItem[] => { const noteGroups = new Map(); - const legacyCards: Card[] = []; for (const card of cards) { - if (card.noteId) { - const existing = noteGroups.get(card.noteId); - if (existing) { - existing.push(card); - } else { - noteGroups.set(card.noteId, [card]); - } + const existing = noteGroups.get(card.noteId); + if (existing) { + existing.push(card); } else { - legacyCards.push(card); + noteGroups.set(card.noteId, [card]); } } - const items: CardDisplayItem[] = []; - - // Add note groups first, sorted by earliest card creation + // Sort note groups by earliest card creation (newest first) const sortedNoteGroups = Array.from(noteGroups.entries()).sort( ([, cardsA], [, cardsB]) => { const minA = Math.min( @@ -312,6 +214,7 @@ export function DeckDetailPage() { }, ); + const items: CardDisplayItem[] = []; for (const [noteId, noteCards] of sortedNoteGroups) { // Sort cards within group: normal first, then reversed noteCards.sort((a, b) => { @@ -321,15 +224,6 @@ export function DeckDetailPage() { items.push({ type: "note", noteId, cards: noteCards }); } - // Add legacy cards, newest first - legacyCards.sort( - (a, b) => - new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime(), - ); - for (const card of legacyCards) { - items.push({ type: "legacy", card }); - } - return items; }, [cards]); @@ -551,26 +445,16 @@ export function DeckDetailPage() { {/* Card List - Grouped by Note */} {cards.length > 0 && (
- {displayItems.map((item, index) => - item.type === "note" ? ( - setEditingNoteId(item.noteId)} - onDeleteNote={() => setDeletingNoteId(item.noteId)} - /> - ) : ( - setEditingCard(item.card)} - onDelete={() => setDeletingCard(item.card)} - /> - ), - )} + {displayItems.map((item, index) => ( + setEditingNoteId(item.noteId)} + onDeleteNote={() => setDeletingNoteId(item.noteId)} + /> + ))}
)} diff --git a/src/client/pages/StudyPage.tsx b/src/client/pages/StudyPage.tsx index bdaf7e3..0eb5118 100644 --- a/src/client/pages/StudyPage.tsx +++ b/src/client/pages/StudyPage.tsx @@ -13,8 +13,8 @@ import { renderCard } from "../utils/templateRenderer"; interface Card { id: string; deckId: string; - noteId: string | null; - isReversed: boolean | null; + noteId: string; + isReversed: boolean; front: string; back: string; state: number; @@ -23,11 +23,11 @@ interface Card { difficulty: number; reps: number; lapses: number; - /** Note type templates for rendering (null for legacy cards) */ + /** Note type templates for rendering */ noteType: { frontTemplate: string; backTemplate: string; - } | null; + }; /** Field values as a name-value map for template rendering */ fieldValuesMap: Record; } diff --git a/src/client/sync/conflict.test.ts b/src/client/sync/conflict.test.ts index 6a10c4f..52362ff 100644 --- a/src/client/sync/conflict.test.ts +++ b/src/client/sync/conflict.test.ts @@ -271,6 +271,8 @@ describe("ConflictResolver", () => { const localCard = await localCardRepository.create({ deckId: deck.id, + noteId: "test-note-id", + isReversed: false, front: "Local Question", back: "Local Answer", }); @@ -278,6 +280,8 @@ describe("ConflictResolver", () => { const serverCard = { id: localCard.id, deckId: deck.id, + noteId: "test-note-id", + isReversed: false, front: "Server Question", back: "Server Answer", state: CardState.Review, @@ -316,6 +320,8 @@ describe("ConflictResolver", () => { const localCard = await localCardRepository.create({ deckId: deck.id, + noteId: "test-note-id", + isReversed: false, front: "Local Question", back: "Local Answer", }); @@ -323,6 +329,8 @@ describe("ConflictResolver", () => { const serverCard = { id: localCard.id, deckId: deck.id, + noteId: "test-note-id", + isReversed: false, front: "Server Question", back: "Server Answer", state: CardState.New, @@ -435,6 +443,8 @@ describe("ConflictResolver", () => { const card = await localCardRepository.create({ deckId: deck.id, + noteId: "test-note-id", + isReversed: false, front: "Local Question", back: "Local Answer", }); @@ -456,6 +466,8 @@ describe("ConflictResolver", () => { { id: card.id, deckId: deck.id, + noteId: "test-note-id", + isReversed: false, front: "Server Question", back: "Server Answer", state: CardState.New, diff --git a/src/client/sync/conflict.ts b/src/client/sync/conflict.ts index d9c3f55..2451920 100644 --- a/src/client/sync/conflict.ts +++ b/src/client/sync/conflict.ts @@ -91,8 +91,8 @@ function serverCardToLocal(card: ServerCard): LocalCard { return { id: card.id, deckId: card.deckId, - noteId: card.noteId ?? null, - isReversed: card.isReversed ?? null, + noteId: card.noteId, + isReversed: card.isReversed, front: card.front, back: card.back, state: card.state as LocalCard["state"], diff --git a/src/client/sync/pull.test.ts b/src/client/sync/pull.test.ts index 9ba678e..dd562a0 100644 --- a/src/client/sync/pull.test.ts +++ b/src/client/sync/pull.test.ts @@ -101,6 +101,8 @@ describe("pullResultToLocalData", () => { { id: "card-1", deckId: "deck-1", + noteId: "test-note-id", + isReversed: false, front: "Question", back: "Answer", state: CardState.Review, @@ -130,8 +132,8 @@ describe("pullResultToLocalData", () => { expect(result.cards[0]).toEqual({ id: "card-1", deckId: "deck-1", - noteId: null, - isReversed: null, + noteId: "test-note-id", + isReversed: false, front: "Question", back: "Answer", state: CardState.Review, @@ -156,6 +158,8 @@ describe("pullResultToLocalData", () => { { id: "card-1", deckId: "deck-1", + noteId: "test-note-id", + isReversed: false, front: "New Card", back: "Answer", state: CardState.New, @@ -568,8 +572,8 @@ describe("PullService", () => { { id: "server-card-1", deckId: deck.id, - noteId: null, - isReversed: null, + noteId: "test-note-id", + isReversed: false, front: "Server Question", back: "Server Answer", state: CardState.New, @@ -715,8 +719,8 @@ describe("PullService", () => { { id: "card-1", deckId: "deck-1", - noteId: null, - isReversed: null, + noteId: "test-note-id", + isReversed: false, front: "Q", back: "A", state: CardState.New, diff --git a/src/client/sync/pull.ts b/src/client/sync/pull.ts index 55c859c..8b55a9b 100644 --- a/src/client/sync/pull.ts +++ b/src/client/sync/pull.ts @@ -33,8 +33,8 @@ export interface ServerDeck { export interface ServerCard { id: string; deckId: string; - noteId?: string | null; - isReversed?: boolean | null; + noteId: string; + isReversed: boolean; front: string; back: string; state: number; @@ -172,8 +172,8 @@ function serverCardToLocal(card: ServerCard): LocalCard { return { id: card.id, deckId: card.deckId, - noteId: card.noteId ?? null, - isReversed: card.isReversed ?? null, + noteId: card.noteId, + isReversed: card.isReversed, front: card.front, back: card.back, state: card.state as CardStateType, diff --git a/src/client/sync/push.test.ts b/src/client/sync/push.test.ts index 9a42eff..16198c1 100644 --- a/src/client/sync/push.test.ts +++ b/src/client/sync/push.test.ts @@ -131,8 +131,8 @@ describe("pendingChangesToPushData", () => { { id: "card-1", deckId: "deck-1", - noteId: null, - isReversed: null, + noteId: "test-note-id", + isReversed: false, front: "Question", back: "Answer", state: CardState.Review, @@ -163,8 +163,8 @@ describe("pendingChangesToPushData", () => { expect(result.cards[0]).toEqual({ id: "card-1", deckId: "deck-1", - noteId: null, - isReversed: null, + noteId: "test-note-id", + isReversed: false, front: "Question", back: "Answer", state: CardState.Review, @@ -187,8 +187,8 @@ describe("pendingChangesToPushData", () => { { id: "card-1", deckId: "deck-1", - noteId: null, - isReversed: null, + noteId: "test-note-id", + isReversed: false, front: "New Card", back: "Answer", state: CardState.New, @@ -566,6 +566,8 @@ describe("PushService", () => { const card = await localCardRepository.create({ deckId: deck.id, + noteId: "test-note-id", + isReversed: false, front: "Question", back: "Answer", }); @@ -611,6 +613,8 @@ describe("PushService", () => { const card = await localCardRepository.create({ deckId: deck.id, + noteId: "test-note-id", + isReversed: false, front: "Q", back: "A", }); @@ -740,6 +744,8 @@ describe("PushService", () => { const card = await localCardRepository.create({ deckId: deck.id, + noteId: "test-note-id", + isReversed: false, front: "Q", back: "A", }); diff --git a/src/client/sync/push.ts b/src/client/sync/push.ts index f5c9275..b83136e 100644 --- a/src/client/sync/push.ts +++ b/src/client/sync/push.ts @@ -35,8 +35,8 @@ export interface SyncDeckData { export interface SyncCardData { id: string; deckId: string; - noteId: string | null; - isReversed: boolean | null; + noteId: string; + isReversed: boolean; front: string; back: string; state: number; diff --git a/src/client/sync/queue.test.ts b/src/client/sync/queue.test.ts index 2038e0d..e815282 100644 --- a/src/client/sync/queue.test.ts +++ b/src/client/sync/queue.test.ts @@ -85,6 +85,8 @@ describe("SyncQueue", () => { }); await localCardRepository.create({ deckId: deck.id, + noteId: "test-note-id", + isReversed: false, front: "Question", back: "Answer", }); @@ -103,6 +105,8 @@ describe("SyncQueue", () => { }); const card = await localCardRepository.create({ deckId: deck.id, + noteId: "test-note-id", + isReversed: false, front: "Question", back: "Answer", }); @@ -145,11 +149,15 @@ describe("SyncQueue", () => { }); await localCardRepository.create({ deckId: deck.id, + noteId: "test-note-id-1", + isReversed: false, front: "Q1", back: "A1", }); await localCardRepository.create({ deckId: deck.id, + noteId: "test-note-id-2", + isReversed: false, front: "Q2", back: "A2", }); @@ -323,6 +331,8 @@ describe("SyncQueue", () => { }); const card = await localCardRepository.create({ deckId: deck.id, + noteId: "test-note-id", + isReversed: false, front: "Q", back: "A", }); @@ -351,6 +361,8 @@ describe("SyncQueue", () => { }); const card = await localCardRepository.create({ deckId: deck.id, + noteId: "test-note-id", + isReversed: false, front: "Q", back: "A", }); @@ -440,8 +452,8 @@ describe("SyncQueue", () => { const serverCard = { id: "server-card-1", deckId: deck.id, - noteId: null, - isReversed: null, + noteId: "test-note-id", + isReversed: false, front: "Server Question", back: "Server Answer", state: CardState.New, @@ -484,6 +496,8 @@ describe("SyncQueue", () => { }); const card = await localCardRepository.create({ deckId: deck.id, + noteId: "test-note-id", + isReversed: false, front: "Q", back: "A", }); -- cgit v1.2.3-70-g09d2