toggle edit in customer view/edit page
This commit is contained in:
parent
1a0255a14a
commit
41eccd64bf
32 changed files with 1523 additions and 1483 deletions
|
@ -26,31 +26,30 @@ using Wonky.Entity.Views;
|
||||||
|
|
||||||
#pragma warning disable CS8618
|
#pragma warning disable CS8618
|
||||||
|
|
||||||
namespace Wonky.Client.Components
|
namespace Wonky.Client.Components;
|
||||||
|
|
||||||
|
public partial class AdvisorCustomerListComponent
|
||||||
{
|
{
|
||||||
public partial class AdvisorCustomerListComponent
|
[Parameter] public List<CompanyDto> CompanyList { get; set; } = new();
|
||||||
|
[Parameter] public EventCallback<string> OnDelete { get; set; }
|
||||||
|
[Parameter] public EventCallback<string> OnSelect { get; set; }
|
||||||
|
[Inject] public NavigationManager Navigator { get; set; }
|
||||||
|
[Inject] public IJSRuntime JsRuntime { get; set; }
|
||||||
|
|
||||||
|
private Lazy<IJSObjectReference> BsTooltip { get; set; } = new();
|
||||||
|
|
||||||
|
private InformationModal InformationModal { get; set; } = new();
|
||||||
|
private string InfoMessage { get; set; } = "";
|
||||||
|
private string CompanyId { get; set; } = "";
|
||||||
|
|
||||||
|
private void ViewCustomer(string companyId)
|
||||||
{
|
{
|
||||||
[Parameter] public List<CompanyDto> CompanyList { get; set; } = new();
|
Navigator.NavigateTo($"/advisor/customers/{companyId}");
|
||||||
[Parameter] public EventCallback<string> OnDelete { get; set; }
|
}
|
||||||
[Parameter] public EventCallback<string> OnSelect { get; set; }
|
|
||||||
[Inject] public NavigationManager Navigator { get; set; }
|
|
||||||
[Inject] public IJSRuntime JsRuntime { get; set; }
|
|
||||||
|
|
||||||
private Lazy<IJSObjectReference> BsTooltip { get; set; } = new();
|
private void CallInformationModal(string info)
|
||||||
|
{
|
||||||
private InformationModal InformationModal { get; set; } = new();
|
InfoMessage = info;
|
||||||
private string InfoMessage { get; set; } = "";
|
InformationModal.Show();
|
||||||
private string CompanyId { get; set; } = "";
|
}
|
||||||
|
}
|
||||||
private void ViewCustomer(string companyId)
|
|
||||||
{
|
|
||||||
Navigator.NavigateTo($"/advisor/customers/{companyId}");
|
|
||||||
}
|
|
||||||
|
|
||||||
private void CallInformationModal(string info)
|
|
||||||
{
|
|
||||||
InfoMessage = info;
|
|
||||||
InformationModal.Show();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -17,35 +17,34 @@ using System.Timers;
|
||||||
using Microsoft.AspNetCore.Components;
|
using Microsoft.AspNetCore.Components;
|
||||||
using Timer = System.Timers.Timer;
|
using Timer = System.Timers.Timer;
|
||||||
|
|
||||||
namespace Wonky.Client.Components
|
namespace Wonky.Client.Components;
|
||||||
|
|
||||||
|
public partial class CatalogSearchPhraseComponent
|
||||||
{
|
{
|
||||||
public partial class CatalogSearchPhraseComponent
|
private Timer Timer { get; set; } = new();
|
||||||
|
private string SearchTerm { get; set; } = "";
|
||||||
|
[Parameter] public EventCallback<string> OnChanged { get; set; }
|
||||||
|
|
||||||
|
private void ClearSearch()
|
||||||
{
|
{
|
||||||
private Timer Timer { get; set; } = new();
|
SearchTerm = "";
|
||||||
private string SearchTerm { get; set; } = "";
|
OnChanged.InvokeAsync("");
|
||||||
[Parameter] public EventCallback<string> OnChanged { get; set; }
|
}
|
||||||
|
|
||||||
private void ClearSearch()
|
|
||||||
{
|
|
||||||
SearchTerm = "";
|
|
||||||
OnChanged.InvokeAsync("");
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnSearchChanged()
|
private void OnSearchChanged()
|
||||||
{
|
{
|
||||||
Timer.Dispose();
|
Timer.Dispose();
|
||||||
Timer = new Timer(500);
|
Timer = new Timer(500);
|
||||||
Timer.AutoReset = false;
|
Timer.AutoReset = false;
|
||||||
Timer.Elapsed += OnTimerElapsed;
|
Timer.Elapsed += OnTimerElapsed;
|
||||||
Timer.Enabled = true;
|
Timer.Enabled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnTimerElapsed(object? sender, ElapsedEventArgs e)
|
private void OnTimerElapsed(object? sender, ElapsedEventArgs e)
|
||||||
{
|
{
|
||||||
OnChanged.InvokeAsync(SearchTerm);
|
OnChanged.InvokeAsync(SearchTerm);
|
||||||
Timer.Elapsed -= OnTimerElapsed;
|
Timer.Elapsed -= OnTimerElapsed;
|
||||||
Timer.Enabled = false;
|
Timer.Enabled = false;
|
||||||
Timer.Dispose();
|
Timer.Dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
|
@ -19,48 +19,47 @@ using Wonky.Client.Services;
|
||||||
using Timer = System.Timers.Timer;
|
using Timer = System.Timers.Timer;
|
||||||
#pragma warning disable CS8618
|
#pragma warning disable CS8618
|
||||||
|
|
||||||
namespace Wonky.Client.Components
|
namespace Wonky.Client.Components;
|
||||||
|
|
||||||
|
public partial class CustomerSearchPhraseComponent
|
||||||
{
|
{
|
||||||
public partial class CustomerSearchPhraseComponent
|
private Timer InputTimer { get; set; } = new();
|
||||||
|
private string SearchTerm { get; set; } = "";
|
||||||
|
private UserProfile Profiles { get; set; } = new ();
|
||||||
|
[Inject] public UserProfileService ProfileService { get; set; }
|
||||||
|
[Parameter] public EventCallback<string> OnChanged { get; set; }
|
||||||
|
|
||||||
|
protected override async Task OnInitializedAsync()
|
||||||
{
|
{
|
||||||
private Timer InputTimer { get; set; } = new();
|
Profiles = await ProfileService.GetProfile();
|
||||||
private string SearchTerm { get; set; } = "";
|
SearchTerm = string.IsNullOrWhiteSpace(Profiles.CompanyFilterPhrase) ? "" : Profiles.CompanyFilterPhrase.Trim();
|
||||||
private UserProfile Profiles { get; set; } = new ();
|
|
||||||
[Inject] public UserProfileService ProfileService { get; set; }
|
|
||||||
[Parameter] public EventCallback<string> OnChanged { get; set; }
|
|
||||||
|
|
||||||
protected override async Task OnInitializedAsync()
|
|
||||||
{
|
|
||||||
Profiles = await ProfileService.GetProfile();
|
|
||||||
SearchTerm = string.IsNullOrWhiteSpace(Profiles.CompanyFilterPhrase) ? "" : Profiles.CompanyFilterPhrase.Trim();
|
|
||||||
|
|
||||||
if(!string.IsNullOrWhiteSpace(SearchTerm))
|
if(!string.IsNullOrWhiteSpace(SearchTerm))
|
||||||
await OnChanged.InvokeAsync(SearchTerm);
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task ClearSearch()
|
|
||||||
{
|
|
||||||
InputTimer.Dispose();
|
|
||||||
SearchTerm = "";
|
|
||||||
await ProfileService.SetCompanyFilterPhrase(SearchTerm.Trim());
|
|
||||||
await OnChanged.InvokeAsync(SearchTerm);
|
await OnChanged.InvokeAsync(SearchTerm);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task OnSearchChanged()
|
|
||||||
{
|
|
||||||
await ProfileService.SetCompanyFilterPhrase(SearchTerm.Trim());
|
|
||||||
InputTimer.Dispose();
|
|
||||||
InputTimer = new Timer(500);
|
|
||||||
InputTimer.AutoReset = false;
|
|
||||||
InputTimer.Elapsed += OnTimerElapsed;
|
|
||||||
InputTimer.Enabled = true;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnTimerElapsed(object? sender, ElapsedEventArgs e)
|
private async Task ClearSearch()
|
||||||
{
|
{
|
||||||
InputTimer.Dispose();
|
InputTimer.Dispose();
|
||||||
OnChanged.InvokeAsync(SearchTerm);
|
SearchTerm = "";
|
||||||
}
|
await ProfileService.SetCompanyFilterPhrase(SearchTerm.Trim());
|
||||||
}
|
await OnChanged.InvokeAsync(SearchTerm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task OnSearchChanged()
|
||||||
|
{
|
||||||
|
await ProfileService.SetCompanyFilterPhrase(SearchTerm.Trim());
|
||||||
|
InputTimer.Dispose();
|
||||||
|
InputTimer = new Timer(500);
|
||||||
|
InputTimer.AutoReset = false;
|
||||||
|
InputTimer.Elapsed += OnTimerElapsed;
|
||||||
|
InputTimer.Enabled = true;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnTimerElapsed(object? sender, ElapsedEventArgs e)
|
||||||
|
{
|
||||||
|
InputTimer.Dispose();
|
||||||
|
OnChanged.InvokeAsync(SearchTerm);
|
||||||
|
}
|
||||||
|
}
|
|
@ -20,38 +20,36 @@ using Microsoft.AspNetCore.Components;
|
||||||
using Wonky.Client.Services;
|
using Wonky.Client.Services;
|
||||||
#pragma warning disable CS8618
|
#pragma warning disable CS8618
|
||||||
|
|
||||||
namespace Wonky.Client.Components
|
namespace Wonky.Client.Components;
|
||||||
{
|
|
||||||
public partial class CustomerSortComponent : IDisposable
|
|
||||||
{
|
|
||||||
[Inject] public ILocalStorageService Storage { get; set; }
|
|
||||||
[Inject] public UserProfileService ProfileService { get; set; }
|
|
||||||
[Parameter] public EventCallback<string> OnChanged { get; set; }
|
|
||||||
private Dictionary<string, string> Items { get; set; } = new();
|
|
||||||
private UserProfile _profiles = new();
|
|
||||||
private string SortCol { get; set; } = "name";
|
|
||||||
protected override async Task OnInitializedAsync()
|
|
||||||
{
|
|
||||||
ProfileService.OnChange += ProfileServiceOnOnChange;
|
|
||||||
_profiles = await ProfileService.GetProfile();
|
|
||||||
SortCol = _profiles.CompanySort;
|
|
||||||
}
|
|
||||||
private async Task OnSelectionChanged(ChangeEventArgs e)
|
|
||||||
{
|
|
||||||
var val = e.Value.ToString();
|
|
||||||
if (val == "-1") return;
|
|
||||||
await OnChanged.InvokeAsync(val);
|
|
||||||
await ProfileService.SetCompanySort(val);
|
|
||||||
}
|
|
||||||
private void ProfileServiceOnOnChange(UserProfile newUserProfile)
|
|
||||||
{
|
|
||||||
_profiles = newUserProfile;
|
|
||||||
StateHasChanged();
|
|
||||||
}
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
ProfileService.OnChange -= ProfileServiceOnOnChange;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
public partial class CustomerSortComponent : IDisposable
|
||||||
|
{
|
||||||
|
[Inject] public ILocalStorageService Storage { get; set; }
|
||||||
|
[Inject] public UserProfileService ProfileService { get; set; }
|
||||||
|
[Parameter] public EventCallback<string> OnChanged { get; set; }
|
||||||
|
private Dictionary<string, string> Items { get; set; } = new();
|
||||||
|
private UserProfile _profiles = new();
|
||||||
|
private string SortCol { get; set; } = "name";
|
||||||
|
protected override async Task OnInitializedAsync()
|
||||||
|
{
|
||||||
|
ProfileService.OnChange += ProfileServiceOnOnChange;
|
||||||
|
_profiles = await ProfileService.GetProfile();
|
||||||
|
SortCol = _profiles.CompanySort;
|
||||||
|
}
|
||||||
|
private async Task OnSelectionChanged(ChangeEventArgs e)
|
||||||
|
{
|
||||||
|
var val = e.Value.ToString();
|
||||||
|
if (val == "-1") return;
|
||||||
|
await OnChanged.InvokeAsync(val);
|
||||||
|
await ProfileService.SetCompanySort(val);
|
||||||
|
}
|
||||||
|
private void ProfileServiceOnOnChange(UserProfile newUserProfile)
|
||||||
|
{
|
||||||
|
_profiles = newUserProfile;
|
||||||
|
StateHasChanged();
|
||||||
|
}
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
ProfileService.OnChange -= ProfileServiceOnOnChange;
|
||||||
|
}
|
||||||
|
}
|
|
@ -27,77 +27,76 @@ using Utils = Wonky.Client.Helpers.Utils;
|
||||||
|
|
||||||
#pragma warning disable CS8618
|
#pragma warning disable CS8618
|
||||||
|
|
||||||
namespace Wonky.Client.Components
|
namespace Wonky.Client.Components;
|
||||||
|
|
||||||
|
public partial class OfficeCountryCustomerListComponent
|
||||||
{
|
{
|
||||||
public partial class OfficeCountryCustomerListComponent
|
// ******************************************************
|
||||||
|
// parameters
|
||||||
|
[Parameter] public string CountryCode { get; set; } = "";
|
||||||
|
[Parameter] public List<CompanyDto> CompanyList { get; set; } = new();
|
||||||
|
// [Parameter] public EventCallback<DraftItem> OnOrderItem { get; set; }
|
||||||
|
[CascadingParameter] public DraftStateProvider DraftProvider { get; set; }
|
||||||
|
|
||||||
|
// ******************************************************
|
||||||
|
// injects
|
||||||
|
[Inject] public ICountryCustomerHistoryRepository HistoryRepo { get; set; }
|
||||||
|
[Inject] public ICountryActivityRepository ActivityRepo { get; set; }
|
||||||
|
|
||||||
|
// ******************************************************
|
||||||
|
// overlays
|
||||||
|
private OfficeCustomerInvoiceListOverlay InvoiceListOverlay { get; set; } = new();
|
||||||
|
private OfficeCustomerActivityListOverlay ActivityListOverlay { get; set; } = new();
|
||||||
|
private OfficeCustomerProductListOverlay ProductListOverlay { get; set; } = new();
|
||||||
|
|
||||||
|
// ******************************************************
|
||||||
|
// variables
|
||||||
|
private InvoiceListView InvoiceList { get; set; } = new();
|
||||||
|
private List<ReportItemView> ActivityList { get; set; } = new();
|
||||||
|
private List<ProductInventoryView> ProductList { get; set; } = new();
|
||||||
|
private CompanyDto SelectedCompany { get; set; } = new();
|
||||||
|
|
||||||
|
// ******************************************************
|
||||||
|
// functions
|
||||||
|
private async Task ShowInvoiceList(string companyId)
|
||||||
{
|
{
|
||||||
// ******************************************************
|
// check for console manipulation
|
||||||
// parameters
|
if (!Utils.Validate(VType.Id, companyId)) return;
|
||||||
[Parameter] public string CountryCode { get; set; } = "";
|
SelectedCompany = CompanyList.First(x => x.CompanyId == companyId);
|
||||||
[Parameter] public List<CompanyDto> CompanyList { get; set; } = new();
|
// call erp to crm sync before requesting invoices
|
||||||
// [Parameter] public EventCallback<DraftItem> OnOrderItem { get; set; }
|
var newSyncDate = await HistoryRepo.RequestErpToCrmSync(CountryCode, companyId, SelectedCompany.HistorySync);
|
||||||
[CascadingParameter] public DraftStateProvider DraftProvider { get; set; }
|
await Task.Delay(500);
|
||||||
|
InvoiceList = await HistoryRepo.RequestInvoiceList(CountryCode, companyId);
|
||||||
// ******************************************************
|
if(!string.IsNullOrWhiteSpace(newSyncDate)) SelectedCompany.HistorySync = newSyncDate;
|
||||||
// injects
|
InvoiceListOverlay.Show();
|
||||||
[Inject] public ICountryCustomerHistoryRepository HistoryRepo { get; set; }
|
}
|
||||||
[Inject] public ICountryActivityRepository ActivityRepo { get; set; }
|
|
||||||
|
|
||||||
// ******************************************************
|
|
||||||
// overlays
|
|
||||||
private OfficeCustomerInvoiceListOverlay InvoiceListOverlay { get; set; } = new();
|
|
||||||
private OfficeCustomerActivityListOverlay ActivityListOverlay { get; set; } = new();
|
|
||||||
private OfficeCustomerProductListOverlay ProductListOverlay { get; set; } = new();
|
|
||||||
|
|
||||||
// ******************************************************
|
|
||||||
// variables
|
|
||||||
private InvoiceListView InvoiceList { get; set; } = new();
|
|
||||||
private List<ReportItemView> ActivityList { get; set; } = new();
|
|
||||||
private List<ProductInventoryView> ProductList { get; set; } = new();
|
|
||||||
private CompanyDto SelectedCompany { get; set; } = new();
|
|
||||||
|
|
||||||
// ******************************************************
|
private async Task ShowActivityList(string companyId)
|
||||||
// functions
|
{
|
||||||
private async Task ShowInvoiceList(string companyId)
|
// check for console manipulation
|
||||||
{
|
if (!Utils.Validate(VType.Id, companyId)) return;
|
||||||
// check for console manipulation
|
SelectedCompany = CompanyList.First(x => x.CompanyId == companyId);
|
||||||
if (!Utils.Validate(VType.Id, companyId)) return;
|
ActivityList = await ActivityRepo.RequestActivityList(companyId);
|
||||||
SelectedCompany = CompanyList.First(x => x.CompanyId == companyId);
|
ActivityListOverlay.Show();
|
||||||
// call erp to crm sync before requesting invoices
|
}
|
||||||
var newSyncDate = await HistoryRepo.RequestErpToCrmSync(CountryCode, companyId, SelectedCompany.HistorySync);
|
|
||||||
await Task.Delay(500);
|
|
||||||
InvoiceList = await HistoryRepo.RequestInvoiceList(CountryCode, companyId);
|
|
||||||
if(!string.IsNullOrWhiteSpace(newSyncDate)) SelectedCompany.HistorySync = newSyncDate;
|
|
||||||
InvoiceListOverlay.Show();
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task ShowActivityList(string companyId)
|
private async Task ShowInventory(string companyId)
|
||||||
{
|
{
|
||||||
// check for console manipulation
|
// check for console manipulation
|
||||||
if (!Utils.Validate(VType.Id, companyId)) return;
|
if (!Utils.Validate(VType.Id, companyId)) return;
|
||||||
SelectedCompany = CompanyList.First(x => x.CompanyId == companyId);
|
SelectedCompany = CompanyList.First(x => x.CompanyId == companyId);
|
||||||
ActivityList = await ActivityRepo.RequestActivityList(companyId);
|
// call erp to crm sync before requesting products
|
||||||
ActivityListOverlay.Show();
|
var newSyncDate = await HistoryRepo.RequestErpToCrmSync(CountryCode, companyId, SelectedCompany.HistorySync);
|
||||||
}
|
await Task.Delay(500);
|
||||||
|
if(!string.IsNullOrWhiteSpace(newSyncDate)) SelectedCompany.HistorySync = newSyncDate;
|
||||||
|
ProductList = await HistoryRepo.RequestInventory(SelectedCompany.CountryCode, SelectedCompany.CompanyId);
|
||||||
|
ProductListOverlay.Show();
|
||||||
|
}
|
||||||
|
|
||||||
private async Task ShowInventory(string companyId)
|
private async Task ShowOrder(string companyId)
|
||||||
{
|
{
|
||||||
// check for console manipulation
|
// check for console manipulation
|
||||||
if (!Utils.Validate(VType.Id, companyId)) return;
|
if (!Utils.Validate(VType.Id, companyId)) return;
|
||||||
SelectedCompany = CompanyList.First(x => x.CompanyId == companyId);
|
SelectedCompany = CompanyList.First(x => x.CompanyId == companyId);
|
||||||
// call erp to crm sync before requesting products
|
|
||||||
var newSyncDate = await HistoryRepo.RequestErpToCrmSync(CountryCode, companyId, SelectedCompany.HistorySync);
|
|
||||||
await Task.Delay(500);
|
|
||||||
if(!string.IsNullOrWhiteSpace(newSyncDate)) SelectedCompany.HistorySync = newSyncDate;
|
|
||||||
ProductList = await HistoryRepo.RequestInventory(SelectedCompany.CountryCode, SelectedCompany.CompanyId);
|
|
||||||
ProductListOverlay.Show();
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task ShowOrder(string companyId)
|
|
||||||
{
|
|
||||||
// check for console manipulation
|
|
||||||
if (!Utils.Validate(VType.Id, companyId)) return;
|
|
||||||
SelectedCompany = CompanyList.First(x => x.CompanyId == companyId);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -20,41 +20,42 @@ using Microsoft.AspNetCore.Components;
|
||||||
using Wonky.Client.Services;
|
using Wonky.Client.Services;
|
||||||
#pragma warning disable CS8618
|
#pragma warning disable CS8618
|
||||||
|
|
||||||
namespace Wonky.Client.Components
|
namespace Wonky.Client.Components;
|
||||||
|
|
||||||
|
public partial class PageSizeComponent : IDisposable
|
||||||
{
|
{
|
||||||
public partial class PageSizeComponent : IDisposable
|
[Inject] public ILocalStorageService Storage { get; set; }
|
||||||
|
[Inject] public UserProfileService ProfileService { get; set; }
|
||||||
|
[Parameter] public EventCallback<string> OnChanged { get; set; }
|
||||||
|
private Dictionary<string, string> Items { get; set; } = new();
|
||||||
|
private UserProfile Profile { get; set; } = new();
|
||||||
|
private string PageSize { get; set; }
|
||||||
|
|
||||||
|
protected override async Task OnInitializedAsync()
|
||||||
{
|
{
|
||||||
[Inject] public ILocalStorageService Storage { get; set; }
|
ProfileService.OnChange += ProfileServiceOnOnChange;
|
||||||
[Inject] public UserProfileService ProfileService { get; set; }
|
Profile = await ProfileService.GetProfile();
|
||||||
[Parameter] public EventCallback<string> OnChanged { get; set; }
|
PageSize = Profile.PageSize;
|
||||||
private Dictionary<string, string> Items { get; set; } = new();
|
|
||||||
private UserProfile _profiles = new();
|
|
||||||
private string PageSize { get; set; } = "";
|
|
||||||
|
|
||||||
protected override async Task OnInitializedAsync()
|
|
||||||
{
|
|
||||||
ProfileService.OnChange += ProfileServiceOnOnChange;
|
|
||||||
_profiles = await ProfileService.GetProfile();
|
|
||||||
PageSize = _profiles.PageSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task OnSelectChanged(ChangeEventArgs e)
|
|
||||||
{
|
|
||||||
var val = e.Value.ToString();
|
|
||||||
if (val == "-1") return;
|
|
||||||
await OnChanged.InvokeAsync(val);
|
|
||||||
await ProfileService.SetPageSize(val);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ProfileServiceOnOnChange(UserProfile newUserProfile)
|
|
||||||
{
|
|
||||||
_profiles = newUserProfile;
|
|
||||||
StateHasChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
ProfileService.OnChange -= ProfileServiceOnOnChange;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
private async Task OnSelectChanged(ChangeEventArgs e)
|
||||||
|
{
|
||||||
|
var val = e.Value?.ToString();
|
||||||
|
if (val == "-1") return;
|
||||||
|
var cVal = Convert.ToInt32(val);
|
||||||
|
if (cVal > 50) val = "50"; // mitigate variable manipulation
|
||||||
|
await OnChanged.InvokeAsync(val);
|
||||||
|
await ProfileService.SetPageSize(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ProfileServiceOnOnChange(UserProfile newUserProfile)
|
||||||
|
{
|
||||||
|
Profile = newUserProfile;
|
||||||
|
StateHasChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
ProfileService.OnChange -= ProfileServiceOnOnChange;
|
||||||
|
}
|
||||||
|
}
|
|
@ -19,44 +19,43 @@ using Microsoft.AspNetCore.Components;
|
||||||
using Wonky.Client.Features;
|
using Wonky.Client.Features;
|
||||||
using Wonky.Entity.Requests;
|
using Wonky.Entity.Requests;
|
||||||
|
|
||||||
namespace Wonky.Client.Components
|
namespace Wonky.Client.Components;
|
||||||
|
|
||||||
|
public partial class PaginationComponent
|
||||||
{
|
{
|
||||||
public partial class PaginationComponent
|
[Parameter] public MetaData MetaData { get; set; } = new();
|
||||||
|
[Parameter] public int Spread { get; set; }
|
||||||
|
[Parameter] public EventCallback<int> SelectedPage { get; set; }
|
||||||
|
private List<PagingLink> Links { get; set; } = new();
|
||||||
|
|
||||||
|
protected override void OnParametersSet()
|
||||||
{
|
{
|
||||||
[Parameter] public MetaData MetaData { get; set; } = new();
|
CreatePaginationLinks();
|
||||||
[Parameter] public int Spread { get; set; }
|
}
|
||||||
[Parameter] public EventCallback<int> SelectedPage { get; set; }
|
|
||||||
private List<PagingLink> Links { get; set; } = new();
|
|
||||||
|
|
||||||
protected override void OnParametersSet()
|
private void CreatePaginationLinks()
|
||||||
|
{
|
||||||
|
Links = new List<PagingLink>
|
||||||
{
|
{
|
||||||
CreatePaginationLinks();
|
new(MetaData.CurrentPage - 1, MetaData.HasPrevious, "Forrige")
|
||||||
}
|
};
|
||||||
|
|
||||||
private void CreatePaginationLinks()
|
for (var i = 1; i <= MetaData.TotalPages; i++)
|
||||||
{
|
{
|
||||||
Links = new List<PagingLink>
|
if (i >= MetaData.CurrentPage - Spread && i <= MetaData.CurrentPage + Spread)
|
||||||
{
|
{
|
||||||
new(MetaData.CurrentPage - 1, MetaData.HasPrevious, "Forrige")
|
Links.Add(new PagingLink(i, true, i.ToString()) {Active = MetaData.CurrentPage == i});
|
||||||
};
|
|
||||||
|
|
||||||
for (var i = 1; i <= MetaData.TotalPages; i++)
|
|
||||||
{
|
|
||||||
if (i >= MetaData.CurrentPage - Spread && i <= MetaData.CurrentPage + Spread)
|
|
||||||
{
|
|
||||||
Links.Add(new PagingLink(i, true, i.ToString()) {Active = MetaData.CurrentPage == i});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Links.Add(new PagingLink(MetaData.CurrentPage + 1, MetaData.HasNext, "Næste"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task OnSelectedPage(PagingLink link)
|
Links.Add(new PagingLink(MetaData.CurrentPage + 1, MetaData.HasNext, "Næste"));
|
||||||
{
|
}
|
||||||
if (link.Page == MetaData.CurrentPage || !link.Enabled)
|
|
||||||
return;
|
private async Task OnSelectedPage(PagingLink link)
|
||||||
MetaData.CurrentPage = link.Page;
|
{
|
||||||
await SelectedPage.InvokeAsync(link.Page);
|
if (link.Page == MetaData.CurrentPage || !link.Enabled)
|
||||||
}
|
return;
|
||||||
|
MetaData.CurrentPage = link.Page;
|
||||||
|
await SelectedPage.InvokeAsync(link.Page);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -21,57 +21,56 @@ using Wonky.Client.HttpRepository;
|
||||||
using Wonky.Client.Shared;
|
using Wonky.Client.Shared;
|
||||||
using Wonky.Entity.DTO;
|
using Wonky.Entity.DTO;
|
||||||
|
|
||||||
namespace Wonky.Client.Components
|
namespace Wonky.Client.Components;
|
||||||
|
|
||||||
|
public partial class TaskItemTableComponent
|
||||||
{
|
{
|
||||||
public partial class TaskItemTableComponent
|
[Parameter] public List<TaskItemDto> TaskItemList { get; set; } = new();
|
||||||
|
[Parameter] public EventCallback<string> OnDeleteTask { get; set; }
|
||||||
|
[Parameter] public EventCallback<string> OnCompleteTask { get; set; }
|
||||||
|
[Parameter] public EventCallback<string> OnTaskCompleted { get; set; }
|
||||||
|
|
||||||
|
private ConfirmationModal _confirmationModal = new ();
|
||||||
|
private string _taskItemIdToDelete = "";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Complete task callback
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="taskItemId"></param>
|
||||||
|
private async Task CompleteTask(string taskItemId)
|
||||||
{
|
{
|
||||||
[Parameter] public List<TaskItemDto> TaskItemList { get; set; } = new();
|
await OnCompleteTask.InvokeAsync(taskItemId);
|
||||||
[Parameter] public EventCallback<string> OnDeleteTask { get; set; }
|
}
|
||||||
[Parameter] public EventCallback<string> OnCompleteTask { get; set; }
|
|
||||||
[Parameter] public EventCallback<string> OnTaskCompleted { get; set; }
|
|
||||||
|
|
||||||
private ConfirmationModal _confirmationModal = new ();
|
/// <summary>
|
||||||
private string _taskItemIdToDelete = "";
|
/// Task completed callback
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="taskItemId"></param>
|
||||||
|
private async Task TaskCompleted(string taskItemId)
|
||||||
|
{
|
||||||
|
await OnTaskCompleted.InvokeAsync(taskItemId);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Complete task callback
|
/// Confirm delete
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="taskItemId"></param>
|
/// <param name="taskItemId"></param>
|
||||||
private async Task CompleteTask(string taskItemId)
|
private void CallConfirmationModal(string taskItemId)
|
||||||
{
|
{
|
||||||
await OnCompleteTask.InvokeAsync(taskItemId);
|
_taskItemIdToDelete = taskItemId;
|
||||||
}
|
_confirmationModal.Show();
|
||||||
|
}
|
||||||
/// <summary>
|
|
||||||
/// Task completed callback
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="taskItemId"></param>
|
|
||||||
private async Task TaskCompleted(string taskItemId)
|
|
||||||
{
|
|
||||||
await OnTaskCompleted.InvokeAsync(taskItemId);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Confirm delete
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="taskItemId"></param>
|
|
||||||
private void CallConfirmationModal(string taskItemId)
|
|
||||||
{
|
|
||||||
_taskItemIdToDelete = taskItemId;
|
|
||||||
_confirmationModal.Show();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnCancelCallback()
|
private void OnCancelCallback()
|
||||||
{
|
{
|
||||||
_confirmationModal.Hide();
|
_confirmationModal.Hide();
|
||||||
}
|
}
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Delete task call back
|
/// Delete task call back
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private async Task DeleteTask()
|
private async Task DeleteTask()
|
||||||
{
|
{
|
||||||
_confirmationModal.Hide();
|
_confirmationModal.Hide();
|
||||||
await OnDeleteTask.InvokeAsync(_taskItemIdToDelete);
|
await OnDeleteTask.InvokeAsync(_taskItemIdToDelete);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
|
@ -15,6 +15,7 @@
|
||||||
|
|
||||||
|
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
|
using System.Text.Json;
|
||||||
using Blazored.LocalStorage;
|
using Blazored.LocalStorage;
|
||||||
using Microsoft.AspNetCore.Components;
|
using Microsoft.AspNetCore.Components;
|
||||||
using Microsoft.AspNetCore.Components.Forms;
|
using Microsoft.AspNetCore.Components.Forms;
|
||||||
|
@ -69,8 +70,8 @@ public partial class WorkDateComponent : IDisposable
|
||||||
/// <param name="e"></param>
|
/// <param name="e"></param>
|
||||||
private async Task OnDateChanged(ChangeEventArgs e)
|
private async Task OnDateChanged(ChangeEventArgs e)
|
||||||
{
|
{
|
||||||
var x = DateTime.TryParse(e.Value.ToString(), out var setDate);
|
if (string.IsNullOrWhiteSpace(e.Value.ToString())) return;
|
||||||
if (x)
|
if (DateTime.TryParse(e.Value.ToString(), out var setDate))
|
||||||
{
|
{
|
||||||
await UserProfile.SetWorkDate(setDate);
|
await UserProfile.SetWorkDate(setDate);
|
||||||
await OnChangedCallback.InvokeAsync($"{setDate:yyyy-MM-dd}");
|
await OnChangedCallback.InvokeAsync($"{setDate:yyyy-MM-dd}");
|
||||||
|
|
|
@ -26,337 +26,336 @@
|
||||||
|
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
|
||||||
namespace Wonky.Client.Helpers
|
namespace Wonky.Client.Helpers;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Squid is guid string shortened and url safe
|
||||||
|
/// </summary>
|
||||||
|
[DebuggerDisplay("{" + nameof(Value) + "}")]
|
||||||
|
public readonly struct Squid : IEquatable<Squid>
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Squid is guid string shortened and url safe
|
/// Return Empty value
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[DebuggerDisplay("{" + nameof(Value) + "}")]
|
// ReSharper disable once MemberCanBePrivate.Global
|
||||||
public readonly struct Squid : IEquatable<Squid>
|
public static readonly Squid Empty = new(Guid.Empty);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Decode Squid to Guid
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value"></param>
|
||||||
|
public Squid(string value)
|
||||||
{
|
{
|
||||||
/// <summary>
|
Value = value;
|
||||||
/// Return Empty value
|
Guid = DecodeSquid(value);
|
||||||
/// </summary>
|
}
|
||||||
// ReSharper disable once MemberCanBePrivate.Global
|
|
||||||
public static readonly Squid Empty = new(Guid.Empty);
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Decode Squid to Guid
|
/// Generate Squid from Guid object
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="value"></param>
|
/// <param name="obj"></param>
|
||||||
public Squid(string value)
|
public Squid(Guid obj)
|
||||||
|
{
|
||||||
|
Value = EncodeGuid(obj);
|
||||||
|
Guid = obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Guid
|
||||||
|
/// </summary>
|
||||||
|
// ReSharper disable once MemberCanBePrivate.Global
|
||||||
|
public Guid Guid { get; }
|
||||||
|
|
||||||
|
public string Value { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// ToString() function
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Equality
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="obj"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public override bool Equals(object? obj)
|
||||||
|
{
|
||||||
|
return obj is Squid other && Equals(other);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// EQuality
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="obj"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public bool Equals(Squid obj)
|
||||||
|
{
|
||||||
|
return Guid.Equals(obj.Guid) && Value == obj.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get hashcode
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
public override int GetHashCode()
|
||||||
|
{
|
||||||
|
unchecked
|
||||||
{
|
{
|
||||||
Value = value;
|
return (Guid.GetHashCode() * 397) ^ (Value != null ? Value.GetHashCode() : 0);
|
||||||
Guid = DecodeSquid(value);
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Generate Squid from Guid object
|
/// Create Squid from new Guid
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="obj"></param>
|
/// <returns></returns>
|
||||||
public Squid(Guid obj)
|
public static Squid NewGuid()
|
||||||
|
{
|
||||||
|
return new Squid(Guid.NewGuid());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Encode string
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static string EncodeString(string value)
|
||||||
|
{
|
||||||
|
var guid = new Guid(value);
|
||||||
|
return EncodeGuid(guid);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Encode Guid
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="obj"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
// ReSharper disable once MemberCanBePrivate.Global
|
||||||
|
public static string EncodeGuid(Guid obj)
|
||||||
|
{
|
||||||
|
var encoded = Convert.ToBase64String(obj.ToByteArray());
|
||||||
|
encoded = encoded
|
||||||
|
.Replace("/", "_")
|
||||||
|
.Replace("+", "-");
|
||||||
|
return encoded.Substring(0, 22);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Decode Squid
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
// ReSharper disable once MemberCanBePrivate.Global
|
||||||
|
public static Guid DecodeSquid(string value)
|
||||||
|
{
|
||||||
|
if (!value.Any()) return Empty;
|
||||||
|
value = value
|
||||||
|
.Replace("_", "/")
|
||||||
|
.Replace("-", "+");
|
||||||
|
var blob = Convert.FromBase64String(value + "==");
|
||||||
|
return new Guid(blob);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Guid From Squid
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="obj"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static Guid FromSquid(Squid obj)
|
||||||
|
{
|
||||||
|
return obj.Guid;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Squid From String
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static Squid FromString(string value)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(value))
|
||||||
|
return Empty;
|
||||||
|
return TryParse(value, out Squid obj) ? obj : Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// TryDecode
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value"></param>
|
||||||
|
/// <param name="obj"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
// ReSharper disable once MemberCanBePrivate.Global
|
||||||
|
public static bool TryDecode(string value, out Guid obj)
|
||||||
|
{
|
||||||
|
try
|
||||||
{
|
{
|
||||||
Value = EncodeGuid(obj);
|
// Decode as Squid
|
||||||
Guid = obj;
|
obj = DecodeSquid(value);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
catch (Exception)
|
||||||
/// <summary>
|
|
||||||
/// Guid
|
|
||||||
/// </summary>
|
|
||||||
// ReSharper disable once MemberCanBePrivate.Global
|
|
||||||
public Guid Guid { get; }
|
|
||||||
|
|
||||||
public string Value { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// ToString() function
|
|
||||||
/// </summary>
|
|
||||||
/// <returns></returns>
|
|
||||||
public override string ToString()
|
|
||||||
{
|
{
|
||||||
return Value;
|
// Return empty Guid
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Equality
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="obj"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public override bool Equals(object? obj)
|
|
||||||
{
|
|
||||||
return obj is Squid other && Equals(other);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// EQuality
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="obj"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public bool Equals(Squid obj)
|
|
||||||
{
|
|
||||||
return Guid.Equals(obj.Guid) && Value == obj.Value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Get hashcode
|
|
||||||
/// </summary>
|
|
||||||
/// <returns></returns>
|
|
||||||
public override int GetHashCode()
|
|
||||||
{
|
|
||||||
unchecked
|
|
||||||
{
|
|
||||||
return (Guid.GetHashCode() * 397) ^ (Value != null ? Value.GetHashCode() : 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Create Squid from new Guid
|
|
||||||
/// </summary>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static Squid NewGuid()
|
|
||||||
{
|
|
||||||
return new Squid(Guid.NewGuid());
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Encode string
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="value"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static string EncodeString(string value)
|
|
||||||
{
|
|
||||||
var guid = new Guid(value);
|
|
||||||
return EncodeGuid(guid);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Encode Guid
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="obj"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
// ReSharper disable once MemberCanBePrivate.Global
|
|
||||||
public static string EncodeGuid(Guid obj)
|
|
||||||
{
|
|
||||||
var encoded = Convert.ToBase64String(obj.ToByteArray());
|
|
||||||
encoded = encoded
|
|
||||||
.Replace("/", "_")
|
|
||||||
.Replace("+", "-");
|
|
||||||
return encoded.Substring(0, 22);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Decode Squid
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="value"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
// ReSharper disable once MemberCanBePrivate.Global
|
|
||||||
public static Guid DecodeSquid(string value)
|
|
||||||
{
|
|
||||||
if (!value.Any()) return Empty;
|
|
||||||
value = value
|
|
||||||
.Replace("_", "/")
|
|
||||||
.Replace("-", "+");
|
|
||||||
var blob = Convert.FromBase64String(value + "==");
|
|
||||||
return new Guid(blob);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Guid From Squid
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="obj"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static Guid FromSquid(Squid obj)
|
|
||||||
{
|
|
||||||
return obj.Guid;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Squid From String
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="value"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static Squid FromString(string value)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrEmpty(value))
|
|
||||||
return Empty;
|
|
||||||
return TryParse(value, out Squid obj) ? obj : Empty;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// TryDecode
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="value"></param>
|
|
||||||
/// <param name="obj"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
// ReSharper disable once MemberCanBePrivate.Global
|
|
||||||
public static bool TryDecode(string value, out Guid obj)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// Decode as Squid
|
|
||||||
obj = DecodeSquid(value);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
catch (Exception)
|
|
||||||
{
|
|
||||||
// Return empty Guid
|
|
||||||
obj = Guid.Empty;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// TryParse
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="value"></param>
|
|
||||||
/// <param name="obj"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
// ReSharper disable once MemberCanBePrivate.Global
|
|
||||||
public static bool TryParse(string value, out Squid obj)
|
|
||||||
{
|
|
||||||
// Parse as Squid string.
|
|
||||||
if (TryDecode(value, out var oGuid))
|
|
||||||
{
|
|
||||||
obj = oGuid;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse as Guid string.
|
|
||||||
if (Guid.TryParse(value, out oGuid))
|
|
||||||
{
|
|
||||||
obj = oGuid;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
obj = Empty;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// TryParse
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="value"></param>
|
|
||||||
/// <param name="obj"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static bool TryParse(string value, out Guid obj)
|
|
||||||
{
|
|
||||||
// Try a Squid string.
|
|
||||||
if (TryDecode(value, out obj))
|
|
||||||
return true;
|
|
||||||
// Try a Guid string.
|
|
||||||
if (Guid.TryParse(value, out obj))
|
|
||||||
return true;
|
|
||||||
obj = Guid.Empty;
|
obj = Guid.Empty;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Operator
|
/// TryParse
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="x"></param>
|
/// <param name="value"></param>
|
||||||
/// <param name="y"></param>
|
/// <param name="obj"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static bool operator ==(Squid x, Squid y)
|
// ReSharper disable once MemberCanBePrivate.Global
|
||||||
|
public static bool TryParse(string value, out Squid obj)
|
||||||
|
{
|
||||||
|
// Parse as Squid string.
|
||||||
|
if (TryDecode(value, out var oGuid))
|
||||||
{
|
{
|
||||||
return x.Guid == y.Guid;
|
obj = oGuid;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
// Parse as Guid string.
|
||||||
/// Operator
|
if (Guid.TryParse(value, out oGuid))
|
||||||
/// </summary>
|
|
||||||
/// <param name="x"></param>
|
|
||||||
/// <param name="y"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static bool operator ==(Squid x, Guid y)
|
|
||||||
{
|
{
|
||||||
return x.Guid == y;
|
obj = oGuid;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
obj = Empty;
|
||||||
/// Operator
|
return false;
|
||||||
/// </summary>
|
}
|
||||||
/// <param name="x"></param>
|
|
||||||
/// <param name="y"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static bool operator ==(Guid x, Squid y)
|
|
||||||
{
|
|
||||||
return y == x; // NB: order of arguments
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Operator
|
/// TryParse
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="x"></param>
|
/// <param name="value"></param>
|
||||||
/// <param name="y"></param>
|
/// <param name="obj"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static bool operator !=(Squid x, Squid y)
|
public static bool TryParse(string value, out Guid obj)
|
||||||
{
|
{
|
||||||
return !(x == y);
|
// Try a Squid string.
|
||||||
}
|
if (TryDecode(value, out obj))
|
||||||
|
return true;
|
||||||
|
// Try a Guid string.
|
||||||
|
if (Guid.TryParse(value, out obj))
|
||||||
|
return true;
|
||||||
|
obj = Guid.Empty;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Operator
|
/// Operator
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="x"></param>
|
/// <param name="x"></param>
|
||||||
/// <param name="y"></param>
|
/// <param name="y"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static bool operator !=(Squid x, Guid y)
|
public static bool operator ==(Squid x, Squid y)
|
||||||
{
|
{
|
||||||
return !(x == y);
|
return x.Guid == y.Guid;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Operator
|
/// Operator
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="x"></param>
|
/// <param name="x"></param>
|
||||||
/// <param name="y"></param>
|
/// <param name="y"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static bool operator !=(Guid x, Squid y)
|
public static bool operator ==(Squid x, Guid y)
|
||||||
{
|
{
|
||||||
return !(x == y);
|
return x.Guid == y;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Operator
|
/// Operator
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="oSquid"></param>
|
/// <param name="x"></param>
|
||||||
/// <returns></returns>
|
/// <param name="y"></param>
|
||||||
public static implicit operator string(Squid oSquid)
|
/// <returns></returns>
|
||||||
{
|
public static bool operator ==(Guid x, Squid y)
|
||||||
return oSquid.Value;
|
{
|
||||||
}
|
return y == x; // NB: order of arguments
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Operator
|
/// Operator
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="oSquid"></param>
|
/// <param name="x"></param>
|
||||||
/// <returns></returns>
|
/// <param name="y"></param>
|
||||||
public static implicit operator Guid(Squid oSquid)
|
/// <returns></returns>
|
||||||
{
|
public static bool operator !=(Squid x, Squid y)
|
||||||
return oSquid.Guid;
|
{
|
||||||
}
|
return !(x == y);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Operator
|
/// Operator
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="value"></param>
|
/// <param name="x"></param>
|
||||||
/// <returns></returns>
|
/// <param name="y"></param>
|
||||||
public static implicit operator Squid(string value)
|
/// <returns></returns>
|
||||||
{
|
public static bool operator !=(Squid x, Guid y)
|
||||||
if (string.IsNullOrEmpty(value))
|
{
|
||||||
return Empty;
|
return !(x == y);
|
||||||
|
}
|
||||||
|
|
||||||
return TryParse(value, out Squid oSquid) ? oSquid : Empty;
|
/// <summary>
|
||||||
}
|
/// Operator
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="x"></param>
|
||||||
|
/// <param name="y"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static bool operator !=(Guid x, Squid y)
|
||||||
|
{
|
||||||
|
return !(x == y);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Operator
|
/// Operator
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="oGuid"></param>
|
/// <param name="oSquid"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static implicit operator Squid(Guid oGuid)
|
public static implicit operator string(Squid oSquid)
|
||||||
{
|
{
|
||||||
return oGuid == Guid.Empty ? Empty : new Squid(oGuid);
|
return oSquid.Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Operator
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="oSquid"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static implicit operator Guid(Squid oSquid)
|
||||||
|
{
|
||||||
|
return oSquid.Guid;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Operator
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static implicit operator Squid(string value)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(value))
|
||||||
|
return Empty;
|
||||||
|
|
||||||
|
return TryParse(value, out Squid oSquid) ? oSquid : Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Operator
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="oGuid"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static implicit operator Squid(Guid oGuid)
|
||||||
|
{
|
||||||
|
return oGuid == Guid.Empty ? Empty : new Squid(oGuid);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -23,104 +23,102 @@ using Wonky.Client.Services;
|
||||||
using Microsoft.AspNetCore.Components;
|
using Microsoft.AspNetCore.Components;
|
||||||
using Toolbelt.Blazor;
|
using Toolbelt.Blazor;
|
||||||
|
|
||||||
namespace Wonky.Client.HttpInterceptors
|
namespace Wonky.Client.HttpInterceptors;
|
||||||
|
|
||||||
|
public class HttpInterceptorService
|
||||||
{
|
{
|
||||||
public class HttpInterceptorService
|
private readonly HttpClientInterceptor _interceptor;
|
||||||
|
private readonly NavigationManager _navigation;
|
||||||
|
private readonly IToastService _toast;
|
||||||
|
private readonly RefreshTokenService _refreshTokenService;
|
||||||
|
private readonly ILogger<HttpInterceptorService> _logger;
|
||||||
|
private readonly ILocalStorageService _storage;
|
||||||
|
private readonly IAuthenticationService _authenticationService;
|
||||||
|
|
||||||
|
public HttpInterceptorService(HttpClientInterceptor interceptor,
|
||||||
|
NavigationManager navigation, IToastService toast,
|
||||||
|
RefreshTokenService refreshTokenService, ILogger<HttpInterceptorService> logger,
|
||||||
|
ILocalStorageService storage, IAuthenticationService authenticationService)
|
||||||
{
|
{
|
||||||
private readonly HttpClientInterceptor _interceptor;
|
_interceptor = interceptor;
|
||||||
private readonly NavigationManager _navigation;
|
_navigation = navigation;
|
||||||
private readonly IToastService _toast;
|
_toast = toast;
|
||||||
private readonly RefreshTokenService _refreshTokenService;
|
_refreshTokenService = refreshTokenService;
|
||||||
private readonly ILogger<HttpInterceptorService> _logger;
|
_logger = logger;
|
||||||
private readonly ILocalStorageService _storage;
|
_storage = storage;
|
||||||
private readonly IAuthenticationService _authenticationService;
|
_authenticationService = authenticationService;
|
||||||
|
}
|
||||||
|
|
||||||
public HttpInterceptorService(HttpClientInterceptor interceptor,
|
public void RegisterEvent()
|
||||||
NavigationManager navigation, IToastService toast,
|
{
|
||||||
RefreshTokenService refreshTokenService, ILogger<HttpInterceptorService> logger,
|
_interceptor.AfterSend += AfterSend;
|
||||||
ILocalStorageService storage, IAuthenticationService authenticationService)
|
}
|
||||||
{
|
|
||||||
_interceptor = interceptor;
|
|
||||||
_navigation = navigation;
|
|
||||||
_toast = toast;
|
|
||||||
_refreshTokenService = refreshTokenService;
|
|
||||||
_logger = logger;
|
|
||||||
_storage = storage;
|
|
||||||
_authenticationService = authenticationService;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void RegisterEvent()
|
public void RegisterBeforeSendEvent()
|
||||||
{
|
{
|
||||||
_interceptor.AfterSend += AfterSend;
|
_interceptor.BeforeSendAsync += InterceptBeforeSend;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RegisterBeforeSendEvent()
|
|
||||||
{
|
|
||||||
_interceptor.BeforeSendAsync += InterceptBeforeSend;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void DisposeEvent()
|
public void DisposeEvent()
|
||||||
{
|
{
|
||||||
_interceptor.AfterSend -= AfterSend;
|
_interceptor.AfterSend -= AfterSend;
|
||||||
_interceptor.BeforeSendAsync -= InterceptBeforeSend;
|
_interceptor.BeforeSendAsync -= InterceptBeforeSend;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task InterceptBeforeSend(object sender, HttpClientInterceptorEventArgs e)
|
private async Task InterceptBeforeSend(object sender, HttpClientInterceptorEventArgs e)
|
||||||
|
{
|
||||||
|
var absolutePath = e.Request.RequestUri.AbsolutePath;
|
||||||
|
if (!absolutePath.Contains("token"))
|
||||||
{
|
{
|
||||||
var absolutePath = e.Request.RequestUri.AbsolutePath;
|
// call TryRefreshToken
|
||||||
if (!absolutePath.Contains("token"))
|
var token = await _refreshTokenService.TryRefreshToken();
|
||||||
|
if (!string.IsNullOrEmpty(token))
|
||||||
{
|
{
|
||||||
// call TryRefreshToken
|
// set new token
|
||||||
var token = await _refreshTokenService.TryRefreshToken();
|
e.Request.Headers.Authorization = new AuthenticationHeaderValue("bearer", token);
|
||||||
if (!string.IsNullOrEmpty(token))
|
|
||||||
{
|
|
||||||
// set new token
|
|
||||||
e.Request.Headers.Authorization = new AuthenticationHeaderValue("bearer", token);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
private void AfterSend (object sender, HttpClientInterceptorEventArgs e)
|
private void AfterSend (object sender, HttpClientInterceptorEventArgs e)
|
||||||
|
{
|
||||||
|
if (e.Response == null || e.Response.IsSuccessStatusCode)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var message = $"En fejl er opstået \n {JsonSerializer.Serialize(e)}";
|
||||||
|
var currDoc = _navigation.ToBaseRelativePath(_navigation.Uri);
|
||||||
|
if (currDoc.Contains("login/"))
|
||||||
|
currDoc = "";
|
||||||
|
|
||||||
|
switch (e.Response.StatusCode)
|
||||||
{
|
{
|
||||||
if (e.Response == null || e.Response.IsSuccessStatusCode)
|
case HttpStatusCode.NotFound:
|
||||||
return;
|
_logger.LogDebug("NotFound <= {}", currDoc);
|
||||||
|
break;
|
||||||
var message = $"En fejl er opstået \n {JsonSerializer.Serialize(e)}";
|
case HttpStatusCode.BadRequest:
|
||||||
var currDoc = _navigation.ToBaseRelativePath(_navigation.Uri);
|
_logger.LogDebug("BadRequest <= {}", currDoc);
|
||||||
if (currDoc.Contains("login/"))
|
_logger.LogDebug("{}", message);
|
||||||
currDoc = "";
|
break;
|
||||||
|
case HttpStatusCode.Unauthorized:
|
||||||
switch (e.Response.StatusCode)
|
_logger.LogDebug("Unauthorized <= {}", currDoc);
|
||||||
{
|
_logger.LogDebug("{}", message);
|
||||||
case HttpStatusCode.NotFound:
|
_authenticationService.Logout();
|
||||||
_logger.LogDebug("NotFound <= {}", currDoc);
|
_navigation.NavigateTo($"/login/{currDoc}");
|
||||||
break;
|
_toast.ShowInfo("Venligst Login. Tak.");
|
||||||
case HttpStatusCode.BadRequest:
|
break;
|
||||||
_logger.LogDebug("BadRequest <= {}", currDoc);
|
case HttpStatusCode.Conflict:
|
||||||
_logger.LogDebug("{}", message);
|
_logger.LogDebug("Conflict <= {}", currDoc);
|
||||||
break;
|
_logger.LogDebug("{}", message);
|
||||||
case HttpStatusCode.Unauthorized:
|
break;
|
||||||
_logger.LogDebug("Unauthorized <= {}", currDoc);
|
case HttpStatusCode.InternalServerError:
|
||||||
_logger.LogDebug("{}", message);
|
_logger.LogDebug("InternalServerError <= {}", currDoc);
|
||||||
_authenticationService.Logout();
|
_logger.LogDebug("{}", message);
|
||||||
_navigation.NavigateTo($"/login/{currDoc}");
|
break;
|
||||||
_toast.ShowInfo("Venligst Login. Tak.");
|
default:
|
||||||
break;
|
_logger.LogDebug("{}", message);
|
||||||
case HttpStatusCode.Conflict:
|
break;
|
||||||
_logger.LogDebug("Conflict <= {}", currDoc);
|
|
||||||
_logger.LogDebug("{}", message);
|
|
||||||
break;
|
|
||||||
case HttpStatusCode.InternalServerError:
|
|
||||||
_logger.LogDebug("InternalServerError <= {}", currDoc);
|
|
||||||
_logger.LogDebug("{}", message);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
_logger.LogDebug("{}", message);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
// throw new HttpResponseException(message);
|
|
||||||
}
|
}
|
||||||
}
|
// throw new HttpResponseException(message);
|
||||||
}
|
}
|
||||||
|
}
|
|
@ -16,26 +16,25 @@
|
||||||
|
|
||||||
using System.Runtime.Serialization;
|
using System.Runtime.Serialization;
|
||||||
|
|
||||||
namespace Wonky.Client.HttpInterceptors
|
namespace Wonky.Client.HttpInterceptors;
|
||||||
|
|
||||||
|
[Serializable]
|
||||||
|
public class HttpResponseException : Exception
|
||||||
{
|
{
|
||||||
[Serializable]
|
public HttpResponseException()
|
||||||
public class HttpResponseException : Exception
|
|
||||||
{
|
{
|
||||||
public HttpResponseException()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
public HttpResponseException(string message)
|
|
||||||
: base(message)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
public HttpResponseException(string message, Exception innerException)
|
|
||||||
: base(message, innerException)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
public HttpResponseException(SerializationInfo info, StreamingContext context)
|
|
||||||
: base(info, context)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
public HttpResponseException(string message)
|
||||||
|
: base(message)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
public HttpResponseException(string message, Exception innerException)
|
||||||
|
: base(message, innerException)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
public HttpResponseException(SerializationInfo info, StreamingContext context)
|
||||||
|
: base(info, context)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -30,7 +30,7 @@
|
||||||
<div class="row g-3">
|
<div class="row g-3">
|
||||||
<label for="date" class="col-form-label-sm col-sm-1">Dato</label>
|
<label for="date" class="col-form-label-sm col-sm-1">Dato</label>
|
||||||
<div class="col-sm-3">
|
<div class="col-sm-3">
|
||||||
<input id="date" class="form-control" type="text" value="@(DateTime.Parse(ReportItem.CreateTimestamp).ToShortDateString())" readonly/>
|
<input id="date" class="form-control" type="text" value="@ReportItem.CreateTimestamp" readonly/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<label for="account" class="col-form-label-sm col-sm-1">Konto</label>
|
<label for="account" class="col-form-label-sm col-sm-1">Konto</label>
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
|
|
||||||
<div class="row bg-dark text-white rounded-2 mb-2 py-2 align-items-center">
|
<div class="row bg-dark text-white rounded-2 mb-2 py-2 align-items-center">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<WorkDateComponent OnChangedCallback="WorkDateComponentCallback" />
|
<WorkDateComponent OnChangedCallback="WorkDateComponentCallback"/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -34,7 +34,7 @@
|
||||||
{
|
{
|
||||||
<div class="alert alert-danger">
|
<div class="alert alert-danger">
|
||||||
<h4>Ring til kontoret. Denne konto er spærret med kode '@Company.Blocked'</h4>
|
<h4>Ring til kontoret. Denne konto er spærret med kode '@Company.Blocked'</h4>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
<div class="row mb-2 bg-dark text-white rounded-3 p-3">
|
<div class="row mb-2 bg-dark text-white rounded-3 p-3">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
|
@ -46,10 +46,9 @@
|
||||||
{
|
{
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<h3>Der kan ikke oprettes besøg når der findes rapport for @SelectedDate.ToShortDateString()</h3>
|
<h3>Der kan ikke oprettes besøg når der findes rapport for @SelectedDate.ToShortDateString()</h3>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -81,8 +80,8 @@ else
|
||||||
{
|
{
|
||||||
<option value="order">Bestilling</option>
|
<option value="order">Bestilling</option>
|
||||||
}
|
}
|
||||||
|
|
||||||
@if(DraftProvider.Draft.DraftType == "offer")
|
@if (DraftProvider.Draft.DraftType == "offer")
|
||||||
{
|
{
|
||||||
<option selected value="quote">Tilbud</option>
|
<option selected value="quote">Tilbud</option>
|
||||||
}
|
}
|
||||||
|
@ -137,7 +136,7 @@ else
|
||||||
<InputText id="phone" class="form-control" @bind-Value="Activity.Phone"/>
|
<InputText id="phone" class="form-control" @bind-Value="Activity.Phone"/>
|
||||||
<ValidationMessage For="@(() => Activity.Phone)"></ValidationMessage>
|
<ValidationMessage For="@(() => Activity.Phone)"></ValidationMessage>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<label for="orderMessage" class="col-sm-2 col-form-label-sm">Note /Kontor</label>
|
<label for="orderMessage" class="col-sm-2 col-form-label-sm">Note /Kontor</label>
|
||||||
<div class="col-sm-4">
|
<div class="col-sm-4">
|
||||||
<InputTextArea id="orderMessage" class="form-control" @bind-Value="Activity.OrderMessage"/>
|
<InputTextArea id="orderMessage" class="form-control" @bind-Value="Activity.OrderMessage"/>
|
||||||
|
@ -149,15 +148,15 @@ else
|
||||||
<InputTextArea id="crmNote" class="form-control" @bind-Value="Activity.CrmNote"/>
|
<InputTextArea id="crmNote" class="form-control" @bind-Value="Activity.CrmNote"/>
|
||||||
<ValidationMessage For="@(() => Activity.CrmNote)"></ValidationMessage>
|
<ValidationMessage For="@(() => Activity.CrmNote)"></ValidationMessage>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-sm-6"></div>
|
<div class="col-sm-6"></div>
|
||||||
<label for="vatNumber" class="col-sm-2 col-form-label-sm">Cvr/Org nr.</label>
|
<label for="vatNumber" class="col-sm-2 col-form-label-sm">Cvr/Org nr.</label>
|
||||||
<div class="col-sm-4">
|
<div class="col-sm-4">
|
||||||
<InputText id="vatNumber" class="form-control" @bind-Value="Activity.VatNumber" />
|
<InputText id="vatNumber" class="form-control" @bind-Value="Activity.VatNumber"/>
|
||||||
<ValidationMessage For="@(() => Activity.VatNumber)" />
|
<ValidationMessage For="@(() => Activity.VatNumber)"/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row g-2 mb-3">
|
<div class="row g-2 mb-3">
|
||||||
<div class="col-sm-3 d-grid mx-auto">
|
<div class="col-sm-3 d-grid mx-auto">
|
||||||
@*
|
@*
|
||||||
|
@ -178,7 +177,7 @@ else
|
||||||
<button class="btn btn-success" disabled="@string.IsNullOrWhiteSpace(Activity.ActivityTypeEnum)" @onclick="ShowInventoryOverlay">Produkter</button>
|
<button class="btn btn-success" disabled="@string.IsNullOrWhiteSpace(Activity.ActivityTypeEnum)" @onclick="ShowInventoryOverlay">Produkter</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="this-draft" style="@(Activity.ActivityStatusEnum is "order" or "quote" ? "display: block" : "display:none")">
|
<div id="this-draft" style="@(Activity.ActivityStatusEnum is "order" or "quote" ? "display: block" : "display:none")">
|
||||||
@* Draft lines in draft -----------------------------------------------------*@
|
@* Draft lines in draft -----------------------------------------------------*@
|
||||||
<div class="row">
|
<div class="row">
|
||||||
|
@ -275,7 +274,7 @@ else
|
||||||
</td>
|
</td>
|
||||||
<td class="align-middle" style="min-width:200px;">
|
<td class="align-middle" style="min-width:200px;">
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<input type="number" class="form-control" @bind-value="@Price"/>
|
<input type="number" class="form-control" @bind-value="@Price"/>
|
||||||
@*
|
@*
|
||||||
***************** Price history overlay button *****************************
|
***************** Price history overlay button *****************************
|
||||||
*@
|
*@
|
||||||
|
@ -285,10 +284,10 @@ else
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
<td class="align-middle" style="min-width:100px;">
|
<td class="align-middle" style="min-width:100px;">
|
||||||
<input type="number" class="form-control" @bind-value="@Discount"/>
|
<input type="number" class="form-control" @bind-value="@Discount"/>
|
||||||
</td>
|
</td>
|
||||||
<td class="align-middle align-content-center justify-content-center">
|
<td class="align-middle align-content-center justify-content-center">
|
||||||
<input type="checkbox" class="form-check" @bind-value="@Sas"/>
|
<input type="checkbox" class="form-check" @bind-value="@Sas"/>
|
||||||
</td>
|
</td>
|
||||||
<td class="align-middle">@SelectedItem.Sku</td>
|
<td class="align-middle">@SelectedItem.Sku</td>
|
||||||
<td class="align-middle">
|
<td class="align-middle">
|
||||||
|
@ -360,26 +359,27 @@ else
|
||||||
***************** Confirm product check overlay button *****************************
|
***************** Confirm product check overlay button *****************************
|
||||||
***************** Continue by submitton order to erp *****************************
|
***************** Continue by submitton order to erp *****************************
|
||||||
*@
|
*@
|
||||||
<button type="button" class="btn btn-warning" @onclick="CallConfirmCheckOverlay" disabled="@(PoFormInvalid || Working)"><i class="bi-cloud-arrow-up"></i> @ButtonText</button>
|
<button type="button" class="btn btn-warning" @onclick="CallConfirmCheckOverlay" disabled="@(PoFormInvalid || Working)">
|
||||||
|
<i class="bi-cloud-arrow-up"></i> @ButtonText
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
<ProductCheckConfirmationOverlay BodyMessage="" CompanyId="@CompanyId" Products="CheckList"
|
<ProductCheckConfirmationOverlay BodyMessage="" CompanyId="@CompanyId" Products="CheckList"
|
||||||
OnOkClicked="ConfirmProductCheckCallback" @ref="ConfirmationCheckOverlay" />
|
OnOkClicked="ConfirmProductCheckCallback" @ref="ConfirmationCheckOverlay"/>
|
||||||
<ConfirmWorkDateModal BodyMessage="@PromptDateConfirm"
|
<ConfirmWorkDateModal BodyMessage="@PromptDateConfirm"
|
||||||
OnOkClicked="WorkDateConfirmCallback" @ref="ConfirmWorkDate"/>
|
OnOkClicked="WorkDateConfirmCallback" @ref="ConfirmWorkDate"/>
|
||||||
|
|
||||||
<ProductHistoryOverlay CompanyId="@CompanyId" ItemSku="@SelectedItem.Sku" @ref="ProductOverlay"/>
|
<ProductHistoryOverlay CompanyId="@CompanyId" ItemSku="@SelectedItem.Sku" @ref="ProductOverlay"/>
|
||||||
|
|
||||||
<PriceCatalogOverlay CountryCode="@Company.CountryCode.ToLower()" OnSelected="PriceListCallback" @ref="CatalogOverlay"/>
|
<PriceCatalogOverlay CountryCode="@Company.CountryCode.ToLower()" OnSelected="PriceListCallback" @ref="CatalogOverlay"/>
|
||||||
|
|
||||||
<ProductPriceHistoryOverlay CompanyId="@CompanyId" Sku="@SelectedItem.Sku" OnSelected="PriceHistoryCallback" @ref="PriceOverlay"/>
|
<ProductPriceHistoryOverlay CompanyId="@CompanyId" Sku="@SelectedItem.Sku" OnSelected="PriceHistoryCallback" @ref="PriceOverlay"/>
|
||||||
|
|
||||||
<CustomerInvoiceListOverlay CustomerInvoices="CompanyInvoices" @ref="InvoiceListOverlay" />
|
<CustomerInvoiceListOverlay CustomerInvoices="CompanyInvoices" @ref="InvoiceListOverlay"/>
|
||||||
|
|
||||||
<CustomerActivityListOverlay Activities="Activities" CompanyName="@Company.Name" @ref="ActivityListOverlay" />
|
<CustomerActivityListOverlay Activities="Activities" CompanyName="@Company.Name" @ref="ActivityListOverlay"/>
|
||||||
|
|
||||||
<CustomerInventoryListOverlay CompanyName="@Company.Name" CompanyId="@CompanyId" CountryCode="@Company.CountryCode"
|
<CustomerInventoryListOverlay CompanyName="@Company.Name" CompanyId="@CompanyId" CountryCode="@Company.CountryCode"
|
||||||
OnSelected="OnInventoryCallback" Inventory="Inventory" @ref="InventoryListOverlay" />
|
OnSelected="OnInventoryCallback" Inventory="Inventory" @ref="InventoryListOverlay"/>
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
|
// Copyright (C) 2022 FCS Frede's Computer Services.
|
||||||
// Copyright (C) 2022 FCS Frede's Computer Services.
|
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// This program is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU Affero General Public License as
|
// it under the terms of the GNU Affero General Public License as
|
||||||
// published by the Free Software Foundation, either version 3 of the
|
// published by the Free Software Foundation, either version 3 of the
|
||||||
|
@ -30,6 +29,7 @@ using Wonky.Client.Services;
|
||||||
using Wonky.Client.Shared;
|
using Wonky.Client.Shared;
|
||||||
using Wonky.Entity.DTO;
|
using Wonky.Entity.DTO;
|
||||||
using Wonky.Entity.Views;
|
using Wonky.Entity.Views;
|
||||||
|
|
||||||
#pragma warning disable CS8618
|
#pragma warning disable CS8618
|
||||||
|
|
||||||
namespace Wonky.Client.Pages;
|
namespace Wonky.Client.Pages;
|
||||||
|
@ -49,18 +49,22 @@ public partial class AdvisorActivityCreatePage : IDisposable
|
||||||
[Inject] public IAdvisorActivityRepository ActivityRepo { get; set; }
|
[Inject] public IAdvisorActivityRepository ActivityRepo { get; set; }
|
||||||
[Inject] public IAdvisorReportRepository ReportRepo { get; set; }
|
[Inject] public IAdvisorReportRepository ReportRepo { get; set; }
|
||||||
[Inject] public IAdvisorCustomerHistoryRepository HistoryRepo { get; set; }
|
[Inject] public IAdvisorCustomerHistoryRepository HistoryRepo { get; set; }
|
||||||
[Inject] public IUserInfoService UserInfoService { get; set; }
|
|
||||||
|
[Inject] public IUserInfoService UserService { get; set; }
|
||||||
|
|
||||||
// *************************************************************
|
// *************************************************************
|
||||||
// Parameters
|
// Parameters
|
||||||
[CascadingParameter] private DraftStateProvider DraftProvider { get; set; } = new();
|
[CascadingParameter] private DraftStateProvider DraftProvider { get; set; } = new();
|
||||||
|
|
||||||
[Parameter] public string CompanyId { get; set; } = "";
|
[Parameter] public string CompanyId { get; set; } = "";
|
||||||
|
|
||||||
// *************************************************************
|
// *************************************************************
|
||||||
// Variables
|
// Variables
|
||||||
private readonly JsonSerializerOptions _options = new() {PropertyNameCaseInsensitive = true};
|
private readonly JsonSerializerOptions _options = new() { PropertyNameCaseInsensitive = true };
|
||||||
private SalesItemView SelectedItem { get; set; } = new();
|
private SalesItemView SelectedItem { get; set; } = new();
|
||||||
private UserProfile UserProfile { get; set; } = new();
|
private UserProfile UserProfile { get; set; } = new();
|
||||||
private ActivityDto Activity { get; set; } = new();
|
private ActivityDto Activity { get; set; } = new();
|
||||||
private CompanyDto Company = new();
|
private CompanyDto Company { get; set; } = new();
|
||||||
private EditContext? ActivityContext { get; set; }
|
private EditContext? ActivityContext { get; set; }
|
||||||
private bool PoFormInvalid { get; set; } = true;
|
private bool PoFormInvalid { get; set; } = true;
|
||||||
private bool ShowItem { get; set; }
|
private bool ShowItem { get; set; }
|
||||||
|
@ -69,7 +73,7 @@ public partial class AdvisorActivityCreatePage : IDisposable
|
||||||
private string Discount { get; set; } = "0";
|
private string Discount { get; set; } = "0";
|
||||||
private bool Sas { get; set; }
|
private bool Sas { get; set; }
|
||||||
private bool InvalidActivityType { get; set; } = true;
|
private bool InvalidActivityType { get; set; } = true;
|
||||||
private bool InvalidActivity { get; set; } = true;
|
private bool InvalidActivity { get; set; } = true;
|
||||||
private bool ReportClosed { get; set; }
|
private bool ReportClosed { get; set; }
|
||||||
private bool Working { get; set; } = true;
|
private bool Working { get; set; } = true;
|
||||||
private UserManagerEditView SalesRep { get; set; } = new();
|
private UserManagerEditView SalesRep { get; set; } = new();
|
||||||
|
@ -78,7 +82,9 @@ public partial class AdvisorActivityCreatePage : IDisposable
|
||||||
private string PromptDateConfirm { get; set; } = "";
|
private string PromptDateConfirm { get; set; } = "";
|
||||||
private string ButtonText { get; set; } = "Gem besøg";
|
private string ButtonText { get; set; } = "Gem besøg";
|
||||||
private bool OrgWarning { get; set; }
|
private bool OrgWarning { get; set; }
|
||||||
|
|
||||||
private const string PromptDemoForgotten = "Har du glemt demo?";
|
private const string PromptDemoForgotten = "Har du glemt demo?";
|
||||||
|
|
||||||
// *************************************************************
|
// *************************************************************
|
||||||
// Overlays
|
// Overlays
|
||||||
private PriceCatalogOverlay CatalogOverlay { get; set; } = new();
|
private PriceCatalogOverlay CatalogOverlay { get; set; } = new();
|
||||||
|
@ -88,14 +94,16 @@ public partial class AdvisorActivityCreatePage : IDisposable
|
||||||
private ProductCheckConfirmationOverlay ConfirmationCheckOverlay { get; set; } = new();
|
private ProductCheckConfirmationOverlay ConfirmationCheckOverlay { get; set; } = new();
|
||||||
private CustomerInvoiceListOverlay InvoiceListOverlay { get; set; } = new();
|
private CustomerInvoiceListOverlay InvoiceListOverlay { get; set; } = new();
|
||||||
private CustomerInventoryListOverlay InventoryListOverlay { get; set; } = new();
|
private CustomerInventoryListOverlay InventoryListOverlay { get; set; } = new();
|
||||||
|
|
||||||
private CustomerActivityListOverlay ActivityListOverlay { get; set; } = new();
|
private CustomerActivityListOverlay ActivityListOverlay { get; set; } = new();
|
||||||
|
|
||||||
// *************************************************************
|
// *************************************************************
|
||||||
// Lists
|
// Lists
|
||||||
private List<ProductInventoryView> Inventory { get; set; } = new();
|
private List<ProductInventoryView> Inventory { get; set; } = new();
|
||||||
private List<ProductInventoryView> CheckList { get; set; } = new();
|
private List<ProductInventoryView> CheckList { get; set; } = new();
|
||||||
private InvoiceListView CompanyInvoices { get; set; } = new();
|
private InvoiceListView CompanyInvoices { get; set; } = new();
|
||||||
private List<ReportItemView> Activities { get; set; } = new();
|
private List<ReportItemView> Activities { get; set; } = new();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Page initialization
|
/// Page initialization
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -110,13 +118,13 @@ public partial class AdvisorActivityCreatePage : IDisposable
|
||||||
// User Preferences
|
// User Preferences
|
||||||
UserProfile = await ProfileService.GetProfile();
|
UserProfile = await ProfileService.GetProfile();
|
||||||
// User Info
|
// User Info
|
||||||
SalesRep = await UserInfoService.GetUserInfo();
|
SalesRep = await UserService.GetUserInfo();
|
||||||
// Fetch Customer from http
|
// Fetch Customer from http
|
||||||
Company = await CompanyRepo.GetCompanyById(CompanyId);
|
Company = await CompanyRepo.GetCompanyById(CompanyId);
|
||||||
if (Company.HasFolded == 1)
|
if (Company.HasFolded == 1)
|
||||||
// Company has shutdown activities
|
// Company has shut down
|
||||||
Activity.OrderMessage = "BEMÆRK: CVR nummer er ophørt.";
|
Activity.OrderMessage = "BEMÆRK: CVR nummer er ophørt.";
|
||||||
|
|
||||||
// variable to validate if customer needs phone number update
|
// variable to validate if customer needs phone number update
|
||||||
OldPhone = Company.Phone;
|
OldPhone = Company.Phone;
|
||||||
if (string.IsNullOrWhiteSpace(Company.Phone)
|
if (string.IsNullOrWhiteSpace(Company.Phone)
|
||||||
|
@ -125,7 +133,7 @@ public partial class AdvisorActivityCreatePage : IDisposable
|
||||||
{
|
{
|
||||||
Company.Phone = Company.Account[..8];
|
Company.Phone = Company.Account[..8];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Populate base activity information
|
// Populate base activity information
|
||||||
Activity.BcId = Company.BcId;
|
Activity.BcId = Company.BcId;
|
||||||
Activity.ActivityStatusEnum = "noSale";
|
Activity.ActivityStatusEnum = "noSale";
|
||||||
|
@ -141,7 +149,7 @@ public partial class AdvisorActivityCreatePage : IDisposable
|
||||||
Activity.Mobile = Company.Mobile;
|
Activity.Mobile = Company.Mobile;
|
||||||
Activity.Name = Company.Name;
|
Activity.Name = Company.Name;
|
||||||
Activity.Address1 = Company.Address1;
|
Activity.Address1 = Company.Address1;
|
||||||
Activity.Address2 = Company.Address2;
|
Activity.Address2 = Company.Address2;
|
||||||
Activity.ZipCode = Company.ZipCode;
|
Activity.ZipCode = Company.ZipCode;
|
||||||
Activity.City = Company.City;
|
Activity.City = Company.City;
|
||||||
Activity.DlvName = Company.Name;
|
Activity.DlvName = Company.Name;
|
||||||
|
@ -150,7 +158,10 @@ public partial class AdvisorActivityCreatePage : IDisposable
|
||||||
Activity.DlvZipCode = Company.ZipCode;
|
Activity.DlvZipCode = Company.ZipCode;
|
||||||
Activity.DlvCity = Company.City;
|
Activity.DlvCity = Company.City;
|
||||||
// Initialize date variable
|
// Initialize date variable
|
||||||
SelectedDate = string.IsNullOrWhiteSpace(UserProfile.WorkDate) ? DateTime.Now : DateTime.Parse(UserProfile.WorkDate);
|
Logger.LogDebug("AdvisorActivityCreatePage => DateTime parser => {}", UserProfile.WorkDate);
|
||||||
|
SelectedDate = string.IsNullOrWhiteSpace(UserProfile.WorkDate)
|
||||||
|
? DateTime.Now
|
||||||
|
: DateTime.Parse(UserProfile.WorkDate);
|
||||||
// raise flag if report is closed
|
// raise flag if report is closed
|
||||||
ReportClosed = await ReportRepo.ReportExist($"{SelectedDate:yyyy-MM-dd}");
|
ReportClosed = await ReportRepo.ReportExist($"{SelectedDate:yyyy-MM-dd}");
|
||||||
// Ask for confirmation of date
|
// Ask for confirmation of date
|
||||||
|
@ -160,6 +171,7 @@ public partial class AdvisorActivityCreatePage : IDisposable
|
||||||
PromptDateConfirm = $"Aktiviteter oprettes med dato {SelectedDate.ToShortDateString()}. Er dette OK?";
|
PromptDateConfirm = $"Aktiviteter oprettes med dato {SelectedDate.ToShortDateString()}. Er dette OK?";
|
||||||
ConfirmWorkDate.Show();
|
ConfirmWorkDate.Show();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Lines may already have been added from the company inventory page
|
// Lines may already have been added from the company inventory page
|
||||||
if (DraftProvider.Draft.DraftType == "order")
|
if (DraftProvider.Draft.DraftType == "order")
|
||||||
{
|
{
|
||||||
|
@ -168,26 +180,27 @@ public partial class AdvisorActivityCreatePage : IDisposable
|
||||||
Activity.ActivityStatusEnum = "order";
|
Activity.ActivityStatusEnum = "order";
|
||||||
PoFormInvalid = false;
|
PoFormInvalid = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Working = false;
|
Working = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task ShowVisitOverlay()
|
private async Task ShowVisitOverlay()
|
||||||
{
|
{
|
||||||
Logger.LogDebug("ShowInventoryOverlay - wait for visits");
|
Logger.LogDebug("ShowInventoryOverlay - wait for visits");
|
||||||
|
|
||||||
ActivityListOverlay.Show();
|
ActivityListOverlay.Show();
|
||||||
|
|
||||||
Activities = await ActivityRepo.GetCustomerActivities(CompanyId);
|
Activities = await ActivityRepo.GetCustomerActivities(CompanyId);
|
||||||
|
|
||||||
await Task.Delay(500);
|
await Task.Delay(500);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task ShowInventoryOverlay()
|
private async Task ShowInventoryOverlay()
|
||||||
{
|
{
|
||||||
Logger.LogDebug("ShowInventoryOverlay - wait for inventory");
|
Logger.LogDebug("ShowInventoryOverlay - wait for inventory");
|
||||||
|
|
||||||
InventoryListOverlay.Show();
|
InventoryListOverlay.Show();
|
||||||
|
|
||||||
Inventory = await HistoryRepo.FetchInventory(CompanyId);
|
Inventory = await HistoryRepo.FetchInventory(CompanyId);
|
||||||
Inventory = Inventory.OrderBy(x => x.Description).ToList();
|
Inventory = Inventory.OrderBy(x => x.Description).ToList();
|
||||||
await Task.Delay(500);
|
await Task.Delay(500);
|
||||||
|
@ -200,31 +213,32 @@ public partial class AdvisorActivityCreatePage : IDisposable
|
||||||
DraftProvider.Draft.Items.Add(item);
|
DraftProvider.Draft.Items.Add(item);
|
||||||
StateHasChanged();
|
StateHasChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task ShowInvoiceOverlay()
|
private async Task ShowInvoiceOverlay()
|
||||||
{
|
{
|
||||||
Logger.LogDebug("ShowInvoiceOverlay - wait for invoices");
|
Logger.LogDebug("ShowInvoiceOverlay - wait for invoices");
|
||||||
|
|
||||||
InvoiceListOverlay.Show();
|
InvoiceListOverlay.Show();
|
||||||
CompanyInvoices = await FetchCompanyInvoices();
|
CompanyInvoices = await FetchCompanyInvoices();
|
||||||
await Task.Delay(500);
|
await Task.Delay(500);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<InvoiceListView> FetchCompanyInvoices()
|
private async Task<InvoiceListView> FetchCompanyInvoices()
|
||||||
{
|
{
|
||||||
// fetch from storage
|
// fetch from storage
|
||||||
var storage = await Storage.GetItemAsStringAsync($"{CompanyId}-invoices");
|
var storage = await Storage.GetItemAsStringAsync($"{CompanyId}-invoices");
|
||||||
await Task.Delay(500);
|
await Task.Delay(500);
|
||||||
var iDate = await Storage.GetItemAsStringAsync($"{CompanyId}-iDate");
|
var iDate = await Storage.GetItemAsStringAsync($"{CompanyId}-iDate");
|
||||||
|
|
||||||
// if we have a list and iDate was today return the list
|
// if we have a list and iDate was today return the list
|
||||||
if (!string.IsNullOrWhiteSpace(storage) && (!string.IsNullOrWhiteSpace(iDate) && DateTime.Parse(iDate.Replace("\"", "")) >= DateTime.Now))
|
if (!string.IsNullOrWhiteSpace(storage) && (!string.IsNullOrWhiteSpace(iDate) &&
|
||||||
|
DateTime.Parse(iDate.Replace("\"", "")) >= DateTime.Now))
|
||||||
{
|
{
|
||||||
Logger.LogDebug("fetching invoices from storage");
|
Logger.LogDebug("fetching invoices from storage");
|
||||||
Logger.LogDebug("storage contains <= {}", storage);
|
Logger.LogDebug("storage contains <= {}", storage);
|
||||||
return JsonSerializer.Deserialize<InvoiceListView>(storage);
|
return JsonSerializer.Deserialize<InvoiceListView>(storage);
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger.LogDebug("pulling invoices from backend");
|
Logger.LogDebug("pulling invoices from backend");
|
||||||
// pull invoices
|
// pull invoices
|
||||||
var companyInvoices = await HistoryRepo.FetchInvoiceList(CompanyId);
|
var companyInvoices = await HistoryRepo.FetchInvoiceList(CompanyId);
|
||||||
|
@ -236,30 +250,31 @@ public partial class AdvisorActivityCreatePage : IDisposable
|
||||||
Logger.LogDebug("backend contains <= {}", JsonSerializer.Serialize(companyInvoices));
|
Logger.LogDebug("backend contains <= {}", JsonSerializer.Serialize(companyInvoices));
|
||||||
return companyInvoices;
|
return companyInvoices;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ShowOrgWarning()
|
private void ShowOrgWarning()
|
||||||
{
|
{
|
||||||
if (OrgWarning)
|
if (OrgWarning)
|
||||||
return;
|
return;
|
||||||
OrgWarning = true;
|
OrgWarning = true;
|
||||||
if (Company.CountryCode.ToLower() == "se" && VatUtils.SanitizeVatNumber(Activity.VatNumber).Length < 10 && Activity.ActivityStatusEnum == "order")
|
if (Company.CountryCode.ToLower() == "se" && VatUtils.SanitizeVatNumber(Activity.VatNumber).Length < 10 &&
|
||||||
|
Activity.ActivityStatusEnum == "order")
|
||||||
{
|
{
|
||||||
Toaster.ShowWarning("Org nummer er ufuldstændig. Skal opdateres før bestilling kan sendes. ", "ADVARSEL");
|
Toaster.ShowWarning("Org nummer er ufuldstændig. Skal opdateres før bestilling kan sendes. ", "ADVARSEL");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task CallConfirmCheckOverlay()
|
private async Task CallConfirmCheckOverlay()
|
||||||
{
|
{
|
||||||
// check if new account
|
// check if new account
|
||||||
if (string.IsNullOrWhiteSpace(Company.Account)
|
if (string.IsNullOrWhiteSpace(Company.Account)
|
||||||
|| Company.Account.ToLower() == "ny"
|
|| Company.Account.ToLower() == "ny"
|
||||||
|| Activity.ActivityStatusEnum.ToLower() == "quote")
|
|| Activity.ActivityStatusEnum.ToLower() == "quote")
|
||||||
{
|
{
|
||||||
// proceed to create activity - as there is no product check to be done
|
// proceed to create activity - as there is no product check to be done
|
||||||
await CreateActivity();
|
await CreateActivity();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// check if product has been checked
|
// check if product has been checked
|
||||||
// fetch products from storage
|
// fetch products from storage
|
||||||
var pStorage = await Storage.GetItemAsStringAsync($"{CompanyId}-products");
|
var pStorage = await Storage.GetItemAsStringAsync($"{CompanyId}-products");
|
||||||
|
@ -269,13 +284,15 @@ public partial class AdvisorActivityCreatePage : IDisposable
|
||||||
if (string.IsNullOrWhiteSpace(pDate))
|
if (string.IsNullOrWhiteSpace(pDate))
|
||||||
pDate = $"{DateTime.Now.AddDays(-1):yyyy-MM-dd}";
|
pDate = $"{DateTime.Now.AddDays(-1):yyyy-MM-dd}";
|
||||||
Logger.LogDebug("pDate => {}", pDate);
|
Logger.LogDebug("pDate => {}", pDate);
|
||||||
|
|
||||||
// check if product data is valid and updated today
|
// check if product data is valid and updated today
|
||||||
if (string.IsNullOrWhiteSpace(pStorage) || pDate.Replace("\"", "") != $"{DateTime.Now:yyyy-MM-dd}")
|
if (string.IsNullOrWhiteSpace(pStorage) || pDate.Replace("\"", "") != $"{DateTime.Now:yyyy-MM-dd}")
|
||||||
{
|
{
|
||||||
Working = true;
|
Working = true;
|
||||||
// pop a message
|
// pop a message
|
||||||
Toaster.ShowError("Produkt gennemgang mangler. Vent mens produkt oversigt indlæses. Gå ikke væk fra siden!", "Produkt check ...");
|
Toaster.ShowError(
|
||||||
|
"Produkt gennemgang mangler. Vent mens produkt oversigt indlæses. Gå ikke væk fra siden!",
|
||||||
|
"Produkt check ...");
|
||||||
// product inventory has not been updated
|
// product inventory has not been updated
|
||||||
// send rpc call to sync ERP to CRM
|
// send rpc call to sync ERP to CRM
|
||||||
Toaster.ShowInfo("Vent mens data synkroniseres ...", "ERP til CRM ...");
|
Toaster.ShowInfo("Vent mens data synkroniseres ...", "ERP til CRM ...");
|
||||||
|
@ -286,11 +303,11 @@ public partial class AdvisorActivityCreatePage : IDisposable
|
||||||
await Storage.SetItemAsync($"{CompanyId}-pDate", ts);
|
await Storage.SetItemAsync($"{CompanyId}-pDate", ts);
|
||||||
// request products from backend
|
// request products from backend
|
||||||
Toaster.ShowInfo("Vent mens produkt oversigt hentes", "CRM produkt liste");
|
Toaster.ShowInfo("Vent mens produkt oversigt hentes", "CRM produkt liste");
|
||||||
|
|
||||||
CheckList = await HistoryRepo.FetchInventory(CompanyId);
|
CheckList = await HistoryRepo.FetchInventory(CompanyId);
|
||||||
if(CheckList.Any())
|
if (CheckList.Any())
|
||||||
CheckList = CheckList.OrderBy(x => x.Description).ToList();
|
CheckList = CheckList.OrderBy(x => x.Description).ToList();
|
||||||
|
|
||||||
await Storage.SetItemAsync($"{CompanyId}-products", CheckList);
|
await Storage.SetItemAsync($"{CompanyId}-products", CheckList);
|
||||||
Working = false;
|
Working = false;
|
||||||
}
|
}
|
||||||
|
@ -298,14 +315,14 @@ public partial class AdvisorActivityCreatePage : IDisposable
|
||||||
{
|
{
|
||||||
// deserialize storage data
|
// deserialize storage data
|
||||||
CheckList = JsonSerializer.Deserialize<List<ProductInventoryView>>(pStorage);
|
CheckList = JsonSerializer.Deserialize<List<ProductInventoryView>>(pStorage);
|
||||||
if(CheckList.Any())
|
if (CheckList.Any())
|
||||||
CheckList = CheckList.OrderBy(x => x.Description).ToList();
|
CheckList = CheckList.OrderBy(x => x.Description).ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Show CheckList modal
|
// Show CheckList modal
|
||||||
ConfirmationCheckOverlay.Show();
|
ConfirmationCheckOverlay.Show();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task ConfirmProductCheckCallback()
|
private async Task ConfirmProductCheckCallback()
|
||||||
{
|
{
|
||||||
ConfirmationCheckOverlay.Hide();
|
ConfirmationCheckOverlay.Hide();
|
||||||
|
@ -314,10 +331,10 @@ public partial class AdvisorActivityCreatePage : IDisposable
|
||||||
{
|
{
|
||||||
item.Check = false;
|
item.Check = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
await Storage.SetItemAsync($"{CompanyId}-products", CheckList);
|
await Storage.SetItemAsync($"{CompanyId}-products", CheckList);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task WorkDateConfirmCallback()
|
private async Task WorkDateConfirmCallback()
|
||||||
{
|
{
|
||||||
await ProfileService.SetDateConfirmed(true);
|
await ProfileService.SetDateConfirmed(true);
|
||||||
|
@ -332,12 +349,12 @@ public partial class AdvisorActivityCreatePage : IDisposable
|
||||||
SelectedDate = DateTime.Parse(workDate);
|
SelectedDate = DateTime.Parse(workDate);
|
||||||
Activity.ActivityDate = workDate;
|
Activity.ActivityDate = workDate;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ShowPriceListOverlay()
|
private void ShowPriceListOverlay()
|
||||||
{
|
{
|
||||||
CatalogOverlay.Show();
|
CatalogOverlay.Show();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task PriceListCallback(SelectedSku sku)
|
private async Task PriceListCallback(SelectedSku sku)
|
||||||
{
|
{
|
||||||
// get selected item
|
// get selected item
|
||||||
|
@ -349,13 +366,13 @@ public partial class AdvisorActivityCreatePage : IDisposable
|
||||||
Quantity = sku.Quantity;
|
Quantity = sku.Quantity;
|
||||||
StateHasChanged();
|
StateHasChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ShowPriceHistoryOverlay()
|
private void ShowPriceHistoryOverlay()
|
||||||
{
|
{
|
||||||
if(ShowItem)
|
if (ShowItem)
|
||||||
PriceOverlay.Show();
|
PriceOverlay.Show();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void PriceHistoryCallback(decimal price)
|
private void PriceHistoryCallback(decimal price)
|
||||||
{
|
{
|
||||||
if (price == 0)
|
if (price == 0)
|
||||||
|
@ -376,6 +393,7 @@ public partial class AdvisorActivityCreatePage : IDisposable
|
||||||
Toaster.ShowError("Kunde adresse er ufuldstændig.");
|
Toaster.ShowError("Kunde adresse er ufuldstændig.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// validate org number
|
// validate org number
|
||||||
// - this is a required input
|
// - this is a required input
|
||||||
// - must validate according to country rules.
|
// - must validate according to country rules.
|
||||||
|
@ -384,6 +402,7 @@ public partial class AdvisorActivityCreatePage : IDisposable
|
||||||
Toaster.ShowError("Firma registreringsnummer er ikke korrekt.");
|
Toaster.ShowError("Firma registreringsnummer er ikke korrekt.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// validate input according to status
|
// validate input according to status
|
||||||
switch (Activity.ActivityStatusEnum)
|
switch (Activity.ActivityStatusEnum)
|
||||||
{
|
{
|
||||||
|
@ -400,6 +419,7 @@ public partial class AdvisorActivityCreatePage : IDisposable
|
||||||
Toaster.ShowError("Ved tilbud skal en gyldig email adresse angives.");
|
Toaster.ShowError("Ved tilbud skal en gyldig email adresse angives.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// raise working flag
|
// raise working flag
|
||||||
Working = true;
|
Working = true;
|
||||||
|
|
||||||
|
@ -412,11 +432,12 @@ public partial class AdvisorActivityCreatePage : IDisposable
|
||||||
Activity.OrderMessage = $"Telefonnr. opdateret.\n{Activity.OrderMessage}";
|
Activity.OrderMessage = $"Telefonnr. opdateret.\n{Activity.OrderMessage}";
|
||||||
await CompanyRepo.UpdateErpData(Company.CompanyId, Company);
|
await CompanyRepo.UpdateErpData(Company.CompanyId, Company);
|
||||||
}
|
}
|
||||||
|
|
||||||
// begin assembling activity
|
// begin assembling activity
|
||||||
Activity.ActivityDate = $"{SelectedDate:yyyy-MM-dd}";
|
Activity.ActivityDate = $"{SelectedDate:yyyy-MM-dd}";
|
||||||
Activity.OurRef = Activity.ActivityTypeEnum switch
|
Activity.OurRef = Activity.ActivityTypeEnum switch
|
||||||
{
|
{
|
||||||
"phone" => $"T:{SalesRep.FirstName}",
|
"phone" => $"T:{SalesRep.FirstName}",
|
||||||
"onSite" => $"B:{SalesRep.FirstName}",
|
"onSite" => $"B:{SalesRep.FirstName}",
|
||||||
_ => ""
|
_ => ""
|
||||||
};
|
};
|
||||||
|
@ -443,6 +464,7 @@ public partial class AdvisorActivityCreatePage : IDisposable
|
||||||
.ToList();
|
.ToList();
|
||||||
Activity.Lines = lines;
|
Activity.Lines = lines;
|
||||||
}
|
}
|
||||||
|
|
||||||
// debug logging
|
// debug logging
|
||||||
Logger.LogDebug("CrmNewActivityPage => \n {}", JsonSerializer.Serialize(Activity));
|
Logger.LogDebug("CrmNewActivityPage => \n {}", JsonSerializer.Serialize(Activity));
|
||||||
// post to api
|
// post to api
|
||||||
|
@ -458,18 +480,19 @@ public partial class AdvisorActivityCreatePage : IDisposable
|
||||||
Navigator.NavigateTo($"/advisor/customers");
|
Navigator.NavigateTo($"/advisor/customers");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// lower working flag
|
// lower working flag
|
||||||
Working = false;
|
Working = false;
|
||||||
// show error message
|
// show error message
|
||||||
Toaster.ShowError(result.Message, "ORDRE FEJL");
|
Toaster.ShowError(result.Message, "ORDRE FEJL");
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task DeleteDraft()
|
private async Task DeleteDraft()
|
||||||
{
|
{
|
||||||
await DraftProvider.DeleteDraftAsync();
|
await DraftProvider.DeleteDraftAsync();
|
||||||
Activity.ActivityStatusEnum = "noSale";
|
Activity.ActivityStatusEnum = "noSale";
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task AddItem(SalesItemView salesItem)
|
private async Task AddItem(SalesItemView salesItem)
|
||||||
{
|
{
|
||||||
ShowItem = false;
|
ShowItem = false;
|
||||||
|
@ -489,12 +512,12 @@ public partial class AdvisorActivityCreatePage : IDisposable
|
||||||
Discount = "0";
|
Discount = "0";
|
||||||
// add it to the cart
|
// add it to the cart
|
||||||
DraftProvider.Draft.Items.Add(item);
|
DraftProvider.Draft.Items.Add(item);
|
||||||
if(Activity.ActivityStatusEnum != "quote")
|
if (Activity.ActivityStatusEnum != "quote")
|
||||||
Activity.ActivityStatusEnum = "order";
|
Activity.ActivityStatusEnum = "order";
|
||||||
// save the item using the CartStateProvider's save method
|
// save the item using the CartStateProvider's save method
|
||||||
await DraftProvider.SaveChangesAsync();
|
await DraftProvider.SaveChangesAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task RemoveItem(DraftItem item)
|
private async Task RemoveItem(DraftItem item)
|
||||||
{
|
{
|
||||||
// remove item
|
// remove item
|
||||||
|
@ -504,10 +527,11 @@ public partial class AdvisorActivityCreatePage : IDisposable
|
||||||
if (!DraftProvider.Draft.Items.Any())
|
if (!DraftProvider.Draft.Items.Any())
|
||||||
Activity.ActivityStatusEnum = "noSale";
|
Activity.ActivityStatusEnum = "noSale";
|
||||||
}
|
}
|
||||||
|
|
||||||
private void HandleFieldChanged(object sender, FieldChangedEventArgs e)
|
private void HandleFieldChanged(object sender, FieldChangedEventArgs e)
|
||||||
{
|
{
|
||||||
Logger.LogDebug("ActivityNewPage => HandleFieldChanged => ActivityStatusEnum <= '{}'", Activity.ActivityStatusEnum);
|
Logger.LogDebug("ActivityNewPage => HandleFieldChanged => ActivityStatusEnum <= '{}'",
|
||||||
|
Activity.ActivityStatusEnum);
|
||||||
DraftProvider.Draft.DraftType = Activity.ActivityStatusEnum;
|
DraftProvider.Draft.DraftType = Activity.ActivityStatusEnum;
|
||||||
if (Activity.ActivityStatusEnum == "noSale")
|
if (Activity.ActivityStatusEnum == "noSale")
|
||||||
{
|
{
|
||||||
|
@ -523,19 +547,20 @@ public partial class AdvisorActivityCreatePage : IDisposable
|
||||||
};
|
};
|
||||||
|
|
||||||
// InvalidCanvas = InvalidActivityType;
|
// InvalidCanvas = InvalidActivityType;
|
||||||
InvalidActivity = InvalidActivityType
|
InvalidActivity = InvalidActivityType
|
||||||
|| PoFormInvalid
|
|| PoFormInvalid
|
||||||
|| DraftProvider.Draft.Items.Count == 0
|
|| DraftProvider.Draft.Items.Count == 0
|
||||||
|| (Activity.ActivityStatusEnum == "offer" && string.IsNullOrWhiteSpace(Activity.Email));
|
|| (Activity.ActivityStatusEnum == "offer" && string.IsNullOrWhiteSpace(Activity.Email));
|
||||||
if (Activity.YourRef.Length > 35 || Activity.ReferenceNumber.Length > 20 || InvalidActivity)
|
if (Activity.YourRef.Length > 35 || Activity.ReferenceNumber.Length > 20 || InvalidActivity)
|
||||||
{
|
{
|
||||||
PoFormInvalid = true;
|
PoFormInvalid = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
PoFormInvalid = !ActivityContext.Validate();
|
PoFormInvalid = !ActivityContext.Validate();
|
||||||
StateHasChanged();
|
StateHasChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ValidationChanged(object sender, ValidationStateChangedEventArgs e)
|
private void ValidationChanged(object sender, ValidationStateChangedEventArgs e)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(Activity.ActivityTypeEnum) && !ReportClosed)
|
if (string.IsNullOrEmpty(Activity.ActivityTypeEnum) && !ReportClosed)
|
||||||
|
@ -544,16 +569,16 @@ public partial class AdvisorActivityCreatePage : IDisposable
|
||||||
PoFormInvalid = true;
|
PoFormInvalid = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Activity.ActivityStatusEnum.ToLower() is "order" or "quote"
|
if (Activity.ActivityStatusEnum.ToLower() is "order" or "quote"
|
||||||
&& Company.CountryCode.ToLower() == "se"
|
&& Company.CountryCode.ToLower() == "se"
|
||||||
&& VatUtils.SanitizeVatNumber(Activity.VatNumber).Length < 10)
|
&& VatUtils.SanitizeVatNumber(Activity.VatNumber).Length < 10)
|
||||||
{
|
{
|
||||||
ShowOrgWarning();
|
ShowOrgWarning();
|
||||||
PoFormInvalid = true;
|
PoFormInvalid = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
PoFormInvalid = false;
|
PoFormInvalid = false;
|
||||||
ActivityContext.OnFieldChanged -= HandleFieldChanged;
|
ActivityContext.OnFieldChanged -= HandleFieldChanged;
|
||||||
ActivityContext.OnValidationStateChanged -= ValidationChanged;
|
ActivityContext.OnValidationStateChanged -= ValidationChanged;
|
||||||
|
@ -561,7 +586,7 @@ public partial class AdvisorActivityCreatePage : IDisposable
|
||||||
ActivityContext.OnFieldChanged += HandleFieldChanged;
|
ActivityContext.OnFieldChanged += HandleFieldChanged;
|
||||||
ActivityContext.OnValidationStateChanged += ValidationChanged;
|
ActivityContext.OnValidationStateChanged += ValidationChanged;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
Interceptor.DisposeEvent();
|
Interceptor.DisposeEvent();
|
||||||
|
|
|
@ -45,4 +45,4 @@
|
||||||
@if (Working)
|
@if (Working)
|
||||||
{
|
{
|
||||||
<WorkingThreeDots/>
|
<WorkingThreeDots/>
|
||||||
}
|
}
|
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
// Copyright (C) 2022 FCS Frede's Computer Services.
|
// Copyright (C) 2022 FCS Frede's Computer Services.
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// This program is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU Affero General Public License as
|
// it under the terms of the GNU Affero General Public License as
|
||||||
|
@ -14,6 +13,7 @@
|
||||||
// along with this program. If not, see [https://www.gnu.org/licenses/agpl-3.0.en.html]
|
// along with this program. If not, see [https://www.gnu.org/licenses/agpl-3.0.en.html]
|
||||||
//
|
//
|
||||||
|
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using Blazored.Toast.Services;
|
using Blazored.Toast.Services;
|
||||||
using Microsoft.AspNetCore.Components;
|
using Microsoft.AspNetCore.Components;
|
||||||
|
@ -21,6 +21,7 @@ using Wonky.Client.HttpInterceptors;
|
||||||
using Wonky.Client.HttpRepository;
|
using Wonky.Client.HttpRepository;
|
||||||
using Wonky.Client.Services;
|
using Wonky.Client.Services;
|
||||||
using Wonky.Entity.Views;
|
using Wonky.Entity.Views;
|
||||||
|
|
||||||
#pragma warning disable CS8618
|
#pragma warning disable CS8618
|
||||||
|
|
||||||
namespace Wonky.Client.Pages;
|
namespace Wonky.Client.Pages;
|
||||||
|
@ -34,7 +35,7 @@ public partial class AdvisorActivityTodayListPage : IDisposable
|
||||||
[Inject] public IAdvisorActivityRepository ActivityRepo { get; set; }
|
[Inject] public IAdvisorActivityRepository ActivityRepo { get; set; }
|
||||||
[Inject] public IAdvisorReportRepository ReportRepo { get; set; }
|
[Inject] public IAdvisorReportRepository ReportRepo { get; set; }
|
||||||
[Inject] public IToastService Toaster { get; set; }
|
[Inject] public IToastService Toaster { get; set; }
|
||||||
private ReportStatusView ReportStatusView { get; set; } = new();
|
private ReportStatusView ReportStatusView { get; set; } = new();
|
||||||
private UserProfile UserProfile { get; set; } = new();
|
private UserProfile UserProfile { get; set; } = new();
|
||||||
private DateTime SelectedDate { get; set; }
|
private DateTime SelectedDate { get; set; }
|
||||||
private bool ReportExist { get; set; }
|
private bool ReportExist { get; set; }
|
||||||
|
@ -45,12 +46,14 @@ public partial class AdvisorActivityTodayListPage : IDisposable
|
||||||
Interceptor.RegisterEvent();
|
Interceptor.RegisterEvent();
|
||||||
Interceptor.RegisterBeforeSendEvent();
|
Interceptor.RegisterBeforeSendEvent();
|
||||||
UserProfile = await ProfileService.GetProfile();
|
UserProfile = await ProfileService.GetProfile();
|
||||||
SelectedDate = string.IsNullOrWhiteSpace(UserProfile.WorkDate) ? DateTime.Now : DateTime.Parse(UserProfile.WorkDate);
|
SelectedDate = string.IsNullOrWhiteSpace(UserProfile.WorkDate)
|
||||||
|
? DateTime.Now
|
||||||
|
: DateTime.Parse(UserProfile.WorkDate);
|
||||||
ReportExist = await ReportRepo.ReportExist($"{SelectedDate:yyyy-MM-dd}");
|
ReportExist = await ReportRepo.ReportExist($"{SelectedDate:yyyy-MM-dd}");
|
||||||
await GetActivities($"{SelectedDate:yyyy-MM-dd}");
|
await GetActivities($"{SelectedDate:yyyy-MM-dd}");
|
||||||
Working = false;
|
Working = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task GetActivities(string workDate)
|
private async Task GetActivities(string workDate)
|
||||||
{
|
{
|
||||||
Working = true;
|
Working = true;
|
||||||
|
@ -67,6 +70,5 @@ public partial class AdvisorActivityTodayListPage : IDisposable
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
Interceptor.DisposeEvent();
|
Interceptor.DisposeEvent();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -23,7 +23,6 @@
|
||||||
@page "/advisor/customers/{CompanyId}/quotes/{OrderId}"
|
@page "/advisor/customers/{CompanyId}/quotes/{OrderId}"
|
||||||
|
|
||||||
<PageTitle>@ReportItem.Company.Name @ReportItem.OrderDate</PageTitle>
|
<PageTitle>@ReportItem.Company.Name @ReportItem.OrderDate</PageTitle>
|
||||||
@* <ReportItemComponent ReportItem="@_item" /> *@
|
|
||||||
|
|
||||||
<table class="table table-sm table-striped d-print-table">
|
<table class="table table-sm table-striped d-print-table">
|
||||||
<thead>
|
<thead>
|
||||||
|
@ -124,7 +123,9 @@
|
||||||
{
|
{
|
||||||
<tr>
|
<tr>
|
||||||
<td colspan="4"></td>
|
<td colspan="4"></td>
|
||||||
<td colspan="2"><h5 class="fw-bold text-center"><i class="bi-lightning-charge the-fast" style="font-size: 2rem;"></i> HASTER</h5></td>
|
<td colspan="2">
|
||||||
|
<h5 class="fw-bold text-center"><i class="bi-lightning-charge the-fast" style="font-size: 2rem;"></i> HASTER</h5>
|
||||||
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
}
|
}
|
||||||
</tbody>
|
</tbody>
|
||||||
|
@ -145,7 +146,7 @@
|
||||||
<button class="btn btn-primary btn-lg" type="button" @onclick="UpdateOfficeNote" disabled="@Disabled">Opdater Note /Kontor</button>
|
<button class="btn btn-primary btn-lg" type="button" @onclick="UpdateOfficeNote" disabled="@Disabled">Opdater Note /Kontor</button>
|
||||||
</div>
|
</div>
|
||||||
</EditForm>
|
</EditForm>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -159,4 +160,4 @@ else
|
||||||
@if (Working)
|
@if (Working)
|
||||||
{
|
{
|
||||||
<WorkingThreeDots/>
|
<WorkingThreeDots/>
|
||||||
}
|
}
|
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
// Copyright (C) 2022 FCS Frede's Computer Services.
|
// Copyright (C) 2022 FCS Frede's Computer Services.
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// This program is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU Affero General Public License as
|
// it under the terms of the GNU Affero General Public License as
|
||||||
|
@ -22,6 +21,7 @@ using Wonky.Client.HttpInterceptors;
|
||||||
using Wonky.Client.HttpRepository;
|
using Wonky.Client.HttpRepository;
|
||||||
using Wonky.Entity.DTO;
|
using Wonky.Entity.DTO;
|
||||||
using Wonky.Entity.Views;
|
using Wonky.Entity.Views;
|
||||||
|
|
||||||
#pragma warning disable CS8618
|
#pragma warning disable CS8618
|
||||||
|
|
||||||
namespace Wonky.Client.Pages;
|
namespace Wonky.Client.Pages;
|
||||||
|
@ -41,6 +41,7 @@ public partial class AdvisorActivityViewEditPage : IDisposable
|
||||||
private bool Disabled { get; set; }
|
private bool Disabled { get; set; }
|
||||||
private int GraceTime { get; set; } = 60;
|
private int GraceTime { get; set; } = 60;
|
||||||
private bool Working { get; set; } = true;
|
private bool Working { get; set; } = true;
|
||||||
|
|
||||||
|
|
||||||
protected override async Task OnInitializedAsync()
|
protected override async Task OnInitializedAsync()
|
||||||
{
|
{
|
||||||
|
@ -59,7 +60,7 @@ public partial class AdvisorActivityViewEditPage : IDisposable
|
||||||
{
|
{
|
||||||
StateHasChanged();
|
StateHasChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task UpdateOfficeNote()
|
private async Task UpdateOfficeNote()
|
||||||
{
|
{
|
||||||
Working = true;
|
Working = true;
|
||||||
|
@ -76,7 +77,7 @@ public partial class AdvisorActivityViewEditPage : IDisposable
|
||||||
return false;
|
return false;
|
||||||
return DateTime.UtcNow < createTs.AddMinutes(GraceTime);
|
return DateTime.UtcNow < createTs.AddMinutes(GraceTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
Interceptor.DisposeEvent();
|
Interceptor.DisposeEvent();
|
||||||
|
|
|
@ -35,10 +35,10 @@
|
||||||
<a class="btn btn-primary d-block" href="/advisor/customers/@Company.CompanyId/activities/new"><i class="bi-arrow-right"></i> Besøg</a>
|
<a class="btn btn-primary d-block" href="/advisor/customers/@Company.CompanyId/activities/new"><i class="bi-arrow-right"></i> Besøg</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<CustomerActivityListComponent Activities="ActivityList" />
|
<CustomerActivityListComponent Activities="ActivityList"/>
|
||||||
}
|
}
|
||||||
@if (Working)
|
@if (Working)
|
||||||
{
|
{
|
||||||
<WorkingThreeDots/>
|
<WorkingThreeDots/>
|
||||||
}
|
}
|
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
// Copyright (C) 2022 FCS Frede's Computer Services.
|
// Copyright (C) 2022 FCS Frede's Computer Services.
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// This program is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU Affero General Public License as
|
// it under the terms of the GNU Affero General Public License as
|
||||||
|
@ -20,6 +19,7 @@ using Wonky.Client.HttpInterceptors;
|
||||||
using Wonky.Client.HttpRepository;
|
using Wonky.Client.HttpRepository;
|
||||||
using Wonky.Entity.DTO;
|
using Wonky.Entity.DTO;
|
||||||
using Wonky.Entity.Views;
|
using Wonky.Entity.Views;
|
||||||
|
|
||||||
#pragma warning disable CS8618
|
#pragma warning disable CS8618
|
||||||
|
|
||||||
namespace Wonky.Client.Pages;
|
namespace Wonky.Client.Pages;
|
||||||
|
@ -33,12 +33,12 @@ public partial class AdvisorCustomerActivityListPage : IDisposable
|
||||||
private List<ReportItemView> ActivityList { get; set; } = new();
|
private List<ReportItemView> ActivityList { get; set; } = new();
|
||||||
private CompanyDto Company { get; set; } = new();
|
private CompanyDto Company { get; set; } = new();
|
||||||
private bool Working { get; set; } = true;
|
private bool Working { get; set; } = true;
|
||||||
|
|
||||||
protected override async Task OnInitializedAsync()
|
protected override async Task OnInitializedAsync()
|
||||||
{
|
{
|
||||||
Interceptor.RegisterEvent();
|
Interceptor.RegisterEvent();
|
||||||
Interceptor.RegisterBeforeSendEvent();
|
Interceptor.RegisterBeforeSendEvent();
|
||||||
|
|
||||||
Company = await CompanyRepo.GetCompanyById(CompanyId);
|
Company = await CompanyRepo.GetCompanyById(CompanyId);
|
||||||
await GetActivities();
|
await GetActivities();
|
||||||
Working = false;
|
Working = false;
|
||||||
|
@ -48,11 +48,11 @@ public partial class AdvisorCustomerActivityListPage : IDisposable
|
||||||
{
|
{
|
||||||
Working = true;
|
Working = true;
|
||||||
ActivityList = await AdvisorActivityRepo.GetCustomerActivities(CompanyId);
|
ActivityList = await AdvisorActivityRepo.GetCustomerActivities(CompanyId);
|
||||||
if(ActivityList.Any())
|
if (ActivityList.Any())
|
||||||
ActivityList = ActivityList.OrderByDescending(x => x.OrderDate).ToList();
|
ActivityList = ActivityList.OrderByDescending(x => x.OrderDate).ToList();
|
||||||
Working = false;
|
Working = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
Interceptor.DisposeEvent();
|
Interceptor.DisposeEvent();
|
||||||
|
|
|
@ -14,7 +14,6 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using System.Xml;
|
|
||||||
using Blazored.LocalStorage;
|
using Blazored.LocalStorage;
|
||||||
using Blazored.Toast.Services;
|
using Blazored.Toast.Services;
|
||||||
using Microsoft.AspNetCore.Components;
|
using Microsoft.AspNetCore.Components;
|
||||||
|
@ -27,162 +26,161 @@ using Wonky.Client.Services;
|
||||||
using Wonky.Client.Shared;
|
using Wonky.Client.Shared;
|
||||||
using Wonky.Entity.DTO;
|
using Wonky.Entity.DTO;
|
||||||
using Wonky.Entity.Models;
|
using Wonky.Entity.Models;
|
||||||
using Wonky.Entity.Views;
|
|
||||||
#pragma warning disable CS8618
|
#pragma warning disable CS8618
|
||||||
|
|
||||||
namespace Wonky.Client.Pages
|
namespace Wonky.Client.Pages;
|
||||||
|
|
||||||
|
public partial class AdvisorCustomerCreatePage : IDisposable
|
||||||
{
|
{
|
||||||
public partial class AdvisorCustomerCreatePage : IDisposable
|
[Inject] public IToastService Toaster { get; set; }
|
||||||
|
[Inject] public ILogger<AdvisorCustomerCreatePage> Logger { get; set; }
|
||||||
|
[Inject] public ILocalStorageService Storage { get; set; }
|
||||||
|
[Inject] public NavigationManager Navigator { get; set; }
|
||||||
|
[Inject] public IAdvisorCustomerRepository CompanyRepo { get; set; }
|
||||||
|
[Inject] public HttpInterceptorService Interceptor { get; set; }
|
||||||
|
[Inject] public VatInfoLookupService VatService { get; set; }
|
||||||
|
[Inject] public IUserInfoService UserInfoService { get; set; }
|
||||||
|
|
||||||
|
private EditContext CompanyContext { get; set; }
|
||||||
|
private CompanyDto Company { get; set; } = new();
|
||||||
|
private VatAddress CompanyVatAddress { get; set; } = new();
|
||||||
|
private VatLookupDkModal VatLookupPopup { get; set; } = new();
|
||||||
|
|
||||||
|
private bool FormInvalid { get; set; } = true;
|
||||||
|
private string RegState { get; set; } = "";
|
||||||
|
private DateTime LastVisit { get; set; }
|
||||||
|
private DateTime NextVisit { get; set; }
|
||||||
|
private bool Dk { get; set; } = true;
|
||||||
|
private bool Working { get; set; }
|
||||||
|
|
||||||
|
protected override async Task OnInitializedAsync()
|
||||||
{
|
{
|
||||||
[Inject] public IToastService Toaster { get; set; }
|
CompanyContext = new EditContext(Company);
|
||||||
[Inject] public ILogger<AdvisorCustomerCreatePage> Logger { get; set; }
|
|
||||||
[Inject] public ILocalStorageService Storage { get; set; }
|
|
||||||
[Inject] public NavigationManager Navigator { get; set; }
|
|
||||||
[Inject] public IAdvisorCustomerRepository CompanyRepo { get; set; }
|
|
||||||
[Inject] public HttpInterceptorService Interceptor { get; set; }
|
|
||||||
[Inject] public VatInfoLookupService VatService { get; set; }
|
|
||||||
[Inject] public IUserInfoService UserInfoService { get; set; }
|
|
||||||
|
|
||||||
private EditContext CompanyContext { get; set; }
|
|
||||||
private CompanyDto Company { get; set; } = new();
|
|
||||||
private VatAddress CompanyVatAddress { get; set; } = new();
|
|
||||||
private VatLookupDkModal VatLookupPopup { get; set; } = new();
|
|
||||||
|
|
||||||
private bool FormInvalid { get; set; } = true;
|
CompanyContext.OnFieldChanged += HandleFieldChanged;
|
||||||
private string RegState { get; set; } = "";
|
CompanyContext.OnValidationStateChanged += ValidationChanged;
|
||||||
private DateTime LastVisit { get; set; }
|
|
||||||
private DateTime NextVisit { get; set; }
|
|
||||||
private bool Dk { get; set; } = true;
|
|
||||||
private bool Working { get; set; }
|
|
||||||
|
|
||||||
protected override async Task OnInitializedAsync()
|
var xu = await UserInfoService.GetUserInfo();
|
||||||
|
Dk = xu.CountryCode.ToLower() == "dk";
|
||||||
|
|
||||||
|
Company.SalesRepId = xu.UserId;
|
||||||
|
Company.CountryCode = xu.CountryCode.ToLower();
|
||||||
|
|
||||||
|
LastVisit = DateTime.Now;
|
||||||
|
NextVisit = DateTime.Now.AddDays(Company.Interval * 7);
|
||||||
|
Company.LastVisit = $"{LastVisit:yyyy-MM-dd}";
|
||||||
|
Company.NextVisit = $"{NextVisit:yyyy-MM-dd}";
|
||||||
|
|
||||||
|
Interceptor.RegisterEvent();
|
||||||
|
Interceptor.RegisterBeforeSendEvent();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Show Vat Lookup modal
|
||||||
|
/// </summary>
|
||||||
|
private void CallVatLookupModal()
|
||||||
|
{
|
||||||
|
VatLookupPopup.Show();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Modal callback to update company properties
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="regInfo"></param>
|
||||||
|
private void SelectCompanyCallback(VirkRegInfo regInfo)
|
||||||
|
{
|
||||||
|
Logger.LogDebug("CrmCompanyView => SelectCompanyCallback => {}", JsonSerializer.Serialize(regInfo));
|
||||||
|
|
||||||
|
// this can be removed in favor of the new data returned from updating the VatNumber
|
||||||
|
RegState = regInfo.States[0].State.ToLower() == "normal" ? "the-good" : "the-dead";
|
||||||
|
if (regInfo.SyncAll)
|
||||||
{
|
{
|
||||||
CompanyContext = new EditContext(Company);
|
Company.Name = regInfo.Name;
|
||||||
|
Company.Address1 = regInfo.Address;
|
||||||
CompanyContext.OnFieldChanged += HandleFieldChanged;
|
Company.Address2 = regInfo.CoName;
|
||||||
CompanyContext.OnValidationStateChanged += ValidationChanged;
|
Company.ZipCode = regInfo.ZipCode;
|
||||||
|
Company.City = regInfo.City;
|
||||||
var xu = await UserInfoService.GetUserInfo();
|
|
||||||
Dk = xu.CountryCode.ToLower() == "dk";
|
|
||||||
|
|
||||||
Company.SalesRepId = xu.UserId;
|
|
||||||
Company.CountryCode = xu.CountryCode.ToLower();
|
|
||||||
|
|
||||||
LastVisit = DateTime.Now;
|
|
||||||
NextVisit = DateTime.Now.AddDays(Company.Interval * 7);
|
|
||||||
Company.LastVisit = $"{LastVisit:yyyy-MM-dd}";
|
|
||||||
Company.NextVisit = $"{NextVisit:yyyy-MM-dd}";
|
|
||||||
|
|
||||||
Interceptor.RegisterEvent();
|
|
||||||
Interceptor.RegisterBeforeSendEvent();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
Company.VatNumber = regInfo.VatNumber;
|
||||||
/// Show Vat Lookup modal
|
Company.ValidVat = 1;
|
||||||
/// </summary>
|
FormInvalid = false;
|
||||||
private void CallVatLookupModal()
|
}
|
||||||
|
|
||||||
|
private async Task SubmitCompanyForm()
|
||||||
|
{
|
||||||
|
Working = true;
|
||||||
|
FormInvalid = true;
|
||||||
|
Company.LastVisit = $"{LastVisit:yyyy-MM-dd}";
|
||||||
|
Company.NextVisit = $"{NextVisit:yyyy-MM-dd}";
|
||||||
|
|
||||||
|
var newId = await CompanyRepo.CreateCompany(Company);
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(newId))
|
||||||
{
|
{
|
||||||
VatLookupPopup.Show();
|
Toaster.ShowSuccess($"'{Company.Name}' er oprettet i CRM.");
|
||||||
|
Navigator.NavigateTo($"/advisor/customers/{newId}");
|
||||||
}
|
}
|
||||||
|
else
|
||||||
/// <summary>
|
|
||||||
/// Modal callback to update company properties
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="regInfo"></param>
|
|
||||||
private void SelectCompanyCallback(VirkRegInfo regInfo)
|
|
||||||
{
|
{
|
||||||
Logger.LogDebug("CrmCompanyView => SelectCompanyCallback => {}", JsonSerializer.Serialize(regInfo));
|
Toaster.ShowWarning($"'{Company.Name}' IKKE oprettet.");
|
||||||
|
|
||||||
// this can be removed in favor of the new data returned from updating the VatNumber
|
|
||||||
RegState = regInfo.States[0].State.ToLower() == "normal" ? "the-good" : "the-dead";
|
|
||||||
if (regInfo.SyncAll)
|
|
||||||
{
|
|
||||||
Company.Name = regInfo.Name;
|
|
||||||
Company.Address1 = regInfo.Address;
|
|
||||||
Company.Address2 = regInfo.CoName;
|
|
||||||
Company.ZipCode = regInfo.ZipCode;
|
|
||||||
Company.City = regInfo.City;
|
|
||||||
}
|
|
||||||
|
|
||||||
Company.VatNumber = regInfo.VatNumber;
|
|
||||||
Company.ValidVat = 1;
|
|
||||||
FormInvalid = false;
|
FormInvalid = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task SubmitCompanyForm()
|
Working = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HandleFieldChanged(object sender, FieldChangedEventArgs e)
|
||||||
|
{
|
||||||
|
NextVisit = LastVisit.AddDays(7 * Company.Interval);
|
||||||
|
// invalid vat number id not accepted by the ERP system
|
||||||
|
// but is removed without warning
|
||||||
|
// it is necessary to validate if vat number has been added
|
||||||
|
// as the format should conform to country rule of generation
|
||||||
|
if (!string.IsNullOrWhiteSpace(Company.VatNumber))
|
||||||
{
|
{
|
||||||
Working = true;
|
// validate vat number according to country
|
||||||
FormInvalid = true;
|
if (!VatUtils.ValidateFormat(Company.CountryCode, Company.VatNumber))
|
||||||
Company.LastVisit = $"{LastVisit:yyyy-MM-dd}";
|
|
||||||
Company.NextVisit = $"{NextVisit:yyyy-MM-dd}";
|
|
||||||
|
|
||||||
var newId = await CompanyRepo.CreateCompany(Company);
|
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(newId))
|
|
||||||
{
|
{
|
||||||
Toaster.ShowSuccess($"'{Company.Name}' er oprettet i CRM.");
|
Toaster.ShowError("Momsnummber er ikke korrekt.");
|
||||||
Navigator.NavigateTo($"/advisor/customers/{newId}");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Toaster.ShowWarning($"'{Company.Name}' IKKE oprettet.");
|
|
||||||
FormInvalid = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
Working = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void HandleFieldChanged(object sender, FieldChangedEventArgs e)
|
|
||||||
{
|
|
||||||
NextVisit = LastVisit.AddDays(7 * Company.Interval);
|
|
||||||
// invalid vat number id not accepted by the ERP system
|
|
||||||
// but is removed without warning
|
|
||||||
// it is necessary to validate if vat number has been added
|
|
||||||
// as the format should conform to country rule of generation
|
|
||||||
if (!string.IsNullOrWhiteSpace(Company.VatNumber))
|
|
||||||
{
|
|
||||||
// validate vat number according to country
|
|
||||||
if (!VatUtils.ValidateFormat(Company.CountryCode, Company.VatNumber))
|
|
||||||
{
|
|
||||||
Toaster.ShowError("Momsnummber er ikke korrekt.");
|
|
||||||
FormInvalid = true;
|
|
||||||
Company.ValidVat = 0;
|
|
||||||
RegState = "the-ugly";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!Company.ValidDateSpan())
|
|
||||||
{
|
|
||||||
Toaster.ShowError("Dato for næste besøg skal ligge efter sidste besøg.");
|
|
||||||
FormInvalid = true;
|
FormInvalid = true;
|
||||||
|
Company.ValidVat = 0;
|
||||||
|
RegState = "the-ugly";
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
FormInvalid = !CompanyContext.Validate();
|
|
||||||
}
|
|
||||||
|
|
||||||
StateHasChanged();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ValidationChanged(object sender, ValidationStateChangedEventArgs e)
|
if (!Company.ValidDateSpan())
|
||||||
{
|
{
|
||||||
|
Toaster.ShowError("Dato for næste besøg skal ligge efter sidste besøg.");
|
||||||
FormInvalid = true;
|
FormInvalid = true;
|
||||||
|
|
||||||
CompanyContext.OnFieldChanged -= HandleFieldChanged;
|
|
||||||
|
|
||||||
CompanyContext = new EditContext(Company);
|
|
||||||
|
|
||||||
FormInvalid = !CompanyContext.Validate();
|
|
||||||
|
|
||||||
CompanyContext.OnFieldChanged += HandleFieldChanged;
|
|
||||||
CompanyContext.OnValidationStateChanged -= ValidationChanged;
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
public void Dispose()
|
|
||||||
{
|
{
|
||||||
Interceptor.DisposeEvent();
|
FormInvalid = !CompanyContext.Validate();
|
||||||
CompanyContext.OnFieldChanged -= HandleFieldChanged;
|
|
||||||
CompanyContext.OnValidationStateChanged -= ValidationChanged;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
StateHasChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ValidationChanged(object sender, ValidationStateChangedEventArgs e)
|
||||||
|
{
|
||||||
|
FormInvalid = true;
|
||||||
|
|
||||||
|
CompanyContext.OnFieldChanged -= HandleFieldChanged;
|
||||||
|
|
||||||
|
CompanyContext = new EditContext(Company);
|
||||||
|
|
||||||
|
FormInvalid = !CompanyContext.Validate();
|
||||||
|
|
||||||
|
CompanyContext.OnFieldChanged += HandleFieldChanged;
|
||||||
|
CompanyContext.OnValidationStateChanged -= ValidationChanged;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
Interceptor.DisposeEvent();
|
||||||
|
CompanyContext.OnFieldChanged -= HandleFieldChanged;
|
||||||
|
CompanyContext.OnValidationStateChanged -= ValidationChanged;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -23,40 +23,42 @@
|
||||||
<div class="sticky-top bg-dark text-light rounded-2 px-3">
|
<div class="sticky-top bg-dark text-light rounded-2 px-3">
|
||||||
<div class="row g-3">
|
<div class="row g-3">
|
||||||
<div class="col-sm-2">
|
<div class="col-sm-2">
|
||||||
<CustomerSearchColumnComponent OnChanged="SetSearchCol" />
|
<CustomerSearchColumnComponent OnChanged="SetSearchCol"/>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-sm-6">
|
<div class="col-sm-6">
|
||||||
<CustomerSearchPhraseComponent OnChanged="SetSearchPhrase" />
|
<CustomerSearchPhraseComponent OnChanged="SetSearchPhrase"/>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-sm-2">
|
<div class="col-sm-2">
|
||||||
<CustomerSortComponent OnChanged="SetSortCol" />
|
<CustomerSortComponent OnChanged="SetSortCol"/>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-sm-2">
|
<div class="col-sm-2">
|
||||||
<PageSizeComponent OnChanged="SetPageSize" />
|
<PageSizeComponent OnChanged="SetPageSize"/>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-sm-3">
|
<div class="col-sm-2 mx-auto">
|
||||||
<button type button class="btn btn-warning @(ShowFolded ? "active" : "")"
|
<button type button class="btn btn-warning @(ShowFolded ? "active" : "")"
|
||||||
data-bs-toggle="button" aria-pressed="@ShowFolded" @onclick="OnFoldedClick">
|
data-bs-toggle="button" aria-pressed="@ShowFolded" @onclick="ToggleFolded">
|
||||||
@ButtonFoldedText
|
@ToggleFoldedText
|
||||||
</button>
|
|
||||||
<button type button class="btn btn-warning @(@ShowHidden ? "active" : "")"
|
|
||||||
data-bs-toggle="button" aria-pressed="@ShowHidden" @onclick="OnHiddenClick">
|
|
||||||
@ButtonHiddenText
|
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-sm-7">
|
<div class="col-sm-2 mx-auto">
|
||||||
|
<button type button class="btn btn-warning @(@ShowHidden ? "active" : "")"
|
||||||
|
data-bs-toggle="button" aria-pressed="@ShowHidden" @onclick="ToggleHidden">
|
||||||
|
@ToggleHiddenText
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-5">
|
||||||
<PaginationComponent MetaData="PageData" Spread="2" SelectedPage="SelectedPage"/>
|
<PaginationComponent MetaData="PageData" Spread="2" SelectedPage="SelectedPage"/>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-sm-2 text-end">
|
<div class="col-sm-1">@* placeholder *@</div>
|
||||||
|
<div class="col-sm-2 mx-auto">
|
||||||
<a class="btn btn-success text-nowrap" href="/advisor/customers/new">Opret kunde <i class="bi-plus"></i></a>
|
<a class="btn btn-success text-nowrap" href="/advisor/customers/new">Opret kunde <i class="bi-plus"></i></a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<AdvisorCustomerListComponent CompanyList="CompanyList" OnDelete="DeleteCompany" />
|
<AdvisorCustomerListComponent CompanyList="CompanyList" OnDelete="DeleteCompany"/>
|
||||||
|
|
||||||
@if (Working)
|
@if (Working)
|
||||||
{
|
{
|
||||||
<WorkingThreeDots />
|
<WorkingThreeDots/>
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
// Copyright (C) 2022 FCS Frede's Computer Services.
|
// Copyright (C) 2022 FCS Frede's Computer Services.
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// This program is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU Affero General Public License as
|
// it under the terms of the GNU Affero General Public License as
|
||||||
|
@ -22,147 +21,147 @@ using Wonky.Client.Services;
|
||||||
using Wonky.Entity.DTO;
|
using Wonky.Entity.DTO;
|
||||||
using Wonky.Entity.Requests;
|
using Wonky.Entity.Requests;
|
||||||
using Wonky.Entity.Views;
|
using Wonky.Entity.Views;
|
||||||
|
|
||||||
#pragma warning disable CS8618
|
#pragma warning disable CS8618
|
||||||
|
|
||||||
namespace Wonky.Client.Pages
|
namespace Wonky.Client.Pages;
|
||||||
|
|
||||||
|
public partial class AdvisorCustomerListPage : IDisposable
|
||||||
{
|
{
|
||||||
public partial class AdvisorCustomerListPage : IDisposable
|
[Inject] public ILocalStorageService Storage { get; set; }
|
||||||
|
[Inject] public UserProfileService ProfileService { get; set; }
|
||||||
|
[Inject] public IAdvisorCustomerRepository CompanyRepo { get; set; }
|
||||||
|
[Inject] public HttpInterceptorService Interceptor { get; set; }
|
||||||
|
[Inject] public NavigationManager Navigator { get; set; }
|
||||||
|
[Inject] public IUserInfoService UserInfoService { get; set; }
|
||||||
|
|
||||||
|
private List<CompanyDto> CompanyList { get; set; } = new();
|
||||||
|
private UserProfile Profile { get; set; } = new();
|
||||||
|
private UserManagerEditView UserInfo { get; set; } = new();
|
||||||
|
private string SavedSearch { get; set; } = "";
|
||||||
|
private bool Working { get; set; } = true;
|
||||||
|
private MetaData PageData { get; set; } = new();
|
||||||
|
private CustomerPaging Paging { get; set; } = new();
|
||||||
|
private string ToggleFoldedText { get; set; } = "Vis Lukkede";
|
||||||
|
private bool ShowFolded { get; set; }
|
||||||
|
private string ToggleHiddenText { get; set; } = "Inkl. Skjulte";
|
||||||
|
private bool ShowHidden { get; set; }
|
||||||
|
|
||||||
|
protected override void OnParametersSet()
|
||||||
{
|
{
|
||||||
[Inject] public ILocalStorageService Storage { get; set; }
|
Interceptor.RegisterEvent();
|
||||||
[Inject] public UserProfileService ProfileService { get; set; }
|
Interceptor.RegisterBeforeSendEvent();
|
||||||
[Inject] public IAdvisorCustomerRepository CompanyRepo { get; set; }
|
}
|
||||||
[Inject] public HttpInterceptorService Interceptor { get; set; }
|
|
||||||
[Inject] public NavigationManager Navigator { get; set; }
|
protected override async Task OnInitializedAsync()
|
||||||
[Inject] public IUserInfoService UserInfoService { get; set; }
|
{
|
||||||
|
// set preferences
|
||||||
|
Profile = await ProfileService.GetProfile();
|
||||||
|
UserInfo = await UserInfoService.GetUserInfo();
|
||||||
|
Paging.OrderBy = Profile.CompanySort;
|
||||||
|
Paging.SearchColumn = Profile.CompanySearch;
|
||||||
|
Paging.PageSize = Convert.ToInt32(Profile.PageSize);
|
||||||
|
Paging.HasFolded = ShowFolded ? 1 : 0;
|
||||||
|
|
||||||
|
// load saved search
|
||||||
|
SavedSearch = string.IsNullOrWhiteSpace(Profile.CompanyFilterPhrase) ? "" : Profile.CompanyFilterPhrase;
|
||||||
|
Paging.SearchTerm = SavedSearch;
|
||||||
|
|
||||||
|
|
||||||
private List<CompanyDto> CompanyList { get; set; } = new();
|
// get companies
|
||||||
private UserProfile Profiles { get; set; } = new();
|
await FetchCustomers();
|
||||||
private UserManagerEditView XUserInfo { get; set; } = new();
|
Working = false;
|
||||||
private string SavedSearch { get; set; } = "";
|
}
|
||||||
private bool Working { get; set; } = true;
|
|
||||||
private MetaData PageData { get; set; } = new();
|
private async Task ToggleFolded()
|
||||||
private CustomerPaging Paging { get; set; } = new();
|
{
|
||||||
private string ButtonFoldedText { get; set; } = "Vis Ophørte";
|
Working = true;
|
||||||
private bool ShowFolded { get; set; }
|
ShowFolded = !ShowFolded;
|
||||||
private string ButtonHiddenText { get; set; } = "Vis Skjulte";
|
ToggleFoldedText = ShowFolded ? "Normal Visning" : "Vis Lukkede";
|
||||||
private bool ShowHidden { get; set; }
|
CompanyList = new List<CompanyDto>();
|
||||||
protected override void OnParametersSet()
|
Paging.PageNumber = 1;
|
||||||
|
Paging.HasFolded = ShowFolded ? 1 : 0;
|
||||||
|
await FetchCustomers();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task ToggleHidden()
|
||||||
|
{
|
||||||
|
Working = true;
|
||||||
|
ShowHidden = !ShowHidden;
|
||||||
|
ToggleHiddenText = ShowHidden ? "Normal Visning" : "Inkl. Skjulte";
|
||||||
|
CompanyList = new List<CompanyDto>();
|
||||||
|
Paging.PageNumber = 1;
|
||||||
|
Paging.IsHidden = ShowHidden ? 1 : 0;
|
||||||
|
await FetchCustomers();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task SelectedPage(int page)
|
||||||
|
{
|
||||||
|
CompanyList = new List<CompanyDto>();
|
||||||
|
Paging.PageNumber = page;
|
||||||
|
await FetchCustomers();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task SetSearchCol(string searchColumn)
|
||||||
|
{
|
||||||
|
CompanyList = new List<CompanyDto>();
|
||||||
|
Paging.SearchColumn = searchColumn;
|
||||||
|
Paging.PageNumber = 1;
|
||||||
|
await FetchCustomers();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task SetPageSize(string pageSize)
|
||||||
|
{
|
||||||
|
CompanyList = new List<CompanyDto>();
|
||||||
|
Paging.PageSize = Convert.ToInt32(pageSize);
|
||||||
|
Paging.PageNumber = 1;
|
||||||
|
await FetchCustomers();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task SetSearchPhrase(string searchTerm)
|
||||||
|
{
|
||||||
|
CompanyList = new List<CompanyDto>();
|
||||||
|
Paging.PageNumber = 1;
|
||||||
|
Paging.SearchTerm = searchTerm;
|
||||||
|
await FetchCustomers();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task SetSortCol(string orderBy)
|
||||||
|
{
|
||||||
|
CompanyList = new List<CompanyDto>();
|
||||||
|
Paging.OrderBy = orderBy;
|
||||||
|
await FetchCustomers();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Removes a company from CRM
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="companyId"></param>
|
||||||
|
private async Task DeleteCompany(string companyId)
|
||||||
|
{
|
||||||
|
CompanyList = new List<CompanyDto>();
|
||||||
|
await CompanyRepo.DeleteCompany(companyId);
|
||||||
|
if (Paging.PageNumber > 1 && CompanyList.Count == 1)
|
||||||
|
Paging.PageNumber--;
|
||||||
|
await FetchCustomers();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task FetchCustomers()
|
||||||
|
{
|
||||||
|
Working = true;
|
||||||
|
var pageRes = await CompanyRepo.GetCompanies(Paging);
|
||||||
|
Working = false;
|
||||||
|
if (pageRes.Items.Any())
|
||||||
{
|
{
|
||||||
Interceptor.RegisterEvent();
|
CompanyList = pageRes.Items;
|
||||||
Interceptor.RegisterBeforeSendEvent();
|
PageData = pageRes.MetaData;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
protected override async Task OnInitializedAsync()
|
|
||||||
{
|
|
||||||
// set preferences
|
|
||||||
Profiles = await ProfileService.GetProfile();
|
|
||||||
XUserInfo = await UserInfoService.GetUserInfo();
|
|
||||||
Paging.OrderBy = Profiles.CompanySort;
|
|
||||||
Paging.SearchColumn = Profiles.CompanySearch;
|
|
||||||
Paging.PageSize = Convert.ToInt32(Profiles.PageSize);
|
|
||||||
Paging.HasFolded = ShowFolded ? 1 : 0;
|
|
||||||
|
|
||||||
// load saved search
|
|
||||||
SavedSearch = string.IsNullOrWhiteSpace(Profiles.CompanyFilterPhrase) ? "" : Profiles.CompanyFilterPhrase;
|
|
||||||
Paging.SearchTerm = SavedSearch;
|
|
||||||
|
|
||||||
// get companies
|
|
||||||
await FetchCustomers();
|
|
||||||
Working = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task OnFoldedClick()
|
|
||||||
{
|
|
||||||
Working = true;
|
|
||||||
ShowFolded = !ShowFolded;
|
|
||||||
ButtonFoldedText = ShowFolded ? "Vis Aktive" : "Vis Ophørte";
|
|
||||||
CompanyList = new List<CompanyDto>();
|
|
||||||
Paging.PageNumber = 1;
|
|
||||||
Paging.HasFolded = ShowFolded ? 1 : 0;
|
|
||||||
await FetchCustomers();
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task OnHiddenClick()
|
|
||||||
{
|
|
||||||
Working = true;
|
|
||||||
ShowHidden = !ShowHidden;
|
|
||||||
ButtonHiddenText = ShowHidden ? "Vis Normale" : "Vis skjulte";
|
|
||||||
CompanyList = new List<CompanyDto>();
|
|
||||||
Paging.PageNumber = 1;
|
|
||||||
Paging.IsHidden = ShowHidden ? 1 : 0;
|
|
||||||
await FetchCustomers();
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task SelectedPage(int page)
|
|
||||||
{
|
{
|
||||||
CompanyList = new List<CompanyDto>();
|
CompanyList = new List<CompanyDto>();
|
||||||
Paging.PageNumber = page;
|
PageData = new MetaData();
|
||||||
await FetchCustomers();
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task SetSearchCol(string searchColumn)
|
|
||||||
{
|
|
||||||
CompanyList = new List<CompanyDto>();
|
|
||||||
Paging.SearchColumn = searchColumn;
|
|
||||||
Paging.PageNumber = 1;
|
|
||||||
await FetchCustomers();
|
|
||||||
}
|
|
||||||
private async Task SetPageSize(string pageSize)
|
|
||||||
{
|
|
||||||
CompanyList = new List<CompanyDto>();
|
|
||||||
Paging.PageSize = Convert.ToInt32(pageSize);
|
|
||||||
Paging.PageNumber = 1;
|
|
||||||
await FetchCustomers();
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private async Task SetSearchPhrase(string searchTerm)
|
public void Dispose() => Interceptor.DisposeEvent();
|
||||||
{
|
}
|
||||||
CompanyList = new List<CompanyDto>();
|
|
||||||
Paging.PageNumber = 1;
|
|
||||||
Paging.SearchTerm = searchTerm;
|
|
||||||
await FetchCustomers();
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task SetSortCol(string orderBy)
|
|
||||||
{
|
|
||||||
CompanyList = new List<CompanyDto>();
|
|
||||||
Paging.OrderBy = orderBy;
|
|
||||||
await FetchCustomers();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Removes a company from CRM
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="companyId"></param>
|
|
||||||
private async Task DeleteCompany(string companyId)
|
|
||||||
{
|
|
||||||
CompanyList = new List<CompanyDto>();
|
|
||||||
await CompanyRepo.DeleteCompany(companyId);
|
|
||||||
if (Paging.PageNumber > 1 && CompanyList.Count == 1)
|
|
||||||
Paging.PageNumber--;
|
|
||||||
await FetchCustomers();
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task FetchCustomers()
|
|
||||||
{
|
|
||||||
Working = true;
|
|
||||||
var pageRes = await CompanyRepo.GetCompanies(Paging);
|
|
||||||
Working = false;
|
|
||||||
if (pageRes.Items.Any())
|
|
||||||
{
|
|
||||||
CompanyList = pageRes.Items;
|
|
||||||
PageData = pageRes.MetaData;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
CompanyList = new List<CompanyDto>();
|
|
||||||
PageData = new MetaData();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose() => Interceptor.DisposeEvent();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
|
@ -36,85 +36,86 @@
|
||||||
// erp context
|
// erp context
|
||||||
<EditForm EditContext="ErpContext">
|
<EditForm EditContext="ErpContext">
|
||||||
<DataAnnotationsValidator/>
|
<DataAnnotationsValidator/>
|
||||||
<div class="row g-3">
|
<div class="row g-1">
|
||||||
@* Company Name *@
|
@* Company Name *@
|
||||||
<label for="name" class="col-sm-1 col-form-label-sm">Navn</label>
|
<label for="name" class="col-sm-1 col-form-label-sm">Navn</label>
|
||||||
<div class="col-sm-5">
|
<div class="col-sm-5">
|
||||||
<InputText id="name" class="form-control" @bind-Value="Company.Name"/>
|
<InputText id="name" class="form-control" @bind-Value="Company.Name" readonly="@(ErpEditDisabled)"/>
|
||||||
<ValidationMessage For="@(() => Company.Name)"></ValidationMessage>
|
<ValidationMessage For="@(() => Company.Name)"></ValidationMessage>
|
||||||
</div>
|
</div>
|
||||||
@* Company Attention *@
|
@* Company Attention *@
|
||||||
<label for="attention" class="col-sm-1 col-form-label-sm">Att.</label>
|
<label for="attention" class="col-sm-1 col-form-label-sm">Att.</label>
|
||||||
<div class="col-sm-5">
|
<div class="col-sm-5">
|
||||||
<InputText id="attention" class="form-control" @bind-Value="Company.Attention"/>
|
<InputText id="attention" class="form-control" @bind-Value="Company.Attention" readonly="@(ErpEditDisabled)"/>
|
||||||
<ValidationMessage For="@(() => Company.Attention)"></ValidationMessage>
|
<ValidationMessage For="@(() => Company.Attention)"></ValidationMessage>
|
||||||
</div>
|
</div>
|
||||||
@* Address 1 *@
|
@* Address 1 *@
|
||||||
<label for="address1" class="col-sm-1 col-form-label-sm">Adresse</label>
|
<label for="address1" class="col-sm-1 col-form-label-sm">Adresse</label>
|
||||||
<div class="col-sm-5">
|
<div class="col-sm-5">
|
||||||
<InputText id="address1" class="form-control" @bind-Value="Company.Address1"/>
|
<InputText id="address1" class="form-control" @bind-Value="Company.Address1" readonly="@(ErpEditDisabled)"/>
|
||||||
<ValidationMessage For="@(() => Company.Address1)"></ValidationMessage>
|
<ValidationMessage For="@(() => Company.Address1)"></ValidationMessage>
|
||||||
</div>
|
</div>
|
||||||
@* Address 2 *@
|
@* Address 2 *@
|
||||||
<label for="address2" class="col-sm-1 col-form-label-sm">Adresse</label>
|
<label for="address2" class="col-sm-1 col-form-label-sm">Adresse</label>
|
||||||
<div class="col-sm-5">
|
<div class="col-sm-5">
|
||||||
<InputText id="address2" class="form-control" @bind-Value="Company.Address2"/>
|
<InputText id="address2" class="form-control" @bind-Value="Company.Address2" readonly="@(ErpEditDisabled)"/>
|
||||||
<ValidationMessage For="@(() => Company.Address2)"></ValidationMessage>
|
<ValidationMessage For="@(() => Company.Address2)"></ValidationMessage>
|
||||||
</div>
|
</div>
|
||||||
@* Post Code *@
|
@* Post Code *@
|
||||||
<label for="zipCode" class="col-sm-1 col-form-label-sm">PostNr</label>
|
<label for="zipCode" class="col-sm-1 col-form-label-sm">PostNr</label>
|
||||||
<div class="col-sm-2">
|
<div class="col-sm-2">
|
||||||
<InputText id="zipCode" class="form-control" @bind-Value="Company.ZipCode"/>
|
<InputText id="zipCode" class="form-control" @bind-Value="Company.ZipCode" readonly="@(ErpEditDisabled)"/>
|
||||||
<ValidationMessage For="@(() => Company.ZipCode)"></ValidationMessage>
|
<ValidationMessage For="@(() => Company.ZipCode)"></ValidationMessage>
|
||||||
</div>
|
</div>
|
||||||
@* City Name *@
|
@* City Name *@
|
||||||
<label for="city" class="col-sm-1 col-form-label-sm">Bynavn</label>
|
<label for="city" class="col-sm-1 col-form-label-sm">Bynavn</label>
|
||||||
<div class="col-sm-8">
|
<div class="col-sm-8">
|
||||||
<InputText id="city" class="form-control" @bind-Value="Company.City"/>
|
<InputText id="city" class="form-control" @bind-Value="Company.City" readonly="@(ErpEditDisabled)"/>
|
||||||
<ValidationMessage For="@(() => Company.City)"></ValidationMessage>
|
<ValidationMessage For="@(() => Company.City)"></ValidationMessage>
|
||||||
</div>
|
</div>
|
||||||
@* Phone *@
|
@* Phone *@
|
||||||
<label for="phone" class="col-sm-1 col-form-label-sm">Telefon</label>
|
<label for="phone" class="col-sm-1 col-form-label-sm">Telefon</label>
|
||||||
<div class="col-sm-3">
|
<div class="col-sm-2">
|
||||||
<InputText id="phone" class="form-control" @bind-Value="Company.Phone"/>
|
<InputText id="phone" class="form-control" @bind-Value="Company.Phone" readonly="@(ErpEditDisabled)"/>
|
||||||
<ValidationMessage For="@(() => Company.Phone)"></ValidationMessage>
|
<ValidationMessage For="@(() => Company.Phone)"></ValidationMessage>
|
||||||
</div>
|
</div>
|
||||||
@* Mobile *@
|
@* Mobile *@
|
||||||
<label for="mobile" class="col-sm-1 col-form-label-sm">Mobil</label>
|
<label for="mobile" class="col-sm-1 col-form-label-sm">Mobil</label>
|
||||||
<div class="col-sm-3">
|
<div class="col-sm-2">
|
||||||
<InputText id="mobile" class="form-control" @bind-Value="Company.Mobile"/>
|
<InputText id="mobile" class="form-control" @bind-Value="Company.Mobile" readonly="@(ErpEditDisabled)"/>
|
||||||
<ValidationMessage For="@(() => Company.Mobile)"></ValidationMessage>
|
<ValidationMessage For="@(() => Company.Mobile)"></ValidationMessage>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-sm-4 d-grid mx-auto">
|
|
||||||
<button type="button" class="btn btn-danger" @onclick="ToggleVisibility">@ToggleButtonText</button>
|
|
||||||
</div>
|
|
||||||
@* Email *@
|
@* Email *@
|
||||||
<label for="email" class="col-sm-1 col-form-label-sm">Epost</label>
|
<label for="email" class="col-sm-1 col-form-label-sm">Epost</label>
|
||||||
<div class="col-sm-5">
|
<div class="col-sm-5">
|
||||||
<InputText id="email" class="form-control" @bind-Value="Company.Email"/>
|
<InputText id="email" class="form-control" @bind-Value="Company.Email" readonly="@(ErpEditDisabled)"/>
|
||||||
<ValidationMessage For="@(() => Company.Email)"></ValidationMessage>
|
<ValidationMessage For="@(() => Company.Email)"></ValidationMessage>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-sm-3 d-grid mx-auto">
|
<div class="col-sm-4">@* ---- placeholder --- *@</div>
|
||||||
<button type="button" class="btn btn-primary d-block" disabled="@(Company.HasFolded == 0 || Company.Name == "ERROR")" onclick="@ForceActivity">Aktiver besøg</button>
|
<div class="col-sm-2 d-grid mx-auto">
|
||||||
|
<button type="button" class="btn btn-edit" @onclick="ToggleErpEdit"><i class="bi-pencil"></i> STAM data</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-sm-3 d-grid mx-auto">
|
<div class="col-sm-3 d-grid mx-auto">
|
||||||
<button type="button" class="btn btn-danger d-block" onclick="@UpdateErpData" disabled="@(Working || Company.Name == "ERROR")"><i class="bi-cloud-arrow-up"></i> STAM data </button>
|
<button type="button" class="btn btn-primary d-block" disabled="@(Company.HasFolded == 0 || Company.Name == "ERROR")" @onclick="ForceActivity">Aktiver besøg</button>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-3 d-grid mx-auto">
|
||||||
|
<button type="button" class="btn btn-danger d-block" onclick="@UpdateErpData" disabled="@(Working || Company.Name == "ERROR" || ErpEditDisabled)"><i class="bi-cloud-arrow-up"></i> STAM data </button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
<hr class="mb-3"/>
|
|
||||||
<div class="row">
|
|
||||||
@* vat number*@
|
@* vat number*@
|
||||||
<label for="vatNumber" class="col-sm-2 col-form-label-sm">CVR/Org nr.</label>
|
<label for="vatNumber" class="col-sm-1 col-form-label-sm">CVR/Org nr.</label>
|
||||||
<div class="col-sm-4">
|
<div class="col-sm-3">
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<span class="input-group-text">
|
<span class="input-group-text">
|
||||||
<DisplayStateComponent StateClass="@VatState"/>
|
<DisplayStateComponent StateClass="@VatState"/>
|
||||||
</span>
|
</span>
|
||||||
<InputText id="vatNumber" class="form-control" @bind-Value="Company.VatNumber"/>
|
<InputText id="vatNumber" class="form-control" @bind-Value="Company.VatNumber" readonly="@(VatEditDisabled)"/>
|
||||||
<ValidationMessage For="@(() => Company.VatNumber)"></ValidationMessage>
|
<ValidationMessage For="@(() => Company.VatNumber)"></ValidationMessage>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="col-sm-2 d-grid mx-auto">
|
||||||
|
<button type="button" class="btn btn-edit" @onclick="ToggleVatEdit"><i class="bi-pencil"></i> Moms/Org Nr.</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
@* vat lookup *@
|
@* vat lookup *@
|
||||||
<div class="col-sm-3 d-grid mx-auto">
|
<div class="col-sm-3 d-grid mx-auto">
|
||||||
@switch (CountryCode)
|
@switch (CountryCode)
|
||||||
|
@ -132,7 +133,7 @@
|
||||||
</div>
|
</div>
|
||||||
@* save vat number *@
|
@* save vat number *@
|
||||||
<div class="col-sm-3 d-grid mx-auto">
|
<div class="col-sm-3 d-grid mx-auto">
|
||||||
<button type="button" class="btn btn-warning d-block" @onclick="UpdateVatNumber"><i class="bi-cloud-arrow-up"></i> Moms/Org Nr.</button>
|
<button type="button" class="btn btn-warning d-block" @onclick="UpdateVatNumber" disabled="@(VatEditDisabled)"><i class="bi-cloud-arrow-up"></i> Moms/Org Nr.</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -240,6 +241,11 @@
|
||||||
<InputTextArea id="crmNotes" class="form-control" @bind-Value="Company.CrmNotes"/>
|
<InputTextArea id="crmNotes" class="form-control" @bind-Value="Company.CrmNotes"/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="row pt-3">
|
||||||
|
<div class="col-sm-3 d-grid">
|
||||||
|
<button type="button" class="btn btn-danger" @onclick="ToggleVisibility">@ToggleButtonText</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</EditForm>
|
</EditForm>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
// Copyright (C) 2022 FCS Frede's Computer Services.
|
// Copyright (C) 2022 FCS Frede's Computer Services.
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// This program is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU Affero General Public License as
|
// it under the terms of the GNU Affero General Public License as
|
||||||
|
@ -28,7 +27,7 @@ using Wonky.Client.Services;
|
||||||
using Wonky.Client.Shared;
|
using Wonky.Client.Shared;
|
||||||
using Wonky.Entity.DTO;
|
using Wonky.Entity.DTO;
|
||||||
using Wonky.Entity.Models;
|
using Wonky.Entity.Models;
|
||||||
using Wonky.Entity.Views;
|
|
||||||
#pragma warning disable CS8618
|
#pragma warning disable CS8618
|
||||||
|
|
||||||
namespace Wonky.Client.Pages;
|
namespace Wonky.Client.Pages;
|
||||||
|
@ -46,8 +45,8 @@ public partial class AdvisorCustomerViewEditPage : IDisposable
|
||||||
[Inject] public VatInfoLookupService VatService { get; set; }
|
[Inject] public VatInfoLookupService VatService { get; set; }
|
||||||
[Inject] public ILocalStorageService Storage { get; set; }
|
[Inject] public ILocalStorageService Storage { get; set; }
|
||||||
[Inject] public IUserInfoService UserInfoService { get; set; }
|
[Inject] public IUserInfoService UserInfoService { get; set; }
|
||||||
|
|
||||||
private readonly JsonSerializerOptions _options = new () { PropertyNameCaseInsensitive = true };
|
private readonly JsonSerializerOptions _options = new() { PropertyNameCaseInsensitive = true };
|
||||||
private CompanyDto Company { get; set; } = new();
|
private CompanyDto Company { get; set; } = new();
|
||||||
private EditContext ErpContext { get; set; }
|
private EditContext ErpContext { get; set; }
|
||||||
private DateTime LastVisit { get; set; }
|
private DateTime LastVisit { get; set; }
|
||||||
|
@ -63,6 +62,8 @@ public partial class AdvisorCustomerViewEditPage : IDisposable
|
||||||
private string ActionLink { get; set; } = "";
|
private string ActionLink { get; set; } = "";
|
||||||
private bool Working { get; set; } = true;
|
private bool Working { get; set; } = true;
|
||||||
private bool CountryIsDk { get; set; } = true;
|
private bool CountryIsDk { get; set; } = true;
|
||||||
|
private bool ErpEditDisabled { get; set; } = true;
|
||||||
|
private bool VatEditDisabled { get; set; } = true;
|
||||||
private List<ContactDto> Contacts { get; set; } = new();
|
private List<ContactDto> Contacts { get; set; } = new();
|
||||||
private VatLookupDkModal VatLookupPopup { get; set; } = new();
|
private VatLookupDkModal VatLookupPopup { get; set; } = new();
|
||||||
private ContactDto SelectedContact { get; set; } = new();
|
private ContactDto SelectedContact { get; set; } = new();
|
||||||
|
@ -70,7 +71,7 @@ public partial class AdvisorCustomerViewEditPage : IDisposable
|
||||||
private ContactModal ContactPopup { get; set; } = new();
|
private ContactModal ContactPopup { get; set; } = new();
|
||||||
private UserManagerEditView UserInfo { get; set; } = new();
|
private UserManagerEditView UserInfo { get; set; } = new();
|
||||||
private string ToggleButtonText { get; set; } = "";
|
private string ToggleButtonText { get; set; } = "";
|
||||||
|
|
||||||
protected override async Task OnInitializedAsync()
|
protected override async Task OnInitializedAsync()
|
||||||
{
|
{
|
||||||
// setup interceptor
|
// setup interceptor
|
||||||
|
@ -78,25 +79,26 @@ public partial class AdvisorCustomerViewEditPage : IDisposable
|
||||||
Interceptor.RegisterBeforeSendEvent();
|
Interceptor.RegisterBeforeSendEvent();
|
||||||
|
|
||||||
// initialize default contact
|
// initialize default contact
|
||||||
DefaultContact = new ContactDto { CompanyId = CompanyId, ContactId = "", FirstName = ""};
|
DefaultContact = new ContactDto { CompanyId = CompanyId, ContactId = "", FirstName = "" };
|
||||||
// setup form context
|
// setup form context
|
||||||
ErpContext = new EditContext(Company);
|
ErpContext = new EditContext(Company);
|
||||||
|
|
||||||
// assign event handlers to context
|
// assign event handlers to context
|
||||||
ErpContext.OnFieldChanged += HandleFieldChanged;
|
ErpContext.OnFieldChanged += HandleFieldChanged;
|
||||||
ErpContext.OnValidationStateChanged += ValidationChanged;
|
ErpContext.OnValidationStateChanged += ValidationChanged;
|
||||||
|
|
||||||
// fetch user info from local storage
|
// fetch user info from local storage
|
||||||
UserInfo = await UserInfoService.GetUserInfo();
|
UserInfo = await UserInfoService.GetUserInfo();
|
||||||
CountryCode = UserInfo.CountryCode.ToLower();
|
CountryCode = UserInfo.CountryCode.ToLower();
|
||||||
CountryIsDk = CountryCode == "dk";
|
CountryIsDk = CountryCode == "dk";
|
||||||
|
|
||||||
Logger.LogDebug("companyId => {}", CompanyId);
|
Logger.LogDebug("companyId => {}", CompanyId);
|
||||||
|
|
||||||
Company = await CustomerRepo.GetCompanyById(CompanyId);
|
Company = await CustomerRepo.GetCompanyById(CompanyId);
|
||||||
|
|
||||||
Logger.LogDebug("company => {}", JsonSerializer.Serialize(Company));
|
Logger.LogDebug("company => {}", JsonSerializer.Serialize(Company));
|
||||||
ToggleButtonText = Company.IsHidden == 0 ? "Skjul kunde" : "Vis kunde";
|
// toggle view button text
|
||||||
|
ToggleButtonText = Company.IsHidden == 0 ? "Udelad kunde i oversigt" : "Brug Normal Visning";
|
||||||
CurrentVat = Company.VatNumber;
|
CurrentVat = Company.VatNumber;
|
||||||
Company.CountryCode = UserInfo.CountryCode.ToLower();
|
Company.CountryCode = UserInfo.CountryCode.ToLower();
|
||||||
// internal flag
|
// internal flag
|
||||||
|
@ -121,7 +123,7 @@ public partial class AdvisorCustomerViewEditPage : IDisposable
|
||||||
// action link passed to activity button component
|
// action link passed to activity button component
|
||||||
ActionLink = $"/advisor/customers/{CompanyId}/activities/new"; // used when drawing visit button
|
ActionLink = $"/advisor/customers/{CompanyId}/activities/new"; // used when drawing visit button
|
||||||
// handle company out of business case
|
// handle company out of business case
|
||||||
if(Company.HasFolded == 1)
|
if (Company.HasFolded == 1)
|
||||||
{
|
{
|
||||||
// this is only used if user has selected to show closed companies
|
// this is only used if user has selected to show closed companies
|
||||||
HasFolded = true;
|
HasFolded = true;
|
||||||
|
@ -135,36 +137,49 @@ public partial class AdvisorCustomerViewEditPage : IDisposable
|
||||||
// valid vat flag
|
// valid vat flag
|
||||||
ValidVat = Company.ValidVat == 1; // true/false flag set if company has a valid vatNumber
|
ValidVat = Company.ValidVat == 1; // true/false flag set if company has a valid vatNumber
|
||||||
// vat state css class
|
// vat state css class
|
||||||
VatState = Company.ValidVat == 1 ? "the-good" : "no-vat"; // assign css class
|
VatState = Company.ValidVat == 1 ? "the-good" : "no-vat"; // assign css class
|
||||||
}
|
}
|
||||||
|
|
||||||
// create search address from address
|
// create search address from address
|
||||||
if (CountryIsDk)
|
if (CountryIsDk)
|
||||||
CompanyVatAddress = PrepareVatAddress(Company);
|
CompanyVatAddress = PrepareVatAddress(Company);
|
||||||
|
|
||||||
await FetchContacts(CompanyId);
|
await FetchContacts(CompanyId);
|
||||||
|
|
||||||
// remove loading image
|
// remove loading image
|
||||||
Working = false;
|
Working = false;
|
||||||
await Task.Delay(100);
|
await Task.Delay(100);
|
||||||
await RequestErpUpdate();
|
await RequestErpUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void ToggleErpEdit()
|
||||||
|
{
|
||||||
|
ErpEditDisabled = !ErpEditDisabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ToggleVatEdit()
|
||||||
|
{
|
||||||
|
VatEditDisabled = !VatEditDisabled;
|
||||||
|
}
|
||||||
|
|
||||||
private async Task ToggleVisibility()
|
private async Task ToggleVisibility()
|
||||||
{
|
{
|
||||||
Company.IsHidden = Company.IsHidden == 0 ? 1 : 0;
|
Company.IsHidden = Company.IsHidden == 0 ? 1 : 0;
|
||||||
ToggleButtonText = Company.IsHidden == 0 ? "Skjul kunde" : "Vis kunde";
|
// toggle view button text
|
||||||
|
ToggleButtonText = Company.IsHidden == 0 ? "Udelad kunde i oversigt" : "Brug Normal Visning";
|
||||||
Logger.LogDebug("ToggleVisibility => Company.IsHidden == {}", Company.IsHidden);
|
Logger.LogDebug("ToggleVisibility => Company.IsHidden == {}", Company.IsHidden);
|
||||||
await CustomerRepo.UpdateCrmData(CompanyId, Company);
|
await CustomerRepo.UpdateCrmData(CompanyId, Company);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task RequestErpUpdate()
|
private async Task RequestErpUpdate()
|
||||||
{
|
{
|
||||||
if(Working)
|
if (Working)
|
||||||
return;
|
return;
|
||||||
Working = true;
|
Working = true;
|
||||||
Company.HistorySync = await HistoryRepo.InvoiceErpToCrmRpc(CompanyId, Company.HistorySync);
|
Company.HistorySync = await HistoryRepo.InvoiceErpToCrmRpc(CompanyId, Company.HistorySync);
|
||||||
Working = false;
|
Working = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Fetch contacts from backend
|
/// Fetch contacts from backend
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -173,7 +188,7 @@ public partial class AdvisorCustomerViewEditPage : IDisposable
|
||||||
{
|
{
|
||||||
// load contacts
|
// load contacts
|
||||||
Contacts = await AdvisorContactRepo.GetContacts(companyId);
|
Contacts = await AdvisorContactRepo.GetContacts(companyId);
|
||||||
if(Contacts.Any() && Contacts.Count > 1)
|
if (Contacts.Any() && Contacts.Count > 1)
|
||||||
Contacts = Contacts.OrderBy(x => x.FirstName).ToList();
|
Contacts = Contacts.OrderBy(x => x.FirstName).ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -183,8 +198,8 @@ public partial class AdvisorCustomerViewEditPage : IDisposable
|
||||||
private void OpenVatLookupModal()
|
private void OpenVatLookupModal()
|
||||||
{
|
{
|
||||||
VatLookupPopup.Show();
|
VatLookupPopup.Show();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Callback to update company properties
|
/// Callback to update company properties
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -206,9 +221,10 @@ public partial class AdvisorCustomerViewEditPage : IDisposable
|
||||||
Company.ZipCode = regInfo.ZipCode;
|
Company.ZipCode = regInfo.ZipCode;
|
||||||
Company.City = regInfo.City;
|
Company.City = regInfo.City;
|
||||||
}
|
}
|
||||||
|
|
||||||
Company.VatNumber = regInfo.VatNumber;
|
Company.VatNumber = regInfo.VatNumber;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Open contact edit popup
|
/// Open contact edit popup
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -245,15 +261,16 @@ public partial class AdvisorCustomerViewEditPage : IDisposable
|
||||||
// contact modified
|
// contact modified
|
||||||
Logger.LogDebug("update => {}", jsonContact);
|
Logger.LogDebug("update => {}", jsonContact);
|
||||||
// send put request to backend
|
// send put request to backend
|
||||||
await AdvisorContactRepo.UpdateContact(contact);
|
await AdvisorContactRepo.UpdateContact(contact);
|
||||||
}
|
}
|
||||||
|
|
||||||
// reset selected contact
|
// reset selected contact
|
||||||
SelectedContact = new ContactDto();
|
SelectedContact = new ContactDto();
|
||||||
// reload contacts from backend
|
// reload contacts from backend
|
||||||
await FetchContacts(CompanyId);
|
await FetchContacts(CompanyId);
|
||||||
Working = false;
|
Working = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Delete contact callback
|
/// Delete contact callback
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -270,7 +287,7 @@ public partial class AdvisorCustomerViewEditPage : IDisposable
|
||||||
await FetchContacts(CompanyId);
|
await FetchContacts(CompanyId);
|
||||||
Working = false;
|
Working = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Update CRM data
|
/// Update CRM data
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -290,6 +307,7 @@ public partial class AdvisorCustomerViewEditPage : IDisposable
|
||||||
Company = result;
|
Company = result;
|
||||||
StateHasChanged();
|
StateHasChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
Working = false;
|
Working = false;
|
||||||
Toaster.ClearAll();
|
Toaster.ClearAll();
|
||||||
}
|
}
|
||||||
|
@ -302,6 +320,7 @@ public partial class AdvisorCustomerViewEditPage : IDisposable
|
||||||
{
|
{
|
||||||
if (Working)
|
if (Working)
|
||||||
return;
|
return;
|
||||||
|
ErpEditDisabled = true;
|
||||||
Working = true;
|
Working = true;
|
||||||
Toaster.ShowInfo("Vent venligst ...", "OPDATERER STAM DATA");
|
Toaster.ShowInfo("Vent venligst ...", "OPDATERER STAM DATA");
|
||||||
var result = await CustomerRepo.UpdateErpData(CompanyId, Company);
|
var result = await CustomerRepo.UpdateErpData(CompanyId, Company);
|
||||||
|
@ -310,6 +329,7 @@ public partial class AdvisorCustomerViewEditPage : IDisposable
|
||||||
Company = result;
|
Company = result;
|
||||||
StateHasChanged();
|
StateHasChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
Working = false;
|
Working = false;
|
||||||
Toaster.ClearAll();
|
Toaster.ClearAll();
|
||||||
}
|
}
|
||||||
|
@ -326,8 +346,10 @@ public partial class AdvisorCustomerViewEditPage : IDisposable
|
||||||
Toaster.ShowError($"Moms Nummer ugyldigt");
|
Toaster.ShowError($"Moms Nummer ugyldigt");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Working)
|
if (Working)
|
||||||
return;
|
return;
|
||||||
|
VatEditDisabled = true;
|
||||||
Working = true;
|
Working = true;
|
||||||
Toaster.ShowInfo("Vent venligst ...", "OPDATERER MOMS NUMMER");
|
Toaster.ShowInfo("Vent venligst ...", "OPDATERER MOMS NUMMER");
|
||||||
var result = await CustomerRepo.UpdateCompanyVat(CompanyId, Company.VatNumber);
|
var result = await CustomerRepo.UpdateCompanyVat(CompanyId, Company.VatNumber);
|
||||||
|
@ -336,10 +358,11 @@ public partial class AdvisorCustomerViewEditPage : IDisposable
|
||||||
Company = result;
|
Company = result;
|
||||||
StateHasChanged();
|
StateHasChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
Toaster.ClearAll();
|
Toaster.ClearAll();
|
||||||
Working = false;
|
Working = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Prepare vat address from company model
|
/// Prepare vat address from company model
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -359,6 +382,7 @@ public partial class AdvisorCustomerViewEditPage : IDisposable
|
||||||
HouseNumber = Regex.Replace(model.Address1[pos1..], "[^0-9]", "").Trim()
|
HouseNumber = Regex.Replace(model.Address1[pos1..], "[^0-9]", "").Trim()
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// process address2
|
// process address2
|
||||||
var pos2 = model.Address2.IndexOfAny(digits);
|
var pos2 = model.Address2.IndexOfAny(digits);
|
||||||
if (pos2 > 0)
|
if (pos2 > 0)
|
||||||
|
@ -370,10 +394,11 @@ public partial class AdvisorCustomerViewEditPage : IDisposable
|
||||||
HouseNumber = Regex.Replace(model.Address2[pos2..], "[^0-9]", "").Trim()
|
HouseNumber = Regex.Replace(model.Address2[pos2..], "[^0-9]", "").Trim()
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// return empty model
|
// return empty model
|
||||||
return new VatAddress();
|
return new VatAddress();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Change activity enabled state
|
/// Change activity enabled state
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -381,7 +406,7 @@ public partial class AdvisorCustomerViewEditPage : IDisposable
|
||||||
{
|
{
|
||||||
EnableActivity = EnableActivity == 0 ? 1 : 0;
|
EnableActivity = EnableActivity == 0 ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Context field change event callback
|
/// Context field change event callback
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -398,9 +423,10 @@ public partial class AdvisorCustomerViewEditPage : IDisposable
|
||||||
ValidVat = true;
|
ValidVat = true;
|
||||||
EnableActivity = 1;
|
EnableActivity = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
StateHasChanged();
|
StateHasChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Context validation change event callback
|
/// Context validation change event callback
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -410,13 +436,13 @@ public partial class AdvisorCustomerViewEditPage : IDisposable
|
||||||
{
|
{
|
||||||
ErpContext.OnFieldChanged -= HandleFieldChanged;
|
ErpContext.OnFieldChanged -= HandleFieldChanged;
|
||||||
ErpContext.OnValidationStateChanged -= ValidationChanged!;
|
ErpContext.OnValidationStateChanged -= ValidationChanged!;
|
||||||
|
|
||||||
ErpContext = new EditContext(Company);
|
ErpContext = new EditContext(Company);
|
||||||
|
|
||||||
ErpContext.OnFieldChanged += HandleFieldChanged;
|
ErpContext.OnFieldChanged += HandleFieldChanged;
|
||||||
ErpContext.OnValidationStateChanged += ValidationChanged;
|
ErpContext.OnValidationStateChanged += ValidationChanged;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Dispose
|
/// Dispose
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -16,13 +16,12 @@
|
||||||
|
|
||||||
using Microsoft.AspNetCore.Components;
|
using Microsoft.AspNetCore.Components;
|
||||||
|
|
||||||
namespace Wonky.Client.Pages
|
namespace Wonky.Client.Pages;
|
||||||
{
|
|
||||||
public partial class ErrorReportPage
|
|
||||||
{
|
|
||||||
[Parameter]
|
|
||||||
public int ErrorCode { get; set; }
|
|
||||||
|
|
||||||
[Parameter] public string ErrorDescription { get; set; } = "";
|
public partial class ErrorReportPage
|
||||||
}
|
{
|
||||||
}
|
[Parameter]
|
||||||
|
public int ErrorCode { get; set; }
|
||||||
|
|
||||||
|
[Parameter] public string ErrorDescription { get; set; } = "";
|
||||||
|
}
|
|
@ -24,123 +24,120 @@ using Wonky.Entity.Requests;
|
||||||
using Wonky.Entity.Views;
|
using Wonky.Entity.Views;
|
||||||
#pragma warning disable CS8618
|
#pragma warning disable CS8618
|
||||||
|
|
||||||
namespace Wonky.Client.Pages
|
namespace Wonky.Client.Pages;
|
||||||
|
|
||||||
|
public partial class OfficeCountryCustomerListPage : IDisposable
|
||||||
{
|
{
|
||||||
public partial class OfficeCountryCustomerListPage : IDisposable
|
[Parameter] public string CountryCode { get; set; } = "";
|
||||||
|
[Inject] public ILocalStorageService Storage { get; set; }
|
||||||
|
[Inject] public UserProfileService ProfileService { get; set; }
|
||||||
|
[Inject] public ICountryCustomerRepository CustomerRepo { get; set; }
|
||||||
|
[Inject] public HttpInterceptorService Interceptor { get; set; }
|
||||||
|
[Inject] public NavigationManager Navigator { get; set; }
|
||||||
|
[Inject] public IUserInfoService UserInfoService { get; set; }
|
||||||
|
|
||||||
|
private List<CompanyDto> Companies { get; set; } = new();
|
||||||
|
private UserProfile Profiles { get; set; } = new();
|
||||||
|
private UserManagerEditView XUserInfo { get; set; } = new();
|
||||||
|
private string SavedSearch { get; set; } = "";
|
||||||
|
private bool ShowFolded { get; set; }
|
||||||
|
private bool Working { get; set; } = true;
|
||||||
|
private MetaData PageData { get; set; } = new();
|
||||||
|
private CustomerPaging Paging { get; set; } = new();
|
||||||
|
private string ButtonFoldedText { get; set; } = "Vis Ophørte";
|
||||||
|
|
||||||
|
protected override async Task OnParametersSetAsync()
|
||||||
{
|
{
|
||||||
[Parameter] public string CountryCode { get; set; } = "";
|
Working = true;
|
||||||
[Inject] public ILocalStorageService Storage { get; set; }
|
|
||||||
[Inject] public UserProfileService ProfileService { get; set; }
|
|
||||||
[Inject] public ICountryCustomerRepository CustomerRepo { get; set; }
|
|
||||||
[Inject] public HttpInterceptorService Interceptor { get; set; }
|
|
||||||
[Inject] public NavigationManager Navigator { get; set; }
|
|
||||||
[Inject] public IUserInfoService UserInfoService { get; set; }
|
|
||||||
|
|
||||||
private List<CompanyDto> Companies { get; set; } = new();
|
|
||||||
private UserProfile Profiles { get; set; } = new();
|
|
||||||
private UserManagerEditView XUserInfo { get; set; } = new();
|
|
||||||
private string SavedSearch { get; set; } = "";
|
|
||||||
private bool ShowFolded { get; set; }
|
|
||||||
private bool Working { get; set; } = true;
|
|
||||||
private MetaData PageData { get; set; } = new();
|
|
||||||
private CustomerPaging Paging { get; set; } = new();
|
|
||||||
private string ButtonFoldedText { get; set; } = "Vis Ophørte";
|
|
||||||
|
|
||||||
protected override async Task OnParametersSetAsync()
|
|
||||||
{
|
|
||||||
Working = true;
|
|
||||||
|
|
||||||
Interceptor.RegisterEvent();
|
Interceptor.RegisterEvent();
|
||||||
Interceptor.RegisterBeforeSendEvent();
|
Interceptor.RegisterBeforeSendEvent();
|
||||||
|
|
||||||
// set preferences
|
// set preferences
|
||||||
Profiles = await ProfileService.GetProfile();
|
Profiles = await ProfileService.GetProfile();
|
||||||
XUserInfo = await UserInfoService.GetUserInfo();
|
XUserInfo = await UserInfoService.GetUserInfo();
|
||||||
Paging.OrderBy = Profiles.CompanySort;
|
Paging.OrderBy = Profiles.CompanySort;
|
||||||
Paging.SearchColumn = Profiles.CompanySearch;
|
Paging.SearchColumn = Profiles.CompanySearch;
|
||||||
Paging.PageSize = Convert.ToInt32(Profiles.PageSize);
|
Paging.PageSize = Convert.ToInt32(Profiles.PageSize);
|
||||||
Paging.HasFolded = ShowFolded ? 1 : 0;
|
Paging.HasFolded = ShowFolded ? 1 : 0;
|
||||||
|
|
||||||
// load saved search
|
// load saved search
|
||||||
SavedSearch = string.IsNullOrWhiteSpace(Profiles.CompanyFilterPhrase) ? "" : Profiles.CompanyFilterPhrase;
|
SavedSearch = string.IsNullOrWhiteSpace(Profiles.CompanyFilterPhrase) ? "" : Profiles.CompanyFilterPhrase;
|
||||||
Paging.SearchTerm = SavedSearch;
|
Paging.SearchTerm = SavedSearch;
|
||||||
|
|
||||||
// get companies
|
// get companies
|
||||||
await FetchCustomers();
|
await FetchCustomers();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task OnFoldedClick()
|
private async Task OnFoldedClick()
|
||||||
{
|
{
|
||||||
Working = true;
|
Working = true;
|
||||||
ShowFolded = !ShowFolded;
|
ShowFolded = !ShowFolded;
|
||||||
ButtonFoldedText = ShowFolded ? "Vis Aktive" : "Vis Ophørte";
|
ButtonFoldedText = ShowFolded ? "Vis Aktive" : "Vis Ophørte";
|
||||||
Companies = new List<CompanyDto>();
|
Companies = new List<CompanyDto>();
|
||||||
Paging.PageNumber = 1;
|
Paging.PageNumber = 1;
|
||||||
Paging.HasFolded = ShowFolded ? 1 : 0;
|
Paging.HasFolded = ShowFolded ? 1 : 0;
|
||||||
await FetchCustomers();
|
await FetchCustomers();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task SelectedPage(int page)
|
private async Task SelectedPage(int page)
|
||||||
{
|
{
|
||||||
Working = true;
|
Working = true;
|
||||||
Companies = new List<CompanyDto>();
|
Companies = new List<CompanyDto>();
|
||||||
Paging.PageNumber = page;
|
Paging.PageNumber = page;
|
||||||
await FetchCustomers();
|
await FetchCustomers();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task SetSearchCol(string searchColumn)
|
private async Task SetSearchCol(string searchColumn)
|
||||||
{
|
{
|
||||||
Working = true;
|
Working = true;
|
||||||
Companies = new List<CompanyDto>();
|
Companies = new List<CompanyDto>();
|
||||||
Paging.SearchColumn = searchColumn;
|
Paging.SearchColumn = searchColumn;
|
||||||
Paging.PageNumber = 1;
|
Paging.PageNumber = 1;
|
||||||
await FetchCustomers();
|
await FetchCustomers();
|
||||||
}
|
}
|
||||||
private async Task SetPageSize(string pageSize)
|
private async Task SetPageSize(string pageSize)
|
||||||
{
|
{
|
||||||
Working = true;
|
Working = true;
|
||||||
Companies = new List<CompanyDto>();
|
Companies = new List<CompanyDto>();
|
||||||
Paging.PageSize = Convert.ToInt32(pageSize);
|
Paging.PageSize = Convert.ToInt32(pageSize);
|
||||||
Paging.PageNumber = 1;
|
Paging.PageNumber = 1;
|
||||||
await FetchCustomers();
|
await FetchCustomers();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task SetSearchPhrase(string searchTerm)
|
private async Task SetSearchPhrase(string searchTerm)
|
||||||
{
|
{
|
||||||
Working = true;
|
Working = true;
|
||||||
Companies = new List<CompanyDto>();
|
Companies = new List<CompanyDto>();
|
||||||
Paging.PageNumber = 1;
|
Paging.PageNumber = 1;
|
||||||
Paging.SearchTerm = searchTerm;
|
Paging.SearchTerm = searchTerm;
|
||||||
await FetchCustomers();
|
await FetchCustomers();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task SetSortCol(string orderBy)
|
private async Task SetSortCol(string orderBy)
|
||||||
|
{
|
||||||
|
Working = true;
|
||||||
|
Companies = new List<CompanyDto>();
|
||||||
|
Paging.OrderBy = orderBy;
|
||||||
|
await FetchCustomers();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task FetchCustomers()
|
||||||
|
{
|
||||||
|
Working = true;
|
||||||
|
var response = await CustomerRepo.GetCompaniesPaged(CountryCode, Paging);
|
||||||
|
Working = false;
|
||||||
|
if (response.Items.Any())
|
||||||
|
{
|
||||||
|
Companies = response.Items;
|
||||||
|
PageData = response.MetaData;
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
Working = true;
|
|
||||||
Companies = new List<CompanyDto>();
|
Companies = new List<CompanyDto>();
|
||||||
Paging.OrderBy = orderBy;
|
PageData = new MetaData();
|
||||||
await FetchCustomers();
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private async Task FetchCustomers()
|
public void Dispose() => Interceptor.DisposeEvent();
|
||||||
{
|
}
|
||||||
Working = true;
|
|
||||||
var response = await CustomerRepo.GetCompaniesPaged(CountryCode, Paging);
|
|
||||||
Working = false;
|
|
||||||
if (response.Items.Any())
|
|
||||||
{
|
|
||||||
Companies = response.Items;
|
|
||||||
PageData = response.MetaData;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Companies = new List<CompanyDto>();
|
|
||||||
PageData = new MetaData();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose() => Interceptor.DisposeEvent();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
|
@ -24,123 +24,121 @@ using Wonky.Entity.Configuration;
|
||||||
using Wonky.Entity.DTO;
|
using Wonky.Entity.DTO;
|
||||||
using Wonky.Entity.Views;
|
using Wonky.Entity.Views;
|
||||||
|
|
||||||
namespace Wonky.Client.Services
|
namespace Wonky.Client.Services;
|
||||||
|
|
||||||
|
public class AuthenticationService : IAuthenticationService
|
||||||
{
|
{
|
||||||
public class AuthenticationService : IAuthenticationService
|
private readonly JsonSerializerOptions _options = new() { PropertyNameCaseInsensitive = true };
|
||||||
|
private readonly HttpClient _client;
|
||||||
|
private readonly AuthenticationStateProvider _authStateProvider;
|
||||||
|
private readonly IOptions<ApiConfig> _apiConfig;
|
||||||
|
private readonly ILogger<AuthenticationService> _logger;
|
||||||
|
private readonly IUserInfoService _infoService;
|
||||||
|
private readonly UserProfileService _profile;
|
||||||
|
private readonly ILocalStorageService _localStorage;
|
||||||
|
|
||||||
|
public AuthenticationService(
|
||||||
|
HttpClient client,
|
||||||
|
AuthenticationStateProvider authStateProvider,
|
||||||
|
IOptions<ApiConfig> apiConfig,
|
||||||
|
ILogger<AuthenticationService> logger,
|
||||||
|
IUserInfoService infoService,
|
||||||
|
UserProfileService profile,
|
||||||
|
ILocalStorageService localStorage
|
||||||
|
)
|
||||||
{
|
{
|
||||||
private readonly JsonSerializerOptions _options = new() { PropertyNameCaseInsensitive = true };
|
_client = client;
|
||||||
private readonly HttpClient _client;
|
_authStateProvider = authStateProvider;
|
||||||
private readonly AuthenticationStateProvider _authStateProvider;
|
_apiConfig = apiConfig;
|
||||||
private readonly IOptions<ApiConfig> _apiConfig;
|
_logger = logger;
|
||||||
private readonly ILogger<AuthenticationService> _logger;
|
_infoService = infoService;
|
||||||
private readonly IUserInfoService _infoService;
|
_profile = profile;
|
||||||
private readonly UserProfileService _profile;
|
_localStorage = localStorage;
|
||||||
private readonly ILocalStorageService _localStorage;
|
}
|
||||||
|
|
||||||
public AuthenticationService(
|
|
||||||
HttpClient client,
|
|
||||||
AuthenticationStateProvider authStateProvider,
|
|
||||||
IOptions<ApiConfig> apiConfig,
|
|
||||||
ILogger<AuthenticationService> logger,
|
|
||||||
IUserInfoService infoService,
|
|
||||||
UserProfileService profile,
|
|
||||||
ILocalStorageService localStorage
|
|
||||||
)
|
|
||||||
{
|
|
||||||
_client = client;
|
|
||||||
_authStateProvider = authStateProvider;
|
|
||||||
_apiConfig = apiConfig;
|
|
||||||
_logger = logger;
|
|
||||||
_infoService = infoService;
|
|
||||||
_profile = profile;
|
|
||||||
_localStorage = localStorage;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<AuthResponseView> Login(CredentialDto credentials)
|
public async Task<AuthResponseView> Login(CredentialDto credentials)
|
||||||
|
{
|
||||||
|
var credForm = new Dictionary<string, string>
|
||||||
{
|
{
|
||||||
var credForm = new Dictionary<string, string>
|
["grant_type"] = "password",
|
||||||
|
["username"] = credentials.Email,
|
||||||
|
["password"] = credentials.Password
|
||||||
|
};
|
||||||
|
|
||||||
|
var response = await _client
|
||||||
|
.PostAsync(_apiConfig.Value.ServicesAuth, new FormUrlEncodedContent(credForm));
|
||||||
|
|
||||||
|
var resContent = await response.Content.ReadAsStringAsync();
|
||||||
|
|
||||||
|
if (!response.IsSuccessStatusCode)
|
||||||
|
return new AuthResponseView
|
||||||
{
|
{
|
||||||
["grant_type"] = "password",
|
IsSuccess = false, ErrorMessage = $"Kontroller indtastning"
|
||||||
["username"] = credentials.Email,
|
|
||||||
["password"] = credentials.Password
|
|
||||||
};
|
};
|
||||||
|
|
||||||
var response = await _client
|
// process response content
|
||||||
.PostAsync(_apiConfig.Value.ServicesAuth, new FormUrlEncodedContent(credForm));
|
var data = JsonSerializer.Deserialize<AuthResponseView>(resContent, _options);
|
||||||
|
|
||||||
|
await _infoService.SetAccessToken(data.AccessToken);
|
||||||
|
await _infoService.SetRefreshToken(data.RefreshToken);
|
||||||
|
await _infoService.SetExpiration((int)DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1)).TotalSeconds + data.ExpiresIn - 60);
|
||||||
|
|
||||||
var resContent = await response.Content.ReadAsStringAsync();
|
_client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("bearer", data.AccessToken);
|
||||||
|
|
||||||
if (!response.IsSuccessStatusCode)
|
var userInfo = await UserInfo();
|
||||||
return new AuthResponseView
|
|
||||||
{
|
|
||||||
IsSuccess = false, ErrorMessage = $"Kontroller indtastning"
|
|
||||||
};
|
|
||||||
|
|
||||||
// process response content
|
await _infoService.SetUserInfo(userInfo);
|
||||||
var data = JsonSerializer.Deserialize<AuthResponseView>(resContent, _options);
|
|
||||||
|
|
||||||
await _infoService.SetAccessToken(data.AccessToken);
|
// notify system on state change
|
||||||
await _infoService.SetRefreshToken(data.RefreshToken);
|
((AuthStateProvider)_authStateProvider).NotifyUserAuthenticationAsync(data.AccessToken);
|
||||||
await _infoService.SetExpiration((int)DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1)).TotalSeconds + data.ExpiresIn - 60);
|
data.IsSuccess = true;
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
_client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("bearer", data.AccessToken);
|
public async Task<string> RefreshToken()
|
||||||
|
{
|
||||||
var userInfo = await UserInfo();
|
var refreshToken = await _infoService.GetRefreshToken();
|
||||||
|
var credentials = new Dictionary<string, string>
|
||||||
await _infoService.SetUserInfo(userInfo);
|
|
||||||
|
|
||||||
// notify system on state change
|
|
||||||
((AuthStateProvider)_authStateProvider).NotifyUserAuthenticationAsync(data.AccessToken);
|
|
||||||
data.IsSuccess = true;
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<string> RefreshToken()
|
|
||||||
{
|
{
|
||||||
var refreshToken = await _infoService.GetRefreshToken();
|
["grant_type"] = "refresh_token",
|
||||||
var credentials = new Dictionary<string, string>
|
["refresh_token"] = refreshToken
|
||||||
{
|
};
|
||||||
["grant_type"] = "refresh_token",
|
var response = await _client.PostAsync(_apiConfig.Value.ServicesAuth, new FormUrlEncodedContent(credentials));
|
||||||
["refresh_token"] = refreshToken
|
if (!response.IsSuccessStatusCode)
|
||||||
};
|
return string.Empty;
|
||||||
var response = await _client.PostAsync(_apiConfig.Value.ServicesAuth, new FormUrlEncodedContent(credentials));
|
|
||||||
if (!response.IsSuccessStatusCode)
|
|
||||||
return string.Empty;
|
|
||||||
|
|
||||||
var resContent = await response.Content.ReadAsStringAsync();
|
var resContent = await response.Content.ReadAsStringAsync();
|
||||||
var data = JsonSerializer.Deserialize<AuthResponseView>(resContent, _options);
|
var data = JsonSerializer.Deserialize<AuthResponseView>(resContent, _options);
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(data.AccessToken))
|
if (string.IsNullOrWhiteSpace(data.AccessToken))
|
||||||
return string.Empty;
|
return string.Empty;
|
||||||
|
|
||||||
// set default request headers using access_token
|
// set default request headers using access_token
|
||||||
_client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("bearer", data.AccessToken);
|
_client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("bearer", data.AccessToken);
|
||||||
await _infoService.SetAccessToken(data.AccessToken);
|
await _infoService.SetAccessToken(data.AccessToken);
|
||||||
await _infoService.SetRefreshToken(data.RefreshToken);
|
await _infoService.SetRefreshToken(data.RefreshToken);
|
||||||
await _infoService.SetExpiration((int)DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1)).TotalSeconds + data.ExpiresIn - 60);
|
await _infoService.SetExpiration((int)DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1)).TotalSeconds + data.ExpiresIn - 60);
|
||||||
return data.AccessToken;
|
return data.AccessToken;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task Logout()
|
public async Task Logout()
|
||||||
{
|
{
|
||||||
var profileBackup = await _profile.GetProfile();
|
var profileBackup = await _profile.GetProfile();
|
||||||
Task.Delay(150);
|
Task.Delay(150);
|
||||||
await _localStorage.ClearAsync();
|
await _localStorage.ClearAsync();
|
||||||
Task.Delay(150);
|
Task.Delay(150);
|
||||||
await _profile.SetProfile(profileBackup);
|
await _profile.SetProfile(profileBackup);
|
||||||
_client.DefaultRequestHeaders.Authorization = null;
|
_client.DefaultRequestHeaders.Authorization = null;
|
||||||
((AuthStateProvider)_authStateProvider).NotifyUserLogout();
|
((AuthStateProvider)_authStateProvider).NotifyUserLogout();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<UserManagerEditView> UserInfo(bool write = false)
|
|
||||||
{
|
|
||||||
var response = await _client.GetAsync(_apiConfig.Value.UserInfo).ConfigureAwait(true);
|
|
||||||
var content = await response.Content.ReadAsStringAsync();
|
|
||||||
var userInfo = JsonSerializer.Deserialize<UserManagerEditView>(content, _options);
|
|
||||||
if(write)
|
|
||||||
await _infoService.SetUserInfo(userInfo);
|
|
||||||
return userInfo ?? new UserManagerEditView();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
public async Task<UserManagerEditView> UserInfo(bool write = false)
|
||||||
|
{
|
||||||
|
var response = await _client.GetAsync(_apiConfig.Value.UserInfo).ConfigureAwait(true);
|
||||||
|
var content = await response.Content.ReadAsStringAsync();
|
||||||
|
var userInfo = JsonSerializer.Deserialize<UserManagerEditView>(content, _options);
|
||||||
|
if(write)
|
||||||
|
await _infoService.SetUserInfo(userInfo);
|
||||||
|
return userInfo ?? new UserManagerEditView();
|
||||||
|
}
|
||||||
|
}
|
|
@ -17,14 +17,12 @@
|
||||||
using Wonky.Entity.DTO;
|
using Wonky.Entity.DTO;
|
||||||
using Wonky.Entity.Views;
|
using Wonky.Entity.Views;
|
||||||
|
|
||||||
namespace Wonky.Client.Services
|
namespace Wonky.Client.Services;
|
||||||
{
|
|
||||||
public interface IAuthenticationService
|
|
||||||
{
|
|
||||||
Task<AuthResponseView> Login(CredentialDto credentials);
|
|
||||||
Task Logout();
|
|
||||||
Task<string> RefreshToken();
|
|
||||||
Task<UserManagerEditView> UserInfo(bool write = false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
public interface IAuthenticationService
|
||||||
|
{
|
||||||
|
Task<AuthResponseView> Login(CredentialDto credentials);
|
||||||
|
Task Logout();
|
||||||
|
Task<string> RefreshToken();
|
||||||
|
Task<UserManagerEditView> UserInfo(bool write = false);
|
||||||
|
}
|
|
@ -22,86 +22,84 @@ using Wonky.Client.Services;
|
||||||
using Wonky.Entity.DTO;
|
using Wonky.Entity.DTO;
|
||||||
using Wonky.Entity.Views;
|
using Wonky.Entity.Views;
|
||||||
|
|
||||||
namespace Wonky.Client.Shared
|
namespace Wonky.Client.Shared;
|
||||||
|
|
||||||
|
public class AuthStateProvider : AuthenticationStateProvider
|
||||||
{
|
{
|
||||||
public class AuthStateProvider : AuthenticationStateProvider
|
private readonly HttpClient _client;
|
||||||
|
// private readonly ILocalStorageService _storage;
|
||||||
|
private readonly AuthenticationState _anonymous;
|
||||||
|
private readonly IUserInfoService _infoService;
|
||||||
|
|
||||||
|
public AuthStateProvider(HttpClient client, IUserInfoService infoService)
|
||||||
{
|
{
|
||||||
private readonly HttpClient _client;
|
_client = client;
|
||||||
// private readonly ILocalStorageService _storage;
|
_infoService = infoService;
|
||||||
private readonly AuthenticationState _anonymous;
|
_anonymous = new AuthenticationState(new ClaimsPrincipal(new ClaimsIdentity()));
|
||||||
private readonly IUserInfoService _infoService;
|
|
||||||
|
|
||||||
public AuthStateProvider(HttpClient client, IUserInfoService infoService)
|
|
||||||
{
|
|
||||||
_client = client;
|
|
||||||
_infoService = infoService;
|
|
||||||
_anonymous = new AuthenticationState(new ClaimsPrincipal(new ClaimsIdentity()));
|
|
||||||
}
|
|
||||||
|
|
||||||
public override async Task<AuthenticationState> GetAuthenticationStateAsync()
|
|
||||||
{
|
|
||||||
var token = await _infoService.GetAccessToken();
|
|
||||||
if (string.IsNullOrEmpty(token))
|
|
||||||
return _anonymous;
|
|
||||||
|
|
||||||
var userInfo = await _infoService.GetUserInfo();
|
|
||||||
if (userInfo == null)
|
|
||||||
return _anonymous;
|
|
||||||
|
|
||||||
_client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("bearer", token);
|
|
||||||
var exp = await _infoService.GetExpiration();
|
|
||||||
var claims = new List<Claim>
|
|
||||||
{
|
|
||||||
new(ClaimTypes.Name, $"{userInfo.FirstName} {userInfo.LastName}"),
|
|
||||||
new(ClaimTypes.Email, userInfo.Email),
|
|
||||||
new(ClaimTypes.Country, userInfo.CountryCode),
|
|
||||||
new(ClaimTypes.MobilePhone, userInfo.PhoneNumber),
|
|
||||||
new(ClaimTypes.Expiration, exp.ToString())
|
|
||||||
};
|
|
||||||
claims.AddRange(
|
|
||||||
from role in userInfo.AssignedRoles
|
|
||||||
where role.Assigned select new Claim(ClaimTypes.Role, role.Name));
|
|
||||||
|
|
||||||
// return the authState for the user
|
|
||||||
return new AuthenticationState(
|
|
||||||
new ClaimsPrincipal(
|
|
||||||
new ClaimsIdentity(claims, "token")));
|
|
||||||
}
|
|
||||||
|
|
||||||
public async void NotifyUserAuthenticationAsync(string token)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrEmpty(token))
|
|
||||||
return;
|
|
||||||
|
|
||||||
_client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("bearer", token);
|
|
||||||
|
|
||||||
var userInfo = await _infoService.GetUserInfo();
|
|
||||||
var exp = await _infoService.GetExpiration();
|
|
||||||
|
|
||||||
var claims = new List<Claim>
|
|
||||||
{
|
|
||||||
new(ClaimTypes.Name, $"{userInfo.FirstName} {userInfo.LastName}"),
|
|
||||||
new(ClaimTypes.Email, userInfo.Email),
|
|
||||||
new(ClaimTypes.Country, userInfo.CountryCode),
|
|
||||||
new(ClaimTypes.MobilePhone, userInfo.PhoneNumber),
|
|
||||||
new(ClaimTypes.Expiration, exp.ToString())
|
|
||||||
};
|
|
||||||
claims.AddRange(
|
|
||||||
from role in userInfo.AssignedRoles
|
|
||||||
where role.Assigned select new Claim(ClaimTypes.Role, role.Name));
|
|
||||||
|
|
||||||
var authState = Task.FromResult(
|
|
||||||
new AuthenticationState(
|
|
||||||
new ClaimsPrincipal(
|
|
||||||
new ClaimsIdentity(claims, "token"))));
|
|
||||||
|
|
||||||
NotifyAuthenticationStateChanged(authState);
|
|
||||||
}
|
|
||||||
public void NotifyUserLogout()
|
|
||||||
{
|
|
||||||
var authState = Task.FromResult(_anonymous);
|
|
||||||
NotifyAuthenticationStateChanged(authState);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
public override async Task<AuthenticationState> GetAuthenticationStateAsync()
|
||||||
|
{
|
||||||
|
var token = await _infoService.GetAccessToken();
|
||||||
|
if (string.IsNullOrEmpty(token))
|
||||||
|
return _anonymous;
|
||||||
|
|
||||||
|
var userInfo = await _infoService.GetUserInfo();
|
||||||
|
if (userInfo == null)
|
||||||
|
return _anonymous;
|
||||||
|
|
||||||
|
_client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("bearer", token);
|
||||||
|
var exp = await _infoService.GetExpiration();
|
||||||
|
var claims = new List<Claim>
|
||||||
|
{
|
||||||
|
new(ClaimTypes.Name, $"{userInfo.FirstName} {userInfo.LastName}"),
|
||||||
|
new(ClaimTypes.Email, userInfo.Email),
|
||||||
|
new(ClaimTypes.Country, userInfo.CountryCode),
|
||||||
|
new(ClaimTypes.MobilePhone, userInfo.PhoneNumber),
|
||||||
|
new(ClaimTypes.Expiration, exp.ToString())
|
||||||
|
};
|
||||||
|
claims.AddRange(
|
||||||
|
from role in userInfo.AssignedRoles
|
||||||
|
where role.Assigned select new Claim(ClaimTypes.Role, role.Name));
|
||||||
|
|
||||||
|
// return the authState for the user
|
||||||
|
return new AuthenticationState(
|
||||||
|
new ClaimsPrincipal(
|
||||||
|
new ClaimsIdentity(claims, "token")));
|
||||||
|
}
|
||||||
|
|
||||||
|
public async void NotifyUserAuthenticationAsync(string token)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(token))
|
||||||
|
return;
|
||||||
|
|
||||||
|
_client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("bearer", token);
|
||||||
|
|
||||||
|
var userInfo = await _infoService.GetUserInfo();
|
||||||
|
var exp = await _infoService.GetExpiration();
|
||||||
|
|
||||||
|
var claims = new List<Claim>
|
||||||
|
{
|
||||||
|
new(ClaimTypes.Name, $"{userInfo.FirstName} {userInfo.LastName}"),
|
||||||
|
new(ClaimTypes.Email, userInfo.Email),
|
||||||
|
new(ClaimTypes.Country, userInfo.CountryCode),
|
||||||
|
new(ClaimTypes.MobilePhone, userInfo.PhoneNumber),
|
||||||
|
new(ClaimTypes.Expiration, exp.ToString())
|
||||||
|
};
|
||||||
|
claims.AddRange(
|
||||||
|
from role in userInfo.AssignedRoles
|
||||||
|
where role.Assigned select new Claim(ClaimTypes.Role, role.Name));
|
||||||
|
|
||||||
|
var authState = Task.FromResult(
|
||||||
|
new AuthenticationState(
|
||||||
|
new ClaimsPrincipal(
|
||||||
|
new ClaimsIdentity(claims, "token"))));
|
||||||
|
|
||||||
|
NotifyAuthenticationStateChanged(authState);
|
||||||
|
}
|
||||||
|
public void NotifyUserLogout()
|
||||||
|
{
|
||||||
|
var authState = Task.FromResult(_anonymous);
|
||||||
|
NotifyAuthenticationStateChanged(authState);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"appInfo": {
|
"appInfo": {
|
||||||
"name": "Wonky Online",
|
"name": "Wonky Online",
|
||||||
"version": "0.117.1",
|
"version": "0.118.0",
|
||||||
"rc": true,
|
"rc": true,
|
||||||
"sandBox": false,
|
"sandBox": false,
|
||||||
"image": "grumpy-coder.png"
|
"image": "grumpy-coder.png"
|
||||||
|
@ -19,7 +19,7 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"apiConfig": {
|
"apiConfig": {
|
||||||
"baseUrl": "https://dev.innotec.dk",
|
"baseUrl": "https://zeta.innotec.dk",
|
||||||
"catalog": "api/v2/catalog/country",
|
"catalog": "api/v2/catalog/country",
|
||||||
"crmCustomers": "api/v2/crm/companies",
|
"crmCustomers": "api/v2/crm/companies",
|
||||||
"crmInventoryExt": "history/inventory",
|
"crmInventoryExt": "history/inventory",
|
||||||
|
|
Loading…
Reference in a new issue