contacts display add/remove/edit

This commit is contained in:
Frede Hundewadt 2022-11-17 19:11:49 +01:00
parent c5e0099af6
commit 7c718360d8
17 changed files with 785 additions and 549 deletions

View file

@ -16,7 +16,7 @@
*@
@* <img class="state the-draw rounded-circle me-1" src="state.png" alt="state"/> *@
<img class="img-fluid float-start border border-secondary rounded-circle state @StateClass-bg me-1" src="state.png" alt="state"/>
<img class="img-fluid rounded-circle state @StateClass-bg" src="state.png" alt="state"/>
@code{
[Parameter] public string StateClass { get; set; } = "";
}

View file

@ -4,5 +4,9 @@ namespace Wonky.Client.HttpInterfaces;
public interface ICrmContactHttpRepository
{
Task CreateContact(ContactDto contact);
Task<string> CreateContact(ContactDto model);
Task<ContactDto> GetContact(string companyId, string contactId);
Task<List<ContactDto>> GetContacts(string companyId);
Task DeleteContact(string companyId, string contactId);
Task UpdateContact(ContactDto model);
}

View file

@ -44,7 +44,7 @@ public class CrmCompanyHttpRepository : ICrmCompanyHttpRepository
private readonly NavigationManager _navigation;
private ILogger<CrmCompanyHttpRepository> _logger;
private readonly HttpClient _client;
private readonly ApiConfig _apiConfig;
private readonly ApiConfig _conf;
public CrmCompanyHttpRepository(HttpClient client,
ILogger<CrmCompanyHttpRepository> logger,
@ -54,8 +54,9 @@ public class CrmCompanyHttpRepository : ICrmCompanyHttpRepository
_client = client;
_logger = logger;
_navigation = navigation;
_apiConfig = apiConfig.Value;
_conf = apiConfig.Value;
}
/// <summary>
/// Get from crm endpoint
/// </summary>
@ -73,7 +74,7 @@ public class CrmCompanyHttpRepository : ICrmCompanyHttpRepository
["isHidden"] = pagingParameters.IsHidden.ToString(),
["hasFolded"] = pagingParameters.HasFolded.ToString()
};
var response = await _client.GetAsync(QueryHelpers.AddQueryString($"{_apiConfig.CrmCustomers}/page", queryString));
var response = await _client.GetAsync(QueryHelpers.AddQueryString($"{_conf.CrmCustomers}/page", queryString));
var content = await response.Content.ReadAsStringAsync();
@ -87,7 +88,7 @@ public class CrmCompanyHttpRepository : ICrmCompanyHttpRepository
public async Task<CompanyDto> GetCompanyById(string companyId)
{
var company = await _client.GetFromJsonAsync<CompanyDto>($"{_apiConfig.CrmCustomers}/{companyId}");
var company = await _client.GetFromJsonAsync<CompanyDto>($"{_conf.CrmCustomers}/{companyId}");
return company ?? new CompanyDto();
}
@ -98,7 +99,7 @@ public class CrmCompanyHttpRepository : ICrmCompanyHttpRepository
/// <returns>company id</returns>
public async Task<string> CreateCompany(CompanyDto model)
{
var response = await _client.PostAsJsonAsync($"{_apiConfig.CrmCustomers}", model);
var response = await _client.PostAsJsonAsync($"{_conf.CrmCustomers}", model);
var content = await response.Content.ReadAsStringAsync();
var result = JsonSerializer.Deserialize<CompanyDto>(content, _options);
return result.CompanyId;
@ -112,7 +113,7 @@ public class CrmCompanyHttpRepository : ICrmCompanyHttpRepository
/// <returns></returns>
public async Task<bool> UpdateCompany(string companyId, CompanyDto model)
{
var response = await _client.PutAsJsonAsync($"{_apiConfig.CrmCustomers}/{companyId}", model);
var response = await _client.PutAsJsonAsync($"{_conf.CrmCustomers}/{companyId}", model);
var content = await response.Content.ReadAsStringAsync();
Console.WriteLine(content);
return response.IsSuccessStatusCode;
@ -125,7 +126,7 @@ public class CrmCompanyHttpRepository : ICrmCompanyHttpRepository
/// <returns></returns>
public async Task<bool> DeleteCompany(string companyId)
{
var response = await _client.DeleteAsync($"{_apiConfig.CrmCustomers}/{companyId}");
var response = await _client.DeleteAsync($"{_conf.CrmCustomers}/{companyId}");
return response.IsSuccessStatusCode;
}
}

View file

@ -0,0 +1,73 @@
using System.Net.Http.Json;
using System.Text.Json;
using Microsoft.AspNetCore.Components;
using Microsoft.Extensions.Options;
using Wonky.Client.HttpInterfaces;
using Wonky.Entity.Configuration;
using Wonky.Entity.DTO;
namespace Wonky.Client.HttpRepository;
public class CrmContactHttpRepository : ICrmContactHttpRepository
{
private readonly JsonSerializerOptions _options = new ()
{
PropertyNameCaseInsensitive = true
};
private readonly NavigationManager _navigation;
private ILogger<CrmContactHttpRepository> _logger;
private readonly HttpClient _client;
private readonly ApiConfig _conf;
public CrmContactHttpRepository(HttpClient client,
ILogger<CrmContactHttpRepository> logger,
NavigationManager navigation,
IOptions<ApiConfig> apiConfig)
{
_client = client;
_logger = logger;
_navigation = navigation;
_conf = apiConfig.Value;
}
/// <summary>
/// Create contact
/// </summary>
/// <param name="model"></param>
public async Task<string> CreateContact(ContactDto model)
{
var response = await _client.PostAsJsonAsync(
$"{_conf.CrmCustomers}/{model.CompanyId}/contacts", model, _options);
return await response.Content.ReadAsStringAsync();
}
public async Task<ContactDto> GetContact(string companyId, string contactId)
{
return await _client.GetFromJsonAsync<ContactDto>(
$"{_conf.CrmCustomers}/{companyId}/contacts/{contactId}");
}
public async Task<List<ContactDto>> GetContacts(string companyId)
{
var response = await _client.GetAsync(
$"{_conf.CrmCustomers}/{companyId}/contacts");
var content = await response.Content.ReadAsStringAsync();
return string.IsNullOrWhiteSpace(content)
? new List<ContactDto>()
: JsonSerializer.Deserialize<List<ContactDto>>(content, _options);
}
public async Task DeleteContact(string companyId, string contactId)
{
await _client.DeleteAsync(
$"{_conf.CrmCustomers}/{companyId}/contacts/{contactId}");
}
public async Task UpdateContact(ContactDto model)
{
await _client.PutAsJsonAsync(
$"{_conf.CrmCustomers}/{model.CompanyId}/contacts/{model.ContactId}", model, _options);
}
}

View file

@ -1,59 +0,0 @@
@page "/companies/{CompanyId}/contacts/new"
<h3>Ny kontakt</h3>
<EditForm EditContext="ContactContext" OnValidSubmit="SubmitContactForm">
<DataAnnotationsValidator/>
<InputText type="hidden" id="companyId" @bind-Value="CompanyId"/>
<table class="table">
<thead>
</thead>
<tbody>
<tr>
<th class="align-middle" scope="row">
JobTitel
</th>
<td class="align-middle">
<InputText id="jobTitle" class="form-control" @bind-Value="Contact.JobTitle"/>
<ValidationMessage For="@(() => Contact.JobTitle)"></ValidationMessage>
</td>
<th class="align-middle" scope="row">
Email
</th>
<td class="align-middle">
<InputText id="email" class="form-control" @bind-Value="Contact.Email"/>
<ValidationMessage For="@(() => Contact.Email)"></ValidationMessage>
</td>
</tr>
<tr>
<th class="align-middle" scope="row">Fornavn</th>
<td class="align-middle">
<InputText id="firstName" class="form-control" @bind-Value="Contact.FirstName"/>
<ValidationMessage For="@(() => Contact.FirstName)"></ValidationMessage>
</td>
<th class="align-middle" scope="row">Efternavn</th>
<td class="align-middle">
<InputText id="lastName" class="form-control" @bind-Value="Contact.LastName"/>
<ValidationMessage For="@(() => Contact.LastName)"></ValidationMessage>
</td>
</tr>
<tr>
<th class="align-middle" scope="row">Mobile</th>
<td class="align-middle">
<InputText id="mobile" class="form-control" @bind-Value="Contact.Mobile"/>
<ValidationMessage For="@(() => Contact.Mobile)"></ValidationMessage>
</td>
<th class="align-middle" scope="row">Telefon</th>
<td class="align-middle">
<InputText id="phone" class="form-control" @bind-Value="Contact.Phone"/>
<ValidationMessage For="@(() => Contact.Phone)"></ValidationMessage>
</td>
</tr>
</tbody>
</table>
<div class="row mb-2">
<div class="col-md-8"></div>
<div class="col-md-4">
<button type="submit" class="btn btn-success" disabled="@FormInvalid">Opret</button>
</div>
</div>
</EditForm>

View file

@ -1,19 +0,0 @@
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Forms;
using Wonky.Entity.DTO;
namespace Wonky.Client.Pages;
public partial class CrmCompanyContactNewPage
{
[Parameter] public string CompanyId { get; set; } = "";
private EditContext ContactContext { get; set; }
private ContactDto Contact { get; set; } = new();
private bool FormInvalid { get; set; } = true;
private async Task SubmitContactForm()
{
}
}

View file

@ -30,29 +30,29 @@
</tr>
</thead>
<tbody>
@if (_dk)
@if (Dk)
{
<tr>
<td>
<VatCompanyNameInputComponent CompanyName="@_company.Name" OnValidSubmit="GetInfoFromName"/>
<VatCompanyNameInputComponent CompanyName="@Company.Name" OnValidSubmit="GetInfoFromName"/>
</td>
</tr>
}
<tr>
<td>
<VatNumberInputComponent VatNumber="@_company.VatNumber" OnValidSubmit="GetInfoFromVat"/>
<VatNumberInputComponent VatNumber="@Company.VatNumber" OnValidSubmit="GetInfoFromVat"/>
</td>
</tr>
@if (_dk)
@if (Dk)
{
<tr>
<td>
<VatAddressInputComponent Address="_vatAddress" OnValidSubmit="GetInfoFromAddress"/>
<VatAddressInputComponent Address="CompanyVatAddress" OnValidSubmit="GetInfoFromAddress"/>
</td>
</tr>
}
@if (_vInfos.Any() && _showInfos)
@if (VatInfos.Any() && ShowInfos)
{
<tr>
<td colspan="2">
@ -67,7 +67,7 @@
</tr>
</thead>
<tbody>
@foreach (var info in _vInfos)
@foreach (var info in VatInfos)
{
<tr>
<td class="align-middle">@info.VatNumber</td>
@ -87,9 +87,9 @@
</tbody>
</table>
<EditForm EditContext="_editContext" OnValidSubmit="SubmitCompanyForm">
<EditForm EditContext="CompanyContext" OnValidSubmit="SubmitCompanyForm">
<DataAnnotationsValidator/>
<InputText type="hidden" id="salesRepId" @bind-Value="_company.SalesRepId"/>
<InputText type="hidden" id="salesRepId" @bind-Value="Company.SalesRepId"/>
<table class="table">
<thead>
<tr>
@ -107,14 +107,14 @@
<tbody>
<tr>
<td>
<InputDate id="lastVisit" class="form-control" @bind-Value="@_lastVisit"/>
<InputDate id="lastVisit" class="form-control" @bind-Value="@LastVisit"/>
</td>
<td>
<InputDate id="nextVisit" class="form-control" @bind-Value="@(_nextVisit)" readonly />
<InputDate id="nextVisit" class="form-control" @bind-Value="@(NextVisit)" readonly />
</td>
<td>
<InputNumber id="interval" class="form-control" @bind-Value="_company.Interval"/>
<ValidationMessage For="@(() => _company.Interval)"></ValidationMessage>
<InputNumber id="interval" class="form-control" @bind-Value="Company.Interval"/>
<ValidationMessage For="@(() => Company.Interval)"></ValidationMessage>
</td>
</tr>
</tbody>
@ -129,70 +129,83 @@
</thead>
<tbody>
<tr>
<td class="align-middle">Moms/Org Reg.</td>
<th class="align-middle">Moms/Org Reg.</th>
<td class="align-middle state">
<DisplayStateComponent StateClass="@RegState"></DisplayStateComponent>
</td>
<td class="align-middle">
<InputText id="vatNumber" class="form-control" @bind-Value="_company.VatNumber"/>
<ValidationMessage For="@(() => _company.VatNumber)"></ValidationMessage>
<InputText id="vatNumber" class="form-control" @bind-Value="Company.VatNumber"/>
<ValidationMessage For="@(() => Company.VatNumber)"></ValidationMessage>
</td>
<td class="align-middle">Telefon</td>
<th class="align-middle">Telefon</th>
<td class="align-middle">
<InputText id="phone" class="form-control" @bind-Value="_company.Phone"/>
<ValidationMessage For="@(() => _company.Phone)"></ValidationMessage>
<InputText id="phone" class="form-control" @bind-Value="Company.Phone"/>
<ValidationMessage For="@(() => Company.Phone)"></ValidationMessage>
</td>
</tr>
<tr>
<td class="align-middle">Firmanavn</td>
<th class="align-middle">Firmanavn</th>
<td class="align-middle"></td>
<td>
<InputText id="name" class="form-control" @bind-Value="_company.Name"/>
<ValidationMessage For="@(() => _company.Name)"></ValidationMessage>
<InputText id="name" class="form-control" @bind-Value="Company.Name"/>
<ValidationMessage For="@(() => Company.Name)"></ValidationMessage>
</td>
<td class="align-middle">Attention</td>
<th class="align-middle">Attention</th>
<td>
<InputText id="attention" class="form-control" @bind-Value="_company.Attention"/>
<ValidationMessage For="@(() => _company.Attention)"></ValidationMessage>
<InputText id="attention" class="form-control" @bind-Value="Company.Attention"/>
<ValidationMessage For="@(() => Company.Attention)"></ValidationMessage>
</td>
</tr>
<tr>
<td class="align-middle">Adresse1</td>
<th class="align-middle">Adresse1</th>
<td class="align-middle"></td>
<td class="align-middle">
<InputText id="address1" class="form-control" @bind-Value="_company.Address1"/>
<ValidationMessage For="@(() => _company.Address1)"></ValidationMessage>
<InputText id="address1" class="form-control" @bind-Value="Company.Address1"/>
<ValidationMessage For="@(() => Company.Address1)"></ValidationMessage>
</td>
<td class="align-middle">Adresse2</td>
<th class="align-middle">Adresse2</th>
<td class="align-middle">
<InputText id="address2" class="form-control" @bind-Value="_company.Address2"/>
<ValidationMessage For="@(() => _company.Address2)"></ValidationMessage>
<InputText id="address2" class="form-control" @bind-Value="Company.Address2"/>
<ValidationMessage For="@(() => Company.Address2)"></ValidationMessage>
</td>
</tr>
<tr>
<td class="align-middle">Postnr</td>
<th class="align-middle">Postnr</th>
<td class="align-middle"></td>
<td class="align-middle">
<InputText id="zipCode" class="form-control" @bind-Value="_company.ZipCode"/>
<ValidationMessage For="@(() => _company.ZipCode)"></ValidationMessage>
<InputText id="zipCode" class="form-control" @bind-Value="Company.ZipCode"/>
<ValidationMessage For="@(() => Company.ZipCode)"></ValidationMessage>
</td>
<td class="align-middle">Bynavn</td>
<th class="align-middle">Bynavn</th>
<td class="align-middle">
<InputText id="city" class="form-control" @bind-Value="_company.City"/>
<ValidationMessage For="@(() => _company.City)"></ValidationMessage>
<InputText id="city" class="form-control" @bind-Value="Company.City"/>
<ValidationMessage For="@(() => Company.City)"></ValidationMessage>
</td>
</tr>
<tr>
<td class="align-middle">Mobil</td>
<th class="align-middle">Mobil</th>
<td class="align-middle"></td>
<td class="align-middle">
<InputText id="mobile" class="form-control" @bind-Value="_company.Mobile"/>
<ValidationMessage For="@(() => _company.Mobile)"></ValidationMessage>
<InputText id="mobile" class="form-control" @bind-Value="Company.Mobile"/>
<ValidationMessage For="@(() => Company.Mobile)"></ValidationMessage>
</td>
<td class="align-middle">Email</td>
<th class="align-middle">Email</th>
<td class="align-middle">
<InputText id="email" class="form-control" @bind-Value="_company.Email"/>
<ValidationMessage For="@(() => _company.Email)"></ValidationMessage>
<InputText id="email" class="form-control" @bind-Value="Company.Email"/>
<ValidationMessage For="@(() => Company.Email)"></ValidationMessage>
</td>
</tr>
<tr>
<th class="align-middle">OBS</th>
<td class="align-middle" colspan="5">
<InputText id="note" class="form-control" @bind-Value="Company.Note"/>
<ValidationMessage For="@(() => Company.Note)"></ValidationMessage>
</td>
</tr>
<tr>
<th class="align-middle">Notater</th>
<td class="align-middle" colspan="5">
<InputTextArea id="crmNotes" class="form-control" @bind-Value="Company.CrmNotes"/>
</td>
</tr>
</tbody>
@ -200,7 +213,7 @@
<div class="row mb-2">
<div class="col-md-8"></div>
<div class="col-md-4">
<button type="submit" class="btn btn-success" disabled="@_formInvalid">Opret</button>
<button type="submit" class="btn btn-success" disabled="@FormInvalid">Opret</button>
</div>
</div>
</EditForm>

View file

@ -38,154 +38,154 @@ namespace Wonky.Client.Pages
{
public partial class CrmCompanyNewPage : IDisposable
{
[Inject] public IToastService _toast { get; set; }
[Inject] public ILogger<CrmCompanyNewPage> _logger { get; set; }
[Inject] public ILocalStorageService _storage { get; set; }
[Inject] public NavigationManager _navigator { get; set; }
[Inject] public ICrmCompanyHttpRepository _companyRepo { get; set; }
[Inject] public HttpInterceptorService _interceptor { get; set; }
[Inject] public VatInfoLookupService _vatService { get; set; }
private EditContext _editContext { get; set; }
private CompanyDto _company { get; set; } = new();
private VirkRegInfo _virkRegInfo { get; set; } = new();
private List<VirkRegInfo> _vInfos { get; set; } = new();
private VatAddress _vatAddress { get; set; } = new();
private bool _formInvalid = true;
[Inject] public IToastService Toaster { get; set; }
[Inject] public ILogger<CrmCompanyNewPage> Logger { get; set; }
[Inject] public ILocalStorageService Storage { get; set; }
[Inject] public NavigationManager Navigator { get; set; }
[Inject] public ICrmCompanyHttpRepository CompanyRepo { get; set; }
[Inject] public HttpInterceptorService Interceptor { get; set; }
[Inject] public VatInfoLookupService VatService { get; set; }
private EditContext CompanyContext { get; set; }
private CompanyDto Company { get; set; } = new();
private VirkRegInfo CompanyRegInfo { get; set; } = new();
private List<VirkRegInfo> VatInfos { get; set; } = new();
private VatAddress CompanyVatAddress { get; set; } = new();
private bool FormInvalid = true;
private string RegState = "";
private DateTime _lastVisit { get; set; }
private DateTime _nextVisit { get; set; }
private bool _dk { get; set; } = true;
private bool _showInfos = true;
private DateTime LastVisit { get; set; }
private DateTime NextVisit { get; set; }
private bool Dk { get; set; } = true;
private bool ShowInfos = true;
protected override async Task OnInitializedAsync()
{
_editContext = new EditContext(_company);
CompanyContext = new EditContext(Company);
_editContext.OnFieldChanged += HandleFieldChanged;
_editContext.OnValidationStateChanged += ValidationChanged;
CompanyContext.OnFieldChanged += HandleFieldChanged;
CompanyContext.OnValidationStateChanged += ValidationChanged;
var ux = await _storage.GetItemAsync<UserInfoView>("_xu");
_dk = ux.CountryCode.ToLower() == "dk";
var ux = await Storage.GetItemAsync<UserInfoView>("_xu");
Dk = ux.CountryCode.ToLower() == "dk";
_company.SalesRepId = ux.Id;
_company.CountryCode = ux.CountryCode.ToLower();
Company.SalesRepId = ux.Id;
Company.CountryCode = ux.CountryCode.ToLower();
_lastVisit = DateTime.Now;
_nextVisit = DateTime.Now.AddDays(_company.Interval * 7);
_company.LastVisit = $"{_lastVisit:yyyy-MM-dd}";
_company.NextVisit = $"{_nextVisit:yyyy-MM-dd}";
LastVisit = DateTime.Now;
NextVisit = DateTime.Now.AddDays(Company.Interval * 7);
Company.LastVisit = $"{LastVisit:yyyy-MM-dd}";
Company.NextVisit = $"{NextVisit:yyyy-MM-dd}";
_interceptor.RegisterEvent();
_interceptor.RegisterBeforeSendEvent();
Interceptor.RegisterEvent();
Interceptor.RegisterBeforeSendEvent();
}
private async Task GetInfoFromName(string entityName)
{
_toast.ShowInfo("Vent for firma info ...");
_vInfos = await _vatService
Toaster.ShowInfo("Vent for firma info ...");
VatInfos = await VatService
.QueryVirkRegistry(new VirkParams {EntityName = entityName});
if (!_vInfos.Any())
if (!VatInfos.Any())
{
_toast.ShowError($"Firma med navn '{entityName}' findes ikke.");
Toaster.ShowError($"Firma med navn '{entityName}' findes ikke.");
}
}
private async Task GetInfoFromAddress(VatAddress address)
{
_showInfos = true;
_toast.ShowInfo("Vent for adresse info ...");
_vInfos = await _vatService.QueryVirkRegistry(
ShowInfos = true;
Toaster.ShowInfo("Vent for adresse info ...");
VatInfos = await VatService.QueryVirkRegistry(
new VirkParams
{
StreetName = address.StreetName,
HouseNumber = address.HouseNumber,
ZipCode = address.ZipCode
});
if (!_vInfos.Any())
if (!VatInfos.Any())
{
_toast.ShowWarning($"Ingen data for adresse ...");
Toaster.ShowWarning($"Ingen data for adresse ...");
}
}
private async Task GetInfoFromVat(string vatNumber)
{
_showInfos = true;
_toast.ShowInfo("Vent for firma info ...");
_vInfos = await _vatService
ShowInfos = true;
Toaster.ShowInfo("Vent for firma info ...");
VatInfos = await VatService
.QueryVirkRegistry(new VirkParams {VatNumber = vatNumber});
if (!_vInfos.Any())
if (!VatInfos.Any())
{
_toast.ShowError($"Firma med CVR '{vatNumber}' findes ikke.");
Toaster.ShowError($"Firma med CVR '{vatNumber}' findes ikke.");
}
}
private void SelectCompany(string vatNumber)
{
_showInfos = false;
_virkRegInfo = (from x in _vInfos where x.VatNumber == vatNumber select x).First();
RegState = _virkRegInfo.States[^1].State == "NORMAL" ? "the-good" : "the-ugly";
_company.Name = _virkRegInfo.Name;
_company.Address1 = _virkRegInfo.Address;
_company.Address2 = _virkRegInfo.CoName;
_company.ZipCode = _virkRegInfo.ZipCode;
_company.City = _virkRegInfo.City;
_company.VatNumber = _virkRegInfo.VatNumber;
_company.ValidVat = 1;
ShowInfos = false;
CompanyRegInfo = (from x in VatInfos where x.VatNumber == vatNumber select x).First();
RegState = CompanyRegInfo.States[^1].State == "NORMAL" ? "the-good" : "the-ugly";
Company.Name = CompanyRegInfo.Name;
Company.Address1 = CompanyRegInfo.Address;
Company.Address2 = CompanyRegInfo.CoName;
Company.ZipCode = CompanyRegInfo.ZipCode;
Company.City = CompanyRegInfo.City;
Company.VatNumber = CompanyRegInfo.VatNumber;
Company.ValidVat = 1;
StateHasChanged();
}
private async Task SubmitCompanyForm()
{
_formInvalid = true;
_company.LastVisit = $"{_lastVisit:yyyy-MM-dd}";
_company.NextVisit = $"{_nextVisit:yyyy-MM-dd}";
FormInvalid = true;
Company.LastVisit = $"{LastVisit:yyyy-MM-dd}";
Company.NextVisit = $"{NextVisit:yyyy-MM-dd}";
var newId = await _companyRepo.CreateCompany(_company);
var newId = await CompanyRepo.CreateCompany(Company);
if (!string.IsNullOrWhiteSpace(newId))
{
_toast.ShowSuccess($"'{_company.Name}' er oprettet i CRM.");
_navigator.NavigateTo($"/companies/{newId}");
Toaster.ShowSuccess($"'{Company.Name}' er oprettet i CRM.");
Navigator.NavigateTo($"/companies/{newId}");
}
else
{
_toast.ShowWarning($"'{_company.Name}' IKKE oprettet.");
_formInvalid = false;
Toaster.ShowWarning($"'{Company.Name}' IKKE oprettet.");
FormInvalid = false;
}
}
private void HandleFieldChanged(object sender, FieldChangedEventArgs e)
{
_nextVisit = _lastVisit.AddDays(7 * _company.Interval);
NextVisit = LastVisit.AddDays(7 * Company.Interval);
if (!_company.ValidDateSpan())
if (!Company.ValidDateSpan())
{
_toast.ShowError("Dato for næste besøg skal ligge efter sidste besøg.");
_formInvalid = true;
Toaster.ShowError("Dato for næste besøg skal ligge efter sidste besøg.");
FormInvalid = true;
}
else
{
_formInvalid = !_editContext.Validate();
FormInvalid = !CompanyContext.Validate();
}
StateHasChanged();
}
private void ValidationChanged(object sender, ValidationStateChangedEventArgs e)
{
_formInvalid = true;
FormInvalid = true;
_editContext.OnFieldChanged -= HandleFieldChanged;
CompanyContext.OnFieldChanged -= HandleFieldChanged;
_editContext = new EditContext(_company);
CompanyContext = new EditContext(Company);
_formInvalid = !_editContext.Validate();
FormInvalid = !CompanyContext.Validate();
_editContext.OnFieldChanged += HandleFieldChanged;
_editContext.OnValidationStateChanged -= ValidationChanged;
CompanyContext.OnFieldChanged += HandleFieldChanged;
CompanyContext.OnValidationStateChanged -= ValidationChanged;
}
public void Dispose()
{
_interceptor.DisposeEvent();
_editContext.OnFieldChanged -= HandleFieldChanged;
_editContext.OnValidationStateChanged -= ValidationChanged;
Interceptor.DisposeEvent();
CompanyContext.OnFieldChanged -= HandleFieldChanged;
CompanyContext.OnValidationStateChanged -= ValidationChanged;
}
}
}

View file

@ -33,11 +33,11 @@
<div class="card-header bg-dark text-white">
<h3>@Company.Name</h3>
</div>
@if (_dk)
@if (Dk)
{
<div class="card-body">
<VatAddressInputComponent Address="_vatAddress" OnValidSubmit="GetInfoFromAddress"/>
@if (_vInfos.Any())
<VatAddressInputComponent Address="CompanyVatAddress" OnValidSubmit="GetInfoFromAddress"/>
@if (VatInfos.Any())
{
<table class="table">
<thead>
@ -50,7 +50,7 @@
</tr>
</thead>
<tbody>
@foreach (var info in _vInfos)
@foreach (var info in VatInfos)
{
<tr>
<td class="align-middle">@info.VatNumber</td>
@ -69,14 +69,12 @@
}
</div>
}
<EditForm EditContext="_editContext" OnValidSubmit="SubmitUpdate">
<EditForm EditContext="CompanyContext" OnValidSubmit="SubmitUpdate">
<DataAnnotationsValidator/>
<div class="card-body">
<table class="table table-sm">
<tbody>
<tr class="align-middle">
<th colspan="2">BEMÆRK</th>
<td colspan="5">
<div class="row mb-1">
<label for="note" class="col-sm-1 col-form-label-sm">OBS</label>
<div class="col-sm-9">
@if (string.IsNullOrWhiteSpace(Company.Note))
{
<InputText name="note" id="note" class="form-control" @bind-Value="Company.Note"/>
@ -86,139 +84,146 @@
<InputText name="note" id="note" class="form-control bg-warning text-black" @bind-Value="Company.Note"/>
}
<ValidationMessage For="@(() => Company.Note)"></ValidationMessage>
</td>
</tr >
<tr class="align-middle">
<th>
CVR/ORG
</th>
<td class="state">
<DisplayStateComponent StateClass="@_vatState"></DisplayStateComponent>
</td>
<td>
</div>
</div>
<div class="row mb-1">
<label for="vatNumber" class="col-sm-1 col-form-label-sm">MomsNr</label>
<div class="col-sm-4">
<div class="input-group">
<span class="input-group-text">
<DisplayStateComponent StateClass="@VatState"/>
</span>
<InputText id="vatNumber" class="form-control" @bind-Value="Company.VatNumber"/>
<ValidationMessage For="@(() => Company.VatNumber)"></ValidationMessage>
@* <button class="btn btn-warning" type="button" @onclick="CallVatLookupModal">CVR opslag</button> *@
</td>
<th>
Konto
</th>
<td colspan="3">
<input type="text" class="form-control" readonly value="@Company.Account"/>
</td>
</tr>
<tr class="align-middle">
<th>
Firmanavn
</th>
<td></td>
<td>
</div>
</div>
<label for="account" class="col-sm-1 col-form-label-sm">Konto</label>
<div class="col-sm-4">
<input id="account" type="text" class="form-control" readonly value="@Company.Account"/>
</div>
</div>
<div class="row mb-1">
<label for="name" class="col-sm-1 col-form-label-sm">Navn</label>
<div class="col-sm-5">
<InputText id="name" class="form-control" @bind-Value="Company.Name"/>
<ValidationMessage For="@(() => Company.Name)"></ValidationMessage>
</td>
<th>
Attention
</th>
<td colspan="3">
</div>
<label for="attention" class="col-sm-1 col-form-label-sm">Att.</label>
<div class="col-sm-3">
<InputText id="attention" class="form-control" @bind-Value="Company.Attention"/>
<ValidationMessage For="@(() => Company.Attention)"></ValidationMessage>
</td>
</tr>
<tr class="align-middle">
<th>
Adresse1
</th>
<td></td>
<td>
</div>
</div>
<div class="row mb-1">
<label for="address1" class="col-sm-1 col-form-label-sm">Adresse</label>
<div class="col-sm-5">
<InputText id="address1" class="form-control" @bind-Value="Company.Address1"/>
<ValidationMessage For="@(() => Company.Address1)"></ValidationMessage>
</td>
<th>
Adresse2
</th>
<td colspan="3">
</div>
<label for="address2" class="col-sm-1 col-form-label-sm">Adresse</label>
<div class="col-sm-3">
<InputText id="address2" class="form-control" @bind-Value="Company.Address2"/>
<ValidationMessage For="@(() => Company.Address2)"></ValidationMessage>
</td>
</tr>
<tr class="align-middle">
<th>
Postnr
</th>
<td></td>
<td>
</div>
</div>
<div class="row mb-1">
<label for="zipCode" class="col-sm-1 col-form-label-sm">PostNr</label>
<div class="col-sm-2">
<InputText id="zipCode" class="form-control" @bind-Value="Company.ZipCode"/>
<ValidationMessage For="@(() => Company.ZipCode)"></ValidationMessage>
</td>
<th>
Bynavn
</th>
<td colspan="3">
</div>
<label for="city" class="col-sm-1 col-form-label-sm">Bynavn</label>
<div class="col-sm-6">
<InputText id="city" class="form-control" @bind-Value="Company.City"/>
<ValidationMessage For="@(() => Company.City)"></ValidationMessage>
</td>
</tr>
<tr class="align-middle">
<th>
Epost
</th>
<td></td>
<td>
<InputText id="email" class="form-control" @bind-Value="Company.Email"/>
<ValidationMessage For="@(() => Company.Email)"></ValidationMessage>
</td>
<th>
Telefon
</th>
<td>
</div>
</div>
<div class="row mb-1">
<label for="phone" class="col-sm-1 col-form-label-sm">Telefon</label>
<div class="col-sm-4">
<InputText id="phone" class="form-control" @bind-Value="Company.Phone"/>
<ValidationMessage For="@(() => Company.Phone)"></ValidationMessage>
</td>
<th>
Mobil
</th>
<td>
</div>
<label for="mobile" class="col-sm-1 col-form-label-sm">Mobil</label>
<div class="col-sm-4">
<InputText id="mobile" class="form-control" @bind-Value="Company.Mobile"/>
<ValidationMessage For="@(() => Company.Mobile)"></ValidationMessage>
</td>
</tr>
<tr class="align-middle">
<th>
Næste besøg
</th>
<td class="state">
<DisplayStateComponent StateClass="@_visitState">
</DisplayStateComponent>
</td>
<td>
<InputDate id="nextVisit" class="form-control" @bind-Value="@(_nextVisit)"/>
</td>
<th>
Besøgt
</th>
<td colspan="3">
<InputDate id="lastVisit" class="form-control" @bind-Value="@_lastVisit"/>
</td>
</tr>
<tr class="align-middle">
<th>
Interval (uger)
</th>
<td></td>
<td>
</div>
</div>
<div class="row mb-1">
<label for="email" class="col-sm-1 col-form-label-sm">Epost</label>
<div class="col-sm-9">
<InputText id="email" class="form-control" @bind-Value="Company.Email"/>
<ValidationMessage For="@(() => Company.Email)"></ValidationMessage>
</div>
</div>
<hr/>
<div class="row mb-1">
<label for="nextVisit" class="col-sm-1 col-form-label-sm">Næste besøg</label>
<div class="col-sm-3">
<div class="input-group">
<span class="input-group-text">
<DisplayStateComponent StateClass="@VisitState"/>
</span>
<InputDate id="nextVisit" class="form-control" @bind-Value="@(NextVisit)"/>
</div>
</div>
<label for="lastVisit" class="col-sm-1 col-form-label-sm">Sidse besøg</label>
<div class="col-sm-3">
<InputDate id="lastVisit" class="form-control" @bind-Value="@LastVisit"/>
</div>
<label for="interval" class="col-sm-2 col-form-label-sm">Uge Interval</label>
<div class="col-sm-2">
<InputNumber id="interval" class="form-control" @bind-Value="Company.Interval"/>
<ValidationMessage For="@(() => Company.Interval)"></ValidationMessage>
</td>
<td colspan="4">
@if (Company.HasFolded == 1)
{
<button type="button" class="btn btn-info" onclick="@ForceActivity">Aktiver besøg</button>
}
</td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="row mb-1">
<label for="contacts" class="col-sm-1 col-form-label-sm">Kontakt</label>
<div id="contacts" class="col-sm-6">
<div class="list-group">
<div class="list-group-item list-group-item-action" @onclick="() => OpenContact(DefaultContact)">
<div class="row">
<div class="col">Stilling</div>
<div class="col">Navn</div>
<div class="col">Direkte</div>
<div class="col text-end">
<i class="bi-plus-circle"></i>
</div>
</div>
</div>
@if (Contacts.Any())
{
@foreach (var contact in Contacts)
{
<div class="list-group-item list-group-item-action" @onclick="() => OpenContact(contact)">
<div class="row">
<div class="col">@contact.JobTitle</div>
<div class="col">@contact.FirstName @contact.LastName</div>
<div class="col">@contact.PhoneDirect</div>
<div class="col text-end">
<i class="bi-pencil"></i>
</div>
</div>
</div>
}
}
</div>
</div>
<label for="crmNotes" class="col-sm-1 col-form-label-sm">Noter</label>
<div class="col-sm-4">
<InputTextArea id="crmNotes" class="form-control" style="height: 100%;" @bind-Value="Company.CrmNotes"/>
</div>
</div>
</div>
<div class="card-footer">
<div class="row mb-2">
<div class="col">
@ -231,13 +236,17 @@
<a class="btn btn-light border-dark d-block" href="/companies/@Company.CompanyId/h/i">Produkter</a>
</div>
<div class="col d-block">
<button type="submit" class="btn btn-light border-dark d-block" disabled="@(_working)">Gem</button>
<button type="submit" class="btn btn-light border-dark d-block" disabled="@(Working)">Gem</button>
@if (Company.HasFolded == 1)
{
<button type="button" class="btn btn-warning" onclick="@ForceActivity">Aktiver besøg</button>
}
</div>
<div class="col">
<ActivityButton ActionLink="@_actionLink"
<ActivityButton ActionLink="@ActionLink"
ButtonText="Besøg"
ButtonType="primary"
Enabled="@_enableActivity">
Enabled="@EnableActivity">
</ActivityButton>
</div>
</div>
@ -250,4 +259,5 @@ else
<LoaderThreeDots/>
}
<VatLookupDkModal VatAddress="_vatAddress" OnSelectedCompany="OnSelectedCompany" @ref="_vatLookupModal"/>
<VatLookupDkModal VatAddress="CompanyVatAddress" OnSelectedCompany="OnSelectedCompany" @ref="VatLookupPopup"/>
<ContactModal ParamContact="@SelectedContact" CompanyName="@Company.Name" @ref="ContactPopup" OnSaveClicked="SaveContact" OnDeleteClicked="DeleteContact" />

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.CodeDom.Compiler;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Text.RegularExpressions;
@ -39,81 +40,85 @@ public partial class CrmCompanyViewPage : IDisposable
{
[Parameter] public string CompanyId { get; set; } = "";
[Inject] public IToastService Toaster { get; set; }
[Inject] public ILogger<CrmCompanyViewPage> _logger { get; set; }
[Inject] public NavigationManager _navigator { get; set; }
[Inject] public ICrmCompanyHttpRepository _companyRepo { get; set; }
[Inject] public ILogger<CrmCompanyViewPage> Logger { get; set; }
[Inject] public NavigationManager Navigator { get; set; }
[Inject] public ICrmCompanyHttpRepository CompanyRepo { get; set; }
[Inject] public ICrmHistoryHttpRepository HistoryRepo { get; set; }
[Inject] public HttpInterceptorService _interceptor { get; set; }
[Inject] public VatInfoLookupService _vatService { get; set; }
[Inject] public ILocalStorageService _storage { get; set; }
private CompanyDto Company { get; set; } = new();
private EditContext _editContext { get; set; }
private List<VirkRegInfo> _vInfos { get; set; } = new();
private VirkRegInfo _virkRegInfo { get; set; } = new();
private DateTime _lastVisit { get; set; }
private DateTime _nextVisit { get; set; }
private string _vatState { get; set; } = "the-ugly";
private VatAddress _vatAddress = new();
private bool _validVat;
private bool _hasFolded;
private bool _formInvalid = true;
private string _orgVat;
private string _countryCode = "dk";
private string _visitState = "the-ugly";
private int _enableActivity = 1;
private bool _hideButtons = false;
private string _actionLink = "";
private bool _working;
private string _btnUpdateText = "Opdater";
private bool _dk { get; set; } = true;
private int _isDirty { get; set; }
private int _vatUpdated { get; set; }
private bool Loading { get; set; } = true;
private VatLookupDkModal _vatLookupModal { get; set; } = new();
[Inject] public ICrmContactHttpRepository ContactRepo { get; set; }
[Inject] public HttpInterceptorService Interceptor { get; set; }
[Inject] public VatInfoLookupService VatService { get; set; }
[Inject] public ILocalStorageService Storage { get; set; }
private readonly JsonSerializerOptions _options = new () { PropertyNameCaseInsensitive = true };
private CompanyDto Company { get; set; } = new();
private EditContext CompanyContext { get; set; }
private List<VirkRegInfo> VatInfos { get; set; } = new();
private VirkRegInfo CompanyRegInfo { get; set; } = new();
private DateTime LastVisit { get; set; }
private DateTime NextVisit { get; set; }
private string VatState { get; set; } = "the-ugly";
private VatAddress CompanyVatAddress = new();
private bool ValidVat;
private bool HasFolded;
private bool FormInvalid = true;
private string CurrentOrgVat;
private string CountryCode = "dk";
private string VisitState = "the-ugly";
private int EnableActivity = 1;
private bool HideButtons = false;
private string ActionLink = "";
private bool Working;
private string BtnUpdateText = "Opdater";
private bool Dk { get; set; } = true;
private int IsDirty { get; set; }
private int VatUpdated { get; set; }
private bool Loading { get; set; } = true;
private List<ContactDto> Contacts { get; set; } = new();
private VatLookupDkModal VatLookupPopup { get; set; } = new();
private ContactDto SelectedContact { get; set; } = new();
private ContactDto DefaultContact { get; set; } = new();
private ContactModal ContactPopup { get; set; } = new();
protected override async Task OnInitializedAsync()
{
var ux = await _storage.GetItemAsync<UserInfoView>("_xu");
_countryCode = ux.CountryCode;
_dk = ux.CountryCode.ToLower() == "dk";
Company = await _companyRepo.GetCompanyById(CompanyId);
_interceptor.RegisterEvent();
_interceptor.RegisterBeforeSendEvent();
DefaultContact = new ContactDto { CompanyId = CompanyId, ContactId = "", FirstName = ""};
var ux = await Storage.GetItemAsync<UserInfoView>("_xu");
CountryCode = ux.CountryCode;
Dk = ux.CountryCode.ToLower() == "dk";
Company = await CompanyRepo.GetCompanyById(CompanyId);
Interceptor.RegisterEvent();
Interceptor.RegisterBeforeSendEvent();
// Company = await _companyRepo.GetCompanyById(CompanyId);
_orgVat = Company.VatNumber;
CurrentOrgVat = Company.VatNumber;
Company.CountryCode = ux.CountryCode.ToLower();
_enableActivity = Company.ValidVat;
EnableActivity = Company.ValidVat;
// override if canvas which has account property as empty string or "NY"
if (Company.Account == "NY" || string.IsNullOrWhiteSpace(Company.Account))
_enableActivity = 1;
EnableActivity = 1;
if (_dk)
_vatAddress = PrepareVatAddress(Company);
if (Dk)
CompanyVatAddress = PrepareVatAddress(Company);
if (Company.Interval == 0)
Company.Interval = 8;
_lastVisit = DateTime.Parse(Company.LastVisit);
_nextVisit = DateTime.Parse(Company.NextVisit);
LastVisit = DateTime.Parse(Company.LastVisit);
NextVisit = DateTime.Parse(Company.NextVisit);
if (_lastVisit.Year < 2020)
_lastVisit = DateTime.Parse("2020-01-01");
if (LastVisit.Year < 2020)
LastVisit = DateTime.Parse("2020-01-01");
if (!Company.ValidDateSpan())
_nextVisit = _lastVisit.AddDays(Company.Interval * 7);
NextVisit = LastVisit.AddDays(Company.Interval * 7);
_visitState = Utils.GetVisitState($"{_nextVisit:yyyy-MM-dd}");
_actionLink = $"/companies/{CompanyId}/activities/new"; // used when drawing visit button
VisitState = Utils.GetVisitState($"{NextVisit:yyyy-MM-dd}");
ActionLink = $"/companies/{CompanyId}/activities/new"; // used when drawing visit button
if(Company.HasFolded == 1)
{
// this is only used if user has selected to show all customers
_hasFolded = true;
_vatState = "the-dead";
_visitState = "the-dead";
HasFolded = true;
VatState = "the-dead";
VisitState = "the-dead";
}
else
{
@ -121,19 +126,51 @@ public partial class CrmCompanyViewPage : IDisposable
if (Company.ValidVat == 0 && !string.IsNullOrWhiteSpace(Company.VatNumber))
Company.ValidVat = VatUtils.ValidateFormat(Company.CountryCode, Company.VatNumber) ? 1 : 0;
// flags
_validVat = Company.ValidVat == 1; // flag set if company has a valid vatNumber
_vatState = Company.ValidVat == 1 ? "the-good" : "no-vat"; // assign css class
ValidVat = Company.ValidVat == 1; // flag set if company has a valid vatNumber
VatState = Company.ValidVat == 1 ? "the-good" : "no-vat"; // assign css class
}
_editContext = new EditContext(Company);
_editContext.OnFieldChanged += HandleFieldChanged;
_editContext.OnValidationStateChanged += ValidationChanged;
CompanyContext = new EditContext(Company);
CompanyContext.OnFieldChanged += HandleFieldChanged;
CompanyContext.OnValidationStateChanged += ValidationChanged;
await SyncCompanyHistory();
Contacts = await ContactRepo.GetContacts(CompanyId);
}
private void ForceActivity()
{
_enableActivity = _enableActivity == 0 ? 1 : 0;
EnableActivity = EnableActivity == 0 ? 1 : 0;
}
private void OpenContact(ContactDto contact)
{
SelectedContact = contact;
ContactPopup.Show();
}
private async Task SaveContact(ContactDto contact)
{
Console.WriteLine(JsonSerializer.Serialize(contact));
if (string.IsNullOrWhiteSpace(contact.ContactId))
{
Console.WriteLine("create");
await ContactRepo.CreateContact(contact);
}
else
{
Console.WriteLine("update");
await ContactRepo.UpdateContact(contact);
}
Contacts = await ContactRepo.GetContacts(CompanyId);
SelectedContact = new ContactDto();
}
private async Task DeleteContact(string contactId)
{
await ContactRepo.DeleteContact(CompanyId, contactId);
Contacts = await ContactRepo.GetContacts(CompanyId);
SelectedContact = new ContactDto();
}
private async Task SyncCompanyHistory()
@ -143,39 +180,39 @@ public partial class CrmCompanyViewPage : IDisposable
private void HandleFieldChanged(object sender, FieldChangedEventArgs e)
{
_nextVisit = _lastVisit.AddDays(Company.Interval * 7);
NextVisit = LastVisit.AddDays(Company.Interval * 7);
// simple validation of VAT format
if (!VatUtils.ValidateFormat(Company.CountryCode, Company.VatNumber))
{
_formInvalid = true;
FormInvalid = true;
}
else
{
_formInvalid = !_editContext.Validate();
FormInvalid = !CompanyContext.Validate();
}
if(_vatUpdated == 0 && e.FieldIdentifier.FieldName != "Note")
_isDirty = 1;
if(VatUpdated == 0 && e.FieldIdentifier.FieldName != "Note" && e.FieldIdentifier.FieldName != "CrmNotes")
IsDirty = 1;
StateHasChanged();
}
private void ValidationChanged(object sender, ValidationStateChangedEventArgs e)
{
_formInvalid = false;
_editContext.OnFieldChanged -= HandleFieldChanged;
_editContext.OnValidationStateChanged -= ValidationChanged;
FormInvalid = false;
CompanyContext.OnFieldChanged -= HandleFieldChanged;
CompanyContext.OnValidationStateChanged -= ValidationChanged;
_editContext = new EditContext(Company);
CompanyContext = new EditContext(Company);
_formInvalid = _editContext.Validate();
FormInvalid = CompanyContext.Validate();
_editContext.OnFieldChanged += HandleFieldChanged;
_editContext.OnValidationStateChanged += ValidationChanged;
CompanyContext.OnFieldChanged += HandleFieldChanged;
CompanyContext.OnValidationStateChanged += ValidationChanged;
}
private async Task SubmitUpdate()
{
_working = true;
Working = true;
// simple format validation if CRM indicates invalid vatNumber
if (!VatUtils.ValidateFormat(Company.CountryCode, Company.VatNumber))
{
@ -185,41 +222,38 @@ public partial class CrmCompanyViewPage : IDisposable
}
Toaster.ShowInfo("Vent venligst ....");
//_hideButtons = true;
Company.LastVisit = $"{_lastVisit:yyyy-MM-dd}";
Company.NextVisit = $"{_nextVisit:yyyy-MM-dd}";
Company.LastVisit = $"{LastVisit:yyyy-MM-dd}";
Company.NextVisit = $"{NextVisit:yyyy-MM-dd}";
Company.IsHidden = 0;
// flag if backend should update ERP system
Company.UpdateErpVat = _vatUpdated;
Company.UpdateErpVat = VatUpdated;
// flag base info has changed
Company.IsDirty = _isDirty;
Company.IsDirty = IsDirty;
var success = await CompanyRepo.UpdateCompany(CompanyId, Company );
var success = await _companyRepo.UpdateCompany(CompanyId, Company );
Toaster.ShowSuccess("Opdatering er afsendt. Der går nogle minutter inden data er opdateret.");
Company = await _companyRepo.GetCompanyById(Company.CompanyId);
Company = await CompanyRepo.GetCompanyById(Company.CompanyId);
Company.ValidVat = 1;
_enableActivity = 1;
if (_virkRegInfo.States[0].State.ToLower() != "normal")
{
Company.HasFolded = 1;
}
StateHasChanged();
_working = false;
EnableActivity = 1;
Working = false;
Toaster.ClearAll();
StateHasChanged();
}
private async Task GetInfoFromAddress(VatAddress address)
{
Toaster.ShowInfo("Vent for adresse info ...");
_vInfos = await _vatService.QueryVirkRegistry(
VatInfos = await VatService.QueryVirkRegistry(
new VirkParams
{
StreetName = address.StreetName,
HouseNumber = address.HouseNumber,
ZipCode = address.ZipCode
});
if (!_vInfos.Any())
if (!VatInfos.Any())
{
Toaster.ShowWarning($"Ingen data fundet ...");
}
@ -256,65 +290,65 @@ public partial class CrmCompanyViewPage : IDisposable
private void CallVatLookupModal()
{
_vatLookupModal.Show();
VatLookupPopup.Show();
}
private void OnSelectedCompany(VirkRegInfo regInfo)
{
_validVat = regInfo.States[0].State.ToLower() == "normal";
Company.HasFolded = _validVat ? 1 : 0;
_enableActivity = _validVat ? 1 : 0;
_vatState = regInfo.States[0].State.ToLower() == "normal" ? "the-good" : "the-dead";
ValidVat = regInfo.States[0].State.ToLower() == "normal";
Company.HasFolded = ValidVat ? 1 : 0;
EnableActivity = ValidVat ? 1 : 0;
VatState = regInfo.States[0].State.ToLower() == "normal" ? "the-good" : "the-dead";
if (regInfo.SyncAll)
{
Company.VatNumber = _virkRegInfo.VatNumber;
Company.Name = _virkRegInfo.Name;
Company.Address1 = _virkRegInfo.Address;
Company.Address2 = _virkRegInfo.CoName;
Company.ZipCode = _virkRegInfo.ZipCode;
Company.City = _virkRegInfo.City;
_isDirty = 1;
Company.VatNumber = CompanyRegInfo.VatNumber;
Company.Name = CompanyRegInfo.Name;
Company.Address1 = CompanyRegInfo.Address;
Company.Address2 = CompanyRegInfo.CoName;
Company.ZipCode = CompanyRegInfo.ZipCode;
Company.City = CompanyRegInfo.City;
IsDirty = 1;
}
else
{
Company.VatNumber = _virkRegInfo.VatNumber;
_vatUpdated = 1;
Company.VatNumber = CompanyRegInfo.VatNumber;
VatUpdated = 1;
}
StateHasChanged();
}
private void SelectCompany(string vatNumber, bool syncAll)
{
_virkRegInfo = (from x in _vInfos where x.VatNumber == vatNumber select x).First();
_validVat = _virkRegInfo.States[0].State.ToLower() == "normal";
Company.HasFolded = _validVat ? 1 : 0;
_enableActivity = _validVat ? 1 : 0;
_vatState = _virkRegInfo.States[0].State.ToLower() == "normal" ? "the-good" : "the-dead";
CompanyRegInfo = (from x in VatInfos where x.VatNumber == vatNumber select x).First();
ValidVat = CompanyRegInfo.States[0].State.ToLower() == "normal";
Company.HasFolded = ValidVat ? 1 : 0;
EnableActivity = ValidVat ? 1 : 0;
VatState = CompanyRegInfo.States[0].State.ToLower() == "normal" ? "the-good" : "the-dead";
if (syncAll)
{
Company.VatNumber = _virkRegInfo.VatNumber;
Company.Name = _virkRegInfo.Name;
Company.Address1 = _virkRegInfo.Address;
Company.Address2 = _virkRegInfo.CoName;
Company.ZipCode = _virkRegInfo.ZipCode;
Company.City = _virkRegInfo.City;
_isDirty = 1;
Company.VatNumber = CompanyRegInfo.VatNumber;
Company.Name = CompanyRegInfo.Name;
Company.Address1 = CompanyRegInfo.Address;
Company.Address2 = CompanyRegInfo.CoName;
Company.ZipCode = CompanyRegInfo.ZipCode;
Company.City = CompanyRegInfo.City;
IsDirty = 1;
}
else
{
Company.VatNumber = _virkRegInfo.VatNumber;
_vatUpdated = 1;
Company.VatNumber = CompanyRegInfo.VatNumber;
VatUpdated = 1;
}
// empty list
_vInfos = new List<VirkRegInfo>();
VatInfos = new List<VirkRegInfo>();
StateHasChanged();
}
public void Dispose()
{
_interceptor.DisposeEvent();
_editContext.OnFieldChanged -= HandleFieldChanged;
_editContext.OnValidationStateChanged -= ValidationChanged;
Interceptor.DisposeEvent();
CompanyContext.OnFieldChanged -= HandleFieldChanged;
CompanyContext.OnValidationStateChanged -= ValidationChanged;
}
}

View file

@ -61,11 +61,13 @@ builder.Services.AddScoped<ICrmReportHttpRepository, CrmReportHttpRepository>();
builder.Services.AddScoped<ICrmTaskItemHttpRepository, CrmTaskItemHttpRepository>();
builder.Services.AddScoped<ICrmHistoryHttpRepository, CrmHistoryHttpRepository>();
builder.Services.AddScoped<ICrmWorkplaceHttpRepository, CrmWorkplaceHttpRepository>();
builder.Services.AddScoped<ICrmContactHttpRepository, CrmContactHttpRepository>();
builder.Services.AddScoped<IOfficeUserHttpRepository, OfficeUserHttpRepository>();
builder.Services.AddScoped<IOfficeReportHttpRepository, OfficeReportHttpRepository>();
builder.Services.AddScoped<IOfficeCustomerHttpRepository, OfficeCustomerHttpRepository>();
builder.Services.AddScoped<IWarehouseHttpRepository, WarehouseHttpRepository>();
builder.Services.AddScoped<ISendMailService, SendMailService>();

View file

@ -0,0 +1,76 @@
@*
// 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 Wonky.Client.Helpers
@using System.Text.Json
<div class="modal" tabindex="-1" role="dialog" style="display:@_modalDisplay">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">@CompanyName</h5>
<button type="button" class="btn-close" @onclick="Hide" data-bs-dismiss="modal" aria-label="Luk"></button>
</div>
<div class="modal-body">
<EditForm Model="Contact" OnValidSubmit="SubmitContact">
<DataAnnotationsValidator/>
<InputText type="hidden" @bind-Value="@Contact.CompanyId"/>
<InputText type="hidden" @bind-Value="@Contact.ContactId"/>
<div class="row">
<div class="col-sm-6">
<label for="firstName">Fornavn</label>
<InputText id="firstName" class="form-control" @bind-Value="Contact.FirstName"/>
<ValidationMessage For="@(() => Contact.FirstName)"></ValidationMessage>
</div>
<div class="col-sm-6">
<label for="lastName">Efternavn</label>
<InputText id="lastName" class="form-control" @bind-Value="Contact.LastName"/>
<ValidationMessage For="@(() => Contact.LastName)"></ValidationMessage>
</div>
<div class="col-sm-6">
<label for="jobTitle">Job Titel</label>
<InputText id="jobTitle" class="form-control" @bind-Value="Contact.JobTitle"/>
<ValidationMessage For="@(() => Contact.JobTitle)"></ValidationMessage>
</div>
<div class="col-sm-6">
<label for="phone">Direkte nr.</label>
<InputText id="phone" class="form-control" @bind-Value="Contact.PhoneDirect"/>
<ValidationMessage For="@(() => Contact.PhoneDirect)"></ValidationMessage>
</div>
<div class="col-sm-6">
@if (string.IsNullOrWhiteSpace(Contact.ContactId))
{
<button type="button" class="btn btn-danger" disabled>Slet</button>
}
else
{
<button type="button" class="btn btn-danger" @onclick="DeleteContact">Slet</button>
}
</div>
<div class="col-sm-6 text-end">
<button type="submit" class="btn btn-primary">Gem</button>
</div>
</div>
</EditForm>
</div>
</div>
</div>
</div>
@if (_showBackdrop)
{
<div class="modal-backdrop fade show"></div>
}

View file

@ -0,0 +1,97 @@
// 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.Text.Json;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Forms;
using Wonky.Client.HttpInterceptors;
using Wonky.Client.HttpInterfaces;
using Wonky.Client.HttpRepository;
using Wonky.Client.Models;
using Wonky.Client.Services;
using Wonky.Entity.DTO;
using Wonky.Entity.Requests;
using Wonky.Entity.Views;
namespace Wonky.Client.Shared;
public partial class ContactModal : IDisposable
{
[Parameter] public ContactDto ParamContact { get; set; } = new();
[Parameter] public string CompanyName { get; set; } = "";
[Parameter] public ICrmContactHttpRepository ContactRepo { get; set; }
[Parameter] public HttpInterceptorService Interceptor { get; set; }
[Parameter] public EventCallback<ContactDto> OnSaveClicked { get; set; }
[Parameter] public EventCallback<string> OnDeleteClicked { get; set; }
private ContactDto Contact { get; set; } = new();
private string _modalDisplay = "";
private bool _showBackdrop;
private bool DisableDelete { get; set; }
private bool FormInvalid { get; set; }
protected override void OnParametersSet()
{
Contact = new ContactDto
{
CompanyId = ParamContact.CompanyId,
ContactId = ParamContact.ContactId,
FirstName = ParamContact.FirstName,
LastName = ParamContact.LastName,
JobTitle = ParamContact.JobTitle,
PhoneDirect = ParamContact.PhoneDirect
};
if (string.IsNullOrWhiteSpace(Contact.ContactId))
DisableDelete = true;
}
protected override void OnInitialized()
{
Interceptor.RegisterEvent();
Interceptor.RegisterBeforeSendEvent();
}
private void DeleteContact()
{
OnDeleteClicked.InvokeAsync(Contact.ContactId);
Hide();
}
private void SubmitContact()
{
OnSaveClicked.InvokeAsync(Contact);
Hide();
}
public void Show()
{
_modalDisplay = "block;";
_showBackdrop = true;
StateHasChanged();
}
private void Hide()
{
_modalDisplay = "none;";
_showBackdrop = false;
Contact = new ContactDto();
StateHasChanged();
}
public void Dispose()
{
Interceptor.DisposeEvent();
}
}

View file

@ -11,10 +11,10 @@
<PackageReference Include="Blazored.LocalStorage" Version="4.2.0" />
<PackageReference Include="Blazored.Toast" Version="3.2.2" />
<PackageReference Include="Microsoft.AspNetCore.Authentication" Version="2.2.0" />
<PackageReference Include="Microsoft.AspNetCore.Authorization" Version="6.0.10" />
<PackageReference Include="Microsoft.AspNetCore.Components.Authorization" Version="6.0.10" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="6.0.10" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="6.0.10" PrivateAssets="all" />
<PackageReference Include="Microsoft.AspNetCore.Authorization" Version="6.0.11" />
<PackageReference Include="Microsoft.AspNetCore.Components.Authorization" Version="6.0.11" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="6.0.11" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="6.0.11" PrivateAssets="all" />
<PackageReference Include="Microsoft.AspNetCore.WebUtilities" Version="2.2.0" />
<PackageReference Include="Microsoft.Extensions.Http" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="6.0.0" />

View file

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

View file

@ -29,11 +29,15 @@ public class CompanyDto
public string Name { get; set; } = "";
/// <summary>
/// Note
/// Alert
/// </summary>
[MaxLength(100, ErrorMessage = "Du kan højst bruge 100 tegn")]
public string Note { get; set; } = "";
/// <summary>
/// Crm note
/// </summary>
public string CrmNotes { get; set; } = "";
/// <summary>
/// Postal code
/// </summary>
[Required(ErrorMessage = "Postnummer skal udfyldes")]

View file

@ -4,25 +4,25 @@ namespace Wonky.Entity.DTO;
public class ContactDto
{
[Required(ErrorMessage = "CompanyId")]
[MaxLength(128, ErrorMessage = "CompanyId mangler")]
public string CompanyId { get; set; } = "";
public string ContactId { get; set; } = "";
[Required(ErrorMessage = "Fornavn skal udfyldes.")]
[MaxLength(30, ErrorMessage = "Du kan højst bruge 30 tegn")]
public string FirstName { get; set; } = "";
[MaxLength(50, ErrorMessage = "Du kan højst bruge 50 tegn.")]
public string JobTitle { get; set; } = "";
[MaxLength(30, ErrorMessage = "Du kan højst bruge 30 tegn.")]
public string LastName { get; set; } = "";
[MaxLength(50, ErrorMessage = "Du kan højst bruge 50 tegn.")]
public string JobTitle { get; set; } = "";
[MaxLength(80, ErrorMessage = "Du kan højst bruge 80 tegn.")]
public string Email { get; set; } = "";
[MaxLength(30, ErrorMessage = "Du kan højst bruge 30 tegn.")]
public string Phone { get; set; } = "";
public string PhoneDirect { get; set; } = "";
[MaxLength(30, ErrorMessage = "Du kan højst bruge 30 tegn.")]
public string Mobile { get; set; } = "";