offline puzzle cache
This commit is contained in:
@@ -0,0 +1,73 @@
|
||||
import type { GenerateResponse } from './types'
|
||||
|
||||
const DB_NAME = 'cruciverb-offline'
|
||||
const DB_VERSION = 1
|
||||
|
||||
function openDB(): Promise<IDBDatabase> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const req = indexedDB.open(DB_NAME, DB_VERSION)
|
||||
req.onupgradeneeded = () => {
|
||||
const db = req.result
|
||||
if (!db.objectStoreNames.contains('puzzles')) {
|
||||
db.createObjectStore('puzzles', { keyPath: 'id' })
|
||||
}
|
||||
if (!db.objectStoreNames.contains('progress')) {
|
||||
db.createObjectStore('progress', { keyPath: 'puzzleId' })
|
||||
}
|
||||
if (!db.objectStoreNames.contains('pending')) {
|
||||
db.createObjectStore('pending', { keyPath: 'id', autoIncrement: true })
|
||||
}
|
||||
}
|
||||
req.onsuccess = () => resolve(req.result)
|
||||
req.onerror = () => reject(req.error)
|
||||
})
|
||||
}
|
||||
|
||||
export async function cachePuzzle(id: string, data: GenerateResponse): Promise<void> {
|
||||
const db = await openDB()
|
||||
const tx = db.transaction('puzzles', 'readwrite')
|
||||
tx.objectStore('puzzles').put({ id, data, cached_at: Date.now() })
|
||||
return new Promise((resolve, reject) => { tx.oncomplete = () => resolve(); tx.onerror = () => reject(tx.error) })
|
||||
}
|
||||
|
||||
export async function getCachedPuzzle(id: string): Promise<GenerateResponse | null> {
|
||||
const db = await openDB()
|
||||
return new Promise((resolve, reject) => {
|
||||
const tx = db.transaction('puzzles', 'readonly')
|
||||
const req = tx.objectStore('puzzles').get(id)
|
||||
req.onsuccess = () => resolve(req.result?.data || null)
|
||||
req.onerror = () => reject(req.error)
|
||||
})
|
||||
}
|
||||
|
||||
export async function saveProgress(puzzleId: string, entries: string[][]): Promise<void> {
|
||||
const db = await openDB()
|
||||
const tx = db.transaction('progress', 'readwrite')
|
||||
tx.objectStore('progress').put({ puzzleId, entries, saved_at: Date.now() })
|
||||
return new Promise((resolve, reject) => { tx.oncomplete = () => resolve(); tx.onerror = () => reject(tx.error) })
|
||||
}
|
||||
|
||||
export async function getProgress(puzzleId: string): Promise<string[][] | null> {
|
||||
const db = await openDB()
|
||||
return new Promise((resolve, reject) => {
|
||||
const tx = db.transaction('progress', 'readonly')
|
||||
const req = tx.objectStore('progress').get(puzzleId)
|
||||
req.onsuccess = () => resolve(req.result?.entries || null)
|
||||
req.onerror = () => reject(req.error)
|
||||
})
|
||||
}
|
||||
|
||||
export function isOnline(): boolean {
|
||||
return navigator.onLine
|
||||
}
|
||||
|
||||
export function onOnlineChange(callback: (online: boolean) => void): () => void {
|
||||
const onOnline = () => callback(true)
|
||||
const onOffline = () => callback(false)
|
||||
window.addEventListener('online', onOnline)
|
||||
window.addEventListener('offline', onOffline)
|
||||
return () => {
|
||||
window.removeEventListener('online', onOnline)
|
||||
window.removeEventListener('offline', onOffline)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user