Update assets/js/offline-engine.js
This commit is contained in:
+80
-94
@@ -1,91 +1,113 @@
|
||||
import { getDB } from './db.js';
|
||||
|
||||
function getStore(storeName, mode = 'readonly') {
|
||||
|
||||
/**
|
||||
* HELPERS
|
||||
*/
|
||||
function store(storeName, mode = 'readonly') {
|
||||
const db = getDB();
|
||||
|
||||
const tx = db.transaction(storeName, mode);
|
||||
|
||||
return tx.objectStore(storeName);
|
||||
}
|
||||
|
||||
export async function saveWords(lang, list, words) {
|
||||
/**
|
||||
* IMPORT WORD LIST FROM SERVER → INDEXEDDB
|
||||
*/
|
||||
export async function importList(lang, list) {
|
||||
|
||||
const store = getStore('words', 'readwrite');
|
||||
const res = await fetch(`/api/list.php?lang=${lang}&list=${list}`);
|
||||
const data = await res.json();
|
||||
|
||||
for (const word of words) {
|
||||
if (!data.words || !Array.isArray(data.words)) {
|
||||
console.error("Import failed:", data);
|
||||
return;
|
||||
}
|
||||
|
||||
store.put({
|
||||
const s = store('words', 'readwrite');
|
||||
|
||||
data.words.forEach(word => {
|
||||
|
||||
s.put({
|
||||
key: `${lang}:${list}:${word.id}`,
|
||||
id: word.id,
|
||||
lang,
|
||||
list,
|
||||
...word
|
||||
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 store = getStore('words');
|
||||
const s = store('words');
|
||||
|
||||
const req = store.getAll();
|
||||
const req = s.getAll();
|
||||
|
||||
req.onsuccess = () => {
|
||||
|
||||
const result = req.result.filter(
|
||||
const filtered = req.result.filter(
|
||||
w => w.lang === lang && w.list === list
|
||||
);
|
||||
|
||||
resolve(result);
|
||||
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(word => {
|
||||
return !word.nextReview ||
|
||||
word.nextReview <= today;
|
||||
});
|
||||
let due = words.filter(w =>
|
||||
!w.nextReview || w.nextReview <= today
|
||||
);
|
||||
|
||||
if (!due.length) {
|
||||
due = words;
|
||||
}
|
||||
|
||||
const random =
|
||||
Math.floor(Math.random() * due.length);
|
||||
|
||||
return due[random];
|
||||
return due[Math.floor(Math.random() * due.length)];
|
||||
}
|
||||
|
||||
export async function answerWord(word, answer) {
|
||||
/**
|
||||
* ANSWER WORD
|
||||
*/
|
||||
export async function answerWord(word, input) {
|
||||
|
||||
const correct =
|
||||
word.answer.trim().toLowerCase() ===
|
||||
answer.trim().toLowerCase();
|
||||
input.trim().toLowerCase();
|
||||
|
||||
const store =
|
||||
getStore('words', 'readwrite');
|
||||
const s = store('words', 'readwrite');
|
||||
|
||||
const updated = { ...word };
|
||||
|
||||
if (correct) {
|
||||
|
||||
const days =
|
||||
updated.interval
|
||||
? updated.interval * 2
|
||||
: 1;
|
||||
updated.correct++;
|
||||
|
||||
const days = updated.interval * 2;
|
||||
updated.interval = days;
|
||||
|
||||
const d = new Date();
|
||||
@@ -96,6 +118,8 @@ export async function answerWord(word, answer) {
|
||||
|
||||
} else {
|
||||
|
||||
updated.wrong++;
|
||||
|
||||
updated.interval = 1;
|
||||
|
||||
const d = new Date();
|
||||
@@ -105,38 +129,29 @@ export async function answerWord(word, answer) {
|
||||
d.toISOString().split('T')[0];
|
||||
}
|
||||
|
||||
store.put(updated);
|
||||
s.put(updated);
|
||||
|
||||
await updateSessionStats(correct);
|
||||
updateSessionStats(correct);
|
||||
|
||||
await queueSync({
|
||||
queueSync({
|
||||
wordId: word.id,
|
||||
lang: word.lang,
|
||||
list: word.list,
|
||||
correct,
|
||||
timestamp: Date.now()
|
||||
ts: Date.now()
|
||||
});
|
||||
|
||||
return {
|
||||
correct
|
||||
};
|
||||
return { correct };
|
||||
}
|
||||
|
||||
async function queueSync(item) {
|
||||
/**
|
||||
* SESSION STATS
|
||||
*/
|
||||
export function updateSessionStats(correct) {
|
||||
|
||||
const store =
|
||||
getStore('sync_queue', 'readwrite');
|
||||
const s = store('session', 'readwrite');
|
||||
|
||||
store.add(item);
|
||||
}
|
||||
|
||||
export async function updateSessionStats(correct) {
|
||||
|
||||
const store =
|
||||
getStore('session', 'readwrite');
|
||||
|
||||
const req =
|
||||
store.get('stats');
|
||||
const req = s.get('stats');
|
||||
|
||||
req.onsuccess = () => {
|
||||
|
||||
@@ -150,13 +165,10 @@ export async function updateSessionStats(correct) {
|
||||
};
|
||||
}
|
||||
|
||||
if (correct) {
|
||||
stats.correct++;
|
||||
} else {
|
||||
stats.wrong++;
|
||||
}
|
||||
if (correct) stats.correct++;
|
||||
else stats.wrong++;
|
||||
|
||||
store.put(stats);
|
||||
s.put(stats);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -164,51 +176,25 @@ export async function getSessionStats() {
|
||||
|
||||
return new Promise(resolve => {
|
||||
|
||||
const store =
|
||||
getStore('session');
|
||||
const s = store('session');
|
||||
|
||||
const req =
|
||||
store.get('stats');
|
||||
const req = s.get('stats');
|
||||
|
||||
req.onsuccess = () => {
|
||||
|
||||
resolve(
|
||||
req.result || {
|
||||
correct: 0,
|
||||
wrong: 0
|
||||
}
|
||||
);
|
||||
resolve(req.result || {
|
||||
correct: 0,
|
||||
wrong: 0
|
||||
});
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
export async function resetSessionStats() {
|
||||
/**
|
||||
* SYNC QUEUE
|
||||
*/
|
||||
function queueSync(item) {
|
||||
|
||||
const store =
|
||||
getStore('session', 'readwrite');
|
||||
|
||||
store.put({
|
||||
key: 'stats',
|
||||
correct: 0,
|
||||
wrong: 0
|
||||
});
|
||||
}
|
||||
|
||||
import { saveWords } from './offline-engine.js';
|
||||
|
||||
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) {
|
||||
throw new Error('No words');
|
||||
}
|
||||
|
||||
await saveWords(lang, list, data.words);
|
||||
|
||||
return data.words.length;
|
||||
const s = store('sync_queue', 'readwrite');
|
||||
s.add(item);
|
||||
}
|
||||
Reference in New Issue
Block a user