import { getDB } from './db.js'; /** * HELPERS */ function store(storeName, mode = 'readonly') { const db = getDB(); const tx = db.transaction(storeName, mode); return tx.objectStore(storeName); } /** * IMPORT WORD LIST FROM SERVER → INDEXEDDB */ export async function importList(lang, list) { const res = await fetch(`/api/list.php?lang=${lang}&list=${list}`); const data = await res.json(); if (!data.words || !Array.isArray(data.words)) { console.error("Import failed:", data); return; } const s = store('words', 'readwrite'); data.words.forEach(word => { s.put({ key: `${lang}:${list}:${word.id}`, id: word.id, lang, list, question: word.question, answer: word.answer, correct: word.correct || 0, wrong: word.wrong || 0, nextReview: word.nextReview || null, interval: word.interval || 1 }); }); console.log(`Imported ${data.words.length} words`); } /** * GET WORDS */ export async function getWords(lang, list) { return new Promise((resolve) => { const s = store('words'); const req = s.getAll(); req.onsuccess = () => { const filtered = req.result.filter( w => w.lang === lang && w.list === list ); resolve(filtered); }; }); } /** * GET NEXT WORD (SRS SIMPLE) */ export async function getNextWord(lang, list) { const words = await getWords(lang, list); if (!words.length) { console.warn("No words in IndexedDB"); return null; } const today = new Date().toISOString().split('T')[0]; let due = words.filter(w => !w.nextReview || w.nextReview <= today ); if (!due.length) { due = words; } return due[Math.floor(Math.random() * due.length)]; } /** * ANSWER WORD */ export async function answerWord(word, input) { const correct = word.answer.trim().toLowerCase() === input.trim().toLowerCase(); const s = store('words', 'readwrite'); const updated = { ...word }; if (correct) { updated.correct++; const days = updated.interval * 2; updated.interval = days; const d = new Date(); d.setDate(d.getDate() + days); updated.nextReview = d.toISOString().split('T')[0]; } else { updated.wrong++; updated.interval = 1; const d = new Date(); d.setDate(d.getDate() + 1); updated.nextReview = d.toISOString().split('T')[0]; } s.put(updated); updateSessionStats(correct); queueSync({ wordId: word.id, lang: word.lang, list: word.list, correct, ts: Date.now() }); return { correct, correctAnswer: word.answer }; } /** * SESSION STATS */ export function updateSessionStats(correct) { const s = store('session', 'readwrite'); const req = s.get('stats'); req.onsuccess = () => { let stats = req.result; if (!stats) { stats = { key: 'stats', correct: 0, wrong: 0 }; } if (correct) stats.correct++; else stats.wrong++; s.put(stats); }; } export async function getSessionStats() { return new Promise(resolve => { const s = store('session'); const req = s.get('stats'); req.onsuccess = () => { resolve(req.result || { correct: 0, wrong: 0 }); }; }); } /** * SYNC QUEUE */ function queueSync(item) { const s = store('sync_queue', 'readwrite'); s.add(item); }