roulette / js /store.js
ratandeep's picture
Deploy Build Small Roulette — static space serendipity engine for the org
653b61d
Raw
History Blame Contribute Delete
1.81 kB
const DEFAULTS = () => ({ liked: {}, hfLiked: {}, saved: {}, seen: [], round: null });
export class Store {
constructor({ key = "bsr:v1", backend } = {}) {
this.key = key;
this.backend = backend || globalThis.localStorage;
this.data = this._read();
}
_read() {
try {
const raw = this.backend?.getItem(this.key);
if (!raw) return DEFAULTS();
return { ...DEFAULTS(), ...JSON.parse(raw) };
} catch {
return DEFAULTS();
}
}
_write() {
try {
this.backend?.setItem(this.key, JSON.stringify(this.data));
} catch {
/* storage full / blocked — ignore */
}
}
// saves
isSaved(id) { return !!this.data.saved[id]; }
toggleSaved(id) {
if (this.data.saved[id]) { delete this.data.saved[id]; this._write(); return false; }
this.data.saved[id] = Date.now(); this._write(); return true;
}
savedIds() {
return Object.keys(this.data.saved).sort((a, b) => this.data.saved[b] - this.data.saved[a]);
}
// local-like fallback
isLocalLiked(id) { return !!this.data.liked[id]; }
setLocalLiked(id, on) {
if (on) this.data.liked[id] = Date.now(); else delete this.data.liked[id];
this._write();
}
// confirmed real HF like (this session/device)
isHfLiked(id) { return !!this.data.hfLiked[id]; }
setHfLiked(id, on) {
if (on) this.data.hfLiked[id] = true; else delete this.data.hfLiked[id];
this._write();
}
// any like (real or local) — for button fill state
isLiked(id) { return this.isHfLiked(id) || this.isLocalLiked(id); }
// seen / progress
markSeen(id) {
if (!this.data.seen.includes(id)) { this.data.seen.push(id); this._write(); }
}
// resume round
saveRound(round) { this.data.round = round; this._write(); }
loadRound() { return this.data.round; }
}