diff --git a/NetinaShop.AdminPanel.PWA/Components/Originals/SideBarUi.razor b/NetinaShop.AdminPanel.PWA/Components/Originals/SideBarUi.razor new file mode 100644 index 0000000..f9b6ffe --- /dev/null +++ b/NetinaShop.AdminPanel.PWA/Components/Originals/SideBarUi.razor @@ -0,0 +1,73 @@ +@inject NavigationManager NavigationManager + + + + @* *@ + + + + +
+ @item.Text +
+
+
+
+
+ +
+ + @code + { + + + private void SelectedChange(TreeItemData? data) + { + if (data != null) + NavigationManager.NavigateTo(data.Page); + } + private HashSet TreeItems { get; set; } = new HashSet(); + + public class TreeItemData + { + public string Text { get; set; } + + public string Icon { get; set; } + + public string Page { get; set; } + + private bool _isActive; + + public bool IsActive + { + get { return _isActive; } + set + { + + _isActive = value; + } + } + + + public HashSet TreeItems { get; set; } = new HashSet(); + + public TreeItemData(string text, string icon, string page) + { + Page = page; + Text = text; + Icon = icon; + } + } + + protected override void OnInitialized() + { + TreeItems.Add(new TreeItemData("داشبورد", Icons.Material.Outlined.Dashboard, "HomePage")); + TreeItems.Add(new TreeItemData("فروش", Icons.Material.Outlined.ShoppingCart, "ProductsPage")); + TreeItems.Add(new TreeItemData("محصولات", Icons.Material.Outlined.CenterFocusStrong, "ProductsPage")); + TreeItems.Add(new TreeItemData("دسته بندی ها", Icons.Material.Outlined.AllInbox, "CategoriesPage")); + TreeItems.Add(new TreeItemData("برند ها", Icons.Custom.Brands.Facebook, "BrandsPage")); + TreeItems.Add(new TreeItemData("مشترکین", Icons.Material.Outlined.People, "ProductsPage")); + TreeItems.Add(new TreeItemData("وبلاگ", Icons.Material.Outlined.Web, "ProductsPage")); + TreeItems.Add(new TreeItemData("تنظیمات", Icons.Material.Outlined.Settings, "ProductsPage")); + } +} \ No newline at end of file diff --git a/NetinaShop.AdminPanel.PWA/Dialogs/Originals/QuestionDialog.razor b/NetinaShop.AdminPanel.PWA/Dialogs/Originals/QuestionDialog.razor new file mode 100644 index 0000000..94ce7e7 --- /dev/null +++ b/NetinaShop.AdminPanel.PWA/Dialogs/Originals/QuestionDialog.razor @@ -0,0 +1,24 @@ + + +

@ContentText

+
+ +
+ تایید + + انصراف +
+
+
+@code +{ + + [CascadingParameter] + MudDialogInstance? MudDialog { get; set; } + + [Parameter] + public string ContentText { get; set; } = string.Empty; + + void Submit() => MudDialog?.Close(DialogResult.Ok(true)); + void Cancel() => MudDialog?.Cancel(); +} \ No newline at end of file diff --git a/NetinaShop.AdminPanel.PWA/Dialogs/ProductActionDialogBox.razor b/NetinaShop.AdminPanel.PWA/Dialogs/ProductActionDialogBox.razor new file mode 100644 index 0000000..dc65e5e --- /dev/null +++ b/NetinaShop.AdminPanel.PWA/Dialogs/ProductActionDialogBox.razor @@ -0,0 +1,80 @@ +@using Radzen.Blazor + + + + + + + اطلاعات کلی + اطلاعات کلی محصول را به دقت وارد کنید + + + + + + + + + + + + + + + + + + + + + + + + + + + توضیحات تکمیلی + می توانید توضیحاتــ تکمیلی محصول را کامل وارد کنید + + + + + + + + + + + + + + + + + + + + + + + + تصاویر محصول + می توانید برای محصول چند تصویر اپلود کنید + + + + + + + تایید + بستن + + + + +@code { + [CascadingParameter] MudDialogInstance MudDialog { get; set; } + + void Submit() => MudDialog.Close(DialogResult.Ok(true)); + void Cancel() => MudDialog.Cancel(); +} \ No newline at end of file diff --git a/NetinaShop.AdminPanel.PWA/Dialogs/ProductCategoryActionDialogBox.razor b/NetinaShop.AdminPanel.PWA/Dialogs/ProductCategoryActionDialogBox.razor new file mode 100644 index 0000000..0f7ee14 --- /dev/null +++ b/NetinaShop.AdminPanel.PWA/Dialogs/ProductCategoryActionDialogBox.razor @@ -0,0 +1,95 @@ +@using Blazorise.Extensions +@inject ISnackbar Snackbar +@inject IRestWrapper RestWrapper + + + + + + + + اطلاعات کلی + اطلاعات کلی دسته بندی محصول را به دقت وارد کنید + + + + + + + + + + + + + + + + +
+ +

منتظر بمانید

+
+
+
+
+ +

@e.Name

+
+
+
+ + + + +
+
+
+ + + تایید + بستن + + + +
+@code { + [CascadingParameter] MudDialogInstance MudDialog { get; set; } + + void Submit() => MudDialog.Close(DialogResult.Ok(true)); + void Cancel() => MudDialog.Cancel(); + + + private List _productCategories = new List(); + private ProductCategorySDto? _selectedCategory; + private async Task> SearchCity(string city) + { + try + { + if (_productCategories.Count == 0) + { + _productCategories = await RestWrapper.CrudDtoApiRest(Address.ProductCategoryController).ReadAll(); + } + if (city.IsNullOrEmpty()) + return _productCategories; + return _productCategories.Where(c => c.Name.Contains(city)); + } + catch (ApiException ex) + { + var exe = await ex.GetContentAsAsync(); + if (exe != null) + Snackbar.Add(exe.Message, Severity.Error); + Snackbar.Add(ex.Content, Severity.Error); + return _productCategories; + } + catch (Exception e) + { + Snackbar.Add(e.Message, Severity.Error); + return _productCategories; + } + } +} \ No newline at end of file diff --git a/NetinaShop.AdminPanel.PWA/Layout/MainLayout.razor b/NetinaShop.AdminPanel.PWA/Layout/MainLayout.razor index 3b200f6..8d218c6 100644 --- a/NetinaShop.AdminPanel.PWA/Layout/MainLayout.razor +++ b/NetinaShop.AdminPanel.PWA/Layout/MainLayout.razor @@ -1,7 +1,4 @@ -@using Toolbelt.Blazor.PWA.Updater -@using Toolbelt.Blazor.PWA.Updater.Service -@using MudBlazor -@inherits LayoutComponentBase +@inherits LayoutComponentBase @inject IPWAUpdaterService PwaUpdaterService @@ -31,12 +28,39 @@ -
- @Body -
- -
-
+ + + + + + + + + امیرحسین خادمی + 09214802813 + + + + + + + + + + + + + + + +
+ @Body +
+ +
+
+
+
@code @@ -52,13 +76,13 @@ }, Palette = new PaletteLight() { - Primary = "#356859", - Secondary = "#FD5523", + Primary = "#001A46", + Secondary = "#E59F2E", }, PaletteDark = new PaletteDark() { - Primary = "#356859", - Secondary = "#FD5523", + Primary = "#001A46", + Secondary = "#E59F2E", } }; diff --git a/NetinaShop.AdminPanel.PWA/Models/Address.cs b/NetinaShop.AdminPanel.PWA/Models/Address.cs new file mode 100644 index 0000000..22cd41f --- /dev/null +++ b/NetinaShop.AdminPanel.PWA/Models/Address.cs @@ -0,0 +1,14 @@ +namespace NetinaShop.AdminPanel.PWA.Models; + +public static class Address +{ +#if DEBUG + //public static string BaseAddress = "http://localhost:32770/api"; + public static string BaseAddress = "https://apinetinashop.visabartar.com/api"; +#else + public static string BaseAddress = "https://apinetinashop.visabartar.com/api"; +#endif + public static string AuthController = $"{BaseAddress}/auth"; + public static string UserController = $"{BaseAddress}/user"; + public static string ProductCategoryController = $"{BaseAddress}/product/category"; +} \ No newline at end of file diff --git a/NetinaShop.AdminPanel.PWA/Models/Api/ApiResult.cs b/NetinaShop.AdminPanel.PWA/Models/Api/ApiResult.cs new file mode 100644 index 0000000..830cfeb --- /dev/null +++ b/NetinaShop.AdminPanel.PWA/Models/Api/ApiResult.cs @@ -0,0 +1,28 @@ +using NetinaShop.Common.Extensions; +using NetinaShop.Common.Models.Api; + +namespace NetinaShop.AdminPanel.PWA.Models.Api; + +public class ApiResult +{ + public ApiResult(bool isSuccess, ApiResultStatusCode statusCode, string message = null) + { + IsSuccess = isSuccess; + StatusCode = statusCode; + Message = message ?? statusCode.ToDisplay(); + } + + public bool IsSuccess { get; set; } + public ApiResultStatusCode StatusCode { get; set; } + + public string Message { get; set; } +} + +public class ApiResult : ApiResult where TData : class +{ + public ApiResult(bool isSuccess, ApiResultStatusCode statusCode, TData data, string message = null) : base(isSuccess, statusCode, message) + { + Data = data; + } + public TData Data { get; set; } +} \ No newline at end of file diff --git a/NetinaShop.AdminPanel.PWA/Models/BaseViewModel.cs b/NetinaShop.AdminPanel.PWA/Models/BaseViewModel.cs new file mode 100644 index 0000000..e633512 --- /dev/null +++ b/NetinaShop.AdminPanel.PWA/Models/BaseViewModel.cs @@ -0,0 +1,33 @@ +namespace NetinaShop.AdminPanel.PWA.Models; + +public class BaseViewModel +{ + public bool IsProcessing { get; set; } = false; + + public virtual void Initialize() + { + + } + public virtual Task InitializeAsync() + { + return Task.CompletedTask; + } +} + +public class BaseViewModel +{ + public bool IsProcessing { get; set; } = false; + public TPageDto PageDto { get; set; } + public BaseViewModel() + { + PageDto = Activator.CreateInstance(); + } + public virtual void Initialize() + { + + } + public virtual Task InitializeAsync() + { + return Task.CompletedTask; + } +} \ No newline at end of file diff --git a/NetinaShop.AdminPanel.PWA/Models/LocalStorageKeys.cs b/NetinaShop.AdminPanel.PWA/Models/LocalStorageKeys.cs new file mode 100644 index 0000000..32e7cd0 --- /dev/null +++ b/NetinaShop.AdminPanel.PWA/Models/LocalStorageKeys.cs @@ -0,0 +1,7 @@ +namespace NetinaShop.AdminPanel.PWA.Models; + +public static class LocalStorageKeys +{ + public const string Token = nameof(Token); + public const string UserInfo = nameof(UserInfo); +} \ No newline at end of file diff --git a/NetinaShop.AdminPanel.PWA/NetinaShop.AdminPanel.PWA.csproj b/NetinaShop.AdminPanel.PWA/NetinaShop.AdminPanel.PWA.csproj index 3171793..ce257a5 100644 --- a/NetinaShop.AdminPanel.PWA/NetinaShop.AdminPanel.PWA.csproj +++ b/NetinaShop.AdminPanel.PWA/NetinaShop.AdminPanel.PWA.csproj @@ -1,4 +1,4 @@ - + net8.0 @@ -18,14 +18,35 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/NetinaShop.AdminPanel.PWA/Pages/BrandsPage.razor b/NetinaShop.AdminPanel.PWA/Pages/BrandsPage.razor new file mode 100644 index 0000000..3691a9b --- /dev/null +++ b/NetinaShop.AdminPanel.PWA/Pages/BrandsPage.razor @@ -0,0 +1,7 @@ +@page "/BrandsPage" + +

BrandsPage

+ +@code { + +} diff --git a/NetinaShop.AdminPanel.PWA/Pages/CategoriesPage.razor b/NetinaShop.AdminPanel.PWA/Pages/CategoriesPage.razor new file mode 100644 index 0000000..e902692 --- /dev/null +++ b/NetinaShop.AdminPanel.PWA/Pages/CategoriesPage.razor @@ -0,0 +1,77 @@ +@page "/CategoriesPage" +@using NetinaShop.AdminPanel.PWA.Utilities +@inject IDialogService DialogService +@inject NavigationManager NavigationManager +@inject IRestWrapper RestWrapper +@inject ISnackbar Snackbar +@inject IUserUtility UserUtility + + + + + + + دسته بندی ها + 124 عدد + + + افزودن دسته بندی + + + + + + + + + + + + @if (@context.Item.IsMain) + { +

بلی

+ } + else + { +

خیر

+ + } +
+
+ + + + + + + + +
+
+
+
+
+
+ +@code +{ + public CategoriesPageViewModel ViewModel { get; set; } + protected override async Task OnInitializedAsync() + { + ViewModel = new CategoriesPageViewModel(NavigationManager, Snackbar, UserUtility, RestWrapper, DialogService); + await ViewModel.InitializeAsync(); + await base.OnInitializedAsync(); + } + +} diff --git a/NetinaShop.AdminPanel.PWA/Pages/CategoriesPage.razor.cs b/NetinaShop.AdminPanel.PWA/Pages/CategoriesPage.razor.cs new file mode 100644 index 0000000..46e552d --- /dev/null +++ b/NetinaShop.AdminPanel.PWA/Pages/CategoriesPage.razor.cs @@ -0,0 +1,98 @@ +using Microsoft.AspNetCore.Components; +using Microsoft.JSInterop; +using MudBlazor; +using NetinaShop.AdminPanel.PWA.Dialogs; +using NetinaShop.AdminPanel.PWA.Dialogs.Originals; +using NetinaShop.AdminPanel.PWA.Models.Api; +using NetinaShop.AdminPanel.PWA.Services.RestServices; +using NetinaShop.AdminPanel.PWA.Utilities; +using NetinaShop.Domain.Entities.ProductCategories; + +namespace NetinaShop.AdminPanel.PWA.Pages; + +public class CategoriesPageViewModel : BaseViewModel> +{ + private readonly NavigationManager _navigationManager; + private readonly ISnackbar _snackbar; + private readonly IUserUtility _userUtility; + private readonly IDialogService _dialogService; + private readonly IRestWrapper _restWrapper; + + public CategoriesPageViewModel(NavigationManager navigationManager, ISnackbar snackbar, IUserUtility userUtility, IRestWrapper restWrapper, IDialogService dialogService) + { + _navigationManager = navigationManager; + _snackbar = snackbar; + _userUtility = userUtility; + _restWrapper = restWrapper; + _dialogService = dialogService; + } + + public override async Task InitializeAsync() + { + try + { + IsProcessing = true; + var dto = await _restWrapper.CrudDtoApiRest(Address.ProductCategoryController) + .ReadAll(); + PageDto = dto; + } + catch (ApiException ex) + { + var exe = await ex.GetContentAsAsync(); + _snackbar.Add(exe != null ? exe.Message : ex.Content, Severity.Error); + } + catch (Exception e) + { + _snackbar.Add(e.Message, Severity.Error); + } + finally + { + + IsProcessing = false; + } + await base.InitializeAsync(); + } + + public async Task AddProductClicked() + { + DialogOptions maxWidth = new DialogOptions() { MaxWidth = MaxWidth.Medium, FullWidth = true, DisableBackdropClick = true }; + await _dialogService.ShowAsync("افزودن دسته جدید", maxWidth); + } + + public async Task DeleteProductCategoryAsync(Guid selectedCategoryId) + { + var options = new DialogOptions { CloseOnEscapeKey = true }; + var parameters = new DialogParameters(); + parameters.Add(x => x.ContentText, "آیا از حذف دسته بندی اطمینان دارید ?"); + var dialogReference = await _dialogService.ShowAsync("حذف شرح حال", parameters, options); + var result = await dialogReference.Result; + if (!result.Canceled) + { + + try + { + + IsProcessing = true; + var token = await _userUtility.GetBearerTokenAsync(); + await _restWrapper.CrudDtoApiRest(Address.ProductCategoryController) + .Delete(selectedCategoryId, token); + _snackbar.Add("حذف دسته بندی با موفقیت انجام شد", Severity.Success); + + } + catch (ApiException ex) + { + var exe = await ex.GetContentAsAsync(); + _snackbar.Add(exe != null ? exe.Message : ex.Content, Severity.Error); + } + catch (Exception e) + { + _snackbar.Add(e.Message, Severity.Error); + } + finally + { + + IsProcessing = false; + } + } + } +} \ No newline at end of file diff --git a/NetinaShop.AdminPanel.PWA/Pages/Home.razor b/NetinaShop.AdminPanel.PWA/Pages/Home.razor index 9001e0b..43565ac 100644 --- a/NetinaShop.AdminPanel.PWA/Pages/Home.razor +++ b/NetinaShop.AdminPanel.PWA/Pages/Home.razor @@ -1,7 +1,7 @@ -@page "/" +@page "/HomePage" -Home + + -

Hello, world!

- -Welcome to your new app. +
+
\ No newline at end of file diff --git a/NetinaShop.AdminPanel.PWA/Pages/ProductsPage.razor b/NetinaShop.AdminPanel.PWA/Pages/ProductsPage.razor new file mode 100644 index 0000000..dcbf687 --- /dev/null +++ b/NetinaShop.AdminPanel.PWA/Pages/ProductsPage.razor @@ -0,0 +1,95 @@ +@page "/ProductsPage" +@using NetinaShop.AdminPanel.PWA.Dialogs +@inject IDialogService DialogService + + + + + + محصولاتــــ + 124 عدد + + افزودن محصول + + + + + + + + + + + + + + + + + + + + + + + +@code +{ + List Products { get; set; } = new List(); + protected override Task OnInitializedAsync() + { + Products.Add(new ProductSDto + { + PersianName = "شامپو ضدشوره هد اند شولدرز (Head & Shoulders) مدل Lemon 2in1 arada حجم 350 میلی لیتر", + BrandNames = "شوریدر", + CategoryName = "شوینده سر", + Cost = 1200000, + + }); + Products.Add(new ProductSDto + { + PersianName = "شامپو ضدشوره هد اند شولدرز (Head & Shoulders) مدل Lemon 2in1 arada حجم 350 میلی لیتر", + BrandNames = "شوریدر", + CategoryName = "شوینده سر", + Cost = 1200000, + + }); + Products.Add(new ProductSDto + { + PersianName = "شامپو ضدشوره هد اند شولدرز (Head & Shoulders) مدل Lemon 2in1 arada حجم 350 میلی لیتر", + BrandNames = "شوریدر", + CategoryName = "شوینده سر", + Cost = 1200000, + + }); + Products.Add(new ProductSDto + { + PersianName = "شامپو ضدشوره هد اند شولدرز (Head & Shoulders) مدل Lemon 2in1 arada حجم 350 میلی لیتر", + BrandNames = "شوریدر", + CategoryName = "شوینده سر", + Cost = 1200000, + + }); + Products.Add(new ProductSDto + { + PersianName = "شامپو ضدشوره هد اند شولدرز (Head & Shoulders) مدل Lemon 2in1 arada حجم 350 میلی لیتر", + BrandNames = "شوریدر", + CategoryName = "شوینده سر", + Cost = 1200000, + + }); + return base.OnInitializedAsync(); + } + + private async Task AddProductClicked() + { + DialogOptions maxWidth = new DialogOptions() { MaxWidth = MaxWidth.Medium, FullWidth = true }; + var options = new DialogOptions { CloseOnEscapeKey = true , Position = DialogPosition.Center, MaxWidth = MaxWidth.Large , DisableBackdropClick = true}; + await DialogService.ShowAsync("افزودن محصول جدید", maxWidth); + } +} diff --git a/NetinaShop.AdminPanel.PWA/Program.cs b/NetinaShop.AdminPanel.PWA/Program.cs index 6a57b0f..6e81247 100644 --- a/NetinaShop.AdminPanel.PWA/Program.cs +++ b/NetinaShop.AdminPanel.PWA/Program.cs @@ -4,6 +4,8 @@ using Microsoft.AspNetCore.Components.WebAssembly.Hosting; using MudBlazor; using MudBlazor.Services; using NetinaShop.AdminPanel.PWA; +using NetinaShop.AdminPanel.PWA.Services.RestServices; +using NetinaShop.AdminPanel.PWA.Utilities; using Toolbelt.Blazor.Extensions.DependencyInjection; var builder = WebAssemblyHostBuilder.CreateDefault(args); @@ -18,6 +20,8 @@ builder.Services.AddMudServices(config => config.SnackbarConfiguration.PositionClass = Defaults.Classes.Position.BottomCenter; }); +builder.Services.AddScoped(); +builder.Services.AddScoped(); builder.Services.AddBlazoredLocalStorage(); builder.Services.AddPWAUpdater(); await builder.Build().RunAsync(); diff --git a/NetinaShop.AdminPanel.PWA/Services/RestServices/IAuthRestApi.cs b/NetinaShop.AdminPanel.PWA/Services/RestServices/IAuthRestApi.cs new file mode 100644 index 0000000..1229c3b --- /dev/null +++ b/NetinaShop.AdminPanel.PWA/Services/RestServices/IAuthRestApi.cs @@ -0,0 +1,13 @@ +namespace NetinaShop.AdminPanel.PWA.Services.RestServices; + +public interface IAuthRestApi +{ + [Get("/verifycode")] + public Task GetVerifyCodeAsync([Query] string phoneNumber); + + [Post("/login/code")] + public Task> LoginWithVerifyCodeAsync([Body] LoginRequestDto request); + + [Post("/signup")] + public Task> CompleteSignUpAsync([Body] SignUpRequestDto request, [Header("Authorization")] string authorization); +} \ No newline at end of file diff --git a/NetinaShop.AdminPanel.PWA/Services/RestServices/ICrudApiRest.cs b/NetinaShop.AdminPanel.PWA/Services/RestServices/ICrudApiRest.cs new file mode 100644 index 0000000..53d7e56 --- /dev/null +++ b/NetinaShop.AdminPanel.PWA/Services/RestServices/ICrudApiRest.cs @@ -0,0 +1,47 @@ +using Refit; + +namespace NetinaShop.AdminPanel.PWA.Services.RestServices; + +public interface ICrudApiRest where T : class +{ + [Post("")] + Task Create([Body] T payload, [Header("Authorization")] string authorization); + + [Get("")] + Task> ReadAll([Query] int page,[Header("Authorization")] string authorization); + + [Get("/{key}")] + Task ReadOne(TKey key, [Header("Authorization")] string authorization); + + [Put("")] + Task Update([Body] T payload, [Header("Authorization")] string authorization); + + [Delete("/{key}")] + Task Delete(TKey key, [Header("Authorization")] string authorization); + +} +public interface ICrudDtoApiRest where T : class where TDto : class +{ + [Post("")] + Task Create([Body] T payload, [Header("Authorization")] string authorization); + [Post("")] + Task Create([Body] TDto payload, [Header("Authorization")] string authorization); + + [Get("")] + Task> ReadAll([Query]int page,[Header("Authorization")] string authorization); + + [Get("")] + Task> ReadAll(); + + [Get("/{key}")] + Task ReadOne(TKey key, [Header("Authorization")] string authorization); + + [Put("")] + Task Update([Body] T payload, [Header("Authorization")] string authorization); + [Put("")] + Task Update([Body] TDto payload, [Header("Authorization")] string authorization); + + [Delete("/{key}")] + Task Delete(TKey key, [Header("Authorization")] string authorization); + +} \ No newline at end of file diff --git a/NetinaShop.AdminPanel.PWA/Services/RestServices/IRestWrapper.cs b/NetinaShop.AdminPanel.PWA/Services/RestServices/IRestWrapper.cs new file mode 100644 index 0000000..d9f7d31 --- /dev/null +++ b/NetinaShop.AdminPanel.PWA/Services/RestServices/IRestWrapper.cs @@ -0,0 +1,11 @@ +namespace NetinaShop.AdminPanel.PWA.Services.RestServices; + +public interface IRestWrapper +{ + public ICrudApiRest CrudApiRest(string address) where T : class; + public ICrudDtoApiRest CrudDtoApiRest(string address) where T : class where TDto : class; + + + public IAuthRestApi AuthRestApi { get; } + public IUserRestApi UserRestApi { get; } +} \ No newline at end of file diff --git a/NetinaShop.AdminPanel.PWA/Services/RestServices/IUserRestApi.cs b/NetinaShop.AdminPanel.PWA/Services/RestServices/IUserRestApi.cs new file mode 100644 index 0000000..a3cbcdf --- /dev/null +++ b/NetinaShop.AdminPanel.PWA/Services/RestServices/IUserRestApi.cs @@ -0,0 +1,9 @@ +namespace NetinaShop.AdminPanel.PWA.Services.RestServices; + +public interface IUserRestApi +{ + + + [Put("")] + Task UpdateUserAsync([Body]UserActionRequestDto request, [Header("Authorization")] string authorization); +} \ No newline at end of file diff --git a/NetinaShop.AdminPanel.PWA/Services/RestServices/RestWrapper.cs b/NetinaShop.AdminPanel.PWA/Services/RestServices/RestWrapper.cs new file mode 100644 index 0000000..793da03 --- /dev/null +++ b/NetinaShop.AdminPanel.PWA/Services/RestServices/RestWrapper.cs @@ -0,0 +1,23 @@ +namespace NetinaShop.AdminPanel.PWA.Services.RestServices; + +public class RestWrapper : IRestWrapper +{ + + private static RefitSettings setting = new RefitSettings(new NewtonsoftJsonContentSerializer(new JsonSerializerSettings + { + Formatting = Newtonsoft.Json.Formatting.Indented, + ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore, + + })); + + public ICrudApiRest CrudApiRest(string address) where T : class + { + return RestService.For>(address, setting); + } + public ICrudDtoApiRest CrudDtoApiRest(string address) where T : class where TDto : class + { + return RestService.For>(address, setting); + } + public IAuthRestApi AuthRestApi => RestService.For(Address.AuthController, setting); + public IUserRestApi UserRestApi => RestService.For(Address.UserController, setting); +} \ No newline at end of file diff --git a/NetinaShop.AdminPanel.PWA/Utilities/IUserUtility.cs b/NetinaShop.AdminPanel.PWA/Utilities/IUserUtility.cs new file mode 100644 index 0000000..39276b8 --- /dev/null +++ b/NetinaShop.AdminPanel.PWA/Utilities/IUserUtility.cs @@ -0,0 +1,11 @@ +namespace NetinaShop.AdminPanel.PWA.Utilities; + +public interface IUserUtility +{ + public Task GetBearerTokenAsync(); + public Task SetBearerTokenAsync(string token); + public Task GetUserAsync(); + public Task SetUserAsync(ApplicationUserSDto user); + public Task LogoutAsync(); + +} \ No newline at end of file diff --git a/NetinaShop.AdminPanel.PWA/Utilities/UserUtility.cs b/NetinaShop.AdminPanel.PWA/Utilities/UserUtility.cs new file mode 100644 index 0000000..812948f --- /dev/null +++ b/NetinaShop.AdminPanel.PWA/Utilities/UserUtility.cs @@ -0,0 +1,26 @@ +namespace NetinaShop.AdminPanel.PWA.Utilities; + +public class UserUtility : IUserUtility +{ + private readonly ILocalStorageService _localStorageService; + + public UserUtility(ILocalStorageService localStorageService) + { + _localStorageService = localStorageService; + } + + public async Task GetBearerTokenAsync() => await _localStorageService.GetItemAsStringAsync(LocalStorageKeys.Token); + public async Task SetBearerTokenAsync(string token) => await _localStorageService.SetItemAsStringAsync(LocalStorageKeys.Token, token); + + public async Task GetUserAsync() => await _localStorageService.GetItemAsync(LocalStorageKeys.UserInfo); + public async Task SetUserAsync(ApplicationUserSDto user) => await _localStorageService.SetItemAsync(LocalStorageKeys.UserInfo, user); + public async Task LogoutAsync() + { + await _localStorageService.RemoveItemAsync(LocalStorageKeys.Token); + await _localStorageService.RemoveItemAsync(LocalStorageKeys.UserInfo); + } + + //public AccessToken? AccessToken { get; set; } + //public List UserClaims => AccessToken == null ? new List() : AccessToken.Permissions; + //public bool HasPermissionTo(string permission) => UserClaims.Any(c => c == permission); +} \ No newline at end of file diff --git a/NetinaShop.AdminPanel.PWA/Utilities/UtilityWrapper.cs b/NetinaShop.AdminPanel.PWA/Utilities/UtilityWrapper.cs new file mode 100644 index 0000000..eb72432 --- /dev/null +++ b/NetinaShop.AdminPanel.PWA/Utilities/UtilityWrapper.cs @@ -0,0 +1,11 @@ +namespace NetinaShop.AdminPanel.PWA.Utilities; + +public class UtilityWrapper +{ + private static UtilityWrapper? _instance; + public static UtilityWrapper Instance + { + get { return _instance ??= new UtilityWrapper(); } + } + +} \ No newline at end of file diff --git a/NetinaShop.AdminPanel.PWA/_Imports.razor b/NetinaShop.AdminPanel.PWA/_Imports.razor index 1e9ad3c..6a75c3d 100644 --- a/NetinaShop.AdminPanel.PWA/_Imports.razor +++ b/NetinaShop.AdminPanel.PWA/_Imports.razor @@ -8,3 +8,16 @@ @using Microsoft.JSInterop @using NetinaShop.AdminPanel.PWA @using NetinaShop.AdminPanel.PWA.Layout +@using MudBlazor +@using Toolbelt.Blazor.PWA.Updater.Service +@using Toolbelt.Blazor.PWA.Updater +@using NetinaShop.AdminPanel.PWA.Components.Originals +@using NetinaShop.Domain.Dtos.SmallDtos +@using NetinaShop.AdminPanel.PWA.Dialogs +@using NetinaShop.Common.Models.Api +@using NetinaShop.Common.Extensions +@using NetinaShop.AdminPanel.PWA.Models.Api +@using NetinaShop.AdminPanel.PWA.Models +@using Refit +@using NetinaShop.Domain.Entities.ProductCategories +@using NetinaShop.AdminPanel.PWA.Services.RestServices \ No newline at end of file diff --git a/NetinaShop.AdminPanel.PWA/tailwind.config.js b/NetinaShop.AdminPanel.PWA/tailwind.config.js index ba45062..e22dfef 100644 --- a/NetinaShop.AdminPanel.PWA/tailwind.config.js +++ b/NetinaShop.AdminPanel.PWA/tailwind.config.js @@ -24,23 +24,6 @@ module.exports = { "iranyekan": ["'iranyekan'"], }, extend: { - colors: { - secondary: { - 100: "#0a202b", - 200: "#0f222b", - 300: "#162830", - 400: "#192930", - 500: "#1c2b31", - 600: "#1e2b30", - 700: "#1d272b", - 800: "#21292c", - 900: "#212729", - }, - visa2: { - 100: "#F0BC5E", - 200: "#eca521", - }, - }, } } } diff --git a/NetinaShop.AdminPanel.PWA/wwwroot/css/app.css b/NetinaShop.AdminPanel.PWA/wwwroot/css/app.css index 75770c5..d90bca3 100644 --- a/NetinaShop.AdminPanel.PWA/wwwroot/css/app.css +++ b/NetinaShop.AdminPanel.PWA/wwwroot/css/app.css @@ -88,10 +88,9 @@ } :root { - --color-primary: rgba(53, 104, 89, 1); - --color-secondary: rgba(253, 85, 35, 1); - --color-medicalhistory: rgba(253, 216, 53, 1); - --color-medicalhistory-template: rgba(41, 187, 189, 1); + --color-primary: rgba(9, 16, 68, 1); + --color-secondary: rgba(229, 159, 46, 1); + --color-background: rgba(243, 244, 246, 1); } } diff --git a/NetinaShop.AdminPanel.PWA/wwwroot/css/app.min.css b/NetinaShop.AdminPanel.PWA/wwwroot/css/app.min.css index 1f8b14b..6ab7b13 100644 --- a/NetinaShop.AdminPanel.PWA/wwwroot/css/app.min.css +++ b/NetinaShop.AdminPanel.PWA/wwwroot/css/app.min.css @@ -397,10 +397,9 @@ video { } :root { - --color-primary: rgba(53, 104, 89, 1); - --color-secondary: rgba(253, 85, 35, 1); - --color-medicalhistory: rgba(253, 216, 53, 1); - --color-medicalhistory-template: rgba(41, 187, 189, 1); + --color-primary: rgba(9, 16, 68, 1); + --color-secondary: rgba(229, 159, 46, 1); + --color-background: rgba(243, 244, 246, 1); } *, ::before, ::after { @@ -502,12 +501,94 @@ video { --tw-backdrop-saturate: ; --tw-backdrop-sepia: ; } -.table { - display: table; +.mx-4 { + margin-left: 1rem; + margin-right: 1rem; +} +.mx-auto { + margin-left: auto; + margin-right: auto; +} +.my-1 { + margin-top: 0.25rem; + margin-bottom: 0.25rem; +} +.my-auto { + margin-top: auto; + margin-bottom: auto; +} +.-ml-4 { + margin-left: -1rem; +} +.-mt-3 { + margin-top: -0.75rem; +} +.mb-10 { + margin-bottom: 2.5rem; +} +.mb-5 { + margin-bottom: 1.25rem; +} +.mr-1 { + margin-right: 0.25rem; +} +.mr-2 { + margin-right: 0.5rem; +} +.mt-3 { + margin-top: 0.75rem; +} +.mt-4 { + margin-top: 1rem; +} +.mt-5 { + margin-top: 1.25rem; +} +.flex { + display: flex; +} +.h-screen { + height: 100vh; +} +.w-full { + width: 100%; +} +.w-screen { + width: 100vw; +} +.flex-row { + flex-direction: row; +} +.justify-end { + justify-content: flex-end; } .border { border-width: 1px; } +.bg-\[--color-background\] { + background-color: var(--color-background); +} +.bg-white { + --tw-bg-opacity: 1; + background-color: rgb(255 255 255 / var(--tw-bg-opacity)); +} +.p-8 { + padding: 2rem; +} +.py-2 { + padding-top: 0.5rem; + padding-bottom: 0.5rem; +} +.py-3 { + padding-top: 0.75rem; + padding-bottom: 0.75rem; +} +.pt-8 { + padding-top: 2rem; +} +.font-bold { + font-weight: 700; +} @font-face { font-family: iranyekan; diff --git a/NetinaShop.AdminPanel.PWA/wwwroot/css/app.output.css b/NetinaShop.AdminPanel.PWA/wwwroot/css/app.output.css new file mode 100644 index 0000000..67cbfdc --- /dev/null +++ b/NetinaShop.AdminPanel.PWA/wwwroot/css/app.output.css @@ -0,0 +1,886 @@ +/* +! tailwindcss v3.4.1 | MIT License | https://tailwindcss.com +*/ + +/* +1. Prevent padding and border from affecting element width. (https://github.com/mozdevs/cssremedy/issues/4) +2. Allow adding a border to an element by just adding a border-width. (https://github.com/tailwindcss/tailwindcss/pull/116) +*/ + +*, +::before, +::after { + box-sizing: border-box; + /* 1 */ + border-width: 0; + /* 2 */ + border-style: solid; + /* 2 */ + border-color: #e5e7eb; + /* 2 */ +} + +::before, +::after { + --tw-content: ''; +} + +/* +1. Use a consistent sensible line-height in all browsers. +2. Prevent adjustments of font size after orientation changes in iOS. +3. Use a more readable tab size. +4. Use the user's configured `sans` font-family by default. +5. Use the user's configured `sans` font-feature-settings by default. +6. Use the user's configured `sans` font-variation-settings by default. +7. Disable tap highlights on iOS +*/ + +html, +:host { + line-height: 1.5; + /* 1 */ + -webkit-text-size-adjust: 100%; + /* 2 */ + -moz-tab-size: 4; + /* 3 */ + -o-tab-size: 4; + tab-size: 4; + /* 3 */ + font-family: ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; + /* 4 */ + font-feature-settings: normal; + /* 5 */ + font-variation-settings: normal; + /* 6 */ + -webkit-tap-highlight-color: transparent; + /* 7 */ +} + +/* +1. Remove the margin in all browsers. +2. Inherit line-height from `html` so users can set them as a class directly on the `html` element. +*/ + +body { + margin: 0; + /* 1 */ + line-height: inherit; + /* 2 */ +} + +/* +1. Add the correct height in Firefox. +2. Correct the inheritance of border color in Firefox. (https://bugzilla.mozilla.org/show_bug.cgi?id=190655) +3. Ensure horizontal rules are visible by default. +*/ + +hr { + height: 0; + /* 1 */ + color: inherit; + /* 2 */ + border-top-width: 1px; + /* 3 */ +} + +/* +Add the correct text decoration in Chrome, Edge, and Safari. +*/ + +abbr:where([title]) { + -webkit-text-decoration: underline dotted; + text-decoration: underline dotted; +} + +/* +Remove the default font size and weight for headings. +*/ + +h1, +h2, +h3, +h4, +h5, +h6 { + font-size: inherit; + font-weight: inherit; +} + +/* +Reset links to optimize for opt-in styling instead of opt-out. +*/ + +a { + color: inherit; + text-decoration: inherit; +} + +/* +Add the correct font weight in Edge and Safari. +*/ + +b, +strong { + font-weight: bolder; +} + +/* +1. Use the user's configured `mono` font-family by default. +2. Use the user's configured `mono` font-feature-settings by default. +3. Use the user's configured `mono` font-variation-settings by default. +4. Correct the odd `em` font sizing in all browsers. +*/ + +code, +kbd, +samp, +pre { + font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; + /* 1 */ + font-feature-settings: normal; + /* 2 */ + font-variation-settings: normal; + /* 3 */ + font-size: 1em; + /* 4 */ +} + +/* +Add the correct font size in all browsers. +*/ + +small { + font-size: 80%; +} + +/* +Prevent `sub` and `sup` elements from affecting the line height in all browsers. +*/ + +sub, +sup { + font-size: 75%; + line-height: 0; + position: relative; + vertical-align: baseline; +} + +sub { + bottom: -0.25em; +} + +sup { + top: -0.5em; +} + +/* +1. Remove text indentation from table contents in Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=999088, https://bugs.webkit.org/show_bug.cgi?id=201297) +2. Correct table border color inheritance in all Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=935729, https://bugs.webkit.org/show_bug.cgi?id=195016) +3. Remove gaps between table borders by default. +*/ + +table { + text-indent: 0; + /* 1 */ + border-color: inherit; + /* 2 */ + border-collapse: collapse; + /* 3 */ +} + +/* +1. Change the font styles in all browsers. +2. Remove the margin in Firefox and Safari. +3. Remove default padding in all browsers. +*/ + +button, +input, +optgroup, +select, +textarea { + font-family: inherit; + /* 1 */ + font-feature-settings: inherit; + /* 1 */ + font-variation-settings: inherit; + /* 1 */ + font-size: 100%; + /* 1 */ + font-weight: inherit; + /* 1 */ + line-height: inherit; + /* 1 */ + color: inherit; + /* 1 */ + margin: 0; + /* 2 */ + padding: 0; + /* 3 */ +} + +/* +Remove the inheritance of text transform in Edge and Firefox. +*/ + +button, +select { + text-transform: none; +} + +/* +1. Correct the inability to style clickable types in iOS and Safari. +2. Remove default button styles. +*/ + +button, +[type='button'], +[type='reset'], +[type='submit'] { + -webkit-appearance: button; + /* 1 */ + background-color: transparent; + /* 2 */ + background-image: none; + /* 2 */ +} + +/* +Use the modern Firefox focus style for all focusable elements. +*/ + +:-moz-focusring { + outline: auto; +} + +/* +Remove the additional `:invalid` styles in Firefox. (https://github.com/mozilla/gecko-dev/blob/2f9eacd9d3d995c937b4251a5557d95d494c9be1/layout/style/res/forms.css#L728-L737) +*/ + +:-moz-ui-invalid { + box-shadow: none; +} + +/* +Add the correct vertical alignment in Chrome and Firefox. +*/ + +progress { + vertical-align: baseline; +} + +/* +Correct the cursor style of increment and decrement buttons in Safari. +*/ + +::-webkit-inner-spin-button, +::-webkit-outer-spin-button { + height: auto; +} + +/* +1. Correct the odd appearance in Chrome and Safari. +2. Correct the outline style in Safari. +*/ + +[type='search'] { + -webkit-appearance: textfield; + /* 1 */ + outline-offset: -2px; + /* 2 */ +} + +/* +Remove the inner padding in Chrome and Safari on macOS. +*/ + +::-webkit-search-decoration { + -webkit-appearance: none; +} + +/* +1. Correct the inability to style clickable types in iOS and Safari. +2. Change font properties to `inherit` in Safari. +*/ + +::-webkit-file-upload-button { + -webkit-appearance: button; + /* 1 */ + font: inherit; + /* 2 */ +} + +/* +Add the correct display in Chrome and Safari. +*/ + +summary { + display: list-item; +} + +/* +Removes the default spacing and border for appropriate elements. +*/ + +blockquote, +dl, +dd, +h1, +h2, +h3, +h4, +h5, +h6, +hr, +figure, +p, +pre { + margin: 0; +} + +fieldset { + margin: 0; + padding: 0; +} + +legend { + padding: 0; +} + +ol, +ul, +menu { + list-style: none; + margin: 0; + padding: 0; +} + +/* +Reset default styling for dialogs. +*/ + +dialog { + padding: 0; +} + +/* +Prevent resizing textareas horizontally by default. +*/ + +textarea { + resize: vertical; +} + +/* +1. Reset the default placeholder opacity in Firefox. (https://github.com/tailwindlabs/tailwindcss/issues/3300) +2. Set the default placeholder color to the user's configured gray 400 color. +*/ + +input::-moz-placeholder, textarea::-moz-placeholder { + opacity: 1; + /* 1 */ + color: #9ca3af; + /* 2 */ +} + +input::placeholder, +textarea::placeholder { + opacity: 1; + /* 1 */ + color: #9ca3af; + /* 2 */ +} + +/* +Set the default cursor for buttons. +*/ + +button, +[role="button"] { + cursor: pointer; +} + +/* +Make sure disabled buttons don't get the pointer cursor. +*/ + +:disabled { + cursor: default; +} + +/* +1. Make replaced elements `display: block` by default. (https://github.com/mozdevs/cssremedy/issues/14) +2. Add `vertical-align: middle` to align replaced elements more sensibly by default. (https://github.com/jensimmons/cssremedy/issues/14#issuecomment-634934210) + This can trigger a poorly considered lint error in some tools but is included by design. +*/ + +img, +svg, +video, +canvas, +audio, +iframe, +embed, +object { + display: block; + /* 1 */ + vertical-align: middle; + /* 2 */ +} + +/* +Constrain images and videos to the parent width and preserve their intrinsic aspect ratio. (https://github.com/mozdevs/cssremedy/issues/14) +*/ + +img, +video { + max-width: 100%; + height: auto; +} + +/* Make elements with the HTML hidden attribute stay hidden by default */ + +[hidden] { + display: none; +} + +* { + font-family: iranyekan; +} + +:root { + --color-primary: rgba(9, 16, 68, 1); + --color-secondary: rgba(229, 159, 46, 1); + --color-background: rgba(243, 244, 246, 1); +} + +*, ::before, ::after { + --tw-border-spacing-x: 0; + --tw-border-spacing-y: 0; + --tw-translate-x: 0; + --tw-translate-y: 0; + --tw-rotate: 0; + --tw-skew-x: 0; + --tw-skew-y: 0; + --tw-scale-x: 1; + --tw-scale-y: 1; + --tw-pan-x: ; + --tw-pan-y: ; + --tw-pinch-zoom: ; + --tw-scroll-snap-strictness: proximity; + --tw-gradient-from-position: ; + --tw-gradient-via-position: ; + --tw-gradient-to-position: ; + --tw-ordinal: ; + --tw-slashed-zero: ; + --tw-numeric-figure: ; + --tw-numeric-spacing: ; + --tw-numeric-fraction: ; + --tw-ring-inset: ; + --tw-ring-offset-width: 0px; + --tw-ring-offset-color: #fff; + --tw-ring-color: rgb(59 130 246 / 0.5); + --tw-ring-offset-shadow: 0 0 #0000; + --tw-ring-shadow: 0 0 #0000; + --tw-shadow: 0 0 #0000; + --tw-shadow-colored: 0 0 #0000; + --tw-blur: ; + --tw-brightness: ; + --tw-contrast: ; + --tw-grayscale: ; + --tw-hue-rotate: ; + --tw-invert: ; + --tw-saturate: ; + --tw-sepia: ; + --tw-drop-shadow: ; + --tw-backdrop-blur: ; + --tw-backdrop-brightness: ; + --tw-backdrop-contrast: ; + --tw-backdrop-grayscale: ; + --tw-backdrop-hue-rotate: ; + --tw-backdrop-invert: ; + --tw-backdrop-opacity: ; + --tw-backdrop-saturate: ; + --tw-backdrop-sepia: ; +} + +::backdrop { + --tw-border-spacing-x: 0; + --tw-border-spacing-y: 0; + --tw-translate-x: 0; + --tw-translate-y: 0; + --tw-rotate: 0; + --tw-skew-x: 0; + --tw-skew-y: 0; + --tw-scale-x: 1; + --tw-scale-y: 1; + --tw-pan-x: ; + --tw-pan-y: ; + --tw-pinch-zoom: ; + --tw-scroll-snap-strictness: proximity; + --tw-gradient-from-position: ; + --tw-gradient-via-position: ; + --tw-gradient-to-position: ; + --tw-ordinal: ; + --tw-slashed-zero: ; + --tw-numeric-figure: ; + --tw-numeric-spacing: ; + --tw-numeric-fraction: ; + --tw-ring-inset: ; + --tw-ring-offset-width: 0px; + --tw-ring-offset-color: #fff; + --tw-ring-color: rgb(59 130 246 / 0.5); + --tw-ring-offset-shadow: 0 0 #0000; + --tw-ring-shadow: 0 0 #0000; + --tw-shadow: 0 0 #0000; + --tw-shadow-colored: 0 0 #0000; + --tw-blur: ; + --tw-brightness: ; + --tw-contrast: ; + --tw-grayscale: ; + --tw-hue-rotate: ; + --tw-invert: ; + --tw-saturate: ; + --tw-sepia: ; + --tw-drop-shadow: ; + --tw-backdrop-blur: ; + --tw-backdrop-brightness: ; + --tw-backdrop-contrast: ; + --tw-backdrop-grayscale: ; + --tw-backdrop-hue-rotate: ; + --tw-backdrop-invert: ; + --tw-backdrop-opacity: ; + --tw-backdrop-saturate: ; + --tw-backdrop-sepia: ; +} + +.mx-4 { + margin-left: 1rem; + margin-right: 1rem; +} + +.mx-auto { + margin-left: auto; + margin-right: auto; +} + +.my-1 { + margin-top: 0.25rem; + margin-bottom: 0.25rem; +} + +.my-auto { + margin-top: auto; + margin-bottom: auto; +} + +.-ml-4 { + margin-left: -1rem; +} + +.-mt-3 { + margin-top: -0.75rem; +} + +.mb-10 { + margin-bottom: 2.5rem; +} + +.mb-5 { + margin-bottom: 1.25rem; +} + +.mr-1 { + margin-right: 0.25rem; +} + +.mr-2 { + margin-right: 0.5rem; +} + +.mt-4 { + margin-top: 1rem; +} + +.mt-5 { + margin-top: 1.25rem; +} + +.mt-3 { + margin-top: 0.75rem; +} + +.flex { + display: flex; +} + +.h-screen { + height: 100vh; +} + +.w-full { + width: 100%; +} + +.w-screen { + width: 100vw; +} + +.flex-row { + flex-direction: row; +} + +.justify-end { + justify-content: flex-end; +} + +.border { + border-width: 1px; +} + +.bg-\[--color-background\] { + background-color: var(--color-background); +} + +.bg-white { + --tw-bg-opacity: 1; + background-color: rgb(255 255 255 / var(--tw-bg-opacity)); +} + +.p-8 { + padding: 2rem; +} + +.py-2 { + padding-top: 0.5rem; + padding-bottom: 0.5rem; +} + +.py-3 { + padding-top: 0.75rem; + padding-bottom: 0.75rem; +} + +.pt-8 { + padding-top: 2rem; +} + +.font-bold { + font-weight: 700; +} + +@font-face { + font-family: iranyekan; + + font-style: normal; + + font-weight: bold; + + src: url('../assets/fonts/eot/iranyekanwebboldfanum.eot'); + + src: url('../assets/fonts/eot/iranyekanwebboldfanum.eot?#iefix') format('embedded-opentype'), /* IE6-8 */ + url('../assets/fonts/woff/iranyekanwebboldfanum.woff') format('woff'), /* FF3.6+, IE9, Chrome6+, Saf5.1+*/ + url('../assets/fonts/ttf/iranyekanwebboldfanum.ttf') format('truetype'); +} + +@font-face { + font-family: iranyekan; + + font-style: normal; + + font-weight: 100; + + src: url('../assets/fonts/eot/iranyekanwebthinfanum.eot'); + + src: url('../assets/fonts/eot/iranyekanwebthinfanum.eot?#iefix') format('embedded-opentype'), /* IE6-8 */ + url('../assets/fonts/woff/iranyekanwebthinfanum.woff') format('woff'), /* FF3.6+, IE9, Chrome6+, Saf5.1+*/ + url('../assets/fonts/ttf/iranyekanwebthinfanum.ttf') format('truetype'); +} + +@font-face { + font-family: iranyekan; + + font-style: normal; + + font-weight: 300; + + src: url('../assets/fonts/eot/iranyekanweblightfanum.eot'); + + src: url('../assets/fonts/eot/iranyekanweblightfanum.eot?#iefix') format('embedded-opentype'), /* IE6-8 */ + url('../assets/fonts/woff/iranyekanweblightfanum.woff') format('woff'), /* FF3.6+, IE9, Chrome6+, Saf5.1+*/ + url('../assets/fonts/ttf/iranyekanweblightfanum.ttf') format('truetype'); +} + +@font-face { + font-family: iranyekan; + + font-style: normal; + + font-weight: normal; + + src: url('../assets/fonts/eot/iranyekanwebregularfanum.eot'); + + src: url('../assets/fonts/eot/iranyekanwebregularfanum.eot?#iefix') format('embedded-opentype'), /* IE6-8 */ + url('../assets/fonts/woff/iranyekanwebregularfanum.woff') format('woff'), /* FF3.6+, IE9, Chrome6+, Saf5.1+*/ + url('../assets/fonts/ttf/iranyekanwebregularfanum.ttf') format('truetype'); +} + +@font-face { + font-family: iranyekan; + + font-style: normal; + + font-weight: 500; + + src: url('../assets/fonts/eot/iranyekanwebmediumfanum.eot'); + + src: url('../assets/fonts/eot/iranyekanwebmediumfanum.eot?#iefix') format('embedded-opentype'), /* IE6-8 */ + url('../assets/fonts/woff/iranyekanwebmediumfanum.woff') format('woff'), /* FF3.6+, IE9, Chrome6+, Saf5.1+*/ + url('../assets/fonts/ttf/iranyekanwebmediumfanum.ttf') format('truetype'); +} + +@font-face { + font-family: iranyekan; + + font-style: normal; + + font-weight: 800; + + src: url('../assets/fonts/eot/iranyekanwebextraboldfanum.eot'); + + src: url('../assets/fonts/eot/iranyekanwebextraboldfanum.eot?#iefix') format('embedded-opentype'), /* IE6-8 */ + url('../assets/fonts/woff/iranyekanwebextraboldfanum.woff') format('woff'), /* FF3.6+, IE9, Chrome6+, Saf5.1+*/ + url('../assets/fonts/ttf/iranyekanwebextraboldfanum.ttf') format('truetype'); +} + +@font-face { + font-family: iranyekan; + + font-style: normal; + + font-weight: 900; + + src: url('../assets/fonts/eot/iranyekanwebblackfanum.eot'); + + src: url('../assets/fonts/eot/iranyekanwebblackfanum.eot?#iefix') format('embedded-opentype'), /* IE6-8 */ + url('../assets/fonts/woff/iranyekanwebblackfanum.woff') format('woff'), /* FF3.6+, IE9, Chrome6+, Saf5.1+*/ + url('../assets/fonts/ttf/iranyekanwebblackfanum.ttf') format('truetype'); +} + +@font-face { + font-family: iranyekan; + + font-style: normal; + + font-weight: 950; + + src: url('../assets/fonts/eot/iranyekanwebextrablackfanum.eot'); + + src: url('../assets/fonts/eot/iranyekanwebextrablackfanum.eot?#iefix') format('embedded-opentype'), /* IE6-8 */ + url('../assets/fonts/woff/iranyekanwebextrablackfanum.woff') format('woff'), /* FF3.6+, IE9, Chrome6+, Saf5.1+*/ + url('../assets/fonts/ttf/iranyekanwebextrablackfanum.ttf') format('truetype'); +} + +.mud-dialog-title { + font-family: iranyekan !important; +} + +h1:focus { + outline: none; +} + +a, .btn-link { + color: #0071c1; +} + +.btn-primary { + color: #fff; + background-color: #1b6ec2; + border-color: #1861ac; +} + +.btn:focus, .btn:active:focus, .btn-link.nav-link:focus, .form-control:focus, .form-check-input:focus { + box-shadow: 0 0 0 0.1rem white, 0 0 0 0.25rem #258cfb; +} + +.content { + padding-top: 1.1rem; +} + +.valid.modified:not([type=checkbox]) { + outline: 1px solid #26b050; +} + +.invalid { + outline: 1px solid red; +} + +.validation-message { + color: red; +} + +#blazor-error-ui { + background: lightyellow; + bottom: 0; + box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2); + display: none; + left: 0; + padding: 0.6rem 1.25rem 0.7rem 1.25rem; + position: fixed; + width: 100%; + z-index: 1000; +} + +#blazor-error-ui .dismiss { + cursor: pointer; + position: absolute; + right: 0.75rem; + top: 0.5rem; +} + +.blazor-error-boundary { + background: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTYiIGhlaWdodD0iNDkiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIG92ZXJmbG93PSJoaWRkZW4iPjxkZWZzPjxjbGlwUGF0aCBpZD0iY2xpcDAiPjxyZWN0IHg9IjIzNSIgeT0iNTEiIHdpZHRoPSI1NiIgaGVpZ2h0PSI0OSIvPjwvY2xpcFBhdGg+PC9kZWZzPjxnIGNsaXAtcGF0aD0idXJsKCNjbGlwMCkiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0yMzUgLTUxKSI+PHBhdGggZD0iTTI2My41MDYgNTFDMjY0LjcxNyA1MSAyNjUuODEzIDUxLjQ4MzcgMjY2LjYwNiA1Mi4yNjU4TDI2Ny4wNTIgNTIuNzk4NyAyNjcuNTM5IDUzLjYyODMgMjkwLjE4NSA5Mi4xODMxIDI5MC41NDUgOTIuNzk1IDI5MC42NTYgOTIuOTk2QzI5MC44NzcgOTMuNTEzIDI5MSA5NC4wODE1IDI5MSA5NC42NzgyIDI5MSA5Ny4wNjUxIDI4OS4wMzggOTkgMjg2LjYxNyA5OUwyNDAuMzgzIDk5QzIzNy45NjMgOTkgMjM2IDk3LjA2NTEgMjM2IDk0LjY3ODIgMjM2IDk0LjM3OTkgMjM2LjAzMSA5NC4wODg2IDIzNi4wODkgOTMuODA3MkwyMzYuMzM4IDkzLjAxNjIgMjM2Ljg1OCA5Mi4xMzE0IDI1OS40NzMgNTMuNjI5NCAyNTkuOTYxIDUyLjc5ODUgMjYwLjQwNyA1Mi4yNjU4QzI2MS4yIDUxLjQ4MzcgMjYyLjI5NiA1MSAyNjMuNTA2IDUxWk0yNjMuNTg2IDY2LjAxODNDMjYwLjczNyA2Ni4wMTgzIDI1OS4zMTMgNjcuMTI0NSAyNTkuMzEzIDY5LjMzNyAyNTkuMzEzIDY5LjYxMDIgMjU5LjMzMiA2OS44NjA4IDI1OS4zNzEgNzAuMDg4N0wyNjEuNzk1IDg0LjAxNjEgMjY1LjM4IDg0LjAxNjEgMjY3LjgyMSA2OS43NDc1QzI2Ny44NiA2OS43MzA5IDI2Ny44NzkgNjkuNTg3NyAyNjcuODc5IDY5LjMxNzkgMjY3Ljg3OSA2Ny4xMTgyIDI2Ni40NDggNjYuMDE4MyAyNjMuNTg2IDY2LjAxODNaTTI2My41NzYgODYuMDU0N0MyNjEuMDQ5IDg2LjA1NDcgMjU5Ljc4NiA4Ny4zMDA1IDI1OS43ODYgODkuNzkyMSAyNTkuNzg2IDkyLjI4MzcgMjYxLjA0OSA5My41Mjk1IDI2My41NzYgOTMuNTI5NSAyNjYuMTE2IDkzLjUyOTUgMjY3LjM4NyA5Mi4yODM3IDI2Ny4zODcgODkuNzkyMSAyNjcuMzg3IDg3LjMwMDUgMjY2LjExNiA4Ni4wNTQ3IDI2My41NzYgODYuMDU0N1oiIGZpbGw9IiNGRkU1MDAiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjwvZz48L3N2Zz4=) no-repeat 1rem/1.8rem, #b32121; + padding: 1rem 1rem 1rem 3.7rem; + color: white; +} + +.blazor-error-boundary::after { + content: "An error has occurred." +} + +.loading-progress { + position: relative; + display: block; + width: 8rem; + height: 8rem; + margin: 20vh auto 1rem auto; +} + +.loading-progress circle { + fill: none; + stroke: #e0e0e0; + stroke-width: 0.6rem; + transform-origin: 50% 50%; + transform: rotate(-90deg); +} + +.loading-progress circle:last-child { + stroke: #1b6ec2; + stroke-dasharray: calc(3.141 * var(--blazor-load-percentage, 0%) * 0.8), 500%; + transition: stroke-dasharray 0.05s ease-in-out; +} + +.loading-progress-text { + position: absolute; + text-align: center; + font-weight: bold; + inset: calc(20vh + 3.25rem) 0 auto 0.2rem; +} + +.loading-progress-text:after { + content: var(--blazor-load-percentage-text, "Loading"); +} + +code { + color: #c02d76; +} diff --git a/NetinaShop.AdminPanel.PWA/wwwroot/index.html b/NetinaShop.AdminPanel.PWA/wwwroot/index.html index afab26b..13fda64 100644 --- a/NetinaShop.AdminPanel.PWA/wwwroot/index.html +++ b/NetinaShop.AdminPanel.PWA/wwwroot/index.html @@ -20,6 +20,8 @@ + + @@ -39,6 +41,7 @@ 🗙 + diff --git a/NetinaShop.AdminPanel.sln b/NetinaShop.AdminPanel.sln index e86122f..115824d 100644 --- a/NetinaShop.AdminPanel.sln +++ b/NetinaShop.AdminPanel.sln @@ -3,7 +3,11 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.8.34316.72 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NetinaShop.AdminPanel.PWA", "NetinaShop.AdminPanel.PWA\NetinaShop.AdminPanel.PWA.csproj", "{EB154E26-A392-4521-B26D-1B82C8597201}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NetinaShop.AdminPanel.PWA", "NetinaShop.AdminPanel.PWA\NetinaShop.AdminPanel.PWA.csproj", "{EB154E26-A392-4521-B26D-1B82C8597201}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NetinaShop.Domain", "..\NetinaShop\NetinaShop.Domain\NetinaShop.Domain.csproj", "{FD9AD662-66FB-431A-A2C1-8D6262402FCE}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NetinaShop.Common", "..\NetinaShop\NetinaShop.Common\NetinaShop.Common.csproj", "{CE60F736-C3F2-4D81-862E-48135E5FFC9C}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -15,6 +19,14 @@ Global {EB154E26-A392-4521-B26D-1B82C8597201}.Debug|Any CPU.Build.0 = Debug|Any CPU {EB154E26-A392-4521-B26D-1B82C8597201}.Release|Any CPU.ActiveCfg = Release|Any CPU {EB154E26-A392-4521-B26D-1B82C8597201}.Release|Any CPU.Build.0 = Release|Any CPU + {FD9AD662-66FB-431A-A2C1-8D6262402FCE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FD9AD662-66FB-431A-A2C1-8D6262402FCE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FD9AD662-66FB-431A-A2C1-8D6262402FCE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FD9AD662-66FB-431A-A2C1-8D6262402FCE}.Release|Any CPU.Build.0 = Release|Any CPU + {CE60F736-C3F2-4D81-862E-48135E5FFC9C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CE60F736-C3F2-4D81-862E-48135E5FFC9C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CE60F736-C3F2-4D81-862E-48135E5FFC9C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CE60F736-C3F2-4D81-862E-48135E5FFC9C}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE