diff --git a/src/Application/Users/UserService.cs b/src/Application/Users/UserService.cs index edb28145..3655d093 100644 --- a/src/Application/Users/UserService.cs +++ b/src/Application/Users/UserService.cs @@ -119,7 +119,7 @@ private string GenerateJwtToken(User user) Subject = new ClaimsIdentity(CreateClaims(user)), Audience = _config[ConfigurationKeys.JwtIssuer], Issuer = _config[ConfigurationKeys.JwtIssuer], - Expires = DateTime.UtcNow.AddHours(1), + Expires = DateTime.Now.AddMonths(1), SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature), }; diff --git a/src/Client/Client.csproj b/src/Client/Client.csproj index 2d7ed339..342b9b7f 100644 --- a/src/Client/Client.csproj +++ b/src/Client/Client.csproj @@ -15,6 +15,7 @@ + diff --git a/src/Client/Pages/Admin/AdminPage.razor b/src/Client/Pages/Admin/AdminPage.razor index 3f23c206..ba70de64 100644 --- a/src/Client/Pages/Admin/AdminPage.razor +++ b/src/Client/Pages/Admin/AdminPage.razor @@ -4,36 +4,43 @@

Adminsida

- - - Hantera kontrakt - Hantera användare - - - - - - - - - - - - + +
+ + + Hantera kontrakt + Hantera användare + + + + + + + + + + + + +
@code { private string _selectedTab = "contracts"; + // Null-forgiving operator used because these fields are set by the Blazor runtime using @ref private ContractTable _contractTable = null!; private UserTable _userTable = null!; + private ContractForm _contractForm = null!; private void AddContractToTable(Contract contract) { - _contractTable.Add(contract); + _contractTable.AddOrUpdate(contract); } private void AddUserToTable(User user) @@ -46,4 +53,10 @@ _selectedTab = tabName; return Task.CompletedTask; } + + private async Task OnContractOpeningForEdit(Contract contract) + { + await _contractForm.EditContractAsync(contract); + } + } diff --git a/src/Client/Pages/Admin/AdminPage.razor.css b/src/Client/Pages/Admin/AdminPage.razor.css new file mode 100644 index 00000000..86ba7676 --- /dev/null +++ b/src/Client/Pages/Admin/AdminPage.razor.css @@ -0,0 +1,4 @@ +::deep .nav-link { + background: #e7e7e7; + color: var(--prodigo-dark-blue) +} diff --git a/src/Client/Pages/Admin/ContractForm.razor b/src/Client/Pages/Admin/ContractForm.razor index d67ec07f..7d4d9adc 100644 --- a/src/Client/Pages/Admin/ContractForm.razor +++ b/src/Client/Pages/Admin/ContractForm.razor @@ -6,8 +6,9 @@ @using Blazorise.Markdown @inject ILogger _logger @inject HttpClient _http +@inject IJSRuntime _js -

Skapa nytt kontrakt

+

Skapa nytt kontrakt

@@ -101,6 +102,38 @@ private const string MinFormHeight = "5rem"; + /// + /// Populates the form with the values of the given . + /// + /// The data to edit. + public async Task EditContractAsync(Contract contract) + { + await _js.InvokeVoidAsync("scrollToElement", "#contract-form-title"); + _shouldRender = true; + _contract = contract; + await DownloadContractFiles(); + } + + private async Task DownloadContractFiles() + { + await DownloadContractFile(_contract.InspirationalImagePath, content => _inspirationalContent = content); + await DownloadContractFile(_contract.SupplierLogoImagePath, content => _supplierLogoContent = content); + await DownloadContractFile(_contract.AdditionalDocument, content => _additionalDocumentContent = content); + } + + private async Task DownloadContractFile(string path, Action setContent) + { + + var fileUri = new Uri(Path.Join(_http.BaseAddress?.ToString(), path[1..]), UriKind.Absolute); + + HttpResponseMessage response = await _http.GetAsync(fileUri); + string mediaType = response.Content.Headers.ContentType?.MediaType ?? "images/jpeg"; + Stream stream = await response.Content.ReadAsStreamAsync(); + + MultipartFormDataContent content = CreateFormDataContent(stream, fileUri.Segments.Last(), mediaType); + setContent(content); + } + private static Contract CreateEmptyContract() { return new Contract @@ -126,34 +159,37 @@ { _shouldRender = false; - content = new MultipartFormDataContent(); - StreamContent fileContent; - const long bitsInAKilobyte = 1024; const long kilobytesInAMegabyte = 1024; const long maxFileSize = bitsInAKilobyte * kilobytesInAMegabyte * 100; + Stream fileStream = arg.File.OpenReadStream(maxFileSize); + + content = CreateFormDataContent(fileStream, arg.File.Name, arg.File.ContentType); + + _shouldRender = true; + } + + private MultipartFormDataContent CreateFormDataContent(Stream fileStream, string fileName, string contentType) + { + StreamContent fileContent; + try { - fileContent = new StreamContent(arg.File.OpenReadStream(maxFileSize)); + fileContent = new StreamContent(fileStream); } catch (IOException ex) { - _logger.LogInformation( - "{FileName} not uploaded: {Message}", - arg.File.Name, ex.Message); - return; + _logger.LogInformation("{FileName} not uploaded: {Message}", fileName, ex.Message); + throw; } - fileContent.Headers.ContentType = - new MediaTypeHeaderValue(arg.File.ContentType); + fileContent.Headers.ContentType = new MediaTypeHeaderValue(contentType); - content.Add( - fileContent, - "\"file\"", - arg.File.Name); + var content = new MultipartFormDataContent(); + content.Add(fileContent, "\"file\"", fileName); - _shouldRender = true; + return content; } private async Task OnSubmit() @@ -192,12 +228,11 @@ { string json = JsonConvert.SerializeObject(_contract); var content = new StringContent(json, Encoding.UTF8, "application/json"); - HttpResponseMessage response = await _http.PostAsync("/api/v1/contracts", content); + HttpResponseMessage response = await _http.PutAsync($"/api/v1/contracts/{_contract.Id}", content); if (response.IsSuccessStatusCode) { await OnContractUploaded.InvokeAsync(_contract); _contract = CreateEmptyContract(); } } - } diff --git a/src/Client/Pages/Admin/ContractTable.razor b/src/Client/Pages/Admin/ContractTable.razor index f9270292..b349b5a7 100644 --- a/src/Client/Pages/Admin/ContractTable.razor +++ b/src/Client/Pages/Admin/ContractTable.razor @@ -12,6 +12,7 @@ Kontraktnamn Företag + Redigera Ta bort @@ -19,7 +20,10 @@ @foreach (Contract contract in contracts) { - + } @@ -28,18 +32,35 @@ @code { - private FetchData> _dataFetcher = null!; + /// + /// Called when a is being opened to be edited. + /// + [Parameter] + public EventCallback ContractOpeningForEdit { get; set; } = EventCallback.Empty; /// /// Adds a contract to the list. /// /// The contract to add. - public void Add(Contract contract) + public void AddOrUpdate(Contract contract) { - _dataFetcher.Data?.Add(contract); + if (_dataFetcher.Data is null) + return; + + if (_dataFetcher.Data.Any(other => other.Id == contract.Id)) + { + _dataFetcher.Data.RemoveAll(toRemove => toRemove.Id == contract.Id); + _dataFetcher.Data.Add(contract); + } + else + { + _dataFetcher.Data.Add(contract); + } InvokeAsync(StateHasChanged); } + private FetchData> _dataFetcher = null!; + /// /// Removes a contract from the list. /// diff --git a/src/Client/Pages/Admin/ContractTableRow.razor b/src/Client/Pages/Admin/ContractTableRow.razor index e8dc756a..2ba10805 100644 --- a/src/Client/Pages/Admin/ContractTableRow.razor +++ b/src/Client/Pages/Admin/ContractTableRow.razor @@ -7,29 +7,45 @@ @Contract.SupplierName + + + + - - + @code { + /// /// Called when a contract has been removed successfully. /// [Parameter] public EventCallback OnContractRemoved { get; set; } = EventCallback.Empty; + /// + /// Called when a is being opened to be edited. + /// + [Parameter] + public EventCallback ContractOpeningForEdit { get; set; } = EventCallback.Empty; /// /// The contract. diff --git a/src/Client/Pages/Contracts/ContractDetails.razor b/src/Client/Pages/Contracts/ContractDetails.razor index 4341e7e5..a78a9259 100644 --- a/src/Client/Pages/Contracts/ContractDetails.razor +++ b/src/Client/Pages/Contracts/ContractDetails.razor @@ -1,5 +1,6 @@ @using Domain.Contracts @using System.Runtime.Serialization +@inject ISessionService _session