data(*): Add final data changes

This commit is contained in:
Josh Creek
2026-01-17 23:30:40 +00:00
parent 479b3ae7a0
commit 46351c9af0
29 changed files with 12187 additions and 122 deletions
+26 -20
View File
@@ -11,6 +11,7 @@
import { pwaAssetsHead } from 'virtual:pwa-assets/head';
$: webManifestLink = pwaInfo ? pwaInfo.webManifest.linkTag : '';
const pwaDescription = (pwaAssetsHead as { description?: { content: string } }).description;
export let data;
let { supabase } = data;
@@ -22,8 +23,10 @@
});
onDestroy(unsubscribe);
onMount(async () => {
await getUser();
let authSubscription: { unsubscribe: () => void } | null = null;
onMount(() => {
void getUser();
// Listen for auth state changes to keep the user store in sync
const {
@@ -36,27 +39,30 @@
}
user.set(localUser);
});
authSubscription = subscription;
if (pwaInfo) {
const { registerSW } = await import('virtual:pwa-register');
registerSW({
immediate: true,
onRegistered(r) {
// uncomment following code if you want check for updates
// r && setInterval(() => {
// console.log('Checking for sw update')
// r.update()
// }, 20000 /* 20s for testing purposes */)
console.log(`SW Registered: ${r}`);
},
onRegisterError(error) {
console.log('SW registration error', error);
}
});
void (async () => {
const { registerSW } = await import('virtual:pwa-register');
registerSW({
immediate: true,
onRegistered(r) {
// uncomment following code if you want check for updates
// r && setInterval(() => {
// console.log('Checking for sw update')
// r.update()
// }, 20000 /* 20s for testing purposes */)
console.log(`SW Registered: ${r}`);
},
onRegisterError(error) {
console.log('SW registration error', error);
}
});
})();
}
return () => {
subscription.unsubscribe();
authSubscription?.unsubscribe();
};
});
@@ -80,8 +86,8 @@
{#if pwaAssetsHead.themeColor}
<meta name="theme-color" content={pwaAssetsHead.themeColor.content} />
{/if}
{#if pwaAssetsHead.description}
<meta name="description" content={pwaAssetsHead.description.content} />
{#if pwaDescription}
<meta name="description" content={pwaDescription.content} />
{/if}
{#each pwaAssetsHead.links as link}
<link {...link} />
+17
View File
@@ -0,0 +1,17 @@
import { json } from '@sveltejs/kit';
import type { RequestHandler } from './$types';
import { listGameDexes } from '$lib/services/PokedexDexScopeService';
/**
* GET /api/game-dexes
* Returns game dexes grouped by game display name.
*/
export const GET: RequestHandler = async ({ locals }) => {
try {
const { gameDexes, gameOrder, games } = await listGameDexes(locals.supabase);
return json({ gameDexes, gameOrder, games });
} catch (err) {
console.error('Unexpected error fetching game dexes:', err);
return json({ error: 'Internal server error' }, { status: 500 });
}
};
+9
View File
@@ -4,6 +4,7 @@ import PokedexRepository from '$lib/repositories/PokedexRepository';
import { requireAuth } from '$lib/utils/auth';
import type { RequestEvent } from '@sveltejs/kit';
import { populatePokedexMappings } from '$lib/services/PokedexMappingService';
import { resolveDexScopes, setPokedexDexScopes } from '$lib/services/PokedexDexScopeService';
// GET: List all pokedexes for user
export const GET = async (event: RequestEvent) => {
@@ -31,12 +32,20 @@ export const POST = async (event: RequestEvent) => {
const data: Partial<Pokedex> = await event.request.json();
requestedName = typeof data.name === 'string' ? data.name : undefined;
data.userId = userId;
const requestedDexScopes = Array.isArray(data.dexScopes) ? data.dexScopes : [];
const repo = new PokedexRepository(event.locals.supabase, userId);
const pokedex = await repo.create(data);
createdPokedexId = pokedex._id;
createdPokedexName = pokedex.name;
const resolvedDexScopes = await resolveDexScopes(event.locals.supabase, {
...pokedex,
dexScopes: requestedDexScopes
});
await setPokedexDexScopes(event.locals.supabase, pokedex._id, resolvedDexScopes);
pokedex.dexScopes = resolvedDexScopes;
// Populate pokedex_entries_mapping table with expected entries
try {
await populatePokedexMappings(event.locals.supabase, pokedex._id, pokedex);
+26 -2
View File
@@ -4,6 +4,7 @@ import PokedexRepository from '$lib/repositories/PokedexRepository';
import { requireAuth } from '$lib/utils/auth';
import type { RequestEvent } from '@sveltejs/kit';
import { recalculatePokedexMappings } from '$lib/services/PokedexMappingService';
import { resolveDexScopes, setPokedexDexScopes } from '$lib/services/PokedexDexScopeService';
// GET: Get single pokedex by ID
export const GET = async (event: RequestEvent) => {
@@ -71,12 +72,35 @@ export const PUT = async (event: RequestEvent) => {
return json({ error: 'Pokedex not found' }, { status: 404 });
}
const dexScopesProvided = Object.prototype.hasOwnProperty.call(data, 'dexScopes');
const requestedDexScopes =
dexScopesProvided && Array.isArray(data.dexScopes)
? data.dexScopes
: existingPokedex.dexScopes || [];
const resolvedDexScopes = await resolveDexScopes(event.locals.supabase, {
...pokedex,
dexScopes: requestedDexScopes
});
const existingDexScopes = new Set(existingPokedex.dexScopes || []);
const nextDexScopes = new Set(resolvedDexScopes);
const dexScopesChanged =
existingDexScopes.size !== nextDexScopes.size ||
[...existingDexScopes].some((dexId) => !nextDexScopes.has(dexId));
if (dexScopesChanged) {
await setPokedexDexScopes(event.locals.supabase, id, resolvedDexScopes);
pokedex.dexScopes = resolvedDexScopes;
}
// Recalculate pokedex_entries_mapping if configuration changed
// Only recalculate if isFormDex or gameScope actually changed (these are the only fields that affect mapping)
// Only recalculate if isFormDex, gameScope, or dexScopes changed
// Compare the persisted result (pokedex) to existingPokedex to catch changes that repo.update may normalize or default
const configChanged =
pokedex.isFormDex !== existingPokedex.isFormDex ||
pokedex.gameScope !== existingPokedex.gameScope;
pokedex.gameScope !== existingPokedex.gameScope ||
dexScopesChanged;
if (configChanged) {
await recalculatePokedexMappings(event.locals.supabase, id, pokedex);
@@ -3,6 +3,7 @@ import CombinedDataRepository from '$lib/repositories/CombinedDataRepository';
import PokedexRepository from '$lib/repositories/PokedexRepository';
import { getOptionalUserId } from '$lib/utils/auth';
import type { RequestEvent } from '@sveltejs/kit';
import { resolveDexScopes } from '$lib/services/PokedexDexScopeService';
// GET: Get combined data (pokédex entries + catch records) for specific pokédex
export const GET = async (event: RequestEvent) => {
@@ -39,6 +40,7 @@ export const GET = async (event: RequestEvent) => {
// Use pokédex's gameScope as default filter if no manual game filter is set
const effectiveGame = game || pokedex.gameScope || '';
const dexScopes = await resolveDexScopes(event.locals.supabase, pokedex);
const repo = new CombinedDataRepository(event.locals.supabase, userId, pokedexId);
@@ -49,11 +51,12 @@ export const GET = async (event: RequestEvent) => {
limit,
enableForms,
region,
effectiveGame
effectiveGame,
dexScopes
);
// Get total count for pagination
const totalCount = await repo.countCombinedData(enableForms, region, effectiveGame);
const totalCount = await repo.countCombinedData(enableForms, region, effectiveGame, dexScopes);
const totalPages = Math.ceil(totalCount / limit);
return json({
+2 -1
View File
@@ -146,11 +146,12 @@
<!-- Email Input -->
<div class="form-control">
<label class="label">
<label class="label" for="forgot-password-email">
<span class="label-text font-medium">Email</span>
</label>
<div class="relative">
<input
id="forgot-password-email"
type="email"
placeholder="your@email.com"
class="input input-bordered w-full pl-10"
+10 -3
View File
@@ -15,7 +15,8 @@
isShinyDex: false,
isOriginDex: false,
isFormDex: false,
gameScope: null
gameScope: null,
dexScopes: []
};
$: mode = editingPokedex ? ('edit' as const) : ('create' as const);
@@ -55,7 +56,8 @@
isShinyDex: false,
isOriginDex: false,
isFormDex: false,
gameScope: null
gameScope: null,
dexScopes: []
};
showModal = true;
}
@@ -199,6 +201,11 @@
</h3>
<PokedexForm bind:pokedex={formData} {mode} onSubmit={handleSubmit} onCancel={closeModal} />
</div>
<div class="modal-backdrop" on:click={closeModal}></div>
<button
type="button"
class="modal-backdrop"
aria-label="Close modal"
on:click={closeModal}
></button>
</div>
{/if}
+5
View File
@@ -467,6 +467,11 @@
/>
</svg>
<span class="font-semibold">{pokedex.gameScope}</span>
{#if pokedex.dexScopes?.length}
<span class="text-xs text-base-content/60">
({pokedex.dexScopes.length} dex{pokedex.dexScopes.length === 1 ? '' : 'es'})
</span>
{/if}
</div>
{:else}
<div class="divider divider-horizontal mx-0"></div>
+4 -2
View File
@@ -174,11 +174,12 @@
<!-- New Password Input -->
<div class="form-control">
<label class="label">
<label class="label" for="reset-password-new">
<span class="label-text font-medium">New Password</span>
</label>
<div class="relative">
<input
id="reset-password-new"
type="password"
placeholder="••••••••"
class="input input-bordered w-full pl-10"
@@ -203,11 +204,12 @@
<!-- Confirm Password Input -->
<div class="form-control">
<label class="label">
<label class="label" for="reset-password-confirm">
<span class="label-text font-medium">Confirm Password</span>
</label>
<div class="relative">
<input
id="reset-password-confirm"
type="password"
placeholder="••••••••"
class="input input-bordered w-full pl-10"