Skip to content

Commit

Permalink
Merge branch 'master' into 87-show-personalized-favorites-2
Browse files Browse the repository at this point in the history
  • Loading branch information
JacobBredin authored May 12, 2022
2 parents 5aba061 + 3e63173 commit 038569b
Show file tree
Hide file tree
Showing 40 changed files with 752 additions and 245 deletions.
2 changes: 1 addition & 1 deletion src/Application/Users/UserService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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),
};
Expand Down
1 change: 1 addition & 0 deletions src/Client/Client.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Blazored.SessionStorage" Version="2.2.0" />
<PackageReference Include="Blazorise.Bootstrap5" Version="1.0.3" />
<PackageReference Include="Blazorise.Icons.FontAwesome" Version="1.0.3" />
<PackageReference Include="Blazorise.Markdown" Version="1.0.3" />
Expand Down
53 changes: 33 additions & 20 deletions src/Client/Pages/Admin/AdminPage.razor
Original file line number Diff line number Diff line change
Expand Up @@ -4,36 +4,43 @@

<h2>Adminsida</h2>

<Tabs SelectedTab="@_selectedTab"
SelectedTabChanged="@OnSelectedTabChanged"
Justified="true"
Pills="true">
<Items>
<Tab Name="contracts">Hantera kontrakt</Tab>
<Tab Name="users">Hantera användare</Tab>
</Items>
<Content>
<TabPanel Name="contracts">
<ContractForm OnContractUploaded="AddContractToTable"/>
<ContractTable @ref="@_contractTable"/>
</TabPanel>
<TabPanel Name="users">
<UserForm OnUserAdded="AddUserToTable"/>
<UserTable @ref="@_userTable"/>
</TabPanel>
</Content>
</Tabs>
<!-- Extra div needed to style the Blazorise-components (see https://github.com/Megabit/Blazorise/issues/1599) -->
<div>
<Tabs SelectedTab="@_selectedTab"
SelectedTabChanged="@OnSelectedTabChanged"
Justified="true"
Pills="true"
TextColor="TextColor.Primary"
Class="tabs">
<Items>
<Tab Name="contracts">Hantera kontrakt</Tab>
<Tab Name="users">Hantera användare</Tab>
</Items>
<Content>
<TabPanel Name="contracts">
<ContractForm @ref="_contractForm" OnContractUploaded="AddContractToTable"/>
<ContractTable @ref="@_contractTable" ContractOpeningForEdit="@OnContractOpeningForEdit"/>
</TabPanel>
<TabPanel Name="users">
<UserForm OnUserAdded="AddUserToTable"/>
<UserTable @ref="@_userTable"/>
</TabPanel>
</Content>
</Tabs>
</div>

@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)
Expand All @@ -46,4 +53,10 @@
_selectedTab = tabName;
return Task.CompletedTask;
}

private async Task OnContractOpeningForEdit(Contract contract)
{
await _contractForm.EditContractAsync(contract);
}

}
4 changes: 4 additions & 0 deletions src/Client/Pages/Admin/AdminPage.razor.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
::deep .nav-link {
background: #e7e7e7;
color: var(--prodigo-dark-blue)
}
71 changes: 53 additions & 18 deletions src/Client/Pages/Admin/ContractForm.razor
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@
@using Blazorise.Markdown
@inject ILogger<AdminPage> _logger
@inject HttpClient _http
@inject IJSRuntime _js

<h4>Skapa nytt kontrakt</h4>
<h4 id="contract-form-title">Skapa nytt kontrakt</h4>

<EditForm Model="@_contract" OnSubmit="OnSubmit">

Expand Down Expand Up @@ -101,6 +102,38 @@

private const string MinFormHeight = "5rem";

/// <summary>
/// Populates the form with the values of the given <see cref="Contract"/>.
/// </summary>
/// <param name="contract">The data to edit.</param>
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<MultipartFormDataContent> 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
Expand All @@ -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()
Expand Down Expand Up @@ -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();
}
}

}
29 changes: 25 additions & 4 deletions src/Client/Pages/Admin/ContractTable.razor
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,18 @@
<tr>
<th scope="col">Kontraktnamn</th>
<th scope="col">Företag</th>
<th scope="col">Redigera</th>
<th scope="col">Ta bort</th>
</tr>
</thead>

<tbody>
@foreach (Contract contract in contracts)
{
<ContractTableRow Contract=@contract OnContractRemoved=@Remove/>
<ContractTableRow @key="@contract.Id"
Contract=@contract
OnContractRemoved=@Remove
ContractOpeningForEdit="@(async () => await ContractOpeningForEdit.InvokeAsync(contract))"/>
}
</tbody>
</table>
Expand All @@ -28,18 +32,35 @@

@code {

private FetchData<List<Contract>> _dataFetcher = null!;
/// <summary>
/// Called when a <see cref="Contract"/> is being opened to be edited.
/// </summary>
[Parameter]
public EventCallback<Contract> ContractOpeningForEdit { get; set; } = EventCallback<Contract>.Empty;

/// <summary>
/// Adds a contract to the list.
/// </summary>
/// <param name="contract">The contract to add.</param>
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<List<Contract>> _dataFetcher = null!;

/// <summary>
/// Removes a contract from the list.
/// </summary>
Expand Down
30 changes: 23 additions & 7 deletions src/Client/Pages/Admin/ContractTableRow.razor
Original file line number Diff line number Diff line change
Expand Up @@ -7,29 +7,45 @@

<td>@Contract.SupplierName</td>

<td>
<button type="button"
class="btn btn-outline-primary m-0"
@onclick="@(async () => await ContractOpeningForEdit.InvokeAsync(Contract))">
<span class="oi oi-pencil"></span>
</button>
</td>

<!-- Button trigger modal -->
<td>
<button type="button" class="btn btn-danger m-0" data-bs-toggle="modal" data-bs-target="#@($"modal_{Contract.Id}")">
<button type="button"
class="btn btn-danger m-0"
data-bs-toggle="modal"
data-bs-target="#@($"modal_{Contract.Id}")">
<span class="oi oi-trash"></span>
</button>
</td>

<RemoveModal
Id=@Contract.Id
Title="Ta bort kontrakt"
Message="@($"Vill du ta bort kontraktet {Contract.Name}?")"
RemovalConfirmed="@(async () => await OnContractRemoved.InvokeAsync(Contract))"
/>
<RemoveModal
Id=@Contract.Id
Title="Ta bort kontrakt"
Message="@($"Vill du ta bort kontraktet {Contract.Name}?")"
RemovalConfirmed="@(async () => await OnContractRemoved.InvokeAsync(Contract))"/>
</tr>


@code {

/// <summary>
/// Called when a contract has been removed successfully.
/// </summary>
[Parameter]
public EventCallback<Contract> OnContractRemoved { get; set; } = EventCallback<Contract>.Empty;

/// <summary>
/// Called when a <see cref="Contract"/> is being opened to be edited.
/// </summary>
[Parameter]
public EventCallback<Contract> ContractOpeningForEdit { get; set; } = EventCallback<Contract>.Empty;

/// <summary>
/// The contract.
Expand Down
9 changes: 2 additions & 7 deletions src/Client/Pages/Contracts/ContractDetails.razor
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
@using Domain.Contracts
@using System.Runtime.Serialization
@inject ISessionService _session

<!-- modal-dialog-scrollable -->
<div class="modal w-100" id="@("id_" + Contract.Id)">
Expand Down Expand Up @@ -96,13 +97,7 @@
[Parameter, EditorRequired,]
public Contract Contract { get; set; } = null!;

/// <summary>
/// The name of the currently logged in user.
/// </summary>
[CascadingParameter(Name = nameof(LoggedInUser))]
public string? LoggedInUser { get; set; }

private bool ShouldHideDetails => string.IsNullOrEmpty(LoggedInUser);
private bool ShouldHideDetails => !_session.IsAuthenticated;

private string ImagePath => string.IsNullOrEmpty(Contract.InspirationalImagePath) ?
Contract.SupplierLogoImagePath :
Expand Down
4 changes: 3 additions & 1 deletion src/Client/Pages/Contracts/RecentlyViewed.razor
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@
@using Application.Contracts
@using System.Collections.ObjectModel
@inject HttpClient _http
@inject ISessionService _session
@inherits AuthenticatedView

<FetchData TData="Contract[]"
Url="/api/v1/contracts/recent"
Context="recents"
ShouldShowErrors="@false">
ShouldShowErrors="@_session.IsAuthenticated">

<!-- No loading indicator. -->
<LoadingIndicator></LoadingIndicator>
Expand Down
7 changes: 6 additions & 1 deletion src/Client/Program.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
using Blazored.SessionStorage;

using Blazorise;
using Blazorise.Bootstrap5;
using Blazorise.Icons.FontAwesome;

using Client;
using Client.Services.Authentication;

using Microsoft.AspNetCore.Components.Web;
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
Expand All @@ -16,6 +19,8 @@
builder.Services
.AddBlazorise(options => { options.Immediate = true; })
.AddBootstrap5Providers()
.AddFontAwesomeIcons();
.AddFontAwesomeIcons()
.AddBlazoredSessionStorage()
.AddScoped<ISessionService, SessionManagerService>(); // Scoped behaves like Singleton.

await builder.Build().RunAsync().ConfigureAwait(false);
14 changes: 14 additions & 0 deletions src/Client/Services/Authentication/AuthenticationEventArgs.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using Application.Users;

namespace Client.Services.Authentication;

/// <summary>
/// Contains information about an authentication changed event.
/// </summary>
public class AuthenticationEventArgs : EventArgs
{
/// <summary>
/// Gets or sets the authentication state associated with this event.
/// </summary>
public AuthenticateResponse? State { get; set; }
}
Loading

0 comments on commit 038569b

Please sign in to comment.