Merge branch 'dev-v6'

This commit is contained in:
Frede Hundewadt 2022-12-30 13:21:38 +01:00
commit 2619e5df3d
105 changed files with 943 additions and 758 deletions

View file

@ -18,7 +18,7 @@ using Wonky.Entity.Views;
namespace Wonky.Client.Components;
public partial class AdvisorActivityTableComponent
public partial class ActivityTableCrmComponent
{
[Parameter] public List<ReportItemView> ActivityList { get; set; } = new();
[Inject] public NavigationManager Navigator { get; set; }

View file

@ -8,19 +8,19 @@
@code {
[Inject] public UserPrefService PrefService { get; set; }
[Inject] public UserProfileService ProfileService { get; set; }
private int KmMorning { get; set; }
private UserPref Prefs { get; set; } = new();
protected override async Task OnInitializedAsync()
{
Prefs = await PrefService.GetPreferences();
Prefs = await ProfileService.GetPreferences();
KmMorning = Prefs.KmMorning;
}
private async Task OnKmChanged()
{
await PrefService.SetKmMorning(KmMorning);
await ProfileService.SetKmMorning(KmMorning);
}
}

View file

@ -23,7 +23,7 @@ namespace Wonky.Client.Components;
public partial class CatalogGroupComponent
{
[Inject] public ILocalStorageService Storage { get; set; }
[Inject] public UserPrefService PrefService { get; set; }
[Inject] public UserProfileService ProfileService { get; set; }
[Parameter] public EventCallback<string> OnChanged { get; set; }
private Dictionary<string, string> Items { get; set; } = new();
private UserPref Prefs = new();

View file

@ -24,7 +24,7 @@ public partial class CatalogSearchComponent : IDisposable
/// <summary>
/// User preference service
/// </summary>
[Inject] public UserPrefService PrefService { get; set; }
[Inject] public UserProfileService ProfileService { get; set; }
/// <summary>
/// OnChanged event callback
@ -46,8 +46,8 @@ public partial class CatalogSearchComponent : IDisposable
/// </summary>
protected override async Task OnInitializedAsync()
{
PrefService.OnChange += ProfileServiceOnOnChange;
Prefs = await PrefService.GetPreferences();
ProfileService.OnChange += ProfileServiceOnOnChange;
Prefs = await ProfileService.GetPreferences();
SearchCol = Prefs.ItemSearch;
await OnChanged.InvokeAsync(SearchCol);
}
@ -61,7 +61,7 @@ public partial class CatalogSearchComponent : IDisposable
var val = e.Value.ToString();
if (val == "-1") return;
await OnChanged.InvokeAsync(val);
await PrefService.SetItemSearch(val);
await ProfileService.SetItemSearch(val);
}
/// <summary>
@ -79,6 +79,6 @@ public partial class CatalogSearchComponent : IDisposable
/// </summary>
public void Dispose()
{
PrefService.OnChange -= ProfileServiceOnOnChange;
ProfileService.OnChange -= ProfileServiceOnOnChange;
}
}

View file

@ -17,6 +17,6 @@
<select class="form-select bg-success text-bg-success" @bind-value="@SortCol" @bind-value:event="oninput" @onchange="OnSelectChanged">
<option value="-1" selected disabled>SORTERING</option>
<option value="name">Navn</option>
<option value="sku">Nummer</option>
<option value="name">Navn sort</option>
<option value="sku">Varenr sort</option>
</select>

View file

@ -24,7 +24,7 @@ public partial class CatalogSortComponent : IDisposable
/// <summary>
/// User preference service
/// </summary>
[Inject] public UserPrefService PrefService { get; set; }
[Inject] public UserProfileService ProfileService { get; set; }
/// <summary>
/// OnChanged callback function
@ -46,8 +46,8 @@ public partial class CatalogSortComponent : IDisposable
/// </summary>
protected override async Task OnInitializedAsync()
{
PrefService.OnChange += ProfileServiceOnOnChange;
Prefs = await PrefService.GetPreferences();
ProfileService.OnChange += ProfileServiceOnOnChange;
Prefs = await ProfileService.GetPreferences();
SortCol = Prefs.ItemSort;
}
@ -60,7 +60,7 @@ public partial class CatalogSortComponent : IDisposable
var val = e.Value.ToString();
if (val == "-1") return;
await OnChanged.InvokeAsync(val);
await PrefService.SetItemSort(val);
await ProfileService.SetItemSort(val);
}
/// <summary>
@ -78,6 +78,6 @@ public partial class CatalogSortComponent : IDisposable
/// </summary>
public void Dispose()
{
PrefService.OnChange -= ProfileServiceOnOnChange;
ProfileService.OnChange -= ProfileServiceOnOnChange;
}
}

View file

@ -23,6 +23,7 @@
<th scope="col">Navn</th>
<th scope="col">Fork</th>
<th scope="col" class="text-nowrap">Varenr</th>
<th scope="col">Colli</th>
<th scope="col">Stk / Pris</th>
</tr>
</thead>
@ -37,6 +38,9 @@
<td class="align-middle">
@salesItem.Sku
</td>
<td class="align-middle">
@salesItem.BoxSize
</td>
<td class="align-middle">
<ul class="list-group">
@foreach (var rate in salesItem.Rates)

View file

@ -25,15 +25,15 @@ namespace Wonky.Client.Components;
public partial class CompanySearchColumnComponent : IDisposable
{
[Inject] public ILocalStorageService Storage { get; set; }
[Inject] public UserPrefService PrefService { get; set; }
[Inject] public UserProfileService ProfileService { get; set; }
[Parameter] public EventCallback<string> OnChanged { get; set; }
private Dictionary<string, string> Items { get; set; } = new();
private UserPref Prefs { get; set; } = new();
private string SearchCol { get; set; } = "name";
protected override async Task OnInitializedAsync()
{
PrefService.OnChange += ProfileServiceOnOnChange;
Prefs = await PrefService.GetPreferences();
ProfileService.OnChange += ProfileServiceOnOnChange;
Prefs = await ProfileService.GetPreferences();
SearchCol = Prefs.CompanySearch;
}
private async Task OnSelectionChanged(ChangeEventArgs e)
@ -41,7 +41,7 @@ public partial class CompanySearchColumnComponent : IDisposable
var val = e.Value.ToString();
if (val == "-1") return;
await OnChanged.InvokeAsync(val);
await PrefService.SetCompanySearch(val);
await ProfileService.SetCompanySearch(val);
}
private void ProfileServiceOnOnChange(UserPref newUserPref)
{
@ -50,6 +50,6 @@ public partial class CompanySearchColumnComponent : IDisposable
}
public void Dispose()
{
PrefService.OnChange -= ProfileServiceOnOnChange;
ProfileService.OnChange -= ProfileServiceOnOnChange;
}
}

View file

@ -25,12 +25,12 @@ namespace Wonky.Client.Components
private Timer InputTimer { get; set; } = new();
private string SearchTerm { get; set; } = "";
private UserPref Prefs { get; set; } = new ();
[Inject] public UserPrefService PrefService { get; set; }
[Inject] public UserProfileService ProfileService { get; set; }
[Parameter] public EventCallback<string> OnChanged { get; set; }
protected override async Task OnInitializedAsync()
{
Prefs = await PrefService.GetPreferences();
Prefs = await ProfileService.GetPreferences();
SearchTerm = string.IsNullOrWhiteSpace(Prefs.CompanyFilterPhrase) ? "" : Prefs.CompanyFilterPhrase.Trim();
if(!string.IsNullOrWhiteSpace(SearchTerm))
@ -41,13 +41,13 @@ namespace Wonky.Client.Components
{
InputTimer.Dispose();
SearchTerm = "";
await PrefService.SetCompanyFilterPhrase(SearchTerm.Trim());
await ProfileService.SetCompanyFilterPhrase(SearchTerm.Trim());
await OnChanged.InvokeAsync(SearchTerm);
}
private async Task OnSearchChanged()
{
await PrefService.SetCompanyFilterPhrase(SearchTerm.Trim());
await ProfileService.SetCompanyFilterPhrase(SearchTerm.Trim());
InputTimer.Dispose();
InputTimer = new Timer(500);
InputTimer.AutoReset = false;

View file

@ -17,6 +17,6 @@
<select class="form-select bg-success text-bg-success" @bind-value="@SortCol" @bind-value:event="oninput" @onchange="OnSelectionChanged">
<option value="-1" selected disabled>SORTERING</option>
<option value="name">Navn</option>
<option value="city">By</option>
<option value="name">Navne sort.</option>
<option value="city">By sort.</option>
</select>

View file

@ -24,15 +24,15 @@ namespace Wonky.Client.Components
public partial class CompanySortComponent : IDisposable
{
[Inject] public ILocalStorageService Storage { get; set; }
[Inject] public UserPrefService PrefService { get; set; }
[Inject] public UserProfileService ProfileService { get; set; }
[Parameter] public EventCallback<string> OnChanged { get; set; }
private Dictionary<string, string> Items { get; set; } = new();
private UserPref Prefs = new();
private string SortCol { get; set; } = "name";
protected override async Task OnInitializedAsync()
{
PrefService.OnChange += ProfileServiceOnOnChange;
Prefs = await PrefService.GetPreferences();
ProfileService.OnChange += ProfileServiceOnOnChange;
Prefs = await ProfileService.GetPreferences();
SortCol = Prefs.CompanySort;
}
private async Task OnSelectionChanged(ChangeEventArgs e)
@ -40,7 +40,7 @@ namespace Wonky.Client.Components
var val = e.Value.ToString();
if (val == "-1") return;
await OnChanged.InvokeAsync(val);
await PrefService.SetCompanySort(val);
await ProfileService.SetCompanySort(val);
}
private void ProfileServiceOnOnChange(UserPref newUserPref)
{
@ -49,7 +49,7 @@ namespace Wonky.Client.Components
}
public void Dispose()
{
PrefService.OnChange -= ProfileServiceOnOnChange;
ProfileService.OnChange -= ProfileServiceOnOnChange;
}
}
}

View file

@ -36,7 +36,7 @@
<div class="list-group-item">
<div class="row align-items-center">
<div class="col-sm-4">
@product.Description
@product.Description <span class="fw-bold">@(product.Discontinued ? "(UDGÅET)" : "")</span>
</div>
<div class="col-sm-3">
@product.Sku

View file

@ -32,7 +32,7 @@ using Wonky.Entity.Views;
namespace Wonky.Client.Components;
public partial class LandingComponentAdmin : IDisposable
{
[Inject] public UserPrefService PrefService { get; set; }
[Inject] public UserProfileService ProfileService { get; set; }
[Inject] public ILogger<LandingComponentAdmin> Logger { get; set; }
[Inject] public HttpInterceptorService Interceptor { get; set; }
[Inject] public IToastService Toaster { get; set; }
@ -52,7 +52,7 @@ public partial class LandingComponentAdmin : IDisposable
protected override async Task OnInitializedAsync()
{
Prefs = await PrefService.GetPreferences();
Prefs = await ProfileService.GetPreferences();
if(!string.IsNullOrWhiteSpace(Prefs.WorkDate))
WordDate = Prefs.WorkDate;

View file

@ -32,7 +32,7 @@ using Wonky.Entity.Views;
namespace Wonky.Client.Components;
public partial class LandingComponentAdvisor : IDisposable
{
[Inject] public UserPrefService PrefService { get; set; }
[Inject] public UserProfileService ProfileService { get; set; }
[Inject] public ILogger<LandingComponentAdvisor> Logger { get; set; }
[Inject] public HttpInterceptorService Inteceptor { get; set; }
[Inject] public IToastService Toaster { get; set; }
@ -51,7 +51,7 @@ public partial class LandingComponentAdvisor : IDisposable
protected override async Task OnInitializedAsync()
{
Prefs = await PrefService.GetPreferences();
Prefs = await ProfileService.GetPreferences();
SelectedDate = string.IsNullOrWhiteSpace(Prefs.WorkDate) ? DateTime.Now : DateTime.Parse(Prefs.WorkDate);
Inteceptor.RegisterEvent();
@ -68,7 +68,7 @@ public partial class LandingComponentAdvisor : IDisposable
private async Task OnCompleteTask(string taskItemId)
{
await PrefService.SetWorkDate(DateTime.Now);
await ProfileService.SetWorkDate(DateTime.Now);
var item = TaskItems.Find(x => x.TaskItemId == taskItemId);
Navigator.NavigateTo($"/companies/{item.ReferenceId}/activities/new");
}

View file

@ -1,91 +0,0 @@
@*
// Copyright (C) 2022 FCS Frede's Computer Services.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see [https://www.gnu.org/licenses/agpl-3.0.en.html]
//
*@
@using System.Globalization
@if (ReportList.Any())
{
<div class="list-group list-group-flush">
<div class="list-group-item px-3 bg-black text-white opacity-75">
<div class="row">
<div class="fw-bold col">
Dato
</div>
<div class="fw-bold col">
Dag
</div>
<div class="fw-bold col">
Start
</div>
<div class="fw-bold col">
Slut
</div>
<div class="fw-bold col text-end">
Resultat
</div>
</div>
</div>
@foreach (var report in ReportList)
{
<a class="list-group-item list-group-item-action" href="/office/users/advisors/@CountryCode/@UserId/reports/@report.ReportDate">
<div class="row">
<div class="col">
@report.ReportDate
</div>
<div class="col">
@{
switch (report.DayTypeEnum)
{
case "Sales":
<span>Salgsdag</span>
break;
case "SickLeave":
<span>Sygdom</span>
break;
case "Office":
<span>Kontordag</span>
break;
case "Meeting":
<span>Salgsmøde</span>
break;
case "Leave":
<span>Ferie</span>
break;
case "Supervisor":
<span>Supervisor</span>
break;
}
}
</div>
<div class="col text-center">
@(report.DayTypeEnum == "Sales" ? report.FromDateTime.Split(" ")[1] : report.FromDateTime.Split(" ")[0])
</div>
<div class="col text-center">
@(report.DayTypeEnum == "Sales" ? report.ToDateTime.Split(" ")[1] : report.ToDateTime.Split(" ")[0])
</div>
<div class="col text-end">
@report.Turnover.ToString(CultureInfo.CurrentUICulture)
</div>
</div>
</a>
}
</div>
}
else
{
<div>Ingen data</div>
}

View file

@ -16,12 +16,12 @@
*@
<select class="form-select bg-info text-bg-info" @bind-value="@PageSize" @bind-value:event="oninput" @onchange="OnSelectChanged">
<option value="-1" selected disabled>RESULTATER</option>
<option value="5">5</option>
<option value="10">10</option>
<option value="15">15</option>
<option value="30">30</option>
<option value="50">50</option>
<option value="-1" selected disabled>ANTAL svar</option>
<option value="5">5 svar</option>
<option value="10">10 svar</option>
<option value="15">15 svar</option>
<option value="30">30 svar</option>
<option value="50">50 svar</option>
</select>

View file

@ -24,15 +24,15 @@ namespace Wonky.Client.Components
public partial class PageSizeComponent : IDisposable
{
[Inject] public ILocalStorageService Storage { get; set; }
[Inject] public UserPrefService PrefService { get; set; }
[Inject] public UserProfileService ProfileService { get; set; }
[Parameter] public EventCallback<string> OnChanged { get; set; }
private Dictionary<string, string> Items { get; set; } = new();
private UserPref Prefs = new();
private string PageSize { get; set; } = "";
protected override async Task OnInitializedAsync()
{
PrefService.OnChange += ProfileServiceOnOnChange;
Prefs = await PrefService.GetPreferences();
ProfileService.OnChange += ProfileServiceOnOnChange;
Prefs = await ProfileService.GetPreferences();
PageSize = Prefs.PageSize;
}
private async Task OnSelectChanged(ChangeEventArgs e)
@ -40,7 +40,7 @@ namespace Wonky.Client.Components
var val = e.Value.ToString();
if (val == "-1") return;
await OnChanged.InvokeAsync(val);
await PrefService.SetPageSize(val);
await ProfileService.SetPageSize(val);
}
private void ProfileServiceOnOnChange(UserPref newUserPref)
{
@ -49,7 +49,7 @@ namespace Wonky.Client.Components
}
public void Dispose()
{
PrefService.OnChange -= ProfileServiceOnOnChange;
ProfileService.OnChange -= ProfileServiceOnOnChange;
}
}
}

View file

@ -18,7 +18,7 @@ using Wonky.Entity.Views;
namespace Wonky.Client.Components;
public partial class OfficeActivityTableComponent
public partial class ReportActivityTableOfficeComponent
{
[Parameter] public List<ReportItemView> ActivityList { get; set; } = new();
[Inject] public NavigationManager Navigator { get; set; }

View file

@ -0,0 +1,61 @@
@*
// Copyright (C) 2022 FCS Frede's Computer Services.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see [https://www.gnu.org/licenses/agpl-3.0.en.html]
//
*@
@using Wonky.Entity.Views
<button type="button" aria-role="navigation" class="list-group-item list-group-item-action"
style="cursor: pointer" @onclick="ShowThisReport">
<div class="row">
<div class="col">
@Report.ReportDate
</div>
<div class="col">
@{
switch (Report.DayTypeEnum)
{
case "Sales":
<span>Salgsdag</span>
break;
case "SickLeave":
<span>Sygdom</span>
break;
case "Office":
<span>Kontordag</span>
break;
case "Meeting":
<span>Salgsmøde</span>
break;
case "Leave":
<span>Ferie</span>
break;
case "Supervisor":
<span>Medkørende Supervisor</span>
break;
}
}
</div>
<div class="col">
@(Report.DayTypeEnum == "Sales" ? Report.FromDateTime.Split(" ")[1] : Report.FromDateTime.Split(" ")[0])
</div>
<div class="col">
@(Report.DayTypeEnum == "Sales" ? Report.ToDateTime.Split(" ")[1] : Report.ToDateTime.Split(" ")[0])
</div>
<div class="col text-end">
@Report.Turnover
</div>
</div>
</button>

View file

@ -0,0 +1,15 @@
using Microsoft.AspNetCore.Components;
using Wonky.Entity.Views;
namespace Wonky.Client.Components;
public partial class ReportListItemComponent
{
[Parameter] public SalesReportListView Report { get; set; } = new();
[Parameter] public EventCallback<string> OnShowReport { get; set; }
private void ShowThisReport()
{
OnShowReport.InvokeAsync(Report.ReportDate);
}
}

View file

@ -1,90 +0,0 @@
@*
// Copyright (C) 2022 FCS Frede's Computer Services.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see [https://www.gnu.org/licenses/agpl-3.0.en.html]
//
*@
<div class="list-group list-group-flush">
<div class="list-group-item px-3 bg-black text-white opacity-75">
<div class="row">
<div class="fw-bold col">
Dato
</div>
<div class="fw-bold col">
Dag
</div>
<div class="fw-bold col">
Start
</div>
<div class="fw-bold col">
Slut
</div>
<div class="fw-bold col text-end">
Resultat
</div>
</div>
</div>
@if (_reports.Any())
{
@foreach (var report in ReportList)
{
<a class="list-group-item list-group-item-action" href="/sales-reports/view/@report.ReportDate">
<div class="row">
<div class="col">
@report.ReportDate
</div>
<div class="col">
@{
switch (report.DayTypeEnum)
{
case "Sales":
<span>Salgsdag</span>
break;
case "SickLeave":
<span>Sygdom</span>
break;
case "Office":
<span>Kontordag</span>
break;
case "Meeting":
<span>Salgsmøde</span>
break;
case "Leave":
<span>Ferie</span>
break;
case "Supervisor":
<span>Medkørende Supervisor</span>
break;
}
}
</div>
<div class="col">
@(report.DayTypeEnum == "Sales" ? report.FromDateTime.Split(" ")[1] : report.FromDateTime.Split(" ")[0])
</div>
<div class="col">
@(report.DayTypeEnum == "Sales" ? report.ToDateTime.Split(" ")[1] : report.ToDateTime.Split(" ")[0])
</div>
<div class="col text-end">
@report.Turnover
</div>
</div>
</a>
}
}
else
{
<div>Ingen data</div>
}
</div>

View file

@ -0,0 +1,50 @@
@*
// Copyright (C) 2022 FCS Frede's Computer Services.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see [https://www.gnu.org/licenses/agpl-3.0.en.html]
//
*@
<div class="list-group list-group-flush">
<div class="list-group-item px-3 bg-black text-white opacity-75">
<div class="row">
<div class="fw-bold col">
Dato
</div>
<div class="fw-bold col">
Dag
</div>
<div class="fw-bold col">
Start
</div>
<div class="fw-bold col">
Slut
</div>
<div class="fw-bold col text-end">
Resultat
</div>
</div>
</div>
@if (Reports.Any())
{
@foreach (var report in ReportList)
{
<ReportListItemComponent Report="report" OnShowReport="ShowThisReport" />
}
}
else
{
<div>Ingen data</div>
}
</div>

View file

@ -19,12 +19,20 @@ using Wonky.Entity.Views;
namespace Wonky.Client.Components;
public partial class ReportTableComponent
public partial class ReportTableCrmComponent
{
[Parameter] public List<SalesReportListView> ReportList { get; set; } = new();
private List<SalesReportListView> _reports { get; set; } = new();
[Parameter] public EventCallback<string> OnShowReport { get; set; }
private List<SalesReportListView> Reports { get; set; } = new();
protected override void OnParametersSet()
{
_reports = ReportList;
Reports = ReportList;
}
private void ShowThisReport(string reportDate)
{
OnShowReport.InvokeAsync(reportDate);
}
}

View file

@ -0,0 +1,51 @@
@*
// Copyright (C) 2022 FCS Frede's Computer Services.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see [https://www.gnu.org/licenses/agpl-3.0.en.html]
//
*@
@using System.Globalization
<div class="list-group list-group-flush">
<div class="list-group-item px-3 bg-black text-white opacity-75">
<div class="row">
<div class="fw-bold col">
Dato
</div>
<div class="fw-bold col">
Dag
</div>
<div class="fw-bold col">
Start
</div>
<div class="fw-bold col">
Slut
</div>
<div class="fw-bold col text-end">
Resultat
</div>
</div>
</div>
@if (ReportList.Any())
{
@foreach (var report in ReportList)
{
<ReportListItemComponent OnShowReport="ShowThisReport" Report="report" />
}
}
else
{
<div>Ingen data</div>
}
</div>

View file

@ -18,9 +18,14 @@ using Wonky.Entity.Views;
namespace Wonky.Client.Components;
public partial class OfficeReportTableComponent
public partial class ReportTableOfficeComponent
{
[Parameter] public List<SalesReportListView> ReportList { get; set; } = new();
[Parameter] public string UserId { get; set; } = "";
[Parameter] public string CountryCode { get; set; } = "";
[Parameter] public EventCallback<string> OnShowReport { get; set; }
private void ShowThisReport(string reportDate)
{
OnShowReport.InvokeAsync(reportDate);
}
}

View file

@ -28,7 +28,7 @@ public partial class WorkDateComponent : IDisposable
/// User preference service
/// </summary>
[Inject]
public UserPrefService Prefs { get; set; }
public UserProfileService Profiles { get; set; }
/// <summary>
/// OnChanged callback function
@ -49,7 +49,7 @@ public partial class WorkDateComponent : IDisposable
/// <summary>
/// user preferences
/// </summary>
private UserPref _prefs = new();
private UserPref Prefs = new();
/// <summary>
/// Component Initialization
@ -57,11 +57,11 @@ public partial class WorkDateComponent : IDisposable
protected override async Task OnInitializedAsync()
{
WorkDateContext = new EditContext(SelectedDate);
Prefs.OnChange += ProfileServiceOnOnChange;
_prefs = await Prefs.GetPreferences();
SelectedDate = string.IsNullOrWhiteSpace(_prefs.WorkDate)
Profiles.OnChange += ProfileServiceOnOnChange;
Prefs = await Profiles.GetPreferences();
SelectedDate = string.IsNullOrWhiteSpace(Prefs.WorkDate)
? DateTime.Now
: DateTime.Parse(_prefs.WorkDate);
: DateTime.Parse(Prefs.WorkDate);
}
/// <summary>
@ -70,11 +70,11 @@ public partial class WorkDateComponent : IDisposable
/// <param name="e"></param>
private async Task OnDateChanged(ChangeEventArgs e)
{
var x = DateTime.TryParse(e.Value.ToString(), out var val);
var x = DateTime.TryParse(e.Value.ToString(), out var setDate);
if (x)
{
await Prefs.SetWorkDate(val);
await OnChangedCallback.InvokeAsync($"{val:yyyy-MM-dd}");
await Profiles.SetWorkDate(setDate);
await OnChangedCallback.InvokeAsync($"{setDate:yyyy-MM-dd}");
}
}
@ -84,7 +84,7 @@ public partial class WorkDateComponent : IDisposable
/// <param name="newUserPref"></param>
private void ProfileServiceOnOnChange(UserPref newUserPref)
{
_prefs = newUserPref;
Prefs = newUserPref;
StateHasChanged();
}
@ -93,6 +93,6 @@ public partial class WorkDateComponent : IDisposable
/// </summary>
public void Dispose()
{
Prefs.OnChange -= ProfileServiceOnOnChange;
Profiles.OnChange -= ProfileServiceOnOnChange;
}
}

View file

@ -21,6 +21,19 @@ namespace Wonky.Client.Helpers;
public static class Utils
{
public static Dictionary<string, string> ParseQuery(string query)
{
if (string.IsNullOrWhiteSpace(query) || query.Contains("://"))
return new Dictionary<string, string>();
var elements = query.Split("&");
return elements.Select(
data
=> data.Split("="))
.ToDictionary(element => element[0], element => element[1]);
}
public static bool IsValidEmail(string email)
{
var trimmedEmail = email.Trim();

View file

@ -18,7 +18,7 @@ using Wonky.Entity.Views;
namespace Wonky.Client.HttpInterfaces;
public interface IOfficeUserHttpRepository
public interface IUserHttpRepository
{
Task<List<UserListAdminView>> GetAdvisors();
Task<WebUserInfoView> GetAdvisorInfo(string userId);

View file

@ -25,7 +25,7 @@ using Wonky.Entity.Views;
namespace Wonky.Client.HttpRepository;
public class OfficeUserHttpRepository : IOfficeUserHttpRepository
public class UserHttpRepository : IUserHttpRepository
{
private readonly JsonSerializerOptions? _options = new JsonSerializerOptions
{
@ -33,11 +33,11 @@ public class OfficeUserHttpRepository : IOfficeUserHttpRepository
};
private readonly NavigationManager _navigation;
private ILogger<OfficeUserHttpRepository> _logger;
private ILogger<UserHttpRepository> _logger;
private readonly HttpClient _client;
private readonly ApiConfig _api;
public OfficeUserHttpRepository(HttpClient client, ILogger<OfficeUserHttpRepository> logger,
public UserHttpRepository(HttpClient client, ILogger<UserHttpRepository> logger,
NavigationManager navigation, IOptions<ApiConfig> configuration)
{
_client = client;

View file

@ -4,6 +4,6 @@ public enum PTarget
{
None,
All,
Report,
Order
FrontPage,
OrderPage
}

View file

@ -31,15 +31,15 @@ using Wonky.Entity.Views;
namespace Wonky.Client.Pages;
public partial class ActivityCreatePage : IDisposable
public partial class ActivityCreateCrmPage : IDisposable
{
// Parameters
[CascadingParameter] DraftStateProvider DraftProvider { get; set; }
[Parameter] public string CompanyId { get; set; }
// Services
[Inject] public ILogger<ActivityCreatePage> Logger { get; set; }
[Inject] public ILogger<ActivityCreateCrmPage> Logger { get; set; }
[Inject] public HttpInterceptorService Interceptor { get; set; }
[Inject] public UserPrefService Prefs { get; set; }
[Inject] public UserProfileService Profiles { get; set; }
[Inject] public IToastService Toast { get; set; }
[Inject] public NavigationManager Navigator { get; set; }
[Inject] public ILocalStorageService Storage { get; set; }
@ -93,7 +93,7 @@ public partial class ActivityCreatePage : IDisposable
Interceptor.RegisterEvent();
Interceptor.RegisterBeforeSendEvent();
// User Preferences
UserPrefs = await Prefs.GetPreferences();
UserPrefs = await Profiles.GetPreferences();
// User Info
ThisUserInfo = await Storage.GetItemAsync<UserInfoView>("_xu");
// Fetch Customer from http
@ -225,7 +225,7 @@ public partial class ActivityCreatePage : IDisposable
/// </summary>
private async Task WorkDateConfirmCallback()
{
await Prefs.SetDateConfirmed(true);
await Profiles.SetDateConfirmed(true);
ConfirmWorkDateModal.Hide();
StateHasChanged();
}

View file

@ -25,7 +25,7 @@ using Wonky.Entity.Views;
namespace Wonky.Client.Pages;
public partial class CustomerActivityListPage : IDisposable
public partial class ActivityListCustomerPage : IDisposable
{
[Parameter] public string CompanyId { get; set; } = "";
[Inject] public HttpInterceptorService _interceptor { get; set; }

View file

@ -40,7 +40,7 @@
</div>
@if (ReportStatusView.ReportItems.Any())
{
<AdvisorActivityTableComponent ActivityList="ReportStatusView.ReportItems"/>
<ActivityTableCrmComponent ActivityList="ReportStatusView.ReportItems"/>
}
@if (Working)
{

View file

@ -25,10 +25,10 @@ using Wonky.Entity.Views;
namespace Wonky.Client.Pages;
public partial class ActivityListTodayPage : IDisposable
public partial class ActivityListTodayCrmPage : IDisposable
{
[Inject] public UserPrefService UserPrefService { get; set; }
[Inject] public ILogger<ActivityListTodayPage> Logger { get; set; }
[Inject] public UserProfileService UserProfileService { get; set; }
[Inject] public ILogger<ActivityListTodayCrmPage> Logger { get; set; }
[Inject] public HttpInterceptorService Interceptor { get; set; }
[Inject] public NavigationManager Navigator { get; set; }
[Inject] public ICrmActivityHttpRepository CrmActivityRepo { get; set; }
@ -44,7 +44,7 @@ public partial class ActivityListTodayPage : IDisposable
{
Interceptor.RegisterEvent();
Interceptor.RegisterBeforeSendEvent();
UserPref = await UserPrefService.GetPreferences();
UserPref = await UserProfileService.GetPreferences();
SelectedDate = string.IsNullOrWhiteSpace(UserPref.WorkDate) ? DateTime.Now : DateTime.Parse(UserPref.WorkDate);
ReportExist = await CrmReportRepo.ReportExist($"{SelectedDate:yyyy-MM-dd}");
await GetActivities($"{SelectedDate:yyyy-MM-dd}");

View file

@ -29,13 +29,13 @@ using Wonky.Entity.Views;
namespace Wonky.Client.Pages;
public partial class ActivityViewPage : IDisposable
public partial class ActivityViewCrmPage : IDisposable
{
[Parameter] public string CompanyId { get; set; } = "";
[Parameter] public string OrderId { get; set; } = "";
[Inject] public HttpInterceptorService Interceptor { get; set; }
[Inject] public ICrmActivityHttpRepository ActivityRepo { get; set; }
[Inject] public ILogger<ActivityViewPage> Logger { get; set; }
[Inject] public ILogger<ActivityViewCrmPage> Logger { get; set; }
[Inject] public IToastService Toaster { get; set; }
[Inject] public NavigationManager Navigator { get; set; }
private ReportItemView ReportItem { get; set; } = new();

View file

@ -34,7 +34,7 @@ public partial class CatalogPage : IDisposable
[Inject] public ILocalStorageService Storage { get; set; }
[Inject] public ICatalogHttpRepository ItemRepo { get; set; }
[Inject] public HttpInterceptorService Interceptor { get; set; }
[Inject] public UserPrefService PrefService { get; set; }
[Inject] public UserProfileService ProfileService { get; set; }
private List<SalesItemView> Items { get; set; } = new();
private MetaData MetaInfo { get; set; } = new();
private CatalogPagingParams PageParams = new();
@ -44,7 +44,7 @@ public partial class CatalogPage : IDisposable
protected override async Task OnInitializedAsync()
{
Prefs = await PrefService.GetPreferences();
Prefs = await ProfileService.GetPreferences();
UserInfo = await Storage.GetItemAsync<UserInfoView>("_xu");
PageParams.CountryCode = UserInfo.CountryCode;

View file

@ -1,70 +0,0 @@
// Copyright (C) 2022 FCS Frede's Computer Services.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see [https://www.gnu.org/licenses/agpl-3.0.en.html]
//
using Blazored.LocalStorage;
using Microsoft.AspNetCore.Components;
using Wonky.Client.HttpInterfaces;
using Wonky.Client.HttpRepository;
using Wonky.Client.Models;
using Wonky.Entity.DTO;
using Wonky.Entity.Views;
namespace Wonky.Client.Pages;
public partial class CrmReportViewPage
{
[Parameter] public string ReportDate { get; set; }
[Inject] public ICrmReportHttpRepository ReportRepo { get; set; }
[Inject] public NavigationManager Navigator { get; set; }
[Inject] public ILocalStorageService Storage { get; set; }
private ReportView Report { get; set; } = new();
private List<ReportItemView> Items { get; set; } = new ();
private bool Working { get; set; } = true;
protected override async Task OnInitializedAsync()
{
if (!string.IsNullOrWhiteSpace(ReportDate))
{
await GetReport(ReportDate);
}
Working = false;
}
private async Task Print(PTarget target)
{
var ux = await Storage.GetItemAsync<UserInfoView>("_ux");
if (target == PTarget.Order)
{
Navigator.NavigateTo($"/print/orders/{ux.CountryCode}/{ux.Id}/{ReportDate}");
return;
}
Navigator.NavigateTo($"/print/report/{ux.CountryCode}/{ux.Id}/{ReportDate}");
}
private async Task GetReport(string workDate)
{
Working = true;
Report = new ReportView();
Items = new List<ReportItemView>();
if(workDate != ReportDate)
Navigator.NavigateTo($"/sales-reports/view/{workDate}");
Report = await ReportRepo.GetReport(workDate);
Items = Report.ReportItems.Where(x => x.Lines.Any()).ToList();
Working = false;
}
}

View file

@ -37,10 +37,10 @@ using Wonky.Entity.Views;
namespace Wonky.Client.Pages
{
public partial class CustomerCardCreatePage : IDisposable
public partial class CustomerCreateCrmPage : IDisposable
{
[Inject] public IToastService Toaster { get; set; }
[Inject] public ILogger<CustomerCardCreatePage> Logger { get; set; }
[Inject] public ILogger<CustomerCreateCrmPage> Logger { get; set; }
[Inject] public ILocalStorageService Storage { get; set; }
[Inject] public NavigationManager Navigator { get; set; }
[Inject] public ICrmCompanyHttpRepository CompanyRepo { get; set; }

View file

@ -11,7 +11,7 @@ using Wonky.Entity.Views;
namespace Wonky.Client.Pages;
public partial class CustomerInvoiceListPage : IDisposable
public partial class CustomerInvoiceListCrmPage : IDisposable
{
[Parameter] public string CompanyId { get; set; } = "";
[Inject] public ICrmCompanyHttpRepository CompanyRepo { get; set; }
@ -19,7 +19,7 @@ public partial class CustomerInvoiceListPage : IDisposable
[Inject] public ICrmHistoryHttpRepository HistoryRepo { get; set; }
[Inject] public IToastService Toaster { get; set; }
[Inject] public ILocalStorageService Storage { get; set; }
[Inject] public ILogger<CustomerInvoiceListPage> Logger { get; set; }
[Inject] public ILogger<CustomerInvoiceListCrmPage> Logger { get; set; }
private InvoiceListView CompanyInvoices { get; set; } = new();
private CompanyDto Company { get; set; } = new();
private bool Working { get; set; } = true;

View file

@ -28,10 +28,10 @@ using Wonky.Entity.Views;
namespace Wonky.Client.Pages
{
public partial class CustomerListPage : IDisposable
public partial class CustomerListCrmPage : IDisposable
{
[Inject] public ILocalStorageService Storage { get; set; }
[Inject] public UserPrefService PrefService { get; set; }
[Inject] public UserProfileService ProfileService { get; set; }
[Inject] public ICrmCompanyHttpRepository CompanyRepo { get; set; }
[Inject] public HttpInterceptorService Interceptor { get; set; }
[Inject] public NavigationManager Navigator { get; set; }
@ -54,7 +54,7 @@ namespace Wonky.Client.Pages
protected override async Task OnInitializedAsync()
{
// set preferences
Prefs = await PrefService.GetPreferences();
Prefs = await ProfileService.GetPreferences();
UserInfo = await Storage.GetItemAsync<UserInfoView>("_xu");
PageParams.OrderBy = Prefs.CompanySort;
PageParams.SearchColumn = Prefs.CompanySearch;

View file

@ -22,15 +22,15 @@ using Wonky.Entity.Requests;
namespace Wonky.Client.Pages;
public partial class OfficeCustomerListPage : IDisposable
public partial class CustomerListOfficePage : IDisposable
{
[Parameter] public string UserId { get; set; } = "";
[Parameter] public string CountryCode { get; set; } = "dk";
[Inject] public ILogger<OfficeCustomerListPage> Logger { get; set; }
[Inject] public ILogger<CustomerListOfficePage> Logger { get; set; }
[Inject] public HttpInterceptorService Interceptor { get; set; }
[Inject] public IOfficeCustomerHttpRepository CustomerRepo { get; set; }
[Inject] public UserPrefService UserPrefService { get; set; }
[Inject] public UserProfileService UserProfileService { get; set; }
private List<CompanyDto> _companyList { get; set; } = new();
private MetaData _metaData { get; set; } = new();
private CompanyPagingParams _paging = new();
@ -45,7 +45,7 @@ public partial class OfficeCustomerListPage : IDisposable
Interceptor.RegisterBeforeSendEvent();
// set preferences
UserPref = await UserPrefService.GetPreferences();
UserPref = await UserProfileService.GetPreferences();
_paging.CountryCode = CountryCode;
@ -104,7 +104,7 @@ public partial class OfficeCustomerListPage : IDisposable
if (!string.IsNullOrWhiteSpace(searchTerm) && searchTerm.TrimEnd().Length > 2)
{
_savedSearch = searchTerm;
await UserPrefService.SetCompanyFilterPhrase(searchTerm.Trim());
await UserProfileService.SetCompanyFilterPhrase(searchTerm.Trim());
}
}

View file

@ -27,15 +27,16 @@ using Wonky.Entity.Views;
namespace Wonky.Client.Pages;
public partial class CustomerProductListPage : IDisposable
public partial class CustomerProductListCrmPage : IDisposable
{
[Parameter] public string CompanyId { get; set; } = "";
[Inject] public ICrmHistoryHttpRepository HistoryRepo { get; set; }
[Inject] public ICrmCompanyHttpRepository CompanyRepo { get; set; }
[Inject] public HttpInterceptorService Interceptor { get; set; }
[Inject] public IToastService Toaster { get; set; }
[Inject] public ILogger<CustomerProductListPage> Logger { get; set; }
[Inject] public ILogger<CustomerProductListCrmPage> Logger { get; set; }
[Inject] public ILocalStorageService Storage { get; set; }
private JsonSerializerOptions _options = new JsonSerializerOptions(JsonSerializerDefaults.Web);
private CompanyDto Company { get; set; } = new();
private List<ProductInventoryView> Inventory { get; set; } = new();
private bool Working { get; set; } = true;
@ -64,6 +65,7 @@ public partial class CustomerProductListPage : IDisposable
}
// fetch product inventory
Inventory = await FetchProductInventory();
Logger.LogDebug("CustomerProductListCrmPage => Inventory <= {}", JsonSerializer.Serialize(Inventory, _options));
Working = false;
}

View file

@ -187,7 +187,9 @@
<div class="row g-2">
<div class="col-sm-4">@contact.JobTitle</div>
<div class="col-sm-4">@contact.FirstName @contact.LastName</div>
<div class="col-sm-3">@contact.PhoneDirect</div>
<div class="col-sm-3">
@contact.PhoneDirect
</div>
<div class="col-sm-1 text-end">
<i class="bi-pencil"></i>
</div>

View file

@ -31,11 +31,11 @@ using Wonky.Entity.Views;
namespace Wonky.Client.Pages;
public partial class CustomerCardPage : IDisposable
public partial class CustomerViewCrmPage : IDisposable
{
[Parameter] public string CompanyId { get; set; } = "";
[Inject] public IToastService Toaster { get; set; }
[Inject] public ILogger<CustomerCardPage> Logger { get; set; }
[Inject] public ILogger<CustomerViewCrmPage> Logger { get; set; }
[Inject] public NavigationManager Navigator { get; set; }
[Inject] public ICrmCompanyHttpRepository CompanyRepo { get; set; }
[Inject] public ICrmHistoryHttpRepository HistoryRepo { get; set; }

View file

@ -24,7 +24,7 @@ using Wonky.Entity.Views;
namespace Wonky.Client.Pages;
public partial class AdminKrvItemViewPage : IDisposable
public partial class KrvItemViewAdminPage : IDisposable
{
[Parameter] public string SalesItemId { get; set; } = "";
private SalesItemView _item { get; set; } = new ();

View file

@ -1,84 +0,0 @@
@*
// Copyright (C) 2022 FCS Frede's Computer Services.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see [https://www.gnu.org/licenses/agpl-3.0.en.html]
//
*@
@using Wonky.Client.Components
@using Microsoft.AspNetCore.Authorization
@using Wonky.Client.Models
@page "/office/users/advisors/{CountryCode}/{UserId}/reports/{ReportDate}"
@attribute [Authorize(Roles = "Admin")]
<div class="row mb-3 g-1 d-print-none">
<div class="col-sm-6">
<WorkDateComponent OnChangedCallback="FetchReport" />
</div>
<div class="col-sm-2 d-grid">
<button class="btn btn-warning" @onclick="() => Print(PTarget.Report)"><i class="bi-printer"></i> Rapport</button>
</div>
<div class="col-sm-2 d-grid">
<button class="btn btn-success" @onclick="() => Print(PTarget.Order)"><i class="bi-printer"></i> Ordrer</button>
</div>
<div class="col-sm-2 d-grid">
<button class="btn btn-primary" type="button" onclick="window.print();"><i class="bi-printer"></i> Print</button>
</div>
</div>
@if (ThisTarget is PTarget.Report or PTarget.All)
{
<div class="report-main d-print-grid">
@if (!string.IsNullOrWhiteSpace(Report.ReportData.DayTypeEnum))
{
<PageTitle>@Report.ReportData.Name</PageTitle>
<div class="row">
<div class="col text-center align-content-center">
<h3>@Report.ReportData.Name</h3>
</div>
</div>
<div class="row">
<div class="w-75">
<ReportSummaryComponent ReportData="Report.ReportData" />
</div>
<div class="w-25">
<ReportDistanceLedgerComponent ReportData="Report.ReportData" />
</div>
</div>
<OfficeActivityTableComponent ActivityList="Report.ReportItems" />
<ReportActivityLedgerComponent ReportData="Report.ReportData" />
}
else
{
<div class="row">
<div class="col">Ingen data</div>
</div>
}
</div>
}
@if (ThisTarget is PTarget.Order or PTarget.All)
{
if (Activities.Any())
{
foreach (var item in Activities.Where(item => item.StatusTypeEnum.ToLower() == "order" && item.ProcessStatusEnum.ToLower() == "none"))
{
<ReportItemComponent ReportItem="@item"></ReportItemComponent>
}
}
}
@if (Working)
{
<WorkingThreeDots/>
}

View file

@ -1,135 +0,0 @@
// Copyright (C) 2022 FCS Frede's Computer Services.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see [https://www.gnu.org/licenses/agpl-3.0.en.html]
//
using Blazored.LocalStorage;
using Microsoft.AspNetCore.Components;
using Wonky.Client.HttpInterceptors;
using Wonky.Client.HttpInterfaces;
using Wonky.Client.Models;
using Wonky.Entity.Views;
namespace Wonky.Client.Pages;
public partial class OfficeReportViewPage : IDisposable
{
/// <summary>
/// Country code from url parameter
/// </summary>
[Parameter]
public string CountryCode { get; set; } = "";
/// <summary>
/// Report date from url parameter
/// </summary>
[Parameter]
public string ReportDate { get; set; } = "";
/// <summary>
/// User entity Id from url parameter
/// </summary>
[Parameter]
public string UserId { get; set; } = "";
/// <summary>
/// Injected interceptor service
/// </summary>
[Inject]
public HttpInterceptorService Interceptor { get; set; }
/// <summary>
/// Injected administrative report http repo
/// </summary>
[Inject]
public IOfficeReportHttpRepository ReportRepo { get; set; }
/// <summary>
/// Navigation Manager
/// </summary>
[Inject]
public NavigationManager Navigator { get; set; }
[Inject] public ILogger<OfficeReportViewPage> Logger { get; set; }
[Inject] public ILocalStorageService Storage { get; set; }
/// <summary>
/// Report to render
/// </summary>
private ReportView Report { get; set; } = new();
private PTarget ThisTarget { get; set; } = PTarget.All;
private List<ReportItemView> Activities { get; set; } = new();
private bool Working { get; set; } = true;
protected override async Task OnParametersSetAsync()
{
Interceptor.RegisterEvent();
Interceptor.RegisterBeforeSendEvent();
await Task.Delay(100);
await FetchReport(ReportDate);
Working = false;
}
private void Print(PTarget target)
{
if (target == PTarget.Order)
{
Navigator.NavigateTo($"/print/orders/{CountryCode}/{UserId}/{ReportDate}");
return;
}
Navigator.NavigateTo($"/print/report/{CountryCode}/{UserId}/{ReportDate}");
}
/// <summary>
/// Work date component event handler
/// </summary>
/// <param name="workDate"></param>
private async Task FetchReport(string workDate)
{
if (workDate != ReportDate)
{
Navigator.NavigateTo($"/office/users/advisors/{CountryCode}/{UserId}/reports/{workDate}");
return;
}
Working = true;
Report = new ReportView();
Activities = new List<ReportItemView>();
Report = await FetchUserReport(UserId, workDate);
Activities = Report.ReportItems.Where(x => x.Lines.Any()).ToList();
await Storage.SetItemAsync($"{UserId}-{ReportDate}", Report);
Working = false;
}
/// <summary>
/// Get report for user with entity Id for work date
/// </summary>
/// <param name="userId"></param>
/// <param name="workDate"></param>
/// <returns></returns>
private async Task<ReportView> FetchUserReport(string userId, string workDate)
{
Working = true;
var x = Report = await ReportRepo.GetReport(userId, workDate);
Working = false;
return x;
}
public void Dispose()
{
Interceptor.DisposeEvent();
}
}

View file

@ -28,16 +28,16 @@ using Wonky.Entity.Views;
namespace Wonky.Client.Pages;
public partial class OfficeOrderNewPage : IDisposable
public partial class OrderCreateOfficePage : IDisposable
{
[CascadingParameter] DraftStateProvider DraftStateProvider { get; set; }
[Parameter] public string CompanyId { get; set; }
[Inject] public HttpInterceptorService Interceptor { get; set; }
[Inject] public IOfficeCustomerHttpRepository OfficeCustomerRepo { get; set; }
[Inject] public IOfficeUserHttpRepository OfficeUserRepo { get; set; }
[Inject] public IUserHttpRepository UserRepo { get; set; }
[Inject] public ICatalogHttpRepository CatalogRepo { get; set; }
[Inject] public ICrmActivityHttpRepository CrmActivityRepo { get; set; }
[Inject] public ILogger<OfficeOrderNewPage> Logger { get; set; }
[Inject] public ILogger<OrderCreateOfficePage> Logger { get; set; }
private ActivityDto _activity { get; set; } = new();
private EditContext _editContext { get; set; }
@ -69,7 +69,7 @@ public partial class OfficeOrderNewPage : IDisposable
_editContext.OnFieldChanged += HandleFieldChanged;
_editContext.OnValidationStateChanged += ValidationChanged;
_userInfo = await OfficeUserRepo.GetAdvisorInfo(_company.SalesRepId);
_userInfo = await UserRepo.GetAdvisorInfo(_company.SalesRepId);
_activity.ActivityDate = $"{DateTime.Now:yyyy-MM-dd}" ;

View file

@ -30,7 +30,7 @@ using Wonky.Client.Services;
namespace Wonky.Client.Pages;
public partial class OfficeOrderViewPage : IDisposable
public partial class OrderViewOfficePage : IDisposable
{
[Parameter] public string CompanyId { get; set; } = "";
[Parameter] public string OrderId { get; set; } = "";
@ -38,8 +38,8 @@ public partial class OfficeOrderViewPage : IDisposable
[Inject] public ICrmActivityHttpRepository ActivityRepo { get; set; }
[Inject] public ISendMailService MailService { get; set; }
[Inject] public ILocalStorageService Storage { get; set; }
[Inject] public IOfficeUserHttpRepository UserRepo { get; set; }
[Inject] public ILogger<OfficeOrderViewPage> Logger { get; set; }
[Inject] public IUserHttpRepository UserRepo { get; set; }
[Inject] public ILogger<OrderViewOfficePage> Logger { get; set; }
[Inject] public IToastService Toast { get; set; }
private ReportItemView _reportItem { get; set; } = new();
private bool _isNotified { get; set; }

View file

@ -25,17 +25,16 @@ using Wonky.Entity.Views;
namespace Wonky.Client.Pages;
public partial class WarehouseOrderViewPage : IDisposable
public partial class OrderViewWarehousePage : IDisposable
{
[Parameter] public string OrderId { get; set; } = "";
[Inject] public HttpInterceptorService _interceptor { get; set; }
[Inject] public IWarehouseHttpRepository _warehouseRepo { get; set; }
[Inject] public NavigationManager _navigator { get; set; }
[Inject] public IToastService _toast { get; set; }
[Inject] public ILogger<WarehouseOrderViewPage> _logger { get; set; }
[Inject] public ILogger<OrderViewWarehousePage> _logger { get; set; }
private WarehouseOrderView _order { get; set; } = new();
private bool Loading { get; set; }
private bool Working { get; set; }
protected override async Task OnParametersSetAsync()

View file

@ -21,8 +21,11 @@
@attribute [Authorize(Roles = "Admin,Advisor")]
<div class="row mb-3 d-print-none">
<div class="col-sm-12 d-grid">
<button class="btn btn-primary" type="button" @onclick="Print">Print</button>
<div class="col-sm-6 d-grid">
<a class="btn btn-info" href="@ReturnUrl"><i class="bi-back"></i> Tilbage</a>
</div>
<div class="col-sm-6 d-grid">
<button class="btn btn-primary" type="button" @onclick="Print"><i class="bi-printer"></i> Udskriv</button>
</div>
</div>
@ -41,6 +44,6 @@
<ReportDistanceLedgerComponent ReportData="Report.ReportData"/>
</div>
</div>
<OfficeActivityTableComponent ActivityList="Report.ReportItems"/>
<ReportActivityTableOfficeComponent ActivityList="Report.ReportItems"/>
<ReportActivityLedgerComponent ReportData="Report.ReportData"/>
</div>

View file

@ -13,14 +13,16 @@
// along with this program. If not, see [https://www.gnu.org/licenses/agpl-3.0.en.html]
//
using System.Runtime.CompilerServices;
using Blazored.LocalStorage;
using Microsoft.AspNetCore.Components;
using Microsoft.JSInterop;
using Wonky.Client.Helpers;
using Wonky.Entity.Views;
namespace Wonky.Client.Pages;
public partial class PrintReportPage
public partial class PrintFrontPage
{
[Parameter] public string CountryCode { get; set; } = "";
[Parameter] public string UserId { get; set; } = "";
@ -28,13 +30,17 @@ public partial class PrintReportPage
[Inject] public ILocalStorageService Storage { get; set; }
[Inject] public NavigationManager Navigator { get; set; }
[Inject] private IJSRuntime JSRuntime { get; set; }
[Inject] public ILogger<PrintReportPage> Logger { get; set; }
[Inject] public ILogger<PrintFrontPage> Logger { get; set; }
private ReportView Report { get; set; } = new();
private IJSObjectReference JsModule { get; set; }
private bool Printed { get; set; }
private string ReturnUrl { get; set; } = "";
protected override async Task OnInitializedAsync()
{
var uri = new Uri(Navigator.Uri);
var query = Utils.ParseQuery(uri.Query[1..]);
ReturnUrl = string.IsNullOrWhiteSpace(query["returnUrl"]) ? "/" : $"{query["returnUrl"]}" ;
Report = await Storage.GetItemAsync<ReportView>($"{UserId}-{ReportDate}");
}
@ -49,10 +55,9 @@ public partial class PrintReportPage
private async Task Print()
{
if(!Printed)
Printed = true;
await JsModule.InvokeVoidAsync("printInvoke");
Navigator.NavigateTo($"/office/users/advisors/{CountryCode}/{UserId}/reports/{ReportDate}");
Navigator.NavigateTo(ReturnUrl);
}
/*

View file

@ -21,12 +21,26 @@
@attribute [Authorize(Roles = "Admin,Advisor")]
<div class="row mb-3 d-print-none">
<div class="col-sm-12 d-grid">
<button class="btn btn-primary" type="button" @onclick="Print">Print</button>
<div class="col-sm-6 d-grid">
<a class="btn btn-info" href="@ReturnUrl"><i class="bi-back"></i> Tilbage</a>
</div>
<div class="col-sm-6 d-grid">
<button class="btn btn-primary" type="button" @onclick="Print"><i class="bi-printer"></i> Udskriv</button>
</div>
</div>
@foreach (var item in Items.Where(item => item.StatusTypeEnum.ToLower() == "order" && item.ProcessStatusEnum.ToLower() == "none"))
@if (Items.Any(item => item.StatusTypeEnum.ToLower() == "order" && item.ProcessStatusEnum.ToLower() == "none"))
{
foreach (var item in Items.Where(item => item.StatusTypeEnum.ToLower() == "order" && item.ProcessStatusEnum.ToLower() == "none"))
{
<ReportItemComponent ReportItem="@item"></ReportItemComponent>
}
}
else
{
<div class="row">
<div class="col">
<h3 class="text-center fw-bold">Der er ingen ordrer til udskrivning</h3>
</div>
</div>
}

View file

@ -16,11 +16,12 @@
using Blazored.LocalStorage;
using Microsoft.AspNetCore.Components;
using Microsoft.JSInterop;
using Wonky.Client.Helpers;
using Wonky.Entity.Views;
namespace Wonky.Client.Pages;
public partial class PrintOrdersPage
public partial class PrintOrderPage
{
[Parameter] public string CountryCode { get; set; } = "";
[Parameter] public string UserId { get; set; } = "";
@ -28,12 +29,11 @@ public partial class PrintOrdersPage
[Inject] public ILocalStorageService Storage { get; set; }
[Inject] public NavigationManager Navigator { get; set; }
[Inject] private IJSRuntime JSRuntime { get; set; }
[Inject] public ILogger<PrintOrdersPage> Logger { get; set; }
[Inject] public ILogger<PrintOrderPage> Logger { get; set; }
private ReportView Report { get; set; } = new();
private List<ReportItemView> Items { get; set; } = new();
private IJSObjectReference JsModule { get; set; }
private string ReturnUrl { get; set; } = "";
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
@ -45,6 +45,10 @@ public partial class PrintOrdersPage
protected override async Task OnInitializedAsync()
{
var uri = new Uri(Navigator.Uri);
var query = Utils.ParseQuery(uri.Query[1..]);
ReturnUrl = string.IsNullOrWhiteSpace(query["returnUrl"]) ? "/" : $"{query["returnUrl"]}";
Report = await Storage.GetItemAsync<ReportView>($"{UserId}-{ReportDate}");
Items = Report.ReportItems;
}
@ -53,7 +57,7 @@ public partial class PrintOrdersPage
{
await JsModule.InvokeVoidAsync("printInvoke");
Navigator.NavigateTo($"/office/users/advisors/{CountryCode}/{UserId}/reports/{ReportDate}");
Navigator.NavigateTo(ReturnUrl);
}
/*

View file

@ -13,11 +13,11 @@ using Wonky.Entity.Views;
namespace Wonky.Client.Pages;
public partial class QuoteListPage : IDisposable
public partial class QuoteListCrmPage : IDisposable
{
[Inject] public ICrmActivityHttpRepository ActivityRepo { get; set; }
[Inject] public HttpInterceptorService Interceptor { get; set; }
[Inject] public ILogger<QuoteListPage> Logger { get; set; }
[Inject] public ILogger<QuoteListCrmPage> Logger { get; set; }
[Inject] public IToastService Toaster { get; set; }
[Inject] public ILocalStorageService Storage { get; set; }
private List<ReportItemView> Quotes { get; set; } = new();

View file

@ -27,14 +27,14 @@ using Wonky.Entity.Views;
namespace Wonky.Client.Pages;
public partial class CrmReportNewPage : IDisposable
public partial class ReportCreateCrmPage : IDisposable
{
[Inject] public HttpInterceptorService Interceptor { get; set; }
[Inject] public UserPrefService PrefService { get; set; }
[Inject] public UserProfileService ProfileService { get; set; }
[Inject] public ICrmActivityHttpRepository CrmActivityRepo { get; set; }
[Inject] public ICrmReportHttpRepository CrmReportRepo { get; set; }
[Inject] public NavigationManager Navigator { get; set; }
[Inject] public ILogger<CrmReportNewPage> Logger { get; set; }
[Inject] public ILogger<ReportCreateCrmPage> Logger { get; set; }
[Inject] public IToastService Toaster { get; set; }
private EditContext ReportContext { get; set; }
private ReportDto Report { get; set; } = new();
@ -64,7 +64,7 @@ public partial class CrmReportNewPage : IDisposable
ReportContext.OnFieldChanged += HandleFieldChanged;
ReportContext.OnValidationStateChanged += ValidationChanged;
Prefs = await PrefService.GetPreferences();
Prefs = await ProfileService.GetPreferences();
_workDate = DateTime.Now;
if (!string.IsNullOrWhiteSpace(Prefs.WorkDate))
_workDate = DateTime.Parse(Prefs.WorkDate);
@ -134,9 +134,9 @@ public partial class CrmReportNewPage : IDisposable
Toaster.ShowInfo($"{result.Message}", $"HTTP Status");
// reset km and date confirmation
await PrefService.SetKmMorning(0);
await ProfileService.SetKmMorning(0);
// reset date confirmed
await PrefService.SetDateConfirmed(false);
await ProfileService.SetDateConfirmed(false);
Navigator.NavigateTo($"/sales-reports/view/{_workDate:yyyy-MM-dd}");
}
/// <summary>

View file

@ -18,12 +18,12 @@
@using Wonky.Client.Components
@page "/sales-reports"
<div class="alert text-black border border-1">
<div class="col">
<div class="card">
<div class="card-header">
<h3>Rapport Arkiv</h3>
</div>
<ReportTableCrmComponent ReportList="ReportList" OnShowReport="ShowThisReport"/>
</div>
<ReportTableComponent ReportList="ReportList" />
@if (Working)

View file

@ -22,10 +22,12 @@ using Wonky.Entity.Views;
namespace Wonky.Client.Pages;
public partial class CrmReportListPage : IDisposable
public partial class ReportListCrmPage : IDisposable
{
[Inject] public ICrmReportHttpRepository CrmReportRepo { get; set; }
[Inject] public ICrmReportHttpRepository ReportRepo { get; set; }
[Inject] public HttpInterceptorService Interceptor { get; set; }
[Inject] public NavigationManager Navigator { get; set; }
[Inject] public ILogger<ReportListCrmPage> Logger { get; set; }
private List<SalesReportListView> ReportList { get; set; } = new();
private bool Working { get; set; } = true;
@ -35,10 +37,19 @@ public partial class CrmReportListPage : IDisposable
Interceptor.RegisterEvent();
Interceptor.RegisterBeforeSendEvent();
ReportList = await CrmReportRepo.GetReports();
ReportList = await ReportRepo.GetReports();
if (ReportList.Any())
ReportList = ReportList.OrderByDescending(x => x.ReportDate).ToList();
Working = false;
}
private void ShowThisReport(string reportDate)
{
Logger.LogDebug("CrmReportListPage => ShowThisReport <= {}", reportDate);
Navigator.NavigateTo($"/sales-reports/view/{reportDate}");
}
public void Dispose()
{
Interceptor.DisposeEvent();

View file

@ -21,16 +21,10 @@
@page "/office/users/advisors/{CountryCode}/{UserId}/reports"
<div class="card">
<div class="card-header bg-dark text-white">
<div class="row">
<div class="col">
<h3>Rapport Arkiv</h3>
</div>
</div>
</div>
<div class="card-body">
<OfficeReportTableComponent CountryCode="@CountryCode" UserId="@UserId" ReportList="@ActivityReports" />
<div class="card-header">
<h3>Rapport Arkiv - @UserInfo.FirstName @UserInfo.LastName</h3>
</div>
<ReportTableOfficeComponent OnShowReport="ShowThisReport" CountryCode="@CountryCode" UserId="@UserId" ReportList="@ActivityReports" />
</div>

View file

@ -13,6 +13,7 @@
// along with this program. If not, see [https://www.gnu.org/licenses/agpl-3.0.en.html]
//
using System.Runtime.CompilerServices;
using Microsoft.AspNetCore.Components;
using Toolbelt.Blazor;
using Wonky.Client.HttpInterceptors;
@ -22,30 +23,37 @@ using Wonky.Entity.Views;
namespace Wonky.Client.Pages;
public partial class OfficeReportListPage : IDisposable
public partial class ReportListOfficePage : IDisposable
{
[Parameter] public string UserId { get; set; } = "";
[Parameter] public string CountryCode { get; set; } = "";
[Inject] public IOfficeReportHttpRepository ReportRepo { get; set; }
[Inject] public HttpInterceptorService Interceptor { get; set; }
[Inject] public IUserHttpRepository UserRepo { get; set; }
[Inject] public NavigationManager Navigator { get; set; }
private List<SalesReportListView> ActivityReports { get; set; } = new();
private bool Working { get; set; } = true;
private WebUserInfoView UserInfo { get; set; } = new();
protected override async Task OnInitializedAsync()
protected override async Task OnParametersSetAsync()
{
Interceptor.RegisterEvent();
Interceptor.RegisterBeforeSendEvent();
await FetchReports();
Working = false;
}
UserInfo = await UserRepo.GetAdvisorInfo(UserId);
private async Task FetchReports()
{
var reports = await ReportRepo.GetReports(UserId);
if (reports.Any())
ActivityReports = reports.OrderByDescending(x => x.ReportDate).ToList();
Working = false;
}
private void ShowThisReport(string reportDate)
{
var uri = new Uri(Navigator.Uri);
var url = uri.AbsoluteUri;
Navigator.NavigateTo($"{url}/{reportDate}");
}
/// <summary>Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.</summary>

View file

@ -21,23 +21,22 @@
@page "/sales-reports/view/{ReportDate}"
@attribute [Authorize(Roles = "Advisor,Admin,Supervisor")]
<div class="report-main">
<div class="row bg-dark text-white rounded-2 mb-2 py-2 align-items-center d-print-none">
<div class="row bg-dark text-white rounded-2 mb-2 py-2 align-items-center d-print-none">
<div class="col-sm-6">
<WorkDateComponent OnChangedCallback="GetReport"/>
<WorkDateComponent OnChangedCallback="FetchReport"/>
</div>
<div class="col-sm-2 d-grid">
<button class="btn btn-warning" @onclick="() => Print(PTarget.Report)"><i class="bi-printer"></i> Rapport</button>
<button class="btn btn-warning" @onclick="() => Print(PTarget.FrontPage)"><i class="bi-printer"></i> Forside</button>
</div>
<div class="col-sm-2 d-grid">
<button class="btn btn-success" @onclick="() => Print(PTarget.Order)"><i class="bi-printer"></i> Ordrer</button>
<button class="btn btn-success" @onclick="() => Print(PTarget.OrderPage)"><i class="bi-printer"></i> Ordrer</button>
</div>
<div class="col-sm-2 d-grid">
<button class="btn btn-primary" type="button" onclick="window.print();"><i class="bi-printer"></i> Print</button>
</div>
<button class="btn btn-primary" type="button" onclick="window.print();"><i class="bi-printer"></i> Rapport</button>
</div>
</div>
<div class="report-main d-print-grid">
@if (!string.IsNullOrWhiteSpace(Report.ReportData.DayTypeEnum))
{
<PageTitle>@Report.ReportData.Name</PageTitle>
@ -52,27 +51,21 @@
<ReportDistanceLedgerComponent ReportData="Report.ReportData"/>
</div>
</div>
<OfficeActivityTableComponent ActivityList="Report.ReportItems"/>
<ReportActivityTableOfficeComponent ActivityList="Report.ReportItems"/>
<ReportActivityLedgerComponent ReportData="Report.ReportData"/>
}
else
{
<div class="row">
<div class="col">Ingen data</div>
<div class="col">Ingen Rapport data</div>
</div>
}
</div>
@if (Items.Any())
@if (Activities.Any())
{
@foreach (var item in Items)
@foreach (var item in Activities)
{
<ReportItemComponent ReportItem="@item"></ReportItemComponent>
}
}
@if (Working)
{
<WorkingThreeDots/>
}

View file

@ -0,0 +1,131 @@
// Copyright (C) 2022 FCS Frede's Computer Services.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see [https://www.gnu.org/licenses/agpl-3.0.en.html]
//
using Blazored.LocalStorage;
using Microsoft.AspNetCore.Components;
using Wonky.Client.HttpInterceptors;
using Wonky.Client.HttpInterfaces;
using Wonky.Client.Models;
using Wonky.Client.Services;
using Wonky.Entity.Views;
namespace Wonky.Client.Pages;
public partial class ReportViewCrmPage : IDisposable
{
[Parameter] public string ReportDate { get; set; }
[Inject] public ICrmReportHttpRepository ReportRepo { get; set; }
[Inject] public NavigationManager Navigator { get; set; }
[Inject] public ILocalStorageService Storage { get; set; }
[Inject] public HttpInterceptorService Interceptor { get; set; }
[Inject] public ILogger<ReportViewCrmPage> Logger { get; set; }
[Inject] public UserProfileService ProfileService { get; set; }
private UserPref Prefs { get; set; } = new();
private ReportView Report { get; set; } = new();
private List<ReportItemView> Activities { get; set; } = new ();
private bool Working { get; set; }
private UserInfoView UserInfo { get; set; } = new();
private string ReturnUrl = "";
protected override async Task OnInitializedAsync()
{
Interceptor.RegisterEvent();
Interceptor.RegisterBeforeSendEvent();
UserInfo = await Storage.GetItemAsync<UserInfoView>("_xu");
ProfileService.OnChange += ProfileServiceOnOnChange;
await ProfileService.SetWorkDate(DateTime.Parse(ReportDate));
if(!string.IsNullOrWhiteSpace(ReportDate))
await FetchReport(ReportDate);
}
private void Print(PTarget target)
{
ReturnUrl = new Uri(Navigator.Uri).AbsolutePath;
switch (target)
{
case PTarget.OrderPage:
Navigator.NavigateTo($"/print/orders/{UserInfo.CountryCode.ToLower()}/{UserInfo.Id}/{ReportDate}?returnUrl={ReturnUrl}");
break;
case PTarget.FrontPage:
Navigator.NavigateTo($"/print/report/{UserInfo.CountryCode.ToLower()}/{UserInfo.Id}/{ReportDate}?returnUrl={ReturnUrl}");
break;
case PTarget.None:
break;
case PTarget.All:
break;
default:
throw new ArgumentOutOfRangeException(nameof(target), target, null);
}
}
private async Task FetchReport(string workDate)
{
// remove busy signal if report is empty
if (string.IsNullOrWhiteSpace(Report.ReportData.ReportDate))
{
Working = false;
}
// ensure the browser address bar contains the correct link
Navigator.NavigateTo($"/sales-reports/view/{workDate}", false, true);
// return if we are already at it
if (Working)
{
return;
}
// reset variables
Report = new ReportView();
Activities = new List<ReportItemView>();
// set busy signal
Working = true;
// fetch report
Report = await ReportRepo.GetReport(workDate);
// extract activities
Activities = Report.ReportItems.Where(x => x.Lines.Any()).ToList();
// store the report locally
if (!string.IsNullOrWhiteSpace(Report.ReportData.ReportDate))
{
await Storage.SetItemAsync($"{UserInfo.Id}-{Report.ReportData.ReportDate}", Report);
}
// remove busy signal
Working = false;
}
private void ProfileServiceOnOnChange(UserPref userPref)
{
Prefs = userPref;
ReportDate = Prefs.WorkDate;
StateHasChanged();
}
public void Dispose()
{
ProfileService.OnChange -= ProfileServiceOnOnChange;
Interceptor.DisposeEvent();
}
}

View file

@ -0,0 +1,73 @@
@*
// Copyright (C) 2022 FCS Frede's Computer Services.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see [https://www.gnu.org/licenses/agpl-3.0.en.html]
//
*@
@using Wonky.Client.Components
@using Microsoft.AspNetCore.Authorization
@using Wonky.Client.Models
@page "/office/users/advisors/{CountryCode}/{UserId}/reports/{ReportDate}"
@attribute [Authorize(Roles = "Admin")]
<div class="row pt-2 pb-2 mb-3 rounded-2 d-print-none bg-dark text-white">
<div class="col-sm-6">
<WorkDateComponent OnChangedCallback="FetchUserReport"/>
</div>
<div class="col-sm-2 d-grid">
<button class="btn btn-warning" @onclick="() => Print(PTarget.FrontPage)"><i class="bi-printer"></i> Forside</button>
</div>
<div class="col-sm-2 d-grid">
<button class="btn btn-success" @onclick="() => Print(PTarget.OrderPage)"><i class="bi-printer"></i> Ordrer</button>
</div>
<div class="col-sm-2 d-grid">
<button class="btn btn-primary" type="button" onclick="window.print();"><i class="bi-printer"></i> Rapport</button>
</div>
</div>
<div class="report-main d-print-print">
@if (!string.IsNullOrWhiteSpace(Report.ReportData.DayTypeEnum))
{
<PageTitle>@Report.ReportData.Name</PageTitle>
<div class="row">
<div class="col text-center align-content-center">
<h3>@Report.ReportData.Name</h3>
</div>
</div>
<div class="row">
<div class="w-75">
<ReportSummaryComponent ReportData="Report.ReportData"/>
</div>
<div class="w-25">
<ReportDistanceLedgerComponent ReportData="Report.ReportData"/>
</div>
</div>
<ReportActivityTableOfficeComponent ActivityList="Report.ReportItems"/>
<ReportActivityLedgerComponent ReportData="Report.ReportData"/>
}
else
{
<div class="row">
<div class="col">Ingen rapport data</div>
</div>
}
</div>
@if (Activities.Any())
{
foreach (var item in Activities.Where(item => item.StatusTypeEnum.ToLower() == "order" && item.ProcessStatusEnum.ToLower() == "none"))
{
<ReportItemComponent ReportItem="@item" />
}
}

View file

@ -0,0 +1,180 @@
// Copyright (C) 2022 FCS Frede's Computer Services.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see [https://www.gnu.org/licenses/agpl-3.0.en.html]
//
using Blazored.LocalStorage;
using Microsoft.AspNetCore.Components;
using Wonky.Client.HttpInterceptors;
using Wonky.Client.HttpInterfaces;
using Wonky.Client.Models;
using Wonky.Client.Services;
using Wonky.Entity.Views;
namespace Wonky.Client.Pages;
public partial class ReportViewOfficePage : IDisposable
{
/// <summary>
/// Country code from url parameter
/// </summary>
[Parameter]
public string CountryCode { get; set; } = "";
/// <summary>
/// User entity Id from url parameter
/// </summary>
[Parameter]
public string UserId { get; set; } = "";
/// <summary>
/// Report Date
/// </summary>
[Parameter]
public string ReportDate { get; set; } = "";
/// <summary>
/// Injected interceptor service
/// </summary>
[Inject]
public HttpInterceptorService Interceptor { get; set; }
/// <summary>
/// Injected administrative report http repo
/// </summary>
[Inject]
public IOfficeReportHttpRepository ReportRepo { get; set; }
/// <summary>
/// Navigation Manager
/// </summary>
[Inject]
public NavigationManager Navigator { get; set; }
/// <summary>
/// Logger service
/// </summary>
[Inject]
public ILogger<ReportViewOfficePage> Logger { get; set; }
/// <summary>
/// Storage service
/// </summary>
[Inject]
public ILocalStorageService Storage { get; set; }
/// <summary>
/// Preference service
/// </summary>
[Inject]
public UserProfileService ProfileService { get; set; }
private ReportView Report { get; set; } = new();
private List<ReportItemView> Activities { get; set; } = new();
private bool Working { get; set; } = true;
private UserPref Prefs = new();
private string ReturnUrl = "";
private string PrintUrl = "";
protected override async Task OnParametersSetAsync()
{
Interceptor.RegisterEvent();
Interceptor.RegisterBeforeSendEvent();
ProfileService.OnChange += ProfileServiceOnOnChange;
await ProfileService.SetWorkDate(DateTime.Parse(ReportDate));
await FetchUserReport(ReportDate);
}
private void Print(PTarget target)
{
ReturnUrl = new Uri(Navigator.Uri).AbsolutePath;
switch (target)
{
case PTarget.OrderPage:
Navigator.NavigateTo($"/print/orders/{CountryCode}/{UserId}/{ReportDate}?returnUrl={ReturnUrl}");
break;
case PTarget.FrontPage:
Navigator.NavigateTo($"/print/report/{CountryCode}/{UserId}/{ReportDate}?returnUrl={ReturnUrl}");
break;
case PTarget.None:
break;
case PTarget.All:
break;
default:
throw new ArgumentOutOfRangeException(nameof(target), target, null);
}
}
/// <summary>
/// Work date component event handler
/// </summary>
/// <param name="workDate"></param>
private async Task FetchUserReport(string workDate)
{
// remove busy signal if report is empty
if (string.IsNullOrWhiteSpace(Report.ReportData.ReportDate))
{
Working = false;
}
ReportDate = workDate;
// ensure the browser address bar contains the correct link
Navigator.NavigateTo($"/office/users/advisors/{CountryCode}/{UserId}/reports/{workDate}", false, true);
// return if we are already at it
if (Working)
{
return;
}
// reset variables
Report = new ReportView();
Activities = new List<ReportItemView>();
// set busy signal
Working = true;
// fetch report
Report = await ReportRepo.GetReport(UserId, workDate);
// extract activities
Activities = Report.ReportItems.Where(x => x.Lines.Any()).ToList();
// store locally
if (!string.IsNullOrWhiteSpace(Report.ReportData.ReportDate))
{
await Storage.SetItemAsync($"{UserId}-{workDate}", Report);
}
// remove busy signal
Working = false;
}
private void ProfileServiceOnOnChange(UserPref userPref)
{
Logger.LogDebug("OfficeReportViewPage => ProfileServiceOnOnChange");
Prefs = userPref;
Logger.LogDebug("OfficeReportViewPage => ProfileServiceOnOnChange => Prefs.WorkDate <= {}", Prefs.WorkDate);
ReportDate = Prefs.WorkDate;
StateHasChanged();
}
public void Dispose()
{
Interceptor.DisposeEvent();
ProfileService.OnChange -= ProfileServiceOnOnChange;
}
}

View file

@ -25,10 +25,10 @@ using Wonky.Entity.Views;
namespace Wonky.Client.Pages;
public partial class CrmTaskItemListPage : IDisposable
public partial class TaskItemListCrmPage : IDisposable
{
[Inject] public UserPrefService UserPrefService { get; set; }
[Inject] public ILogger<CrmTaskItemListPage> Logger { get; set; }
[Inject] public UserProfileService UserProfileService { get; set; }
[Inject] public ILogger<TaskItemListCrmPage> Logger { get; set; }
[Inject] public HttpInterceptorService Interceptor { get; set; }
[Inject] public NavigationManager Navigator { get; set; }
[Inject] public ICrmTaskItemHttpRepository TaskItemRepo { get; set; }
@ -41,7 +41,7 @@ public partial class CrmTaskItemListPage : IDisposable
protected override async Task OnInitializedAsync()
{
Prefs = await UserPrefService.GetPreferences();
Prefs = await UserProfileService.GetPreferences();
if(!string.IsNullOrWhiteSpace(Prefs.WorkDate))
WorkDate = Prefs.WorkDate;

View file

@ -24,7 +24,7 @@ using Wonky.Entity.DTO;
namespace Wonky.Client.Pages;
public partial class CrmTaskItemViewPage : IDisposable
public partial class TaskItemViewCrmPage : IDisposable
{
[Parameter] public string TaskItemId { get; set; }
[Inject] public HttpInterceptorService _interceptor { get; set; }

View file

@ -22,11 +22,11 @@ using Wonky.Entity.Views;
namespace Wonky.Client.Pages;
public partial class OfficeUserListPage : IDisposable
public partial class UserListOfficePage : IDisposable
{
[Parameter] public string CountryCode { get; set; } = "";
[Inject] public HttpInterceptorService _interceptor { get; set; }
[Inject] public IOfficeUserHttpRepository OfficeUserRepo { get; set; }
[Inject] public IUserHttpRepository UserRepo { get; set; }
private List<UserListAdminView> _salesReps { get; set; } = new();
private bool Working { get; set; } = true;
@ -35,7 +35,7 @@ public partial class OfficeUserListPage : IDisposable
{
_interceptor.RegisterEvent();
_interceptor.RegisterBeforeSendEvent();
var AdvisorList = await OfficeUserRepo.GetAdvisors();
var AdvisorList = await UserRepo.GetAdvisors();
_salesReps = AdvisorList
.Where(x => x.CountryCode.ToLower() == CountryCode && Convert.ToInt32(x.SalesRep) < 100)
.ToList();

View file

@ -22,15 +22,15 @@ using Wonky.Entity.Requests;
namespace Wonky.Client.Pages;
public partial class OfficeCustomerSalesRepListPage : IDisposable
public partial class UserListSalesRepPage : IDisposable
{
[Parameter] public string UserId { get; set; } = "";
[Parameter] public string CountryCode { get; set; } = "dk";
[Inject] public ILogger<OfficeCustomerSalesRepListPage> Logger { get; set; }
[Inject] public ILogger<UserListSalesRepPage> Logger { get; set; }
[Inject] public HttpInterceptorService Interceptor { get; set; }
[Inject] public IOfficeCustomerHttpRepository CustomerRepo { get; set; }
[Inject] public UserPrefService UserPrefService { get; set; }
[Inject] public UserProfileService UserProfileService { get; set; }
private List<CompanyDto> _companyList { get; set; } = new();
private MetaData _metaData { get; set; } = new();
private CompanyPagingParams _paging = new();
@ -45,7 +45,7 @@ public partial class OfficeCustomerSalesRepListPage : IDisposable
Interceptor.RegisterBeforeSendEvent();
// set preferences
UserPref = await UserPrefService.GetPreferences();
UserPref = await UserProfileService.GetPreferences();
_paging.CountryCode = CountryCode;
_paging.OrderBy = UserPref.CompanySort;
_paging.SearchColumn = UserPref.CompanySearch;
@ -103,7 +103,7 @@ public partial class OfficeCustomerSalesRepListPage : IDisposable
if (!string.IsNullOrWhiteSpace(searchTerm) && searchTerm.TrimEnd().Length > 2)
{
_savedSearch = searchTerm;
await UserPrefService.SetCompanyFilterPhrase(searchTerm.Trim());
await UserProfileService.SetCompanyFilterPhrase(searchTerm.Trim());
}
}

View file

@ -26,13 +26,13 @@ using Wonky.Entity.Views;
namespace Wonky.Client.Pages;
public partial class OfficeUserViewPage : IDisposable
public partial class UserViewOfficePage : IDisposable
{
[Parameter] public string UserId { get; set; } = "";
[Parameter] public string CountryCode { get; set; } = "";
[Inject] public HttpInterceptorService _interceptor { get; set; }
[Inject] public IOfficeUserHttpRepository OfficeUserRepo { get; set; }
[Inject] public ILogger<OfficeUserViewPage> _logger { get; set; }
[Inject] public IUserHttpRepository UserRepo { get; set; }
[Inject] public ILogger<UserViewOfficePage> _logger { get; set; }
[Inject] public NavigationManager _navigator { get; set; }
[Inject] public IToastService _toast { get; set; }
private WebUserInfoView _userInfo { get; set; } = new();
@ -56,7 +56,7 @@ public partial class OfficeUserViewPage : IDisposable
_interceptor.RegisterEvent();
_interceptor.RegisterBeforeSendEvent();
_userInfo = await OfficeUserRepo.GetAdvisorInfo(UserId);
_userInfo = await UserRepo.GetAdvisorInfo(UserId);
_updateInfo.Email = _userInfo.Email;
_updateInfo.CountryCode = _userInfo.CountryCode;
@ -75,7 +75,7 @@ public partial class OfficeUserViewPage : IDisposable
{
Working = true;
_toast.ShowInfo("Sender data til server ...");
await OfficeUserRepo.UpdateAdvisor(UserId, _updateInfo);
await UserRepo.UpdateAdvisor(UserId, _updateInfo);
Working = false;
}
@ -103,7 +103,7 @@ public partial class OfficeUserViewPage : IDisposable
if (Working)
return;
Working = true;
await OfficeUserRepo.ResetUserPassword(UserId, _passwords.NewPassword, _passwords.ConfirmPassword);
await UserRepo.ResetUserPassword(UserId, _passwords.NewPassword, _passwords.ConfirmPassword);
_toast.ShowInfo("Password er nulstillet.");
_passwords.NewPassword = "";
_passwords.ConfirmPassword = "";

View file

@ -62,7 +62,7 @@ builder.Services.AddScoped<ICrmReportHttpRepository, CrmReportHttpRepository>();
builder.Services.AddScoped<ICrmTaskItemHttpRepository, CrmTaskItemHttpRepository>();
builder.Services.AddScoped<ICrmWorkplaceHttpRepository, CrmWorkplaceHttpRepository>();
// administrative repositories
builder.Services.AddScoped<IOfficeUserHttpRepository, OfficeUserHttpRepository>();
builder.Services.AddScoped<IUserHttpRepository, UserHttpRepository>();
builder.Services.AddScoped<IOfficeReportHttpRepository, OfficeReportHttpRepository>();
builder.Services.AddScoped<IOfficeCustomerHttpRepository, OfficeCustomerHttpRepository>();
// warehouse repository
@ -86,7 +86,7 @@ builder.Services.AddScoped<RefreshTokenService>();
// vat registry service
builder.Services.AddScoped<VatInfoLookupService>();
// preference service
builder.Services.AddScoped<UserPrefService>();
builder.Services.AddScoped<UserProfileService>();
// activity draft service
builder.Services.AddScoped<OrderDraftService>();

View file

@ -29,11 +29,11 @@ public record UserPref
public bool DateConfirmed { get; set; }
}
public class UserPrefService
public class UserProfileService
{
private readonly ILocalStorageService _localStorageService;
public event Action<UserPref>? OnChange;
public UserPrefService(ILocalStorageService localStorageService)
public UserProfileService(ILocalStorageService localStorageService)
{
_localStorageService = localStorageService;
}

View file

@ -20,10 +20,16 @@
<div class="modal-dialog modal-dialog-scrollable modal-lg modal-xl">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title">@SalesItem.Name @SalesItem.Sku</h4>
<h4 class="modal-title">@SalesItem.Name @SalesItem.Sku (@SalesItem.BoxSize stk/colli)</h4>
<button type="button" class="btn-close" @onclick="Hide" data-bs-dismiss="modal" aria-label="Luk"></button>
</div>
<div class="modal-body">
@if (SalesItem.Discontinued)
{
<h3>Udgået produkt</h3>
}
else
{
@* draft line ----------------------------------------------------- *@
<div class="row">
<div class="col">
@ -77,6 +83,7 @@
}
</div>
@* end price list item -------------------------------------------- *@
}
@* product history ------------------------------------------------ *@
<table class="table table-striped">
@ -98,7 +105,10 @@
<td class="align-middle">@entry.Discount</td>
<td class="align-middle">@entry.Price</td>
<td class="align-middle">
@if (!SalesItem.Discontinued)
{
<button type="button" class="btn btn-primary btn-sm" data-bs-dismiss="modal" @onclick="() => SelectHistory(entry)"><i class="bi-plus"></i> VÆLG</button>
}
</td>
</tr>
}

View file

@ -44,9 +44,12 @@ public partial class InventoryReorderModal
return;
History = await CrmHistoryRepo.FetchHistory(CompanyId, SalesItem.Sku);
if (!History.Any())
await Task.Delay(1000);
SelectedItem.Item = SalesItem;
SelectedItem.Discount = 0;
SelectedItem.Quantity = 1;
if(SalesItem.Rates.Any())
SelectedItem.Price = decimal.Parse(SalesItem.Rates[0].Rate, CultureInfo.InvariantCulture);
}

View file

@ -25,35 +25,42 @@
</div>
<div class="modal-body">
<div class="sticky-top bg-dark rounded-2 p-3">
<div class="row">
<div class="col">
<div class="row mb-2">
<div class="col-sm-2">
<CatalogSearchComponent OnChanged="SetSearchCol"/>
</div>
<div class="col">
<div class="col-sm-6">
<CatalogSearchPhraseComponent OnChanged="SetSearchPhrase"/>
</div>
<div class="col">
<div class="col-sm-2">
<CatalogSortComponent OnChanged="SetSortCol"/>
</div>
<div class="col">
<div class="col-sm-2">
<PageSizeComponent OnChanged="SetPageSize"/>
</div>
</div>
<div class="row mb-3">
<div class="col-md-12">
<div class="row mb-2">
<div class="col-sm-12">
<PaginationComponent MetaData="_metaData" Spread="2" SelectedPage="SelectedPage" />
</div>
</div>
<div class="row text-white">
<div class="col-sm-3 fw-bold">Vare</div>
<div class="col-sm-2 fw-bold">Varenr</div>
<div class="col-sm-2 fw-bold">Fork</div>
<div class="col-sm-1 text-center fw-bold">Colli</div>
<div class="col-sm-4 text-center fw-bold">Stk / Pris</div>
</div>
</div>
@if (_items.Any())
{
<ul class="list-group">
<ul class="list-group list-group-flush">
@foreach (var item in _items)
{
<li class="list-group-item">
<div class="row align-middle">
<div class="col-sm-4 text-sm-start">
<div class="col-sm-3 text-sm-start">
@item.Name
</div>
<div class="col-sm-2 text-sm-start">
@ -62,6 +69,9 @@
<div class="col-sm-2 text-sm-start">
@item.ShortName
</div>
<div class="col-sm-1 text-center">
@item.BoxSize
</div>
<div class="col-sm-4">
<ul class="list-group">
@foreach (var rate in item.Rates)

View file

@ -30,7 +30,7 @@ public partial class PriceListModal : IDisposable
[Parameter] public EventCallback<SelectedSku> OnSelected { get; set; }
[Inject] public ICatalogHttpRepository ItemRepo { get; set; }
[Inject] public HttpInterceptorService Interceptor { get; set; }
[Inject] public UserPrefService UserPrefService { get; set; }
[Inject] public UserProfileService UserProfileService { get; set; }
private string _modalDisplay = "";
private bool _showBackdrop;
@ -41,7 +41,7 @@ public partial class PriceListModal : IDisposable
protected override async Task OnInitializedAsync()
{
_userPref = await UserPrefService.GetPreferences();
_userPref = await UserProfileService.GetPreferences();
_paging.CountryCode = CountryCode;
_paging.OrderBy = _userPref.ItemSort;
_paging.SearchColumn = _userPref.ItemSearch;

View file

@ -1,7 +1,7 @@
{
"appInfo": {
"name": "Wonky Client",
"version": "0.87.1",
"version": "0.91.1",
"rc": true,
"sandBox": false,
"image": "grumpy-coder.png"

Some files were not shown because too many files have changed in this diff Show more