diff --git a/FilterCair.Client/Pages/Admin/Customers.razor b/FilterCair.Client/Pages/Admin/Customers.razor index a9f1ff3..f792527 100644 --- a/FilterCair.Client/Pages/Admin/Customers.razor +++ b/FilterCair.Client/Pages/Admin/Customers.razor @@ -1,6 +1,8 @@ @page "/admin/customers" @layout AdminLayout @using FilterCair.Shared.Models +@inject FilterCair.Client.Services.API.CustomerService CustomerService +@inject IJSRuntime JS Kunden verwalten @@ -14,8 +16,14 @@ - - @if (customers.Count == 0) + @if (isLoading) + { +
+
+

Lade Kunden...

+
+ } + else if (customers.Count == 0) {
Keine Kunden vorhanden. Lege den ersten Kunden an! @@ -45,7 +53,8 @@ @c.Telefon @c.Email - @@ -75,34 +84,26 @@
-
-
-
-
- - + +
@@ -116,15 +117,18 @@ private List customers = new(); private CustomerModel newCustomer = new(); private bool showModal = false; + private bool isLoading = true; - protected override void OnInitialized() + protected override async Task OnInitializedAsync() { - // TODO: später über API laden - customers = new() - { - new() { Id = 1, Name = "Freudenberg Weinheim", Standort = "Weinheim", Ansprechpartner = "Marc Wieland", Telefon = "+49 6201 80 1234", Email = "marc.wieland@freudenberg-pm.com" }, - new() { Id = 2, Name = "CleanAir Solutions", Standort = "Mannheim", Ansprechpartner = "Tom Fischer", Telefon = "+49 621 555 123" , Email = "FischersTom@cleanair.de"} - }; + await LoadCustomers(); + } + + private async Task LoadCustomers() + { + isLoading = true; + customers = await CustomerService.GetCustomersAsync(); + isLoading = false; } private void ShowCreateModal() @@ -138,15 +142,35 @@ showModal = false; } - private void SaveCustomer() + private async Task SaveCustomer() { - newCustomer.Id = customers.Count + 1; - customers.Add(newCustomer); - showModal = false; + var success = await CustomerService.AddCustomerAsync(newCustomer); + if (success) + { + await LoadCustomers(); + await JS.InvokeVoidAsync("alert", "✅ Kunde erfolgreich angelegt!"); + CloseModal(); + } + else + { + await JS.InvokeVoidAsync("alert", "❌ Fehler beim Speichern."); + } } - private void DeleteCustomer(CustomerModel customer) + private async Task DeleteCustomer(CustomerModel customer) { - customers.Remove(customer); + bool confirmed = await JS.InvokeAsync("confirm", $"Soll der Kunde '{customer.Name}' wirklich gelöscht werden?"); + if (!confirmed) return; + + var success = await CustomerService.DeleteCustomerAsync(customer.Id); + if (success) + { + customers.Remove(customer); + await JS.InvokeVoidAsync("alert", "🗑️ Kunde gelöscht."); + } + else + { + await JS.InvokeVoidAsync("alert", "❌ Fehler beim Löschen."); + } } } diff --git a/FilterCair.Client/Pages/CustomerList.razor b/FilterCair.Client/Pages/CustomerList.razor index 708efc5..26838f7 100644 --- a/FilterCair.Client/Pages/CustomerList.razor +++ b/FilterCair.Client/Pages/CustomerList.razor @@ -1,13 +1,13 @@ @page "/customers" @using FilterCair.Shared.Models +@inject FilterCair.Client.Services.API.CustomerService CustomerService + @inject IJSRuntime JS @inject NavigationManager Nav @inject FilterCair.Client.Services.AppState State

Kundenübersicht

- -

Kunden & Fabriken @@ -23,62 +23,62 @@
- @foreach (var c in FilteredCustomers) + @if (customers == null) { -
-
-
-
- @c.Name -
-

- @c.Standort -

-

- @c.Ansprechpartner -

+

Lade Kunden...

+ } + else + { + @foreach (var c in FilteredCustomers) + { +
+
+
+
+ @c.Name +
+

+ @c.Standort +

+

+ @c.Ansprechpartner +

+
-
+ } + + @if (!FilteredCustomers.Any()) + { +
+ + Keine passenden Kunden gefunden. +
+ } }
- - @if (FilteredCustomers.Count() == 0) - { -
- - Keine passenden Kunden gefunden. -
- }
@code { - private List customers = new(); + private List? customers; private string searchText = ""; private IEnumerable FilteredCustomers => string.IsNullOrWhiteSpace(searchText) - ? customers - : customers.Where(c => - c.Name.Contains(searchText, StringComparison.OrdinalIgnoreCase) || - c.Standort.Contains(searchText, StringComparison.OrdinalIgnoreCase)); + ? customers ?? new List() + : customers!.Where(c => + c.Name.Contains(searchText, StringComparison.OrdinalIgnoreCase) || + c.Standort.Contains(searchText, StringComparison.OrdinalIgnoreCase)); - protected override void OnInitialized() + protected override async Task OnInitializedAsync() { - // später aus API laden - customers = new() - { - new() { Id = 1, Name = "Freudenberg Weinheim", Standort = "Weinheim", Ansprechpartner = "Marc Wieland", Telefon = "+49 6201 80 1234" }, - new() { Id = 2, Name = "FilterTech GmbH", Standort = "Kaiserslautern", Ansprechpartner = "Lena Becker", Telefon = "+49 631 987654" }, - new() { Id = 3, Name = "CleanAir Solutions", Standort = "Mannheim", Ansprechpartner = "Tom Fischer", Telefon = "+49 621 555 123" } - }; + customers = await CustomerService.GetCustomersAsync(); } private async Task SelectCustomer(CustomerModel c) { await State.SetCustomerAsync(c.Name); - Nav.NavigateTo("/qrscanner"); + Nav.NavigateTo("/qrscanner"); } - -} \ No newline at end of file +} diff --git a/FilterCair.Client/Program.cs b/FilterCair.Client/Program.cs index 8916b18..16f51d9 100644 --- a/FilterCair.Client/Program.cs +++ b/FilterCair.Client/Program.cs @@ -25,4 +25,7 @@ builder.Services.AddMsalAuthentication(options => //Services builder.Services.AddScoped(); +//API Services +builder.Services.AddScoped(); + await builder.Build().RunAsync(); diff --git a/FilterCair.Client/Services/API/CustomerService.cs b/FilterCair.Client/Services/API/CustomerService.cs new file mode 100644 index 0000000..f74c35b --- /dev/null +++ b/FilterCair.Client/Services/API/CustomerService.cs @@ -0,0 +1,61 @@ +using FilterCair.Shared.Models; +using System.Net.Http.Json; + +namespace FilterCair.Client.Services.API +{ + public class CustomerService + { + private readonly HttpClient _http; + private readonly IConfiguration _config; + private string BaseUrl => _config["Api:BaseUrl"] + "/api/Customer"; + + + public CustomerService(HttpClient http, IConfiguration config) + { + _http = http; + _config = config; + } + + public async Task> GetCustomersAsync() + { + try + { + var result = await _http.GetFromJsonAsync>(BaseUrl); + return result ?? new(); + } + catch (Exception ex) + { + Console.WriteLine($"❌ Fehler beim Laden der Kunden: {ex.Message}"); + return new(); + } + } + + public async Task AddCustomerAsync(CustomerModel customer) + { + try + { + var response = await _http.PostAsJsonAsync(BaseUrl, customer); + return response.IsSuccessStatusCode; + } + catch (Exception ex) + { + Console.WriteLine($"❌ Fehler beim Anlegen: {ex.Message}"); + return false; + } + } + + public async Task DeleteCustomerAsync(int id) + { + try + { + var response = await _http.DeleteAsync($"{BaseUrl}/{id}"); + return response.IsSuccessStatusCode; + } + catch (Exception ex) + { + Console.WriteLine($"❌ Fehler beim Löschen: {ex.Message}"); + return false; + } + } + } +} diff --git a/FilterCair.Client/wwwroot/appsettings.json b/FilterCair.Client/wwwroot/appsettings.json index 4101c2e..38628a4 100644 --- a/FilterCair.Client/wwwroot/appsettings.json +++ b/FilterCair.Client/wwwroot/appsettings.json @@ -14,6 +14,6 @@ ] }, "Api": { - "BaseUrl": "https://filtercair-api.azurewebsites.net" + "BaseUrl": "https://filtercair-server-gwctc2gbf5f4axgj.westeurope-01.azurewebsites.net" } } diff --git a/FilterCair.Server/Controllers/TestController.cs b/FilterCair.Server/Controllers/TestController.cs deleted file mode 100644 index c0ab4c5..0000000 --- a/FilterCair.Server/Controllers/TestController.cs +++ /dev/null @@ -1,17 +0,0 @@ -using Microsoft.AspNetCore.Mvc; -using Microsoft.AspNetCore.Authorization; - -namespace FilterCair.Server.Controllers -{ - [ApiController] - [Route("api/[controller]")] - public class TestController : ControllerBase - { - [HttpGet("public")] - public IActionResult GetPublic() => Ok("✅ Öffentlich erreichbar – keine Auth nötig"); - - [Authorize] - [HttpGet("protected")] - public IActionResult GetProtected() => Ok("🔒 Du bist authentifiziert über Azure AD!"); - } -} \ No newline at end of file diff --git a/FilterCair.Server/Deploy.ps1 b/FilterCair.Server/Deploy.ps1 index 2a9d0b2..f5cb35a 100644 --- a/FilterCair.Server/Deploy.ps1 +++ b/FilterCair.Server/Deploy.ps1 @@ -10,7 +10,7 @@ $ErrorActionPreference = "Stop" # Variables -$projectPath = "C:\DEVQPDC\Masterarbeit\filtercair_dev\Masterarbeit_New\FilterCair.Server" +$projectPath = "C:\DEVQPDC\FilterCairStack\FilterCair.Server" $publishFolder = "$projectPath\bin\Release\net9.0\linux-x64\publish" $zipFile = "$projectPath\publish.zip" $resourceGroup = "FilterCair-RG" diff --git a/FilterCair.Server/FilterCair.Server.csproj b/FilterCair.Server/FilterCair.Server.csproj index c966c92..c981e25 100644 --- a/FilterCair.Server/FilterCair.Server.csproj +++ b/FilterCair.Server/FilterCair.Server.csproj @@ -9,14 +9,24 @@ + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + - - + + diff --git a/FilterCair.Server/Program.cs b/FilterCair.Server/Program.cs index 723ebc0..acd8ad1 100644 --- a/FilterCair.Server/Program.cs +++ b/FilterCair.Server/Program.cs @@ -1,4 +1,6 @@ +using FilterCair.Server.Data; using Microsoft.AspNetCore.Authentication.JwtBearer; +using Microsoft.EntityFrameworkCore; using Microsoft.Identity.Web; var builder = WebApplication.CreateBuilder(args); @@ -6,11 +8,18 @@ var builder = WebApplication.CreateBuilder(args); builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) .AddMicrosoftIdentityWebApi(builder.Configuration.GetSection("AzureAd")); + +builder.Services.AddDbContext(options => + options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection"), + sql => sql.EnableRetryOnFailure(5, TimeSpan.FromSeconds(10), null)) +); + + builder.Services.AddCors(options => { options.AddPolicy("AllowClient", policy => { - policy.WithOrigins("https://filtercair-client.azurewebsites.net", "https://localhost:5001") + policy.WithOrigins("https://filtercair-client-efava4bfgvamhkfu.westeurope-01.azurewebsites.net", "https://localhost:5001") .AllowAnyHeader() .AllowAnyMethod(); }); diff --git a/FilterCair.Server/appsettings.json b/FilterCair.Server/appsettings.json index 6cb8457..f9220b5 100644 --- a/FilterCair.Server/appsettings.json +++ b/FilterCair.Server/appsettings.json @@ -8,7 +8,7 @@ "SignedOutCallbackPath": "/authentication/logout-callback" }, "ConnectionStrings": { - "DefaultConnection": "Server=tcp:filtercair-sql.database.windows.net,1433;Initial Catalog=FilterCairDB;User ID=sqladmin;Password=SuperSicher123!;Encrypt=True;" + "DefaultConnection": "Server=tcp:filtercair-azure-sql-server.database.windows.net,1433;Initial Catalog=FilterCairDB;Encrypt=True;TrustServerCertificate=False;Connection Timeout=30;Authentication=Active Directory Managed Identity;" }, "Logging": { "LogLevel": { diff --git a/FilterCair.Server/publish.zip b/FilterCair.Server/publish.zip deleted file mode 100644 index 118b179..0000000 Binary files a/FilterCair.Server/publish.zip and /dev/null differ