// NextSnap - IndexedDB Storage using Dexie.js 'use strict'; const Storage = { db: null, init() { // Initialize Dexie database this.db = new Dexie('nextsnap'); // Define schema with compound indexes this.db.version(1).stores({ photos: '++id, username, timestamp, filename, targetPath, status, [username+status], [username+timestamp]', settings: '++id, username, [username+key]' }); return this.db.open(); }, async savePhoto(photoData) { /** * Save a photo to IndexedDB * photoData: { * username: string, * timestamp: number, * filename: string, * targetPath: string, * blob: Blob, * status: 'pending' | 'uploading' | 'uploaded' | 'verified' * retryCount: number, * lastError: string * } */ const id = await this.db.photos.add({ username: photoData.username, timestamp: photoData.timestamp, filename: photoData.filename, targetPath: photoData.targetPath, blob: photoData.blob, status: photoData.status || 'pending', retryCount: photoData.retryCount || 0, lastError: photoData.lastError || null }); return id; }, async getPhoto(id) { return await this.db.photos.get(id); }, async getAllPhotos(username = null) { if (username) { return await this.db.photos .where('username').equals(username) .reverse() .sortBy('timestamp'); } return await this.db.photos.reverse().sortBy('timestamp'); }, async getPendingPhotos(username = null) { if (username) { return await this.db.photos .where('[username+status]') .equals([username, 'pending']) .sortBy('timestamp'); } return await this.db.photos .where('status').equals('pending') .sortBy('timestamp'); }, async getRecentPhotos(username, limit = 5) { return await this.db.photos .where('username').equals(username) .reverse() .limit(limit) .sortBy('timestamp'); }, async updatePhoto(id, updates) { return await this.db.photos.update(id, updates); }, async deletePhoto(id) { return await this.db.photos.delete(id); }, async getPhotoCount(username = null, status = null) { let collection = this.db.photos; if (username && status) { return await collection .where('[username+status]') .equals([username, status]) .count(); } else if (username) { return await collection .where('username').equals(username) .count(); } else if (status) { return await collection .where('status').equals(status) .count(); } return await collection.count(); }, async saveSetting(username, key, value) { // Check if setting exists const existing = await this.db.settings .where('[username+key]') .equals([username, key]) .first(); if (existing) { await this.db.settings.update(existing.id, { value: value }); } else { await this.db.settings.add({ username: username, key: key, value: value }); } }, async getSetting(username, key, defaultValue = null) { const setting = await this.db.settings .where('[username+key]') .equals([username, key]) .first(); return setting ? setting.value : defaultValue; }, async clearVerifiedPhotos(username = null) { if (username) { return await this.db.photos .where('[username+status]') .equals([username, 'verified']) .delete(); } return await this.db.photos .where('status').equals('verified') .delete(); } }; // Make Storage globally available window.Storage = Storage;