mirror of
https://github.com/jcreek/LivingDexTracker.git
synced 2026-07-13 11:03:44 +00:00
data(*): Add final data changes
This commit is contained in:
+26
-20
@@ -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} />
|
||||
|
||||
@@ -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 });
|
||||
}
|
||||
};
|
||||
@@ -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);
|
||||
|
||||
@@ -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({
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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"
|
||||
|
||||
Reference in New Issue
Block a user