diff --git a/.idea/.idea.Wonky.Client/.idea/.gitignore b/.idea/.idea.Wonky.Client/.idea/.gitignore
new file mode 100644
index 00000000..00d2f20c
--- /dev/null
+++ b/.idea/.idea.Wonky.Client/.idea/.gitignore
@@ -0,0 +1,13 @@
+# Default ignored files
+/shelf/
+/workspace.xml
+# Rider ignored files
+/modules.xml
+/projectSettingsUpdater.xml
+/.idea.Wonky.Client.iml
+/contentModel.xml
+# Editor-based HTTP Client requests
+/httpRequests/
+# Datasource local storage ignored files
+/dataSources/
+/dataSources.local.xml
diff --git a/.idea/.idea.Wonky.Client/.idea/encodings.xml b/.idea/.idea.Wonky.Client/.idea/encodings.xml
new file mode 100644
index 00000000..df87cf95
--- /dev/null
+++ b/.idea/.idea.Wonky.Client/.idea/encodings.xml
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/.idea/.idea.Wonky.Client/.idea/indexLayout.xml b/.idea/.idea.Wonky.Client/.idea/indexLayout.xml
new file mode 100644
index 00000000..7b08163c
--- /dev/null
+++ b/.idea/.idea.Wonky.Client/.idea/indexLayout.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/.idea.Wonky.Client/.idea/misc.xml b/.idea/.idea.Wonky.Client/.idea/misc.xml
new file mode 100644
index 00000000..1d8c84d0
--- /dev/null
+++ b/.idea/.idea.Wonky.Client/.idea/misc.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/.idea.Wonky.Client/.idea/vcs.xml b/.idea/.idea.Wonky.Client/.idea/vcs.xml
new file mode 100644
index 00000000..94a25f7f
--- /dev/null
+++ b/.idea/.idea.Wonky.Client/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Wonky.Client.sln b/Wonky.Client.sln
new file mode 100644
index 00000000..5bce659c
--- /dev/null
+++ b/Wonky.Client.sln
@@ -0,0 +1,22 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30114.105
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Wonky.Client", "Wonky.Client\Wonky.Client.csproj", "{A001767F-6CA1-428E-938A-EA491A778D3E}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {A001767F-6CA1-428E-938A-EA491A778D3E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {A001767F-6CA1-428E-938A-EA491A778D3E}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {A001767F-6CA1-428E-938A-EA491A778D3E}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {A001767F-6CA1-428E-938A-EA491A778D3E}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+EndGlobal
diff --git a/Wonky.Client/App.razor b/Wonky.Client/App.razor
new file mode 100644
index 00000000..a70fb891
--- /dev/null
+++ b/Wonky.Client/App.razor
@@ -0,0 +1,35 @@
+@using Wonky.Client.Shared
+@*
+// 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]
+//
+*@
+
+
+
+
+
+
+ Checker autorisation ...
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Wonky.Client/AppId.cs b/Wonky.Client/AppId.cs
new file mode 100644
index 00000000..91b972b6
--- /dev/null
+++ b/Wonky.Client/AppId.cs
@@ -0,0 +1,9 @@
+namespace Wonky.Client;
+
+public class AppId
+{
+ public string Version { get; set; } = "0.2.1";
+ public string Name { get; set; } = "Inno Client";
+
+ public bool IsBeta { get; set; } = false;
+}
\ No newline at end of file
diff --git a/Wonky.Client/AuthProviders/AuthStateProvider.cs b/Wonky.Client/AuthProviders/AuthStateProvider.cs
new file mode 100644
index 00000000..2ef46633
--- /dev/null
+++ b/Wonky.Client/AuthProviders/AuthStateProvider.cs
@@ -0,0 +1,125 @@
+// 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.Net.Http.Headers;
+using System.Security.Claims;
+using Blazored.LocalStorage;
+using Microsoft.AspNetCore.Components.Authorization;
+using Wonky.Entity.DTO;
+
+namespace Wonky.Client.AuthProviders
+{
+ public class AuthStateProvider : AuthenticationStateProvider
+ {
+ private readonly HttpClient _client;
+ private readonly ILocalStorageService _storage;
+ private readonly AuthenticationState _anonymous;
+
+ public AuthStateProvider(HttpClient client, ILocalStorageService storage)
+ {
+ _client = client;
+ _storage = storage;
+ _anonymous = new AuthenticationState(new ClaimsPrincipal(new ClaimsIdentity()));
+ }
+
+ public override async Task GetAuthenticationStateAsync()
+ {
+ // fetch token from localStorage
+ var token = await _storage.GetItemAsync("_tx");
+
+ if (string.IsNullOrEmpty(token))
+ // return anonymous if empty
+ return _anonymous;
+
+ // create an authorized user
+ var userInfo = await _storage.GetItemAsync("_ux");
+ if (userInfo == null)
+ return _anonymous;
+
+ // set client authorization header
+ _client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("bearer", token);
+
+ var exp = await _storage.GetItemAsync("_ex");
+
+ var roles = ExtractRoles(userInfo);
+ var claims = new List
+ {
+ new(ClaimTypes.Name, userInfo.FullName),
+ new(ClaimTypes.Email, userInfo.Email),
+ new(ClaimTypes.MobilePhone, userInfo.PhoneNumber),
+ new(ClaimTypes.Expiration, exp)
+ };
+ claims.AddRange(roles.Select(role => new Claim(ClaimTypes.Role, role)));
+
+ // return the authState for the user
+ return new AuthenticationState(
+ new ClaimsPrincipal(
+ new ClaimsIdentity(claims, "token")));
+ }
+
+ public async void NotifyUserAuthenticationAsync(string token)
+ {
+ if (string.IsNullOrEmpty(token))
+ // do nothing
+ return;
+
+ // set client authorization header
+ _client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("bearer", token);
+
+ // create an authorized user
+ var userInfo = await _storage.GetItemAsync("_ux");
+ var exp = await _storage.GetItemAsync("_ex");
+ var roles = ExtractRoles(userInfo);
+ var claims = new List
+ {
+ new(ClaimTypes.Name, userInfo.FullName),
+ new(ClaimTypes.Email, userInfo.Email),
+ new(ClaimTypes.MobilePhone, userInfo.PhoneNumber),
+ new(ClaimTypes.Expiration, exp)
+ };
+ claims.AddRange(roles.Select(role => new Claim(ClaimTypes.Role, role)));
+ // create authState
+ var authState = Task.FromResult(
+ new AuthenticationState(
+ new ClaimsPrincipal(
+ new ClaimsIdentity(claims, "token"))));
+
+ // send authState to notifier
+ NotifyAuthenticationStateChanged(authState);
+ }
+ public void NotifyUserLogout()
+ {
+ var authState = Task.FromResult(_anonymous);
+ NotifyAuthenticationStateChanged(authState);
+ }
+
+ private static IEnumerable ExtractRoles(UserInfoDto userInfo)
+ {
+ var roles = new List();
+ if (userInfo.IsAdmin)
+ roles.Add("Admin");
+ if (userInfo.IsAdviser)
+ roles.Add("Adviser");
+ if (userInfo.IsSupervisor)
+ roles.Add("Supervisor");
+ if(userInfo.IsEDoc)
+ roles.Add("EDoc");
+ if (userInfo.IsEShop)
+ roles.Add("EShop");
+ return roles;
+ }
+ }
+}
+
diff --git a/Wonky.Client/Components/AppVersion.razor b/Wonky.Client/Components/AppVersion.razor
new file mode 100644
index 00000000..1e9a389c
--- /dev/null
+++ b/Wonky.Client/Components/AppVersion.razor
@@ -0,0 +1,15 @@
+@*// 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 Affero GNU 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
+// Affero GNU General Public License for more details.
+//
+// You should have received a copy of the Affero GNU General Public License
+// along with this program. If not, see [https://www.gnu.org/licenses/agpl-3.0.en.html]
+//*@
+@app.Name@app.Version@if(app.IsBeta){-beta}
\ No newline at end of file
diff --git a/Wonky.Client/Components/AppVersion.razor.cs b/Wonky.Client/Components/AppVersion.razor.cs
new file mode 100644
index 00000000..9ded2d11
--- /dev/null
+++ b/Wonky.Client/Components/AppVersion.razor.cs
@@ -0,0 +1,6 @@
+namespace Wonky.Client.Components;
+
+public partial class AppVersion
+{
+ private AppId app { get; set; } = new();
+}
\ No newline at end of file
diff --git a/Wonky.Client/Components/AuthLinks.razor b/Wonky.Client/Components/AuthLinks.razor
new file mode 100644
index 00000000..2925ec44
--- /dev/null
+++ b/Wonky.Client/Components/AuthLinks.razor
@@ -0,0 +1,27 @@
+@*
+// 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.Security.Claims
+
+
+ @context.User.Identity.Name
+ Log af
+
+
+ Log ind
+
+
\ No newline at end of file
diff --git a/Wonky.Client/Components/CompanyListHeader.razor b/Wonky.Client/Components/CompanyListHeader.razor
new file mode 100644
index 00000000..a6483b8c
--- /dev/null
+++ b/Wonky.Client/Components/CompanyListHeader.razor
@@ -0,0 +1,25 @@
+@*
+// 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]
+//
+*@
+
+
+
Status
+
Navn
+
Konto
+
Bynavn
+
+
+
diff --git a/Wonky.Client/Components/CompanySearchField.razor b/Wonky.Client/Components/CompanySearchField.razor
new file mode 100644
index 00000000..758359d2
--- /dev/null
+++ b/Wonky.Client/Components/CompanySearchField.razor
@@ -0,0 +1,25 @@
+@*
+// 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]
+//
+*@
+
+
+
+
diff --git a/Wonky.Client/Components/CompanySearchField.razor.cs b/Wonky.Client/Components/CompanySearchField.razor.cs
new file mode 100644
index 00000000..70d1da75
--- /dev/null
+++ b/Wonky.Client/Components/CompanySearchField.razor.cs
@@ -0,0 +1,33 @@
+
+// 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 Microsoft.AspNetCore.Components;
+
+namespace Wonky.Client.Components;
+
+public partial class CompanySearchField
+{
+ [Parameter]
+ public EventCallback OnFilterChanged { get; set; }
+
+ private async Task ApplyFilter(ChangeEventArgs eventArgs)
+ {
+ if (eventArgs?.Value?.ToString() == "name")
+ return;
+ await OnFilterChanged.InvokeAsync(eventArgs?.Value?.ToString());
+ }
+}
\ No newline at end of file
diff --git a/Wonky.Client/Components/CompanySearchField.razor.css b/Wonky.Client/Components/CompanySearchField.razor.css
new file mode 100644
index 00000000..4d7d555a
--- /dev/null
+++ b/Wonky.Client/Components/CompanySearchField.razor.css
@@ -0,0 +1,3 @@
+.search-field {
+ margin-bottom: 10px;
+}
\ No newline at end of file
diff --git a/Wonky.Client/Components/CompanySort.razor b/Wonky.Client/Components/CompanySort.razor
new file mode 100644
index 00000000..95f3ff93
--- /dev/null
+++ b/Wonky.Client/Components/CompanySort.razor
@@ -0,0 +1,25 @@
+@*
+// 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]
+//
+*@
+
+
+
+
\ No newline at end of file
diff --git a/Wonky.Client/Components/CompanySort.razor.cs b/Wonky.Client/Components/CompanySort.razor.cs
new file mode 100644
index 00000000..3a03a89b
--- /dev/null
+++ b/Wonky.Client/Components/CompanySort.razor.cs
@@ -0,0 +1,35 @@
+
+// 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 Microsoft.AspNetCore.Components;
+
+namespace Wonky.Client.Components
+{
+ public partial class CompanySort
+ {
+ [Parameter]
+ public EventCallback OnSortChanged { get; set; }
+
+ private async Task ApplySort(ChangeEventArgs eventArgs)
+ {
+ if (eventArgs?.Value?.ToString() == "-1")
+ return;
+ await OnSortChanged.InvokeAsync(eventArgs?.Value?.ToString());
+ }
+ }
+}
+
diff --git a/Wonky.Client/Components/CompanyTable.razor b/Wonky.Client/Components/CompanyTable.razor
new file mode 100644
index 00000000..be687780
--- /dev/null
+++ b/Wonky.Client/Components/CompanyTable.razor
@@ -0,0 +1,69 @@
+@*
+// 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]
+//
+*@
+@if (Companies.Any())
+{
+
+ @foreach (var company in Companies)
+ {
+
+
+
@company.Name
+
@company.Account
+
@company.City
+
+
+ }
+ @*
+
+
+
+
Status
+
Navn
+
Konto
+
Bynavn
+
+
+
+
+ @foreach (var company in Companies)
+ {
+
+
+
+
+
+ @company.Name
+
+
+ @company.Account
+
+
+ @company.City
+
+
+
+
+
+ }
+
+
+*@
+}
+else
+{
+
Henter data...
+}
\ No newline at end of file
diff --git a/Wonky.Client/Components/CompanyTable.razor.cs b/Wonky.Client/Components/CompanyTable.razor.cs
new file mode 100644
index 00000000..d739862a
--- /dev/null
+++ b/Wonky.Client/Components/CompanyTable.razor.cs
@@ -0,0 +1,44 @@
+
+// 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 Microsoft.AspNetCore.Components;
+using Wonky.Client.Shared;
+using Wonky.Entity.DTO;
+
+namespace Wonky.Client.Components
+{
+ public partial class CompanyTable
+ {
+ [Parameter] public List Companies { get; set; } = new();
+ [Parameter] public EventCallback OnDelete { get; set; }
+
+ private Confirmation _confirmation = new ();
+ private string _companyIdToDelete = string.Empty;
+
+ private void CallConfirmationModal(string companyId)
+ {
+ _companyIdToDelete = companyId;
+ _confirmation.Show();
+ }
+
+ private async Task DeleteProduct()
+ {
+ _confirmation.Hide();
+ await OnDelete.InvokeAsync(_companyIdToDelete);
+ }
+ }
+}
diff --git a/Wonky.Client/Components/CounterPrint.razor b/Wonky.Client/Components/CounterPrint.razor
new file mode 100644
index 00000000..b1ce1f12
--- /dev/null
+++ b/Wonky.Client/Components/CounterPrint.razor
@@ -0,0 +1,43 @@
+@using Microsoft.Extensions.Logging
+@implements IDisposable
+
+
@Title
+
+
Current count: @CurrentCount
+
+@code {
+
+ [Parameter] public string Title { get; set; }
+
+ [Parameter] public int CurrentCount { get; set; }
+
+ [Inject] public ILogger Logger { get; set; }
+
+ protected override void OnInitialized()
+ {
+ Logger.Log(LogLevel.Information,$"OnInitialized => Title: {Title}, CurrentCount: {CurrentCount}");
+ }
+
+ protected override void OnParametersSet()
+ {
+ Logger.Log(LogLevel.Information,$"OnParameterSet => Title: {Title}, CurrentCount: {CurrentCount}");
+ }
+
+ protected override void OnAfterRender(bool firstRender)
+ {
+ if (firstRender)
+ {
+ Logger.Log(LogLevel.Information,"This is the first render of the component");
+ }
+ }
+
+ protected override bool ShouldRender()
+ {
+ return true;
+ }
+
+ public void Dispose()
+ {
+ Logger.Log(LogLevel.Information,"Component removed from the parnet's render tree.");
+ }
+}
diff --git a/Wonky.Client/Components/Home.razor b/Wonky.Client/Components/Home.razor
new file mode 100644
index 00000000..958554ca
--- /dev/null
+++ b/Wonky.Client/Components/Home.razor
@@ -0,0 +1,19 @@
+@*
+// 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]
+//
+*@
+
+Forside
+
@Title
\ No newline at end of file
diff --git a/Wonky.Client/Components/Home.razor.cs b/Wonky.Client/Components/Home.razor.cs
new file mode 100644
index 00000000..8d0d1857
--- /dev/null
+++ b/Wonky.Client/Components/Home.razor.cs
@@ -0,0 +1,27 @@
+
+// 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 Microsoft.AspNetCore.Components;
+
+namespace Wonky.Client.Components
+{
+ public partial class Home
+ {
+ [Parameter] public string Title { get; set; } = "Hej";
+
+ [Parameter] public RenderFragment? LoginContent { get; set; }
+ }
+}
diff --git a/Wonky.Client/Components/PageSizeDropDown.razor b/Wonky.Client/Components/PageSizeDropDown.razor
new file mode 100644
index 00000000..8b46ec06
--- /dev/null
+++ b/Wonky.Client/Components/PageSizeDropDown.razor
@@ -0,0 +1,26 @@
+@*
+// 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]
+//
+*@
+
+
+
+
\ No newline at end of file
diff --git a/Wonky.Client/Components/PageSizeDropDown.razor.cs b/Wonky.Client/Components/PageSizeDropDown.razor.cs
new file mode 100644
index 00000000..21e47bd0
--- /dev/null
+++ b/Wonky.Client/Components/PageSizeDropDown.razor.cs
@@ -0,0 +1,32 @@
+
+// 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 Microsoft.AspNetCore.Components;
+
+namespace Wonky.Client.Components
+{
+ public partial class PageSizeDropDown
+ {
+ [Parameter]
+ public EventCallback SelectedPageSize { get; set; }
+
+ private async Task OnPageSizeChange(ChangeEventArgs eventArgs)
+ {
+ await SelectedPageSize.InvokeAsync(int.Parse(eventArgs.Value?.ToString()!));
+ }
+ }
+}
diff --git a/Wonky.Client/Components/PageSizeDropDown.razor.css b/Wonky.Client/Components/PageSizeDropDown.razor.css
new file mode 100644
index 00000000..afa708ab
--- /dev/null
+++ b/Wonky.Client/Components/PageSizeDropDown.razor.css
@@ -0,0 +1,4 @@
+.form-control {
+ width: auto;
+ float: right;
+}
\ No newline at end of file
diff --git a/Wonky.Client/Components/Pagination.razor b/Wonky.Client/Components/Pagination.razor
new file mode 100644
index 00000000..a91e3329
--- /dev/null
+++ b/Wonky.Client/Components/Pagination.razor
@@ -0,0 +1,29 @@
+@*
+// 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]
+//
+*@
+
+
\ No newline at end of file
diff --git a/Wonky.Client/Components/Pagination.razor.cs b/Wonky.Client/Components/Pagination.razor.cs
new file mode 100644
index 00000000..e8976382
--- /dev/null
+++ b/Wonky.Client/Components/Pagination.razor.cs
@@ -0,0 +1,63 @@
+
+// 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 Microsoft.AspNetCore.Components;
+using Wonky.Client.Features;
+using Wonky.Entity.Requests;
+
+namespace Wonky.Client.Components
+{
+ public partial class Pagination
+ {
+ [Parameter] public MetaData MetaData { get; set; } = new();
+ [Parameter] public int Spread { get; set; }
+ [Parameter] public EventCallback SelectedPage { get; set; }
+
+ private List? _links;
+
+ protected override void OnParametersSet()
+ {
+ CreatePaginationLinks();
+ }
+
+ private void CreatePaginationLinks()
+ {
+ _links = new List
+ {
+ new(MetaData.CurrentPage - 1, MetaData.HasPrevious, "Forrige")
+ };
+
+ for (var i = 1; i <= MetaData.TotalPages; i++)
+ {
+ if (i >= MetaData.CurrentPage - Spread && i <= MetaData.CurrentPage + Spread)
+ {
+ _links.Add(new PagingLink(i, true, i.ToString()) {Active = MetaData.CurrentPage == i});
+ }
+ }
+
+ _links.Add(new PagingLink(MetaData.CurrentPage + 1, MetaData.HasNext, "Næste"));
+ }
+
+ private async Task OnSelectedPage(PagingLink link)
+ {
+ if (link.Page == MetaData.CurrentPage || !link.Enabled)
+ return;
+ MetaData.CurrentPage = link.Page;
+ await SelectedPage.InvokeAsync(link.Page);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Wonky.Client/Components/PoLineCreate.razor b/Wonky.Client/Components/PoLineCreate.razor
new file mode 100644
index 00000000..231673e8
--- /dev/null
+++ b/Wonky.Client/Components/PoLineCreate.razor
@@ -0,0 +1,69 @@
+@using Microsoft.AspNetCore.Components
+@*
+// 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]
+//
+*@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Wonky.Client/Components/PoLineCreate.razor.cs b/Wonky.Client/Components/PoLineCreate.razor.cs
new file mode 100644
index 00000000..239db777
--- /dev/null
+++ b/Wonky.Client/Components/PoLineCreate.razor.cs
@@ -0,0 +1,41 @@
+// 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 Microsoft.AspNetCore.Components;
+using Microsoft.AspNetCore.Components.Forms;
+using Wonky.Client.Models;
+using Wonky.Entity.DTO;
+
+namespace Wonky.Client.Components;
+
+public partial class PoLineCreate
+{
+ private List Lines = new();
+ private CrmActivityLine _orderLine = new();
+ private EditContext _editContext;
+
+
+ [Parameter] public PurchaseOrder PurchaseOrder { get; set; }
+
+ protected override async Task OnInitializedAsync()
+ {
+
+ }
+
+ private void CreateLine()
+ {
+ Lines.Add(_orderLine);
+ }
+}
\ No newline at end of file
diff --git a/Wonky.Client/Components/PurchaseOrderLinesTable.razor b/Wonky.Client/Components/PurchaseOrderLinesTable.razor
new file mode 100644
index 00000000..9e47acb2
--- /dev/null
+++ b/Wonky.Client/Components/PurchaseOrderLinesTable.razor
@@ -0,0 +1,66 @@
+@*
+// 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]
+//
+*@
+
+
+
+ Varenr.
+
+
+ Tekst
+
+
+ Antal
+
+
+ Stk.pris
+
+
+ Rabat
+
+
+ Linjesum
+
+
+@if (Lines.Any())
+{
+ foreach (var line in Lines)
+ {
+
+ }
+}
\ No newline at end of file
diff --git a/Wonky.Client/Components/PurchaseOrderLinesTable.razor.cs b/Wonky.Client/Components/PurchaseOrderLinesTable.razor.cs
new file mode 100644
index 00000000..0c4b5e11
--- /dev/null
+++ b/Wonky.Client/Components/PurchaseOrderLinesTable.razor.cs
@@ -0,0 +1,25 @@
+// 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 Microsoft.AspNetCore.Components;
+using Wonky.Entity.DTO;
+
+namespace Wonky.Client.Components;
+
+public partial class PurchaseOrderLinesTable
+{
+ [Parameter] public List Lines { get; set; } = new();
+
+}
\ No newline at end of file
diff --git a/Wonky.Client/Components/PurchaseOrderLinesTable.razor.css b/Wonky.Client/Components/PurchaseOrderLinesTable.razor.css
new file mode 100644
index 00000000..e69de29b
diff --git a/Wonky.Client/Components/PurchaseOrderTable.razor b/Wonky.Client/Components/PurchaseOrderTable.razor
new file mode 100644
index 00000000..463e4902
--- /dev/null
+++ b/Wonky.Client/Components/PurchaseOrderTable.razor
@@ -0,0 +1,51 @@
+@*
+// Copyright (C) 2022 FCS Frede's Computer Services.
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as
+// published by the Free Software Foundation, either version 3 of the
+// License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see [https://www.gnu.org/licenses/agpl-3.0.en.html]
+//
+*@
+
+
+
+ Id
+
+
+ Konto
+
+
Firma
+
+
+
+
+
+@if (PurchaseOrders.Any())
+{
+ @foreach (var order in PurchaseOrders)
+ {
+
+
+ @order.ActivityId
+
+
+ @order.Account
+
+
+ @order.Name
+
+
+
+
+
+
+ }
+}
\ No newline at end of file
diff --git a/Wonky.Client/Components/PurchaseOrderTable.razor.cs b/Wonky.Client/Components/PurchaseOrderTable.razor.cs
new file mode 100644
index 00000000..2d2813b6
--- /dev/null
+++ b/Wonky.Client/Components/PurchaseOrderTable.razor.cs
@@ -0,0 +1,25 @@
+// 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 Microsoft.AspNetCore.Components;
+using Wonky.Client.Models;
+
+namespace Wonky.Client.Components;
+
+public partial class PurchaseOrderTable
+{
+ [Parameter] public List PurchaseOrders { get; set; } = new();
+
+}
\ No newline at end of file
diff --git a/Wonky.Client/Components/PurchaseOrderTable.razor.css b/Wonky.Client/Components/PurchaseOrderTable.razor.css
new file mode 100644
index 00000000..46800d16
--- /dev/null
+++ b/Wonky.Client/Components/PurchaseOrderTable.razor.css
@@ -0,0 +1,2 @@
+body {
+}
diff --git a/Wonky.Client/Components/RegInfoCompany.razor b/Wonky.Client/Components/RegInfoCompany.razor
new file mode 100644
index 00000000..e50cb71b
--- /dev/null
+++ b/Wonky.Client/Components/RegInfoCompany.razor
@@ -0,0 +1,37 @@
+@*
+// 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.Encodings.Web
+
+
diff --git a/Wonky.Client/Components/RegInfoCompany.razor.cs b/Wonky.Client/Components/RegInfoCompany.razor.cs
new file mode 100644
index 00000000..1b1ecdda
--- /dev/null
+++ b/Wonky.Client/Components/RegInfoCompany.razor.cs
@@ -0,0 +1,47 @@
+// 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 Microsoft.AspNetCore.Components;
+using Wonky.Client.Services;
+using Wonky.Entity.Models;
+using Wonky.Entity.Requests;
+
+namespace Wonky.Client.Components;
+
+public partial class RegInfoCompany
+{
+ [Inject] public VirkRegistryService VirkRegistryService { get; set; }
+
+ [Parameter] public string VatNumber { get; set; } = "";
+
+ private VirkRegInfo VirkRegInfo { get; set; } = new();
+ private bool HideMe = true;
+ private bool CvrInvalid => string.IsNullOrEmpty(VatNumber);
+ private VirkParams _virkParams = new();
+ private string CurrentState = "UKENDT";
+ private async Task GetCvrData()
+ {
+ _virkParams.VatNumber = VatNumber;
+ if (string.IsNullOrWhiteSpace(VirkRegInfo.VatNumber))
+ {
+ var result = await VirkRegistryService.QueryVirkRegistry(_virkParams);
+ if (result.Any())
+ {
+ CurrentState = VirkRegInfo.States[^1].State;
+ }
+ }
+ HideMe = !HideMe;
+ }
+}
\ No newline at end of file
diff --git a/Wonky.Client/Components/RegLookupAddress.razor b/Wonky.Client/Components/RegLookupAddress.razor
new file mode 100644
index 00000000..5d6cf6aa
--- /dev/null
+++ b/Wonky.Client/Components/RegLookupAddress.razor
@@ -0,0 +1,111 @@
+@*
+// 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]
+//
+*@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+@if (_adrInfos.Any())
+{
+
+ @foreach (var info in _adrInfos)
+ {
+ @if(info.Name == "INGEN DATA")
+ {
+
+
@info.Name
+
+ }
+ else
+ {
+
+
+
@info.Name
+
+
+
+
+ Reg.nr.
+
+
+ @info.VatNumber
+
+
+
+
+ Conavn
+
+
+ @info.CoName
+
+
+
+
+ Adresse
+
+
+ @info.Address
+
+
+
+
+ Postnr
+
+
+ @info.ZipCode
+
+
+
+
+ Bynavn
+
+
+ @info.City
+
+
+
+
+ }
+ }
+
+}
+else
+{
+
+ Henter data...
+
+}
+
diff --git a/Wonky.Client/Components/RegLookupAddress.razor.cs b/Wonky.Client/Components/RegLookupAddress.razor.cs
new file mode 100644
index 00000000..652cac55
--- /dev/null
+++ b/Wonky.Client/Components/RegLookupAddress.razor.cs
@@ -0,0 +1,92 @@
+// 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.ComponentModel.DataAnnotations;
+using Microsoft.AspNetCore.Components;
+using Microsoft.AspNetCore.Components.Forms;
+using Wonky.Client.HttpInterceptors;
+using Wonky.Client.Services;
+using Wonky.Entity.Models;
+using Wonky.Entity.Requests;
+
+namespace Wonky.Client.Components;
+
+public partial class RegLookupAddress : IDisposable
+{
+ private Query AdrQuery { get; set; } = new();
+ private EditContext AdrContext { get; set; }
+ private List _adrInfos { get; set; } = new();
+ private bool ShowAdrResult;
+ private bool AdrInvalid = true;
+ [Inject] public VirkRegistryService AdrQueryService { get; set; }
+ [Inject] public HttpInterceptorService Interceptor { get; set; }
+
+ protected override void OnInitialized()
+ {
+ ShowAdrResult = false;
+ AdrContext = new EditContext(AdrQuery);
+ AdrContext.OnFieldChanged += HandleAdrChanged;
+ AdrContext.OnValidationStateChanged += AdrValidationChanged;
+ Interceptor.RegisterEvent();
+ Interceptor.RegisterBeforeSendEvent();
+ }
+
+ private async Task FetchAddressData()
+ {
+ ShowAdrResult = true;
+
+ var query = new VirkParams
+ {
+ VatNumber = "",
+ HouseNumber = AdrQuery.HouseNumber,
+ StreetName = AdrQuery.StreetName,
+ ZipCode = AdrQuery.ZipCode
+ };
+ _adrInfos = await AdrQueryService.QueryVirkRegistry(query).ConfigureAwait(true);
+ }
+ private void HandleAdrChanged(object sender, FieldChangedEventArgs e)
+ {
+ AdrInvalid = !AdrContext.Validate();
+ StateHasChanged();
+ }
+
+ private void AdrValidationChanged(object sender, ValidationStateChangedEventArgs e)
+ {
+ AdrInvalid = true;
+ AdrContext.OnFieldChanged -= HandleAdrChanged;
+ AdrContext = new EditContext(AdrQuery);
+ AdrContext.OnFieldChanged += HandleAdrChanged;
+ AdrContext.NotifyValidationStateChanged();
+ }
+
+ public void Dispose()
+ {
+ Interceptor.DisposeEvent();
+ AdrContext.OnFieldChanged -= HandleAdrChanged;
+ AdrContext.OnValidationStateChanged -= AdrValidationChanged;
+ }
+
+ public class Query
+ {
+ [Required(ErrorMessage = "Vejnavn skal udfyldes", AllowEmptyStrings = false)]
+ public string StreetName { get; set; } = "";
+
+ [Required(ErrorMessage = "Husnummer skal udfyldes")]
+ public string HouseNumber { get; set; } = "";
+
+ [Required(ErrorMessage = "Postnummer skal udfyldes")]
+ public string ZipCode { get; set; } = "";
+ }
+}
\ No newline at end of file
diff --git a/Wonky.Client/Components/RegLookupAddress.razor.css b/Wonky.Client/Components/RegLookupAddress.razor.css
new file mode 100644
index 00000000..f8223a63
--- /dev/null
+++ b/Wonky.Client/Components/RegLookupAddress.razor.css
@@ -0,0 +1,11 @@
+@media (min-width: 768px) and (max-width:991px){
+ .card-columns {
+ column-count: 3;
+ }
+}
+
+@media (min-width: 992px){
+ .card-columns {
+ column-count: 4;
+ }
+}
diff --git a/Wonky.Client/Components/RegLookupVatNo.razor b/Wonky.Client/Components/RegLookupVatNo.razor
new file mode 100644
index 00000000..2a5a34aa
--- /dev/null
+++ b/Wonky.Client/Components/RegLookupVatNo.razor
@@ -0,0 +1,103 @@
+@*
+// 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]
+//
+*@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+@if (_vatInfos.Any())
+{
+
+ @foreach (var info in _vatInfos)
+ {
+ @if(info.Name == "INGEN DATA")
+ {
+
+
@info.Name
+
+ }
+ else
+ {
+
+
+
@info.Name
+
+
+
+
+ Reg.nr.
+
+
+ @info.VatNumber
+
+
+
+
+ Conavn
+
+
+ @info.CoName
+
+
+
+
+ Adresse
+
+
+ @info.Address
+
+
+
+
+ Postnr
+
+
+ @info.ZipCode
+
+
+
+
+ Bynavn
+
+
+ @info.City
+
+
+
+
+ }
+ }
+
+}
+else
+{
+
+ Henter data...
+
+}
+
diff --git a/Wonky.Client/Components/RegLookupVatNo.razor.cs b/Wonky.Client/Components/RegLookupVatNo.razor.cs
new file mode 100644
index 00000000..016b4e18
--- /dev/null
+++ b/Wonky.Client/Components/RegLookupVatNo.razor.cs
@@ -0,0 +1,82 @@
+// 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.ComponentModel.DataAnnotations;
+using Microsoft.AspNetCore.Components;
+using Microsoft.AspNetCore.Components.Forms;
+using Wonky.Client.HttpInterceptors;
+using Wonky.Client.Services;
+using Wonky.Entity.Models;
+using Wonky.Entity.Requests;
+
+namespace Wonky.Client.Components;
+
+public partial class RegLookupVatNo : IDisposable
+{
+ private EditContext _regContext { get; set; }
+ private List _vatInfos { get; set; } = new();
+ private bool _showVatResult = true;
+ private bool _regInvalid = true;
+
+ [Required] private string VatNumber { get; set; } = "";
+ [Inject] private VirkRegistryService RegQueryService { get; set; }
+ [Inject] private HttpInterceptorService Interceptor { get; set; }
+
+ protected override void OnInitialized()
+ {
+ _showVatResult = false;
+ _regContext = new EditContext(VatNumber);
+ _regContext.OnFieldChanged += HandleRegChanged;
+ Interceptor.RegisterEvent();
+ Interceptor.RegisterBeforeSendEvent();
+ }
+
+ private void HandleRegChanged(object sender, FieldChangedEventArgs e)
+ {
+ _regInvalid = !_regContext.Validate();
+ StateHasChanged();
+ }
+ private async Task FetchRegData()
+ {
+ _showVatResult = true;
+
+ var query = new VirkParams
+ {
+ VatNumber = VatNumber,
+ HouseNumber = "",
+ StreetName = "",
+ ZipCode = ""
+ };
+ _vatInfos = await RegQueryService.QueryVirkRegistry(query).ConfigureAwait(true);
+ }
+
+ private void RegValidationChanged(object sender, ValidationStateChangedEventArgs e)
+ {
+ _vatInfos.Clear();
+ _regInvalid = true;
+ _regContext.OnFieldChanged -= HandleRegChanged;
+ _regContext = new EditContext(VatNumber);
+ _regContext.OnFieldChanged += HandleRegChanged;
+ _regContext.NotifyValidationStateChanged();
+ }
+
+ public void Dispose()
+ {
+ Interceptor.DisposeEvent();
+ _regContext.OnFieldChanged -= HandleRegChanged;
+ _regContext.OnValidationStateChanged -= RegValidationChanged;
+ }
+
+}
\ No newline at end of file
diff --git a/Wonky.Client/Components/RegStateVatNumber.razor b/Wonky.Client/Components/RegStateVatNumber.razor
new file mode 100644
index 00000000..6b714b7a
--- /dev/null
+++ b/Wonky.Client/Components/RegStateVatNumber.razor
@@ -0,0 +1,29 @@
+@*
+// 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]
+//
+*@
+
+
\ No newline at end of file
diff --git a/Wonky.Client/Components/RegStateVatNumber.razor.cs b/Wonky.Client/Components/RegStateVatNumber.razor.cs
new file mode 100644
index 00000000..f4607dea
--- /dev/null
+++ b/Wonky.Client/Components/RegStateVatNumber.razor.cs
@@ -0,0 +1,46 @@
+// 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 Microsoft.AspNetCore.Components;
+using Wonky.Client.Services;
+using Wonky.Entity.Models;
+using Wonky.Entity.Requests;
+
+namespace Wonky.Client.Components;
+
+public partial class RegStateVatNumber
+{
+ [Inject] public VirkRegistryService VirkRegistryService { get; set; }
+
+ [Parameter] public string VatNumber { get; set; } = "";
+
+ private VirkRegInfo VirkRegInfo { get; set; } = new();
+ private readonly VirkParams _virkParams = new();
+ private string CurrentRegState = "UKENDT";
+
+ protected override async Task OnParametersSetAsync()
+ {
+ _virkParams.VatNumber = VatNumber;
+ if (!string.IsNullOrEmpty(VatNumber))
+ {
+ var result = await VirkRegistryService.QueryVirkRegistry(_virkParams);
+ VirkRegInfo = result.Any() ? result[0] : new VirkRegInfo();
+ if (VirkRegInfo.States.Any())
+ CurrentRegState = VirkRegInfo.States[^1].State;
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/Wonky.Client/Components/RegStateVatNumber.razor.css b/Wonky.Client/Components/RegStateVatNumber.razor.css
new file mode 100644
index 00000000..5f282702
--- /dev/null
+++ b/Wonky.Client/Components/RegStateVatNumber.razor.css
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/Wonky.Client/Components/SalesItemGroupFilter.razor b/Wonky.Client/Components/SalesItemGroupFilter.razor
new file mode 100644
index 00000000..18685312
--- /dev/null
+++ b/Wonky.Client/Components/SalesItemGroupFilter.razor
@@ -0,0 +1,28 @@
+@*
+// 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]
+//
+*@
+
+
+
+
\ No newline at end of file
diff --git a/Wonky.Client/Components/SalesItemGroupFilter.razor.cs b/Wonky.Client/Components/SalesItemGroupFilter.razor.cs
new file mode 100644
index 00000000..d5a81918
--- /dev/null
+++ b/Wonky.Client/Components/SalesItemGroupFilter.razor.cs
@@ -0,0 +1,30 @@
+// 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 Microsoft.AspNetCore.Components;
+
+namespace Wonky.Client.Components;
+
+public partial class SalesItemGroupFilter
+{
+ [Parameter] public EventCallback OnGroupFilterChanged { get; set; }
+
+ private async Task ApplyGroupFilter(ChangeEventArgs eventArgs)
+ {
+ if (eventArgs?.Value?.ToString() == "-1")
+ return;
+ await OnGroupFilterChanged.InvokeAsync(eventArgs?.Value?.ToString());
+ }
+}
\ No newline at end of file
diff --git a/Wonky.Client/Components/SalesItemGroupFilter.razor.css b/Wonky.Client/Components/SalesItemGroupFilter.razor.css
new file mode 100644
index 00000000..e01c1fc6
--- /dev/null
+++ b/Wonky.Client/Components/SalesItemGroupFilter.razor.css
@@ -0,0 +1,3 @@
+.group-field {
+ margin-bottom: 10px;
+}
\ No newline at end of file
diff --git a/Wonky.Client/Components/SalesItemSearchField.razor b/Wonky.Client/Components/SalesItemSearchField.razor
new file mode 100644
index 00000000..abb200c4
--- /dev/null
+++ b/Wonky.Client/Components/SalesItemSearchField.razor
@@ -0,0 +1,25 @@
+@*
+// 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]
+//
+*@
+
+
+
+
diff --git a/Wonky.Client/Components/SalesItemSearchField.razor.cs b/Wonky.Client/Components/SalesItemSearchField.razor.cs
new file mode 100644
index 00000000..a682ea12
--- /dev/null
+++ b/Wonky.Client/Components/SalesItemSearchField.razor.cs
@@ -0,0 +1,30 @@
+// 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 Microsoft.AspNetCore.Components;
+
+namespace Wonky.Client.Components;
+
+public partial class SalesItemSearchField
+{
+ [Parameter] public EventCallback OnSearchFieldChanged { get; set; }
+
+ private async Task ApplySearchField(ChangeEventArgs eventArgs)
+ {
+ if (eventArgs?.Value?.ToString() == "-1")
+ return;
+ await OnSearchFieldChanged.InvokeAsync(eventArgs?.Value?.ToString());
+ }
+}
\ No newline at end of file
diff --git a/Wonky.Client/Components/SalesItemSearchField.razor.css b/Wonky.Client/Components/SalesItemSearchField.razor.css
new file mode 100644
index 00000000..4d7d555a
--- /dev/null
+++ b/Wonky.Client/Components/SalesItemSearchField.razor.css
@@ -0,0 +1,3 @@
+.search-field {
+ margin-bottom: 10px;
+}
\ No newline at end of file
diff --git a/Wonky.Client/Components/SalesItemSort.razor b/Wonky.Client/Components/SalesItemSort.razor
new file mode 100644
index 00000000..e66cf283
--- /dev/null
+++ b/Wonky.Client/Components/SalesItemSort.razor
@@ -0,0 +1,24 @@
+@*
+// 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]
+//
+*@
+
+
+
+
\ No newline at end of file
diff --git a/Wonky.Client/Components/SalesItemSort.razor.cs b/Wonky.Client/Components/SalesItemSort.razor.cs
new file mode 100644
index 00000000..c416f92a
--- /dev/null
+++ b/Wonky.Client/Components/SalesItemSort.razor.cs
@@ -0,0 +1,31 @@
+// 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 Microsoft.AspNetCore.Components;
+
+namespace Wonky.Client.Components;
+
+public partial class SalesItemSort
+{
+ [Parameter]
+ public EventCallback OnSortFieldChanged { get; set; }
+
+ private async Task ApplySort(ChangeEventArgs eventArgs)
+ {
+ if (eventArgs?.Value?.ToString() == "-1")
+ return;
+ await OnSortFieldChanged.InvokeAsync(eventArgs?.Value?.ToString());
+ }
+}
\ No newline at end of file
diff --git a/Wonky.Client/Components/SalesItemTable.razor b/Wonky.Client/Components/SalesItemTable.razor
new file mode 100644
index 00000000..85ecd45d
--- /dev/null
+++ b/Wonky.Client/Components/SalesItemTable.razor
@@ -0,0 +1,61 @@
+@*
+// Copyright (C) 2022 FCS Frede's Computer Services.
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as
+// published by the Free Software Foundation, either version 3 of the
+// License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see [https://www.gnu.org/licenses/agpl-3.0.en.html]
+//
+*@
+
+@if (SalesItems.Any())
+{
+
+}
\ No newline at end of file
diff --git a/Wonky.Client/Components/SalesItemTable.razor.cs b/Wonky.Client/Components/SalesItemTable.razor.cs
new file mode 100644
index 00000000..9fe0f7ad
--- /dev/null
+++ b/Wonky.Client/Components/SalesItemTable.razor.cs
@@ -0,0 +1,31 @@
+// Copyright (C) 2022 FCS Frede's Computer Services.
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as
+// published by the Free Software Foundation, either version 3 of the
+// License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see [https://www.gnu.org/licenses/agpl-3.0.en.html]
+//
+
+using Blazored.Toast.Services;
+using Microsoft.AspNetCore.Components;
+using Wonky.Entity.DTO;
+
+namespace Wonky.Client.Components;
+
+public partial class SalesItemTable
+{
+ [Parameter] public List SalesItems { get; set; } = new();
+ [Parameter] public string PoDraftAccount { get; set; } = "";
+ [Inject] private IToastService ToastService { get; set; }
+ private void AddToDraft()
+ {
+ ToastService.ShowInfo("TODO: læg til ordre kladde");
+ }
+}
\ No newline at end of file
diff --git a/Wonky.Client/Components/SalesItemTable.razor.css b/Wonky.Client/Components/SalesItemTable.razor.css
new file mode 100644
index 00000000..738b44aa
--- /dev/null
+++ b/Wonky.Client/Components/SalesItemTable.razor.css
@@ -0,0 +1,3 @@
+.product-img {
+ width: 80px;
+}
\ No newline at end of file
diff --git a/Wonky.Client/Components/SearchPhrase.razor b/Wonky.Client/Components/SearchPhrase.razor
new file mode 100644
index 00000000..385b46b1
--- /dev/null
+++ b/Wonky.Client/Components/SearchPhrase.razor
@@ -0,0 +1,22 @@
+@*
+// 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]
+//
+*@
+
+
+
+
\ No newline at end of file
diff --git a/Wonky.Client/Components/SearchPhrase.razor.cs b/Wonky.Client/Components/SearchPhrase.razor.cs
new file mode 100644
index 00000000..4ddc2853
--- /dev/null
+++ b/Wonky.Client/Components/SearchPhrase.razor.cs
@@ -0,0 +1,44 @@
+// 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.Timers;
+using Microsoft.AspNetCore.Components;
+using Timer = System.Timers.Timer;
+
+namespace Wonky.Client.Components
+{
+ public partial class SearchPhrase
+ {
+ private Timer _timer = new();
+ public string SearchTerm { get; set; } = "";
+
+ [Parameter] public EventCallback OnSearchChanged { get; set; }
+
+ private void SearchChanged()
+ {
+ _timer = new Timer(1000);
+ _timer.Elapsed += OnTimerElapsed;
+ _timer.AutoReset = false;
+ _timer.Enabled = true;
+ }
+
+ private void OnTimerElapsed(object? sender, ElapsedEventArgs e)
+ {
+ OnSearchChanged.InvokeAsync(SearchTerm);
+ _timer.Enabled = false;
+ _timer.Dispose();
+ }
+ }
+}
diff --git a/Wonky.Client/Components/SearchPhrase.razor.css b/Wonky.Client/Components/SearchPhrase.razor.css
new file mode 100644
index 00000000..32935266
--- /dev/null
+++ b/Wonky.Client/Components/SearchPhrase.razor.css
@@ -0,0 +1,3 @@
+.search-input {
+ margin-bottom: 10px;
+}
\ No newline at end of file
diff --git a/Wonky.Client/Features/JwtParser.cs b/Wonky.Client/Features/JwtParser.cs
new file mode 100644
index 00000000..c6fdab6f
--- /dev/null
+++ b/Wonky.Client/Features/JwtParser.cs
@@ -0,0 +1,56 @@
+using System.Security.Claims;
+using System.Text.Json;
+
+namespace Wonky.Client.Features;
+
+public class JwtParser
+{
+ public static IEnumerable ParseClaimsFromJwt(string jwt)
+ {
+ var claims = new List();
+ var payload = jwt.Split('.')[1];
+
+ var jsonBytes = ParseBase64WithoutPadding(payload);
+
+ var keyValuePairs = JsonSerializer
+ .Deserialize>(jsonBytes);
+
+ ExtractRolesFromJwt(claims, keyValuePairs);
+
+ claims.AddRange(keyValuePairs!
+ .Select(kvp => new Claim(kvp.Key, kvp.Value.ToString())));
+
+ return claims;
+ }
+
+ private static void ExtractRolesFromJwt(List claims,
+ Dictionary? keyValuePairs)
+ {
+ keyValuePairs.TryGetValue(ClaimTypes.Role, out object roles);
+ if (roles == null) return;
+ var parsedRoles = roles.ToString().Trim()
+ .TrimStart('[').TrimEnd(']').Split(',');
+ if (parsedRoles.Length > 1)
+ {
+ claims.AddRange(parsedRoles
+ .Select(parsedRole => new Claim(ClaimTypes.Role, parsedRole.Trim('"'))));
+ }
+ else
+ {
+ claims.Add(new Claim(ClaimTypes.Role, parsedRoles[0]));
+ }
+ keyValuePairs.Remove(ClaimTypes.Role);
+ }
+
+
+ private static byte[] ParseBase64WithoutPadding(string base64)
+ {
+ switch (base64.Length % 4)
+ {
+ case 2: base64 += "=="; break;
+ case 3: base64 += "="; break;
+ }
+
+ return Convert.FromBase64String(base64);
+ }
+}
\ No newline at end of file
diff --git a/Wonky.Client/Features/PagingLink.cs b/Wonky.Client/Features/PagingLink.cs
new file mode 100644
index 00000000..a4d6c97a
--- /dev/null
+++ b/Wonky.Client/Features/PagingLink.cs
@@ -0,0 +1,31 @@
+// 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]
+//
+
+namespace Wonky.Client.Features;
+
+public class PagingLink
+{
+ public string Text { get; set; }
+ public int Page { get; set; }
+ public bool Enabled { get; set; }
+ public bool Active { get; set; }
+
+ public PagingLink(int page, bool enabled, string text)
+ {
+ Page = page;
+ Enabled = enabled;
+ Text = text;
+ }
+}
\ No newline at end of file
diff --git a/Wonky.Client/Features/PagingResponse.cs b/Wonky.Client/Features/PagingResponse.cs
new file mode 100644
index 00000000..28e0941c
--- /dev/null
+++ b/Wonky.Client/Features/PagingResponse.cs
@@ -0,0 +1,24 @@
+// Copyright (C) 2022 FCS Frede's Computer Services.
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as
+// published by the Free Software Foundation, either version 3 of the
+// License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see [https://www.gnu.org/licenses/agpl-3.0.en.html]
+//
+
+using Wonky.Entity.Requests;
+
+namespace Wonky.Client.Features;
+
+public class PagingResponse where T : class
+{
+ public List? Items { get; set; }
+ public MetaData? MetaData { get; set; }
+}
\ No newline at end of file
diff --git a/Wonky.Client/Helpers/Utils.cs b/Wonky.Client/Helpers/Utils.cs
new file mode 100644
index 00000000..830eedaa
--- /dev/null
+++ b/Wonky.Client/Helpers/Utils.cs
@@ -0,0 +1,24 @@
+// 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]
+//
+
+namespace Wonky.Client.Helpers;
+
+public static class Utils
+{
+ public static int GetHashFromNow()
+ {
+ return DateTime.Now.ToFileTimeUtc().GetHashCode();
+ }
+}
\ No newline at end of file
diff --git a/Wonky.Client/HttpInterceptors/HttpInterceptorService.cs b/Wonky.Client/HttpInterceptors/HttpInterceptorService.cs
new file mode 100644
index 00000000..d3178991
--- /dev/null
+++ b/Wonky.Client/HttpInterceptors/HttpInterceptorService.cs
@@ -0,0 +1,109 @@
+// 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.Net;
+using System.Net.Http.Headers;
+using Blazored.Toast.Services;
+using Microsoft.AspNetCore.Components;
+using Toolbelt.Blazor;
+using Wonky.Client.Services;
+
+namespace Wonky.Client.HttpInterceptors
+{
+ public class HttpInterceptorService
+ {
+ private readonly HttpClientInterceptor _interceptor;
+ private readonly NavigationManager _navigation;
+ private readonly IToastService _toast;
+ private readonly RefreshTokenService _refreshTokenService;
+ private ILogger _logger;
+
+ public HttpInterceptorService(HttpClientInterceptor interceptor,
+ NavigationManager navigation, IToastService toast,
+ RefreshTokenService refreshTokenService, ILogger logger)
+ {
+ _interceptor = interceptor;
+ _navigation = navigation;
+ _toast = toast;
+ _refreshTokenService = refreshTokenService;
+ _logger = logger;
+ }
+
+ public void RegisterEvent()
+ {
+ _interceptor.AfterSend += AfterSend;
+ }
+
+ public void RegisterBeforeSendEvent()
+ {
+ _interceptor.BeforeSendAsync += InterceptBeforeSendAsync;
+ }
+ public void DisposeEvent()
+ {
+ _interceptor.AfterSend -= AfterSend;
+ _interceptor.BeforeSendAsync -= InterceptBeforeSendAsync;
+ }
+
+ public async Task InterceptBeforeSendAsync(object sender, HttpClientInterceptorEventArgs e)
+ {
+ var absolutePath = e.Request.RequestUri.AbsolutePath;
+
+ if (!absolutePath.Contains("token"))
+ {
+ // call TryRefreshToken
+ var token = await _refreshTokenService.TryRefreshToken();
+
+ if (!string.IsNullOrEmpty(token))
+ {
+ // set new token
+ e.Request.Headers.Authorization = new AuthenticationHeaderValue("bearer", token);
+ }
+
+ }
+ }
+
+ public void AfterSend (object sender, HttpClientInterceptorEventArgs e)
+ {
+ if (e.Response == null || e.Response.IsSuccessStatusCode)
+ return;
+
+ string? message;
+ var currDoc = _navigation.ToBaseRelativePath(_navigation.Uri);
+
+ switch (e.Response.StatusCode)
+ {
+ case HttpStatusCode.NotFound:
+ _navigation.NavigateTo("/404");
+ message = "404 - Page not found.";
+ break;
+ case HttpStatusCode.BadRequest:
+ _navigation.NavigateTo($"/login/{currDoc}");
+ message = "Verifikation nødvendig ...";
+ _toast.ShowInfo(message);
+ break;
+ case HttpStatusCode.Unauthorized:
+ _navigation.NavigateTo($"/login/{currDoc}");
+ message = "Verifikation nødvendig ...";
+ _toast.ShowInfo(message);
+ break;
+ default: _navigation.NavigateTo("/500");
+ message = "500 - Internal server error";
+ break;
+ }
+ throw new HttpResponseException(message);
+ }
+ }
+}
+
diff --git a/Wonky.Client/HttpInterceptors/HttpResponseException.cs b/Wonky.Client/HttpInterceptors/HttpResponseException.cs
new file mode 100644
index 00000000..83ceb9e3
--- /dev/null
+++ b/Wonky.Client/HttpInterceptors/HttpResponseException.cs
@@ -0,0 +1,40 @@
+// 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.Runtime.Serialization;
+
+namespace Wonky.Client.HttpInterceptors
+{
+ [Serializable]
+ public class HttpResponseException : Exception
+ {
+ public HttpResponseException()
+ {
+ }
+ public HttpResponseException(string message)
+ : base(message)
+ {
+ }
+ public HttpResponseException(string message, Exception innerException)
+ : base(message, innerException)
+ {
+ }
+ public HttpResponseException(SerializationInfo info, StreamingContext context)
+ : base(info, context)
+ {
+ }
+
+ }
+}
diff --git a/Wonky.Client/HttpRepository/CompanyHttpRepository.cs b/Wonky.Client/HttpRepository/CompanyHttpRepository.cs
new file mode 100644
index 00000000..2509d4cc
--- /dev/null
+++ b/Wonky.Client/HttpRepository/CompanyHttpRepository.cs
@@ -0,0 +1,110 @@
+// 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.Net.Http.Json;
+using System.Text.Json;
+using Microsoft.AspNetCore.Components;
+using Microsoft.AspNetCore.WebUtilities;
+using Microsoft.Extensions.Options;
+using Wonky.Client.Features;
+using Wonky.Entity.Configuration;
+using Wonky.Entity.DTO;
+using Wonky.Entity.Requests;
+
+#pragma warning disable CS8601
+
+namespace Wonky.Client.HttpRepository;
+
+public class CompanyHttpRepository : ICompanyHttpRepository
+{
+ private readonly JsonSerializerOptions _options = new JsonSerializerOptions
+ {
+ PropertyNameCaseInsensitive = true
+ };
+
+ private readonly NavigationManager _navigation;
+ private ILogger _logger;
+ private readonly HttpClient _client;
+ private readonly ApiConfig _apiConfig;
+
+ public CompanyHttpRepository(HttpClient client,
+ ILogger logger,
+ NavigationManager navigation, IOptions apiConfig)
+ {
+ _client = client;
+ _logger = logger;
+ _navigation = navigation;
+ _apiConfig = apiConfig.Value;
+ }
+
+ public async Task> GetCompanies(PagingParams pagingParameters)
+ {
+ var queryString = new Dictionary
+ {
+ ["pageNumber"] = pagingParameters.PageNumber.ToString(),
+ ["pageSize"] = pagingParameters.PageSize.ToString(),
+ ["searchTerm"] = string.IsNullOrEmpty(pagingParameters.SearchTerm) ? "" : pagingParameters.SearchTerm,
+ ["orderBy"] = string.IsNullOrEmpty(pagingParameters.OrderBy) ? "" : pagingParameters.OrderBy,
+ ["searchColumn"] = string.IsNullOrEmpty(pagingParameters.SearchColumn) ? "" : pagingParameters.SearchColumn
+ };
+ var response = await _client
+ .GetAsync(QueryHelpers.AddQueryString($"{_apiConfig.CrmCompanies}", queryString));
+
+ var content = await response.Content.ReadAsStringAsync();
+
+ var pagingResponse = new PagingResponse
+ {
+ Items = JsonSerializer.Deserialize>(content, _options),
+ MetaData = JsonSerializer.Deserialize(
+ response.Headers.GetValues("X-Pagination").First(), _options)
+ };
+ return pagingResponse;
+ }
+
+ public async Task GetCompanyByAccount(string accountNumber)
+ {
+ var company = await _client.GetFromJsonAsync(
+ $"{_apiConfig.CrmCompanies}/account/{accountNumber}");
+ return company ?? new CompanyDto();
+ }
+
+ public async Task GetCompanyById(string companyId)
+ {
+ var company = await _client.GetFromJsonAsync(
+ $"{_apiConfig.CrmCompanies}/id/{companyId}");
+ return company ?? new CompanyDto();
+ }
+
+ public async Task CreateCompany(CompanyDto companyDto)
+ {
+ var response = await _client.PostAsJsonAsync(
+ $"{_apiConfig.CrmCompanies}", companyDto);
+ var content = await response.Content.ReadAsStringAsync();
+ var result = JsonSerializer.Deserialize(content);
+ return result.CompanyId;
+ }
+
+ public async Task UpdateCompany(CompanyDto companyDto)
+ {
+ await _client.PutAsJsonAsync(
+ $"{_apiConfig.CrmCompanies}/{companyDto.CompanyId}", companyDto);
+ }
+
+ public async Task DeleteCompany(string companyId)
+ {
+ await _client.DeleteAsync(
+ $"{_apiConfig.CrmCompanies}/{companyId}");
+ }
+}
\ No newline at end of file
diff --git a/Wonky.Client/HttpRepository/ICompanyHttpRepository.cs b/Wonky.Client/HttpRepository/ICompanyHttpRepository.cs
new file mode 100644
index 00000000..5c31f6f6
--- /dev/null
+++ b/Wonky.Client/HttpRepository/ICompanyHttpRepository.cs
@@ -0,0 +1,30 @@
+// 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.Features;
+using Wonky.Entity.DTO;
+using Wonky.Entity.Requests;
+
+namespace Wonky.Client.HttpRepository;
+
+public interface ICompanyHttpRepository
+{
+ Task> GetCompanies(PagingParams pagingParameters);
+ Task GetCompanyByAccount(string accountNumber);
+ Task GetCompanyById(string companyId);
+ Task CreateCompany(CompanyDto companyDto);
+ Task UpdateCompany(CompanyDto companyDto);
+ Task DeleteCompany(string companyId);
+}
\ No newline at end of file
diff --git a/Wonky.Client/HttpRepository/IKrvProductHttpRepository.cs b/Wonky.Client/HttpRepository/IKrvProductHttpRepository.cs
new file mode 100644
index 00000000..4086b03b
--- /dev/null
+++ b/Wonky.Client/HttpRepository/IKrvProductHttpRepository.cs
@@ -0,0 +1,29 @@
+// 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.Features;
+using Wonky.Entity.DTO;
+using Wonky.Entity.Requests;
+
+namespace Wonky.Client.HttpRepository;
+
+public interface IKrvProductHttpRepository
+{
+ Task> GetProducts(PagingParams pagingParameters);
+ Task GetProduct(string productId);
+ Task CreateProduct(KrvProductDto product);
+ Task UploadImage(MultipartFormDataContent content, string productId);
+ Task UpdateProduct(KrvProductDto product);
+}
\ No newline at end of file
diff --git a/Wonky.Client/HttpRepository/IKrvVariantHttpRepository.cs b/Wonky.Client/HttpRepository/IKrvVariantHttpRepository.cs
new file mode 100644
index 00000000..2bbbb5ff
--- /dev/null
+++ b/Wonky.Client/HttpRepository/IKrvVariantHttpRepository.cs
@@ -0,0 +1,29 @@
+// 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.Features;
+using Wonky.Entity.DTO;
+using Wonky.Entity.Requests;
+
+namespace Wonky.Client.HttpRepository;
+
+public interface IKrvVariantHttpRepository
+{
+ Task> GetVariants(PagingParams pagingParameters);
+ Task GetVariant(string variantId);
+ Task CreateVariant(KrvVariantDto variantDto);
+ Task UploadImage(MultipartFormDataContent content, string variantId);
+ Task UpdateVariant(KrvVariantDto variant);
+}
\ No newline at end of file
diff --git a/Wonky.Client/HttpRepository/ISalesItemHttpRepository.cs b/Wonky.Client/HttpRepository/ISalesItemHttpRepository.cs
new file mode 100644
index 00000000..15c6f347
--- /dev/null
+++ b/Wonky.Client/HttpRepository/ISalesItemHttpRepository.cs
@@ -0,0 +1,26 @@
+// 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.Features;
+using Wonky.Entity.DTO;
+using Wonky.Entity.Requests;
+
+namespace Wonky.Client.HttpRepository;
+
+public interface ISalesItemHttpRepository
+{
+ Task> GetSalesItems(PagingParams pagingParameters);
+ Task GetSalesItem(string id);
+}
\ No newline at end of file
diff --git a/Wonky.Client/HttpRepository/KrvProductHttpRepository.cs b/Wonky.Client/HttpRepository/KrvProductHttpRepository.cs
new file mode 100644
index 00000000..aae696e6
--- /dev/null
+++ b/Wonky.Client/HttpRepository/KrvProductHttpRepository.cs
@@ -0,0 +1,108 @@
+// 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.Net.Http.Json;
+using System.Text.Json;
+using Microsoft.AspNetCore.Components;
+using Microsoft.AspNetCore.WebUtilities;
+using Microsoft.Extensions.Options;
+using Wonky.Client.Features;
+using Wonky.Entity.Configuration;
+using Wonky.Entity.DTO;
+using Wonky.Entity.Requests;
+
+namespace Wonky.Client.HttpRepository;
+
+public class KrvProductHttpRepository : IKrvProductHttpRepository
+{
+ private readonly JsonSerializerOptions? _options = new JsonSerializerOptions
+ {
+ PropertyNameCaseInsensitive = true
+ };
+
+ private readonly NavigationManager _navigation;
+ private ILogger _logger;
+ private readonly HttpClient _client;
+ private readonly ApiConfig _apiConfig;
+
+ public KrvProductHttpRepository(HttpClient client,
+ ILogger logger,
+ NavigationManager navigation, IOptions configuration)
+ {
+ _client = client;
+ _logger = logger;
+ _navigation = navigation;
+ _apiConfig = configuration.Value;
+ }
+
+ public async Task> GetProducts(PagingParams pagingParameters)
+ {
+ var queryString = new Dictionary
+ {
+ ["pageNumber"] = pagingParameters.PageNumber.ToString(),
+ ["pageSize"] = pagingParameters.PageSize.ToString(),
+ ["searchTerm"] = string.IsNullOrEmpty(pagingParameters.SearchTerm) ? "" : pagingParameters.SearchTerm,
+ ["orderBy"] = string.IsNullOrEmpty(pagingParameters.OrderBy) ? "" : pagingParameters.OrderBy
+ };
+ var response = await _client
+ .GetAsync(QueryHelpers.AddQueryString($"{_apiConfig.KrvProducts}", queryString))
+ ;
+
+ var content = await response.Content
+ .ReadAsStringAsync()
+ ;
+
+ var pagingResponse = new PagingResponse
+ {
+ Items = JsonSerializer.Deserialize>(content, _options),
+ MetaData = JsonSerializer.Deserialize(
+ response.Headers.GetValues("X-Pagination").First(), _options)
+ };
+ return pagingResponse;
+ }
+
+ public async Task GetProduct(string productId)
+ {
+ var product = await _client
+ .GetFromJsonAsync($"{_apiConfig.KrvProducts}/get/id({productId})")
+ ;
+ return product ?? new KrvProductDto();
+ }
+
+ public async Task CreateProduct(KrvProductDto productDto)
+ {
+ await _client
+ .PostAsJsonAsync($"{_apiConfig.KrvProducts}", productDto)
+ ;
+ }
+
+ public async Task UploadImage(MultipartFormDataContent content, string productId)
+ {
+ var postResult = await _client
+ .PostAsync($"{_apiConfig.ImageUpload}/products/id({productId})/image", content)
+ ;
+
+ var postContent = await postResult.Content.ReadAsStringAsync();
+
+ return postContent;
+ }
+
+ public async Task UpdateProduct(KrvProductDto product)
+ {
+ Console.WriteLine(product.ProductId);
+
+ await _client.PutAsJsonAsync($"{_apiConfig.KrvProducts}/put/id({product.ProductId})", product);
+ }
+}
\ No newline at end of file
diff --git a/Wonky.Client/HttpRepository/KrvVariantHttpRepository.cs b/Wonky.Client/HttpRepository/KrvVariantHttpRepository.cs
new file mode 100644
index 00000000..23d41fcb
--- /dev/null
+++ b/Wonky.Client/HttpRepository/KrvVariantHttpRepository.cs
@@ -0,0 +1,112 @@
+// 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.Net.Http.Json;
+using System.Text.Json;
+using Microsoft.AspNetCore.Components;
+using Microsoft.AspNetCore.WebUtilities;
+using Microsoft.Extensions.Options;
+using Wonky.Client.Features;
+using Wonky.Entity.Configuration;
+using Wonky.Entity.DTO;
+using Wonky.Entity.Requests;
+
+namespace Wonky.Client.HttpRepository;
+
+public class KrvVariantHttpRepository : IKrvVariantHttpRepository
+{
+ private readonly JsonSerializerOptions _options = new JsonSerializerOptions
+ {
+ PropertyNameCaseInsensitive = true
+ };
+
+ private readonly NavigationManager _navigation;
+ private ILogger _logger;
+ private readonly HttpClient _client;
+ private readonly ApiConfig _apiConfig;
+
+ public KrvVariantHttpRepository(HttpClient client,
+ ILogger logger,
+ NavigationManager navigation, IOptions configuration)
+ {
+ _client = client;
+ _logger = logger;
+ _navigation = navigation;
+ _apiConfig = configuration.Value;
+ }
+
+ public async Task> GetVariants(PagingParams pagingParameters)
+ {
+ var queryString = new Dictionary
+ {
+ ["pageNumber"] = pagingParameters.PageNumber.ToString(),
+ ["pageSize"] = pagingParameters.PageSize.ToString(),
+ ["searchTerm"] = string.IsNullOrEmpty(pagingParameters.SearchTerm) ? "" : pagingParameters.SearchTerm,
+ ["orderBy"] = string.IsNullOrEmpty(pagingParameters.OrderBy) ? "" : pagingParameters.OrderBy
+ };
+ var response = await _client
+ .GetAsync(QueryHelpers.AddQueryString($"{_apiConfig.KrvVariants}", queryString))
+ ;
+
+ var content = await response.Content
+ .ReadAsStringAsync()
+ ;
+
+ var pagingResponse = new PagingResponse
+ {
+ Items = JsonSerializer.Deserialize>(content, _options),
+ MetaData = JsonSerializer.Deserialize(
+ response.Headers.GetValues("X-Pagination").First(), _options)
+ };
+ return pagingResponse;
+ }
+
+ public async Task GetVariant(string variantId)
+ {
+ var variant = await _client
+ .GetFromJsonAsync($"{_apiConfig.KrvVariants}/get/id({variantId})")
+ ;
+ return variant ?? new KrvVariantDto();
+ }
+
+ public async Task CreateVariant(KrvVariantDto variantDto)
+ {
+ await _client
+ .PostAsJsonAsync($"v2/", variantDto)
+ ;
+ }
+
+ public async Task UploadImage(MultipartFormDataContent content, string variantId)
+ {
+ Console.WriteLine($" Repo -> UploadImage -> {variantId}");
+
+ var postResult = await _client
+ .PostAsync($"{_apiConfig.ImageUpload}/variants/id({variantId})/image", content)
+ ;
+
+ var postContent = await postResult.Content.ReadAsStringAsync();
+
+ Console.WriteLine(postContent);
+
+ return postContent;
+ }
+
+ public async Task UpdateVariant(KrvVariantDto variant)
+ {
+ Console.WriteLine(variant.VariantId);
+
+ await _client.PutAsJsonAsync($"{_apiConfig.KrvVariants}/put/id({variant.VariantId})", variant);
+ }
+}
\ No newline at end of file
diff --git a/Wonky.Client/HttpRepository/SalesItemHttpRepository.cs b/Wonky.Client/HttpRepository/SalesItemHttpRepository.cs
new file mode 100644
index 00000000..013a2682
--- /dev/null
+++ b/Wonky.Client/HttpRepository/SalesItemHttpRepository.cs
@@ -0,0 +1,79 @@
+// 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.Net.Http.Json;
+using System.Text.Json;
+using Microsoft.AspNetCore.Components;
+using Microsoft.AspNetCore.WebUtilities;
+using Microsoft.Extensions.Options;
+using Wonky.Client.Features;
+using Wonky.Entity.Configuration;
+using Wonky.Entity.DTO;
+using Wonky.Entity.Requests;
+
+namespace Wonky.Client.HttpRepository;
+
+public class SalesItemHttpRepository : ISalesItemHttpRepository
+{
+ private readonly JsonSerializerOptions _options = new JsonSerializerOptions
+ {
+ PropertyNameCaseInsensitive = true
+ };
+
+ private readonly NavigationManager _navigation;
+ private ILogger _logger;
+ private readonly HttpClient _client;
+ private readonly ApiConfig _apiConfig;
+
+ public SalesItemHttpRepository(HttpClient client,
+ ILogger logger,
+ NavigationManager navigation, IOptions configuration)
+ {
+ _client = client;
+ _logger = logger;
+ _navigation = navigation;
+ _apiConfig = configuration.Value;
+ }
+
+ public async Task> GetSalesItems(PagingParams pagingParameters)
+ {
+ var queryString = new Dictionary
+ {
+ ["pageNumber"] = pagingParameters.PageNumber.ToString(),
+ ["pageSize"] = pagingParameters.PageSize.ToString(),
+ ["searchTerm"] = string.IsNullOrEmpty(pagingParameters.SearchTerm) ? "" : pagingParameters.SearchTerm,
+ ["orderBy"] = string.IsNullOrEmpty(pagingParameters.OrderBy) ? "" : pagingParameters.OrderBy
+ };
+ var response = await _client
+ .GetAsync(QueryHelpers.AddQueryString($"{_apiConfig.PriceCatalog}", queryString));
+
+ var content = await response.Content.ReadAsStringAsync();
+
+ var pagingResponse = new PagingResponse
+ {
+ Items = JsonSerializer.Deserialize>(content, _options),
+ MetaData = JsonSerializer.Deserialize(
+ response.Headers.GetValues("X-Pagination").First(), _options)
+ };
+ return pagingResponse;
+ }
+
+ public async Task GetSalesItem(string id)
+ {
+ var salesItem = await _client
+ .GetFromJsonAsync($"{_apiConfig.PriceCatalog}/{id}");
+ return salesItem ?? new SalesItemDto();
+ }
+}
\ No newline at end of file
diff --git a/Wonky.Client/Models/PurchaseOrder.cs b/Wonky.Client/Models/PurchaseOrder.cs
new file mode 100644
index 00000000..71154d88
--- /dev/null
+++ b/Wonky.Client/Models/PurchaseOrder.cs
@@ -0,0 +1,49 @@
+// 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.ComponentModel.DataAnnotations;
+using Wonky.Entity.DTO;
+
+namespace Wonky.Client.Models
+{
+ public class PurchaseOrder
+ {
+ public int ActivityId { get; set; }
+ public string CrmCompanyKey { get; set; } = "";
+ [Required(ErrorMessage = "Sælger skal udfyldes")] public string SalesRep { get; set; } = "";
+ // From company row
+ [Required(ErrorMessage = "Konto skal udfyldes")] public string Account { get; set; } = "";
+ [Required(ErrorMessage = "Moms nummer skal udfyldes")] public string VatNumber { get; set; } = "";
+ [Required(ErrorMessage = "Navn skal udfyldes")] public string Name { get; set; } = "";
+ public string Address { get; set; } = "";
+ public string Address2 { get; set; } = "";
+ [Required(ErrorMessage = "Bynavn skal udfyldes")] public string City { get; set; }= "";
+ [Required(ErrorMessage = "Postnummer skal udfyldes")] public string ZipCode { get; set; } = "";
+ public string Phone { get; set; } = "";
+ public string EMail { get; set; } = "";
+ // Form entries
+ public string ReferenceNumber { get; set; } = "";
+ [Required(ErrorMessage = "Indkøber skal udfyldes")] public string YourRef { get; set; } = "";
+ public string OurRef { get; set; } = "";
+ [MaxLength(255, ErrorMessage = "Du kan højst bruge 255 tegn")] public string OrderMessage { get; set; } = "";
+ // From company or form entry
+ public string DlvName { get; set; } = "";
+ public string DlvAddress1 { get; set; } = "";
+ public string DlvAddress2 { get; set; } = "";
+ public string DlvZipCode { get; set; } = "";
+ public string DlvCity { get; set; } = "";
+ public List Lines { get; set; } = new();
+ }
+}
diff --git a/Wonky.Client/Models/PurchaseOrderLine.cs b/Wonky.Client/Models/PurchaseOrderLine.cs
new file mode 100644
index 00000000..232f6cd7
--- /dev/null
+++ b/Wonky.Client/Models/PurchaseOrderLine.cs
@@ -0,0 +1,28 @@
+// 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]
+//
+namespace Wonky.Client.Models;
+
+public class PurchaseOrderLine
+{
+ public int ActivityLineId { get; set; }
+ public int ActivityId { get; set; }
+ public string Sku { get; set; } = "";
+ public string Text { get; set; } = "";
+ public int Qty { get; set; }
+ public decimal Price { get; set; }
+ public decimal Discount { get; set; }
+ public decimal LineAmount { get; set; }
+ public int LineNumber { get; set; }
+}
\ No newline at end of file
diff --git a/Wonky.Client/Models/Quote.cs b/Wonky.Client/Models/Quote.cs
new file mode 100644
index 00000000..f4d1019a
--- /dev/null
+++ b/Wonky.Client/Models/Quote.cs
@@ -0,0 +1,26 @@
+// 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]
+//
+
+namespace Wonky.Client.Models
+{
+ public class Quote
+ {
+ public int QuoteId { get; set; }
+ public string CompanyId { get; set; } = "";
+ public string Name { get; set; } = "";
+ public string EMail { get; set; } = "";
+ public List Items { get; set; } = new();
+ }
+}
diff --git a/Wonky.Client/Models/QuoteItem.cs b/Wonky.Client/Models/QuoteItem.cs
new file mode 100644
index 00000000..fadd0039
--- /dev/null
+++ b/Wonky.Client/Models/QuoteItem.cs
@@ -0,0 +1,24 @@
+// 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]
+//
+
+namespace Wonky.Client.Models;
+
+public class QuoteItem
+{
+ public string Sku { get; set; } = "";
+ public string Text { get; set; } = "";
+ public int Qty { get; set; }
+ public decimal Price { get; set; }
+}
\ No newline at end of file
diff --git a/Wonky.Client/Pages/About.razor b/Wonky.Client/Pages/About.razor
new file mode 100644
index 00000000..96a1a1f3
--- /dev/null
+++ b/Wonky.Client/Pages/About.razor
@@ -0,0 +1,6 @@
+@page "/About"
+
Hvad er Wonky Online
+
+Wonky Online er Innotec Danmarks egen udviklede ordresystem.
+
+
\ No newline at end of file
diff --git a/Wonky.Client/Pages/ActivityList.razor b/Wonky.Client/Pages/ActivityList.razor
new file mode 100644
index 00000000..414c7a37
--- /dev/null
+++ b/Wonky.Client/Pages/ActivityList.razor
@@ -0,0 +1,10 @@
+@page "/activites"
+@using Client.V1.Components;
+
+
Salgs Aktivitet
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Wonky.Client/Pages/ActivityList.razor.cs b/Wonky.Client/Pages/ActivityList.razor.cs
new file mode 100644
index 00000000..e69dcf2b
--- /dev/null
+++ b/Wonky.Client/Pages/ActivityList.razor.cs
@@ -0,0 +1,16 @@
+using System.Diagnostics;
+using Microsoft.AspNetCore.Components;
+
+namespace Wonky.Client.Pages;
+
+public partial class ActivityList
+{
+ public List Activities { get; set; } = new();
+
+ [Inject] public ActivityDbContext DbContext { get; set; }
+
+ protected override async Task OnInitializedAsync()
+ {
+ Activities = await DbContext.GetAllActivities();
+ }
+}
\ No newline at end of file
diff --git a/Wonky.Client/Pages/ActivityList.razor.css b/Wonky.Client/Pages/ActivityList.razor.css
new file mode 100644
index 00000000..e69de29b
diff --git a/Wonky.Client/Pages/CompanyActivity.razor b/Wonky.Client/Pages/CompanyActivity.razor
new file mode 100644
index 00000000..b1fa3032
--- /dev/null
+++ b/Wonky.Client/Pages/CompanyActivity.razor
@@ -0,0 +1,23 @@
+@*
+// 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]
+//
+*@
+
+@page "/CompanyActivity"
+
CompanyActivity
+
+@code {
+
+}
\ No newline at end of file
diff --git a/Wonky.Client/Pages/CompanyCreate.razor b/Wonky.Client/Pages/CompanyCreate.razor
new file mode 100644
index 00000000..0225e977
--- /dev/null
+++ b/Wonky.Client/Pages/CompanyCreate.razor
@@ -0,0 +1,146 @@
+@*
+// 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]
+//
+*@
+
+@page "/create-company"
+@using Microsoft.AspNetCore.Authorization
+@using Microsoft.AspNetCore.Components
+
+@attribute [Authorize(Roles = "Adviser")]
+
Opret firma
+
+
+
+ @if(_virkRegInfo.VatNumber != string.Empty)
+ {
+ foreach (var state in _virkRegInfo.States)
+ {
+
+
+
+
Status
+
@state.State
+
+
+
Opdateret
+
@state.LastUpdate
+
+
+
Periode
+
Start
+
@state.TimeFrame.StartDate
+
+
+
Periode
+
Slut
+
@state.TimeFrame.EndDate
+
+
+
+ }
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+@* *@
+
+
+ @* *@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Wonky.Client/Pages/CompanyCreate.razor.cs b/Wonky.Client/Pages/CompanyCreate.razor.cs
new file mode 100644
index 00000000..fe9a40fa
--- /dev/null
+++ b/Wonky.Client/Pages/CompanyCreate.razor.cs
@@ -0,0 +1,127 @@
+// 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.ComponentModel.DataAnnotations;
+using Blazored.LocalStorage;
+using Blazored.Toast.Services;
+using Microsoft.AspNetCore.Components;
+using Microsoft.AspNetCore.Components.Forms;
+using Wonky.Client.HttpInterceptors;
+using Wonky.Client.HttpRepository;
+using Wonky.Client.Services;
+using Wonky.Entity.DTO;
+using Wonky.Entity.Models;
+using Wonky.Entity.Requests;
+
+namespace Wonky.Client.Pages
+{
+ public partial class CompanyCreate : IDisposable
+ {
+ private CompanyDto _companyDto = new();
+ private VirkRegInfo _virkRegInfo = new();
+ private EditContext _editContext;
+ private bool _formInvalid = true;
+
+ private EditContext _cvrContext;
+ private bool _cvrInvalid = true;
+ private VirkParams _virkParams = new();
+ [Required] public string VatToLookup { get; set; } = "";
+ [Inject] public ICompanyHttpRepository CompanyRepo { get; set; }
+ [Inject] public HttpInterceptorService Interceptor { get; set; }
+ [Inject] public IToastService ToastService { get; set; }
+ [Inject] public ILogger Logger { get; set; }
+ [Inject] public VirkRegistryService VirkRegistryService { get; set; }
+ [Inject] public ILocalStorageService StorageService { get; set; }
+ [Inject] public NavigationManager Navigation { get; set; }
+
+ protected override async Task OnInitializedAsync()
+ {
+ _editContext = new EditContext(_companyDto);
+ _editContext.OnFieldChanged += HandleFieldChanged;
+
+ _cvrContext = new EditContext(VatToLookup);
+ _cvrContext.OnFieldChanged += HandleCvrChanged;
+ _cvrContext.OnValidationStateChanged += CvrValidationChanged;
+
+ var ux = await StorageService.GetItemAsync("_ux");
+ _companyDto.SalesRepId = ux.Id;
+
+ Interceptor.RegisterEvent();
+ Interceptor.RegisterBeforeSendEvent();
+ }
+
+ private async Task GetCvrDataFromVat()
+ {
+ var result = await VirkRegistryService.QueryVirkRegistry(new VirkParams {VatNumber = VatToLookup}).ConfigureAwait(true);
+ if (!result.Any())
+ {
+ ToastService.ShowError($"Firma med CVR '{VatToLookup}' findes ikke.");
+ return;
+ }
+ ToastService.ShowSuccess($"Data for '{VatToLookup}' er hentet.");
+ _virkRegInfo = result[0];
+ _companyDto.Name = _virkRegInfo.Name;
+ _companyDto.Address1 = _virkRegInfo.CoName;
+ _companyDto.Address2 = _virkRegInfo.Address;
+ _companyDto.ZipCode = _virkRegInfo.ZipCode;
+ _companyDto.City = _virkRegInfo.City;
+ _companyDto.VatNumber = _virkRegInfo.VatNumber;
+ }
+
+ private async Task Create()
+ {
+ var newId = await CompanyRepo.CreateCompany(_companyDto);
+ ToastService.ShowSuccess($"Godt så! '{_companyDto.Name}' er oprettet i CRM.");
+ Navigation.NavigateTo($"/company/{newId}");
+ }
+
+ private void HandleCvrChanged(object sender, FieldChangedEventArgs e)
+ {
+ _cvrInvalid = !_cvrContext.Validate();
+ StateHasChanged();
+ }
+
+ private void CvrValidationChanged(object sender, ValidationStateChangedEventArgs e)
+ {
+ _cvrInvalid = true;
+ _cvrContext.OnFieldChanged -= HandleCvrChanged;
+ _cvrContext = new EditContext(VatToLookup);
+ _cvrContext.OnFieldChanged += HandleCvrChanged;
+ _cvrContext.OnValidationStateChanged -= CvrValidationChanged;
+ }
+
+ private void HandleFieldChanged(object sender, FieldChangedEventArgs e)
+ {
+ _formInvalid = !_editContext.Validate();
+ StateHasChanged();
+ }
+ private void ValidationChanged(object sender, ValidationStateChangedEventArgs e)
+ {
+ _formInvalid = true;
+ _editContext.OnFieldChanged -= HandleFieldChanged;
+ _editContext = new EditContext(_companyDto);
+ _editContext.OnFieldChanged += HandleFieldChanged;
+ _editContext.OnValidationStateChanged -= ValidationChanged;
+ }
+
+ public void Dispose()
+ {
+ Interceptor.DisposeEvent();
+ _editContext.OnFieldChanged -= HandleFieldChanged;
+ _editContext.OnValidationStateChanged -= ValidationChanged;
+ }
+ }
+}
+
diff --git a/Wonky.Client/Pages/CompanyInfo.razor b/Wonky.Client/Pages/CompanyInfo.razor
new file mode 100644
index 00000000..42efd29c
--- /dev/null
+++ b/Wonky.Client/Pages/CompanyInfo.razor
@@ -0,0 +1,23 @@
+@*
+// 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]
+//
+*@
+
+@page "/CompanyInfo"
+
CompanyInfo
+
+@code {
+
+}
\ No newline at end of file
diff --git a/Wonky.Client/Pages/CompanyKApv.razor b/Wonky.Client/Pages/CompanyKApv.razor
new file mode 100644
index 00000000..da8c3f49
--- /dev/null
+++ b/Wonky.Client/Pages/CompanyKApv.razor
@@ -0,0 +1,23 @@
+@*
+// 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]
+//
+*@
+
+@page "/CompanyKApv"
+
CompanyKApv
+
+@code {
+
+}
\ No newline at end of file
diff --git a/Wonky.Client/Pages/CompanyList.razor b/Wonky.Client/Pages/CompanyList.razor
new file mode 100644
index 00000000..bb379308
--- /dev/null
+++ b/Wonky.Client/Pages/CompanyList.razor
@@ -0,0 +1,53 @@
+@*
+// 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]
+//
+*@
+
+@page "/companies"
+@using Microsoft.AspNetCore.Authorization
+
+@attribute [Authorize(Roles = "Adviser")]
+
+
\ No newline at end of file
diff --git a/Wonky.Client/Pages/CompanyList.razor.cs b/Wonky.Client/Pages/CompanyList.razor.cs
new file mode 100644
index 00000000..71dd7b07
--- /dev/null
+++ b/Wonky.Client/Pages/CompanyList.razor.cs
@@ -0,0 +1,94 @@
+// 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 Microsoft.AspNetCore.Components;
+using Wonky.Client.HttpInterceptors;
+using Wonky.Client.HttpRepository;
+using Wonky.Entity.DTO;
+using Wonky.Entity.Requests;
+
+namespace Wonky.Client.Pages
+{
+ public partial class CompanyList : IDisposable
+ {
+ public List? Companies { get; set; } = new();
+ public MetaData? MetaData { get; set; } = new();
+
+ private PagingParams _paging = new();
+
+ [Inject]
+ public ICompanyHttpRepository CompanyRepo { get; set; }
+
+ [Inject]
+ public HttpInterceptorService Interceptor { get; set; }
+
+ protected override async Task OnInitializedAsync()
+ {
+ Interceptor.RegisterEvent();
+ Interceptor.RegisterBeforeSendEvent();
+ await GetCompanies();
+ }
+
+ private async Task SelectedPage(int page)
+ {
+ _paging.PageNumber = page;
+ await GetCompanies();
+ }
+
+ private async Task GetCompanies()
+ {
+ var pagingResponse = await CompanyRepo.GetCompanies(_paging);
+ Companies = pagingResponse.Items;
+ MetaData = pagingResponse.MetaData;
+ }
+
+ private async Task FilterChanged(string? searchColumn)
+ {
+ _paging.SearchColumn = searchColumn;
+ _paging.PageNumber = 1;
+ await GetCompanies();
+ }
+ private async Task SetPageSize(int pageSize)
+ {
+ _paging.PageSize = pageSize;
+ _paging.PageNumber = 1;
+ await GetCompanies();
+ }
+
+ private async Task SearchChanged(string? searchTerm)
+ {
+ _paging.PageNumber = 1;
+ _paging.SearchTerm = searchTerm;
+ await GetCompanies();
+ }
+
+ private async Task SortChanged(string? orderBy)
+ {
+ _paging.OrderBy = orderBy;
+ await GetCompanies();
+ }
+
+ private async Task DeleteCompany(string companyId)
+ {
+ await CompanyRepo.DeleteCompany(companyId);
+ if (_paging.PageNumber > 1 && Companies.Count == 1)
+ _paging.PageNumber--;
+ await GetCompanies();
+ }
+ public void Dispose() => Interceptor.DisposeEvent();
+ }
+}
+
+
\ No newline at end of file
diff --git a/Wonky.Client/Pages/CompanyProducts.razor b/Wonky.Client/Pages/CompanyProducts.razor
new file mode 100644
index 00000000..22ee7f55
--- /dev/null
+++ b/Wonky.Client/Pages/CompanyProducts.razor
@@ -0,0 +1,23 @@
+@*
+// 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]
+//
+*@
+
+@page "/CompanyProducts"
+
CompanyProducts
+
+@code {
+
+}
\ No newline at end of file
diff --git a/Wonky.Client/Pages/CompanyUpdate.razor b/Wonky.Client/Pages/CompanyUpdate.razor
new file mode 100644
index 00000000..e7200e8e
--- /dev/null
+++ b/Wonky.Client/Pages/CompanyUpdate.razor
@@ -0,0 +1,127 @@
+@*
+// 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]
+//
+*@
+
+@page "/update-company/{account}"
+@using Microsoft.AspNetCore.Authorization
+@using Microsoft.AspNetCore.Components
+@attribute [Authorize(Roles = "Adviser")]
+
+@if (_companyDto != null)
+{
+
+}
\ No newline at end of file
diff --git a/Wonky.Client/Pages/CompanyUpdate.razor.cs b/Wonky.Client/Pages/CompanyUpdate.razor.cs
new file mode 100644
index 00000000..a6e013c3
--- /dev/null
+++ b/Wonky.Client/Pages/CompanyUpdate.razor.cs
@@ -0,0 +1,65 @@
+// Copyright (C) 2022 FCS Frede's Computer Services.
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as
+// published by the Free Software Foundation, either version 3 of the
+// License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see [https://www.gnu.org/licenses/agpl-3.0.en.html]
+//
+
+using Blazored.Toast.Services;
+using Microsoft.AspNetCore.Components;
+using Microsoft.AspNetCore.Components.Forms;
+using Wonky.Client.HttpInterceptors;
+using Wonky.Client.HttpRepository;
+using Wonky.Entity.DTO;
+
+namespace Wonky.Client.Pages;
+
+public partial class CompanyUpdate : IDisposable
+{
+ private CompanyDto _companyDto;
+ private EditContext _editContext;
+ private bool _formInvalid = true;
+
+ [Inject] public ICompanyHttpRepository CompanyRepo { get; set; }
+ [Inject] public HttpInterceptorService Interceptor { get; set; }
+ [Inject] public IToastService ToastService { get; set; }
+ [Inject] public ILogger Logger { get; set; }
+ [Inject] public NavigationManager Navigation { get; set; }
+ [Parameter] public string Account { get; set; } = null!;
+
+ protected override async Task OnInitializedAsync()
+ {
+ _companyDto = await CompanyRepo.GetCompanyByAccount(Account);
+ _editContext = new EditContext(_companyDto);
+ _editContext.OnFieldChanged += HandleFieldChanged!;
+ Interceptor.RegisterEvent();
+ Interceptor.RegisterBeforeSendEvent();
+ }
+
+ private async Task Update()
+ {
+ await CompanyRepo.UpdateCompany(_companyDto);
+ ToastService.ShowSuccess($"Godt så. Firma '{_companyDto!.Name}' er opdateret.");
+ Navigation.NavigateTo($"/company/{_companyDto.CompanyId}");
+ }
+ private void HandleFieldChanged(object sender, FieldChangedEventArgs e)
+ {
+ _formInvalid = !_editContext!.Validate();
+ StateHasChanged();
+ }
+
+ public void Dispose()
+ {
+ Interceptor.DisposeEvent();
+ _editContext.OnFieldChanged -= HandleFieldChanged!;
+ }
+
+}
\ No newline at end of file
diff --git a/Wonky.Client/Pages/CompanyView.razor b/Wonky.Client/Pages/CompanyView.razor
new file mode 100644
index 00000000..fdf1ac85
--- /dev/null
+++ b/Wonky.Client/Pages/CompanyView.razor
@@ -0,0 +1,96 @@
+@*
+// 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]
+//
+*@
+
+@page "/company/account/{account}"
+@page "/company/{companyId}"
+@using Microsoft.AspNetCore.Authorization
+@attribute [Authorize(Roles = "Adviser")]
+
+
diff --git a/Wonky.Client/Pages/CompanyView.razor.cs b/Wonky.Client/Pages/CompanyView.razor.cs
new file mode 100644
index 00000000..86880d20
--- /dev/null
+++ b/Wonky.Client/Pages/CompanyView.razor.cs
@@ -0,0 +1,61 @@
+// Copyright (C) 2022 FCS Frede's Computer Services.
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as
+// published by the Free Software Foundation, either version 3 of the
+// License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see [https://www.gnu.org/licenses/agpl-3.0.en.html]
+//
+
+using Microsoft.AspNetCore.Components;
+using Wonky.Client.HttpInterceptors;
+using Wonky.Client.HttpRepository;
+using Wonky.Entity.DTO;
+
+namespace Wonky.Client.Pages;
+
+public partial class CompanyView : IDisposable
+{
+ private CompanyDto CompanyDto { get; set; } = new ();
+
+ [Inject]
+ public ICompanyHttpRepository CompanyRepo { get; set; }
+
+ [Inject]
+ public HttpInterceptorService Interceptor { get; set; }
+
+ [Parameter] public string Account { get; set; } = "";
+
+ [Parameter] public string CompanyId { get; set; } = "";
+
+ protected override async Task OnInitializedAsync()
+ {
+ Interceptor.RegisterEvent();
+ Interceptor.RegisterBeforeSendEvent();
+ if (!string.IsNullOrWhiteSpace(Account))
+ {
+ CompanyDto = await CompanyRepo.GetCompanyByAccount(Account);
+ }
+ else
+ {
+ if (!string.IsNullOrWhiteSpace(CompanyId))
+ {
+ CompanyDto = await CompanyRepo.GetCompanyById(CompanyId);
+ }
+ }
+ }
+
+ ///
+ /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
+ ///
+ public void Dispose()
+ {
+ Interceptor!.DisposeEvent();
+ }
+}
\ No newline at end of file
diff --git a/Wonky.Client/Pages/Index.razor b/Wonky.Client/Pages/Index.razor
new file mode 100644
index 00000000..2c6d5eb7
--- /dev/null
+++ b/Wonky.Client/Pages/Index.razor
@@ -0,0 +1,25 @@
+@*
+// 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]
+//
+*@
+
+@page "/"
+@page "/index"
+@inject IWebAssemblyHostEnvironment _hostEnvironment
+
+
+
+@code{
+}
diff --git a/Wonky.Client/Pages/KrvAdmin/KrvProduct.razor b/Wonky.Client/Pages/KrvAdmin/KrvProduct.razor
new file mode 100644
index 00000000..9baf20d9
--- /dev/null
+++ b/Wonky.Client/Pages/KrvAdmin/KrvProduct.razor
@@ -0,0 +1,14 @@
+@page "/krv-product/{productId}"
+@using Microsoft.AspNetCore.Authorization
+@attribute [Authorize(Roles = "Admin")]
+
diff --git a/Wonky.Client/Pages/KrvAdmin/KrvVariantView.razor.cs b/Wonky.Client/Pages/KrvAdmin/KrvVariantView.razor.cs
new file mode 100644
index 00000000..699a9b70
--- /dev/null
+++ b/Wonky.Client/Pages/KrvAdmin/KrvVariantView.razor.cs
@@ -0,0 +1,35 @@
+using Microsoft.AspNetCore.Components;
+using Wonky.Client.HttpInterceptors;
+using Wonky.Client.HttpRepository;
+using Wonky.Entity.DTO;
+
+namespace Wonky.Client.Pages.KrvAdmin;
+
+public partial class KrvVariantView : IDisposable
+{
+ private KrvVariantDto Variant { get; set; } = new ();
+
+ [Inject]
+ public IKrvVariantHttpRepository VariantRepo { get; set; }
+
+ [Inject]
+ public HttpInterceptorService Interceptor { get; set; }
+
+ [Parameter]
+ public string VariantId { get; set; } = "";
+
+ protected override async Task OnInitializedAsync()
+ {
+ Interceptor.RegisterEvent();
+ Interceptor.RegisterBeforeSendEvent();
+ Variant = await VariantRepo.GetVariant(VariantId);
+ }
+
+ ///
+ /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
+ ///
+ public void Dispose()
+ {
+ Interceptor.DisposeEvent();
+ }
+}
\ No newline at end of file
diff --git a/Wonky.Client/Pages/KrvAdmin/KrvVariantView.razor.css b/Wonky.Client/Pages/KrvAdmin/KrvVariantView.razor.css
new file mode 100644
index 00000000..a9b07550
--- /dev/null
+++ b/Wonky.Client/Pages/KrvAdmin/KrvVariantView.razor.css
@@ -0,0 +1,10 @@
+/* variant image preview */
+.image-name {
+ margin-left: 10px;
+}
+.image-preview {
+ width: auto;
+ max-width: 200px;
+ height: 100px;
+ margin-top: 15px;
+}
\ No newline at end of file
diff --git a/Wonky.Client/Pages/Login.razor b/Wonky.Client/Pages/Login.razor
new file mode 100644
index 00000000..a3897c79
--- /dev/null
+++ b/Wonky.Client/Pages/Login.razor
@@ -0,0 +1,54 @@
+@*
+// 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]
+//
+*@
+
+@page "/login/{returnUrl?}"
+
Login
+
+@if
+ (ShowAuthError)
+{
+
+ @if (Error != null)
+ {
+ @Error
+ }
+
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Wonky.Client/Pages/Login.razor.cs b/Wonky.Client/Pages/Login.razor.cs
new file mode 100644
index 00000000..4cde5dcd
--- /dev/null
+++ b/Wonky.Client/Pages/Login.razor.cs
@@ -0,0 +1,51 @@
+// Copyright (C) 2022 FCS Frede's Computer Services.
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as
+// published by the Free Software Foundation, either version 3 of the
+// License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see [https://www.gnu.org/licenses/agpl-3.0.en.html]
+//
+
+using Microsoft.AspNetCore.Components;
+using Wonky.Client.Services;
+using Wonky.Entity.DTO;
+
+namespace Wonky.Client.Pages;
+
+public partial class Login
+{
+ private UserAuthenticationDto _userAuthenticationDto = new ();
+
+ [Inject]
+ public IAuthenticationService AuthenticationService { get; set; }
+
+ [Inject] public NavigationManager NavigationManager { get; set; }
+
+ [Parameter] public string ReturnUrl { get; set; } = "";
+ private bool ShowAuthError { get; set; }
+ private string? Error { get; set; }
+
+ private async Task ExecuteLogin()
+ {
+ ShowAuthError = false;
+
+ var result = await AuthenticationService.Login(_userAuthenticationDto);
+ if (!result.IsSuccess)
+ {
+ Error = result.ErrorMessage;
+ ShowAuthError = true;
+ }
+ else
+ {
+ var returnUrl = string.IsNullOrEmpty(ReturnUrl) ? "/companies" : ReturnUrl;
+ NavigationManager.NavigateTo(returnUrl);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Wonky.Client/Pages/Logout.razor b/Wonky.Client/Pages/Logout.razor
new file mode 100644
index 00000000..d3ea2042
--- /dev/null
+++ b/Wonky.Client/Pages/Logout.razor
@@ -0,0 +1,18 @@
+@*
+// 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]
+//
+*@
+
+@page "/logout"
diff --git a/Wonky.Client/Pages/Logout.razor.cs b/Wonky.Client/Pages/Logout.razor.cs
new file mode 100644
index 00000000..1bd8e90d
--- /dev/null
+++ b/Wonky.Client/Pages/Logout.razor.cs
@@ -0,0 +1,34 @@
+// 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 Microsoft.AspNetCore.Components;
+using Wonky.Client.Services;
+
+namespace Wonky.Client.Pages;
+
+public partial class Logout
+{
+ [Inject]
+ public IAuthenticationService AuthenticationService { get; set; }
+
+ [Inject]
+ public NavigationManager NavigationManager { get; set; }
+
+ protected override async Task OnInitializedAsync()
+ {
+ await AuthenticationService.Logout();
+ NavigationManager.NavigateTo("/");
+ }
+}
\ No newline at end of file
diff --git a/Wonky.Client/Pages/Page401.razor b/Wonky.Client/Pages/Page401.razor
new file mode 100644
index 00000000..0d14bca7
--- /dev/null
+++ b/Wonky.Client/Pages/Page401.razor
@@ -0,0 +1,37 @@
+
+@*
+// 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]
+//
+*@
+@page "/401"
+
+
+
+
+
401 - Ikke autoriseret
+
+
+
+
+
+
+
Du har ikke adgang til siden - det er alt vi ved.
+
+
+
+
+
+
+
diff --git a/Wonky.Client/Pages/Page401.razor.css b/Wonky.Client/Pages/Page401.razor.css
new file mode 100644
index 00000000..da6530ec
--- /dev/null
+++ b/Wonky.Client/Pages/Page401.razor.css
@@ -0,0 +1,6 @@
+.page401 {
+ text-align: center;
+ color: darkblue;
+ font-size: 24px;
+ box-shadow: 1px 1px 1px grey;
+}
\ No newline at end of file
diff --git a/Wonky.Client/Pages/Page404.razor b/Wonky.Client/Pages/Page404.razor
new file mode 100644
index 00000000..ec32f202
--- /dev/null
+++ b/Wonky.Client/Pages/Page404.razor
@@ -0,0 +1,45 @@
+@*
+// 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]
+//
+*@
+
+@page "/page404"
+@page "/404"
+
\ No newline at end of file
diff --git a/Wonky.Client/Pages/Page404.razor.cs b/Wonky.Client/Pages/Page404.razor.cs
new file mode 100644
index 00000000..d47639b2
--- /dev/null
+++ b/Wonky.Client/Pages/Page404.razor.cs
@@ -0,0 +1,31 @@
+// 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 Microsoft.AspNetCore.Components;
+
+namespace Wonky.Client.Pages;
+
+public partial class Page404
+{
+ [Inject]
+ public NavigationManager NavigationManager { get; set; }
+
+ public void NavigateToHome()
+ {
+ // preserving the uri for later navigation
+ var currUri = NavigationManager.Uri;
+ NavigationManager.NavigateTo("/");
+ }
+}
\ No newline at end of file
diff --git a/Wonky.Client/Pages/Page404.razor.css b/Wonky.Client/Pages/Page404.razor.css
new file mode 100644
index 00000000..d6321790
--- /dev/null
+++ b/Wonky.Client/Pages/Page404.razor.css
@@ -0,0 +1,6 @@
+.page404 {
+ text-align: center;
+ color: black;
+ font-size: 24px;
+ box-shadow: 1px 1px 1px grey;
+}
\ No newline at end of file
diff --git a/Wonky.Client/Pages/Page500.razor b/Wonky.Client/Pages/Page500.razor
new file mode 100644
index 00000000..34d117f0
--- /dev/null
+++ b/Wonky.Client/Pages/Page500.razor
@@ -0,0 +1,36 @@
+@*
+// 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]
+//
+*@
+
+@page "/error"
+@page "/500"
+
+
+
+
+
500 - Inter server fejl
+
+
+
+
+
+
+
+ Der er opstået en fejl - det er alt vi ved.
+
+
+
+
diff --git a/Wonky.Client/Pages/Page500.razor.css b/Wonky.Client/Pages/Page500.razor.css
new file mode 100644
index 00000000..05f99eee
--- /dev/null
+++ b/Wonky.Client/Pages/Page500.razor.css
@@ -0,0 +1,6 @@
+.page500 {
+ text-align: center;
+ color: black;
+ font-size: 24px;
+ box-shadow: 1px 1px 1px grey;
+}
\ No newline at end of file
diff --git a/Wonky.Client/Pages/ProductCreate.razor b/Wonky.Client/Pages/ProductCreate.razor
new file mode 100644
index 00000000..a8516adc
--- /dev/null
+++ b/Wonky.Client/Pages/ProductCreate.razor
@@ -0,0 +1,54 @@
+@*
+// 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]
+//
+*@
+
+@page "/create-product"
+@using Microsoft.AspNetCore.Authorization
+@using Microsoft.AspNetCore.Components
+@attribute [Authorize(Roles = "Admin")]
+
Opret KRV Produkt
+@* *@
+
+
+ @* *@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Wonky.Client/Pages/ProductCreate.razor.cs b/Wonky.Client/Pages/ProductCreate.razor.cs
new file mode 100644
index 00000000..b1d34b53
--- /dev/null
+++ b/Wonky.Client/Pages/ProductCreate.razor.cs
@@ -0,0 +1,87 @@
+// Copyright (C) 2022 FCS Frede's Computer Services.
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as
+// published by the Free Software Foundation, either version 3 of the
+// License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see [https://www.gnu.org/licenses/agpl-3.0.en.html]
+//
+
+using Blazored.Toast.Services;
+using Microsoft.AspNetCore.Components;
+using Microsoft.AspNetCore.Components.Forms;
+using Wonky.Client.HttpInterceptors;
+using Wonky.Client.HttpRepository;
+using Wonky.Entity.DTO;
+
+namespace Wonky.Client.Pages
+{
+ public partial class ProductCreate : IDisposable
+ {
+ private KrvProductDto _productDto { get; set; } = new();
+
+ private EditContext _editContext;
+ private bool _formInvalid = true;
+
+ [Inject]
+ public IKrvProductHttpRepository ProductRepo { get; set; }
+
+ [Inject]
+ public HttpInterceptorService Interceptor { get; set; }
+
+ [Inject]
+ public IToastService ToastService { get; set; }
+
+ [Inject]
+ public ILogger Logger { get; set; }
+
+ protected override void OnInitialized()
+ {
+ _editContext = new EditContext(_productDto);
+ _editContext.OnFieldChanged += HandleFieldChanged;
+ Interceptor.RegisterEvent();
+ Interceptor.RegisterBeforeSendEvent();
+ }
+
+ private async Task Create()
+ {
+ Logger.LogDebug($"{_productDto}");
+ await ProductRepo.CreateProduct(_productDto);
+ ToastService.ShowSuccess($"Godt så. Produktet '{_productDto.TradingName}' er oprettet.");
+ _productDto = new KrvProductDto();
+ _editContext.OnValidationStateChanged += ValidationChanged;
+ _editContext.NotifyValidationStateChanged();
+ }
+
+ private void HandleFieldChanged(object sender, FieldChangedEventArgs e)
+ {
+ _formInvalid = !_editContext.Validate();
+ StateHasChanged();
+ }
+
+ private void ValidationChanged(object sender, ValidationStateChangedEventArgs e)
+ {
+ _formInvalid = true;
+ _editContext.OnFieldChanged -= HandleFieldChanged;
+ _editContext = new EditContext(_productDto);
+ _editContext.OnFieldChanged += HandleFieldChanged;
+ _editContext.OnValidationStateChanged -= ValidationChanged;
+ }
+
+ public void Dispose()
+ {
+ Interceptor.DisposeEvent();
+ _editContext.OnFieldChanged -= HandleFieldChanged;
+ _editContext.OnValidationStateChanged -= ValidationChanged;
+ }
+
+ private void AssignImageUrl(string imgUrl) => _productDto.PictureLink = imgUrl;
+ }
+}
+
diff --git a/Wonky.Client/Pages/PurchaseOrderCreate.razor b/Wonky.Client/Pages/PurchaseOrderCreate.razor
new file mode 100644
index 00000000..7871c3a0
--- /dev/null
+++ b/Wonky.Client/Pages/PurchaseOrderCreate.razor
@@ -0,0 +1,129 @@
+@*
+// 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]
+//
+*@
+
+@page "/company/{account}/activity"
+@using Microsoft.AspNetCore.Authorization
+@attribute [Authorize(Roles = "Adviser")]
+
@_purchaseOrder.Name
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Wonky.Client/Pages/PurchaseOrderCreate.razor.cs b/Wonky.Client/Pages/PurchaseOrderCreate.razor.cs
new file mode 100644
index 00000000..12fd0c6c
--- /dev/null
+++ b/Wonky.Client/Pages/PurchaseOrderCreate.razor.cs
@@ -0,0 +1,145 @@
+// Copyright (C) 2022 FCS Frede's Computer Services.
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as
+// published by the Free Software Foundation, either version 3 of the
+// License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see [https://www.gnu.org/licenses/agpl-3.0.en.html]
+//
+
+using Blazored.LocalStorage;
+using Blazored.Toast.Services;
+using Microsoft.AspNetCore.Components;
+using Microsoft.AspNetCore.Components.Forms;
+using Wonky.Client.Helpers;
+using Wonky.Client.HttpInterceptors;
+using Wonky.Client.HttpRepository;
+using Wonky.Client.Models;
+using Wonky.Entity.DTO;
+using Wonky.Entity.Requests;
+
+namespace Wonky.Client.Pages;
+
+public partial class PurchaseOrderCreate : IDisposable
+{
+ private List SalesItemList { get; set; } = new();
+ private PurchaseOrder _purchaseOrder = new ();
+ private CompanyDto _companyDto = new();
+ private EditContext _editContext;
+ private bool _poFormInvalid = true;
+ private MetaData? MetaData { get; set; } = new();
+ private PagingParams _paging = new();
+
+
+ [Inject] public IToastService ToastService { get; set; }
+ [Inject] public NavigationManager NavigationManager { get; set; }
+ [Inject] public ICompanyHttpRepository CompanyRepo { get; set; }
+ [Inject] public HttpInterceptorService Interceptor { get; set; }
+ [Inject] public ILocalStorageService StorageService { get; set; }
+ [Inject] public ISalesItemHttpRepository SalesItemRepo { get; set; }
+ [Parameter] public string Account { get; set; }
+
+ public List Lines { get; set; } = new();
+ protected override async Task OnInitializedAsync()
+ {
+ Interceptor.RegisterEvent();
+ Interceptor.RegisterBeforeSendEvent();
+
+ var ux = await StorageService.GetItemAsync("_ux");
+
+ _companyDto = await CompanyRepo.GetCompanyByAccount(Account);
+
+ _editContext = new EditContext(_purchaseOrder);
+ _editContext.OnFieldChanged += HandleFieldChanged;
+
+ // set up indexdb identification
+ _purchaseOrder.ActivityId = Utils.GetHashFromNow();
+
+ // permanent identifications
+ _purchaseOrder.SalesRep = ux.Adviser;
+ _purchaseOrder.Account = Account;
+ _purchaseOrder.VatNumber = _companyDto.VatNumber;
+ _purchaseOrder.EMail = _companyDto.Email;
+ _purchaseOrder.Phone = _companyDto.Phone;
+ _purchaseOrder.OurRef = ux.FullName.Split(" ")[0];
+
+ _purchaseOrder.Name = _companyDto.Name;
+ _purchaseOrder.Address = _companyDto.Address1;
+ _purchaseOrder.Address2 = _companyDto.Address2;
+ _purchaseOrder.ZipCode = _companyDto.ZipCode;
+ _purchaseOrder.City = _companyDto.City;
+
+ _purchaseOrder.DlvName = _companyDto.Name;
+ _purchaseOrder.DlvAddress1 = _companyDto.Address1;
+ _purchaseOrder.DlvAddress2 = _companyDto.Address2;
+ _purchaseOrder.DlvZipCode = _companyDto.ZipCode;
+ _purchaseOrder.DlvCity = _companyDto.City;
+
+ await GetSalesItems();
+ }
+
+
+ private async Task CreateActivity()
+ {
+ await StorageService.SetItemAsync(Account, _purchaseOrder);
+
+ ToastService.ShowSuccess($"Aktivitet oprettet.");
+ }
+
+ private async Task SearchFieldChange(string? searchField)
+ {
+ _paging.PageNumber = 1;
+ _paging.SearchColumn = searchField;
+ await GetSalesItems();
+ }
+ private async Task SearchTermChanged(string? searchTerm)
+ {
+ _paging.PageNumber = 1;
+ _paging.SearchTerm = searchTerm;
+ await GetSalesItems();
+ }
+
+ private async Task OrderByChanged(string? orderBy)
+ {
+ _paging.OrderBy = orderBy;
+ await GetSalesItems();
+ }
+
+ private async Task GetSalesItems()
+ {
+ if (SalesItemRepo != null)
+ {
+ var pagingResponse = await SalesItemRepo.GetSalesItems(_paging);
+ SalesItemList = pagingResponse.Items;
+ MetaData = pagingResponse.MetaData;
+ }
+ }
+
+ private void HandleFieldChanged(object sender, FieldChangedEventArgs e)
+ {
+ _poFormInvalid = !_editContext.Validate();
+ StateHasChanged();
+ }
+ private void ValidationChanged(object sender, ValidationStateChangedEventArgs e)
+ {
+ _poFormInvalid = false;
+ _editContext.OnFieldChanged -= HandleFieldChanged;
+ _editContext = new EditContext(_purchaseOrder);
+ _editContext.OnFieldChanged += HandleFieldChanged;
+ _editContext.OnValidationStateChanged -= ValidationChanged;
+ }
+
+ public void Dispose()
+ {
+ Interceptor.DisposeEvent();
+ _editContext.OnFieldChanged -= HandleFieldChanged;
+ _editContext.OnValidationStateChanged -= ValidationChanged;
+ }
+
+}
\ No newline at end of file
diff --git a/Wonky.Client/Pages/Registration.razor b/Wonky.Client/Pages/Registration.razor
new file mode 100644
index 00000000..d87f7795
--- /dev/null
+++ b/Wonky.Client/Pages/Registration.razor
@@ -0,0 +1,66 @@
+@*
+// 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]
+//
+*@
+
+@page "/register"
+@using Microsoft.AspNetCore.Components
+
+
\ No newline at end of file
diff --git a/Wonky.Client/Pages/Registration.razor.cs b/Wonky.Client/Pages/Registration.razor.cs
new file mode 100644
index 00000000..a4f316fc
--- /dev/null
+++ b/Wonky.Client/Pages/Registration.razor.cs
@@ -0,0 +1,54 @@
+// 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 Microsoft.AspNetCore.Components;
+using Wonky.Client.Services;
+using Wonky.Entity.DTO;
+
+namespace Wonky.Client.Pages
+{
+ public partial class Registration
+ {
+ private UserRegistrationDto _userRegistration = new ();
+
+ [Inject]
+ public IAuthenticationService AuthenticationService { get; set; }
+
+ [Inject]
+ public NavigationManager NavigationManager { get; set; }
+
+ public bool ShowRegistrationErrors { get; set; }
+ public IEnumerable? Errors { get; set; }
+
+ public async Task Register()
+ {
+ ShowRegistrationErrors = false;
+
+ var result = await AuthenticationService.RegisterUser(_userRegistration);
+ if (!result.IsSuccess)
+ {
+ Errors = result.Errors;
+ ShowRegistrationErrors = true;
+ }
+ else
+ {
+ // todo: redirect to login page
+ // todo: store url
+ // var returnUrl = NavigationManager.Uri;
+ NavigationManager.NavigateTo("/login");
+ }
+ }
+ }
+}
diff --git a/Wonky.Client/Pages/ReportError.razor b/Wonky.Client/Pages/ReportError.razor
new file mode 100644
index 00000000..da38f683
--- /dev/null
+++ b/Wonky.Client/Pages/ReportError.razor
@@ -0,0 +1,25 @@
+@*
+// 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]
+//
+*@
+
+@page "/report-error/{errorCode:int}/{errorDescription}"
+
\ No newline at end of file
diff --git a/Wonky.Client/Pages/ReportError.razor.cs b/Wonky.Client/Pages/ReportError.razor.cs
new file mode 100644
index 00000000..e41b4027
--- /dev/null
+++ b/Wonky.Client/Pages/ReportError.razor.cs
@@ -0,0 +1,27 @@
+// 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 Microsoft.AspNetCore.Components;
+
+namespace Wonky.Client.Pages
+{
+ public partial class ReportError
+ {
+ [Parameter]
+ public int ErrorCode { get; set; }
+
+ [Parameter] public string ErrorDescription { get; set; } = "";
+ }
+}
diff --git a/Wonky.Client/Pages/SalesItemCatalog.razor b/Wonky.Client/Pages/SalesItemCatalog.razor
new file mode 100644
index 00000000..c1c33801
--- /dev/null
+++ b/Wonky.Client/Pages/SalesItemCatalog.razor
@@ -0,0 +1,50 @@
+@*
+// Copyright (C) 2022 FCS Frede's Computer Services.
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as
+// published by the Free Software Foundation, either version 3 of the
+// License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see [https://www.gnu.org/licenses/agpl-3.0.en.html]
+//
+*@
+
+@page "/price-catalog"
+@using Microsoft.AspNetCore.Authorization
+
+@attribute [Authorize(Roles = "Adviser,Admin")]
+
+
\ No newline at end of file
diff --git a/Wonky.Client/Pages/SalesItemCatalog.razor.cs b/Wonky.Client/Pages/SalesItemCatalog.razor.cs
new file mode 100644
index 00000000..60ecfdd2
--- /dev/null
+++ b/Wonky.Client/Pages/SalesItemCatalog.razor.cs
@@ -0,0 +1,78 @@
+// 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 Microsoft.AspNetCore.Components;
+using Wonky.Client.HttpInterceptors;
+using Wonky.Client.HttpRepository;
+using Wonky.Entity.DTO;
+using Wonky.Entity.Requests;
+
+namespace Wonky.Client.Pages;
+
+public partial class SalesItemCatalog : IDisposable
+{
+ private List SalesItemList { get; set; } = new();
+ private MetaData? MetaData { get; set; } = new();
+ private PagingParams _paging = new();
+
+ [Inject] public ISalesItemHttpRepository SalesItemRepo { get; set; }
+ [Inject] public HttpInterceptorService Interceptor { get; set; }
+
+ protected override async Task OnInitializedAsync()
+ {
+ Interceptor.RegisterEvent();
+ Interceptor.RegisterBeforeSendEvent();
+ await GetSalesItems();
+ }
+
+ private async Task SelectedPage(int page)
+ {
+ _paging.PageNumber = page;
+ await GetSalesItems();
+ }
+
+ private async Task GetSalesItems()
+ {
+ if (SalesItemRepo != null)
+ {
+ var pagingResponse = await SalesItemRepo.GetSalesItems(_paging);
+ SalesItemList = pagingResponse.Items;
+ MetaData = pagingResponse.MetaData;
+ }
+ }
+
+ private async Task SetPageSize(int pageSize)
+ {
+ _paging.PageSize = pageSize;
+ _paging.PageNumber = 1;
+ await GetSalesItems();
+ }
+
+ private async Task SearchChanged(string? searchTerm)
+ {
+ _paging.PageNumber = 1;
+ _paging.SearchTerm = searchTerm;
+ await GetSalesItems();
+ }
+
+ private async Task SortChanged(string? orderBy)
+ {
+ _paging.OrderBy = orderBy;
+ await GetSalesItems();
+ }
+
+ public void Dispose() => Interceptor.DisposeEvent();
+
+}
\ No newline at end of file
diff --git a/Wonky.Client/Pages/SalesItemView.razor b/Wonky.Client/Pages/SalesItemView.razor
new file mode 100644
index 00000000..1e643924
--- /dev/null
+++ b/Wonky.Client/Pages/SalesItemView.razor
@@ -0,0 +1,66 @@
+@*
+// 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]
+//
+*@
+
+@page "/sales-item/{salesItemId}"
+@using Microsoft.AspNetCore.Authorization
+@attribute [Authorize(Roles = "Adviser,Admin")]
+
+
+
@Item.ItemName
+
+
+
+
+
+
Navn
+
@Item.ItemName
+
+
+
Varenr
+
@Item.ItemNumber
+
+
+
+
@Item.ProductGroup
+
+
+
Kort Navn
+
@Item.ShortName
+
+
+
+
+
+
+
Priser
+
+
+
+ @foreach (var rate in Item.Rates)
+ {
+
+
@rate.Quantity
+
@rate.Rate
+
+ }
+
+
+
+
+
\ No newline at end of file
diff --git a/Wonky.Client/Pages/SalesItemView.razor.cs b/Wonky.Client/Pages/SalesItemView.razor.cs
new file mode 100644
index 00000000..dd8238eb
--- /dev/null
+++ b/Wonky.Client/Pages/SalesItemView.razor.cs
@@ -0,0 +1,50 @@
+// Copyright (C) 2022 FCS Frede's Computer Services.
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as
+// published by the Free Software Foundation, either version 3 of the
+// License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see [https://www.gnu.org/licenses/agpl-3.0.en.html]
+//
+
+using Microsoft.AspNetCore.Components;
+using Wonky.Client.HttpInterceptors;
+using Wonky.Client.HttpRepository;
+using Wonky.Entity.DTO;
+
+namespace Wonky.Client.Pages;
+
+public partial class SalesItemView : IDisposable
+{
+ private SalesItemDto Item { get; set; } = new ();
+
+ [Inject]
+ public ISalesItemHttpRepository SalesItemRepo { get; set; }
+
+ [Inject]
+ public HttpInterceptorService Interceptor { get; set; }
+
+ [Parameter]
+ public string SalesItemId { get; set; } = "";
+
+ protected override async Task OnInitializedAsync()
+ {
+ Interceptor.RegisterEvent();
+ Interceptor.RegisterBeforeSendEvent();
+ Item = await SalesItemRepo.GetSalesItem(SalesItemId);
+ }
+
+ ///
+ /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
+ ///
+ public void Dispose()
+ {
+ Interceptor!.DisposeEvent();
+ }
+}
\ No newline at end of file
diff --git a/Wonky.Client/Pages/SalesItemView.razor.css b/Wonky.Client/Pages/SalesItemView.razor.css
new file mode 100644
index 00000000..50839936
--- /dev/null
+++ b/Wonky.Client/Pages/SalesItemView.razor.css
@@ -0,0 +1,10 @@
+/* item image preview */
+.image-name {
+ margin-left: 10px;
+}
+.image-preview {
+ width: auto;
+ max-width: 200px;
+ height: 100px;
+ margin-top: 15px;
+}
\ No newline at end of file
diff --git a/Wonky.Client/Pages/Testing/Counter.razor b/Wonky.Client/Pages/Testing/Counter.razor
new file mode 100644
index 00000000..7b00c5ae
--- /dev/null
+++ b/Wonky.Client/Pages/Testing/Counter.razor
@@ -0,0 +1,36 @@
+@page "/counter"
+@using Client.V1.Components
+@using System.Security.Claims
+
+
+
+ Bruger @context.User.FindFirst(ClaimTypes.Name).Value har tilladelse
+
+
+ Bruger har IKKE tilladelse
+
+
+
+
+
+
+@code {
+ private int currentCount = 0;
+
+ [CascadingParameter]
+ public Task AuthState { get; set; }
+
+ private async void IncrementCount()
+ {
+ var authState = await AuthState;
+ var user = authState.User;
+ if(user.Identity.IsAuthenticated)
+ {
+ currentCount++;
+ }
+ else
+ {
+ currentCount--;
+ }
+ }
+}
diff --git a/Wonky.Client/Pages/Testing/JsInterop.razor b/Wonky.Client/Pages/Testing/JsInterop.razor
new file mode 100644
index 00000000..d0b22791
--- /dev/null
+++ b/Wonky.Client/Pages/Testing/JsInterop.razor
@@ -0,0 +1,77 @@
+@page "/js-interop"
+
\ No newline at end of file
diff --git a/Wonky.Client/Pages/Testing/JsInterop2.razor.cs b/Wonky.Client/Pages/Testing/JsInterop2.razor.cs
new file mode 100644
index 00000000..c155a8da
--- /dev/null
+++ b/Wonky.Client/Pages/Testing/JsInterop2.razor.cs
@@ -0,0 +1,43 @@
+using Microsoft.AspNetCore.Components;
+using Microsoft.JSInterop;
+
+namespace Wonky.Client.Pages.Testing;
+
+public partial class JsInterop2
+{
+ private MouseCoordinates _coordinates = new MouseCoordinates();
+
+ [Inject] public IJSRuntime JsRuntime { get; set; }
+
+ [JSInvokable]
+ public static string CalculateSquareRoot(int number)
+ {
+ var result = Math.Sqrt(number);
+ return $"result from {number} is {result}";
+ }
+
+ [JSInvokable("CalculateSquareRootJustResult")]
+ public static string CalculateSquareRoot(int number, bool justResult)
+ {
+ var result = Math.Sqrt(number);
+ return !justResult ? $"result from {number} is {result}" : result.ToString();
+ }
+
+ private async Task SendDotNetInstanceToJS()
+ {
+ var dotNetObjRef = DotNetObjectReference.Create(this);
+ await JsRuntime.InvokeVoidAsync("jsFunctions.registerMouseCoordinatesHandler", dotNetObjRef);
+ }
+
+ [JSInvokable]
+ public void ShowCoordinates(MouseCoordinates coordinates)
+ {
+ _coordinates = coordinates;
+ StateHasChanged();
+ }
+ public class MouseCoordinates
+ {
+ public int X { get; set; }
+ public int Y { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/Wonky.Client/Pages/Testing/JsInterop2.razor.css b/Wonky.Client/Pages/Testing/JsInterop2.razor.css
new file mode 100644
index 00000000..ebbe8075
--- /dev/null
+++ b/Wonky.Client/Pages/Testing/JsInterop2.razor.css
@@ -0,0 +1,7 @@
+.coords {
+ height: 200px;
+ width: 400px;
+ background-color: #d6d8d6;
+ text-align: center;
+ font-size: 20px;
+}
\ No newline at end of file
diff --git a/Wonky.Client/Pages/VirkDataLookup.razor b/Wonky.Client/Pages/VirkDataLookup.razor
new file mode 100644
index 00000000..ce3a64ba
--- /dev/null
+++ b/Wonky.Client/Pages/VirkDataLookup.razor
@@ -0,0 +1,38 @@
+@*
+// 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]
+//
+*@
+
+@page "/VirkData"
+Innotec Danmark
+
+
Virk CVR Database
+
+
+
CVR opslag
+
+
+
+
+
+
+
+
Adresse opslag
+
+
+
+
+
+
diff --git a/Wonky.Client/Program.cs b/Wonky.Client/Program.cs
new file mode 100644
index 00000000..d7392db4
--- /dev/null
+++ b/Wonky.Client/Program.cs
@@ -0,0 +1,67 @@
+// 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 Microsoft.AspNetCore.Components.Web;
+using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
+using Microsoft.AspNetCore.Components.Authorization;
+using Microsoft.Extensions.Options;
+using Toolbelt.Blazor.Extensions.DependencyInjection;
+using Blazored.LocalStorage;
+using Blazored.Toast;
+using Wonky.Client;
+using Wonky.Client.AuthProviders;
+using Wonky.Client.HttpInterceptors;
+using Wonky.Client.HttpRepository;
+using Wonky.Client.Services;
+using Wonky.Entity.Configuration;
+
+var builder = WebAssemblyHostBuilder.CreateDefault(args);
+builder.RootComponents.Add("#app");
+builder.RootComponents.Add("head::after");
+
+builder.Logging.AddConfiguration(builder.Configuration.GetSection("Logging"));
+
+builder.Services.AddScoped(sp => sp.GetService().CreateClient("InnoAPI"));
+
+builder.Services.AddHttpClient("InnoAPI", (sp, cl) =>
+{
+ var apiConfig = sp.GetRequiredService>();
+ cl.BaseAddress = new Uri(apiConfig.Value.BaseAddress);
+ cl.EnableIntercept(sp);
+});
+
+builder.Services.AddBlazoredToast();
+
+builder.Services.AddHttpClientInterceptor();
+
+builder.Services.Configure(builder.Configuration.GetSection("ApiConfig"));
+
+builder.Services.AddScoped();
+builder.Services.AddScoped();
+builder.Services.AddScoped();
+builder.Services.AddScoped();
+
+builder.Services.AddScoped();
+builder.Services.AddBlazoredLocalStorage();
+builder.Services.AddAuthorizationCore();
+
+builder.Services.AddScoped();
+builder.Services.AddScoped();
+builder.Services.AddScoped();
+builder.Services.AddScoped();
+
+
+// ---------------------------------------
+
+await builder.Build().RunAsync();
diff --git a/Wonky.Client/Properties/launchSettings.json b/Wonky.Client/Properties/launchSettings.json
new file mode 100644
index 00000000..ac9f3170
--- /dev/null
+++ b/Wonky.Client/Properties/launchSettings.json
@@ -0,0 +1,30 @@
+{
+ "iisSettings": {
+ "windowsAuthentication": false,
+ "anonymousAuthentication": true,
+ "iisExpress": {
+ "applicationUrl": "http://localhost:33781",
+ "sslPort": 44330
+ }
+ },
+ "profiles": {
+ "Wonky.Client": {
+ "commandName": "Project",
+ "dotnetRunMessages": true,
+ "launchBrowser": true,
+ "inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}",
+ "applicationUrl": "https://localhost:7207;http://localhost:5101",
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development"
+ }
+ },
+ "IIS Express": {
+ "commandName": "IISExpress",
+ "launchBrowser": true,
+ "inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}",
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development"
+ }
+ }
+ }
+}
diff --git a/Wonky.Client/Services/AuthenticationService.cs b/Wonky.Client/Services/AuthenticationService.cs
new file mode 100644
index 00000000..f984b3b7
--- /dev/null
+++ b/Wonky.Client/Services/AuthenticationService.cs
@@ -0,0 +1,155 @@
+// 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.Net.Http.Headers;
+using System.Net.Http.Json;
+using System.Text.Json;
+using Blazored.LocalStorage;
+using Microsoft.AspNetCore.Components.Authorization;
+using Microsoft.Extensions.Options;
+using Wonky.Client.AuthProviders;
+using Wonky.Entity.Configuration;
+using Wonky.Entity.DTO;
+
+namespace Wonky.Client.Services
+{
+ public class AuthenticationService : IAuthenticationService
+ {
+ private readonly JsonSerializerOptions _options = new() { PropertyNameCaseInsensitive = true };
+ private readonly HttpClient _client;
+ private readonly AuthenticationStateProvider _authStateProvider;
+ private readonly ILocalStorageService _localStorage;
+ private readonly IOptions _apiConfig;
+
+ public AuthenticationService(HttpClient client,
+ AuthenticationStateProvider authStateProvider,
+ ILocalStorageService localStorage, IOptions apiConfig)
+ {
+ _client = client;
+ _authStateProvider = authStateProvider;
+ _localStorage = localStorage;
+ _apiConfig = apiConfig;
+ }
+
+ public async Task RegisterUser(UserRegistrationDto userRegistrationDto)
+ {
+
+ var response = await _client
+ .PostAsJsonAsync(_apiConfig.Value.UserRegistration, userRegistrationDto);
+
+ if (response.IsSuccessStatusCode)
+ return new ResponseDto {IsSuccess = true};
+
+ var content = await response.Content
+ .ReadAsStringAsync()
+ ;
+ var result = JsonSerializer.Deserialize(content, _options);
+ return result ?? new ResponseDto();
+ }
+
+ public async Task Login(UserAuthenticationDto userAuth)
+ {
+ var credentials = new Dictionary
+ {
+ ["grant_type"] = "password",
+ ["username"] = userAuth.Email,
+ ["password"] = userAuth.Password
+ };
+ var response = await _client
+ .PostAsync(_apiConfig.Value.TokenPath, new FormUrlEncodedContent(credentials));
+
+ var resContent = await response.Content.ReadAsStringAsync();
+
+ // if not success - return error status
+ if (!response.IsSuccessStatusCode)
+ return new AuthResponseDto {IsSuccess = false, ErrorMessage = $"Kontroller indtastning"};
+
+ // process response content
+ var data = JsonSerializer.Deserialize(resContent, _options);
+
+ await _localStorage.SetItemAsync("_tx", 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);
+
+ // set default request headers using access_token
+ _client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("bearer", data.AccessToken);
+
+ var userInfo = await UserInfo();
+
+ await _localStorage.SetItemAsync("_ux", userInfo);
+
+ // notify system on state change
+ ((AuthStateProvider)_authStateProvider).NotifyUserAuthenticationAsync(data.AccessToken);
+
+ data.IsSuccess = true;
+ return data;
+ }
+
+ public async Task RefreshToken()
+ {
+ var refreshToken = await _localStorage.GetItemAsync("_rx");
+ var credentials = new Dictionary
+ {
+ ["grant_type"] = "refresh_token",
+ ["refresh_token"] = refreshToken
+ };
+
+ var response = await _client.PostAsync(_apiConfig.Value.TokenPath, new FormUrlEncodedContent(credentials));
+
+ if (response.IsSuccessStatusCode)
+ {
+ var resContent = await response.Content.ReadAsStringAsync();
+ var data = JsonSerializer.Deserialize(resContent, _options);
+
+ // set default request headers using access_token
+ _client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("bearer", data.AccessToken);
+
+ await _localStorage.SetItemAsync("_tx", 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;
+ }
+
+ return string.Empty;
+ }
+
+ public async Task Logout()
+ {
+ // clear localStorage
+ await _localStorage.RemoveItemAsync("_tx");
+ await _localStorage.RemoveItemAsync("_rx");
+ await _localStorage.RemoveItemAsync("_ux");
+ await _localStorage.RemoveItemAsync("_ex");
+ // notify system on user logout
+ ((AuthStateProvider)_authStateProvider).NotifyUserLogout();
+ // remove request headers
+ _client.DefaultRequestHeaders.Authorization = null;
+ }
+
+ public async Task UserInfo(bool write = false)
+ {
+ var infoResponse = await _client.GetAsync(_apiConfig.Value.UserInfo);
+ var infoContent = await infoResponse.Content.ReadAsStringAsync();
+ var userInfo = JsonSerializer.Deserialize(infoContent, _options);
+ if(write)
+ await _localStorage.SetItemAsync("_ux", userInfo);
+ return userInfo ?? new UserInfoDto();
+ }
+
+ }
+}
+
diff --git a/Wonky.Client/Services/IAuthenticationService.cs b/Wonky.Client/Services/IAuthenticationService.cs
new file mode 100644
index 00000000..d6a83972
--- /dev/null
+++ b/Wonky.Client/Services/IAuthenticationService.cs
@@ -0,0 +1,29 @@
+// Copyright (C) 2022 FCS Frede's Computer Services.
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as
+// published by the Free Software Foundation, either version 3 of the
+// License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see [https://www.gnu.org/licenses/agpl-3.0.en.html]
+//
+
+using Wonky.Entity.DTO;
+
+namespace Wonky.Client.Services
+{
+ public interface IAuthenticationService
+ {
+ Task RegisterUser(UserRegistrationDto userRegistrationDto);
+ Task Login(UserAuthenticationDto userAuth);
+ Task Logout();
+ Task RefreshToken();
+ Task UserInfo(bool write = false);
+ }
+}
+
diff --git a/Wonky.Client/Services/RefreshTokenService.cs b/Wonky.Client/Services/RefreshTokenService.cs
new file mode 100644
index 00000000..8a44298e
--- /dev/null
+++ b/Wonky.Client/Services/RefreshTokenService.cs
@@ -0,0 +1,50 @@
+// Copyright (C) 2022 FCS Frede's Computer Services.
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as
+// published by the Free Software Foundation, either version 3 of the
+// License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see [https://www.gnu.org/licenses/agpl-3.0.en.html]
+//
+
+using Microsoft.AspNetCore.Components.Authorization;
+
+namespace Wonky.Client.Services;
+
+public class RefreshTokenService
+{
+ private readonly AuthenticationStateProvider _authStateProvider;
+ private readonly IAuthenticationService _authService;
+ private ILogger _logger;
+
+ public RefreshTokenService(AuthenticationStateProvider authProvider,
+ IAuthenticationService authService, ILogger logger)
+ {
+ _authStateProvider = authProvider;
+ _authService = authService;
+ _logger = logger;
+ }
+
+ public async Task TryRefreshToken()
+ {
+ var authState = await _authStateProvider.GetAuthenticationStateAsync();
+
+ var user = authState.User;
+
+ var expClaim = user.FindFirst(c => c.Type.Contains("exp"))?.Value;
+
+ var expTime = DateTimeOffset.FromUnixTimeSeconds(Convert.ToInt64(expClaim));
+
+ var diff = expTime - DateTime.UtcNow;
+ return diff.TotalMinutes <= 2
+ ? await _authService.RefreshToken()
+ : string.Empty;
+ }
+
+}
\ No newline at end of file
diff --git a/Wonky.Client/Services/VirkRegistryService.cs b/Wonky.Client/Services/VirkRegistryService.cs
new file mode 100644
index 00000000..81a7ced1
--- /dev/null
+++ b/Wonky.Client/Services/VirkRegistryService.cs
@@ -0,0 +1,75 @@
+// 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.WebUtilities;
+using Microsoft.Extensions.Options;
+using Wonky.Entity.Configuration;
+using Wonky.Entity.Models;
+using Wonky.Entity.Requests;
+
+namespace Wonky.Client.Services;
+
+public class VirkRegistryService
+{
+ private readonly JsonSerializerOptions _options = new() { PropertyNameCaseInsensitive = true };
+ private readonly HttpClient _client;
+ private readonly IOptions _apiConfig;
+ private readonly List _noData = new() { new VirkRegInfo { Name = "INGEN DATA" } };
+
+ public VirkRegistryService(HttpClient client, IOptions apiConfig)
+ {
+ _client = client;
+ _apiConfig = apiConfig;
+ }
+
+ public async Task> QueryVirkRegistry(VirkParams @params)
+ {
+ if(!ValidateCvrQuery(@params))
+ {
+ throw new ArgumentException("CvrQuery does not validate");
+ }
+ var queryString = new Dictionary
+ {
+ ["vatNumber"] = @params.VatNumber,
+ ["streetName"] = @params.StreetName,
+ ["houseNumber"] = @params.HouseNumber,
+ ["zipCode"] = @params.ZipCode
+ };
+ var endpoint = QueryHelpers.AddQueryString(_apiConfig.Value.CvrLookup , queryString);
+ var response = await _client.GetAsync(endpoint);
+ var content = await response.Content.ReadAsStringAsync();
+
+ var jsonResult = JsonSerializer.Deserialize>(content, _options);
+
+ if (string.IsNullOrWhiteSpace(content) || !jsonResult.Any()) return _noData;
+
+ if (!string.IsNullOrWhiteSpace(@params.VatNumber)) return jsonResult;
+
+ var result = jsonResult
+ .Where(x => x.States[^1].State == "NORMAL")
+ .OrderBy(x => x.Name).ToList();
+
+ return result.Count == 0 ? _noData : result;
+ }
+
+ private static bool ValidateCvrQuery(VirkParams @params)
+ {
+ if (!string.IsNullOrWhiteSpace(@params.VatNumber))
+ return true;
+ return !string.IsNullOrWhiteSpace(@params.HouseNumber) && !string.IsNullOrWhiteSpace(@params.StreetName) &&
+ !string.IsNullOrWhiteSpace(@params.ZipCode);
+ }
+}
\ No newline at end of file
diff --git a/Wonky.Client/Shared/Confirmation.razor b/Wonky.Client/Shared/Confirmation.razor
new file mode 100644
index 00000000..cf53bcb0
--- /dev/null
+++ b/Wonky.Client/Shared/Confirmation.razor
@@ -0,0 +1,39 @@
+@*
+// 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]
+//
+*@
+
+
+
+
+
Bekræft handling
+
+ ×
+
+
+
@BodyMessage
+
+
+
+
+@if (_showBackdrop)
+{
+
+}
\ No newline at end of file
diff --git a/Wonky.Client/Shared/Confirmation.razor.cs b/Wonky.Client/Shared/Confirmation.razor.cs
new file mode 100644
index 00000000..d4e60393
--- /dev/null
+++ b/Wonky.Client/Shared/Confirmation.razor.cs
@@ -0,0 +1,40 @@
+// 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 Microsoft.AspNetCore.Components;
+
+namespace Wonky.Client.Shared;
+
+public partial class Confirmation
+{
+ private string _modalDisplay = "";
+ private bool _showBackdrop = false;
+ [Parameter] public string BodyMessage { get; set; } = "";
+ [Parameter] public EventCallback OnOkClicked { get; set; }
+
+ public void Show()
+ {
+ _modalDisplay = "block;";
+ _showBackdrop = true;
+ StateHasChanged();
+ }
+
+ public void Hide()
+ {
+ _modalDisplay = "none;";
+ _showBackdrop = false;
+ StateHasChanged();
+ }
+}
\ No newline at end of file
diff --git a/Wonky.Client/Shared/MainLayout.razor b/Wonky.Client/Shared/MainLayout.razor
new file mode 100644
index 00000000..5ba1d2d5
--- /dev/null
+++ b/Wonky.Client/Shared/MainLayout.razor
@@ -0,0 +1,38 @@
+@*
+// 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]
+//
+*@
+@inherits LayoutComponentBase
+
+
+
+
+
+
+
+
+
+
+
+
+ @Body
+
+
+
+
diff --git a/Wonky.Client/Shared/MainLayout.razor.css b/Wonky.Client/Shared/MainLayout.razor.css
new file mode 100644
index 00000000..c7ac7630
--- /dev/null
+++ b/Wonky.Client/Shared/MainLayout.razor.css
@@ -0,0 +1,81 @@
+.page {
+ position: relative;
+ display: flex;
+ flex-direction: column;
+}
+
+main {
+ flex: 1;
+}
+
+.sidebar {
+ background-image: linear-gradient(180deg, rgb(5, 39, 103) 0%, #3a0647 70%);
+}
+
+.top-row {
+ background-color: #f7f7f7;
+ border-bottom: 1px solid #d6d5d5;
+ justify-content: flex-end;
+ height: 3.5rem;
+ display: flex;
+ align-items: center;
+}
+
+ .top-row ::deep a, .top-row ::deep .btn-link {
+ white-space: nowrap;
+ margin-left: 1.5rem;
+ text-decoration: none;
+ }
+
+ .top-row ::deep a:hover, .top-row ::deep .btn-link:hover {
+ text-decoration: underline;
+ }
+
+ .top-row ::deep a:first-child {
+ overflow: hidden;
+ text-overflow: ellipsis;
+ }
+
+@media (max-width: 640.98px) {
+ .top-row:not(.auth) {
+ display: none;
+ }
+
+ .top-row.auth {
+ justify-content: space-between;
+ }
+
+ .top-row ::deep a, .top-row ::deep .btn-link {
+ margin-left: 0;
+ }
+}
+
+@media (min-width: 641px) {
+ .page {
+ flex-direction: row;
+ }
+
+ .sidebar {
+ width: 250px;
+ height: 100vh;
+ position: sticky;
+ top: 0;
+ }
+
+ .top-row {
+ position: sticky;
+ top: 0;
+ z-index: 1;
+ }
+
+ .top-row.auth ::deep a:first-child {
+ flex: 1;
+ text-align: right;
+ width: 0;
+ }
+
+ .top-row, article {
+ padding-left: 2rem !important;
+ padding-right: 1.5rem !important;
+ }
+}
diff --git a/Wonky.Client/Shared/NavMenu.razor b/Wonky.Client/Shared/NavMenu.razor
new file mode 100644
index 00000000..1fc7abfa
--- /dev/null
+++ b/Wonky.Client/Shared/NavMenu.razor
@@ -0,0 +1,104 @@
+@*
+// 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]
+//
+*@
+
+@inject IWebAssemblyHostEnvironment HostEnvironment
+
+
+
+
+
+
+
+
+
+
+
+
+@code {
+ private bool collapseNavMenu = true;
+
+ private string? NavMenuCssClass => collapseNavMenu ? "collapse" : null;
+
+ private void ToggleNavMenu()
+ {
+ collapseNavMenu = !collapseNavMenu;
+ }
+}
diff --git a/Wonky.Client/Shared/NavMenu.razor.css b/Wonky.Client/Shared/NavMenu.razor.css
new file mode 100644
index 00000000..e681f238
--- /dev/null
+++ b/Wonky.Client/Shared/NavMenu.razor.css
@@ -0,0 +1,62 @@
+.navbar-toggler {
+ background-color: rgba(255, 255, 255, 0.1);
+}
+
+.top-row {
+ height: 3.5rem;
+ background-color: rgba(0,0,0,0.4);
+}
+
+.navbar-brand {
+ font-size: 1.1rem;
+}
+
+.oi {
+ width: 2rem;
+ font-size: 1.1rem;
+ vertical-align: text-top;
+ top: -2px;
+}
+
+.nav-item {
+ font-size: 0.9rem;
+ padding-bottom: 0.5rem;
+}
+
+ .nav-item:first-of-type {
+ padding-top: 1rem;
+ }
+
+ .nav-item:last-of-type {
+ padding-bottom: 1rem;
+ }
+
+ .nav-item ::deep a {
+ color: #d7d7d7;
+ border-radius: 4px;
+ height: 3rem;
+ display: flex;
+ align-items: center;
+ line-height: 3rem;
+ }
+
+.nav-item ::deep a.active {
+ background-color: rgba(255,255,255,0.25);
+ color: white;
+}
+
+.nav-item ::deep a:hover {
+ background-color: rgba(255,255,255,0.1);
+ color: white;
+}
+
+@media (min-width: 641px) {
+ .navbar-toggler {
+ display: none;
+ }
+
+ .collapse {
+ /* Never collapse the sidebar for wide screens */
+ display: block;
+ }
+}
diff --git a/Wonky.Client/Shared/PoStateProvider.razor b/Wonky.Client/Shared/PoStateProvider.razor
new file mode 100644
index 00000000..2ffcc492
--- /dev/null
+++ b/Wonky.Client/Shared/PoStateProvider.razor
@@ -0,0 +1,27 @@
+@*
+// 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]
+//
+*@
+
+@if (hasLoaded)
+{
+
+ @ChildContent
+
+}
+else
+{
+
Indlæser...
+}
\ No newline at end of file
diff --git a/Wonky.Client/Shared/PoStateProvider.razor.cs b/Wonky.Client/Shared/PoStateProvider.razor.cs
new file mode 100644
index 00000000..01391e7a
--- /dev/null
+++ b/Wonky.Client/Shared/PoStateProvider.razor.cs
@@ -0,0 +1,45 @@
+// Copyright (C) 2022 FCS Frede's Computer Services.
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as
+// published by the Free Software Foundation, either version 3 of the
+// License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see [https://www.gnu.org/licenses/agpl-3.0.en.html]
+//
+
+using Blazored.LocalStorage;
+using Microsoft.AspNetCore.Components;
+using Wonky.Client.Models;
+
+namespace Wonky.Client.Shared;
+
+public partial class PoStateProvider
+{
+ [Parameter] public RenderFragment ChildContent { get; set; }
+ public PurchaseOrder PurchaseOrder { get; set; }
+ [Parameter] public string Account { get; set; } = "";
+ [Inject] public ILocalStorageService LocalStorageService { get; set; }
+
+ private bool hasLoaded;
+
+ protected override async Task OnParametersSetAsync()
+ {
+ PurchaseOrder = await LocalStorageService.GetItemAsync(Account);
+
+ if (PurchaseOrder == null || PurchaseOrder.Lines.Count == 0)
+ PurchaseOrder = new PurchaseOrder();
+
+ hasLoaded = true;
+ }
+
+ public async Task SaveChangesAsync()
+ {
+ await LocalStorageService.SetItemAsync(Account, PurchaseOrder);
+ }
+}
\ No newline at end of file
diff --git a/Wonky.Client/Shared/ProductImageUpload.razor b/Wonky.Client/Shared/ProductImageUpload.razor
new file mode 100644
index 00000000..bde94dbe
--- /dev/null
+++ b/Wonky.Client/Shared/ProductImageUpload.razor
@@ -0,0 +1,30 @@
+@*
+// 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]
+//
+*@
+
+
+
+
+ @_fileUploadMessage
+
+@if (!string.IsNullOrEmpty(ImgUrl))
+{
+
+
+
+}
\ No newline at end of file
diff --git a/Wonky.Client/Shared/ProductImageUpload.razor.cs b/Wonky.Client/Shared/ProductImageUpload.razor.cs
new file mode 100644
index 00000000..aabab342
--- /dev/null
+++ b/Wonky.Client/Shared/ProductImageUpload.razor.cs
@@ -0,0 +1,62 @@
+// 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.Net.Http.Headers;
+using Microsoft.AspNetCore.Components;
+using Microsoft.AspNetCore.Components.Forms;
+using Wonky.Client.HttpRepository;
+
+namespace Wonky.Client.Shared
+{
+ public partial class ProductImageUpload
+ {
+ private string _fileUploadMessage = "Ingen fil valgt";
+
+ [Parameter]
+ public string ImgUrl { get; set; } = "";
+
+ [Parameter]
+ public string ProductId { get; set; } = "";
+ private EventCallback OnChange { get; set; }
+
+ [Inject]
+ public IKrvProductHttpRepository ProductRepo { get; set; }
+
+ private async Task HandleSelected(InputFileChangeEventArgs e)
+ {
+ var imageFile = e.File;
+ if (imageFile.Size == 0)
+ return;
+
+ _fileUploadMessage = string.Empty;
+ _fileUploadMessage += $"{imageFile.Name}";
+
+ var resizedFile = await imageFile.RequestImageFileAsync("image/png", 500, 500);
+
+ await using var ms = resizedFile.OpenReadStream(resizedFile.Size);
+
+ var content = new MultipartFormDataContent();
+
+ content.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data");
+
+ content.Add(new StreamContent(ms,
+ Convert.ToInt32(resizedFile.Size)), "image", imageFile.Name);
+
+ ImgUrl = await ProductRepo.UploadImage(content, ProductId);
+
+ await OnChange.InvokeAsync(ImgUrl);
+ }
+ }
+}
diff --git a/Wonky.Client/Shared/ProductImageUpload.razor.css b/Wonky.Client/Shared/ProductImageUpload.razor.css
new file mode 100644
index 00000000..97d15716
--- /dev/null
+++ b/Wonky.Client/Shared/ProductImageUpload.razor.css
@@ -0,0 +1,8 @@
+/* product image upload */
+.image-name {
+ margin-left: 10px;
+}
+.image-preview {
+ width: 300px;
+ margin-top: 15px;
+}
\ No newline at end of file
diff --git a/Wonky.Client/Shared/VariantImageUpload.razor b/Wonky.Client/Shared/VariantImageUpload.razor
new file mode 100644
index 00000000..c826f4bb
--- /dev/null
+++ b/Wonky.Client/Shared/VariantImageUpload.razor
@@ -0,0 +1,31 @@
+@*
+// 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]
+//
+*@
+
+
+
+
+ @_fileUploadMessage
+
+@if(!string.IsNullOrWhiteSpace(PictureLink))
+{
+
` all receive top and bottom margins. We nuke the top\n// margin for easier control within type scales as it avoids margin collapsing.\n\n%heading {\n margin-top: 0; // 1\n margin-bottom: $headings-margin-bottom;\n font-family: $headings-font-family;\n font-style: $headings-font-style;\n font-weight: $headings-font-weight;\n line-height: $headings-line-height;\n color: $headings-color;\n}\n\nh1 {\n @extend %heading;\n @include font-size($h1-font-size);\n}\n\nh2 {\n @extend %heading;\n @include font-size($h2-font-size);\n}\n\nh3 {\n @extend %heading;\n @include font-size($h3-font-size);\n}\n\nh4 {\n @extend %heading;\n @include font-size($h4-font-size);\n}\n\nh5 {\n @extend %heading;\n @include font-size($h5-font-size);\n}\n\nh6 {\n @extend %heading;\n @include font-size($h6-font-size);\n}\n\n\n// Reset margins on paragraphs\n//\n// Similarly, the top margin on `
`s get reset. However, we also reset the\n// bottom margin to use `rem` units instead of `em`.\n\np {\n margin-top: 0;\n margin-bottom: $paragraph-margin-bottom;\n}\n\n\n// Abbreviations\n//\n// 1. Duplicate behavior to the data-bs-* attribute for our tooltip plugin\n// 2. Add the correct text decoration in Chrome, Edge, Opera, and Safari.\n// 3. Add explicit cursor to indicate changed behavior.\n// 4. Prevent the text-decoration to be skipped.\n\nabbr[title],\nabbr[data-bs-original-title] { // 1\n text-decoration: underline dotted; // 2\n cursor: help; // 3\n text-decoration-skip-ink: none; // 4\n}\n\n\n// Address\n\naddress {\n margin-bottom: 1rem;\n font-style: normal;\n line-height: inherit;\n}\n\n\n// Lists\n\nol,\nul {\n padding-left: 2rem;\n}\n\nol,\nul,\ndl {\n margin-top: 0;\n margin-bottom: 1rem;\n}\n\nol ol,\nul ul,\nol ul,\nul ol {\n margin-bottom: 0;\n}\n\ndt {\n font-weight: $dt-font-weight;\n}\n\n// 1. Undo browser default\n\ndd {\n margin-bottom: .5rem;\n margin-left: 0; // 1\n}\n\n\n// Blockquote\n\nblockquote {\n margin: 0 0 1rem;\n}\n\n\n// Strong\n//\n// Add the correct font weight in Chrome, Edge, and Safari\n\nb,\nstrong {\n font-weight: $font-weight-bolder;\n}\n\n\n// Small\n//\n// Add the correct font size in all browsers\n\nsmall {\n @include font-size($small-font-size);\n}\n\n\n// Mark\n\nmark {\n padding: $mark-padding;\n background-color: $mark-bg;\n}\n\n\n// Sub and Sup\n//\n// Prevent `sub` and `sup` elements from affecting the line height in\n// all browsers.\n\nsub,\nsup {\n position: relative;\n @include font-size($sub-sup-font-size);\n line-height: 0;\n vertical-align: baseline;\n}\n\nsub { bottom: -.25em; }\nsup { top: -.5em; }\n\n\n// Links\n\na {\n color: $link-color;\n text-decoration: $link-decoration;\n\n &:hover {\n color: $link-hover-color;\n text-decoration: $link-hover-decoration;\n }\n}\n\n// And undo these styles for placeholder links/named anchors (without href).\n// It would be more straightforward to just use a[href] in previous block, but that\n// causes specificity issues in many other styles that are too complex to fix.\n// See https://github.com/twbs/bootstrap/issues/19402\n\na:not([href]):not([class]) {\n &,\n &:hover {\n color: inherit;\n text-decoration: none;\n }\n}\n\n\n// Code\n\npre,\ncode,\nkbd,\nsamp {\n font-family: $font-family-code;\n @include font-size(1em); // Correct the odd `em` font sizing in all browsers.\n direction: ltr #{\"/* rtl:ignore */\"};\n unicode-bidi: bidi-override;\n}\n\n// 1. Remove browser default top margin\n// 2. Reset browser default of `1em` to use `rem`s\n// 3. Don't allow content to break outside\n\npre {\n display: block;\n margin-top: 0; // 1\n margin-bottom: 1rem; // 2\n overflow: auto; // 3\n @include font-size($code-font-size);\n color: $pre-color;\n\n // Account for some code outputs that place code tags in pre tags\n code {\n @include font-size(inherit);\n color: inherit;\n word-break: normal;\n }\n}\n\ncode {\n @include font-size($code-font-size);\n color: $code-color;\n word-wrap: break-word;\n\n // Streamline the style when inside anchors to avoid broken underline and more\n a > & {\n color: inherit;\n }\n}\n\nkbd {\n padding: $kbd-padding-y $kbd-padding-x;\n @include font-size($kbd-font-size);\n color: $kbd-color;\n background-color: $kbd-bg;\n @include border-radius($border-radius-sm);\n\n kbd {\n padding: 0;\n @include font-size(1em);\n font-weight: $nested-kbd-font-weight;\n }\n}\n\n\n// Figures\n//\n// Apply a consistent margin strategy (matches our type styles).\n\nfigure {\n margin: 0 0 1rem;\n}\n\n\n// Images and content\n\nimg,\nsvg {\n vertical-align: middle;\n}\n\n\n// Tables\n//\n// Prevent double borders\n\ntable {\n caption-side: bottom;\n border-collapse: collapse;\n}\n\ncaption {\n padding-top: $table-cell-padding-y;\n padding-bottom: $table-cell-padding-y;\n color: $table-caption-color;\n text-align: left;\n}\n\n// 1. Removes font-weight bold by inheriting\n// 2. Matches default `
` alignment by inheriting `text-align`.\n// 3. Fix alignment for Safari\n\nth {\n font-weight: $table-th-font-weight; // 1\n text-align: inherit; // 2\n text-align: -webkit-match-parent; // 3\n}\n\nthead,\ntbody,\ntfoot,\ntr,\ntd,\nth {\n border-color: inherit;\n border-style: solid;\n border-width: 0;\n}\n\n\n// Forms\n//\n// 1. Allow labels to use `margin` for spacing.\n\nlabel {\n display: inline-block; // 1\n}\n\n// Remove the default `border-radius` that macOS Chrome adds.\n// See https://github.com/twbs/bootstrap/issues/24093\n\nbutton {\n // stylelint-disable-next-line property-disallowed-list\n border-radius: 0;\n}\n\n// Explicitly remove focus outline in Chromium when it shouldn't be\n// visible (e.g. as result of mouse click or touch tap). It already\n// should be doing this automatically, but seems to currently be\n// confused and applies its very visible two-tone outline anyway.\n\nbutton:focus:not(:focus-visible) {\n outline: 0;\n}\n\n// 1. Remove the margin in Firefox and Safari\n\ninput,\nbutton,\nselect,\noptgroup,\ntextarea {\n margin: 0; // 1\n font-family: inherit;\n @include font-size(inherit);\n line-height: inherit;\n}\n\n// Remove the inheritance of text transform in Firefox\nbutton,\nselect {\n text-transform: none;\n}\n// Set the cursor for non-`