dex/src/store/selection.js
chris cd2655011f Scaffold Pokedex PWA (Vite + Workbox)
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-27 10:54:36 -04:00

62 lines
1.7 KiB
JavaScript

import { createStore } from './createStore.js';
/**
* The "unified Pokémon selection".
*
* One record per Pokémon, keyed by NATIONAL dex id. That key is what makes
* it unified: mark Pikachu once and every game's view — Kanto, Paldea,
* National, search results — reflects it, because each view computes its
* own progress by intersecting its species list with this single map.
*/
export const selection = createStore('pdx.selection', {
version: 2,
pokemon: {},
});
const BLANK = { seen: false, caught: false, favorite: false, note: '' };
export function entry(id) {
return selection.get().pokemon[id] || BLANK;
}
export function toggle(id, field) {
selection.set((s) => {
const current = s.pokemon[id] || BLANK;
const next = {
...current,
[field]: !current[field],
updatedAt: new Date().toISOString(),
};
// Catching something implies you've seen it.
if (field === 'caught' && next.caught) next.seen = true;
return { ...s, pokemon: { ...s.pokemon, [id]: next } };
});
}
export function setNote(id, note) {
selection.set((s) => {
const current = s.pokemon[id] || BLANK;
return {
...s,
pokemon: {
...s.pokemon,
[id]: { ...current, note, updatedAt: new Date().toISOString() },
},
};
});
}
/** Aggregate seen/caught counts over an arbitrary list of national ids. */
export function stats(speciesIds) {
const p = selection.get().pokemon;
let seen = 0;
let caught = 0;
for (const id of speciesIds) {
const e = p[id];
if (!e) continue;
if (e.seen || e.caught) seen++;
if (e.caught) caught++;
}
return { seen, caught, total: speciesIds.length };
}