Compare commits

...

4 Commits

Author SHA1 Message Date
Kira Jiroux 82edd11e08 Finalizing base dependency injection. 2025-02-17 14:34:08 -05:00
Kira Jiroux 14ebe20a56 Add DependencyInjection for Article/Pokemon Services. 2025-02-17 14:02:20 -05:00
Kira Jiroux 4a2d6dfd87 Adding features; one with video, one to experiment + introduce made functionality from other project 2025-02-17 12:08:43 -05:00
Kira Jiroux 3938dfc0eb Added Domain and Application Layers 2025-02-17 11:58:47 -05:00
17 changed files with 14686 additions and 41 deletions

View File

@ -0,0 +1,22 @@
using Microsoft.Extensions.DependencyInjection;
using Portfolio.Application.Services.Articles;
using Portfolio.Application.Services.PokemonService;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Portfolio.Application
{
public static class DependencyInjection
{
public static IServiceCollection AddApplication(this IServiceCollection services)
{
services.AddScoped<IArticleService, ArticleService>();
services.AddScoped<IPokemonService, PokemonService>();
return services;
}
}
}

View File

@ -0,0 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="9.0.2" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Portfolio.Domain\Portfolio.Domain.csproj" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,34 @@
using Portfolio.Domain.Features.Articles;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Portfolio.Application.Services.Articles
{
public class ArticleService : IArticleService
{
public List<Article> GetAllArticles()
{
return new List<Article>() {
new Article
{
Id = 1,
Title = "Fantasy",
Content = "Pink ponies and purple giraffes roamed the field. Cotton candy grew from the ground as a chocolate river meandered off to the side. What looked like stones in the pasture were actually rock candy. Everything in her dream seemed to be perfect except for the fact that she had no mouth.",
},
new Article
{
Id = 2,
Title = "Why",
Content = "Sometimes there isn't a good answer. No matter how you try to rationalize the outcome, it doesn't make sense. And instead of an answer, you are simply left with a question. Why?",
}
};
}
}
}

View File

@ -0,0 +1,14 @@
using Portfolio.Domain.Features.Articles;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Portfolio.Application.Services.Articles
{
public interface IArticleService
{
List<Article> GetAllArticles();
}
}

View File

@ -0,0 +1,14 @@
using Portfolio.Domain.Features.Pokemon;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Portfolio.Application.Services.PokemonService
{
public interface IPokemonService
{
List<Pokemon> GetAllPokemon();
}
}

View File

@ -0,0 +1,47 @@
using Portfolio.Domain.Features.Articles;
using Portfolio.Domain.Features.Pokemon;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Portfolio.Application.Services.PokemonService
{
public class PokemonService : IPokemonService
{
public List<Pokemon> GetAllPokemon()
{
return new List<Pokemon>() {
new Pokemon
{
Id = 1,
PokemonId = "001",
PokemonName = "Bulbasaur",
SleepType = "Dozing",
Speciality = "Ingredients"
},
new Pokemon
{
Id = 2,
PokemonId = "002",
PokemonName = "Ivysaur",
SleepType = "Dozing",
Speciality = "Ingredients"
},
new Pokemon
{
Id = 3,
PokemonId = "003",
PokemonName = "Venasaur",
SleepType = "Dozing",
Speciality = "Ingredients"
},
};
}
}
}

View File

@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Portfolio.Domain.Features.Articles
{
public class Article
{
public int Id { get; set; }
public required string Title { get; set; }
public string? Content { get; set; }
public DateTime DatePublished { get; set; } = DateTime.Now;
public bool IsPublished { get; set; } = false;
}
}

View File

@ -0,0 +1,18 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Portfolio.Domain.Features.Pokemon
{
public class Pokemon
{
public int Id { get; set; }
public required string PokemonId { get; set; }
public required string PokemonName { get; set; }
public required string SleepType { get; set; }
public required string Speciality { get; set; }
}
}

View File

@ -0,0 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>

View File

@ -15,13 +15,19 @@
</div>
<div class="nav-item px-3">
<NavLink class="nav-link" href="weather">
<span class="bi bi-list-nested-nav-menu" aria-hidden="true"></span> Weather
<NavLink class="nav-link" href="articles">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-journal-richtext" viewBox="0 0 16 16">
<path d="M7.5 3.75a.75.75 0 1 1-1.5 0 .75.75 0 0 1 1.5 0m-.861 1.542 1.33.886 1.854-1.855a.25.25 0 0 1 .289-.047L11 4.75V7a.5.5 0 0 1-.5.5h-5A.5.5 0 0 1 5 7v-.5s1.54-1.274 1.639-1.208M5 9.5a.5.5 0 0 1 .5-.5h5a.5.5 0 0 1 0 1h-5a.5.5 0 0 1-.5-.5m0 2a.5.5 0 0 1 .5-.5h2a.5.5 0 0 1 0 1h-2a.5.5 0 0 1-.5-.5" />
<path d="M3 0h10a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H3a2 2 0 0 1-2-2v-1h1v1a1 1 0 0 0 1 1h10a1 1 0 0 0 1-1V2a1 1 0 0 0-1-1H3a1 1 0 0 0-1 1v1H1V2a2 2 0 0 1 2-2" />
<path d="M1 5v-.5a.5.5 0 0 1 1 0V5h.5a.5.5 0 0 1 0 1h-2a.5.5 0 0 1 0-1zm0 3v-.5a.5.5 0 0 1 1 0V8h.5a.5.5 0 0 1 0 1h-2a.5.5 0 0 1 0-1zm0 3v-.5a.5.5 0 0 1 1 0v.5h.5a.5.5 0 0 1 0 1h-2a.5.5 0 0 1 0-1z" />
</svg> Articles
</NavLink>
</div>
<div class="nav-item px-3">
<NavLink class="nav-link" href="pokemonsleep">
<span class="bi bi-p-circle-fill" aria-hidden="true"></span> Pokemon Sleep
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-p-circle-fill" viewBox="0 0 16 16">
<path d="M16 8A8 8 0 1 1 0 8a8 8 0 0 1 16 0M5.5 4.002V12h1.283V9.164h1.668C10.033 9.164 11 8.08 11 6.586c0-1.482-.955-2.584-2.538-2.584zm2.77 4.072c.893 0 1.419-.545 1.419-1.488s-.526-1.482-1.42-1.482H6.778v2.97z" />
</svg> Pokemon Sleep
</NavLink>
</div>
</nav>

View File

@ -0,0 +1,33 @@
@page "/articles"
@inject IArticleService ArticleService
<PageTitle>Articles</PageTitle>
<h3>Articles</h3>
@if(articles.Count == 0)
{
<p><em>Loading...</em></p>
}
else
{
@foreach(var article in articles)
{
<h4>@article.Title</h4>
<p>@article.Content</p>
<small>@article.DatePublished</small>
}
}
@code {
private List<Article> articles = new List<Article>();
protected override void OnInitialized()
{
var result = ArticleService.GetAllArticles();
if (result is not null)
{
articles = result;
}
}
}

View File

@ -1,64 +1,90 @@
@page "/pokemonsleep"
@inject IPokemonService PokemonService
@attribute [StreamRendering]
<PageTitle>Pokemon Sleep</PageTitle>
<h1>Pokemon Sleep</h1>
<p>This component will eventually show data from the PokemonSleepAPI. For right now it copies Weather.</p>
@if (forecasts == null)
@if (pokemons == null)
{
<p><em>Loading...</em></p>
}
else
{
<table class="table">
<thead>
<tr>
<th>Date</th>
<th>Temp. (C)</th>
<th>Temp. (F)</th>
<th>Summary</th>
</tr>
</thead>
<tbody>
@foreach (var forecast in forecasts)
{
<div class="card shadow border-0 mt-4" style ="margin: auto; width: 900px; max-width: 60%; ">
<div class="card-header bg-secondary bg-gradient ml-0 py-3">
<div class="row">
<div class="col-12 text-center">
<h1 class="text-info">Available Pokemon</h1>
</div>
</div>
</div>
<div class="card-body p-4">
<div class="row pb-3">
<div class="col-6">
</div>
<div class="col-6 text-end">
<a asp-controller="Pokemon" asp-action="PokemonCreate" class="btn btn-outline-primary"><i class="bi bi-plus-square"></i> Add New Pokemon</a>
</div>
</div>
<table class="table">
<thead>
<tr>
<td>@forecast.Date.ToShortDateString()</td>
<td>@forecast.TemperatureC</td>
<td>@forecast.TemperatureF</td>
<td>@forecast.Summary</td>
<th scope="col" style="width: 50%;"></th>
<th scope="col">#</th>
<th scope="col">Pokemon</th>
<th scope="col">Sleep Type</th>
<th scope="col" style="padding-right: 30px;">Speciality</th>
<th scope="col"></th>
</tr>
</thead>
<tbody>
@foreach (var pokemon in pokemons)
{
string URL = "https://www.serebii.net/pokemonsleep/pokemon/" + pokemon.Id + ".png";
string ShinyURL = "https://www.serebii.net/pokemonsleep/pokemon/shiny/" + pokemon.Id + ".png";
<tr style=" text-align: center; margin:0; padding: 0;">
<td style="display: block; margin:0; padding: 0;">
<img style=" width: 90px; height: 90px; " src=@URL />
<img style=" width: 90px; height: 90px; " src=@ShinyURL />
</td>
<th scope="row">@pokemon.Id</th>
<td> @pokemon.PokemonName</td>
<td>@pokemon.SleepType</td>
<td style="padding-right: 30px;">@pokemon.Speciality</td>
<td>
<a asp-controller="Pokemon" asp-action="PokemonDelete" asp-route-Id="@pokemon.Id" class="btn btn-danger">
<i class="bi bi-trash"></i>
</a>
</td>
</tr>
}
</tbody>
</table>
</tbody>
</table>
</div>
</div>
}
@code {
private WeatherForecast[]? forecasts;
private List<Pokemon> pokemons;
protected override async Task OnInitializedAsync()
{
// Simulate asynchronous loading to demonstrate streaming rendering
await Task.Delay(500);
var startDate = DateOnly.FromDateTime(DateTime.Now);
var summaries = new[] { "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" };
forecasts = Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = startDate.AddDays(index),
TemperatureC = Random.Shared.Next(-20, 55),
Summary = summaries[Random.Shared.Next(summaries.Length)]
}).ToArray();
}
private class WeatherForecast
{
public DateOnly Date { get; set; }
public int TemperatureC { get; set; }
public string? Summary { get; set; }
public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
var result = PokemonService.GetAllPokemon();
if (result is not null)
{
pokemons = result;
}
}
}

View File

@ -8,3 +8,8 @@
@using Microsoft.JSInterop
@using Portfolio.WebUI.Server
@using Portfolio.WebUI.Server.Components
@using Portfolio.Domain.Features.Articles
@using Portfolio.Domain.Features.Pokemon
@using Portfolio.Application.Services.Articles
@using Portfolio.Application.Services.PokemonService

View File

@ -6,4 +6,8 @@
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Portfolio.Application\Portfolio.Application.csproj" />
</ItemGroup>
</Project>

View File

@ -1,10 +1,13 @@
using Portfolio.WebUI.Server.Components;
using Portfolio.Application;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddRazorComponents();
builder.Services.AddApplication();
var app = builder.Build();
// Configure the HTTP request pipeline.

File diff suppressed because it is too large Load Diff

View File

@ -7,6 +7,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{491A0B76-7D9
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Portfolio.WebUI.Server", "Portfolio.WebUI.Server\Portfolio.WebUI.Server.csproj", "{334A4A79-9DF9-4FAD-9B06-B2FA02443620}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Portfolio.Domain", "Portfolio.Domain\Portfolio.Domain.csproj", "{48065C06-C40E-4A69-B013-8DF2D266D7CF}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Portfolio.Application", "Portfolio.Application\Portfolio.Application.csproj", "{24C9C19A-22CE-4E7B-A393-7423A471513E}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -17,12 +21,22 @@ Global
{334A4A79-9DF9-4FAD-9B06-B2FA02443620}.Debug|Any CPU.Build.0 = Debug|Any CPU
{334A4A79-9DF9-4FAD-9B06-B2FA02443620}.Release|Any CPU.ActiveCfg = Release|Any CPU
{334A4A79-9DF9-4FAD-9B06-B2FA02443620}.Release|Any CPU.Build.0 = Release|Any CPU
{48065C06-C40E-4A69-B013-8DF2D266D7CF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{48065C06-C40E-4A69-B013-8DF2D266D7CF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{48065C06-C40E-4A69-B013-8DF2D266D7CF}.Release|Any CPU.ActiveCfg = Release|Any CPU
{48065C06-C40E-4A69-B013-8DF2D266D7CF}.Release|Any CPU.Build.0 = Release|Any CPU
{24C9C19A-22CE-4E7B-A393-7423A471513E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{24C9C19A-22CE-4E7B-A393-7423A471513E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{24C9C19A-22CE-4E7B-A393-7423A471513E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{24C9C19A-22CE-4E7B-A393-7423A471513E}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{334A4A79-9DF9-4FAD-9B06-B2FA02443620} = {491A0B76-7D94-42C5-BD6B-F90036F33A04}
{48065C06-C40E-4A69-B013-8DF2D266D7CF} = {491A0B76-7D94-42C5-BD6B-F90036F33A04}
{24C9C19A-22CE-4E7B-A393-7423A471513E} = {491A0B76-7D94-42C5-BD6B-F90036F33A04}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {9BE77343-6369-422B-B64A-32CF27B8D257}