enhanced client side experience

This commit is contained in:
2023-11-17 14:57:36 -06:00
parent 4a582bee0b
commit aeb3293942
5 changed files with 76 additions and 62 deletions

View File

@@ -1,38 +0,0 @@
using Microsoft.AspNetCore.Mvc;
using Unbinder.Repositories;
namespace Unbinder.Controllers.Api
{
public abstract class BaseApiController<T> : ControllerBase where T : class
{
protected readonly IBaseRepository<T> repository;
public BaseApiController(IBaseRepository<T> repository)
{
this.repository = repository;
}
public IActionResult UpdateById(int id)
{
var result = repository.UpdateById(id);
if (result == null)
{
return NotFound();
}
return Ok(result);
}
[HttpDelete("{id}")]
public IActionResult DeleteById(int id)
{
var result = repository.DeleteById(id);
if (result == 0)
{
return NotFound();
}
return Ok(result);
}
}
}

View File

@@ -4,12 +4,22 @@ using Unbinder.Repositories;
namespace Unbinder.Controllers.Api
{
[Route("api/[controller]")]
[ApiController]
public class RecipeApiController : BaseApiController<Recipe>
public class RecipeApiController(IRecipeRepository _repository) : ControllerBase
{
public RecipeApiController(IRecipeRepository recipeRepository) : base(recipeRepository)
private readonly IRecipeRepository repository = _repository;
[HttpGet]
[Route("/api/recipe/search")]
public IActionResult Search([FromQuery] string? q)
{
if (q == null) return Ok(repository.GetAll);
var result = repository.GetAll?.Where(r => r.Name.Contains(q, StringComparison.OrdinalIgnoreCase));
return result == null
? NotFound()
: Ok(result);
}
}
}

View File

@@ -29,7 +29,7 @@ namespace Unbinder.Controllers
}
[Route("[controller]/search")]
public IActionResult Search([FromQuery] string? q, string? category)
public IActionResult Search([FromQuery] string? q, [FromQuery] string? category)
{
if (q == null && category == null) return View(_recipeRepository.GetAll);

View File

@@ -13,12 +13,12 @@ var builder = WebApplication.CreateBuilder(args);
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");
// Add services to the container.
builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApp(builder.Configuration.GetSection("AzureAd"));
//builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
// .AddMicrosoftIdentityWebApp(builder.Configuration.GetSection("AzureAd"));
builder.Services.AddAuthorization(options =>
// By default, all incoming requests will be authorized according to the default policy.
options.FallbackPolicy = options.DefaultPolicy);
//builder.Services.AddAuthorization(options =>
// // By default, all incoming requests will be authorized according to the default policy.
// options.FallbackPolicy = options.DefaultPolicy);
builder.Services.AddDbContext<UnbinderDbContext>(options =>
options.UseSqlServer(connectionString));
@@ -27,6 +27,16 @@ builder.Services.AddDbContext<UnbinderDbContext>(options =>
builder.Services.AddControllersWithViews();
builder.Services.AddRazorPages();
builder.Services.AddCors(options =>
{
options.AddPolicy("AllowAll", builder =>
{
builder.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader();
});
});
builder.Services.AddScoped<IRecipeRepository, RecipeRepository>();
builder.Services.AddScoped<IIngredientRepository, IngredientRepository>();
@@ -45,8 +55,8 @@ if (!app.Environment.IsDevelopment())
app.UseStaticFiles();
app.UseAuthentication();
app.UseAuthorization();
//app.UseAuthentication();
//app.UseAuthorization();
app.MapDefaultControllerRoute();

View File

@@ -1,20 +1,52 @@
@model IEnumerable<Recipe>
<div>
<p id="displayed-query-string"></p>
@foreach (var recipe in @Model)
{
<p>@recipe.Name</p>
<p>@recipe.RecipeText</p>
}
<div id="search-page-header" class="mb-8 border-white border-b">
<h3 id="query-message"></h3>
<input class="text-black" id="new-search-query" type="text" />
<button id="execute-search">Search</button>
</div>
<div id="search-results">
@foreach (var recipe in @Model)
{
<p>@recipe.Name</p>
<p>@recipe.RecipeText</p>
}
</div>
</div>
<script type="text/javascript">
const query = window.location.search?.split("=")[1];
const target = document.getElementById("displayed-query-string");
document.addEventListener("DOMContentLoaded", () => {
// dom elements
const query = window.location.search?.split("=")[1];
const message = document.getElementById("query-message");
const textField = document.getElementById("new-search-query");
const searchButton = document.getElementById("execute-search");
const searchResultsContainer = document.getElementById("search-results");
if (query) {
target.innerHTML = `Viewing ${@Model.ToArray().Length} results for: ${query}`;
} else {
target.innerHTML = "Enter a new search term below:";
}
console.log(query);
// set initial message value
if (query) {
message.innerHTML = `Viewing ${@Model.ToArray().Length} results for: ${query}`;
} else {
message.innerHTML = "Enter a new search term below:";
}
// handle search updates on client side
searchButton.onclick = async () => {
const newResult = await fetch(`/api/recipe/search?q=${textField.value}`);
console.log(newResult);
const newResultJson = await newResult.json();
window.location.search = `?q=${textField.value}`;
searchResultsContainer.innerHTML = `@{
foreach (var recipe in @Model)
{
<p>@recipe.Name</p>
<p>@recipe.RecipeText</p>
}
}`;
}
});
</script>