WIP: workplaces and documents

This commit is contained in:
Frede Hundewadt 2023-04-02 14:39:23 +02:00
parent 30e1fa1d75
commit 0a96c9c640
45 changed files with 537 additions and 691 deletions

View file

@ -1,48 +0,0 @@
@* Copyright (C) 2022 FCS Frede's Computer Services.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see [https://www.gnu.org/licenses/agpl-3.0.en.html]
*@
@using Wonky.Entity.DTO
@using Wonky.Entity.Views
@if (Workplaces.Any())
{
<div class="list-group">
<div class="row">
<div class="col">
Arbejdssted
</div>
<div class="col">
Note
</div>
</div>
@foreach (var workplace in Workplaces)
{
<a class="list-group-item list-group-item-action" href="/advisor/customers/@CompanyId/workplaces/@workplace.WorkplaceId">
<div class="row">
<div class="col">
@workplace.Name
</div>
<div class="col">
@workplace.Description
</div>
</div>
</a>
}
</div>
}
else
{
<div>Ingen data</div>
}

View file

@ -1,26 +0,0 @@
// Copyright (C) 2022 FCS Frede's Computer Services.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see [https://www.gnu.org/licenses/agpl-3.0.en.html]
//
using Microsoft.AspNetCore.Components;
using Wonky.Entity.Views;
namespace Wonky.Client.Components;
public partial class WorkplaceListComponent
{
[Parameter] public List<WorkplaceListView> Workplaces { get; set; } = new();
[Parameter] public string CompanyId { get; set; } = "";
}

View file

@ -16,6 +16,7 @@
using System.Net.Mail;
using System.Text.RegularExpressions;
using Wonky.Client.Models;
using Wonky.Entity.DTO;
namespace Wonky.Client.Helpers;
@ -24,6 +25,67 @@ namespace Wonky.Client.Helpers;
/// </summary>
public static class Utils
{
/// <summary>
/// map user role edit model to role assignment model
/// </summary>
/// <param name="model"></param>
/// <returns></returns>
public static List<UserRoleAssignment> MapSaveAssignedRoles(RoleAssignment model)
{
return new List<UserRoleAssignment>()
{
new (){ Name = "Admin", Assigned = model.Admin},
new (){ Name = "Advisor", Assigned = model.Advisor},
new (){ Name = "EDoc", Assigned = model.EDoc},
new (){ Name = "EShop", Assigned = model.EShop},
new (){ Name = "Managment", Assigned = model.Management},
new (){ Name = "Office", Assigned = model.Office},
new (){ Name = "Supervisor", Assigned = model.Supervisor},
new (){ Name = "Warehouse", Assigned = model.Warehouse}
};
}
/// <summary>
/// map user role assignment to edit model
/// </summary>
/// <param name="model"></param>
/// <returns></returns>
public static RoleAssignment MapEditAssignedRoles(UserManagerEditView model)
{
var x = new RoleAssignment();
foreach (var role in model.AssignedRoles)
{
switch (role.Name.ToLower())
{
case "admin":
x.Admin = role.Assigned;
break;
case "advisor":
x.Advisor = role.Assigned;
break;
case "edoc":
x.EDoc = role.Assigned;
break;
case "eshop":
x.EShop = role.Assigned;
break;
case "management":
x.Management = role.Assigned;
break;
case "office":
x.Office = role.Assigned;
break;
case "supervisor":
x.Supervisor = role.Assigned;
break;
case "warehouse":
x.Warehouse = role.Assigned;
break;
}
}
return x;
}
/// <summary>
/// Sanitize string by removing everything but digits
/// </summary>

View file

@ -46,11 +46,6 @@ public class AdvisorWorkplaceRepository : IAdvisorWorkplaceRepository
_api = configuration.Value;
}
/// <summary>
/// Get Workplaces for given customer id
/// </summary>
/// <param name="companyId"></param>
/// <returns></returns>
public async Task<List<WorkplaceListView>> GetWorkplaces(string companyId)
{
var result = await _client.GetFromJsonAsync<List<WorkplaceListView>>(
@ -58,12 +53,6 @@ public class AdvisorWorkplaceRepository : IAdvisorWorkplaceRepository
return result ?? new List<WorkplaceListView>();
}
/// <summary>
/// Get specific workplace using customer id and workplace id
/// </summary>
/// <param name="companyId"></param>
/// <param name="workplaceId"></param>
/// <returns></returns>
public async Task<WorkplaceDto> GetWorkplace(string companyId, string workplaceId)
{
var result = await _client.GetFromJsonAsync<WorkplaceDto>(
@ -71,39 +60,28 @@ public class AdvisorWorkplaceRepository : IAdvisorWorkplaceRepository
return result ?? new WorkplaceDto();
}
/// <summary>
/// Create new workplace given the customer id and workplace data
/// </summary>
/// <param name="companyId"></param>
/// <param name="workplace"></param>
/// <returns></returns>
public async Task CreateWorkplace(string companyId, WorkplaceDto workplace)
{
await _client.PostAsJsonAsync(
$"{_api.CrmCustomers}/{companyId}/{_api.CrmWorkplaceExt}", workplace, _options);
}
/// <summary>
/// Update workplace given the customer id and updated data
/// </summary>
/// <param name="companyId"></param>
/// <param name="workplace"></param>
/// <returns></returns>
public async Task UpdateWorkplace(string companyId, WorkplaceDto workplace)
{
await _client.PutAsJsonAsync(
$"{_api.CrmCustomers}/{companyId}/{_api.CrmWorkplaceExt}/{workplace.WorkplaceId}", workplace, _options);
}
/// <summary>
/// Delete workplace given customer id and workplace id
/// </summary>
/// <param name="companyId"></param>
/// <param name="workplaceId"></param>
/// <returns></returns>
public async Task DeleteWorkplace(string companyId, string workplaceId)
{
await _client.DeleteAsync(
$"{_api.CrmCustomers}/{companyId}/{_api.CrmWorkplaceExt}/{workplaceId}");
}
public async Task<WorkplaceInventory> GetWorkplaceInventory(string companyId, string workplaceId)
{
var result = await _client.GetFromJsonAsync<WorkplaceInventory>(
$"{_api.CrmCustomers}/{companyId}/{_api.CrmWorkplaceExt}/{workplaceId}/documents");
return result ?? new WorkplaceInventory();
}
}

View file

@ -61,4 +61,12 @@ public interface IAdvisorWorkplaceRepository
/// <param name="workplaceId"></param>
/// <returns></returns>
Task DeleteWorkplace(string companyId, string workplaceId);
/// <summary>
/// Get list of products and documentation for workplace
/// </summary>
/// <param name="companyId"></param>
/// <param name="workplaceId"></param>
/// <returns></returns>
Task<WorkplaceInventory> GetWorkplaceInventory(string companyId, string workplaceId);
}

View file

@ -46,5 +46,5 @@ public interface IOfficeUserInfoRepository
/// </summary>
/// <param name="userId"></param>
/// <returns></returns>
Task<UserAdvisorInfoView> GetUserInfo(string userId);
Task<UserInfoAdvisorView> GetUserInfo(string userId);
}

View file

@ -47,7 +47,7 @@ public interface ISystemUserRepository
/// </summary>
/// <param name="model"></param>
/// <returns></returns>
Task<UserManagerEditView> CreateUser(UserManagerCreate model);
Task<UserManagerEditView> CreateUser(UserManagerCreateView model);
/// <summary>
/// Update User using userId and updated data

View file

@ -1,28 +0,0 @@
// Copyright (C) 2022 FCS Frede's Computer Services.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see [https://www.gnu.org/licenses/agpl-3.0.en.html]
//
using Wonky.Entity.DTO;
using Wonky.Entity.Views;
namespace Wonky.Client.HttpRepository;
public interface IWorkplaceHttpRepository
{
Task<List<WorkplaceListView>> GetWorkplaces(string companyId);
Task<WorkplaceDto> GetWorkplace(string companyId, string workplaceId);
Task CreateWorkplace(string companyId, WorkplaceDto workplace);
Task UpdateWorkplace(string companyId, WorkplaceDto workplace);
Task DeleteWorkplace(string companyId, string workplaceId);
}

View file

@ -75,9 +75,9 @@ public class OfficeUserInfoRepository : IOfficeUserInfoRepository
/// </summary>
/// <param name="userId"></param>
/// <returns></returns>
public async Task<UserAdvisorInfoView> GetUserInfo(string userId)
public async Task<UserInfoAdvisorView> GetUserInfo(string userId)
{
return await _client.GetFromJsonAsync<UserAdvisorInfoView>($"{_api.UserData}/{userId}");
return await _client.GetFromJsonAsync<UserInfoAdvisorView>($"{_api.UserData}/{userId}");
}
}

View file

@ -53,7 +53,7 @@ public class OrderProcessRepository : IOrderProcessRepository
/// <returns></returns>
public async Task<List<WarehouseOrderView>> GetWarehouseOrderListByDate(string date)
{
return await _client.GetFromJsonAsync<List<WarehouseOrderView>>($"{_api.Warehouse}?date={date}", _options);
return await _client.GetFromJsonAsync<List<WarehouseOrderView>>($"{_api.Warehouse}/date?date={date}", _options);
}
/// <summary>
@ -65,7 +65,7 @@ public class OrderProcessRepository : IOrderProcessRepository
public async Task<List<WarehouseOrderView>> GetWarehouseOrderListByStatus(string status, string express = "")
{
return await _client.GetFromJsonAsync<List<WarehouseOrderView>>(
$"{_api.Warehouse}?status={status}&express={express}", _options);
$"{_api.Warehouse}?status={status}&express={express}/state", _options);
}
/// <summary>

View file

@ -72,11 +72,12 @@ public class SystemUserRepository : ISystemUserRepository
/// </summary>
/// <param name="model"></param>
/// <returns></returns>
public async Task<UserManagerEditView> CreateUser(UserManagerCreate model)
public async Task<UserManagerEditView> CreateUser(UserManagerCreateView model)
{
var result = await _client.PostAsJsonAsync($"{_api.UserManager}", model, _options);
if (!result.IsSuccessStatusCode)
return new UserManagerEditView();
try
{
return await result.Content.ReadFromJsonAsync<UserManagerEditView>();

View file

@ -1,80 +0,0 @@
// Copyright (C) 2022 FCS Frede's Computer Services.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see [https://www.gnu.org/licenses/agpl-3.0.en.html]
//
using System.Net.Http.Json;
using System.Text.Json;
using Microsoft.AspNetCore.Components;
using Microsoft.Extensions.Options;
using Wonky.Entity.Configuration;
using Wonky.Entity.DTO;
using Wonky.Entity.Views;
namespace Wonky.Client.HttpRepository;
public class WorkplaceHttpRepository : IWorkplaceHttpRepository
{
private readonly JsonSerializerOptions? _options = new JsonSerializerOptions
{
PropertyNameCaseInsensitive = true
};
private readonly NavigationManager _navigation;
private ILogger<WorkplaceHttpRepository> _logger;
private readonly HttpClient _client;
private readonly ApiConfig _api;
public WorkplaceHttpRepository(HttpClient client,
ILogger<WorkplaceHttpRepository> logger,
NavigationManager navigation,
IOptions<ApiConfig> configuration)
{
_client = client;
_logger = logger;
_navigation = navigation;
_api = configuration.Value;
}
public async Task<List<WorkplaceListView>> GetWorkplaces(string companyId)
{
var result = await _client.GetFromJsonAsync<List<WorkplaceListView>>(
$"{_api.CrmCustomers}/{companyId}/{_api.CrmWorkplaceExt}", _options);
return result ?? new List<WorkplaceListView>();
}
public async Task<WorkplaceDto> GetWorkplace(string companyId, string workplaceId)
{
var result = await _client.GetFromJsonAsync<WorkplaceDto>(
$"{_api.CrmCustomers}/{companyId}/{_api.CrmWorkplaceExt}/{workplaceId}", _options);
return result ?? new WorkplaceDto();
}
public async Task CreateWorkplace(string companyId, WorkplaceDto workplace)
{
await _client.PostAsJsonAsync(
$"{_api.CrmCustomers}/{companyId}/{_api.CrmWorkplaceExt}", workplace, _options);
}
public async Task UpdateWorkplace(string companyId, WorkplaceDto workplace)
{
await _client.PutAsJsonAsync(
$"{_api.CrmCustomers}/{companyId}/{_api.CrmWorkplaceExt}/{workplace.WorkplaceId}", workplace, _options);
}
public async Task DeleteWorkplace(string companyId, string workplaceId)
{
await _client.DeleteAsync(
$"{_api.CrmCustomers}/{companyId}/{_api.CrmWorkplaceExt}/{workplaceId}");
}
}

View file

@ -15,7 +15,7 @@
namespace Wonky.Client.Models;
public class AssignedRoles
public class RoleAssignment
{
public bool Admin { get; set; }
public bool Advisor { get; set; }

View file

@ -247,6 +247,15 @@
</div>
</div>
</EditForm>
<div class="row mt-5">
<div class="col-sm-3">
<a class="btn btn-info" href="@($"/advisor/customers/{CompanyId}/workplaces")">Arbejdssteder</a>
</div>
</div>
}
@if (Working)

View file

@ -20,7 +20,43 @@
@page "/advisor/customers/{CompanyId}/workplaces/{WorkplaceId}/documents"
<PageTitle>Dokumenter for Arbejdssted</PageTitle>
<h2>Dokumenter</h2>
@if (WorkplaceInventory.Products.Any())
{
<table class="table table-striped">
<thead>
<tr>
<th>Produkt</th>
<th>APB</th>
<th>APV</th>
<th>Oprettet</th>
</tr>
</thead>
<tbody>
@foreach (var document in Documents)
{
<tr>
<td>
@document.ProductName
</td>
<td>
@document.ApbLink
</td>
<td>
@document.ApvLink
</td>
<td>
@document.DocumentDate
</td>
</tr>
}
</tbody>
</table>
}
@if (Working)
{

View file

@ -16,18 +16,72 @@
using Microsoft.AspNetCore.Components;
using Wonky.Client.HttpInterceptors;
using Wonky.Client.HttpRepository;
using Wonky.Entity.DTO;
using Wonky.Entity.Views;
#pragma warning disable CS8618
namespace Wonky.Client.Pages;
public partial class AdvisorWorkplaceDocumentListPage
public partial class AdvisorWorkplaceDocumentListPage : IDisposable
{
// ##################################################################
[Inject] public HttpInterceptorService Interceptor { get; set; }
[Inject] public IAdvisorWorkplaceRepository WorkplaceRepo { get; set; }
// ##################################################################
[Parameter] public string CompanyId { get; set; } = "";
[Parameter] public string WorkplaceId { get; set; } = "";
[Inject] public HttpInterceptorService _interceptor { get; set; }
[Inject] public IAdvisorWorkplaceRepository Workplaces { get; set; }
// ##################################################################
private bool Working { get; set; } = true;
private WorkplaceInventory WorkplaceInventory { get; set; } = new();
private List<Document> Documents { get; set; } = new();
protected override async Task OnParametersSetAsync()
{
Interceptor.RegisterEvent();
Interceptor.RegisterBeforeSendEvent();
WorkplaceInventory = await WorkplaceRepo.GetWorkplaceInventory(CompanyId, WorkplaceId);
foreach (var product in WorkplaceInventory.Products)
{
var newDoc = new Document();
foreach (var variant in product.Variants)
{
newDoc.ProductName = variant.VariantName;
foreach (var doc in variant.Docs)
{
if (doc.DocumentTypeEnum == "Apb")
{
newDoc.ApbLink = doc.DocumentLink;
}
else
{
newDoc.ApvLink = doc.DocumentLink;
}
newDoc.DocumentDate = doc.DocumentDate;
}
Documents.Add(newDoc);
}
}
Working = false;
}
public void Dispose()
{
Interceptor.DisposeEvent();
}
}
internal sealed class Document
{
public string ProductName { get; set; }
public string ApbLink { get; set; }
public string ApvLink { get; set; }
public string DocumentDate { get; set; }
}

View file

@ -19,17 +19,57 @@
@attribute [Authorize(Roles = "Advisor")]
@page "/advisor/customers/{CompanyId}/workplaces"
<PageTitle>@Company.Name arbejdssteder</PageTitle>
<div class="row bg-light border border-1 rounded-2">
<div class="col">
<h2>@Company.Name</h2>
</div>
</div>
<div class="row">
<WorkplaceListComponent CompanyId="@CompanyId" Workplaces="@WorkplaceList" />
</div>
<div class="card">
<div class="card-header">
<div class="row">
<div class="col-sm-8">
<h2>@Company.Name</h2>
</div>
<div class="col-sm-2">
<div class="btn btn-primary"><i class="bi-plus-lg"></i> NY</div>
</div>
<div class="col-sm-2">
</div>
</div>
</div>
<div class="card-body">
@if (Workplaces.Any())
{
<div class="list-group">
<div class="list-group-item">
<div class="row">
<div class="col">
<h3>Navn</h3>
</div>
<div class="col">
<h3>Beskrivelse</h3>
</div>
</div>
</div>
@foreach (var workplace in Workplaces)
{
<a class="list-group-item list-group-item-action" href="/advisor/customers/@CompanyId/workplaces/@workplace.WorkplaceId">
<div class="row">
<div class="col">
@workplace.Name
</div>
<div class="col">
@workplace.Description
</div>
</div>
</a>
}
</div>
}
else
{
<div>Ingen data</div>
}
</div>
</div>
@if (Working)
{
<WorkingThreeDots />
}
<WorkingThreeDots/>
}

View file

@ -29,7 +29,7 @@ public partial class AdvisorWorkplaceListPage : IDisposable
[Inject] public IAdvisorWorkplaceRepository WorkplaceRepo { get; set; }
[Inject] public IAdvisorCustomerRepository CustomerRepo { get; set; }
[Inject] public HttpInterceptorService Interceptor { get; set; }
private List<WorkplaceListView> WorkplaceList { get; set; } = new();
private List<WorkplaceListView> Workplaces { get; set; } = new();
private CompanyDto Company { get; set; } = new();
private bool Working { get; set; } = true;
@ -44,7 +44,7 @@ public partial class AdvisorWorkplaceListPage : IDisposable
protected override async Task OnInitializedAsync()
{
Working = true;
WorkplaceList = await WorkplaceRepo.GetWorkplaces(CompanyId);
Workplaces = await WorkplaceRepo.GetWorkplaces(CompanyId);
Working = false;
}

View file

@ -105,7 +105,7 @@
</table>
<div class="row mb-2">
<div class="col-md-4">
<button type="button" class="btn btn-danger" @onclick="DeleteWorkplace">Slet</button>
<button type="button" class="btn btn-danger" disabled @onclick="DeleteWorkplace">Slet</button>
</div>
<div class="col-md-4">
<button type="submit" class="btn btn-success">Gem</button>

View file

@ -19,36 +19,42 @@ using Microsoft.AspNetCore.Components.Forms;
using Wonky.Client.HttpInterceptors;
using Wonky.Client.HttpRepository;
using Wonky.Entity.DTO;
#pragma warning disable CS8618
#pragma warning disable CS8618
namespace Wonky.Client.Pages;
public partial class AdvisorWorkplaceViewPage : IDisposable
public partial class AdvisorWorkplaceViewEditPage : IDisposable
{
[Parameter] public string CompanyId { get; set; } = "";
[Parameter] public string WorkplaceId { get; set; } = "";
// #############################################################
[Inject] public IAdvisorWorkplaceRepository Workplaces { get; set; }
[Inject] public IAdvisorCustomerRepository CustomerRepo { get; set; }
[Inject] public HttpInterceptorService Interceptor { get; set; }
[Inject] public NavigationManager Navigator { get; set; }
// #############################################################
[Parameter] public string CompanyId { get; set; } = "";
[Parameter] public string WorkplaceId { get; set; } = "";
// #############################################################
private WorkplaceDto Workplace { get; set; } = new();
private EditContext WorkplaceContext { get; set; }
private bool Working { get; set; } = true;
protected override async Task OnParametersSetAsync()
protected override async Task OnInitializedAsync()
{
WorkplaceContext = new EditContext(Workplace);
WorkplaceContext.OnFieldChanged += HandleFieldChanged;
WorkplaceContext.OnValidationStateChanged += ValidationChanged;
Interceptor.RegisterEvent();
Interceptor.RegisterBeforeSendEvent();
Workplace = await Workplaces.GetWorkplace(CompanyId, WorkplaceId);
Working = false;
StateHasChanged();
}
protected override void OnInitialized()
{
WorkplaceContext = new EditContext(Workplace);
}
private async Task SubmitUpdate()
{
Working = true;
@ -56,6 +62,7 @@ public partial class AdvisorWorkplaceViewPage : IDisposable
Working = false;
}
private async Task DeleteWorkplace()
{
Working = true;
@ -63,8 +70,30 @@ public partial class AdvisorWorkplaceViewPage : IDisposable
Navigator.NavigateTo($"/advisor/customers/{CompanyId}/workplaces");
}
private void HandleFieldChanged(object sender, FieldChangedEventArgs e)
{
WorkplaceContext.Validate();
StateHasChanged();
}
private void ValidationChanged(object sender, ValidationStateChangedEventArgs e)
{
WorkplaceContext.OnFieldChanged -= HandleFieldChanged;
WorkplaceContext.OnValidationStateChanged -= ValidationChanged;
WorkplaceContext = new EditContext(Workplace);
WorkplaceContext.OnFieldChanged += HandleFieldChanged;
WorkplaceContext.OnValidationStateChanged += ValidationChanged;
}
public void Dispose()
{
WorkplaceContext.OnFieldChanged += HandleFieldChanged;
WorkplaceContext.OnValidationStateChanged += ValidationChanged;
Interceptor.DisposeEvent();
}
}

View file

@ -47,7 +47,7 @@ public partial class OfficeAdvisorCustomerPagedListPage : IDisposable
private bool ShowFolded { get; set; }
private string ToggleFoldedText { get; set; } = "Vis Lukkede";
private bool Working { get; set; } = true;
private UserAdvisorInfoView SalesRep { get; set; } = new();
private UserInfoAdvisorView SalesRep { get; set; } = new();
protected override async Task OnParametersSetAsync()
{

View file

@ -19,11 +19,11 @@
@attribute [Authorize(Roles = "Admin,Office")]
@page "/office/users/advisors/{CountryCode}/{UserId}/reports"
<PageTitle>Rapport Arkiv @AdvisorInfo.FirstName @AdvisorInfo.LastName</PageTitle>
<PageTitle>Rapport Arkiv @InfoAdvisor.FirstName @InfoAdvisor.LastName</PageTitle>
<div class="card">
<div class="card-header">
<div class="mt-3 h3 card-title">
Rapport Arkiv - @AdvisorInfo.FirstName @AdvisorInfo.LastName
Rapport Arkiv - @InfoAdvisor.FirstName @InfoAdvisor.LastName
</div>
</div>
<OfficeReportListComponent OnShowReport="ShowThisReport" CountryCode="@CountryCode" UserId="@UserId" ReportList="@ActivityReports" />

View file

@ -38,7 +38,7 @@ public partial class OfficeAdvisorReportListPage : IDisposable
// #############################################################
private List<SalesReportListView> ActivityReports { get; set; } = new();
private bool Working { get; set; } = true;
private UserAdvisorInfoView AdvisorInfo { get; set; } = new();
private UserInfoAdvisorView InfoAdvisor { get; set; } = new();
/// <summary>
/// override OnParametersSeAsync
@ -48,8 +48,8 @@ public partial class OfficeAdvisorReportListPage : IDisposable
Interceptor.RegisterEvent();
Interceptor.RegisterBeforeSendEvent();
AdvisorInfo = await UserRepo.GetUserInfo(UserId);
while (string.IsNullOrWhiteSpace(AdvisorInfo.UserId))
InfoAdvisor = await UserRepo.GetUserInfo(UserId);
while (string.IsNullOrWhiteSpace(InfoAdvisor.UserId))
{
await Task.Delay(500);
}

View file

@ -62,7 +62,7 @@ public partial class OfficeOrderCreatePage : IDisposable
private UserManagerEditView UserInfo { get; set; } = new();
private SalesItemView SelectedItem { get; set; } = new();
private ActivityDto Activity { get; set; } = new();
private UserAdvisorInfoView SalesRep { get; set; } = new();
private UserInfoAdvisorView SalesRep { get; set; } = new();
// edit context
private EditContext ActivityContext { get; set; }
// variables

View file

@ -18,11 +18,11 @@
@attribute [Authorize(Roles = "Admin,Management,Supervisor")]
@page "/supervisor/advisors/{UserId}"
<PageTitle>Rapport Arkiv @AdvisorInfo.FirstName @AdvisorInfo.LastName</PageTitle>
<PageTitle>Rapport Arkiv @InfoAdvisor.FirstName @InfoAdvisor.LastName</PageTitle>
<div class="card">
<div class="card-header">
<div class="mt-3 h3 card-title">
Rapport Arkiv - @AdvisorInfo.FirstName @AdvisorInfo.LastName
Rapport Arkiv - @InfoAdvisor.FirstName @InfoAdvisor.LastName
</div>
</div>
<ReportListComponent OnShowReport="ShowReport" ReportList="@ActivityReports" />

View file

@ -22,7 +22,7 @@ public partial class SupervisorAdvisorViewPage : IDisposable
// #############################################################
private UserAdvisorInfoView AdvisorInfo { get; set; } = new();
private UserInfoAdvisorView InfoAdvisor { get; set; } = new();
private List<SalesReportListView> ActivityReports { get; set; } = new();
private bool Working { get; set; } = true;
@ -32,9 +32,9 @@ public partial class SupervisorAdvisorViewPage : IDisposable
Interceptor.RegisterEvent();
Interceptor.RegisterBeforeSendEvent();
AdvisorInfo = await UserRepo.GetUserInfo(UserId);
InfoAdvisor = await UserRepo.GetUserInfo(UserId);
while (string.IsNullOrWhiteSpace(AdvisorInfo.UserId))
while (string.IsNullOrWhiteSpace(InfoAdvisor.UserId))
{
await Task.Delay(500);
}

View file

@ -26,7 +26,7 @@
</div>
</div>
<div class="card-body">
<EditForm EditContext="NewUserContext" OnValidSubmit="CreateUser">
<EditForm EditContext="NewUserContext" OnValidSubmit="CreateUserRequest">
<DataAnnotationsValidator/>
<div class="row g-3 mb-3">
<label for="firstName" class="col-sm-2 col-form-label">Fornavn</label>
@ -53,7 +53,7 @@
<ValidationMessage For="@(() => NewUserInfo.PhoneNumber)"></ValidationMessage>
</div>
<label for="salesRep" class="col-sm-2 col-form-label">MedarbejderId</label>
<label for="salesRep" class="col-sm-2 col-form-label">Sælgernr</label>
<div class="col-sm-4">
<InputText id="salesRep" class="form-control" @bind-Value="NewUserInfo.SalesRep"/>
<ValidationMessage For="@(() => NewUserInfo.SalesRep)"></ValidationMessage>
@ -102,7 +102,7 @@
<label for="advisor" class="form-check-label">Sælger</label>
</div>
</div>
<div class="row">
<div class="row mb-3">
<div class="col">
</div>
<div class="col">

View file

@ -31,58 +31,54 @@ namespace Wonky.Client.Pages;
public partial class SystemUserCreatePage : IDisposable
{
// #############################################################
[Inject] public HttpInterceptorService Interceptor { get; set; }
[Inject] public ISystemUserRepository UserRepo { get; set; }
[Inject] public ILogger<SystemUserCreatePage> Logger { get; set; }
[Inject] public IToastService Toaster { get; set; }
[Inject] public HttpInterceptorService Interceptor { get; set; }
[Inject] public ISystemUserRepository UserRepo { get; set; }
[Inject] public ILogger<SystemUserCreatePage> Logger { get; set; }
[Inject] public IToastService Toaster { get; set; }
// #############################################################
private UserManagerCreate NewUserInfo { get; set; } = new();
private UserManagerCreateView NewUserInfo { get; set; } = new();
private EditContext NewUserContext { get; set; }
private bool ContextInvalid { get; set; } = true;
private bool Working { get; set; } = true;
private bool ReadOnly { get; set; } = true;
private PasswordInput PasswdInput { get; set; } = new();
private AssignedRoles AssignedRoles { get; set; } = new();
private RoleAssignment AssignedRoles { get; set; } = new();
private readonly JsonSerializerOptions _options = new JsonSerializerOptions
{
PropertyNameCaseInsensitive = true
};
protected override async Task OnParametersSetAsync()
protected override void OnParametersSet()
{
Interceptor.RegisterEvent();
Interceptor.RegisterBeforeSendEvent();
NewUserContext = new EditContext(NewUserInfo);
NewUserContext.OnFieldChanged += ContextHandleFieldChanged!;
NewUserContext.OnValidationStateChanged += ContextValidationChanged;
Working = false;
}
private async Task CreateUser()
{
// NewUserInfo.AssignedRoles = new List<UserRoleAssignment>()
// {
// new (){ Name = "Admin", Assigned = false },
// new (){ Name = "Advisor", Assigned = false },
// new (){ Name = "Management", Assigned = false },
// new (){ Name = "Office", Assigned = false },
// new (){ Name = "Supervisor", Assigned = false },
// new (){ Name = "Warehouse", Assigned = false },
// };
private async Task CreateUserRequest()
{
ReadOnly = true;
Working = true;
NewUserInfo.AssignedRoles = Utils.MapSaveAssignedRoles(AssignedRoles);
Toaster.ShowInfo("Sender data til server ...");
await UserRepo.CreateUser(NewUserInfo);
Working = false;
Toaster.ShowInfo("Bruger er oprettet ...");
}
private void ContextHandleFieldChanged(object sender, FieldChangedEventArgs e)
private void ContextHandleFieldChanged(object? sender, FieldChangedEventArgs e)
{
Logger.LogDebug("contextHandleFieldChanged => e.FieldIdentifier.FieldName {}", e.FieldIdentifier.FieldName);
if (e.FieldIdentifier.FieldName == "NewPassword")
@ -93,23 +89,27 @@ public partial class SystemUserCreatePage : IDisposable
return;
}
}
NewUserInfo.Passwd = PasswdInput.NewPassword;
ContextInvalid = !NewUserContext.Validate();
StateHasChanged();
}
private void ContextValidationChanged(object? sender, ValidationStateChangedEventArgs e)
{
ContextInvalid = true;
NewUserContext.OnFieldChanged -= ContextHandleFieldChanged!;
NewUserContext.OnFieldChanged -= ContextHandleFieldChanged;
NewUserContext.OnValidationStateChanged -= ContextValidationChanged;
NewUserContext = new EditContext(NewUserInfo);
NewUserContext.OnFieldChanged += ContextHandleFieldChanged!;
NewUserContext.OnFieldChanged += ContextHandleFieldChanged;
NewUserContext.OnValidationStateChanged += ContextValidationChanged;
}
public void Dispose()
{
Interceptor.DisposeEvent();

View file

@ -30,9 +30,9 @@
</div>
</div>
<div class="card-body">
@if (!string.IsNullOrWhiteSpace(UserData.UserId))
@if (!string.IsNullOrWhiteSpace(UserInfo.UserId))
{
<EditForm EditContext="UserEditContext" OnValidSubmit="UpdateUser">
<EditForm EditContext="UserEditContext" OnValidSubmit="SendUpdateRequest">
<DataAnnotationsValidator/>
<div class="row">
<div class="col">
@ -43,15 +43,15 @@
Fornavn
</th>
<td>
<InputText id="firstName" class="form-control" @bind-Value="UserData.FirstName" readonly="@ReadOnly" />
<ValidationMessage For="@(() => UserData.FirstName)"></ValidationMessage>
<InputText id="firstName" class="form-control" @bind-Value="UserInfo.FirstName" readonly="@ReadOnly"/>
<ValidationMessage For="@(() => UserInfo.FirstName)"></ValidationMessage>
</td>
<th scope="col">
Efternavn
</th>
<td>
<InputText id="lastName" class="form-control" @bind-Value="UserData.LastName" readonly="@ReadOnly" />
<ValidationMessage For="@(() => UserData.LastName)"></ValidationMessage>
<InputText id="lastName" class="form-control" @bind-Value="UserInfo.LastName" readonly="@ReadOnly"/>
<ValidationMessage For="@(() => UserInfo.LastName)"></ValidationMessage>
</td>
</tr>
<tr class="align-middle">
@ -60,9 +60,9 @@
</th>
<td>
<div class="form-floating">
<InputText id="email" class="form-control" @bind-Value="UserData.Email" readonly="@ReadOnly" placeholder="name@innotec.dk"/>
<InputText id="email" class="form-control" @bind-Value="UserInfo.Email" readonly="@ReadOnly" placeholder="name@innotec.dk"/>
<label for="email">Email adresse - bruges til login</label>
<ValidationMessage For="@(() => UserData.Email)"></ValidationMessage>
<ValidationMessage For="@(() => UserInfo.Email)"></ValidationMessage>
</div>
</td>
<th scope="col">
@ -70,9 +70,9 @@
</th>
<td>
<div class="form-floating">
<InputText id="phoneNumber" class="form-control" @bind-Value="UserData.PhoneNumber" readonly="@ReadOnly" placeholder="+45 20202020"/>
<InputText id="phoneNumber" class="form-control" @bind-Value="UserInfo.PhoneNumber" readonly="@ReadOnly" placeholder="+45 20202020"/>
<label for="phoneNumber">Mobil nummer - bruges til korte beskeder</label>
<ValidationMessage For="@(() => UserData.PhoneNumber)"></ValidationMessage>
<ValidationMessage For="@(() => UserInfo.PhoneNumber)"></ValidationMessage>
</div>
</td>
</tr>
@ -82,17 +82,17 @@
</th>
<td>
<div class="form-floating">
<InputText id="salesRep" class="form-control" @bind-Value="UserData.SalesRep" readonly="@ReadOnly" placeholder="10"/>
<InputText id="salesRep" class="form-control" @bind-Value="UserInfo.SalesRep" readonly="@ReadOnly" placeholder="10"/>
<label for="salesRep">Sælgernummer fra ERP</label>
<ValidationMessage For="@(() => UserData.SalesRep)"></ValidationMessage>
<ValidationMessage For="@(() => UserInfo.SalesRep)"></ValidationMessage>
</div>
</td>
<th scope="col">
Landekode
</th>
<td>
<InputText id="countryCode" class="form-control" @bind-Value="UserData.CountryCode" readonly="@ReadOnly" />
<ValidationMessage For="@(() => UserData.CountryCode)"></ValidationMessage>
<InputText id="countryCode" class="form-control" @bind-Value="UserInfo.CountryCode" readonly="@ReadOnly"/>
<ValidationMessage For="@(() => UserInfo.CountryCode)"></ValidationMessage>
</td>
</tr>
<tr class="align-middle">
@ -100,28 +100,49 @@
Spærret
</th>
<td>
<InputCheckbox id="lockoutEnabled" class="form-check" @bind-Value="UserData.LockoutEnabled" disabled="@ReadOnly"/>
<ValidationMessage For="@(() => UserData.LockoutEnabled)"></ValidationMessage>
<InputCheckbox id="lockoutEnabled" class="form-check" @bind-Value="UserInfo.LockoutEnabled" disabled="@ReadOnly"/>
<ValidationMessage For="@(() => UserInfo.LockoutEnabled)"></ValidationMessage>
</td>
<th scope="col">Beskrivelse</th>
<td>
<div class="form-floating">
<InputText id="description" class="form-control" @bind-Value="@UserData.Description" readonly="@ReadOnly" placeholder="Info tekst"/>
<InputText id="description" class="form-control" @bind-Value="@UserInfo.Description" readonly="@ReadOnly" placeholder="Info tekst"/>
<label for="description">Kort bruger beskrivelse</label>
<ValidationMessage For="@(() => UserData.Description)"></ValidationMessage>
<ValidationMessage For="@(() => UserInfo.Description)"></ValidationMessage>
</div>
</td>
</tr>
<tr>
<th scope="col">Roller</th>
<td>
@foreach (var role in UserData.AssignedRoles)
{
<div class="form-check">
<InputCheckbox id="@(role.Name)" class="form-check-input" @bind-Value="role.Assigned" disabled="@ReadOnly" />
<label class="form-check-label">@role.Name</label>
</div>
}
<div class="ms-2 col-sm-2 form-check form-switch">
<InputCheckbox id="admin" class="form-check-input" disabled="@ReadOnly" @bind-Value="AssignedRoles.Admin"/>
<label for="admin" class="form-check-label">Administrator</label>
</div>
<div class="ms-2 col-sm-2 form-check form-switch">
<InputCheckbox id="office" class="form-check-input" disabled="@ReadOnly" @bind-Value="AssignedRoles.Office"/>
<label for="office" class="form-check-label">Kontor</label>
</div>
<div class="ms-2 col-sm-2 form-check form-switch">
<InputCheckbox id="eshop" class="form-check-input" disabled="@ReadOnly" @bind-Value="AssignedRoles.EShop"/>
<label for="eshop" class="form-check-label">Kunde</label>
</div>
<div class="ms-2 col-sm-2 form-check form-switch">
<InputCheckbox id="warehouse" class="form-check-input" disabled="@ReadOnly" @bind-Value="AssignedRoles.Warehouse"/>
<label for="warehouse" class="form-check-label">Forsendelse</label>
</div>
<div class="ms-2 col-sm-2 form-check form-switch">
<InputCheckbox id="management" class="form-check-input" disabled="@ReadOnly" @bind-Value="AssignedRoles.Management"/>
<label for="management" class="form-check-label">Ledelse</label>
</div>
<div class="ms-2 col-sm-2 form-check form-switch">
<InputCheckbox id="supervisor" class="form-check-input" disabled="@ReadOnly" @bind-Value="AssignedRoles.Supervisor"/>
<label for="supervisor" class="form-check-label">Supervisor</label>
</div>
<div class="ms-2 col-sm-2 form-check form-switch">
<InputCheckbox id="advisor" class="form-check-input" disabled="@ReadOnly" @bind-Value="AssignedRoles.Advisor"/>
<label for="advisor" class="form-check-label">Sælger</label>
</div>
</td>
</tr>
</tbody>
@ -130,18 +151,21 @@
</div>
<div class="row">
<div class="col">
<button type="button" class="btn btn-danger" @onclick="() => ReadOnly = !ReadOnly">Rediger</button>
<button type="button" class="btn btn-danger" disabled="@ReadOnly" @onclick="SendDeleteRequest">SLET</button>
</div>
<div class="col">
<button type="submit" class="btn btn-primary">Gem</button>
<button type="button" class="btn btn-warning" @onclick="() => ReadOnly = !ReadOnly">Rediger</button>
</div>
<div class="col">
<button type="submit" class="btn btn-primary" disabled="@ReadOnly">Gem</button>
</div>
<div class="col">
<a class="btn btn-primary" href="/system/users">Tilbage</a>
</div>
</div>
</EditForm>
<EditForm EditContext="PasswdContext" class="mt-5" >
<DataAnnotationsValidator />
<EditForm EditContext="PasswdContext" class="mt-5">
<DataAnnotationsValidator/>
<h3>NULSTIL ADGANGSKODE</h3>
<div class="alert alert-info">
<div class="h4">Password politik</div>
@ -163,7 +187,7 @@
</div>
<div class="row">
<div class="col align-content-end">
<button class="btn btn-danger" @onclick="SetPassword" disabled="@PwInvalid">NULSTIL</button>
<button class="btn btn-danger" @onclick="SetPassword" disabled="@PwInvalid">NULSTIL</button>
</div>
</div>
</EditForm>
@ -175,4 +199,4 @@
@if (Working)
{
<WorkingThreeDots/>
}
}

View file

@ -21,6 +21,7 @@ using Microsoft.AspNetCore.Components.Forms;
using Wonky.Client.Helpers;
using Wonky.Client.HttpInterceptors;
using Wonky.Client.HttpRepository;
using Wonky.Client.Models;
using Wonky.Entity.DTO;
#pragma warning disable CS8618
@ -29,19 +30,19 @@ namespace Wonky.Client.Pages;
public partial class SystemUserViewEditPage : IDisposable
{
// #############################################################
[Inject] public HttpInterceptorService Interceptor { get; set; }
[Inject] public ISystemUserRepository UserRepo { get; set; }
[Inject] public ILogger<SystemUserViewEditPage> Logger { get; set; }
[Inject] public IToastService Toaster { get; set; }
[Inject] public HttpInterceptorService Interceptor { get; set; }
[Inject] public ISystemUserRepository UserRepo { get; set; }
[Inject] public ILogger<SystemUserViewEditPage> Logger { get; set; }
[Inject] public IToastService Toaster { get; set; }
[Inject] public NavigationManager Navigator { get; set; }
// #############################################################
[Parameter] public string UserId { get; set; } = "";
[Parameter] public string CountryCode { get; set; } = "";
// #############################################################
private UserManagerEditView UserData { get; set; } = new();
private UserManagerEditView UserInfo { get; set; } = new();
private EditContext UserEditContext { get; set; }
private ResetPasswordDto Passwords { get; set; } = new();
private EditContext PasswdContext { get; set; }
@ -49,56 +50,80 @@ public partial class SystemUserViewEditPage : IDisposable
private bool Working { get; set; } = true;
private bool ReadOnly { get; set; } = true;
private RoleAssignment AssignedRoles { get; set; } = new();
private readonly JsonSerializerOptions _options = new JsonSerializerOptions
{
PropertyNameCaseInsensitive = true
};
protected override async Task OnParametersSetAsync()
{
Interceptor.RegisterEvent();
Interceptor.RegisterBeforeSendEvent();
UserData = await UserRepo.GetUserInfo(UserId);
UserEditContext = new EditContext(UserData);
UserInfo = await UserRepo.GetUserInfo(UserId);
AssignedRoles = Utils.MapEditAssignedRoles(UserInfo);
UserEditContext = new EditContext(UserInfo);
PasswdContext = new EditContext(Passwords);
PasswdContext.OnFieldChanged += PwHandleFieldChanged!;
PasswdContext.OnValidationStateChanged += PwValidationChanged;
Working = false;
}
private async Task UpdateUser()
private async Task SendUpdateRequest()
{
ReadOnly = true;
Working = true;
UserInfo.AssignedRoles = Utils.MapSaveAssignedRoles(AssignedRoles);
Toaster.ShowInfo("Sender data til server ...");
await UserRepo.UpdateUserInfo(UserId, UserData);
await UserRepo.UpdateUserInfo(UserId, UserInfo);
Working = false;
Toaster.ShowInfo("Bruger er opdateret ...");
}
private async Task SendDeleteRequest()
{
ReadOnly = true;
Working = true;
Toaster.ShowInfo("Forspørgsel om sletning sendt.");
await UserRepo.DeleteUser(UserId);
Navigator.NavigateTo("/system/users");
}
private void PwHandleFieldChanged(object sender, FieldChangedEventArgs e)
{
PwInvalid = !PasswdContext.Validate();
StateHasChanged();
}
private void PwValidationChanged(object? sender, ValidationStateChangedEventArgs e)
{
PwInvalid = true;
if (!Utils.IsValidPasswd(Passwords.NewPassword))
return;
PasswdContext.OnFieldChanged -= PwHandleFieldChanged!;
PasswdContext.OnValidationStateChanged -= PwValidationChanged;
PasswdContext = new EditContext(Passwords);
PasswdContext.OnFieldChanged += PwHandleFieldChanged!;
PasswdContext.OnValidationStateChanged += PwValidationChanged;
}
private async Task SetPassword()
{
if (Working)
@ -111,6 +136,8 @@ public partial class SystemUserViewEditPage : IDisposable
Working = false;
Toaster.ShowInfo("Adgangskode er nulstillet.");
}
public void Dispose()
{
Interceptor.DisposeEvent();

View file

@ -1,6 +0,0 @@
@using Microsoft.AspNetCore.Authorization
@using Wonky.Client.Components
@attribute [Authorize(Roles = "Advisor")]
@page "/advisor/customers//{CompanyId}/workplaces/{WorkplaceId}/documents"
<h2>Dokumenter</h2>

View file

@ -1,35 +0,0 @@
using Microsoft.AspNetCore.Components;
using Wonky.Client.HttpInterceptors;
using Wonky.Client.HttpRepository;
using Wonky.Entity.DTO;
#pragma warning disable CS8618
namespace Wonky.Client.Pages;
public partial class WorkplaceDocumentListPage : IDisposable
{
// ##############################################################
[Inject] private HttpInterceptorService Interceptor { get; set; }
[Inject] private IWorkplaceHttpRepository WorkplaceRepo { get; set; }
// ##############################################################
[Parameter] public string CompanyId { get; set; } = "";
[Parameter] public string WorkplaceId { get; set; } = "";
// ##############################################################
private WorkplaceDto Workplace { get; set; } = new();
protected override async Task OnParametersSetAsync()
{
Interceptor.RegisterEvent();
Interceptor.RegisterBeforeSendEvent();
}
public void Dispose()
{
Interceptor.DisposeEvent();
}
}

View file

@ -1,30 +0,0 @@
@*
// Copyright (C) 2022 FCS Frede's Computer Services.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see [https://www.gnu.org/licenses/agpl-3.0.en.html]
//
*@
@using Microsoft.AspNetCore.Authorization
@using Wonky.Client.Components
@attribute [Authorize(Roles = "Advisor")]
@page "/advisor/customers/{CompanyId}/workplaces"
<div class="row bg-light border border-1 rounded-2">
<div class="col">
<h2>@Customer.Name</h2>
</div>
</div>
<div class="row">
<WorkplaceListComponent CompanyId="@CompanyId" Workplaces="@Workplaces" />
</div>

View file

@ -1,60 +0,0 @@
// Copyright (C) 2022 FCS Frede's Computer Services.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see [https://www.gnu.org/licenses/agpl-3.0.en.html]
//
using Microsoft.AspNetCore.Components;
using Wonky.Client.HttpInterceptors;
using Wonky.Client.HttpRepository;
using Wonky.Entity.DTO;
using Wonky.Entity.Views;
#pragma warning disable CS8618
namespace Wonky.Client.Pages;
public partial class WorkplaceListPage : IDisposable
{
// ##############################################################
[Inject] private IWorkplaceHttpRepository WorkplaceRepo { get; set; }
[Inject] private IAdvisorCustomerRepository CustomerRepo { get; set; }
[Inject] private HttpInterceptorService Interceptor { get; set; }
// ##############################################################
[Parameter] public string CompanyId { get; set; } = "";
// ##############################################################
private List<WorkplaceListView> Workplaces { get; set; } = new();
private CompanyDto Customer { get; set; } = new();
protected override async Task OnParametersSetAsync()
{
Interceptor.RegisterEvent();
Interceptor.RegisterBeforeSendEvent();
Customer = await CustomerRepo.GetCompanyById(CompanyId);
}
protected override async Task OnInitializedAsync()
{
Workplaces = await WorkplaceRepo.GetWorkplaces(CompanyId);
}
public void Dispose()
{
Interceptor.DisposeEvent();
}
}

View file

@ -1,121 +0,0 @@
@*
// Copyright (C) 2022 FCS Frede's Computer Services.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see [https://www.gnu.org/licenses/agpl-3.0.en.html]
//
*@
@using Microsoft.AspNetCore.Authorization
@attribute [Authorize(Roles = "Advisor")]
@page "/advisor/customers/{CompanyId}/workplaces/{WorkplaceId}"
<div class="card">
<div class="card-header">
<div class="card-title">
<h2>@Workplace.CompanyName</h2>
<h3>@Workplace.Name @(!string.IsNullOrWhiteSpace(Workplace.Description) ? $"- {Workplace.Description}" : "")</h3>
</div>
</div>
<div class="card-body">
<EditForm EditContext="WorkplaceContext" OnValidSubmit="SubmitUpdate">
<DataAnnotationsValidator/>
<table class="table">
<thead>
<tr>
<th colspan="4">
Stamdata
</th>
</tr>
</thead>
<tbody>
<tr>
<td class="align-middle">Navn</td>
<td class="align-middle">
<InputText id="name" class="form-control" @bind-Value="Workplace.Name"/>
<ValidationMessage For="@(() => Workplace.Name)"></ValidationMessage>
</td>
<td class="align-middle">Beskrivelse</td>
<td class="align-middle">
<InputText id="description" class="form-control" @bind-Value="Workplace.Description"/>
<ValidationMessage For="@(() => Workplace.Description)"></ValidationMessage>
</td>
</tr>
<tr>
<th class="align-middle text-center" colspan="4">Placering og Opbevaring</th>
</tr>
<tr>
<td class="align-middle">Produkter</td>
<td class="align-middle">
<InputText id="productStorage" class="form-control" @bind-Value="Workplace.ProductStorage"/>
<ValidationMessage For="@(() => Workplace.ProductStorage)"></ValidationMessage>
</td>
<td class="align-middle" colspan="2"></td>
</tr>
<tr>
<td class="align-middle">Masker</td>
<td class="align-middle">
<InputText id="maskStorage" class="form-control" @bind-Value="Workplace.MaskStorage"/>
<ValidationMessage For="@(() => Workplace.MaskStorage)"></ValidationMessage>
</td>
<td class="align-middle">Øjenskylleflaske</td>
<td class="align-middle">
<InputText id="eyeCleanerLocation" class="form-control" @bind-Value="Workplace.EyeCleanerLocation"/>
<ValidationMessage For="@(() => Workplace.EyeCleanerLocation)"></ValidationMessage>
</td>
</tr>
<tr>
<td class="align-middle">Handsker</td>
<td class="align-middle">
<InputText id="glovesStorage" class="form-control" @bind-Value="Workplace.GlovesStorage"/>
<ValidationMessage For="@(() => Workplace.GlovesStorage)"></ValidationMessage>
</td>
<td class="align-middle">Førstehjælp</td>
<td class="align-middle">
<InputText id="firstAidStorage" class="form-control" @bind-Value="Workplace.FirstAidStorage"/>
<ValidationMessage For="@(() => Workplace.FirstAidStorage)"></ValidationMessage>
</td>
</tr>
<tr>
<td class="align-middle">Sikkerhedsbriller</td>
<td class="align-middle">
<InputText id="gogglesStorage" class="form-control" @bind-Value="Workplace.GogglesStorage"/>
<ValidationMessage For="@(() => Workplace.GogglesStorage)"></ValidationMessage>
</td>
<td class="align-middle" colspan="2"></td>
</tr>
<tr>
<td class="align-middle">Affald</td>
<td class="align-middle">
<InputText id="masteDeposit" class="form-control" @bind-Value="Workplace.WasteDeposit"/>
<ValidationMessage For="@(() => Workplace.WasteDeposit)"></ValidationMessage>
</td>
<td class="align-middle" colspan="2"></td>
</tr>
</tbody>
</table>
<div class="row mb-2">
<div class="col-md-4">
<button type="button" class="btn btn-danger" @onclick="DeleteWorkplace">Slet</button>
</div>
<div class="col-md-4">
<button type="submit" class="btn btn-success">Gem</button>
</div>
<div class="col-md-4">
<a class="btn btn-primary" href="/companies/@CompanyId/workplaces/@WorkplaceId/documents">Dokumenter</a>
</div>
</div>
</EditForm>
</div>
</div>

View file

@ -1,75 +0,0 @@
// Copyright (C) 2022 FCS Frede's Computer Services.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see [https://www.gnu.org/licenses/agpl-3.0.en.html]
//
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Forms;
using Wonky.Client.HttpInterceptors;
using Wonky.Client.HttpRepository;
using Wonky.Entity.DTO;
#pragma warning disable CS8618
namespace Wonky.Client.Pages;
public partial class WorkplaceViewPage : IDisposable
{
// ##############################################################33333
[Inject] private IWorkplaceHttpRepository WorkplaceRepo { get; set; }
[Inject] private IAdvisorCustomerRepository CustomerRepo { get; set; }
[Inject] private HttpInterceptorService Interceptor { get; set; }
[Inject] private NavigationManager Navigator { get; set; }
// ##############################################################33333
[Parameter] public string CompanyId { get; set; } = "";
[Parameter] public string WorkplaceId { get; set; } = "";
// ##############################################################33333
private WorkplaceDto Workplace { get; set; } = new();
private EditContext WorkplaceContext { get; set; }
protected override async Task OnParametersSetAsync()
{
Interceptor.RegisterEvent();
Interceptor.RegisterBeforeSendEvent();
Workplace = await WorkplaceRepo.GetWorkplace(CompanyId, WorkplaceId);
}
protected override void OnInitialized()
{
WorkplaceContext = new EditContext(Workplace);
}
private async Task SubmitUpdate()
{
await WorkplaceRepo.UpdateWorkplace(CompanyId, Workplace);
}
private async Task DeleteWorkplace()
{
await WorkplaceRepo.DeleteWorkplace(CompanyId, Workplace.WorkplaceId);
Navigator.NavigateTo($"/companies/{CompanyId}/workplaces");
}
public void Dispose()
{
Interceptor.DisposeEvent();
}
}

View file

@ -1,7 +1,7 @@
{
"appInfo": {
"name": "Wonky Online",
"version": "0.127.0",
"version": "0.131.0",
"rc": true,
"sandBox": false,
"image": "grumpy-coder.png"
@ -40,7 +40,7 @@
"servicesVatDk": "api/v2/services/virk",
"serviceVatEu": "api/v2/services/vies",
"servicesVatNo": "api/v2/services/brReg",
"servicesAuth": "token",
"servicesAuth": "v2/token",
"syncRpc": "api/v2/rpc",
"syncRpcInvoiceExt": "invoices",
"userData": "/api/v2/client/users",

View file

@ -18,22 +18,43 @@ using System.ComponentModel.DataAnnotations;
namespace Wonky.Entity.DTO;
public class UserManagerCreate
public class UserManagerCreateView
{
[MaxLength(128)] public string CompanyId { get; set; } = "";
[MaxLength(128)] public string ContactId { get; set; } = "";
[Required(ErrorMessage = "Landekode skal udfyldes")][MaxLength(2, ErrorMessage = "Landekode er 2 bogstaver")] public string CountryCode { get; set; } = "";
[MaxLength(128, ErrorMessage = "Kort beskrivelse på højst 128 tegn.")] public string Description { get; set; } = "";
[Required(ErrorMessage = "Email adresse skal udfyldes")][MaxLength(255, ErrorMessage = "Der er afsat 255 tegn til email adressen")] public string Email { get; set; } = "";
[Required(ErrorMessage = "Landekode skal udfyldes")]
[MaxLength(2, ErrorMessage = "Landekode er 2 bogstaver")]
public string CountryCode { get; set; } = "";
[MaxLength(128, ErrorMessage = "Kort beskrivelse på højst 128 tegn.")]
public string Description { get; set; } = "";
[Required(ErrorMessage = "Email adresse skal udfyldes")]
[MaxLength(255, ErrorMessage = "Der er afsat 255 tegn til email adressen")]
public string Email { get; set; } = "";
public bool EmailConfirmed { get; set; }
public bool EShop { get; set; }
[Required(ErrorMessage = "Fornavn skal udfyldes")][MaxLength(50, ErrorMessage = "Der er afsat 50 tegn til fornavn")] public string FirstName { get; set; } = "";
[Required(ErrorMessage = "Efternavn skal udfyldes")][MaxLength(50, ErrorMessage = "Der er afsat 50 tegn til efternavn")] public string LastName { get; set; } = "";
[Required(ErrorMessage = "Fornavn skal udfyldes")]
[MaxLength(50, ErrorMessage = "Der er afsat 50 tegn til fornavn")]
public string FirstName { get; set; } = "";
[Required(ErrorMessage = "Efternavn skal udfyldes")]
[MaxLength(50, ErrorMessage = "Der er afsat 50 tegn til efternavn")]
public string LastName { get; set; } = "";
public bool LockoutEnabled { get; set; }
public string Passwd { get; set; } = "";
[Required(ErrorMessage = "Telefon nummer skal udfyldes")][MaxLength(20, ErrorMessage = "Der er afsat 20 tegn til telefon nummber")] public string PhoneNumber { get; set; } = "";
[Required(ErrorMessage = "Medarbejder ID skal udfyldes")][MaxLength(20, ErrorMessage = "Der er afsat 20 tegn til medarbejder ID")] public string SalesRep { get; set; } = "";
[MaxLength(20, ErrorMessage = "Der er afsat 20 tegn til telefon nummber")]
public string PhoneNumber { get; set; } = "";
[MaxLength(20, ErrorMessage = "Der er afsat 20 tegn til medarbejder ID")]
public string SalesRep { get; set; } = "";
public string UserId { get; set; } = "";
public List<UserRoleAssignment> AssignedRoles { get; set; } = new();
public List<SubjectAssignment> AssignedSubjects { get; set; } = new();
public List<SubjectAssignment> AssignedMembers { get; set; } = new();
}

View file

@ -23,48 +23,76 @@ public class WorkplaceDto
/// Workplace entity id
/// </summary>
public string WorkplaceId { get; set; } = "";
/// <summary>
/// Company name
/// </summary>
public string CompanyName { get; set; } = "";
/// <summary>
/// Workplace name
/// </summary>
[Required(ErrorMessage = "Navn skal angives")] [MaxLength(128, ErrorMessage = "Der kan højst anvendes 128 tegn")] public string Name { get; set; } = "";
[Required(ErrorMessage = "Navn skal angives")]
[MaxLength(128, ErrorMessage = "Der kan højst anvendes 128 tegn")]
public string Name { get; set; } = "";
/// <summary>
/// Workplace description
/// </summary>
[MaxLength(128, ErrorMessage = "Der kan højst anvendes 128 tegn")] public string Description { get; set; } = "";
[MaxLength(128, ErrorMessage = "Der kan højst anvendes 128 tegn")]
public string Description { get; set; } = "";
/// <summary>
/// Short url to document overview
/// </summary>
public string ShortUrl { get; set; } = "";
/// <summary>
/// Product storage location
/// </summary>
[Required(ErrorMessage = "Opbevaringssted skal angives")] [MaxLength(128, ErrorMessage = "Der kan højst anvendes 128 tegn")] public string ProductStorage { get; set; } = "";
[Required(ErrorMessage = "Opbevaringssted skal angives")]
[MaxLength(128, ErrorMessage = "Der kan højst anvendes 128 tegn")]
public string ProductStorage { get; set; } = "";
/// <summary>
/// Mask storage location
/// </summary>
[Required(ErrorMessage = "Opbevaringssted skal angives")] [MaxLength(128, ErrorMessage = "Der kan højst anvendes 128 tegn")] public string MaskStorage { get; set; } = "";
[Required(ErrorMessage = "Opbevaringssted skal angives")]
[MaxLength(128, ErrorMessage = "Der kan højst anvendes 128 tegn")]
public string MaskStorage { get; set; } = "";
/// <summary>
/// Gloves storage location
/// </summary>
[Required(ErrorMessage = "Opbevaringssted skal angives")] [MaxLength(128, ErrorMessage = "Der kan højst anvendes 128 tegn")] public string GlovesStorage { get; set; } = "";
[Required(ErrorMessage = "Opbevaringssted skal angives")]
[MaxLength(128, ErrorMessage = "Der kan højst anvendes 128 tegn")]
public string GlovesStorage { get; set; } = "";
/// <summary>
/// Goggles storage location
/// </summary>
[Required(ErrorMessage = "Opbevaringssted skal angives")] [MaxLength(128, ErrorMessage = "Der kan højst anvendes 128 tegn")] public string GogglesStorage { get; set; } = "";
[Required(ErrorMessage = "Opbevaringssted skal angives")]
[MaxLength(128, ErrorMessage = "Der kan højst anvendes 128 tegn")]
public string GogglesStorage { get; set; } = "";
/// <summary>
/// Eye cleaner storage location
/// </summary>
[Required(ErrorMessage = "Opbevaringssted skal angives")] [MaxLength(128, ErrorMessage = "Der kan højst anvendes 128 tegn")] public string EyeCleanerLocation { get; set; } = "";
[Required(ErrorMessage = "Opbevaringssted skal angives")]
[MaxLength(128, ErrorMessage = "Der kan højst anvendes 128 tegn")]
public string EyeCleanerLocation { get; set; } = "";
/// <summary>
/// First aid storage location
/// </summary>
[Required(ErrorMessage = "Opbevaringssted skal angives")] [MaxLength(128, ErrorMessage = "Der kan højst anvendes 128 tegn")] public string FirstAidStorage { get; set; } = "";
[Required(ErrorMessage = "Opbevaringssted skal angives")]
[MaxLength(128, ErrorMessage = "Der kan højst anvendes 128 tegn")]
public string FirstAidStorage { get; set; } = "";
/// <summary>
/// Waste deposit location
/// </summary>
[Required(ErrorMessage = "Opbevaringssted skal angives")] [MaxLength(128, ErrorMessage = "Der kan højst anvendes 128 tegn")] public string WasteDeposit { get; set; } = "";
[Required(ErrorMessage = "Opbevaringssted skal angives")]
[MaxLength(128, ErrorMessage = "Der kan højst anvendes 128 tegn")]
public string WasteDeposit { get; set; } = "";
}

View file

@ -1,6 +1,6 @@
namespace Wonky.Entity.Views;
public class UserAdvisorInfoView
public class UserInfoAdvisorView
{
public string CountryCode { get; set; } = "";
public string Description { get; set; } = "";

View file

@ -1,6 +1,6 @@
namespace Wonky.Entity.Views;
public class UserCustomerInfoView
public class UserInfoCustomerView
{
public string CompanyId { get; set; } = "";
public string ContactId { get; set; } = "";

View file

@ -0,0 +1,12 @@
using System.Diagnostics.Contracts;
namespace Wonky.Entity.Views;
public class WorkplaceInventory
{
public string WorkplaceId { get; set; } = "";
public string CompanyName { get; set; } = "";
public string WorkplaceName { get; set; } = "";
public string WorkplaceLink { get; set; } = "";
public List<WorkplaceProduct> Products { get; set; } = new();
}

View file

@ -0,0 +1,8 @@
namespace Wonky.Entity.Views;
public class WorkplaceProduct
{
public string TradingName { get; set; } = "";
public string ProductId { get; set; } = "";
public List<WorkplaceProductVariant> Variants { get; set; } = new();
}

View file

@ -0,0 +1,8 @@
namespace Wonky.Entity.Views;
public class WorkplaceProductVariant
{
public string VariantName { get; set; } = "";
public string VariantId { get; set; } = "";
public List<WorkplaceProductVariantDoc> Docs { get; set; } = new();
}

View file

@ -0,0 +1,10 @@
namespace Wonky.Entity.Views;
public class WorkplaceProductVariantDoc
{
public string DocumentId { get; set; } = "";
public string DocumentTypeEnum { get; set; } = "";
public string DocumentDescription { get; set; } = "";
public string DocumentDate { get; set; } = "";
public string DocumentLink { get; set; } = "";
}