feat(*): Add pagination to my dex

This commit is contained in:
Josh Creek
2024-07-12 21:33:02 +01:00
parent 3d42bef3e5
commit 5fdc43124e
4 changed files with 124 additions and 127 deletions
+29
View File
@@ -0,0 +1,29 @@
<script lang="ts">
export let currentPage: number;
export let itemsPerPage: number;
export let totalPages: number;
function nextPage() {
currentPage = Math.min(currentPage + 1, totalPages);
}
function previousPage() {
currentPage = Math.max(currentPage - 1, 1);
}
function setItemsPerPage(event: any) {
itemsPerPage = parseInt(event.target.value, 10);
}
</script>
<div>
<button on:click={previousPage} disabled={currentPage === 1}>Previous</button>
<button on:click={nextPage} disabled={currentPage === totalPages}>Next</button>
<label for="itemsPerPage">Items per page:</label>
<select id="itemsPerPage" on:change={setItemsPerPage}>
<option value="20">20</option>
<option value="50">50</option>
<option value="100">100</option>
</select>
</div>
@@ -0,0 +1,45 @@
import PokedexEntryModel, { type PokedexEntry } from '$lib/models/PokedexEntry';
import CatchRecordModel, { type CatchRecord } from '$lib/models/CatchRecord';
import { CombinedData } from '$lib/models/CombinedData';
class CombinedDataRepository {
async findCombinedData(page: number = 1, limit: number = 20): Promise<CombinedData[]> {
const skip = (page - 1) * limit;
const combinedData: CombinedData[] = await PokedexEntryModel.aggregate([
{
$lookup: {
from: 'catchrecords',
localField: '_id',
foreignField: 'pokedexEntryId',
as: 'catchRecord'
}
},
{
$unwind: {
path: '$catchRecord',
preserveNullAndEmptyArrays: true
}
},
{
$sort: {
'boxPlacement.box': 1,
'boxPlacement.row': 1,
'boxPlacement.column': 1
}
},
{ $skip: skip },
{ $limit: limit }
]).exec();
return combinedData.map((data) => ({
pokedexEntry: data as PokedexEntry,
catchRecord: data.catchRecord as CatchRecord
}));
}
async countCombinedData(): Promise<number> {
return PokedexEntryModel.countDocuments().exec();
}
}
export default CombinedDataRepository;
+23
View File
@@ -0,0 +1,23 @@
import { json } from '@sveltejs/kit';
import { dbConnect, dbDisconnect } from '$lib/utils/db';
import CombinedDataRepository from '$lib/repositories/CombinedDataRepository';
export const GET = async ({ url }) => {
const page = parseInt(url.searchParams.get('page') || '1', 10);
const limit = parseInt(url.searchParams.get('limit') || '20', 10);
try {
await dbConnect();
const repo = new CombinedDataRepository();
const combinedData = await repo.findCombinedData(page, limit);
const totalCount = await repo.countCombinedData();
const totalPages = Math.ceil(totalCount / limit);
return json({ combinedData, totalPages });
} catch (error) {
console.error(error);
return json({ error: 'Internal Server Error' }, { status: 500 });
} finally {
dbDisconnect();
}
};
+27 -127
View File
@@ -2,11 +2,16 @@
import { onMount, onDestroy } from 'svelte'; import { onMount, onDestroy } from 'svelte';
import { user } from '$lib/stores/user.js'; import { user } from '$lib/stores/user.js';
import { type User } from '@supabase/auth-js'; import { type User } from '@supabase/auth-js';
import mongoose, { Types } from 'mongoose'; import { type CatchRecord } from '$lib/models/CatchRecord';
import { type PokedexEntry } from '$lib/models/PokedexEntry';
import CatchRecordModel, { type CatchRecord } from '$lib/models/CatchRecord';
import { type CombinedData } from '$lib/models/CombinedData'; import { type CombinedData } from '$lib/models/CombinedData';
import PokedexEntryCatchRecord from '$lib/components/pokedex/PokedexEntryCatchRecord.svelte'; import PokedexEntryCatchRecord from '$lib/components/pokedex/PokedexEntryCatchRecord.svelte';
import Pagination from '$lib/components/Pagination.svelte';
import { browser } from '$app/environment';
let combinedData = null as CombinedData[] | null;
let currentPage = 1 as number;
let itemsPerPage = 20 as number;
let totalPages = 0 as number;
let localUser: User | null; let localUser: User | null;
const unsubscribe = user.subscribe((value) => { const unsubscribe = user.subscribe((value) => {
@@ -14,13 +19,6 @@
}); });
onDestroy(unsubscribe); onDestroy(unsubscribe);
let pokedexEntries = null as PokedexEntry[] | null;
let catchRecords = null as CatchRecord[] | null;
let combinedData = null as CombinedData[] | null;
let creatingRecords = false;
let totalRecordsCreated = 0;
let showOrigins = true; let showOrigins = true;
let showForms = true; let showForms = true;
@@ -32,118 +30,23 @@
showForms = !showForms; showForms = !showForms;
} }
async function fetchPokeDexEntries() { async function getData() {
console.log('Fetching updated Pokedex entry data'); const response = await fetch(`/api/combined-data?page=${currentPage}&limit=${itemsPerPage}`);
const response = await fetch('/api/pokedexentries'); const data = await response.json();
if (!response.ok) {
throw new Error('Failed to fetch Pokémon data'); combinedData = data.combinedData;
totalPages = data.totalPages;
} }
pokedexEntries = await response.json();
}
async function fetchCatchRecords() {
const response = await fetch('/api/catch-records');
if (!response.ok) {
throw new Error('Failed to fetch catch record data');
}
catchRecords = await response.json();
// If there are no catch records, make one for each pokedex entry
if (catchRecords?.length === 0 && localUser?.id) {
creatingRecords = true;
const newCatchRecords = pokedexEntries.map((entry) => ({
userId: localUser?.id,
pokedexEntryId: entry._id,
haveToEvolve: false,
caught: false,
inHome: false,
hasGigantamaxed: false,
personalNotes: ''
}));
if (newCatchRecords.length === 0) {
alert('No pokedex entries to create catch records for');
return;
}
const batchSize = 500;
for (let i = 0; i < newCatchRecords.length; i += batchSize) {
const batch = newCatchRecords.slice(i, i + batchSize);
const requestOptions = {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(batch)
};
try {
const response = await fetch('/api/catch-records', requestOptions);
if (!response.ok) {
throw new Error('Failed to create catch records');
}
const createdRecords = await response.json();
totalRecordsCreated += createdRecords.length;
console.log(`Created ${createdRecords.length} catch records`);
} catch (error) {
console.error('Error creating catch records:', error);
}
}
await fetchCatchRecords();
console.log('Created catch records for each pokedex entry');
creatingRecords = false;
}
}
const fetchLastModifiedDate = async () => {
const response = await fetch('/api/pokedex-metadata');
const { lastModified } = await response.json();
return new Date(lastModified);
};
const cacheData = () => {
localStorage.setItem('pokeDexEntries', JSON.stringify(pokedexEntries));
localStorage.setItem('pokeDexLastUpdated', new Date().toISOString());
};
const checkForUpdates = async () => {
const cachedData = localStorage.getItem('pokeDexEntries');
const cachedDate = localStorage.getItem('pokeDexLastUpdated');
if (cachedData && cachedDate) {
const lastModified = await fetchLastModifiedDate();
const lastUpdated = new Date(cachedDate);
if (lastModified <= lastUpdated) {
pokedexEntries = JSON.parse(cachedData);
return;
}
}
await fetchPokeDexEntries();
cacheData();
};
onMount(async () => { onMount(async () => {
await checkForUpdates() await getData();
.then(async () => { });
await fetchCatchRecords();
})
.then(async () => {
combinedData = [];
// Combine pokedex entries with their corresponding catch records $: {
pokedexEntries.forEach((entry) => { if (browser) {
let catchRecord = catchRecords.find((record) => record.pokedexEntryId === entry._id); currentPage, itemsPerPage, getData();
if (catchRecord) { }
combinedData.push({ pokedexEntry: entry, catchRecord });
} }
});
});
});
async function updateACatch(catchRecord: CatchRecord) { async function updateACatch(catchRecord: CatchRecord) {
alert('here'); alert('here');
@@ -179,9 +82,9 @@
<button on:click={() => toggleOrigins()}>Toggle Origins</button> <button on:click={() => toggleOrigins()}>Toggle Origins</button>
</div> </div>
<!-- <p> <Pagination bind:currentPage bind:itemsPerPage bind:totalPages />
<button on:click={() => updateACatch(catchRecord)}>Save</button> {currentPage}
</p> -->
{#each combinedData as { pokedexEntry, catchRecord }} {#each combinedData as { pokedexEntry, catchRecord }}
<div> <div>
<PokedexEntryCatchRecord <PokedexEntryCatchRecord
@@ -193,14 +96,11 @@
/> />
</div> </div>
{/each} {/each}
<Pagination bind:currentPage bind:itemsPerPage bind:totalPages />
{currentPage}
{:else} {:else}
<span class="loading loading-spinner loading-xl"></span>
<h1>Loading Pokédex</h1> <h1>Loading Pokédex</h1>
<p>Please be patient, this can take some time on the first load.</p> <span class="loading loading-spinner loading-xl"></span>
{#if totalRecordsCreated > 0}
<p>Processing {totalRecordsCreated}/{pokedexEntries?.length}</p>
{:else if creatingRecords}
<p>Processing...</p>
{/if}
{/if} {/if}
</div> </div>