From 5fdc43124e38cd9ad94b46980d8b69e9696ee30c Mon Sep 17 00:00:00 2001
From: Josh Creek <8179928+jcreek@users.noreply.github.com>
Date: Fri, 12 Jul 2024 21:33:02 +0100
Subject: [PATCH] feat(*): Add pagination to my dex
---
src/lib/components/Pagination.svelte | 29 ++++
.../repositories/CombinedDataRepository.ts | 45 +++++
src/routes/api/combined-data/+server.ts | 23 +++
src/routes/mydex/+page.svelte | 154 +++---------------
4 files changed, 124 insertions(+), 127 deletions(-)
create mode 100644 src/lib/components/Pagination.svelte
create mode 100644 src/lib/repositories/CombinedDataRepository.ts
create mode 100644 src/routes/api/combined-data/+server.ts
diff --git a/src/lib/components/Pagination.svelte b/src/lib/components/Pagination.svelte
new file mode 100644
index 0000000..d99ad5a
--- /dev/null
+++ b/src/lib/components/Pagination.svelte
@@ -0,0 +1,29 @@
+
+
+
+
+
+
+
+
+
diff --git a/src/lib/repositories/CombinedDataRepository.ts b/src/lib/repositories/CombinedDataRepository.ts
new file mode 100644
index 0000000..adc033f
--- /dev/null
+++ b/src/lib/repositories/CombinedDataRepository.ts
@@ -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 {
+ 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 {
+ return PokedexEntryModel.countDocuments().exec();
+ }
+}
+
+export default CombinedDataRepository;
diff --git a/src/routes/api/combined-data/+server.ts b/src/routes/api/combined-data/+server.ts
new file mode 100644
index 0000000..cc8ace3
--- /dev/null
+++ b/src/routes/api/combined-data/+server.ts
@@ -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();
+ }
+};
diff --git a/src/routes/mydex/+page.svelte b/src/routes/mydex/+page.svelte
index ace0aa5..6dd73f6 100644
--- a/src/routes/mydex/+page.svelte
+++ b/src/routes/mydex/+page.svelte
@@ -2,11 +2,16 @@
import { onMount, onDestroy } from 'svelte';
import { user } from '$lib/stores/user.js';
import { type User } from '@supabase/auth-js';
- import mongoose, { Types } from 'mongoose';
- import { type PokedexEntry } from '$lib/models/PokedexEntry';
- import CatchRecordModel, { type CatchRecord } from '$lib/models/CatchRecord';
+ import { type CatchRecord } from '$lib/models/CatchRecord';
import { type CombinedData } from '$lib/models/CombinedData';
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;
const unsubscribe = user.subscribe((value) => {
@@ -14,13 +19,6 @@
});
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 showForms = true;
@@ -32,119 +30,24 @@
showForms = !showForms;
}
- async function fetchPokeDexEntries() {
- console.log('Fetching updated Pokedex entry data');
- const response = await fetch('/api/pokedexentries');
- if (!response.ok) {
- throw new Error('Failed to fetch Pokémon data');
- }
+ async function getData() {
+ const response = await fetch(`/api/combined-data?page=${currentPage}&limit=${itemsPerPage}`);
+ const data = await response.json();
- pokedexEntries = await response.json();
+ combinedData = data.combinedData;
+ totalPages = data.totalPages;
}
- 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 () => {
- await checkForUpdates()
- .then(async () => {
- await fetchCatchRecords();
- })
- .then(async () => {
- combinedData = [];
-
- // Combine pokedex entries with their corresponding catch records
- pokedexEntries.forEach((entry) => {
- let catchRecord = catchRecords.find((record) => record.pokedexEntryId === entry._id);
- if (catchRecord) {
- combinedData.push({ pokedexEntry: entry, catchRecord });
- }
- });
- });
+ await getData();
});
+ $: {
+ if (browser) {
+ currentPage, itemsPerPage, getData();
+ }
+ }
+
async function updateACatch(catchRecord: CatchRecord) {
alert('here');
// if (!localUser?.id) {
@@ -179,9 +82,9 @@
-
+
+ {currentPage}
+
{#each combinedData as { pokedexEntry, catchRecord }}
{/each}
+
+
+ {currentPage}
{:else}
-
Loading Pokédex
- Please be patient, this can take some time on the first load.
- {#if totalRecordsCreated > 0}
- Processing {totalRecordsCreated}/{pokedexEntries?.length}
- {:else if creatingRecords}
- Processing...
- {/if}
+
{/if}