enhanced client side experience
This commit is contained in:
@@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -4,12 +4,22 @@ using Unbinder.Repositories;
|
|||||||
|
|
||||||
namespace Unbinder.Controllers.Api
|
namespace Unbinder.Controllers.Api
|
||||||
{
|
{
|
||||||
[Route("api/[controller]")]
|
|
||||||
[ApiController]
|
[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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ namespace Unbinder.Controllers
|
|||||||
}
|
}
|
||||||
|
|
||||||
[Route("[controller]/search")]
|
[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);
|
if (q == null && category == null) return View(_recipeRepository.GetAll);
|
||||||
|
|
||||||
|
|||||||
@@ -13,12 +13,12 @@ var builder = WebApplication.CreateBuilder(args);
|
|||||||
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");
|
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");
|
||||||
|
|
||||||
// Add services to the container.
|
// Add services to the container.
|
||||||
builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
|
//builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
|
||||||
.AddMicrosoftIdentityWebApp(builder.Configuration.GetSection("AzureAd"));
|
// .AddMicrosoftIdentityWebApp(builder.Configuration.GetSection("AzureAd"));
|
||||||
|
|
||||||
builder.Services.AddAuthorization(options =>
|
//builder.Services.AddAuthorization(options =>
|
||||||
// By default, all incoming requests will be authorized according to the default policy.
|
// // By default, all incoming requests will be authorized according to the default policy.
|
||||||
options.FallbackPolicy = options.DefaultPolicy);
|
// options.FallbackPolicy = options.DefaultPolicy);
|
||||||
|
|
||||||
builder.Services.AddDbContext<UnbinderDbContext>(options =>
|
builder.Services.AddDbContext<UnbinderDbContext>(options =>
|
||||||
options.UseSqlServer(connectionString));
|
options.UseSqlServer(connectionString));
|
||||||
@@ -27,6 +27,16 @@ builder.Services.AddDbContext<UnbinderDbContext>(options =>
|
|||||||
builder.Services.AddControllersWithViews();
|
builder.Services.AddControllersWithViews();
|
||||||
builder.Services.AddRazorPages();
|
builder.Services.AddRazorPages();
|
||||||
|
|
||||||
|
builder.Services.AddCors(options =>
|
||||||
|
{
|
||||||
|
options.AddPolicy("AllowAll", builder =>
|
||||||
|
{
|
||||||
|
builder.AllowAnyOrigin()
|
||||||
|
.AllowAnyMethod()
|
||||||
|
.AllowAnyHeader();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
builder.Services.AddScoped<IRecipeRepository, RecipeRepository>();
|
builder.Services.AddScoped<IRecipeRepository, RecipeRepository>();
|
||||||
builder.Services.AddScoped<IIngredientRepository, IngredientRepository>();
|
builder.Services.AddScoped<IIngredientRepository, IngredientRepository>();
|
||||||
|
|
||||||
@@ -45,8 +55,8 @@ if (!app.Environment.IsDevelopment())
|
|||||||
|
|
||||||
app.UseStaticFiles();
|
app.UseStaticFiles();
|
||||||
|
|
||||||
app.UseAuthentication();
|
//app.UseAuthentication();
|
||||||
app.UseAuthorization();
|
//app.UseAuthorization();
|
||||||
|
|
||||||
app.MapDefaultControllerRoute();
|
app.MapDefaultControllerRoute();
|
||||||
|
|
||||||
|
|||||||
@@ -1,20 +1,52 @@
|
|||||||
@model IEnumerable<Recipe>
|
@model IEnumerable<Recipe>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<p id="displayed-query-string"></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)
|
@foreach (var recipe in @Model)
|
||||||
{
|
{
|
||||||
<p>@recipe.Name</p>
|
<p>@recipe.Name</p>
|
||||||
<p>@recipe.RecipeText</p>
|
<p>@recipe.RecipeText</p>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
|
document.addEventListener("DOMContentLoaded", () => {
|
||||||
|
// dom elements
|
||||||
const query = window.location.search?.split("=")[1];
|
const query = window.location.search?.split("=")[1];
|
||||||
const target = document.getElementById("displayed-query-string");
|
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");
|
||||||
|
|
||||||
|
console.log(query);
|
||||||
|
|
||||||
|
// set initial message value
|
||||||
if (query) {
|
if (query) {
|
||||||
target.innerHTML = `Viewing ${@Model.ToArray().Length} results for: ${query}`;
|
message.innerHTML = `Viewing ${@Model.ToArray().Length} results for: ${query}`;
|
||||||
} else {
|
} else {
|
||||||
target.innerHTML = "Enter a new search term below:";
|
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>
|
</script>
|
||||||
Reference in New Issue
Block a user