Individual pokemon views are being served and can move to the next pokemon. Edit form can be accessed from either table or individual view and goes back to where it was.

This commit is contained in:
Kira Jiroux 2025-04-05 00:28:36 -04:00
parent 42d3a864e4
commit 99ac4581ae
17 changed files with 608 additions and 96 deletions

View File

@ -10,7 +10,12 @@ namespace Portfolio.Application.Services.PokemonService
public interface IPokemonService public interface IPokemonService
{ {
Task<List<Pokemon>> GetAllPokemonAsync(); Task<List<Pokemon>> GetAllPokemonAsync();
Task<Pokemon> GetPokemonByPokemonIdAsync(int id);
Task<Pokemon> GetPokemonByIdAsync(int id); Task<Pokemon> GetPokemonByIdAsync(int id);
Task<List<int>> GetAllPokemonIdsAsync();
Task<int?> GetPreviousPokemonIdAsync(int id);
Task<int?> GetNextPokemonIdAsync(int id);
Task<int?> GetVariationPokemonIdAsync(int id);
Task AddPokemonAsync(Pokemon pokemon); Task AddPokemonAsync(Pokemon pokemon);
Task DeletePokemonAsync(int pokemonId); Task DeletePokemonAsync(int pokemonId);
Task UpdatePokemonAsync(Pokemon pokemon); Task UpdatePokemonAsync(Pokemon pokemon);

View File

@ -33,14 +33,40 @@ namespace Portfolio.Application.Services.PokemonService
} }
public async Task<List<int>> GetAllPokemonIdsAsync()
{
return await _pokemonRepository.GetAllPokemonIdsAsync();
}
public async Task<int?> GetNextPokemonIdAsync(int id)
{
return await _pokemonRepository.GetNextPokemonIdAsync(id);
}
public async Task<Pokemon> GetPokemonByPokemonIdAsync(int id)
{
return await _pokemonRepository.GetPokemonByPokemonIdAsync(id);
}
public async Task<Pokemon> GetPokemonByIdAsync(int id) public async Task<Pokemon> GetPokemonByIdAsync(int id)
{ {
return await _pokemonRepository.GetPokemonByIdAsync(id); return await _pokemonRepository.GetPokemonByIdAsync(id);
} }
public async Task<int?> GetPreviousPokemonIdAsync(int id)
{
return await _pokemonRepository.GetPreviousPokemonIdAsync(id);
}
public async Task UpdatePokemonAsync(Pokemon pokemon) public async Task UpdatePokemonAsync(Pokemon pokemon)
{ {
await _pokemonRepository.UpdatePokemonAsync(pokemon); await _pokemonRepository.UpdatePokemonAsync(pokemon);
} }
public async Task<int?> GetVariationPokemonIdAsync(int id)
{
return await _pokemonRepository.GetVariationPokemonIdAsync(id);
}
} }
} }

View File

@ -10,6 +10,11 @@ namespace Portfolio.Domain.Features.Pokemon
{ {
Task<List<Pokemon>> GetAllPokemonsAsync(); Task<List<Pokemon>> GetAllPokemonsAsync();
Task<Pokemon> GetPokemonByIdAsync(int id); Task<Pokemon> GetPokemonByIdAsync(int id);
Task<Pokemon> GetPokemonByPokemonIdAsync(int id);
Task<List<int>> GetAllPokemonIdsAsync();
Task<int?> GetPreviousPokemonIdAsync(int currentPokemonId);
Task<int?> GetNextPokemonIdAsync(int currentPokemonId);
Task<int?> GetVariationPokemonIdAsync(int pokemonId);
Task AddPokemonAsync(Pokemon pokemon); Task AddPokemonAsync(Pokemon pokemon);
Task DeletePokemonAsync(int pokemonId); Task DeletePokemonAsync(int pokemonId);
Task UpdatePokemonAsync(Pokemon pokemon); Task UpdatePokemonAsync(Pokemon pokemon);

View File

@ -21,11 +21,14 @@ namespace Portfolio.Infrastructure.Repositories
{ {
return await _context.Pokemons.ToListAsync(); return await _context.Pokemons.ToListAsync();
} }
public async Task<Pokemon> GetPokemonByPokemonIdAsync(int id)
{
return await _context.Pokemons.FirstOrDefaultAsync(p => p.PokemonId == id);
}
public async Task<Pokemon> GetPokemonByIdAsync(int id) public async Task<Pokemon> GetPokemonByIdAsync(int id)
{ {
return await _context.Pokemons.FirstOrDefaultAsync(p => p.Id == id); return await _context.Pokemons.FirstOrDefaultAsync(p => p.Id == id);
} }
public async Task AddPokemonAsync(Pokemon pokemon) public async Task AddPokemonAsync(Pokemon pokemon)
{ {
_context.Pokemons.Add(pokemon); _context.Pokemons.Add(pokemon);
@ -46,5 +49,68 @@ namespace Portfolio.Infrastructure.Repositories
_context.Pokemons.Update(pokemon); _context.Pokemons.Update(pokemon);
await _context.SaveChangesAsync(); await _context.SaveChangesAsync();
} }
public async Task<int?> GetPreviousPokemonIdAsync(int currentPokemonId)
{
// Get the previous Pokémon's PokemonId
var prevPokemonId = await _context.Pokemons
.Where(p => p.PokemonId < currentPokemonId)
.OrderByDescending(p => p.PokemonId)
.Select(p => (int?)p.PokemonId)
.FirstOrDefaultAsync();
// If no previous PokemonId is found, wrap around to the last one
if (prevPokemonId == null)
{
prevPokemonId = await _context.Pokemons
.OrderByDescending(p => p.PokemonId) // Get the last PokemonId
.Select(p => (int?)p.PokemonId)
.FirstOrDefaultAsync();
}
return prevPokemonId;
}
public async Task<int?> GetNextPokemonIdAsync(int currentPokemonId)
{
// Get the next Pokémon's PokemonId
var nextPokemonId = await _context.Pokemons
.Where(p => p.PokemonId > currentPokemonId)
.OrderBy(p => p.PokemonId)
.Select(p => (int?)p.PokemonId)
.FirstOrDefaultAsync();
// If no next PokemonId is found, wrap around to the first one
if (nextPokemonId == null)
{
nextPokemonId = await _context.Pokemons
.OrderBy(p => p.PokemonId) // Get the first PokemonId
.Select(p => (int?)p.PokemonId)
.FirstOrDefaultAsync();
}
return nextPokemonId;
}
public async Task<List<int>> GetAllPokemonIdsAsync()
{
return await _context.Pokemons
.OrderBy(p => p.PokemonId) // Ensure it's ordered by PokemonId
.Select(p => p.PokemonId)
.ToListAsync();
}
public async Task<int?> GetVariationPokemonIdAsync(int pokemonId)
{
// Find a variation for the given PokemonId (where IsVariation is true)
var variation = await _context.Pokemons
.Where(p => p.PokemonId == pokemonId && p.IsVariation)
.FirstOrDefaultAsync();
// Return the Id of the variation, or null if no variation is found
return variation?.Id;
}
} }
} }

View File

@ -0,0 +1,9 @@
<div id="load">
<div>G</div>
<div>N</div>
<div>I</div>
<div>D</div>
<div>A</div>
<div>O</div>
<div>L</div>
</div>

View File

@ -0,0 +1,195 @@
body {
background: #000;
}
#load {
position: absolute;
width: 600px;
height: 36px;
left: 50%;
top: 40%;
margin-left: -300px;
overflow: visible;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
cursor: default;
}
#load div {
position: absolute;
width: 20px;
height: 36px;
opacity: 0;
font-family: Helvetica, Arial, sans-serif;
animation: move 3s linear infinite;
-o-animation: move 3s linear infinite;
-moz-animation: move 3s linear infinite;
-webkit-animation: move 3s linear infinite;
transform: rotate(180deg);
-o-transform: rotate(180deg);
-moz-transform: rotate(180deg);
-webkit-transform: rotate(180deg);
color: #35C4F0;
}
#load div:nth-child(2) {
animation-delay: 0.2s;
-o-animation-delay: 0.2s;
-moz-animation-delay: 0.2s;
-webkit-animation-delay: 0.2s;
}
#load div:nth-child(3) {
animation-delay: 0.4s;
-o-animation-delay: 0.4s;
-webkit-animation-delay: 0.4s;
-webkit-animation-delay: 0.4s;
}
#load div:nth-child(4) {
animation-delay: 0.6s;
-o-animation-delay: 0.6s;
-moz-animation-delay: 0.6s;
-webkit-animation-delay: 0.6s;
}
#load div:nth-child(5) {
animation-delay: 0.8s;
-o-animation-delay: 0.8s;
-moz-animation-delay: 0.8s;
-webkit-animation-delay: 0.8s;
}
#load div:nth-child(6) {
animation-delay: 1s;
-o-animation-delay: 1s;
-moz-animation-delay: 1s;
-webkit-animation-delay: 1s;
}
#load div:nth-child(7) {
animation-delay: 1.2s;
-o-animation-delay: 1.2s;
-moz-animation-delay: 1.2s;
-webkit-animation-delay: 1.2s;
}
@keyframes move {
0% {
left: 0;
opacity: 0;
}
35% {
left: 41%;
-moz-transform: rotate(0deg);
-webkit-transform: rotate(0deg);
-o-transform: rotate(0deg);
transform: rotate(0deg);
opacity: 1;
}
65% {
left: 59%;
-moz-transform: rotate(0deg);
-webkit-transform: rotate(0deg);
-o-transform: rotate(0deg);
transform: rotate(0deg);
opacity: 1;
}
100% {
left: 100%;
-moz-transform: rotate(-180deg);
-webkit-transform: rotate(-180deg);
-o-transform: rotate(-180deg);
transform: rotate(-180deg);
opacity: 0;
}
}
@-moz-keyframes move {
0% {
left: 0;
opacity: 0;
}
35% {
left: 41%;
-moz-transform: rotate(0deg);
transform: rotate(0deg);
opacity: 1;
}
65% {
left: 59%;
-moz-transform: rotate(0deg);
transform: rotate(0deg);
opacity: 1;
}
100% {
left: 100%;
-moz-transform: rotate(-180deg);
transform: rotate(-180deg);
opacity: 0;
}
}
@-webkit-keyframes move {
0% {
left: 0;
opacity: 0;
}
35% {
left: 41%;
-webkit-transform: rotate(0deg);
transform: rotate(0deg);
opacity: 1;
}
65% {
left: 59%;
-webkit-transform: rotate(0deg);
transform: rotate(0deg);
opacity: 1;
}
100% {
left: 100%;
-webkit-transform: rotate(-180deg);
transform: rotate(-180deg);
opacity: 0;
}
}
@-o-keyframes move {
0% {
left: 0;
opacity: 0;
}
35% {
left: 41%;
-o-transform: rotate(0deg);
transform: rotate(0deg);
opacity: 1;
}
65% {
left: 59%;
-o-transform: rotate(0deg);
transform: rotate(0deg);
opacity: 1;
}
100% {
left: 100%;
-o-transform: rotate(-180deg);
transform: rotate(-180deg);
opacity: 0;
}
}

View File

@ -28,7 +28,7 @@
</div> </div>
</div> </div>
<div class="bg-info-subtle border rounded border-2 border-info pokemon-flavor-text"> <div class="bg-info-subtle border rounded border-2 border-info z-3 pokemon-flavor-text">
@if (string.IsNullOrEmpty(_pokemon.FlavorText)) @if (string.IsNullOrEmpty(_pokemon.FlavorText))
{ {
<p class="">[ Pokemon Flavor Text Placeholder ]</p> <p class="">[ Pokemon Flavor Text Placeholder ]</p>

View File

@ -0,0 +1,6 @@
@inject NavigationManager Navigation
<button class="btn btn-warning" @onclick="() => EditPokemon(PokemonId)">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-pencil-fill" viewBox="0 0 16 16">
<path d="M12.854.146a.5.5 0 0 0-.707 0L10.5 1.793 14.207 5.5l1.647-1.646a.5.5 0 0 0 0-.708zm.646 6.061L9.793 2.5 3.293 9H3.5a.5.5 0 0 1 .5.5v.5h.5a.5.5 0 0 1 .5.5v.5h.5a.5.5 0 0 1 .5.5v.5h.5a.5.5 0 0 1 .5.5v.207zm-7.468 7.468A.5.5 0 0 1 6 13.5V13h-.5a.5.5 0 0 1-.5-.5V12h-.5a.5.5 0 0 1-.5-.5V11h-.5a.5.5 0 0 1-.5-.5V10h-.5a.5.5 0 0 1-.175-.032l-.179.178a.5.5 0 0 0-.11.168l-2 5a.5.5 0 0 0 .65.65l5-2a.5.5 0 0 0 .168-.11z" />
</svg>
</button>

View File

@ -0,0 +1,15 @@
using Microsoft.AspNetCore.Components;
using Microsoft.EntityFrameworkCore.Metadata.Internal;
namespace Portfolio.WebUI.Server.Components.Component
{
public partial class PokemonEditButton
{
[Parameter] public int PokemonId { get; set; }
private void EditPokemon(int PokemonId)
{
Navigation.NavigateTo($"/pokemonsleep/edit/{PokemonId}");
}
}
}

View File

@ -6,62 +6,63 @@
@rendermode InteractiveServer @rendermode InteractiveServer
<!-- Main Body --> <!-- Main UI -->
@if (pokemons == null) <div class="card shadow border-0 mt-4 m-auto w-50">
{
<p><em>Loading...</em></p>
}
else
{
<!-- Main UI -->
<div class="card shadow border-0 mt-4 m-auto w-50">
<!-- Table Header --> <!-- Table Header -->
<div class="card-header bg-secondary bg-gradient ml-0 py-3"> <div class="card-header bg-secondary bg-gradient ml-0 py-3">
<div class="row"> <div class="row">
<div class="col-12 text-center position-relative"> <div class="col-12 text-center position-relative">
<h2 class="text-info">Available Pokémon</h2> <h2 class="text-info">Available Pokémon</h2>
<div class="m-1 col-1 badge bg-info position-absolute top-0 end-0"><p class="statText">@(pokemons.Count()) Pokemon</p></div> <div class="m-1 col-1 badge bg-info position-absolute top-0 end-0"><p class="statText">@(pokemons.Count()) Pokemon</p></div>
</div>
</div> </div>
</div> </div>
</div>
<!-- Table --> <!-- Table -->
<div class="tableFixHead"> <div class="tableFixHead">
<table class="table table-striped"> <table class="table table-striped">
<!-- Table Head -->
<thead>
<tr>
<th class="text-bg-info col col-2" scope="col"></th>
<th class="text-bg-info col pokemon-dex-width" scope="col">#</th>
<th class="text-bg-info col pokemon-name-width" scope="col">Pokemon</th>
<th class="text-bg-info col pokemon-type-width" scope="col">Type</th>
<th class="text-bg-info col pokemon-type-width" scope="col">Sleep Type</th>
<th class="text-bg-info col pokemon-type-width" scope="col">Speciality</th>
<th class="text-bg-info col pokemon-type-width" scope="col"></th>
</tr>
</thead>
<!-- Table Head -->
<thead>
<tr>
<th class="text-bg-info col col-2" scope="col"></th>
<th class="text-bg-info col pokemon-dex-width" scope="col">#</th>
<th class="text-bg-info col pokemon-name-width" scope="col">Pokemon</th>
<th class="text-bg-info col pokemon-type-width" scope="col">Type</th>
<th class="text-bg-info col pokemon-type-width" scope="col">Sleep Type</th>
<th class="text-bg-info col pokemon-type-width" scope="col">Speciality</th>
<th class="text-bg-info col pokemon-type-width" scope="col"></th>
</tr>
</thead>
@if(pokemons == null)
{
<tbody>
<Loading />
</tbody>
}
else
{
<!-- Table Body --> <!-- Table Body -->
<tbody> <tbody>
@foreach (var pokemon in pokemons) @foreach (var pokemon in pokemons)
{ {
<tr> <tr>
<!-- Section: Pokemon Image --> <!-- Section: Pokemon Image -->
@{ @{
string baseUrl = pokemon.PokemonImageUrl; string baseUrl = pokemon.PokemonImageUrl;
string shinyUrl = pokemon.PokemonShinyImageUrl; string shinyUrl = pokemon.PokemonShinyImageUrl;
} }
<td style="text-align: center;"> <td style="text-align: center;">
@if(shinyUrl == null){ @if (shinyUrl == null)
{
<div class="flip-container"> <div class="flip-container">
<div class="flipper"> <div class="flipper">
<img class="front" src="@baseUrl" /> <img class="front" src="@baseUrl" />
</div> </div>
</div> </div>
} }
else else
{ {
@ -71,7 +72,7 @@ else
<img class="back" src="@shinyUrl" /> <img class="back" src="@shinyUrl" />
</div> </div>
</div> </div>
} }
</td> </td>
@ -83,22 +84,22 @@ else
{ {
@if (pokemon.VariationName == "Alolan") @if (pokemon.VariationName == "Alolan")
{ {
<td style="vertical-align: auto;"> Alolan @pokemon.PokemonName</td> <td @onclick="() => ViewPokemon(pokemon.PokemonId)" style="vertical-align: auto;"> Alolan @pokemon.PokemonName</td>
} }
@if (pokemon.VariationName == "Paldean") @if (pokemon.VariationName == "Paldean")
{ {
<td style="vertical-align: auto;"> Paldean @pokemon.PokemonName</td> <td @onclick="() => ViewPokemon(pokemon.PokemonId)" style="vertical-align: auto;"> Paldean @pokemon.PokemonName</td>
} }
} }
else // Otherwise, Base Case else // Otherwise, Base Case
{ {
<td style="vertical-align: auto;"> @pokemon.PokemonName</td> <td @onclick="() => ViewPokemon(pokemon.PokemonId)" style="vertical-align: auto;"> @pokemon.PokemonName</td>
} }
<!-- Section 4: Pokemon Type --> <!-- Section 4: Pokemon Type -->
<td > <td>
<div class="m-1 col-1" > <div class="m-1 col-1">
<img src="@GetTypeImageUrl(pokemon.PokemonType)" class="" style="width:60px; height:60px;" /> <img src="@GetTypeImageUrl(pokemon.PokemonType)" class="" style="width:60px; height:60px;" />
</div> </div>
</td> </td>
@ -115,14 +116,10 @@ else
<!-- Section 7: Functional Buttons --> <!-- Section 7: Functional Buttons -->
<td> <td>
<button class="btn btn-warning" @onclick="() => EditPokemon(pokemon.Id)"> <PokemonEditButton PokemonId="pokemon.Id" />
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-pencil-fill" viewBox="0 0 16 16">
<path d="M12.854.146a.5.5 0 0 0-.707 0L10.5 1.793 14.207 5.5l1.647-1.646a.5.5 0 0 0 0-.708zm.646 6.061L9.793 2.5 3.293 9H3.5a.5.5 0 0 1 .5.5v.5h.5a.5.5 0 0 1 .5.5v.5h.5a.5.5 0 0 1 .5.5v.5h.5a.5.5 0 0 1 .5.5v.207zm-7.468 7.468A.5.5 0 0 1 6 13.5V13h-.5a.5.5 0 0 1-.5-.5V12h-.5a.5.5 0 0 1-.5-.5V11h-.5a.5.5 0 0 1-.5-.5V10h-.5a.5.5 0 0 1-.175-.032l-.179.178a.5.5 0 0 0-.11.168l-2 5a.5.5 0 0 0 .65.65l5-2a.5.5 0 0 0 .168-.11z" />
</svg>
</button>
<button class="btn btn-danger" @onclick="() => ConfirmDelete(pokemon.Id)"> <button class="btn btn-danger" @onclick="() => ConfirmDelete(pokemon.Id)">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor"
class="bi bi-trash" viewBox="0 0 16 16"> class="bi bi-trash" viewBox="0 0 16 16">
<path d="M5.5 5.5A.5.5 0 0 1 6 6v6a.5.5 0 0 1-1 0V6a.5.5 0 0 1 .5-.5m2.5 0a.5.5 0 0 1 .5.5v6a.5.5 0 0 1-1 0V6a.5.5 0 0 1 .5-.5m3 .5a.5.5 0 0 0-1 0v6a.5.5 0 0 0 1 0z" /> <path d="M5.5 5.5A.5.5 0 0 1 6 6v6a.5.5 0 0 1-1 0V6a.5.5 0 0 1 .5-.5m2.5 0a.5.5 0 0 1 .5.5v6a.5.5 0 0 1-1 0V6a.5.5 0 0 1 .5-.5m3 .5a.5.5 0 0 0-1 0v6a.5.5 0 0 0 1 0z" />
<path d="M14.5 3a1 1 0 0 1-1 1H13v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V4h-.5a1 1 0 0 1-1-1V2a1 1 0 0 1 1-1H6a1 1 0 0 1 1-1h2a1 1 0 0 1 1 1h3.5a1 1 0 0 1 1 1zM4.118 4 4 4.059V13a1 1 0 0 0 1 1h6a1 1 0 0 0 1-1V4.059L11.882 4zM2.5 3h11V2h-11z" /> <path d="M14.5 3a1 1 0 0 1-1 1H13v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V4h-.5a1 1 0 0 1-1-1V2a1 1 0 0 1 1-1H6a1 1 0 0 1 1-1h2a1 1 0 0 1 1 1h3.5a1 1 0 0 1 1 1zM4.118 4 4 4.059V13a1 1 0 0 0 1 1h6a1 1 0 0 0 1-1V4.059L11.882 4zM2.5 3h11V2h-11z" />
</svg> </svg>
@ -132,9 +129,11 @@ else
</tr> </tr>
} }
</tbody> </tbody>
}
</table> </table>
</div>
</div> </div>
</div>
}

View File

@ -33,7 +33,7 @@ else
<DataAnnotationsValidator /> <DataAnnotationsValidator />
<!-- Section 1 --> <!-- Section 1 -->
<div class="row "> <div class="row mt-3">
<div class="col-sm-3 input-group mb-3 "> <div class="col-sm-3 input-group mb-3 ">
<!-- Pokemon #--> <!-- Pokemon #-->
<span for="PokemonId" class="input-group-text">#</span> <span for="PokemonId" class="input-group-text">#</span>
@ -43,6 +43,53 @@ else
</div> </div>
</div> </div>
<!-- Pokemon Type, Sleep Type, and Speciality -->
<div class="row">
<!-- Pokemon Type -->
<div class="col mb-3 m-auto">
<label for="PokemonType" class="form-label">Pokemon Type</label>
<InputSelect id="PokemonType" @bind-Value="NewPokemon.PokemonType" class="form-select">
<option dsabled value="">Select Type</option>
<option value="Grass">Grass</option>
<option value="Fire">Fire</option>
<option value="Water">Water</option>
<option value="Normal">Normal</option>
<option value="Flying">Flying</option>
<option value="Bug">Bug</option>
<option value="Poison">Poison</option>
<option value="Electric">Electric</option>
<option value="Ground">Ground</option>
<option value="Rock">Rock</option>
<option value="Ice">Ice</option>
<option value="Steel">Steel</option>
<option value="Fighting">Fighting</option>
<option value="Psychic">Psychic</option>
<option value="Dark">Dark</option>
<option value="Fairy">Fairy</option>
<option value="Ghost">Ghost</option>
<option value="Dragon">Dragon</option>
</InputSelect>
</div>
<!-- Sleep Type -->
<div class="col mb-3 m-auto">
<label for="SleepType" class="form-label">Sleep Type</label>
<InputSelect id="SleepType" @bind-Value="NewPokemon.SleepType" class="form-select">
<option value="Dozing">Dozing</option>
<option value="Snoozing">Snoozing</option>
<option value="Slumbering">Slumbering</option>
</InputSelect>
</div>
<!-- Speciality-->
<div class="col mb-3 m-auto">
<label for="Speciality" class="form-label">Specialty</label>
<InputSelect id="Speciality" @bind-Value="NewPokemon.Speciality" class="form-select">
<option value="Berries">Berries</option>
<option value="Ingredients">Ingredients</option>
<option value="Skills">Skills</option>
</InputSelect>
</div>
</div>
<!-- Section 2 --> <!-- Section 2 -->
<div class="row"> <div class="row">
<div class="input-group mb-3"> <div class="input-group mb-3">
@ -59,31 +106,6 @@ else
</div> </div>
</div> </div>
</div> </div>
<!-- Section 3 -->
<div class="row mb-3 m-auto" >
<label for="SleepType" class="form-label">Sleep Type</label>
<InputSelect id="SleepType" @bind-Value="NewPokemon.SleepType" class="form-select">
<option hidden value="">Dozing / Snoozing / Slumbering</option>
<option value="Dozing">Dozing</option>
<option value="Snoozing">Snoozing</option>
<option value="Slumbering">Slumbering</option>
</InputSelect>
</div>
<!-- Section 4 -->
<div class="row mb-3 m-auto">
<label for="Speciality" class="form-label">Specialty</label>
<InputSelect id="SleepType" @bind-Value="NewPokemon.Speciality" class="form-select">
<option hidden value="">Berries / Ingredients / Skills</option>
<option value="Berries">Berries</option>
<option value="Ingredients">Ingredients</option>
<option value="Skills">Skills</option>
<option value="Other">Other</option>
</InputSelect>
</div>
<!-- New Image URL Field --> <!-- New Image URL Field -->
<div class="row mb-3 m-auto"> <div class="row mb-3 m-auto">
<label for="ImageUrl" class="form-label">Base Image URL</label> <label for="ImageUrl" class="form-label">Base Image URL</label>
@ -93,8 +115,12 @@ else
<label for="ImageUrl" class="form-label">Shiny Image URL</label> <label for="ImageUrl" class="form-label">Shiny Image URL</label>
<InputText id="ImageUrl" @bind-Value="NewPokemon.PokemonShinyImageUrl" class="form-control" /> <InputText id="ImageUrl" @bind-Value="NewPokemon.PokemonShinyImageUrl" class="form-control" />
</div> </div>
<button type="submit" class="btn btn-primary mb-3">Add Pokémon</button>
<button type="button" class="btn btn-secondary mb-3" @onclick="@Cancel">Cancel</button> <!-- Form Buttons -->
<div class="d-flex justify-content-between">
<button type="button" class="btn btn-secondary mb-3" @onclick="Cancel">Cancel</button>
<button type="submit" class="btn btn-primary mb-3">Add Pokemon</button>
</div>
</EditForm> </EditForm>
</div> </div>
</div> </div>

View File

@ -1,6 +1,7 @@
@page "/pokemonsleep/edit/{id:int}" @page "/pokemonsleep/edit/{id:int}"
@inject IPokemonService PokemonService @inject IPokemonService PokemonService
@inject NavigationManager Navigation @inject NavigationManager Navigation
@inject IJSRuntime JSRuntime
@attribute [StreamRendering] @attribute [StreamRendering]
@rendermode InteractiveServer @rendermode InteractiveServer
@ -31,7 +32,8 @@ else
<EditForm class="col mb-3" Model="pokemon" OnValidSubmit="HandleSubmit"> <EditForm class="col mb-3" Model="pokemon" OnValidSubmit="HandleSubmit">
<DataAnnotationsValidator /> <DataAnnotationsValidator />
<div class="row"> <!-- Dex Number and Name -->
<div class="row ">
<div class="col-sm-3 input-group mb-3"> <div class="col-sm-3 input-group mb-3">
<span for="PokemonId" class="input-group-text">#</span> <span for="PokemonId" class="input-group-text">#</span>
<InputNumber min="0" id="PokemonId" @bind-Value="pokemon.PokemonId" class="form-control" required disabled /> <InputNumber min="0" id="PokemonId" @bind-Value="pokemon.PokemonId" class="form-control" required disabled />
@ -39,7 +41,9 @@ else
</div> </div>
</div> </div>
<!-- Pokemon Type, Sleep Type, and Speciality -->
<div class="row"> <div class="row">
<!-- Pokemon Type -->
<div class="col mb-3 m-auto"> <div class="col mb-3 m-auto">
<label for="PokemonType" class="form-label">Pokemon Type</label> <label for="PokemonType" class="form-label">Pokemon Type</label>
<InputSelect id="PokemonType" @bind-Value="pokemon.PokemonType" class="form-select"> <InputSelect id="PokemonType" @bind-Value="pokemon.PokemonType" class="form-select">
@ -64,7 +68,7 @@ else
<option value="Dragon">Dragon</option> <option value="Dragon">Dragon</option>
</InputSelect> </InputSelect>
</div> </div>
<!-- Sleep Type -->
<div class="col mb-3 m-auto"> <div class="col mb-3 m-auto">
<label for="SleepType" class="form-label">Sleep Type</label> <label for="SleepType" class="form-label">Sleep Type</label>
<InputSelect id="SleepType" @bind-Value="pokemon.SleepType" class="form-select"> <InputSelect id="SleepType" @bind-Value="pokemon.SleepType" class="form-select">
@ -73,7 +77,7 @@ else
<option value="Slumbering">Slumbering</option> <option value="Slumbering">Slumbering</option>
</InputSelect> </InputSelect>
</div> </div>
<!-- Speciality-->
<div class="col mb-3 m-auto"> <div class="col mb-3 m-auto">
<label for="Speciality" class="form-label">Specialty</label> <label for="Speciality" class="form-label">Specialty</label>
<InputSelect id="Speciality" @bind-Value="pokemon.Speciality" class="form-select"> <InputSelect id="Speciality" @bind-Value="pokemon.Speciality" class="form-select">
@ -83,30 +87,46 @@ else
</InputSelect> </InputSelect>
</div> </div>
</div> </div>
<!-- Variation Check -->
<div class="row">
<div class="input-group mb-3">
<!-- Variation Check -->
<div class=" d-inline-flex">
<InputCheckbox id="IsVariation" @bind-Value="pokemon.IsVariation" @onclick="@Toggle" class="form-check-input checkbox-styling p-3 mt-1" />
<span for="IsVariation" class="input-group-text m-1">Variation?</span>
</div>
<!-- Variation Region Input -->
<div class="w-75 mx-2 mt-1">
<InputText placeholder="What Variant? (Alolan, Paldean)" hidden="@HideLabel" id="VariationName" @bind-Value="pokemon.VariationName" class="form-control" />
</div>
</div>
</div>
<!-- New Image URL Field --> <!-- Image URL Input -->
<div class="row mb-3 m-auto"> <div class="row mb-3 m-auto">
<label for="ImageUrl" class="form-label">Base Image URL</label> <label for="ImageUrl" class="form-label">Base Image URL</label>
<InputText id="ImageUrl" @bind-Value="pokemon.PokemonImageUrl" class="form-control" /> <InputText id="ImageUrl" @bind-Value="pokemon.PokemonImageUrl" class="form-control" />
</div> </div>
<!-- Shiny Image URL Input -->
<div class="row mb-3 m-auto"> <div class="row mb-3 m-auto">
<label for="ImageUrl" class="form-label">Shiny Image URL</label> <label for="ImageUrl" class="form-label">Shiny Image URL</label>
<InputText id="ImageUrl" @bind-Value="pokemon.PokemonShinyImageUrl" class="form-control" /> <InputText id="ImageUrl" @bind-Value="pokemon.PokemonShinyImageUrl" class="form-control" />
</div> </div>
<!-- Flavor Text Input -->
<div class="row mb-3 m-auto"> <div class="row mb-3 m-auto">
<label for="FlavorText" class="form-label">Flavor Text</label> <label for="FlavorText" class="form-label">Flavor Text</label>
<InputText id="FlavorText" @bind-Value="pokemon.FlavorText" class="form-control" required /> <InputText id="FlavorText" @bind-Value="pokemon.FlavorText" class="form-control" required />
</div> </div>
<button type="submit" class="btn btn-primary mb-3">Save Changes</button> <!-- Form Buttons -->
<button type="button" class="btn btn-secondary mb-3" @onclick="Cancel">Cancel</button> <div class="d-flex justify-content-between">
<button type="button" class="btn btn-secondary mb-3" @onclick="Cancel">Cancel</button>
<button type="submit" class="btn btn-primary mb-3">Save Changes</button>
</div>
</EditForm> </EditForm>
</div> </div>
</div> </div>
} }
@code {
}

View File

@ -1,4 +1,5 @@
using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.Components;
using Microsoft.JSInterop;
using Portfolio.Domain.Features.Pokemon; using Portfolio.Domain.Features.Pokemon;
namespace Portfolio.WebUI.Server.Components.Pages namespace Portfolio.WebUI.Server.Components.Pages
@ -16,12 +17,21 @@ namespace Portfolio.WebUI.Server.Components.Pages
private async Task HandleSubmit() private async Task HandleSubmit()
{ {
await PokemonService.UpdatePokemonAsync(pokemon); await PokemonService.UpdatePokemonAsync(pokemon);
Navigation.NavigateTo("/pokemonsleep"); //Navigation.NavigateTo("/pokemonsleep");
await JSRuntime.InvokeVoidAsync("history.back");
} }
private void Cancel() private async void Cancel()
{ {
Navigation.NavigateTo("/pokemonsleep"); await JSRuntime.InvokeVoidAsync("history.back");
} }
private bool HideLabel { get; set; } = true;
private void Toggle()
{
HideLabel = !HideLabel;
}
} }
} }

View File

@ -9,7 +9,7 @@
<PageTitle>Pokémon Sleep</PageTitle> <PageTitle>Pokémon Sleep</PageTitle>
<div class="w-100"> <div class="w-100">
<PokemonBackground PokemonImages="pokemonImageUrls" ShinyPokemonImages="pokemonShinyImageUrls" /> <!-- <PokemonBackground PokemonImages="pokemonImageUrls" ShinyPokemonImages="pokemonShinyImageUrls" /> -->
<PokemonHeader /> <PokemonHeader />

View File

@ -1,5 +1,81 @@
@page "/pokemonsleep/pokemon/{id:int}" @page "/pokemonsleep/pokemon/{id:int}"
@inject IPokemonService PokemonService
@inject NavigationManager Navigation
@code { @attribute [StreamRendering]
@rendermode InteractiveServer
<PokemonHeader />
@if (_pokemon == null)
{
<p><em>Loading...</em></p>
}
else
{
<PageTitle>@_pokemon.PokemonName</PageTitle>
<!-- Total Componenet-->
<div class="w-100">
<div class="d-flex justify-content-center mt-4">
<button class="mt-1 p-2 btn btn-danger rounded-5 align-self-start shadow-sm" disabled="@(!_previousPokemonId.HasValue)" @onclick="NavigateToPrevious">
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" fill="currentColor" class="bi bi-arrow-left-circle-fill" viewBox="0 0 16 16">
<path d="M8 0a8 8 0 1 0 0 16A8 8 0 0 0 8 0m3.5 7.5a.5.5 0 0 1 0 1H5.707l2.147 2.146a.5.5 0 0 1-.708.708l-3-3a.5.5 0 0 1 0-.708l3-3a.5.5 0 1 1 .708.708L5.707 7.5z" />
</svg>
</button>
<div class="mt-5 mx-5 d-flex justify-content-center">
@if (_variationPokemonId != null)
{
@if (_variationPokemonId != null && _pokemonVariant == null){
<p><em>Loading...</em></p>
}
else
{
@if(_pokemon.Id != _pokemonVariant.Id)
{
<div class="d-flex justify-content-center">
<div class="position-relative">
<PokemonCard Pokemon="_pokemon" />
<div class="position-absolute top-100 start-50 translate-middle mt-5">
<PokemonEditButton PokemonId="_pokemon.Id" />
</div>
</div>
<div class="position-relative">
<PokemonCard Pokemon="_pokemonVariant" />
<div class="position-absolute top-100 start-50 translate-middle mt-5">
<PokemonEditButton PokemonId="_pokemonVariant.Id" />
</div>
</div>
</div>
}
else
{
<div class="position-relative">
<PokemonCard Pokemon="_pokemonVariant" />
<div class="position-absolute top-100 start-50 translate-middle mt-5">
<PokemonEditButton PokemonId="_pokemonVariant.Id" />
</div>
</div>
}
}
}
else{
<div class="position-relative">
<PokemonCard Pokemon="_pokemon" />
<div class="position-absolute top-100 start-50 translate-middle mt-5">
<PokemonEditButton PokemonId="_pokemon.Id" />
</div>
</div>
}
</div>
<button class="mt-1 p-2 btn btn-danger rounded-5 align-self-start shadow-sm" disabled="@(!_nextPokemonId.HasValue)" @onclick="NavigateToNext">
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" fill="currentColor" class="bi bi-arrow-right-circle-fill" viewBox="0 0 16 16">
<path d="M8 0a8 8 0 1 1 0 16A8 8 0 0 1 8 0M4.5 7.5a.5.5 0 0 0 0 1h5.793l-2.147 2.146a.5.5 0 0 0 .708.708l3-3a.5.5 0 0 0 0-.708l-3-3a.5.5 0 1 0-.708.708L10.293 7.5z" />
</svg>
</button>
</div>
</div>
} }

View File

@ -0,0 +1,52 @@
using Microsoft.AspNetCore.Components;
using Portfolio.Domain.Features.Pokemon;
namespace Portfolio.WebUI.Server.Components.Pages
{
public partial class PokemonView
{
[Parameter] public int Id { get; set; }
private Pokemon? _pokemon;
private Pokemon? _pokemonVariant;
private List<int> _pokemonIds;
private int? _nextPokemonId;
private int? _previousPokemonId;
private int? _variationPokemonId;
private int _currentIndex;
protected override async Task OnParametersSetAsync()
{
_pokemon = await PokemonService.GetPokemonByPokemonIdAsync(Id);
// These can be smart queries if your data is sorted by ID or by another property
_pokemonIds = await PokemonService.GetAllPokemonIdsAsync();
_currentIndex = _pokemonIds.IndexOf(_pokemon.PokemonId);
//Console.WriteLine(_currentIndex);
_nextPokemonId = await PokemonService.GetNextPokemonIdAsync(Id);
_previousPokemonId = await PokemonService.GetPreviousPokemonIdAsync(Id);
_variationPokemonId = await PokemonService.GetVariationPokemonIdAsync(Id);
if (_variationPokemonId != null)
{
Console.WriteLine(_variationPokemonId);
_pokemonVariant = await PokemonService.GetPokemonByIdAsync((int)_variationPokemonId);
Console.WriteLine(_pokemonVariant.VariationName);
}
}
private void NavigateToNext()
{
if (_nextPokemonId.HasValue)
Navigation.NavigateTo($"/pokemonsleep/pokemon/{_nextPokemonId.Value}");
}
private void NavigateToPrevious()
{
if (_previousPokemonId.HasValue)
Navigation.NavigateTo($"/pokemonsleep/pokemon/{_previousPokemonId.Value}");
}
}
}

View File

@ -0,0 +1,2 @@
body {
}