Browse Source

- Updates to work with the new strucutre

pull/1/head
Dan 1 year ago
parent
commit
81c8488a37
  1. 41
      src/app/core/models/plan.model.ts
  2. 10
      src/app/core/services/plan.service.ts
  3. 58
      src/app/core/services/pokemon.service.ts
  4. 8
      src/app/features/plan/plan-game/plan-game.component.ts
  5. 137
      src/app/features/plan/plan-pokemon/plan-pokemon.component.ts
  6. 4
      src/app/features/plan/plan.component.ts

41
src/app/core/models/plan.model.ts

@ -1,29 +1,14 @@
export interface GamePlan { export interface GamePlan {
game_name: string; game_name: string;
game_id: number; pokemon: Record<string, PokemonFamilyEntry>;
pokemon: PlanPokemon[]; }
}
export interface PokemonFamilyEntry {
export interface PlanPokemon { representative: string;
pfic: string; catch_count: number;
name: string; evolve_to: string[];
form_name?: string; breed_for: string[];
catch_count: number; Any?: number;
evolve_to: EvolutionTarget[]; Male?: number;
breed_for: BreedingTarget[]; Female?: number;
} }
export interface EvolutionTarget {
pfic: string;
name: string;
form_name?: string;
method: string;
count: number;
}
export interface BreedingTarget {
pfic: string;
name: string;
form_name?: string;
count: number;
}

10
src/app/core/services/plan.service.ts

@ -30,8 +30,10 @@ export class PlanService {
} }
private recalculateAffectedGames(pfic: string) { private recalculateAffectedGames(pfic: string) {
return
// This would need to check all games for the affected Pokemon // This would need to check all games for the affected Pokemon
// and update their totals accordingly // and update their totals accordingly
/*
this.getPlan().pipe(take(1)).subscribe(games => { this.getPlan().pipe(take(1)).subscribe(games => {
games.forEach(game => { games.forEach(game => {
const affectedPokemon = game.pokemon.find(p => const affectedPokemon = game.pokemon.find(p =>
@ -47,10 +49,16 @@ export class PlanService {
} }
}); });
}); });
*/
} }
private calculateGameTotal(game: GamePlan): number { private calculateGameTotal(game: GamePlan): number {
return game.pokemon.reduce((total, pokemon) => total + pokemon.catch_count, 0); var sum = 0;
for(const family in game.pokemon)
{
sum += game.pokemon[family].catch_count;
}
return sum
} }
} }

58
src/app/core/services/pokemon.service.ts

@ -1,6 +1,6 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http'; import { HttpClient } from '@angular/common/http';
import { concatMap, map, Observable, pipe, shareReplay, tap } from 'rxjs'; import { catchError, concatMap, map, Observable, pipe, shareReplay, tap } from 'rxjs';
import { Pokemon, PokemonEncounter } from '../models/pokemon.model'; import { Pokemon, PokemonEncounter } from '../models/pokemon.model';
import { environment } from '../../../environments/environment.development'; import { environment } from '../../../environments/environment.development';
import { comparePfics } from '../utils/pfic-utils'; import { comparePfics } from '../utils/pfic-utils';
@ -165,9 +165,56 @@ export class PokemonService {
return this.caughtPokemon.has(pfic); return this.caughtPokemon.has(pfic);
} }
getPokemonFromPFIC(pfic:string): Pokemon { getPokemonFromPFIC(pfic: string): Observable<Pokemon | null> {
return this.pokemonFormMap.get(pfic) as Pokemon // Check the cache for the PFIC
const cachedPokemon = this.pokemonFormMap.get(pfic);
if (cachedPokemon) {
// Return the cached Pokémon as an Observable
return new Observable((observer) => {
observer.next(cachedPokemon);
observer.complete();
});
}
// If not in cache, fetch from the server
return this.http.get<any>(`${this.apiUrl}/pokemon/${pfic}/details`).pipe(
map(data => {
const pkmn = {
PFIC: data.pfic,
Name: data.data.name,
Form: data.data.form_name,
NationalDex: data.data.national_dex,
Generation: data.data.generation,
StorableInHome: data.data.storable_in_home,
IsBabyForm: data.data.is_baby_form,
Encounters: data.data.encounters || [],
MarkIcon: "",
MarkName: data.data.mark,
Image: "",
IsDefault: data.data.is_default || false,
IsGenderRelevant: data.data.gender_relevant,
IsCaught: this.caughtPokemon.has(data.pfic)
} as Pokemon;
pkmn.MarkIcon = this.getMarkImgName(pkmn.MarkName)
pkmn.Image = this.getPokemonImageUrl(pkmn)
return pkmn;
}),
tap((pokemon) => {
// Cache the result for future requests
this.pokemonFormMap.set(pfic, pokemon);
}),
map((pokemon) => pokemon), // Map the server response directly to the output
shareReplay(1), // Cache the HTTP result for future subscribers
catchError((error): Observable<Pokemon | null> => {
console.error(`Error fetching Pokémon with PFIC ${pfic}:`, error);
return new Observable((observer) => {
observer.next(null);
observer.complete();
});
})
);
} }
updateCaughtStatus(pfic: string, caught: boolean) { updateCaughtStatus(pfic: string, caught: boolean) {
if (caught) { if (caught) {
@ -177,7 +224,10 @@ export class PokemonService {
} }
} }
getPokemonImageUrl(data: Pokemon): string { getPokemonImageUrl(data: Pokemon | null): string {
if (data === null) {
return "";
}
if (data.IsGenderRelevant) { if (data.IsGenderRelevant) {
return `/assets/images/pokemon/${data.PFIC}.png`; return `/assets/images/pokemon/${data.PFIC}.png`;
} }

8
src/app/features/plan/plan-game/plan-game.component.ts

@ -73,7 +73,13 @@ export class PlanGameComponent {
@Output() gameSelect = new EventEmitter<GamePlan>(); @Output() gameSelect = new EventEmitter<GamePlan>();
getTotalCatchCount(): number { getTotalCatchCount(): number {
return this.game.pokemon.reduce((sum, pokemon) => sum + pokemon.catch_count, 0); var sum = 0;
for(const family in this.game.pokemon)
{
sum += this.game.pokemon[family].catch_count;
}
return sum
//return this.game.pokemon.values().reduce((sum, pokemon) => sum + pokemon.catch_count, 0);
} }
getGameBoxArt(): string { getGameBoxArt(): string {

137
src/app/features/plan/plan-pokemon/plan-pokemon.component.ts

@ -1,12 +1,13 @@
import { Component, Input, Output, EventEmitter } from '@angular/core'; import { Component, Input, Output, EventEmitter, ChangeDetectorRef } from '@angular/core';
import { CommonModule } from '@angular/common'; import { CommonModule } from '@angular/common';
import { MatExpansionModule } from '@angular/material/expansion'; import { MatExpansionModule } from '@angular/material/expansion';
import { MatIconModule } from '@angular/material/icon'; import { MatIconModule } from '@angular/material/icon';
import { MatChipsModule } from '@angular/material/chips'; import { MatChipsModule } from '@angular/material/chips';
import { MatTooltipModule } from '@angular/material/tooltip'; import { MatTooltipModule } from '@angular/material/tooltip';
import { PlanPokemon } from '../../../core/models/plan.model'; import { PokemonFamilyEntry } from '../../../core/models/plan.model';
import { LazyImgDirective } from '../../../shared/directives/lazy-img.directive'; import { LazyImgDirective } from '../../../shared/directives/lazy-img.directive';
import { PokemonService } from '../../../core/services/pokemon.service'; import { PokemonService } from '../../../core/services/pokemon.service';
import { Pokemon } from '../../../core/models/pokemon.model';
// Define an interface for the status update event // Define an interface for the status update event
interface PokemonStatusEvent { interface PokemonStatusEvent {
@ -35,58 +36,58 @@ interface PokemonStatusEvent {
<div class="pokemon-header"> <div class="pokemon-header">
<img <img
lazyImg lazyImg
[src]="pokemonService.getPokemonImageUrl(pokemonService.getPokemonFromPFIC(pokemon.pfic))" [src]="pokemonService.getPokemonImageUrl(this.representative_pokemon)"
[alt]="pokemon.name" [alt]="this.representative_pokemon?.Name"
class="pokemon-thumbnail" class="pokemon-thumbnail"
[class.grayscale]="pokemon.catch_count === 0" [class.grayscale]="pokemon_family.catch_count === 0"
> >
<div class="pokemon-info"> <div class="pokemon-info">
<div class="pokemon-name"> <div class="pokemon-name">
{{ pokemon.name }} {{ this.representative_pokemon?.Name }}
<span *ngIf="pokemon.form_name" class="form-name"> <span *ngIf="this.representative_pokemon?.Form" class="form-name">
({{ pokemon.form_name }}) ({{ this.representative_pokemon?.Form }})
</span> </span>
</div> </div>
<div class="catch-info"> <div class="catch-info">
<img <img
src="/assets/images/pokeball_color.png" src="/assets/images/pokeball_color.png"
[class.grayscale]="pokemon.catch_count === 0" [class.grayscale]="pokemon_family.catch_count === 0"
class="pokeball-icon" class="pokeball-icon"
[matTooltip]="'Need: ' + pokemon.catch_count" [matTooltip]="'Need: ' + pokemon_family.catch_count"
> >
<span class="catch-count">{{ pokemon.catch_count }}</span> <span class="catch-count">{{ pokemon_family.catch_count }}</span>
</div> </div>
</div> </div>
</div> </div>
</mat-expansion-panel-header> </mat-expansion-panel-header>
<div class="targets-grid" *ngIf="hasTargets"> <div class="targets-grid" *ngIf="hasTargets">
<ng-container *ngIf="pokemon.evolve_to.length > 0"> <ng-container *ngIf="evolve_to.length > 0">
<div class="target-section"> <div class="target-section">
<h4>Evolution Targets</h4> <h4>Evolution Targets</h4>
<div class="target-cards"> <div class="target-cards">
<div <div
*ngFor="let target of pokemon.evolve_to" *ngFor="let target of evolve_to"
class="target-card" class="target-card"
[class.completed]="isTargetCompleted(target.pfic)" [class.completed]="isTargetCompleted(target.PFIC)"
> >
<img <img
lazyImg lazyImg
[src]="pokemonService.getPokemonImageUrl(pokemonService.getPokemonFromPFIC(target.pfic))" [src]="pokemonService.getPokemonImageUrl(target)"
[alt]="target.name" [alt]="target.Name"
class="target-image" class="target-image"
[class.grayscale]="isTargetCompleted(target.pfic)" [class.grayscale]="isTargetCompleted(target.PFIC)"
> >
<div class="target-details"> <div class="target-details">
<div class="target-name"> <div class="target-name">
{{ target.name }} {{ target.Name }}
<span *ngIf="target.form_name">({{ target.form_name }})</span> <span *ngIf="target.Form">({{ target.Form }})</span>
</div> </div>
<mat-chip-listbox> <mat-chip-listbox>
<mat-chip>{{ target.method }}</mat-chip> <mat-chip>Method _PLACEDHOLDER_</mat-chip>
<mat-chip color="primary" selected>Need: {{ target.count }}</mat-chip> <mat-chip color="primary" selected>Need: {{ 1 }}</mat-chip>
</mat-chip-listbox> </mat-chip-listbox>
</div> </div>
</div> </div>
@ -94,30 +95,30 @@ interface PokemonStatusEvent {
</div> </div>
</ng-container> </ng-container>
<ng-container *ngIf="pokemon.breed_for.length > 0"> <ng-container *ngIf="pokemon_family.breed_for.length > 0">
<div class="target-section"> <div class="target-section">
<h4>Breeding Targets</h4> <h4>Breeding Targets</h4>
<div class="target-cards"> <div class="target-cards">
<div <div
*ngFor="let target of pokemon.breed_for" *ngFor="let target of breed_for"
class="target-card" class="target-card"
[class.completed]="isTargetCompleted(target.pfic)" [class.completed]="isTargetCompleted(target.PFIC)"
> >
<img <img
lazyImg lazyImg
[src]="pokemonService.getPokemonImageUrl(pokemonService.getPokemonFromPFIC(target.pfic))" [src]="pokemonService.getPokemonImageUrl(target)"
[alt]="target.name" [alt]="target.Name"
class="target-image" class="target-image"
[class.grayscale]="isTargetCompleted(target.pfic)" [class.grayscale]="isTargetCompleted(target.PFIC)"
> >
<div class="target-details"> <div class="target-details">
<div class="target-name"> <div class="target-name">
{{ target.name }} {{ target.Name }}
<span *ngIf="target.form_name">({{ target.form_name }})</span> <span *ngIf="target.Form">({{ target.Form }})</span>
</div> </div>
<mat-chip-listbox> <mat-chip-listbox>
<mat-chip>Breed</mat-chip> <mat-chip>Breed</mat-chip>
<mat-chip color="primary" selected>Need: {{ target.count }}</mat-chip> <mat-chip color="primary" selected>Need: {{ 1 }}</mat-chip>
</mat-chip-listbox> </mat-chip-listbox>
</div> </div>
</div> </div>
@ -252,13 +253,61 @@ interface PokemonStatusEvent {
`] `]
}) })
export class PlanPokemonComponent { export class PlanPokemonComponent {
@Input() pokemon!: PlanPokemon; @Input() pokemon_family!: PokemonFamilyEntry;
@Output() statusUpdate = new EventEmitter<PokemonStatusEvent>(); @Output() statusUpdate = new EventEmitter<PokemonStatusEvent>();
constructor(public pokemonService: PokemonService) {} representative_pokemon: Pokemon | null = null;
evolve_to: Pokemon[] = [];
breed_for: Pokemon[] = [];
constructor(
public pokemonService: PokemonService,
private cdr: ChangeDetectorRef
) {}
ngOnInit() {
this.pokemonService.getPokemonFromPFIC(this.pokemon_family.representative).subscribe({
next: (pokemon) => {
this.representative_pokemon = pokemon
},
error: (error) => {
console.error('Error loading Pokemon:', error);
this.cdr.markForCheck();
}
});
for(const target of this.pokemon_family.evolve_to) {
this.pokemonService.getPokemonFromPFIC(target).subscribe({
next: (pokemon) => {
if(pokemon) {
this.evolve_to.push(pokemon)
}
},
error: (error) => {
console.error('Error loading Pokemon:', error);
this.cdr.markForCheck();
}
});
}
for(const target of this.pokemon_family.breed_for) {
this.pokemonService.getPokemonFromPFIC(target).subscribe({
next: (pokemon) => {
if(pokemon) {
this.breed_for.push(pokemon)
}
},
error: (error) => {
console.error('Error loading Pokemon:', error);
this.cdr.markForCheck();
}
});
}
}
get hasTargets(): boolean { get hasTargets(): boolean {
return this.pokemon.evolve_to.length > 0 || this.pokemon.breed_for.length > 0; return this.pokemon_family.evolve_to.length > 0 || this.pokemon_family.breed_for.length > 0;
} }
isTargetCompleted(pfic: string): boolean { isTargetCompleted(pfic: string): boolean {
@ -271,14 +320,14 @@ export class PlanPokemonComponent {
let evolveCount = 0; let evolveCount = 0;
// Calculate breeding needs // Calculate breeding needs
if (this.pokemon.breed_for.length > 0) { if (this.pokemon_family.breed_for.length > 0) {
breedCount = 1; // We only need one for breeding, regardless of how many we breed breedCount = 1; // We only need one for breeding, regardless of how many we breed
} }
// Calculate evolution needs // Calculate evolution needs
this.pokemon.evolve_to.forEach(target => { this.pokemon_family.evolve_to.forEach(target => {
if (!this.isTargetCompleted(target.pfic)) { if (!this.isTargetCompleted(target)) {
evolveCount += target.count; evolveCount += 1;
} }
}); });
@ -287,23 +336,27 @@ export class PlanPokemonComponent {
updateCatchCount() { updateCatchCount() {
const newCount = this.calculateTotalNeeded(); const newCount = this.calculateTotalNeeded();
if (newCount !== this.pokemon.catch_count) { if (newCount !== this.pokemon_family.catch_count) {
this.pokemon.catch_count = newCount; this.pokemon_family.catch_count = newCount;
if (newCount === 0) { if (newCount === 0) {
// Emit event to move to completed section // Emit event to move to completed section
this.statusUpdate.emit({ this.statusUpdate.emit({
pfic: this.pokemon.pfic, pfic: this.pokemon_family.representative,
caught: true, caught: true,
completed: true completed: true
}); });
} else if (newCount > 0 && this.pokemon.catch_count === 0) { } else if (newCount > 0 && this.pokemon_family.catch_count === 0) {
// Emit event to move back to active section // Emit event to move back to active section
this.statusUpdate.emit({ this.statusUpdate.emit({
pfic: this.pokemon.pfic, pfic: this.pokemon_family.representative,
caught: false, caught: false,
completed: false completed: false
}); });
} }
} }
} }
getRepresentativePokemon() {
return this.pokemonService.getPokemonFromPFIC(this.pokemon_family.representative)
}
} }

4
src/app/features/plan/plan.component.ts

@ -36,8 +36,8 @@ import { PlanPokemonComponent } from "./plan-pokemon/plan-pokemon.component";
<h2>{{ selectedGame.game_name }} - Pokémon to Catch</h2> <h2>{{ selectedGame.game_name }} - Pokémon to Catch</h2>
<div class="pokemon-list"> <div class="pokemon-list">
<app-plan-pokemon <app-plan-pokemon
*ngFor="let pokemon of selectedGame.pokemon" *ngFor="let pokemon of selectedGame.pokemon | keyvalue"
[pokemon]="pokemon" [pokemon_family]="pokemon.value"
(statusUpdate)="onPokemonStatusUpdate($event)" (statusUpdate)="onPokemonStatusUpdate($event)"
></app-plan-pokemon> ></app-plan-pokemon>
</div> </div>

Loading…
Cancel
Save