import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnInit } from '@angular/core'; import { CommonModule } from '@angular/common'; import { MatCardModule } from '@angular/material/card'; import { MatIconModule } from '@angular/material/icon'; import { MatButtonModule } from '@angular/material/button'; import { MatAutocompleteModule } from '@angular/material/autocomplete'; import { MatInputModule } from '@angular/material/input'; import { MatFormFieldModule } from '@angular/material/form-field'; import { FormControl, ReactiveFormsModule } from '@angular/forms'; import { PokemonService } from '../../../core/services/pokemon.service'; import { Pokemon } from '../../../core/models/pokemon.model'; import { PokemonCellComponent } from '../pokemon-cell/pokemon-cell.component'; import { PokemonDetailsComponent } from '../pokemon-details/pokemon-details.component'; import { map, startWith } from 'rxjs/operators'; import { Observable } from 'rxjs'; interface PokemonSearchResult { pokemon: Pokemon; boxNumber: number; } @Component({ selector: 'app-pokemon-carousel', standalone: true, imports: [ CommonModule, MatCardModule, MatIconModule, MatButtonModule, MatAutocompleteModule, MatInputModule, MatFormFieldModule, ReactiveFormsModule, PokemonCellComponent, PokemonDetailsComponent ], template: `
Search Pokémon {{ result.pokemon.Name }} ({{ result.pokemon.Form }}) (Box {{ result.boxNumber + 1 }})
Box {{ currentBoxIndex + 1 }} of {{ pokemonGroups.length }}
`, styles: [` .search-container { display: flex; justify-content: center; } .search-field { width: 100%; max-width: 400px; } .carousel-container { display: flex; align-items: center; justify-content: center; position: relative; //height: calc(100vh - 200px); padding-top: 2em; padding-bottom: 2em; } .pokemon-box-container { flex: 1; max-width: 800px; position: relative; } .pokemon-box { background-color: white; border: 2px solid #ccc; border-radius: 10px; padding: 20px; position: relative; width: 100%; box-sizing: border-box; } .box-title { background-color: #4CAF50; color: white; padding: 5px 15px; border-radius: 15px 15px 0 0; position: absolute; top: -30px; left: 20px; font-weight: bold; } .pokemon-grid { display: grid; grid-template-columns: repeat(6, 1fr); gap: 10px; } .nav-button { margin: 0 20px; &.prev { left: 0; } &.next { right: 0; } &:disabled { opacity: 0.5; } } .box-navigation { text-align: center; padding: 10px; font-size: 1.1em; color: #666; } `], changeDetection: ChangeDetectionStrategy.OnPush }) export class PokemonCarouselComponent implements OnInit { pokemonGroups: (Pokemon | null)[][] = []; currentBoxIndex = 0; selectedPokemon: Pokemon | null = null; caughtPokemon = new Set(); searchControl = new FormControl(''); filteredOptions: Observable; get currentGroup(): (Pokemon | null)[] { return this.pokemonGroups[this.currentBoxIndex] || []; } constructor( private pokemonService: PokemonService, private cdr: ChangeDetectorRef ) { this.filteredOptions = this.searchControl.valueChanges.pipe( startWith(''), map(value => this.filterPokemon(value)) ); } ngOnInit() { this.loadPokemon(); } private loadPokemon() { this.pokemonService.getPokemonList().subscribe({ next: (groups) => { this.pokemonGroups = groups; this.cdr.markForCheck(); }, error: (error) => { console.error('Error loading Pokemon:', error); this.cdr.markForCheck(); } }); } nextBox() { if (this.currentBoxIndex < this.pokemonGroups.length - 1) { this.currentBoxIndex++; this.cdr.markForCheck(); } } previousBox() { if (this.currentBoxIndex > 0) { this.currentBoxIndex--; this.cdr.markForCheck(); } } onPokemonCaught(pfic: string) { this.pokemonService.toggleCatch(pfic).subscribe( response => { if (response.status === 'caught') { this.caughtPokemon.add(pfic); } else { this.caughtPokemon.delete(pfic); } this.cdr.markForCheck(); } ); } onPokemonSelected(pokemon: Pokemon) { this.selectedPokemon = pokemon; this.cdr.markForCheck(); } private filterPokemon(value: string | PokemonSearchResult | null): PokemonSearchResult[] { if (!value) return []; const searchTerm = typeof value === 'string' ? value.toLowerCase() : ''; if (searchTerm.length < 2) return []; // Only search with 2 or more characters const results: PokemonSearchResult[] = []; this.pokemonGroups.forEach((group, boxIndex) => { group.forEach(pokemon => { if (pokemon && pokemon.Name.toLowerCase().includes(searchTerm)) { results.push({ pokemon, boxNumber: boxIndex }); } }); }); return results.slice(0, 10); // Limit to 10 results } displayFn(result: PokemonSearchResult): string { return result?.pokemon?.Name || ''; } onSearchSelect(event: any) { const result: PokemonSearchResult = event.option.value; this.currentBoxIndex = result.boxNumber; this.searchControl.setValue(''); this.cdr.markForCheck(); } }