feat(*): Add ability to filter by game and region

This commit is contained in:
Josh Creek
2024-07-14 20:51:05 +01:00
parent e871fa7fea
commit f2da6e5b37
3 changed files with 126 additions and 16 deletions
+35 -2
View File
@@ -6,7 +6,9 @@ class CombinedDataRepository {
async findCombinedData( async findCombinedData(
page: number = 1, page: number = 1,
limit: number = 20, limit: number = 20,
enableForms: boolean = true enableForms: boolean = true,
region: string = '',
game: string = ''
): Promise<CombinedData[]> { ): Promise<CombinedData[]> {
const skip = (page - 1) * limit; const skip = (page - 1) * limit;
const pipeline: any[] = [ const pipeline: any[] = [
@@ -43,6 +45,22 @@ class CombinedDataRepository {
}); });
} }
if (region.length > 0) {
pipeline.unshift({
$match: {
regionToCatchIn: region
}
});
}
if (game.length > 0) {
pipeline.unshift({
$match: {
gamesToCatchIn: { $in: [game] }
}
});
}
const combinedData: CombinedData[] = await PokedexEntryModel.aggregate(pipeline).exec(); const combinedData: CombinedData[] = await PokedexEntryModel.aggregate(pipeline).exec();
// Filter out entries with no catch records // Filter out entries with no catch records
@@ -54,13 +72,28 @@ class CombinedDataRepository {
})); }));
} }
async countCombinedData(enableForms: boolean): Promise<number> { async countCombinedData(enableForms: boolean, region: string, game: string): Promise<number> {
const filter: any = {}; const filter: any = {};
if (!enableForms) { if (!enableForms) {
filter['boxPlacement.box'] = { $ne: null }; filter['boxPlacement.box'] = { $ne: null };
} }
if (region.length > 0) {
filter['regionToCatchIn'] = region;
}
if (game.length > 0) {
// Check if gamesToCatchIn is not already defined in filter
if (!filter['gamesToCatchIn']) {
filter['gamesToCatchIn'] = [];
}
// Add the game to the filter if it's not already included
if (!filter['gamesToCatchIn'].includes(game)) {
filter['gamesToCatchIn'].push(game);
}
}
return PokedexEntryModel.countDocuments(filter).exec(); return PokedexEntryModel.countDocuments(filter).exec();
} }
} }
+4 -2
View File
@@ -6,16 +6,18 @@ export const GET = async ({ url }) => {
const page = parseInt(url.searchParams.get('page') || '1', 10); const page = parseInt(url.searchParams.get('page') || '1', 10);
const limit = parseInt(url.searchParams.get('limit') || '20', 10); const limit = parseInt(url.searchParams.get('limit') || '20', 10);
const enableForms = url.searchParams.get('enableForms') === 'true'; const enableForms = url.searchParams.get('enableForms') === 'true';
const region = url.searchParams.get('region');
const game = url.searchParams.get('game');
try { try {
await dbConnect(); await dbConnect();
const repo = new CombinedDataRepository(); const repo = new CombinedDataRepository();
const combinedData = await repo.findCombinedData(page, limit, enableForms); const combinedData = await repo.findCombinedData(page, limit, enableForms, region, game);
if (combinedData.length === 0) { if (combinedData.length === 0) {
return json({ error: 'No combined data found' }, { status: 404 }); return json({ error: 'No combined data found' }, { status: 404 });
} }
const totalCount = await repo.countCombinedData(enableForms); const totalCount = await repo.countCombinedData(enableForms, region, game);
const totalPages = Math.ceil(totalCount / limit); const totalPages = Math.ceil(totalCount / limit);
return json({ combinedData, totalPages }); return json({ combinedData, totalPages });
+87 -12
View File
@@ -16,6 +16,8 @@
let creatingRecords = false; let creatingRecords = false;
let totalRecordsCreated = 0; let totalRecordsCreated = 0;
let failedToLoad = false; let failedToLoad = false;
let catchRegion = '';
let catchGame = '';
let localUser: User | null; let localUser: User | null;
const unsubscribe = user.subscribe((value) => { const unsubscribe = user.subscribe((value) => {
@@ -39,7 +41,7 @@
combinedData = null; combinedData = null;
const response = await fetch( const response = await fetch(
`/api/combined-data?page=${currentPage}&limit=${itemsPerPage}&enableForms=${showForms}` `/api/combined-data?page=${currentPage}&limit=${itemsPerPage}&enableForms=${showForms}&region=${catchRegion}&game=${catchGame}`
); );
const data = await response.json(); const data = await response.json();
@@ -150,17 +152,90 @@
<div class="flex"> <div class="flex">
<aside class="w-64 bg-gray-800 text-white p-4 fixed h-5/6"> <aside class="w-64 bg-gray-800 text-white p-4 fixed h-5/6">
<h2 class="text-2xl font-semibold mb-4">Filters</h2> <h2 class="text-2xl font-semibold mb-4">Filters</h2>
<!-- <ul> <ul>
<li class="mb-2"><a href="#" class="block p-2 hover:bg-gray-700 rounded">Dashboard</a></li> <li class="mb-2">
<li class="mb-2"><a href="#" class="block p-2 hover:bg-gray-700 rounded">Profile</a></li> <button class="block p-2 hover:bg-gray-700 rounded" on:click={() => toggleForms()}
<li class="mb-2"><a href="#" class="block p-2 hover:bg-gray-700 rounded">Settings</a></li> >Toggle Forms (Currently {showForms ? 'On' : 'Off'})</button
<li class="mb-2"><a href="#" class="block p-2 hover:bg-gray-700 rounded">Logout</a></li> >
</ul> --> </li>
<li class="mb-2">
<button class="block p-2 hover:bg-gray-700 rounded" on:click={() => toggleOrigins()}
>Toggle Origins (Currently {showOrigins ? 'On' : 'Off'})</button
>
</li>
</ul>
<div class="mb-4"> <div class="mb-4">
<button class="btn btn-sm" on:click={() => toggleForms()}>Toggle Forms</button> <label for="catchRegionSelect">Region to catch in:</label>
{showForms ? 'On' : 'Off'} <select
<button class="btn btn-sm" on:click={() => toggleOrigins()}>Toggle Origins</button> id="catchRegionSelect"
{showOrigins ? 'On' : 'Off'} class="select select-bordered w-full max-w-xs text-black"
bind:value={catchRegion}
on:change={getData}
>
<option value="">All</option>
<option value="Kanto">Kanto (Red, Blue, Yellow, LG: Pikachu, LG: Eevee)</option>
<option value="Johto">Johto (Gold, Silver, Crystal, HG, SS)</option>
<option value="Hoenn">Hoenn (Ruby, Sapphire, Emerald, OR, AS)</option>
<option value="Sinnoh">Sinnoh (Diamond, Pearl, Platinum, BD, SP)</option>
<option value="Unova">Unova (Black, White, Black2, White2, Dream Radar)</option>
<option value="Kalos">Kalos (X, Y)</option>
<option value="Alola">Alola (Sun, Moon, Moon Demo, US, UM)</option>
<option value="Galar">Galar (Sword, Shield)</option>
<option value="Hisui">Hisui (PLA)</option>
<option value="Paldea">Paldea (Scarlet, Violet)</option>
<option value="Unknown">Unknown (Home, Go)</option>
</select>
</div>
<div class="mb-4">
<label for="catchGameSelect">Game to catch in: {catchGame}</label>
<select
id="catchGameSelect"
class="select select-bordered w-full max-w-xs text-black"
bind:value={catchGame}
on:change={getData}
>
<option value="">All</option>
<option value="Red">Red (Kanto)</option>
<option value="Blue">Blue (Kanto)</option>
<option value="Yellow">Yellow (Kanto)</option>
<option value="LG: Pikachu">LG: Pikachu (Kanto)</option>
<option value="LG: Eevee">LG: Eevee (Kanto)</option>
<option value="Gold">Gold (Johto)</option>
<option value="Silver">Silver (Johto)</option>
<option value="Crystal">Crystal (Johto)</option>
<option value="HG">HG (Johto)</option>
<option value="SS">SS (Johto)</option>
<option value="Ruby">Ruby (Hoenn)</option>
<option value="Sapphire">Sapphire (Hoenn)</option>
<option value="Emerald">Emerald (Hoenn)</option>
<option value="OR">OR (Hoenn)</option>
<option value="AS">AS (Hoenn)</option>
<option value="Diamond">Diamond (Sinnoh)</option>
<option value="Pearl">Pearl (Sinnoh)</option>
<option value="Platinum">Platinum (Sinnoh)</option>
<option value="BD">BD (Sinnoh)</option>
<option value="SP">SP (Sinnoh)</option>
<option value="Black">Black (Unova)</option>
<option value="White">White (Unova)</option>
<option value="Black2">Black2 (Unova)</option>
<option value="White2">White2 (Unova)</option>
<option value="Dream Radar">Dream Radar (Unova)</option>
<option value="X">X (Kalos)</option>
<option value="Y">Y (Kalos)</option>
<option value="Sun">Sun (Alola)</option>
<option value="Moon">Moon (Alola)</option>
<option value="Moon Demo">Moon Demo (Alola)</option>
<option value="US">US (Alola)</option>
<option value="UM">UM (Alola)</option>
<option value="Sword">Sword (Galar)</option>
<option value="Shield">Shield (Galar)</option>
<option value="PLA">PLA (Hisui)</option>
<option value="Scarlet">Scarlet (Paldea)</option>
<option value="Violet">Violet (Paldea)</option>
<option value="Home">Home (Unknown)</option>
<option value="Go">Go (Unknown)</option>
</select>
</div> </div>
<h2 class="text-2xl font-semibold mb-4">Paging</h2> <h2 class="text-2xl font-semibold mb-4">Paging</h2>
@@ -171,7 +246,7 @@
<main class="flex-1 p-4 ml-64"> <main class="flex-1 p-4 ml-64">
<div class="max-w-min mx-auto"> <div class="max-w-min mx-auto">
{#if combinedData} {#if combinedData && combinedData.length > 0}
{#each combinedData as { pokedexEntry, catchRecord }} {#each combinedData as { pokedexEntry, catchRecord }}
<PokedexEntryCatchRecord <PokedexEntryCatchRecord
{pokedexEntry} {pokedexEntry}