cosmetic fixes found during today's lectures v.0.72.1

This commit is contained in:
Frede Hundewadt 2022-11-30 18:46:33 +01:00
parent 3a51363ea4
commit e6b7e658b3
21 changed files with 317 additions and 235 deletions

View file

@ -74,3 +74,7 @@
</tbody>
</table>
}
else
{
<div>Ingen data</div>
}

View file

@ -21,23 +21,10 @@ namespace Wonky.Client.Components;
public partial class AdvisorActivityTableComponent
{
[Parameter] public List<ReportItemView> Activities { get; set; }
[Inject] public NavigationManager _navigator { get; set; }
[Inject] public NavigationManager Navigator { get; set; }
// private static string GetProcessStatus(string processStatus)
// private void ShowOrder(string companyId, string orderId)
// {
// return processStatus.ToLower() switch
// {
// "express" => "the-fast",
// "none" => "the-good",
// "picked" => "the-bad",
// "packed" => "the-ugly",
// "shipped" => "the-dead",
// _ => ""
// };
// Navigator.NavigateTo($"office/customers/{companyId}/orders/{orderId}");
// }
private void ShowOrder(string companyId, string orderId)
{
_navigator.NavigateTo($"office/customers/{companyId}/orders/{orderId}");
}
}

View file

@ -18,57 +18,51 @@
@using Wonky.Client.Components;
@using Wonky.Client.Helpers;
@if (Companies.Any())
{
<table class="table table-striped">
<thead>
<tr>
<th scope="col">BS</th>
<th scope="col"></th>
<th scope="col">Navn</th>
<th scope="col">Konto</th>
<th scope="col">Tlf</th>
<th scope="col">Bynavn</th>
<th scope="col"></th>
<table class="table table-striped">
<thead>
<tr>
<th scope="col">BS</th>
<th scope="col"></th>
<th scope="col">Navn</th>
<th scope="col">Konto</th>
<th scope="col">Tlf</th>
<th scope="col">Bynavn</th>
<th scope="col"></th>
</tr>
</thead>
<tbody>
@foreach (var company in Companies)
{
<tr @onclick="() => { ViewCustomer(company.CompanyId); }" style="cursor: pointer">
<td class="state align-middle">
<DisplayStateComponent StateClass="@(company.HasFolded == 1 ? "the-dead" : Utils.GetVisitState(company.NextVisit))"/>
</td>
<td class="align-middle">
@if (!string.IsNullOrWhiteSpace(company.Note))
{
<i class="bi-exclamation-diamond-fill text-danger" style="font-size: 2rem;"></i>
}
</td>
<td class="align-middle">
@company.Name
</td>
<td class="align-middle">
@company.Account
</td>
<td class="align-middle">
@company.Phone
</td>
<td class="align-middle">
@company.City
</td>
<td class="align-middle">
<ActivityButton CompanyId="@company.CompanyId" ActionLink="/companies/$ID$/activities/new"
ButtonText="Besøg" ButtonType="primary" Enabled="@company.ValidVat"/>
</td>
</tr>
</thead>
<tbody>
@foreach (var company in Companies)
{
<tr @onclick="() => { ViewCustomer(company.CompanyId); }" style="cursor: pointer">
<td class="state align-middle">
<DisplayStateComponent StateClass="@(company.HasFolded == 1 ? "the-dead" : Utils.GetVisitState(company.NextVisit))" />
</td>
<td class="align-middle">
@if (!string.IsNullOrWhiteSpace(company.Note))
{
<i class="bi-exclamation-diamond-fill text-danger" style="font-size: 2rem;"></i>
}
</td>
<td class="align-middle">
@company.Name
</td>
<td class="align-middle">
@company.Account
</td>
<td class="align-middle">
@company.Phone
</td>
<td class="align-middle">
@company.City
</td>
<td class="align-middle">
<ActivityButton CompanyId="@company.CompanyId" ActionLink="/companies/$ID$/activities/new"
ButtonText="Besøg" ButtonType="primary" Enabled="@company.ValidVat" />
</td>
</tr>
}
}
</tbody>
</table>
}
else
{
<LoaderThreeDots />
}
<InformationModal BodyMessage="@_info" />
</tbody>
</table>
<InformationModal BodyMessage="@_info"/>

View file

@ -17,11 +17,32 @@
@if (Inventory.Any())
{
<table class="table table-striped">
@*
<div class="list-group">
@foreach (var product in Inventory)
{
<div class="list-group-item list-group-item-action" @onclick="() => CallShowReorderModal(product.Sku)" style="cursor: pointer;">
<div class="row">
<div class="col-sm-4">
@product.Description
</div>
<div class="col-sm-3">@product.Sku</div>
<div class="col-sm-1">
@product.Quantity
</div>
<div class="col-sm-4">
<button class="btn btn-info d-block">Vis mere <i class="bi-arrow-right"></i></button>
</div>
</div>
</div>
}
</div>
*@
<table class="table table-striped table-borderless">
<tbody>
@foreach (var product in Inventory)
{
<tr>
<tr style="cursor: pointer" @onclick="() => CallShowReorderModal(product.Sku)">
<td class="align-middle">
@product.Description
</td>
@ -32,7 +53,7 @@
@product.Quantity
</td>
<td class="align-middle">
<a class="btn btn-dark d-block" type="button" @onclick="() => CallShowReorderModal(product.Sku)">Historik</a>
<a class="btn btn-info d-block" type="button" @onclick="() => CallShowReorderModal(product.Sku)"><i class="bi-arrow-right-circle"></i> Se Historik</a>
</td>
</tr>
}

View file

@ -14,12 +14,28 @@
//
using System;
using System.Net.Mail;
using Wonky.Entity.DTO;
namespace Wonky.Client.Helpers;
public static class Utils
{
public static bool IsValidEmail(string email)
{
var trimmedEmail = email.Trim();
if (trimmedEmail.EndsWith(".")) {
return false; // suggested by @TK-421
}
try {
var addr = new MailAddress(email);
return addr.Address == trimmedEmail;
}
catch {
return false;
}
}
public static int GetHashFromNow()
{
return DateTime.Now.ToFileTimeUtc().GetHashCode();

View file

@ -86,6 +86,8 @@ public class CrmActivityHttpRepository : ICrmActivityHttpRepository
{
var response = await _client
.GetAsync($"{_api.CrmActivities}/date/{activityDate}");
if (!response.IsSuccessStatusCode)
return new ReportStatusView();
var content = await response.Content.ReadAsStringAsync();
return string.IsNullOrWhiteSpace(content)
? new ReportStatusView()
@ -113,7 +115,12 @@ public class CrmActivityHttpRepository : ICrmActivityHttpRepository
{
var response = await _client.GetAsync($"{_api.CrmActivities}/company/{customerId}");
var content = await response.Content.ReadAsStringAsync();
return JsonSerializer.Deserialize<List<ReportItemView>>(content, _options);
if(!response.IsSuccessStatusCode)
return new List<ReportItemView>();
return string.IsNullOrWhiteSpace(content)
? new List<ReportItemView>()
: JsonSerializer.Deserialize<List<ReportItemView>>(content, _options);
}
/// <summary>

View file

@ -64,7 +64,7 @@ else
<option value="noSale">Ingen salg</option>
@if (!string.IsNullOrEmpty(Activity.VatNumber) && !string.IsNullOrWhiteSpace(Activity.Address1) && Company.HasFolded == 0)
{
@if (DraftStateProvider.Draft.DraftType == "quote")
@if (DraftStateProvider.Draft.DraftType == "order")
{
<option selected value="order">Bestilling</option>
}
@ -233,30 +233,25 @@ else
<tbody>
<tr>
<td class="align-middle">
<input type="number" class="form-control" @bind-value="@Quantity"/>
<InputNumber TValue="int" class="form-control" @bind-value="@Quantity"/>
</td>
<td class="align-middle">
<div class="input-group">
<input type="number" class="form-control" @bind-value="@Price"/>
<InputNumber TValue="decimal" class="form-control" @bind-value="@Price"/>
<button class="btn btn-warning" type="button" @onclick="CallPriceHistoryModal">
<i class="bi-list-ul"></i>
</button>
@*
<button class="btn btn-info btn-sm" type="button" @onclick="CallHistoryModal">
<i class="oi oi-list"></i>
</button>
*@
</div>
</td>
<td class="align-middle">
<input type="number" class="form-control" @bind-value="@Discount"/>
<InputNumber TValue="decimal" class="form-control" @bind-value="@Discount"/>
</td>
<td class="align-middle align-content-center justify-content-center">
<input type="checkbox" class="form-check" @bind-value="@Sas"/>
<InputCheckbox class="form-check" @bind-value="@Sas"/>
</td>
<td class="align-middle">@SelectedItem.Sku</td>
<td class="align-middle">
<button type="button" class="btn btn-warning text-nowrap d-block" @onclick="@(() => AddItem(SelectedItem))">bestil @Quantity stk @SelectedItem.Name</button>
<button type="button" class="btn btn-primary text-nowrap d-block" @onclick="@(() => AddItem(SelectedItem))">BESTIL @SelectedItem.Name</button>
</td>
</tr>
</tbody>
@ -334,7 +329,7 @@ else
<a class="btn btn-warning" href="/companies/@Company.CompanyId">Tilbage</a>
</div>
<div class="col text-end">
<button type="button" class="btn btn-primary" @onclick="CreateActivity" disabled="@PoFormInvalid">Opret besøg</button>
<button type="button" class="btn btn-primary" @onclick="CreateActivity" disabled="@(PoFormInvalid || Working)">Opret besøg</button>
</div>
</div>
}

View file

@ -22,6 +22,7 @@ using Wonky.Client.HttpRepository;
using Wonky.Client.Models;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Forms;
using Wonky.Client.Helpers;
using Wonky.Client.HttpInterfaces;
using Wonky.Client.Services;
using Wonky.Client.Shared;
@ -55,16 +56,17 @@ public partial class CrmActivityNewPage : IDisposable
private EditContext ActivityContext { get; set; }
private bool PoFormInvalid { get; set; } = true;
private bool ShowItem { get; set; }
private string Quantity = "1";
private string Price = "0";
private string Discount = "0";
private bool Sas;
private bool InvalidActivityType = true;
private bool InvalidStatusType = true;
private bool InvalidActivity = true;
private bool InvalidCanvas = true;
private bool NoHistory = true;
private string Quantity { get; set; } = "1";
private string Price { get; set; } = "0";
private string Discount { get; set; } = "0";
private bool Sas { get; set; }
private bool InvalidActivityType { get; set; } = true;
private bool InvalidStatusType { get; set; } = true;
private bool InvalidActivity { get; set; } = true;
private bool InvalidCanvas { get; set; } = true;
private bool NoHistory { get; set; } = true;
private bool ReportClosed { get; set; }
private bool Working { get; set; } = true;
private UserInfoView ThisUserInfo { get; set; } = new();
private DateTime SelectedDate { get; set; }
private string OldPhone { get; set; } = "";
@ -75,6 +77,9 @@ public partial class CrmActivityNewPage : IDisposable
private ProductPriceHistoryModal PriceHistoryModal { get; set; }
private ConfirmWorkDateModal ConfirmWorkDate { get; set; } = new();
/// <summary>
/// Page initialization
/// </summary>
protected override async Task OnInitializedAsync()
{
ActivityContext = new EditContext(Activity);
@ -143,6 +148,7 @@ public partial class CrmActivityNewPage : IDisposable
Activity.ActivityStatusEnum = "order";
PoFormInvalid = false;
}
Working = false;
StateHasChanged();
}
@ -184,12 +190,10 @@ public partial class CrmActivityNewPage : IDisposable
// get selected item
if (string.IsNullOrWhiteSpace(sku.ItemId))
return;
SelectedItem = await Catalog.GetSalesItemId(sku.ItemId);
ShowItem = true;
Price = sku.Rate;
Quantity = sku.Quantity;
StateHasChanged();
}
@ -210,7 +214,6 @@ public partial class CrmActivityNewPage : IDisposable
{
if (price == 0)
return;
Price = price.ToString("N2", CultureInfo.InvariantCulture);
StateHasChanged();
}
@ -221,30 +224,33 @@ public partial class CrmActivityNewPage : IDisposable
private async Task CreateActivity()
{
// disable submit button to avoid multiple clicks
PoFormInvalid = true;
if (Working)
return;
// validate customer address1 - this is a required input
if (string.IsNullOrWhiteSpace(Activity.Address1))
{
Toast.ShowError("Kunde adresse er ufuldstændig.");
PoFormInvalid = false;
return;
}
if (Activity.ActivityStatusEnum == "order")
//
switch (Activity.ActivityStatusEnum)
{
if (DraftStateProvider.Draft.Items.Count == 0)
{
// don't accept order with no lines
case "order" when DraftStateProvider.Draft.Items.Count == 0:
Toast.ShowError("Ved bestilling skal der være en eller flere linjer i kladden.");
PoFormInvalid = false;
return;
}
if (Company.Account is "NY" or "" && string.IsNullOrWhiteSpace(Activity.Phone))
{
// phone number is required if first time customer
case "order" when Company.Account is "NY" or "" && string.IsNullOrWhiteSpace(Activity.Phone):
Toast.ShowError("Ved bestilling til ny kunde skal telefon nummer angives.");
PoFormInvalid = false;
return;
}
// verify email address is a valid address
case "quote" when !Utils.IsValidEmail(Activity.Email):
Toast.ShowError("Ved tilbud skal en gyldig email adresse angives.");
return;
}
// raise working flag
Working = true;
// reset selected item
SelectedItem = new SalesItemView();
// check if phone number need to be updated
@ -284,21 +290,24 @@ public partial class CrmActivityNewPage : IDisposable
.ToList();
Activity.Lines = lines;
}
// debug logging
Logger.LogDebug("CrmNewActivityPage => \n {}", JsonSerializer.Serialize(Activity));
// post to api
var result = await CrmActivityRepo.CreateActivity(Activity);
// debug logging
Logger.LogDebug("ApiResponseView => \n {}", JsonSerializer.Serialize(result));
// show result message
if (result.IsSuccess)
{
Toast.ShowSuccess($"{result.Message}",
DraftStateProvider.Draft.Items.Count == 0 ? "Besøg er oprettet" : "Bestilling er oprettet");
DraftStateProvider.Draft.Items.Count == 0 ? "Besøg er oprettet" : "Bestilling/Tilbud er oprettet");
await DeleteDraft();
Navigator.NavigateTo($"/companies");
return;
}
PoFormInvalid = false;
// lower working flag
Working = false;
// show error message
Toast.ShowError(result.Message, "ORDRE FEJL");
}
@ -367,16 +376,11 @@ public partial class CrmActivityNewPage : IDisposable
|| PoFormInvalid
|| DraftStateProvider.Draft.Items.Count == 0
|| (Activity.ActivityStatusEnum == "offer" && string.IsNullOrWhiteSpace(Activity.Email));
if (Activity.YourRef.Length > 35 || Activity.ReferenceNumber.Length > 20)
if (Activity.YourRef.Length > 35 || Activity.ReferenceNumber.Length > 20 || InvalidActivity)
{
PoFormInvalid = true;
return;
}
if (InvalidActivity)
{
PoFormInvalid = true;
return;
}
PoFormInvalid = !ActivityContext.Validate();
StateHasChanged();
}

View file

@ -20,68 +20,80 @@
@page "/companies/{CompanyId}/activities"
@attribute [Authorize(Roles = "Advisor")]
<h2>@Company.Name</h2>
<div class="list-group">
<div class="list-group-item">
<div class="row">
<div class="col">
<h4>Dato</h4>
</div>
<div class="col">
<h4>Demo</h4>
</div>
<div class="col">
<h4>Salg</h4>
</div>
<div class="col">
<h4>Note /Kontor</h4>
</div>
<div class="col">
<h4>Note /Selv</h4>
</div>
@if (!string.IsNullOrWhiteSpace(Company.Name))
{
<div class="row pt-2 pb-1 rounded-2 bg-dark text-white">
<div class="col-sm-6">
<h4 class="pt-1">@Company.Name</h4>
</div>
<div class="col-sm-3 align-content-end">
<a class="btn btn-primary d-block" href="/companies/@Company.CompanyId"><i class="bi-arrow-right"></i> Kundekort</a>
</div>
<div class="col-sm-3 align-content-end">
<a class="btn btn-primary d-block" href="/companies/@Company.CompanyId/activities/new"><i class="bi-arrow-right"></i> Besøg</a>
</div>
</div>
@if (Activities.Any())
{
@foreach (var activity in Activities)
<div class="list-group">
<div class="list-group-item">
<div class="row">
<div class="col">
<h4>Dato</h4>
</div>
<div class="col">
<h4>Demo</h4>
</div>
<div class="col">
<h4>Salg</h4>
</div>
<div class="col">
<h4>Note /Kontor</h4>
</div>
<div class="col">
<h4>Note /Selv</h4>
</div>
</div>
</div>
@if (Activities.Any())
{
@foreach (var activity in Activities)
{
<div class="list-group-item">
<div class="row">
<div class="col">
@activity.OrderDate
</div>
<div class="col">
@activity.Demo
</div>
<div class="col">
@activity.Sales
</div>
<div class="col">
@activity.OfficeNote
</div>
<div class="col">
ikke fuldt implementeret
</div>
</div>
</div>
}
}
else
{
<div class="list-group-item">
<div class="row">
<div class="col">
@activity.OrderDate
</div>
<div class="col">
@activity.Demo
</div>
<div class="col">
@activity.Sales
</div>
<div class="col">
@activity.OfficeNote
</div>
<div class="col">
Ingen data
</div>
</div>
</div>
}
}
else
{
<div class="list-group-item">
<div class="row">
<div class="col">
Ingen data
</div>
</div>
</div>
}
</div>
}
@if (Working)
{
<LoaderThreeDots />
<LoaderThreeDots/>
}

View file

@ -28,7 +28,6 @@ namespace Wonky.Client.Pages;
public partial class CrmCompanyActivityListPage : IDisposable
{
[Parameter] public string CompanyId { get; set; } = "";
[Inject] public HttpInterceptorService _interceptor { get; set; }
[Inject] public ICrmActivityHttpRepository CrmActivityRepo { get; set; }
[Inject] public ICrmCompanyHttpRepository CompanyRepo { get; set; }
@ -42,9 +41,16 @@ public partial class CrmCompanyActivityListPage : IDisposable
_interceptor.RegisterBeforeSendEvent();
Company = await CompanyRepo.GetCompanyById(CompanyId);
await GetActivities();
Working = false;
}
private async Task GetActivities()
{
Working = true;
Activities = await CrmActivityRepo.GetCustomerActivities(CompanyId);
Activities = Activities.OrderByDescending(x => x.OrderDate).ToList();
if(Activities.Any())
Activities = Activities.OrderByDescending(x => x.OrderDate).ToList();
Working = false;
}

View file

@ -19,13 +19,15 @@
@using Microsoft.AspNetCore.Authorization
@page "/companies/{CompanyId}/h/i"
@attribute [Authorize(Roles = "Advisor")]
<div class="row pt-2 pb-2 rounded-2 bg-dark text-white">
<div class="col-6">
<h3>@Company.Name</h3>
<div class="row pt-2 pb-1 rounded-2 bg-dark text-white">
<div class="col-sm-6">
<h4 class="pt-1">@Company.Name</h4>
</div>
<div class="col-6 align-content-end">
<a class="btn btn-primary" href="/companies/@Company.CompanyId">Kundekort</a>
<a class="btn btn-primary" href="/companies/@Company.CompanyId/activities/new">Besøg</a>
<div class="col-sm-3 align-content-end">
<a class="btn btn-primary d-block" href="/companies/@Company.CompanyId"><i class="bi-arrow-right"></i> Kundekort</a>
</div>
<div class="col-sm-3 align-content-end">
<a class="btn btn-primary d-block" href="/companies/@Company.CompanyId/activities/new"><i class="bi-arrow-right"></i> Besøg</a>
</div>
</div>
@if (Loading)

View file

@ -2,13 +2,15 @@
@using Wonky.Client.Components
@if (!string.IsNullOrWhiteSpace(Company.Name))
{
<div class="row pt-2 pb-2 rounded-2 bg-dark text-white">
<div class="col-6">
<h3>@Company.Name</h3>
<div class="row pt-2 pb-1 rounded-2 bg-dark text-white">
<div class="col-sm-6">
<h4 class="pt-1">@Company.Name</h4>
</div>
<div class="col-6 align-content-end">
<a class="btn btn-primary" href="/companies/@Company.CompanyId">Kundekort</a>
<a class="btn btn-primary" href="/companies/@Company.CompanyId/activities/new">Besøg</a>
<div class="col-sm-3 align-content-end">
<a class="btn btn-primary d-block" href="/companies/@Company.CompanyId"><i class="bi-arrow-right"></i> Kundekort</a>
</div>
<div class="col-sm-3 align-content-end">
<a class="btn btn-primary d-block" href="/companies/@Company.CompanyId/activities/new"><i class="bi-arrow-right"></i> Besøg</a>
</div>
</div>
<InvoiceTableComponent CompanyId="@CompanyId" InvoiceList="@History.Invoices"/>

View file

@ -55,3 +55,7 @@
</div>
<AdvisorCompanyTableComponent Companies="_companyList" OnDelete="DeleteCompany" />
@if (Working)
{
<LoaderThreeDots />
}

View file

@ -42,6 +42,7 @@ namespace Wonky.Client.Pages
private UserInfoView _userInfo { get; set; } = new();
private string _savedSearch { get; set; } = "";
private bool _includeFolded { get; set; }
private bool Working { get; set; } = true;
protected override async Task OnInitializedAsync()
{
@ -132,9 +133,11 @@ namespace Wonky.Client.Pages
private async Task GetCompanies()
{
Working = true;
var pagingResponse = await _companyRepo.GetCompanies(_paging);
_companyList = pagingResponse.Items;
_metaData = pagingResponse.MetaData;
Working = false;
}
public void Dispose() => _interceptor.DisposeEvent();

View file

@ -123,7 +123,7 @@
</div>
@* save vat number *@
<div class="col-sm-2 text-end">
<button type="button" class="btn btn-primary" @onclick="UpdateVatNumber">MOMS Nr<i class="bi-save"></i></button>
<button type="button" class="btn btn-primary" @onclick="UpdateVatNumber">MOMS Nr. <i class="bi-save"></i></button>
</div>
</div>
@ -131,16 +131,16 @@
@* activity buttons *@
<div class="row mt-3 mb-2">
<div class="col">
<a class="btn btn-light border-dark d-block" href="/companies/@Company.CompanyId/invoices">Poster</a>
<a class="btn btn-dark opacity-50 d-block" href="/companies/@Company.CompanyId/invoices">Poster</a>
</div>
<div class="col">
<a class="btn btn-light border-dark d-block" href="/companies/@Company.CompanyId/quotes">Tilbud</a>
<a class="btn btn-dark opacity-50 d-block" href="/companies/@Company.CompanyId/quotes">Tilbud</a>
</div>
<div class="col">
<a class="btn btn-light border-dark d-block" href="/companies/@Company.CompanyId/activities">Besøg</a>
<a class="btn btn-dark opacity-50 d-block" href="/companies/@Company.CompanyId/activities">Besøg</a>
</div>
<div class="col">
<a class="btn btn-light border-dark d-block" href="/companies/@Company.CompanyId/h/i">Produkter</a>
<a class="btn btn-dark opacity-50 d-block" href="/companies/@Company.CompanyId/h/i">Produkter</a>
</div>
<div class="col">
<ActivityButton ActionLink="@ActionLink"
@ -168,7 +168,7 @@
</div>
@* Save CRM data button *@
<div class="col-sm-3 text-end">
<button type="button" class="btn btn-primary" @onclick="UpdateCrmData">CRM <i class="bi-save"></i></button>
<button type="button" class="btn btn-primary" @onclick="UpdateCrmData">CRM data <i class="bi-save"></i></button>
</div>
</div>
@* crm context - contacts *@
@ -232,10 +232,6 @@
</div>
</EditForm>
}
else
{
<LoaderThreeDots/>
}
<VatLookupDkModal VatAddress="CompanyVatAddress" EntityName="@Company.Name" VatNumber="@Company.VatNumber"
@ref="VatLookupPopup" OnSelectedCompany="SelectedCompanyCallback" />

View file

@ -28,7 +28,7 @@
@* report header *@
<div class="row sticky-top bg-dark text-white rounded-2 mb-2 py-2 align-items-center">
<div class="col-sm-8">
<WorkDateComponent OnChangedCallback="SetWorkDate"/>
<WorkDateComponent OnChangedCallback="SetWorkDateCallback"/>
</div>
<div class="col-sm-4 text-end">
<AdvisorActivityKmStartComponent/>
@ -45,14 +45,14 @@
<th scope="col">Dag / Periode</th>
<th scope="col">Begyndt</th>
<th scope="col">Afsluttet</th>
@* <th></th> *@
<th></th>
<th></th>
</tr>
</thead>
<tbody>
<tr>
<td>
<select id="dayType" class="col-md-3 form-select text-bg-primary bg-primary"
<InputSelect id="dayType" class="form-select text-bg-primary bg-primary"
@bind-Value="Report.DayTypeEnum" @bind-Value:event="onchange">
<option value="">&rarr; TAG MIG &larr;</option>
<option value="sales">Salgsdag</option>
@ -61,7 +61,7 @@
<option value="supervisor">Medkørende Supervisor</option>
<option value="sickLeave">Sygdom</option>
<option value="leave">Ferie</option>
</select>
</InputSelect>
<ValidationMessage For="@(() => Report.DayTypeEnum)"/>
</td>
@if (Report.DayTypeEnum.ToLower().Contains("leave"))
@ -72,9 +72,11 @@
<td>
<InputDate class="form-control" @bind-Value="EndLeave"/>
</td>
Report.Figures.KmMorning = 0;
}
else
{
Report.Figures.KmMorning = Preferences.KmMorning;
<td>
<input type="time" id="checkIn" class="form-control"
@bind-Value="_checkIn" @bind-Value:event="oninput" @onchange="OnTimeChanged"/>
@ -84,21 +86,17 @@
@bind-Value="_checkOut" @bind-Value:event="oninput" @onchange="OnTimeChanged"/>
</td>
}
@*
<th>
<td class="text-end">
<button type="button" class="btn btn-warning"
@onclick="GetKeyFigures" disabled="@(!NoFigures)">
Nøgletal
</button>
</th>
*@
</td>
<td class="text-end">
@* <div style="display:@(_working ? "none" : "block");"> *@
<button type="button" class="btn btn-primary"
@onclick="SubmitReport" disabled="@(NoFigures || Working)">
Gem Rapport
</button>
@* </div> *@
</td>
</tr>
</tbody>
@ -114,7 +112,7 @@
<thead>
<tr>
<th scope="col" style="width:60%">Tekst</th>
<th scope="col">Medkørende Supervisor</th>
<th scope="col">Supervisor</th>
</tr>
</thead>
<tbody>
@ -126,7 +124,6 @@
<td>
<InputText id="supervisedBy" class="form-control" @bind-Value="Report.SupervisedBy"/>
<ValidationMessage For="@(() => Report.SupervisedBy)"/>
</td>
</tr>
</tbody>
@ -304,5 +301,5 @@
</tbody>
</table>
</div>
</EditForm>>
<ConfirmationModal BodyMessage="@Prompt" OnOkClicked="ReportSaveConfirmed" @ref="ConfirmReportModal"/>
</EditForm>
<ConfirmationModal BodyMessage="@Prompt" OnOkClicked="ConfirmSaveCallback" @ref="ConfirmReportModal"/>

View file

@ -46,9 +46,9 @@ public partial class CrmReportNewPage : IDisposable
private List<ReportItemView> Activities { get; set; } = new();
private ReportFiguresDto InitialValues { get; set; }
private Preferences Preferences { get; set; } = new();
private bool FormInvalid = true;
private bool NoFigures = true;
private bool Working;
private bool FormInvalid { get; set; } = true;
private bool NoFigures { get; set; } = true;
private bool Working { get; set; } = true;
private DateTime _workDate { get; set; } = DateTime.Now;
private TimeOnly _checkIn { get; set; } = new(12, 0);
private TimeOnly _checkOut { get; set; } = new(12, 0);
@ -57,6 +57,9 @@ public partial class CrmReportNewPage : IDisposable
private ConfirmationModal ConfirmReportModal { get; set; }
private string Prompt { get; set; } = "";
/// <summary>
/// OnInitialized
/// </summary>
protected override async Task OnInitializedAsync()
{
Interceptor.RegisterEvent();
@ -81,8 +84,14 @@ public partial class CrmReportNewPage : IDisposable
Report.Figures.Distance = 0;
Report.Figures.DistancePrivateMonth = 0;
await GetKeyFigures();
Working = false;
}
/// <summary>
/// Field data change event
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void HandleFieldChanged(object sender, FieldChangedEventArgs e)
{
Console.WriteLine($"e Model => {e.FieldIdentifier.Model}");
@ -91,6 +100,11 @@ public partial class CrmReportNewPage : IDisposable
StateHasChanged();
}
/// <summary>
/// Validation change event
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void ValidationChanged(object sender, ValidationStateChangedEventArgs e)
{
FormInvalid = false;
@ -100,7 +114,10 @@ public partial class CrmReportNewPage : IDisposable
ReportContext.OnValidationStateChanged += ValidationChanged;
}
private async Task ReportSaveConfirmed()
/// <summary>
/// Save report confirmed callback
/// </summary>
private async Task ConfirmSaveCallback()
{
// attempt to eliminate doubled click on submit button
if (Working)
@ -114,27 +131,30 @@ public partial class CrmReportNewPage : IDisposable
await PreferenceService.SetDateConfirmed(false);
Navigator.NavigateTo($"/sales-reports/view/{_workDate:yyyy-MM-dd}");
}
/// <summary>
/// Submit report
/// </summary>
private void SubmitReport()
{
// attempt to eliminate doubled click on submit button
if (Working)
return;
// check daytype
if (string.IsNullOrWhiteSpace(Report.DayTypeEnum))
{
Toaster.ShowError("Dagtype skal vælges", "Dag type skal angives");
Toaster.ShowError("Dagtype skal vælges", "Dag type mangler");
return;
}
if (Report.Figures.KmMorning > Report.Figures.KmEvening)
// distance day check - only if not leave
if (Report.Figures.KmMorning > Report.Figures.KmEvening && !Report.DayTypeEnum.ToLower().Contains("leave"))
{
Toaster.ShowError("Km udregning er negativ - kontroller venligst km tal", "Kontroller km tal");
return;
}
// local working variables
DateTime checkIn;
DateTime checkOut;
// create a date time object using workDate and workHour input
if (Report.DayTypeEnum.ToLower().Contains("leave"))
{
checkIn = new DateTime(BeginLeave.Year, BeginLeave.Month, BeginLeave.Day, 0, 0, 0);
@ -145,23 +165,27 @@ public partial class CrmReportNewPage : IDisposable
checkIn = new DateTime(_workDate.Year, _workDate.Month, _workDate.Day, _checkIn.Hour, _checkIn.Minute, 0);
checkOut = new DateTime(_workDate.Year, _workDate.Month, _workDate.Day, _checkOut.Hour, _checkOut.Minute, 0);
}
// assign a workday number if the day is marked as salesDay
Report.SalesDayNumber = Report.DayTypeEnum == "sales" ? Report.Figures.SalesDayCount + 1 : 0;
// format report date time input
Report.FromDateTime = checkIn.ToString("yyyy-MM-dd'T'HH:mm:ss", CultureInfo.InvariantCulture);
Report.ToDateTime = checkOut.ToString("yyyy-MM-dd'T'HH:mm:ss", CultureInfo.InvariantCulture);
// assign final distance numbers
Report.Figures.Distance = Report.Figures.KmEvening - Report.Figures.KmMorning;
Report.Figures.DistanceMonth += Report.Figures.Distance;
Report.Figures.DistancePrivateMonth += Report.Figures.DistancePrivate;
Logger.LogDebug("_workDate => {workDate}", $"{_workDate:yyyy-MM-dd}");
Logger.LogDebug("_report => {report}", JsonSerializer.Serialize(Report));
// create a prompt
Prompt = Report.Figures.Distance > 1000 ? $"'{Report.Figures.Distance}'KM tal er meget højt. Er du sikker på at det er rigtigt? Gem rapport for {_workDate.ToLongDateString()}?" : $"Gem Rapport for {_workDate.ToLongDateString()}?";
// pop confirmation
ConfirmReportModal.Show();
}
/// <summary>
/// On Time changed - update the Report Date fields
/// </summary>
private void OnTimeChanged()
{
var f = new DateTime(_workDate.Year, _workDate.Month, _workDate.Day, _checkIn.Hour, _checkIn.Minute,0);
@ -171,7 +195,11 @@ public partial class CrmReportNewPage : IDisposable
Report.ToDateTime = $"{t:yyyy-MM-dd'T'HH:mm}";
}
private void SetWorkDate(string workDate)
/// <summary>
/// Set workDate callback
/// </summary>
/// <param name="workDate"></param>
private void SetWorkDateCallback(string workDate)
{
_workDate = DateTime.Parse(workDate);
NoFigures = true;
@ -188,6 +216,9 @@ public partial class CrmReportNewPage : IDisposable
Report.ToDateTime = $"{_workDate:yyyy-MM-dd'T'12:00}";
}
/// <summary>
/// Get key figures from backend
/// </summary>
private async Task GetKeyFigures()
{
Working = true;
@ -197,7 +228,8 @@ public partial class CrmReportNewPage : IDisposable
Report.Figures = data.ReportData;
InitialValues = data.ReportData;
Activities = data.ReportItems;
Report.Figures.KmMorning = Preferences.KmMorning;
if(!Report.DayTypeEnum.ToLower().Contains("leave"))
Report.Figures.KmMorning = Preferences.KmMorning;
NoFigures = false;
Working = false;
}

View file

@ -16,7 +16,7 @@
*@
<div class="modal" tabindex="-1" role="dialog" style="display:@_modalDisplay">
<div class="modal-dialog">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<h3 class="modal-title">Bekræft Venligst</h3>

View file

@ -16,7 +16,7 @@
*@
<div class="modal" tabindex="-1" role="dialog" style="display:@_modalDisplay">
<div class="modal-dialog">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Bekræft Venligst</h5>

View file

@ -17,7 +17,7 @@
@* <div class="modal" tabindex="-1" role="dialog" style="display:@_modalDisplay"> *@
<div class="modal fade" tabindex="-1" style="display:@_modalDisplay">
<div class="modal-dialog">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header bg-info">
<h5 class="modal-title">Info</h5>

View file

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