7 changed files with 802 additions and 63 deletions
@ -0,0 +1,227 @@ |
|||||
|
import { Component, Input, Output, EventEmitter, SimpleChanges } from '@angular/core'; |
||||
|
import { CommonModule } from '@angular/common'; |
||||
|
import { PokemonFamilyEntry } from '../../../core/models/plan.model'; |
||||
|
import { Pokemon } from '../../../core/models/pokemon.model'; |
||||
|
import { PokemonService } from '../../../core/services/pokemon.service'; |
||||
|
import { MatChipsModule } from '@angular/material/chips'; |
||||
|
|
||||
|
@Component({ |
||||
|
selector: 'app-plan-pokemon-details', |
||||
|
standalone: true, |
||||
|
imports: [ |
||||
|
CommonModule, |
||||
|
MatChipsModule |
||||
|
], |
||||
|
template: ` |
||||
|
<div class="targets-grid" *ngIf="hasTargets"> |
||||
|
<ng-container *ngIf="evolve_to.length > 0"> |
||||
|
<div class="target-section"> |
||||
|
<h4>Evolution Targets</h4> |
||||
|
<div class="target-cards"> |
||||
|
<div |
||||
|
*ngFor="let target of evolve_to" |
||||
|
class="target-card" |
||||
|
[class.completed]="isTargetCompleted(target.PFIC)" |
||||
|
> |
||||
|
<img |
||||
|
lazyImg |
||||
|
[src]="pokemonService.getPokemonImageUrl(target)" |
||||
|
[alt]="target.Name" |
||||
|
class="target-image" |
||||
|
[class.grayscale]="isTargetCompleted(target.PFIC)" |
||||
|
> |
||||
|
<div class="target-details"> |
||||
|
<div class="target-name"> |
||||
|
{{ target.Name }} |
||||
|
<span *ngIf="target.Form">({{ target.Form }})</span> |
||||
|
</div> |
||||
|
<span *ngIf="target.EvolutionMethod">{{target?.EvolutionMethod}}</span> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</ng-container> |
||||
|
|
||||
|
<ng-container *ngIf="pokemon_family.breed_for.length > 0"> |
||||
|
<div class="target-section"> |
||||
|
<h4>Breeding Targets</h4> |
||||
|
<div class="target-cards"> |
||||
|
<div |
||||
|
*ngFor="let target of breed_for" |
||||
|
class="target-card" |
||||
|
[class.completed]="isTargetCompleted(target.PFIC)" |
||||
|
> |
||||
|
<img |
||||
|
lazyImg |
||||
|
[src]="pokemonService.getPokemonImageUrl(target)" |
||||
|
[alt]="target.Name" |
||||
|
class="target-image" |
||||
|
[class.grayscale]="isTargetCompleted(target.PFIC)" |
||||
|
> |
||||
|
<div class="target-details"> |
||||
|
<div class="target-name"> |
||||
|
{{ target.Name }} |
||||
|
<span *ngIf="target.Form">({{ target.Form }})</span> |
||||
|
</div> |
||||
|
<mat-chip-listbox> |
||||
|
<mat-chip>Breed</mat-chip> |
||||
|
</mat-chip-listbox> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</ng-container> |
||||
|
</div> |
||||
|
`,
|
||||
|
styles: [` |
||||
|
.targets-grid { |
||||
|
padding: 16px 8px; |
||||
|
display: flex; |
||||
|
flex-direction: column; |
||||
|
gap: 24px; |
||||
|
} |
||||
|
|
||||
|
.target-cards { |
||||
|
display: grid; |
||||
|
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)); |
||||
|
gap: 16px; |
||||
|
} |
||||
|
|
||||
|
.target-card { |
||||
|
display: flex; |
||||
|
align-items: center; |
||||
|
gap: 12px; |
||||
|
padding: 8px; |
||||
|
border: 1px solid #eee; |
||||
|
border-radius: 8px; |
||||
|
transition: background-color 0.3s ease; |
||||
|
|
||||
|
&:hover { |
||||
|
background-color: #f5f5f5; |
||||
|
} |
||||
|
|
||||
|
&.completed { |
||||
|
background-color: #f0f0f0; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.target-image { |
||||
|
width: 64px; |
||||
|
height: 64px; |
||||
|
object-fit: contain; |
||||
|
} |
||||
|
|
||||
|
.target-details { |
||||
|
display: flex; |
||||
|
flex-direction: column; |
||||
|
gap: 8px; |
||||
|
} |
||||
|
|
||||
|
.target-name { |
||||
|
font-weight: 500; |
||||
|
|
||||
|
span { |
||||
|
color: #666; |
||||
|
font-size: 0.9em; |
||||
|
} |
||||
|
} |
||||
|
`]
|
||||
|
}) |
||||
|
export class PlanPokemonDetailsComponent { |
||||
|
@Input() pokemon_family!: PokemonFamilyEntry; |
||||
|
evolve_to: Pokemon[] = []; |
||||
|
breed_for: Pokemon[] = []; |
||||
|
|
||||
|
constructor( |
||||
|
public pokemonService: PokemonService |
||||
|
) {} |
||||
|
|
||||
|
ngOnInit() { |
||||
|
this.evolve_to = [] |
||||
|
this.breed_for = [] |
||||
|
|
||||
|
this.loadPokemonFamilyInfo(this.pokemon_family); |
||||
|
} |
||||
|
|
||||
|
ngOnChanges(changes: SimpleChanges) { |
||||
|
if (changes['pokemon_family']) { |
||||
|
const currentFamily = changes['pokemon_family'].currentValue; |
||||
|
const previousFamily = changes['pokemon_family'].previousValue; |
||||
|
|
||||
|
// Check if there's a meaningful change
|
||||
|
if (currentFamily && currentFamily !== previousFamily) { |
||||
|
// Your logic here, e.g., re-fetch data or reset states
|
||||
|
this.loadPokemonFamilyInfo(currentFamily); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
loadPokemonFamilyInfo(newFamily: PokemonFamilyEntry) { |
||||
|
const evolveToArray: Pokemon[] = []; |
||||
|
newFamily.evolve_to.forEach((target) => { |
||||
|
this.pokemonService.getPokemonFromPFIC(target).subscribe({ |
||||
|
next: (pokemon) => { |
||||
|
if (pokemon) { |
||||
|
evolveToArray.push(pokemon); |
||||
|
} |
||||
|
}, |
||||
|
complete: () => { |
||||
|
this.customSort(evolveToArray); |
||||
|
this.evolve_to = [...evolveToArray]; // Assign once all have completed
|
||||
|
}, |
||||
|
error: (error) => { |
||||
|
console.error('Error loading Pokémon:', error); |
||||
|
} |
||||
|
}); |
||||
|
}); |
||||
|
|
||||
|
const breedForArray: Pokemon[] = []; |
||||
|
newFamily.breed_for.forEach((target) => { |
||||
|
this.pokemonService.getPokemonFromPFIC(target).subscribe({ |
||||
|
next: (pokemon) => { |
||||
|
if (pokemon) { |
||||
|
breedForArray.push(pokemon); |
||||
|
} |
||||
|
}, |
||||
|
complete: () => { |
||||
|
this.customSort(breedForArray); |
||||
|
this.breed_for = [...breedForArray]; // Assign once all have completed
|
||||
|
}, |
||||
|
error: (error) => { |
||||
|
console.error('Error loading Pokémon:', error); |
||||
|
} |
||||
|
}); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
parsePfic(pfic: string): (number | string)[] { |
||||
|
const parts = pfic.split('-'); |
||||
|
return parts.map(part => /^\d+$/.test(part) ? parseInt(part) : part); |
||||
|
} |
||||
|
|
||||
|
customSort(arr: Pokemon[]): Pokemon[] { |
||||
|
return arr.sort((a, b) => { |
||||
|
const parsedA = this.parsePfic(a.PFIC); |
||||
|
const parsedB = this.parsePfic(b.PFIC); |
||||
|
|
||||
|
for (let i = 0; i < Math.min(parsedA.length, parsedB.length); i++) { |
||||
|
if (parsedA[i] !== parsedB[i]) { |
||||
|
if (typeof parsedA[i] === 'number' && typeof parsedB[i] === 'number') { |
||||
|
return (parsedA[i] as number) - (parsedB[i] as number); |
||||
|
} |
||||
|
return (parsedA[i] as string).localeCompare(parsedB[i] as string); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return parsedA.length - parsedB.length; |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
get hasTargets(): boolean { |
||||
|
return this.pokemon_family.evolve_to.length > 0 || this.pokemon_family.breed_for.length > 0; |
||||
|
} |
||||
|
|
||||
|
isTargetCompleted(pfic: string): boolean { |
||||
|
return this.pokemonService.isTargetCompleted(pfic); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,325 @@ |
|||||
|
import { Component, Input, Output, EventEmitter, ChangeDetectorRef, SimpleChanges } from '@angular/core'; |
||||
|
import { CommonModule } from '@angular/common'; |
||||
|
import { MatExpansionModule } from '@angular/material/expansion'; |
||||
|
import { MatIconModule } from '@angular/material/icon'; |
||||
|
import { MatChipsModule } from '@angular/material/chips'; |
||||
|
import { MatTooltipModule } from '@angular/material/tooltip'; |
||||
|
import { PokemonFamilyEntry } from '../../../core/models/plan.model'; |
||||
|
import { LazyImgDirective } from '../../../shared/directives/lazy-img.directive'; |
||||
|
import { PokemonService } from '../../../core/services/pokemon.service'; |
||||
|
import { Pokemon } from '../../../core/models/pokemon.model'; |
||||
|
import { MatCardModule } from '@angular/material/card'; |
||||
|
|
||||
|
// Define an interface for the status update event
|
||||
|
interface PokemonStatusEvent { |
||||
|
pfic: string; |
||||
|
caught: boolean; |
||||
|
completed?: boolean; // Make completed optional
|
||||
|
} |
||||
|
|
||||
|
@Component({ |
||||
|
selector: 'app-plan-pokemonV2', |
||||
|
standalone: true, |
||||
|
imports: [ |
||||
|
CommonModule, |
||||
|
MatExpansionModule, |
||||
|
MatIconModule, |
||||
|
MatChipsModule, |
||||
|
MatTooltipModule, |
||||
|
LazyImgDirective, |
||||
|
MatCardModule |
||||
|
], |
||||
|
template: ` |
||||
|
|
||||
|
<mat-card |
||||
|
class="pokemon-row" |
||||
|
[class.selected]="isSelected" |
||||
|
(click)="onSelect()"> |
||||
|
<div class="pokemon-header"> |
||||
|
<img |
||||
|
lazyImg |
||||
|
[src]="pokemonService.getPokemonImageUrl(this.representative_pokemon)" |
||||
|
[alt]="this.representative_pokemon?.Name" |
||||
|
class="pokemon-thumbnail" |
||||
|
[class.grayscale]="pokemon_family.catch_count === 0" |
||||
|
> |
||||
|
|
||||
|
<div class="pokemon-info"> |
||||
|
<div class="pokemon-name"> |
||||
|
{{ this.representative_pokemon?.Name }} |
||||
|
<span class="form-name"> |
||||
|
<span *ngIf="this.pokemon_family?.Male"> |
||||
|
<img src="assets/images/Male_symbol_(fixed_width).svg" >: {{ this.pokemon_family.Male }} |
||||
|
</span> |
||||
|
<span *ngIf="this.pokemon_family?.Female"> |
||||
|
<img src="assets/images/Venus_symbol_(fixed_width).svg" >: {{ this.pokemon_family.Female }} |
||||
|
</span> |
||||
|
<span *ngIf="this.pokemon_family?.Any"> |
||||
|
<img src="assets/images/Male_and_female_sign.svg" >: {{ this.pokemon_family.Any }} |
||||
|
</span> |
||||
|
</span> |
||||
|
</div> |
||||
|
|
||||
|
<div class="catch-info"> |
||||
|
<img |
||||
|
src="/assets/images/pokeball_color.png" |
||||
|
[class.grayscale]="pokemon_family.catch_count === 0" |
||||
|
class="pokeball-icon" |
||||
|
[matTooltip]="'Need: ' + pokemon_family.catch_count" |
||||
|
> |
||||
|
<span class="catch-count">{{ pokemon_family.catch_count }}</span> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</mat-card> |
||||
|
`,
|
||||
|
styles: [` |
||||
|
.pokemon-panel { |
||||
|
margin-bottom: 8px; |
||||
|
} |
||||
|
|
||||
|
.pokemon-row{ |
||||
|
margin:5px; |
||||
|
cursor: pointer; |
||||
|
transition: transform 0.2s, box-shadow 0.2s; |
||||
|
} |
||||
|
|
||||
|
.pokemon-row:hover { |
||||
|
transform: translateY(-4px); |
||||
|
box-shadow: 0 4px 8px rgba(0,0,0,0.2); |
||||
|
} |
||||
|
|
||||
|
.pokemon-row.selected { |
||||
|
border: 2px solid #4CAF50; |
||||
|
transform: translateY(-2px); |
||||
|
} |
||||
|
|
||||
|
.pokemon-header { |
||||
|
display: flex; |
||||
|
align-items: center; |
||||
|
gap: 16px; |
||||
|
width: 100%; |
||||
|
} |
||||
|
|
||||
|
.pokemon-thumbnail { |
||||
|
width: 48px; |
||||
|
height: 48px; |
||||
|
object-fit: contain; |
||||
|
} |
||||
|
|
||||
|
.pokemon-info { |
||||
|
display: flex; |
||||
|
justify-content: space-between; |
||||
|
align-items: center; |
||||
|
flex-grow: 1; |
||||
|
} |
||||
|
|
||||
|
.pokemon-name { |
||||
|
font-weight: 500; |
||||
|
font-size: 1.1em; |
||||
|
} |
||||
|
|
||||
|
.form-name { |
||||
|
color: #666; |
||||
|
font-size: 0.9em; |
||||
|
margin-left: 4px; |
||||
|
} |
||||
|
|
||||
|
.catch-info { |
||||
|
display: flex; |
||||
|
align-items: center; |
||||
|
gap: 8px; |
||||
|
min-width: 80px; |
||||
|
} |
||||
|
|
||||
|
.pokeball-icon { |
||||
|
width: 24px; |
||||
|
height: 24px; |
||||
|
cursor: pointer; |
||||
|
transition: filter 0.3s ease; |
||||
|
} |
||||
|
|
||||
|
.grayscale { |
||||
|
filter: grayscale(100%); |
||||
|
} |
||||
|
|
||||
|
.catch-count { |
||||
|
font-weight: 500; |
||||
|
color: #4CAF50; |
||||
|
} |
||||
|
|
||||
|
.targets-grid { |
||||
|
padding: 16px 8px; |
||||
|
gap: 24px; |
||||
|
} |
||||
|
|
||||
|
.target-section { |
||||
|
h4 { |
||||
|
margin: 0 0 12px 0; |
||||
|
color: #666; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.target-cards { |
||||
|
gap: 16px; |
||||
|
display: flex; |
||||
|
flex-wrap: wrap; |
||||
|
justify-content: center; |
||||
|
} |
||||
|
|
||||
|
.target-card { |
||||
|
display: flex; |
||||
|
align-items: center; |
||||
|
gap: 12px; |
||||
|
padding: 8px; |
||||
|
border: 1px solid #eee; |
||||
|
border-radius: 8px; |
||||
|
transition: background-color 0.3s ease; |
||||
|
|
||||
|
&:hover { |
||||
|
background-color: #f5f5f5; |
||||
|
} |
||||
|
|
||||
|
&.completed { |
||||
|
background-color: #f0f0f0; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.target-image { |
||||
|
width: 64px; |
||||
|
height: 64px; |
||||
|
object-fit: contain; |
||||
|
} |
||||
|
|
||||
|
.target-details { |
||||
|
display: flex; |
||||
|
flex-direction: column; |
||||
|
gap: 8px; |
||||
|
} |
||||
|
|
||||
|
.target-name { |
||||
|
font-weight: 500; |
||||
|
|
||||
|
span { |
||||
|
color: #666; |
||||
|
font-size: 0.9em; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
mat-chip-list { |
||||
|
display: flex; |
||||
|
gap: 4px; |
||||
|
} |
||||
|
`]
|
||||
|
}) |
||||
|
export class PlanPokemonV2Component { |
||||
|
@Input() pokemon_family!: PokemonFamilyEntry; |
||||
|
@Input() isSelected = false; |
||||
|
@Output() statusUpdate = new EventEmitter<PokemonStatusEvent>(); |
||||
|
@Output() familySelected = new EventEmitter<PokemonFamilyEntry>(); |
||||
|
|
||||
|
representative_pokemon: Pokemon | null = null; |
||||
|
|
||||
|
constructor( |
||||
|
public pokemonService: PokemonService, |
||||
|
private cdr: ChangeDetectorRef |
||||
|
) {} |
||||
|
|
||||
|
ngOnInit() { |
||||
|
this.representative_pokemon = null; |
||||
|
this.handlePokemonFamilyChange(this.pokemon_family); |
||||
|
} |
||||
|
|
||||
|
ngOnChanges(changes: SimpleChanges) { |
||||
|
if (changes['pokemon_family']) { |
||||
|
const currentFamily = changes['pokemon_family'].currentValue; |
||||
|
const previousFamily = changes['pokemon_family'].previousValue; |
||||
|
|
||||
|
// Check if there's a meaningful change
|
||||
|
if (currentFamily && currentFamily !== previousFamily) { |
||||
|
// Your logic here, e.g., re-fetch data or reset states
|
||||
|
this.handlePokemonFamilyChange(currentFamily); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private handlePokemonFamilyChange(newFamily: PokemonFamilyEntry) { |
||||
|
// This function contains logic to handle the input change.
|
||||
|
// For example, resetting component states or fetching additional data.
|
||||
|
console.log('Pokemon family has changed:', newFamily); |
||||
|
|
||||
|
this.representative_pokemon = null; |
||||
|
|
||||
|
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(); |
||||
|
} |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
get hasTargets(): boolean { |
||||
|
return this.pokemon_family.evolve_to.length > 0 || this.pokemon_family.breed_for.length > 0; |
||||
|
} |
||||
|
|
||||
|
isTargetCompleted(pfic: string): boolean { |
||||
|
return this.pokemonService.isTargetCompleted(pfic); |
||||
|
} |
||||
|
|
||||
|
calculateTotalNeeded(): number { |
||||
|
let total = 1; // Initial catch
|
||||
|
let breedCount = 0; |
||||
|
let evolveCount = 0; |
||||
|
|
||||
|
// Calculate breeding needs
|
||||
|
if (this.pokemon_family.breed_for.length > 0) { |
||||
|
breedCount = 1; // We only need one for breeding, regardless of how many we breed
|
||||
|
} |
||||
|
|
||||
|
// Calculate evolution needs
|
||||
|
this.pokemon_family.evolve_to.forEach(target => { |
||||
|
if (!this.isTargetCompleted(target)) { |
||||
|
evolveCount += 1; |
||||
|
} |
||||
|
}); |
||||
|
|
||||
|
return total + breedCount + evolveCount; |
||||
|
} |
||||
|
|
||||
|
updateCatchCount() { |
||||
|
const newCount = this.calculateTotalNeeded(); |
||||
|
if (newCount !== this.pokemon_family.catch_count) { |
||||
|
this.pokemon_family.catch_count = newCount; |
||||
|
if (newCount === 0) { |
||||
|
// Emit event to move to completed section
|
||||
|
this.statusUpdate.emit({ |
||||
|
pfic: this.pokemon_family.representative, |
||||
|
caught: true, |
||||
|
completed: true |
||||
|
}); |
||||
|
} else if (newCount > 0 && this.pokemon_family.catch_count === 0) { |
||||
|
// Emit event to move back to active section
|
||||
|
this.statusUpdate.emit({ |
||||
|
pfic: this.pokemon_family.representative, |
||||
|
caught: false, |
||||
|
completed: false |
||||
|
}); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
getRepresentativePokemon() { |
||||
|
return this.pokemonService.getPokemonFromPFIC(this.pokemon_family.representative) |
||||
|
} |
||||
|
|
||||
|
trackByPfic(index: number, item: any): string { |
||||
|
return item.PFIC; // Assuming PFIC or another unique identifier is available
|
||||
|
} |
||||
|
|
||||
|
onSelect() { |
||||
|
this.familySelected.emit(this.pokemon_family); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,189 @@ |
|||||
|
import { ChangeDetectorRef, Component, OnInit, ViewChild } from '@angular/core'; |
||||
|
import { CommonModule } from '@angular/common'; |
||||
|
import { MatCardModule } from '@angular/material/card'; |
||||
|
import { FormsModule } from '@angular/forms'; |
||||
|
import { PlanGameComponent } from './plan-game/plan-game.component'; |
||||
|
import { PlanService } from '../../core/services/plan.service'; |
||||
|
import { GamePlan, PokemonFamilyEntry } from '../../core/models/plan.model'; |
||||
|
import { PlanPokemonV2Component } from "./plan-pokemon/plan-pokemonV2.component"; |
||||
|
import { ScrollingModule, CdkVirtualScrollViewport } from '@angular/cdk/scrolling'; |
||||
|
import { PlanPokemonDetailsComponent } from "./plan-pokemon-details/plan-pokemon-details.component"; |
||||
|
|
||||
|
@Component({ |
||||
|
selector: 'app-planV2', |
||||
|
standalone: true, |
||||
|
imports: [ |
||||
|
CommonModule, |
||||
|
MatCardModule, |
||||
|
FormsModule, |
||||
|
PlanGameComponent, |
||||
|
PlanPokemonV2Component, |
||||
|
ScrollingModule, |
||||
|
PlanPokemonDetailsComponent |
||||
|
], |
||||
|
template: ` |
||||
|
<div class="plan-container"> |
||||
|
<div class="games-section"> |
||||
|
<div class="games-scroll"> |
||||
|
<div class="games-list"> |
||||
|
<app-plan-game |
||||
|
*ngFor="let game of gamePlans" |
||||
|
[game]="game" |
||||
|
[isSelected]="selectedGame?.game_name === game.game_name" |
||||
|
(gameSelect)="selectGame($event)" |
||||
|
></app-plan-game> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
|
||||
|
<div class="content-section"> |
||||
|
<div class="game-stats" *ngIf="selectedGame"> |
||||
|
<h2>{{ selectedGame.game_name }} - Game Stats</h2> |
||||
|
<!-- Add game stats here --> |
||||
|
</div> |
||||
|
|
||||
|
<div class="middle-section"> |
||||
|
<div class="pokemon-section" *ngIf="selectedGame"> |
||||
|
<cdk-virtual-scroll-viewport [itemSize]="56" class="pokemon-viewport"> |
||||
|
<div *cdkVirtualFor="let pokemon of selectedGame.pokemon | keyvalue; trackBy: trackByPfic"> |
||||
|
<app-plan-pokemonV2 |
||||
|
[pokemon_family]="pokemon.value" |
||||
|
(statusUpdate)="onPokemonStatusUpdate($event)" |
||||
|
[isSelected]="selectedPokemon?.family_pfic === pokemon.key" |
||||
|
(familySelected)="selectPokemon($event)" |
||||
|
></app-plan-pokemonV2> |
||||
|
</div> |
||||
|
</cdk-virtual-scroll-viewport> |
||||
|
</div> |
||||
|
|
||||
|
<div class="details-section"> |
||||
|
<h2>{{ selectedPokemon?.representative }} - Details</h2> |
||||
|
<app-plan-pokemon-details |
||||
|
*ngIf="selectedPokemon" |
||||
|
[pokemon_family]="selectedPokemon" |
||||
|
></app-plan-pokemon-details> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
`,
|
||||
|
styles: [` |
||||
|
.plan-container { |
||||
|
display: flex; |
||||
|
height: calc(100vh - 64px); /* Adjust based on your header height */ |
||||
|
overflow: hidden; |
||||
|
} |
||||
|
|
||||
|
.games-section { |
||||
|
width: 11%; |
||||
|
padding: 20px; |
||||
|
overflow-y: auto; |
||||
|
background: #f5f5f5; |
||||
|
border-right: 1px solid #ddd; |
||||
|
} |
||||
|
|
||||
|
.games-scroll { |
||||
|
width: 100%; |
||||
|
} |
||||
|
|
||||
|
.games-list { |
||||
|
display: flex; |
||||
|
flex-direction: column; |
||||
|
gap: 16px; |
||||
|
} |
||||
|
|
||||
|
.content-section { |
||||
|
flex: 1; |
||||
|
display: flex; |
||||
|
flex-direction: column; |
||||
|
padding: 20px; |
||||
|
overflow: hidden; |
||||
|
} |
||||
|
|
||||
|
.middle-section { |
||||
|
flex: 2; |
||||
|
display: flex; |
||||
|
flex-direction: row; |
||||
|
margin-right: 20px; |
||||
|
} |
||||
|
|
||||
|
.game-stats { |
||||
|
padding-bottom: 16px; |
||||
|
border-bottom: 1px solid #ddd; |
||||
|
margin-bottom: 16px; |
||||
|
} |
||||
|
|
||||
|
.pokemon-section { |
||||
|
flex: 1; |
||||
|
min-height: 0; /* Important for Firefox */ |
||||
|
display: flex; |
||||
|
flex-direction: row; |
||||
|
margin-right: 15px; |
||||
|
} |
||||
|
|
||||
|
.pokemon-viewport { |
||||
|
flex: 1; |
||||
|
overflow-y: auto; |
||||
|
padding: 16px; |
||||
|
background: #f5f5f5; |
||||
|
border-radius: 8px; |
||||
|
margin-bottom: 20px; |
||||
|
} |
||||
|
|
||||
|
.details-section { |
||||
|
flex: 1; |
||||
|
padding: 16px; |
||||
|
background: #fff; |
||||
|
border-radius: 8px; |
||||
|
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); |
||||
|
width:15% |
||||
|
} |
||||
|
`]
|
||||
|
}) |
||||
|
export class PlanV2Component implements OnInit { |
||||
|
@ViewChild(CdkVirtualScrollViewport) viewport!: CdkVirtualScrollViewport; |
||||
|
|
||||
|
gamePlans: GamePlan[] = []; |
||||
|
selectedGame: GamePlan | null = null; |
||||
|
selectedPokemon: PokemonFamilyEntry | null = null; |
||||
|
|
||||
|
constructor(private planService: PlanService, private cdr: ChangeDetectorRef) {} |
||||
|
|
||||
|
ngOnInit() { |
||||
|
this.loadPlan(); |
||||
|
} |
||||
|
|
||||
|
private loadPlan() { |
||||
|
this.planService.getPlan().subscribe( |
||||
|
plan => { |
||||
|
this.gamePlans = plan; |
||||
|
if (!this.selectedGame && plan.length > 0) { |
||||
|
this.selectedGame = plan[0]; |
||||
|
} |
||||
|
} |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
selectGame(game: GamePlan) { |
||||
|
if (this.viewport) { |
||||
|
this.viewport.scrollToIndex(0); // Reset scroll to top when switching games
|
||||
|
} |
||||
|
this.selectedGame = null; // Clear the selected game first to avoid stale data
|
||||
|
this.cdr.detectChanges(); |
||||
|
this.selectedGame = game; |
||||
|
this.cdr.detectChanges(); |
||||
|
} |
||||
|
|
||||
|
onPokemonStatusUpdate(event: { pfic: string, caught: boolean }) { |
||||
|
this.loadPlan(); |
||||
|
} |
||||
|
|
||||
|
selectPokemon(pokemon: any) { |
||||
|
this.selectedPokemon = pokemon; |
||||
|
} |
||||
|
|
||||
|
trackByPfic(index: number, item: any): string { |
||||
|
return item.key; // Assuming PFIC or another unique identifier is available
|
||||
|
} |
||||
|
} |
||||
|
|
||||
Loading…
Reference in new issue