This commit is contained in:
Frede Hundewadt 2022-05-08 12:37:17 +02:00
parent 49def84d0a
commit db0bec0c36
11 changed files with 118 additions and 101 deletions

View file

@ -14,5 +14,5 @@
// along with this program. If not, see [https://www.gnu.org/licenses/agpl-3.0.en.html]
//
*@<div>
<img class="spinner pe-3" src="loader.gif" alt="Afventer netværk svar ..."/>Afventer netværk svar ...
<img class="spinner pe-3" src="loader.gif" alt="Afventer svar fra netværk ..."/>Afventer netværk svar ...
</div>

View file

@ -17,7 +17,7 @@
<span class="version">@Name</span> <span class="version">@Version</span>@if(IsBeta){<span class="version">-beta</span>}
@code
{
private const string Version = "0.2.27";
private const string Version = "0.2.31";
private const string Name = "wwo";
private const bool IsBeta = true;
}

View file

@ -8,7 +8,8 @@ public class DraftItem
public NgSalesItemView Item { get; set; }
public decimal Price { get; set; }
public decimal Discount { get; set; }
public decimal LineTotal => (Price - Price * Discount / 100) * Quantity;
public bool Sas { get; set; }
public decimal LineTotal => (Price - Price * Discount / 100) * (decimal) Quantity;
}
public class Draft

View file

@ -54,7 +54,7 @@ namespace Wonky.Client.Pages
_createCompany = new EditContext(_dtoNgCompany);
_createCompany.OnFieldChanged += HandleFieldChanged;
var ux = await StorageService.GetItemAsync<UserInfoView>("_ux");
var ux = await StorageService.GetItemAsync<UserInfoView>("_xu");
_dtoNgCompany.SalesRepId = ux.Id;
_dtoNgCompany.CountryCode = ux.CountryCode;
Interceptor.RegisterEvent();

View file

@ -37,7 +37,7 @@
<div class="card-body">
@foreach (var info in VInfos)
{
<div class="row mb-2">
<div class="row mb-1">
<div class="col">
@info.VatNumber
</div>
@ -57,89 +57,88 @@
<div class="card-body">
<EditForm EditContext="_updateCompany" OnValidSubmit="Update">
<DataAnnotationsValidator/>
<div class="form-group row mb-2">
<div class="form-group row mb-1">
<label for="vatNumber" class="col-md-2 col-form-label">CVR/ORG</label>
<div class="col-md-10">
<InputText id="vatNumber" class="form-control" @bind-Value="DtoNgCompany.VatNumber"/>
<ValidationMessage For="@(() => DtoNgCompany.VatNumber)"></ValidationMessage>
</div>
</div>
<div class="form-group row mb-2">
<div class="form-group row mb-1">
<label for="name" class="col-md-2 col-form-label">Firmanavn</label>
<div class="col-md-10">
<InputText id="name" class="form-control" @bind-Value="DtoNgCompany.Name"/>
<ValidationMessage For="@(() => DtoNgCompany.Name)"></ValidationMessage>
</div>
</div>
<div class="form-group row mb-2">
<div class="form-group row mb-1">
<label for="address1" class="col-md-2 col-form-label">Conavn</label>
<div class="col-md-10">
<InputText id="address1" class="form-control" @bind-Value="DtoNgCompany.Address1"/>
<ValidationMessage For="@(() => DtoNgCompany.Address1)"></ValidationMessage>
</div>
</div>
<div class="form-group row mb-2">
<div class="form-group row mb-1">
<label for="address2" class="col-md-2 col-form-label">Adresse</label>
<div class="col-md-10">
<InputText id="address2" class="form-control" @bind-Value="DtoNgCompany.Address2"/>
</div>
</div>
<div class="form-group row mb-2">
<div class="form-group row mb-1">
<label for="zipCode" class="col-md-2 col-form-label">Postnr</label>
<div class="col-md-10">
<InputText id="zipCode" class="form-control" @bind-Value="DtoNgCompany.ZipCode"/>
<ValidationMessage For="@(() => DtoNgCompany.ZipCode)"></ValidationMessage>
</div>
</div>
<div class="form-group row mb-2">
<div class="form-group row mb-1">
<label for="city" class="col-md-2 col-form-label">Bynavn</label>
<div class="col-md-10">
<InputText id="city" class="form-control" @bind-Value="DtoNgCompany.City"/>
<ValidationMessage For="@(() => DtoNgCompany.City)"></ValidationMessage>
</div>
</div>
<div class="form-group row mb-2">
<div class="form-group row mb-1">
<label for="phone" class="col-md-2 col-form-label">Telefon</label>
<div class="col-md-10">
<InputText id="phone" class="form-control" @bind-Value="DtoNgCompany.Phone"/>
</div>
</div>
<div class="form-group row mb-2">
<div class="form-group row mb-1">
<label for="mobile" class="col-md-2 col-form-label">Mobil</label>
<div class="col-md-10">
<InputText id="mobile" class="form-control" @bind-Value="DtoNgCompany.Mobile"/>
</div>
</div>
<div class="form-group row mb-2">
<div class="form-group row mb-1">
<label for="email" class="col-md-2 col-form-label">Email</label>
<div class="col-md-10">
<InputText id="email" class="form-control" @bind-Value="DtoNgCompany.Email"/>
</div>
</div>
<div class="form-group row mb-2">
<div class="form-group row mb-1">
<label for="attention" class="col-md-2 col-form-label">Attention</label>
<div class="col-md-10">
<InputText id="attention" class="form-control" @bind-Value="DtoNgCompany.Attention"/>
</div>
</div>
<div class="form-group row mb-2">
<div class="form-group row mb-1">
<label for="lastVisit" class="col-form-label col-md-2">Sidste besøg</label>
<div class="col-md-3">
<div class="col-md-4">
<InputDate id="lastVisit" class="form-control" @bind-Value="@LastVisit"/>
</div>
</div>
<div class="form-group row mb-2">
<label for="nextVisit" class="col-form-label col-md-2">Næste besøg</label>
<div class="col-md-3">
<div class="col-md-4">
<InputDate id="nextVisit" class="form-control" @bind-Value="@(NextVisit)"/>
</div>
</div>
<div class="form-group row mb-2">
<div class="form-group row mb-1">
<label for="interval" class="col-form-label col-md-2">Interval (uger)</label>
<div class="col-md-3">
<div class="col-md-4">
<InputNumber id="interval" class="form-control" @bind-Value="DtoNgCompany.Interval"/>
</div>
</div>
<div class="row mb-2">
<div class="row mb-1">
<div class="col-md-12 text-right">
<button type="submit" class="btn btn-success">GEM</button>
</div>

View file

@ -38,47 +38,50 @@
aria-labelledby="activityHeader" data-bs-parent="#crmActivity">
<div class="accordion-body">
<div class="row mb-1">
<div class="col-sm-6 col-md-6">
<select id="activityType" class="form-select" @bind-Value="@_poDraft.ActivityTypeEnum" @bind-Value:event="oninput" @onchange="CheckActivity">
<option value="-1" selected>VÆLG</option>
<option value="onSite">Besøg</option>
<option value="phone">Telefon</option>
<option value="canvas">Kanvas</option>
</select>
</div>
<div class="col-sm-6 col-md-6">
<select id="statusType" class="form-select" @bind-Value="@_poDraft.ActivityStatusEnum" @bind-Value:event="oninput" @onchange="CheckStatus">
<option value="-1" selected>VÆLG</option>
<option value="order">Ordre</option>
<option value="quote">Tilbud</option>
</select>
</div>
</div>
<div class="row mb-1">
<div class="col-sm-6 col-md-6">
<InputDate id="activityDate" class="form-control" @bind-Value="@(_poDraft.ActivityDate)" />
</div>
<div class="col-sm-6 col-md-6">
<InputCheckbox id="checkDate" class="form-check-input" @bind-Value="@_poDraft.CheckDate" @onclick="CheckDate" />
<label for="checkDate" class="form-check-label">Godkendt</label>
</div>
</div>
<div class="row mb-1">
<label for="account" class="col-sm-2 col-md-2 col-form-label">Konto</label>
<div class="col-sm-4 col-md-4">
<label for="account" class="col-md-2 col-form-label">Konto</label>
<div class="col-md-4">
<InputText id="account" class="form-control" @bind-Value="_poDraft.Account" readonly/>
<ValidationMessage For="@(() => _poDraft.Account)"></ValidationMessage>
</div>
<label for="salesRep" class="col-sm-2 col-md-2 col-form-label">Sælger</label>
<div class="col-sm-4 col-md-4">
<label for="salesRep" class="col-md-2 col-form-label">Sælger</label>
<div class="col-md-4">
<InputText id="salesRep" class="form-control" @bind-Value="_poDraft.SalesRep" readonly/>
<ValidationMessage For="@(() => _poDraft.SalesRep)"></ValidationMessage>
</div>
</div>
<div class="row mb-1">
<label for="demo" class="col-md-2 col-form-label">Demo</label>
<div class="col-md-10">
<label for="activityType" class="col-md-2 col-form-label">Kontakt</label>
<div class="col-md-4">
<select id="activityType" class="form-select" @bind-Value="@_poDraft.ActivityTypeEnum" @bind-Value:event="oninput" @onchange="CheckActivity">
<option value="" selected>VÆLG</option>
<option value="onSite">Besøg</option>
<option value="phone">Telefon</option>
</select>
</div>
<label for="statusType" class="col-md-2 col-form-label">Status</label>
<div class="col-md-4">
<select id="statusType" class="form-select" @bind-Value="@_poDraft.ActivityStatusEnum" @bind-Value:event="oninput" @onchange="CheckStatus">
<option value="" selected>VÆLG</option>
<option value="order">Ordre</option>
<option value="quote">Tilbud</option>
<option value="canvas">Kanvas</option>
</select>
</div>
</div>
<div class="row mb-1">
<label for="activityDate" class="col-md-2 col-form-label">Dato</label>
<div class="col-md-4">
<InputDate id="activityDate" class="form-control" @bind-Value="@(_poDraft.ActivityDate)"/>
</div>
<label for="checkDate" class="col-md-2 form-check-label">Bekræft dato?</label>
<div class="col-md-4">
<InputCheckbox id="checkDate" class="form-check-input" @bind-Value="@_poDraft.CheckDate" @onclick="CheckDate"/>
</div>
</div>
<div class="row mb-1">
<label for="demo" class="col-md-4 col-form-label">Demo</label>
<div class="col-md-8">
<InputText id="demo" class="form-control" @bind-Value="_poDraft.Demo"/>
</div>
</div>
@ -197,6 +200,9 @@
<div class="col">
Rabat
</div>
<div class="col">
SAS
</div>
<div class="col">
</div>
@ -209,13 +215,16 @@
@_selectedItem.Sku
</div>
<div class="col">
<input class="form-control" type="number" @bind-value="@Quantity"/>
<input type="number" class="form-control" @bind-value="@Quantity"/>
</div>
<div class="col">
<input class="form-control" type="number" @bind-value="@Price"/>
<input type="number" class="form-control" @bind-value="@Price"/>
</div>
<div class="col">
<input class="form-control" type="number" @bind-value="@Discount"/>
<input type="number" class="form-control" @bind-value="@Discount"/>
</div>
<div class="col">
<input type="checkbox" class="form-check" @bind-value="@Sas"/>
</div>
<div class="col">
<button class="btn btn-info" @onclick="@(() => AddItem(_selectedItem))">Læg til</button>
@ -252,6 +261,7 @@
<td class="text-end">@cItem.Quantity</td>
<td class="text-end">@cItem.Price</td>
<td class="text-end">@cItem.LineTotal</td>
<td><input type="checkbox" checked="@cItem.Sas" disabled/></td>
<td>
<button class="btn btn-warning" @onclick="@(() => RemoveItem(@cItem))">Slet</button>
</td>
@ -329,12 +339,13 @@
</div>
</div>
<div class="row mt-2 mb-2" style="display:@(HideButtons ? "none" : "block")">
<div class="row mt-2 mb-2" >
<div class="col">
<a class="btn btn-primary" href="/company/@NgCompany.CompanyId">Tilbage</a>
</div>
<div class="col">
<button type="submit" class="btn btn-success" disabled="@InvalidActivity">Gem</button>
@* <button type="submit" class="btn btn-success" disabled="@InvalidActivity">Gem</button> *@
<button type="submit" class="btn btn-success" disabled="@InvalidActivity">OK</button>
</div>
</div>
</EditForm>

View file

@ -53,6 +53,7 @@ public partial class CrmActivityCreate : IDisposable
private string Quantity = "1";
private string Price = "0";
private string Discount = "0";
private bool Sas;
private bool InvalidActivityType { get; set; } = true;
private bool InvalidStatusType { get; set; } = true;
private bool InvalidActivity { get; set; } = true;
@ -72,7 +73,7 @@ public partial class CrmActivityCreate : IDisposable
_prefs = await UserPrefs.GetPreferences();
_paging.SearchColumn = _prefs.ItemSearch;
await GetSalesItems();
Ux = await StorageService.GetItemAsync<UserInfoView>("_ux");
Ux = await StorageService.GetItemAsync<UserInfoView>("_xu");
NgCompany = await CompanyRepo.GetCompanyById(CompanyId);
DraftContext = new EditContext(_poDraft);
@ -112,8 +113,8 @@ public partial class CrmActivityCreate : IDisposable
await UserPrefs.SetWorkDate(_poDraft.ActivityDate);
var activityType = _poDraft.ActivityTypeEnum switch
{
"caPhone" => "Tlf. ",
"caOnSite" => "Bsg. ",
"phone" => "Tlf. ",
"onSite" => "Bsg. ",
_ => ""
};
_poDraft.OurRef = $"{activityType}{Ux.FullName.Split(" ")[0]}";
@ -128,7 +129,8 @@ public partial class CrmActivityCreate : IDisposable
Sku = item.Item.Sku,
Text = item.Item.Name,
LineAmount = item.LineTotal,
LineNumber = ++ln
LineNumber = ++ln,
Sas = item.Sas
}))
{
_poDraft.Lines.Add(line);
@ -140,18 +142,18 @@ public partial class CrmActivityCreate : IDisposable
private void CheckActivity()
{
InvalidActivityType = string.IsNullOrWhiteSpace(_poDraft.ActivityTypeEnum);
Console.WriteLine($"Type => {InvalidActivityType}");
Console.WriteLine($"ActivityType => {InvalidActivityType}");
}
private void CheckStatus()
{
InvalidStatusType = string.IsNullOrWhiteSpace(_poDraft.ActivityStatusEnum);
Console.WriteLine($"statusType => {InvalidStatusType}");
Console.WriteLine($"StatusType => {InvalidStatusType}");
}
private void CheckDate()
{
InvalidDate = _poDraft.CheckDate;
Console.WriteLine($"invalidDate => {InvalidDate}");
Console.WriteLine($"InvalidDate => {InvalidDate}");
}
private async Task DeleteDraft()
@ -175,8 +177,15 @@ public partial class CrmActivityCreate : IDisposable
{
Item = ngSalesItem,
Quantity = Convert.ToInt32(Quantity),
Price = Convert.ToDecimal(Price)
Price = Convert.ToDecimal(Price),
Discount = Convert.ToDecimal(Discount),
Sas = Sas
};
// reset internals to initial state
Sas = false;
Quantity = "1";
Price = "0";
Discount = "0";
// add it to the cart
DraftStateProvider.Draft.Items.Add(item);
// save the item using the CartStateProvider's save method

View file

@ -44,7 +44,7 @@ public partial class Login
}
else
{
var returnUrl = string.IsNullOrEmpty(ReturnUrl) ? "/Companies" : ReturnUrl;
var returnUrl = string.IsNullOrEmpty(ReturnUrl) ? "/companies" : ReturnUrl;
NavigationManager.NavigateTo(returnUrl);
}
}

View file

@ -37,21 +37,21 @@ namespace Wonky.Client.Providers
public override async Task<AuthenticationState> GetAuthenticationStateAsync()
{
// fetch token from localStorage
var token = await _storage.GetItemAsync<string>("_ax");
var token = await _storage.GetItemAsync<string>("_xa");
if (string.IsNullOrEmpty(token))
// return anonymous if empty
return _anonymous;
// create an authorized user
var userInfo = await _storage.GetItemAsync<UserInfoView>("_ux");
var userInfo = await _storage.GetItemAsync<UserInfoView>("_xu");
if (userInfo == null)
return _anonymous;
// set client authorization header
_client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("bearer", token);
var exp = await _storage.GetItemAsync<string>("_ex");
var exp = await _storage.GetItemAsync<string>("_xe");
var roles = ExtractRoles(userInfo);
var claims = new List<Claim>
@ -79,8 +79,8 @@ namespace Wonky.Client.Providers
_client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("bearer", token);
// create an authorized user
var userInfo = await _storage.GetItemAsync<UserInfoView>("_ux");
var exp = await _storage.GetItemAsync<string>("_ex");
var userInfo = await _storage.GetItemAsync<UserInfoView>("_xu");
var exp = await _storage.GetItemAsync<string>("_xe");
var roles = ExtractRoles(userInfo);
var claims = new List<Claim>
{

View file

@ -79,9 +79,9 @@ namespace Wonky.Client.Services
// process response content
var data = JsonSerializer.Deserialize<AuthResponseView>(resContent, _options);
await _localStorage.SetItemAsync("_ax", data.AccessToken);
await _localStorage.SetItemAsync("_rx", data.RefreshToken);
await _localStorage.SetItemAsync("_ex",
await _localStorage.SetItemAsync("_xa", data.AccessToken);
await _localStorage.SetItemAsync("_xr", data.RefreshToken);
await _localStorage.SetItemAsync("_xe",
(int)DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1)).TotalSeconds + data.ExpiresIn - 60);
// set default request headers using access_token
@ -89,7 +89,7 @@ namespace Wonky.Client.Services
var userInfo = await UserInfo();
await _localStorage.SetItemAsync("_ux", userInfo);
await _localStorage.SetItemAsync("_xu", userInfo);
// notify system on state change
((AuthStateProvider)_authStateProvider).NotifyUserAuthenticationAsync(data.AccessToken);
@ -100,7 +100,7 @@ namespace Wonky.Client.Services
public async Task<string> RefreshToken()
{
var refreshToken = await _localStorage.GetItemAsync<string>("_rx");
var refreshToken = await _localStorage.GetItemAsync<string>("_xr");
var credentials = new Dictionary<string, string>
{
["grant_type"] = "refresh_token",
@ -109,31 +109,28 @@ namespace Wonky.Client.Services
var response = await _client.PostAsync(_apiConfig.Value.TokenPath, new FormUrlEncodedContent(credentials));
if (response.IsSuccessStatusCode)
{
var resContent = await response.Content.ReadAsStringAsync();
var data = JsonSerializer.Deserialize<AuthResponseView>(resContent, _options);
if (!response.IsSuccessStatusCode) return string.Empty;
var resContent = await response.Content.ReadAsStringAsync();
var data = JsonSerializer.Deserialize<AuthResponseView>(resContent, _options);
// set default request headers using access_token
_client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("bearer", data.AccessToken);
// set default request headers using access_token
_client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("bearer", data.AccessToken);
await _localStorage.SetItemAsync("_ax", data.AccessToken);
await _localStorage.SetItemAsync("_rx", data.RefreshToken);
await _localStorage.SetItemAsync("_ex",
(int)DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1)).TotalSeconds + data.ExpiresIn - 60);
return data.AccessToken;
}
await _localStorage.SetItemAsync("_xa", data.AccessToken);
await _localStorage.SetItemAsync("_xr", data.RefreshToken);
await _localStorage.SetItemAsync("_xe",
(int)DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1)).TotalSeconds + data.ExpiresIn - 60);
return data.AccessToken;
return string.Empty;
}
public async Task Logout()
{
// clear localStorage
await _localStorage.RemoveItemAsync("_ax");
await _localStorage.RemoveItemAsync("_rx");
await _localStorage.RemoveItemAsync("_ux");
await _localStorage.RemoveItemAsync("_ex");
await _localStorage.RemoveItemAsync("_xa");
await _localStorage.RemoveItemAsync("_xr");
await _localStorage.RemoveItemAsync("_xu");
await _localStorage.RemoveItemAsync("_xe");
// notify system on user logout
((AuthStateProvider)_authStateProvider).NotifyUserLogout();
// remove request headers
@ -146,7 +143,7 @@ namespace Wonky.Client.Services
var infoContent = await infoResponse.Content.ReadAsStringAsync();
var userInfo = JsonSerializer.Deserialize<UserInfoView>(infoContent, _options);
if(write)
await _localStorage.SetItemAsync("_ux", userInfo);
await _localStorage.SetItemAsync("_xu", userInfo);
return userInfo ?? new UserInfoView();
}

View file

@ -36,7 +36,7 @@ namespace Wonky.Entity.DTO
[Required(ErrorMessage = "Vælg aktivitetstype")] public string ActivityTypeEnum { get; set; } = "";
[Required(ErrorMessage = "Vælg status for besøg ")] public string ActivityStatusEnum { get; set; } = "";
public bool CheckDate { get; set; }
public DateTime ActivityDate { get; set; }
[Required] public DateTime ActivityDate { get; set; }
[MaxLength(50, ErrorMessage = "Du kan højst bruge 50 tegn")] public string Demo { get; set; } = "";
[MaxLength(20, ErrorMessage = "Du kan højst bruge 20 tegn")] public string OurRef { get; set; } = "";
[MaxLength(20, ErrorMessage = "Du kan højst bruge 20 tegn")] public string ReferenceNumber { get; set; } = "";