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(
page: number = 1,
limit: number = 20,
enableForms: boolean = true
enableForms: boolean = true,
region: string = '',
game: string = ''
): Promise<CombinedData[]> {
const skip = (page - 1) * limit;
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();
// 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 = {};
if (!enableForms) {
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();
}
}
+4 -2
View File
@@ -6,16 +6,18 @@ export const GET = async ({ url }) => {
const page = parseInt(url.searchParams.get('page') || '1', 10);
const limit = parseInt(url.searchParams.get('limit') || '20', 10);
const enableForms = url.searchParams.get('enableForms') === 'true';
const region = url.searchParams.get('region');
const game = url.searchParams.get('game');
try {
await dbConnect();
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) {
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);
return json({ combinedData, totalPages });
+87 -12
View File
@@ -16,6 +16,8 @@
let creatingRecords = false;
let totalRecordsCreated = 0;
let failedToLoad = false;
let catchRegion = '';
let catchGame = '';
let localUser: User | null;
const unsubscribe = user.subscribe((value) => {
@@ -39,7 +41,7 @@
combinedData = null;
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();
@@ -150,17 +152,90 @@
<div class="flex">
<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>
<!-- <ul>
<li class="mb-2"><a href="#" class="block p-2 hover:bg-gray-700 rounded">Dashboard</a></li>
<li class="mb-2"><a href="#" class="block p-2 hover:bg-gray-700 rounded">Profile</a></li>
<li class="mb-2"><a href="#" class="block p-2 hover:bg-gray-700 rounded">Settings</a></li>
<li class="mb-2"><a href="#" class="block p-2 hover:bg-gray-700 rounded">Logout</a></li>
</ul> -->
<ul>
<li class="mb-2">
<button class="block p-2 hover:bg-gray-700 rounded" on:click={() => toggleForms()}
>Toggle Forms (Currently {showForms ? 'On' : 'Off'})</button
>
</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">
<button class="btn btn-sm" on:click={() => toggleForms()}>Toggle Forms</button>
{showForms ? 'On' : 'Off'}
<button class="btn btn-sm" on:click={() => toggleOrigins()}>Toggle Origins</button>
{showOrigins ? 'On' : 'Off'}
<label for="catchRegionSelect">Region to catch in:</label>
<select
id="catchRegionSelect"
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>
<h2 class="text-2xl font-semibold mb-4">Paging</h2>
@@ -171,7 +246,7 @@
<main class="flex-1 p-4 ml-64">
<div class="max-w-min mx-auto">
{#if combinedData}
{#if combinedData && combinedData.length > 0}
{#each combinedData as { pokedexEntry, catchRecord }}
<PokedexEntryCatchRecord
{pokedexEntry}