Compare commits

..

No commits in common. "master" and "release" have entirely different histories.

105 changed files with 2102 additions and 6229 deletions

View File

@ -1,20 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsAspireHost>true</IsAspireHost>
<UserSecretsId>045801e7-58a1-4ee6-9d28-93c23b5dcd6b</UserSecretsId>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Aspire.Hosting.AppHost" Version="8.2.2" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Netina.AdminPanel.PWA\Netina.AdminPanel.PWA.csproj" />
</ItemGroup>
</Project>

View File

@ -1,3 +0,0 @@
var builder = DistributedApplication.CreateBuilder(args);
builder.Build().Run();

View File

@ -1,29 +0,0 @@
{
"$schema": "https://json.schemastore.org/launchsettings.json",
"profiles": {
"https": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"applicationUrl": "https://localhost:17057;http://localhost:15006",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development",
"DOTNET_ENVIRONMENT": "Development",
"DOTNET_DASHBOARD_OTLP_ENDPOINT_URL": "https://localhost:21274",
"DOTNET_RESOURCE_SERVICE_ENDPOINT_URL": "https://localhost:22232"
}
},
"http": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"applicationUrl": "http://localhost:15006",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development",
"DOTNET_ENVIRONMENT": "Development",
"DOTNET_DASHBOARD_OTLP_ENDPOINT_URL": "http://localhost:19034",
"DOTNET_RESOURCE_SERVICE_ENDPOINT_URL": "http://localhost:20044"
}
}
}
}

View File

@ -1,8 +0,0 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
}
}

View File

@ -1,9 +0,0 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning",
"Aspire.Hosting.Dcp": "Warning"
}
}
}

View File

@ -1,4 +1,5 @@
@using Netina.AdminPanel.PWA.Layout @using Netina.AdminPanel.PWA.Models
@using Netina.AdminPanel.PWA.Layout
@using Netina.AdminPanel.PWA.Pages @using Netina.AdminPanel.PWA.Pages
<Router AppAssembly="@typeof(App).Assembly"> <Router AppAssembly="@typeof(App).Assembly">
<Found Context="routeData"> <Found Context="routeData">

View File

@ -1,28 +0,0 @@
<MudPaper Outlined="true"
class="@(Comment.IsAdmin ? "border-solid border-blue-500 p-2" : "p-2")"
@attributes="CapturedAttributes">
<MudGrid>
<MudItem sm="8">
<MudField Label="عنوان" DisableUnderLine="true" Variant="Variant.Text">@Comment.Title</MudField>
</MudItem>
<MudItem sm="4">
<MudField Label="نام نام خانوادگی" DisableUnderLine="true" Variant="Variant.Text">@Comment.UserFullName</MudField>
</MudItem>
<MudItem sm="12">
<MudTextField @bind-Value="@Comment.Content" DisableUnderLine="true" Lines="4" ReadOnly="true" T="string" Label="متن نظر" Variant="Variant.Outlined"></MudTextField>
</MudItem>
</MudGrid>
@foreach (var item in Comment.Children)
{
<CommentItemTemplate class="mr-3 mt-2 p-2" Comment="item" />
}
</MudPaper>
@code {
[Parameter]
public CommentSDto Comment { get; set; }
[Parameter(CaptureUnmatchedValues = true)]
public Dictionary<string, object> CapturedAttributes { get; set; } = new();
}

View File

@ -1,9 +1,8 @@
@inject IJSRuntime JsRuntime @inject IJSRuntime JsRuntime
@implements IAsyncDisposable @implements IAsyncDisposable
<head> <head>
<link rel="stylesheet" href="assets/vendor/ckeditor5-content.css" /> <link rel="stylesheet" href="css/content-styles.css" />
</head> </head>
<style> <style>
.ck-content * { .ck-content * {
@ -16,9 +15,65 @@
</style> </style>
<div class="editor"></div> <div class="editor"></div>
<script type="text/javascript">
@code
{ function destroyEditor() {
// document.querySelector('.editor').ckeditorInstance.destroy();
window.editor = null;
}
function lunchEditor(data) {
if (!document.querySelector('.editor')) return
if (window.editor) return
ClassicEditor.create(document.querySelector('.editor'), {
htmlSupport: {
allow: [
{
name: 'iframe',
attributes: true,
classes: true,
styles: true
}
]
}
})
.then(editor => {
window.editor = editor;
window.editor.setData(data);
editor.editing.view.document.on('blur', () => {
GLOBAL.DotNetReference.invokeMethodAsync('MyMethod', window.editor.getData());
});
})
.catch(handleSampleError);
}
var GLOBAL = {};
GLOBAL.DotNetReference = null;
GLOBAL.SetDotnetReference = function (pDotNetReference) {
GLOBAL.DotNetReference = pDotNetReference;
};
function handleSampleError(error) {
const issueUrl = 'https://github.com/ckeditor/ckeditor5/issues';
const message = [
'Oops, something went wrong!',
`Please, report the following error on ${issueUrl} with the build id "pws0dnpd0jqj-zi42lsl7aqxa" and the error stack trace:`
].join('\n');
console.error(message);
console.error(error);
}
function setData(data) {
if (!!window.editor.date && window.editor.data != data) {
window.editor.setData(data);
}
}
</script>
@code {
@ -45,7 +100,7 @@
{ {
try try
{ {
await JsRuntime.InvokeVoidAsync("setData", Text); await JsRuntime.InvokeVoidAsync("window.setData", Text);
isTextSeted = true; isTextSeted = true;
} }
catch (Exception e) catch (Exception e)
@ -59,23 +114,20 @@
protected override async Task OnAfterRenderAsync(bool firstRender) protected override async Task OnAfterRenderAsync(bool firstRender)
{ {
if (firstRender) var lDotNetReference = DotNetObjectReference.Create(this);
{ await JsRuntime.InvokeVoidAsync("GLOBAL.SetDotnetReference", lDotNetReference);
var lDotNetReference = DotNetObjectReference.Create(this); await JsRuntime.InvokeVoidAsync("window.lunchEditor", Text);
await JsRuntime.InvokeVoidAsync("GLOBAL.SetDotnetReference", lDotNetReference); await base.OnAfterRenderAsync(firstRender);
await JsRuntime.InvokeVoidAsync("initializeCKEditor", Text);
await base.OnAfterRenderAsync(firstRender);
}
} }
public void Dispose() public void Dispose()
{ {
JsRuntime.InvokeVoidAsync("destroyEditor", Text); JsRuntime.InvokeVoidAsync("window.destroyEditor", Text);
} }
public async ValueTask DisposeAsync() public async ValueTask DisposeAsync()
{ {
await JsRuntime.InvokeVoidAsync("destroyEditor", Text); await JsRuntime.InvokeVoidAsync("window.destroyEditor", Text);
} }
} }

View File

@ -1,11 +1,10 @@
@inject NavigationManager NavigationManager @inject NavigationManager NavigationManager
@inject IRestWrapper RestWrapper @inject IRestWrapper RestWrapper
@inject IUserUtility UserUtility @inject IUserUtility UserUtility
@inject ISnackbar Snackbar
<MudStack class="bg-[--mud-palette-background] h-screen w-full pt-4"> <MudStack class="w-full pt-4 h-screen bg-[--mud-palette-background]">
<MudNavMenu Rounded="true" Margin="Margin.Dense" Color="Color.Warning" Bordered="true"> <MudNavMenu Rounded="true" Margin="Margin.Dense" Color="Color.Warning" Class="pa-2" Bordered="true">
<MudNavLink Href="home" Match="NavLinkMatch.Prefix" Icon="@Icons.Material.Filled.Dashboard">داشبورد</MudNavLink> <MudNavLink Href="home" Match="NavLinkMatch.Prefix" Icon="@Icons.Material.Filled.Dashboard">داشبورد</MudNavLink>
@if (isShop) @if (isShop)
{ {
@ -22,18 +21,9 @@
Icon="@Icons.Material.Outlined.AllInbox">دسته بندی محصولاتـــ</MudNavLink> Icon="@Icons.Material.Outlined.AllInbox">دسته بندی محصولاتـــ</MudNavLink>
<MudNavLink Href="product/brands" <MudNavLink Href="product/brands"
Icon="@Icons.Custom.Brands.Facebook">برند محصولاتــــ</MudNavLink> Icon="@Icons.Custom.Brands.Facebook">برند محصولاتــــ</MudNavLink>
<MudNavLink Href="product/shipping"
Icon="@Icons.Material.Outlined.AirportShuttle">روش های ارسال</MudNavLink>
</MudNavGroup> </MudNavGroup>
} }
<MudNavGroup Title="نظرات و امتیازاتـــ" Expanded="false"
Icon="@Icons.Material.Outlined.Comment">
<MudNavLink Href="reviews"
Icon="@Icons.Material.Filled.Comment">مدیریت نظراتـــ</MudNavLink>
</MudNavGroup>
<MudNavGroup Title="وبلاگــــ" Expanded="false" <MudNavGroup Title="وبلاگــــ" Expanded="false"
Icon="@Icons.Material.Outlined.Web"> Icon="@Icons.Material.Outlined.Web">
@ -46,12 +36,7 @@
<MudNavGroup Title="مدیریت برگه ها" Expanded="false" <MudNavGroup Title="مدیریت برگه ها" Expanded="false"
Icon="@Icons.Material.Outlined.Pages"> Icon="@Icons.Material.Outlined.Pages">
<MudNavLink Href="management/pages" Icon="@Icons.Material.Filled.Pageview">برگه ها</MudNavLink> <MudNavLink Href="management/pages" Icon="@Icons.Material.Filled.Pageview">برگه ها</MudNavLink>
<MudNavLink Href="setting/faq" Icon="@Icons.Material.Filled.ManageAccounts">سوالات متداول</MudNavLink> <MudNavLink Href="management/faqs" Icon="@Icons.Material.Filled.ManageAccounts">سوالات متداول</MudNavLink>
<MudNavLink Href="setting/pages" Icon="@Icons.Material.Outlined.Folder">تنظیماتــ برگه ها</MudNavLink>
</MudNavGroup>
<MudNavGroup Title="شخصی سازی" Expanded="false" Icon="@Icons.Material.Filled.SettingsSystemDaydream">
<MudNavLink Href="personaliztion/main" Icon="@Icons.Material.Filled.SettingsBrightness">کاتالوگ و بنرها</MudNavLink>
</MudNavGroup> </MudNavGroup>
@if (isShop) @if (isShop)
@ -66,6 +51,18 @@
</MudNavGroup> </MudNavGroup>
} }
@if (isShop)
{
<MudNavGroup Title="انبارداری" Expanded="false"
Icon="@Icons.Material.Outlined.Inventory">
<MudNavLink Href="inveroty"
Icon="@Icons.Material.Outlined.Inventory2">انبار</MudNavLink>
<MudNavLink Href="inventory/shipping"
Icon="@Icons.Material.Outlined.AirportShuttle">روش های ارسال</MudNavLink>
</MudNavGroup>
}
@if (isShop) @if (isShop)
{ {
<MudNavGroup Title="باشگاه مشتریانـــ" Expanded="false" <MudNavGroup Title="باشگاه مشتریانـــ" Expanded="false"
@ -73,16 +70,23 @@
<MudNavLink Href="customers" <MudNavLink Href="customers"
Icon="@Icons.Material.Outlined.PeopleAlt">مشترکین</MudNavLink> Icon="@Icons.Material.Outlined.PeopleAlt">مشترکین</MudNavLink>
<MudNavLink Href="smspanel"
Icon="@Icons.Material.Outlined.Sms">پنل پیامکی</MudNavLink>
<MudNavLink Href="newsletler" <MudNavLink Href="newsletler"
Icon="@Icons.Material.Outlined.Newspaper">خبرنامه</MudNavLink> Icon="@Icons.Material.Outlined.Newspaper">خبرنامه</MudNavLink>
</MudNavGroup> </MudNavGroup>
} }
@if (isShop) @if (isShop)
{
<MudNavGroup Title="شخصی سازی" Expanded="false" Icon="@Icons.Material.Outlined.PersonalInjury">
<MudNavLink Href="personalization/nav" Icon="@Icons.Material.Filled.Navigation">فهرست ها</MudNavLink>
</MudNavGroup>
}
@if (isShop)
{ {
<MudNavGroup Title="فروشگاه من" Expanded="false" Icon="@Icons.Material.Outlined.Settings"> <MudNavGroup Title="فروشگاه من" Expanded="false" Icon="@Icons.Material.Outlined.Settings">
<MudNavLink Href="management/shop" Icon="@Icons.Material.Filled.Shop2">فروشگاه</MudNavLink> <MudNavLink Href="management/shop" Icon="@Icons.Material.Filled.Shop2">فروشگاه</MudNavLink>
<MudNavLink Href="management/marketer" Icon="@Icons.Material.Filled.Person4">بازاریاب ها</MudNavLink> <MudNavLink Href="management/marketer" Icon="@Icons.Material.Filled.Person4">بازاریاب ها</MudNavLink>
<MudNavLink Href="personalization/nav" Icon="@Icons.Material.Filled.MenuOpen">فهرست ها</MudNavLink>
</MudNavGroup> </MudNavGroup>
} }
else else
@ -97,7 +101,7 @@
<MudNavLink Href="setting/users" Icon="@Icons.Material.Filled.ManageAccounts">نقش ها و کاربران</MudNavLink> <MudNavLink Href="setting/users" Icon="@Icons.Material.Filled.ManageAccounts">نقش ها و کاربران</MudNavLink>
</MudNavGroup> </MudNavGroup>
</MudNavMenu> </MudNavMenu>
<p class="bottom-0 mx-auto align-bottom">Version : @version</p> <p class="bottom-0 align-bottom mx-auto">Version : @version</p>
</MudStack> </MudStack>
@code @code
@ -108,27 +112,20 @@
{ {
try try
{ {
try _permissions = await UserUtility.GetPermissionsAsync() ?? new List<string>();
var token = await UserUtility.GetBearerTokenAsync();
if (token == null)
{ {
_permissions = await UserUtility.GetPermissionsAsync() ?? new List<string>(); await UserUtility.LogoutAsync();
var token = await UserUtility.GetBearerTokenAsync(); NavigationManager.NavigateTo("login", true, true);
if (token == null) return;
{ }
await UserUtility.LogoutAsync();
NavigationManager.NavigateTo("login", true, true);
return;
}
var rest = await RestWrapper.SettingRestApi.GetSettingAsync<NetinaSetting>(nameof(NetinaSetting), token); var rest = await RestWrapper.SettingRestApi.GetSettingAsync<NetinaSetting>(nameof(NetinaSetting), token);
if (rest.WebSiteType == 0) if (rest.WebSiteType == 0)
isShop = true; isShop = true;
else else
isShop = false; isShop = false;
}
catch (Exception e)
{
Snackbar.Add("در دریافت اطلاعات مشکلی رخ داده است", Severity.Error);
}
await base.OnInitializedAsync(); await base.OnInitializedAsync();
} }

View File

@ -30,9 +30,9 @@
<ProgressIndicatorInPopoverTemplate> <ProgressIndicatorInPopoverTemplate>
<MudList Clickable="false"> <MudList Clickable="false">
<MudListItem> <MudListItem>
<div class="mx-auto flex w-full flex-row"> <div class="flex flex-row w-full mx-auto">
<MudProgressCircular class="my-auto -ml-4 mr-1" Size="Size.Small" Indeterminate="true" /> <MudProgressCircular class="my-auto mr-1 -ml-4" Size="Size.Small" Indeterminate="true" />
<p class="text-md mx-auto my-1 font-bold">منتظر بمانید</p> <p class="font-bold my-1 mx-auto text-md">منتظر بمانید</p>
</div> </div>
</MudListItem> </MudListItem>
</MudList> </MudList>
@ -63,6 +63,7 @@
<div class="min-h-[33rem]"> <div class="min-h-[33rem]">
<MudStack class="mt-4" Spacing="0"> <MudStack class="mt-4" Spacing="0">
<MudText Typo="Typo.h6">متن بلاگ</MudText> <MudText Typo="Typo.h6">متن بلاگ</MudText>
<MudText Typo="Typo.caption">می توانید کتن کامل بلاگــــ خود را کامل وارد کنید</MudText> <MudText Typo="Typo.caption">می توانید کتن کامل بلاگــــ خود را کامل وارد کنید</MudText>
</MudStack> </MudStack>
@ -78,7 +79,7 @@
<MudTabPanel Text="تـــــصاویر" Icon="@Icons.Material.Outlined.ImageSearch"> <MudTabPanel Text="تـــــصاویر" Icon="@Icons.Material.Outlined.ImageSearch">
<div class="min-h-[33rem]"> <div class="min-h-[33rem]">
<MudStack class="mb-2 mt-4" Spacing="0"> <MudStack class="mt-4 mb-2" Spacing="0">
<MudText Typo="Typo.h6">تصاویر محصول</MudText> <MudText Typo="Typo.h6">تصاویر محصول</MudText>
<MudText Typo="Typo.caption">می توانید برای محصول چند تصویر اپلود کنید</MudText> <MudText Typo="Typo.caption">می توانید برای محصول چند تصویر اپلود کنید</MudText>
@ -87,15 +88,15 @@
<MudIconButton HtmlTag="label" <MudIconButton HtmlTag="label"
Color="Color.Info" Color="Color.Info"
Variant="Variant.Outlined" Variant="Variant.Outlined"
class="h-28 w-28" class="w-28 h-28"
Size="Size.Large" Size="Size.Large"
Icon="@Icons.Material.Outlined.Wallpaper" Icon="@Icons.Material.Outlined.Wallpaper"
OnClick="async () => await ViewModel.SelectFileAsync()"> OnClick="async () => await ViewModel.SelectFileAsync()">
</MudIconButton> </MudIconButton>
@foreach (var item in ViewModel.Files) @foreach (var item in ViewModel.Files)
{ {
<div class="h-28 w-28"> <div class="w-28 h-28">
<MudImage Src="@item.GetLink()" Elevation="25" Class="absolute h-28 w-28 rounded-lg" /> <MudImage Src="@item.GetLink()" Elevation="25" Class="rounded-lg w-28 h-28 absolute" />
<MudIconButton DisableElevation="true" <MudIconButton DisableElevation="true"
class="absolute m-1.5" class="absolute m-1.5"
@ -106,11 +107,11 @@
Icon="@Icons.Material.Outlined.Delete" /> Icon="@Icons.Material.Outlined.Delete" />
@if (item.IsHeader) @if (item.IsHeader)
{ {
<p class="absolute bottom-0 mr-2 rounded-lg bg-pink-500 px-1.5 py-0.5 text-white">هدر</p> <p class="bg-pink-500 px-1.5 py-0.5 absolute bottom-0 mr-2 rounded-lg text-white">هدر</p>
} }
@if (item.IsPrimary) @if (item.IsPrimary)
{ {
<p class="absolute bottom-0 mr-2 rounded-lg bg-blue-500 px-1.5 py-0.5 text-white">اصلی</p> <p class="bg-blue-500 px-1.5 py-0.5 absolute bottom-0 mr-2 rounded-lg text-white">اصلی</p>
} }
</div> </div>
} }
@ -123,7 +124,7 @@
</MudContainer> </MudContainer>
</DialogContent> </DialogContent>
<DialogActions> <DialogActions>
<MudStack Row="true" class="bottom-0 mx-4 h-fit w-full"> <MudStack Row="true" class="w-full h-fit mx-4 bottom-0">
@if (ViewModel.IsEditing) @if (ViewModel.IsEditing)
{ {

View File

@ -1,4 +1,8 @@
@inject ISnackbar Snackbar @using Netina.AdminPanel.PWA.Models.Api
@using Netina.AdminPanel.PWA.Models
@using Netina.Domain.Entities.Blogs
@inject ISnackbar Snackbar
@inject IRestWrapper RestWrapper @inject IRestWrapper RestWrapper
@inject IUserUtility UserUtility @inject IUserUtility UserUtility
@ -23,7 +27,7 @@
</MudStack> </MudStack>
</DialogContent> </DialogContent>
<DialogActions> <DialogActions>
<MudStack Row="true" class="mx-4 mb-2 w-full"> <MudStack Row="true" class="w-full mx-4 mb-2">
@if (_isEditing) @if (_isEditing)
{ {

View File

@ -1,234 +1,236 @@
@inject ISnackbar Snackbar @using Netina.AdminPanel.PWA.Models.Api
@using Netina.AdminPanel.PWA.Models
@using Netina.Domain.Entities.Brands
@inject ISnackbar Snackbar
@inject IRestWrapper RestWrapper @inject IRestWrapper RestWrapper
@inject IUserUtility UserUtility @inject IUserUtility UserUtility
@inject IDialogService DialogService @inject IDialogService DialogService
<MudDialog class="mx-auto"> <MudDialog class="mx-auto">
<DialogContent> <DialogContent>
<MudContainer class="h-full p-0"> <MudStack>
<MudTabs Outlined="true" Elevation="0" Rounded="true" Centered="true"> <MudDivider class="-mt-3" />
<MudTabPanel Text="اطلاعات کلی" Icon="@Icons.Material.Outlined.Info"> <MudStack Spacing="0">
<MudStack> <MudText Typo="Typo.h6">اطلاعات کلی</MudText>
<MudStack Spacing="0"> <MudText Typo="Typo.caption">اطلاعات کلی دسته بندی محصول را به دقت وارد کنید</MudText>
</MudStack>
<MudGrid>
<MudItem lg="6" md="6">
<MudTextField T="string" Label="نام فارسی برند" @bind-Value="@_persianName" Variant="Variant.Outlined"></MudTextField>
</MudItem>
<MudItem lg="6" md="6">
<MudTextField T="string" Label="نام انگلیسی برند" @bind-Value="@_englishName" Variant="Variant.Outlined"></MudTextField>
</MudItem>
<MudItem lg="6" md="6">
<MudSelect T="bool" Label="آیا صفحه شخصی دارد ؟" @bind-Value="@_hasSpecialPage" ToStringFunc="b=>b.ToPersianString()" Variant="Variant.Outlined" AnchorOrigin="Origin.BottomCenter">
<MudSelectItem T="bool" Value="true"></MudSelectItem>
<MudSelectItem T="bool" Value="false" />
</MudSelect>
</MudItem>
<MudItem lg="6" md="6">
<MudTextField T="string" Label="لینک صفحه شخصی برند" @bind-Value="@_pageUrl" Variant="Variant.Outlined"></MudTextField>
</MudItem>
<MudItem lg="12" md="12">
<MudTextField T="string" Label="توضیحاتــ" @bind-Value="@_description" Variant="Variant.Outlined"></MudTextField>
</MudItem>
<MudItem sm="12" md="12" lg="12">
<MudStack class="mt-1 mb-4" Spacing="0">
<MudText Typo="Typo.h6">اطلاعات کلی</MudText> <MudText Typo="Typo.h6">تصاویر برند</MudText>
<MudText Typo="Typo.caption">اطلاعات کلی دسته بندی محصول را به دقت وارد کنید</MudText> <MudText Typo="Typo.caption">می توانید برای برند چند تصویر اپلود کنید</MudText>
</MudStack>
<MudGrid>
<MudItem lg="6" md="6">
<MudTextField T="string" Label="نام فارسی برند" @bind-Value="@ViewModel.PageDto.PersianName" Variant="Variant.Outlined"></MudTextField>
</MudItem>
<MudItem lg="6" md="6">
<MudTextField T="string" Label="نام انگلیسی برند" @bind-Value="@ViewModel.PageDto.EnglishName" Variant="Variant.Outlined"></MudTextField>
</MudItem>
<MudItem lg="6" md="6">
<MudSelect T="bool" Label="آیا صفحه شخصی دارد ؟" @bind-Value="@ViewModel.PageDto.HasSpecialPage" ToStringFunc="b=>b.ToPersianString()" Variant="Variant.Outlined" AnchorOrigin="Origin.BottomCenter">
<MudSelectItem T="bool" Value="true"></MudSelectItem>
<MudSelectItem T="bool" Value="false" />
</MudSelect>
</MudItem>
<MudItem lg="6" md="6">
<MudTextField T="string" Label="لینک صفحه شخصی برند" @bind-Value="@ViewModel.PageDto.PageUrl" Variant="Variant.Outlined"></MudTextField>
</MudItem>
<MudItem sm="12" md="12" lg="12">
<MudStack class="mt-1 mb-4" Spacing="0">
<MudText Typo="Typo.h6">تصاویر برند</MudText>
<MudText Typo="Typo.caption">می توانید برای برند چند تصویر اپلود کنید</MudText>
</MudStack>
<MudStack Row="true">
<MudIconButton HtmlTag="label"
Color="Color.Info"
Variant="Variant.Outlined"
class="w-28 h-28"
Size="Size.Large"
Icon="@Icons.Material.Outlined.Wallpaper"
OnClick="async () => await ViewModel.SelectFileAsync()" />
@foreach (var item in ViewModel.PageDto.Files)
{
<div class="w-28 h-28">
<MudImage Src="@item.GetLink()" Elevation="25" Class="rounded-lg w-28 h-28 absolute" />
<MudIconButton DisableElevation="true"
class="absolute m-1.5"
Size="@Size.Small"
Variant="@Variant.Filled"
OnClick="() => ViewModel.PageDto.Files.Remove(item)"
Color="@Color.Error"
Icon="@Icons.Material.Outlined.Delete" />
@if (item.IsHeader)
{
<p class="bg-pink-500 px-1.5 py-0.5 absolute bottom-0 mr-2 rounded-lg text-white">هدر</p>
}
@if (item.IsPrimary)
{
<p class="bg-blue-500 px-1.5 py-0.5 absolute bottom-0 mr-2 rounded-lg text-white">اصلی</p>
}
</div>
}
</MudStack>
</MudItem>
<MudItem lg="12" md="12">
<RichTextEditorUi @bind-Text="@ViewModel.PageDto.Description" ></RichTextEditorUi>
</MudItem>
</MudGrid>
</MudStack> </MudStack>
</MudTabPanel> <MudStack Row="true">
<MudIconButton HtmlTag="label"
Color="Color.Info"
Variant="Variant.Outlined"
class="w-28 h-28"
Size="Size.Large"
Icon="@Icons.Material.Outlined.Wallpaper"
OnClick="async () => await SelectFileAsync()">
</MudIconButton>
@foreach (var item in Files)
{
<div class="w-28 h-28">
<MudImage Src="@item.GetLink()" Elevation="25" Class="rounded-lg w-28 h-28 absolute" />
<MudTabPanel Text="متاتگ و سوالات متداول"> <MudIconButton DisableElevation="true"
class="absolute m-1.5"
Size="@Size.Small"
Variant="@Variant.Filled"
OnClick="() => RemoveFile(item)"
Color="@Color.Error"
Icon="@Icons.Material.Outlined.Delete" />
@if (item.IsHeader)
{
<p class="bg-pink-500 px-1.5 py-0.5 absolute bottom-0 mr-2 rounded-lg text-white">هدر</p>
}
@if (item.IsPrimary)
{
<p class="bg-blue-500 px-1.5 py-0.5 absolute bottom-0 mr-2 rounded-lg text-white">اصلی</p>
}
</div>
}
<MudGrid> </MudStack>
<MudItem xs="12"> </MudItem>
<MudText Typo="Typo.h6">اطلاعات متا تگ</MudText>
<MudText Typo="Typo.caption">می توانید متا تگ های سئو برای صفحه مورد نظر را وارد کنید</MudText>
<MudGrid>
<MudItem lg="5" md="6"> </MudGrid>
<MudTextField @bind-Value="@ViewModel.MetaTagType" T="string" Label="نوع" Variant="Variant.Outlined"></MudTextField> </MudStack>
</MudItem>
<MudItem lg="5" md="6">
<MudTextField @bind-Value="@ViewModel.MetaTagValue" T="string" Label="مقدار" Variant="Variant.Outlined"></MudTextField>
</MudItem>
<MudItem lg="2" md="12">
<MudButton Variant="Variant.Filled"
Size="Size.Large"
Color="Color.Info"
class="mt-2 w-full py-3"
OnClick="ViewModel.AddMetaTag"
StartIcon="@Icons.Material.Outlined.Add">افزودن</MudButton>
</MudItem>
<MudItem sm="12">
<MudDataGrid Items="@ViewModel.MetaTags"
T="MetaTagSDto"
Elevation="0"
Outlined="true"
Bordered="true"
Striped="true"
Filterable="false"
SortMode="@SortMode.None"
Groupable="false">
<Columns>
<PropertyColumn T="MetaTagSDto" TProperty="string" Property="x => x.Type" Title="نوع" />
<PropertyColumn T="MetaTagSDto" TProperty="string" Property="x => x.Value" Title="مقدار" />
<TemplateColumn T="MetaTagSDto" CellClass="d-flex justify-end">
<CellTemplate>
<MudStack Row>
<MudButton DisableElevation="true"
Size="@Size.Small"
Variant="@Variant.Filled"
OnClick="() => ViewModel.MetaTags.Remove(context.Item)"
Color="@Color.Error"
StartIcon="@Icons.Material.Outlined.Delete">حذف</MudButton>
</MudStack>
</CellTemplate>
</TemplateColumn>
</Columns>
</MudDataGrid>
</MudItem>
</MudGrid>
</MudItem>
<MudItem xs="12">
<MudText Typo="Typo.h6">سوالات متداول</MudText>
<MudText Typo="Typo.caption">می توانید سوالات متداول شهر موردنظر را وارد کنید</MudText>
<MudGrid class="mt-1">
<MudItem lg="5" md="6">
<MudTextField @bind-Value="@ViewModel.FaqQuestion" T="string" Label="سوال" Variant="Variant.Outlined"></MudTextField>
</MudItem>
<MudItem lg="5" md="6">
<MudTextField @bind-Value="@ViewModel.FaqAnswer" T="string" Label="پاسخ" Variant="Variant.Outlined"></MudTextField>
</MudItem>
<MudItem lg="2" md="12">
<MudButton Variant="Variant.Filled"
Size="Size.Large"
Color="Color.Info"
class="mt-2 w-full py-3"
OnClick="ViewModel.AddFaq"
StartIcon="@Icons.Material.Outlined.Add">افزودن</MudButton>
</MudItem>
<MudItem sm="12">
<MudExpansionPanels class="mt-1" Elevation="2">
@foreach (var item in ViewModel.Faqs)
{
<MudExpansionPanel>
<TitleContent>
<MudStack Row="true">
<MudIconButton Icon="@Icons.Material.Outlined.Delete"
Size="@Size.Small"
Variant="@Variant.Outlined"
Color="@Color.Error"
OnClick="() => ViewModel.Faqs.Remove(item.Key)"/>
<MudText>@item.Key</MudText>
</MudStack>
</TitleContent>
<ChildContent>
@item.Value
</ChildContent>
</MudExpansionPanel>
}
</MudExpansionPanels>
</MudItem>
</MudGrid>
</MudItem>
</MudGrid>
</MudTabPanel>
</MudTabs>
</MudContainer>
</DialogContent> </DialogContent>
<DialogActions> <DialogActions>
<MudStack Row="true" class="w-full mx-4 mb-2"> <MudStack Row="true" class="w-full mx-4 mb-2">
@if (ViewModel.IsEditing) @if (_isEditing)
{ {
<BaseButtonUi class="w-64 rounded-md" IsProcessing="@ViewModel.IsProcessing" <BaseButtonUi class="w-64 rounded-md" IsProcessing="@_isProcessing"
Icon="@Icons.Material.Outlined.Check" Icon="@Icons.Material.Outlined.Check"
Variant="Variant.Filled" Color="Color.Success" Variant="Variant.Filled" Color="Color.Success"
Content="ثبت ویرایش" OnClickCallback="ViewModel.SubmitEditAsync" /> Content="ثبت ویرایش" OnClickCallback="SubmitEditAsync" />
} }
else else
{ {
<BaseButtonUi class="w-64 rounded-md" IsProcessing="@ViewModel.IsProcessing" <BaseButtonUi class="w-64 rounded-md" IsProcessing="@_isProcessing"
Icon="@Icons.Material.Outlined.Check" Icon="@Icons.Material.Outlined.Check"
Variant="Variant.Filled" Color="Color.Success" Variant="Variant.Filled" Color="Color.Success"
Content="تایید" OnClickCallback="ViewModel.SubmitCreateAsync" /> Content="تایید" OnClickCallback="SubmitCreateAsync" />
} }
<MudSpacer /> <MudSpacer />
<MudButton Variant="Variant.Outlined" Size="Size.Large" Color="Color.Error" OnClick="ViewModel.Cancel">بستن</MudButton> <MudButton Variant="Variant.Outlined" Size="Size.Large" Color="Color.Error" OnClick="Cancel">بستن</MudButton>
</MudStack> </MudStack>
</DialogActions> </DialogActions>
</MudDialog> </MudDialog>
@code { @code {
[CascadingParameter] [CascadingParameter] MudDialogInstance MudDialog { get; set; }
MudDialogInstance MudDialog { get; set; }
[Parameter] [Parameter]
public BrandSDto? Brand { get; set; } public BrandSDto? Brand { get; set; }
void Cancel() => MudDialog.Cancel();
public readonly ObservableCollection<StorageFileSDto> Files = new ObservableCollection<StorageFileSDto>();
private bool _isProcessing = false;
private string _persianName = string.Empty;
private string _englishName = string.Empty;
private string _description = string.Empty;
private bool _hasSpecialPage;
private bool _isEditing;
private string _pageUrl = string.Empty;
public BrandActionDialogBoxViewModel ViewModel { get; set; } protected override async Task OnParametersSetAsync()
protected override async Task OnInitializedAsync()
{ {
ViewModel = Brand == null ? new BrandActionDialogBoxViewModel(Snackbar, RestWrapper, UserUtility, DialogService, MudDialog) : if (Brand != null)
new BrandActionDialogBoxViewModel(Snackbar, RestWrapper, UserUtility, DialogService, MudDialog, Brand); {
await ViewModel.InitializeAsync(); _isEditing = true;
await base.OnInitializedAsync(); try
{
_isProcessing = true;
var response = await RestWrapper.CrudDtoApiRest<Brand, BrandLDto, Guid>(Address.BrandController).ReadOne(Brand.Id);
var brandLDto = response;
brandLDto.Files.ForEach(f => Files.Add(f));
_hasSpecialPage = brandLDto.HasSpecialPage;
_description = brandLDto.Description;
_englishName = brandLDto.EnglishName;
_persianName = brandLDto.PersianName;
}
catch (ApiException ex)
{
var exe = await ex.GetContentAsAsync<ApiResult>();
Snackbar.Add(exe != null ? exe.Message : ex.Content, Severity.Error);
MudDialog.Cancel();
}
catch (Exception e)
{
Snackbar.Add(e.Message, Severity.Error);
MudDialog.Cancel();
}
finally
{
_isProcessing = false;
}
}
await base.OnParametersSetAsync();
}
private async Task SubmitCreateAsync()
{
try
{
if (_englishName.IsNullOrEmpty())
throw new AppException("لطفا نام برند را وارد کنید");
_isProcessing = true;
var token = await UserUtility.GetBearerTokenAsync();
if (token == null)
throw new AppException("Token is null");
var request = new CreateBrandCommand(_persianName, _englishName, _description, _hasSpecialPage, _pageUrl, Files.ToList());
await RestWrapper.CrudApiRest<Brand, Guid>(Address.BrandController).Create<CreateBrandCommand>(request, token);
MudDialog.Close(DialogResult.Ok(true));
}
catch (ApiException ex)
{
var exe = await ex.GetContentAsAsync<ApiResult>();
Snackbar.Add(exe != null ? exe.Message : ex.Content, Severity.Error);
}
catch (Exception e)
{
Snackbar.Add(e.Message, Severity.Error);
}
finally
{
_isProcessing = false;
}
}
private async Task SubmitEditAsync()
{
try
{
if (Brand == null)
throw new AppException("برند به درستی ارسال نشده است");
if (_englishName.IsNullOrEmpty())
throw new AppException("لطفا نام برند را وارد کنید");
_isProcessing = true;
var token = await UserUtility.GetBearerTokenAsync();
if (token == null)
throw new AppException("Token is null");
var request = new UpdateBrandCommand(Brand.Id, _persianName, _englishName, _description, _hasSpecialPage, _pageUrl, Files.ToList());
await RestWrapper.CrudApiRest<Brand, Guid>(Address.BrandController).Update<UpdateBrandCommand>(request, token);
MudDialog.Close();
}
catch (ApiException ex)
{
var exe = await ex.GetContentAsAsync<ApiResult>();
Snackbar.Add(exe != null ? exe.Message : ex.Content, Severity.Error);
MudDialog.Cancel();
}
catch (Exception e)
{
Snackbar.Add(e.Message, Severity.Error);
MudDialog.Cancel();
}
finally
{
_isProcessing = false;
}
}
public async Task SelectFileAsync()
{
DialogOptions maxWidth = new DialogOptions() { MaxWidth = MaxWidth.Medium, FullWidth = true, DisableBackdropClick = true };
var dialog = await DialogService.ShowAsync<StorageDialogBox>("انتخاب عکس برند", maxWidth);
var result = await dialog.Result;
var file = result.Data;
if (file is StorageFileSDto storageFile)
Files.Add(storageFile);
}
public void RemoveFile(StorageFileSDto file)
{
Files.Remove(file);
} }
} }

View File

@ -1,231 +0,0 @@
using Netina.Domain.Dtos.LargDtos;
using Netina.Domain.Entities.Brands;
namespace Netina.AdminPanel.PWA.Dialogs;
public class BrandActionDialogBoxViewModel : BaseViewModel<BrandLDto>
{
private readonly ISnackbar _snackbar;
private readonly IRestWrapper _restWrapper;
private readonly IUserUtility _userUtility;
private readonly IDialogService _dialogService;
private readonly MudDialogInstance _mudDialog;
public BrandActionDialogBoxViewModel(ISnackbar snackbar,
IRestWrapper restWrapper,
IUserUtility userUtility,
IDialogService dialogService,
MudDialogInstance mudDialog) : base(userUtility)
{
_snackbar = snackbar;
_restWrapper = restWrapper;
_userUtility = userUtility;
_dialogService = dialogService;
_mudDialog = mudDialog;
}
public BrandActionDialogBoxViewModel(ISnackbar snackbar,
IRestWrapper restWrapper,
IUserUtility userUtility,
IDialogService dialogService,
MudDialogInstance mudDialog,
BrandSDto brand) : base(userUtility)
{
_snackbar = snackbar;
_restWrapper = restWrapper;
_userUtility = userUtility;
_dialogService = dialogService;
_mudDialog = mudDialog;
Brand = brand;
}
private BrandSDto? _brand = null;
public BrandSDto? Brand
{
get => _brand;
set
{
_brand = value;
if (_brand != null)
{
IsEditing = true;
}
}
}
public void Cancel() => _mudDialog.Cancel();
public bool IsEditing = false;
public override async Task InitializeAsync()
{
if (Brand != null)
{
IsEditing = true;
try
{
IsProcessing = true;
var response = await _restWrapper.CrudDtoApiRest<Brand, BrandLDto, Guid>(Address.BrandController).ReadOne(Brand.Id);
var brandLDto = response;
brandLDto.MetaTags.ForEach(m => MetaTags.Add(m));
PageDto = brandLDto;
}
catch (ApiException ex)
{
var exe = await ex.GetContentAsAsync<ApiResult>();
_snackbar.Add(exe != null ? exe.Message : ex.Content, Severity.Error);
_mudDialog.Cancel();
}
catch (Exception e)
{
_snackbar.Add(e.Message, Severity.Error);
_mudDialog.Cancel();
}
finally
{
IsProcessing = false;
}
}
await base.InitializeAsync();
}
public async Task SubmitCreateAsync()
{
try
{
if (PageDto.EnglishName.IsNullOrEmpty())
throw new AppException("لطفا نام برند را وارد کنید");
IsProcessing = true;
var token = await _userUtility.GetBearerTokenAsync();
if (token == null)
throw new AppException("Token is null");
var request = new CreateBrandCommand(PageDto.PersianName,
PageDto.EnglishName,
PageDto.Description,
PageDto.HasSpecialPage,
PageDto.PageUrl,
PageDto.Files,
Faqs,
MetaTags.ToDictionary(x => x.Type, x => x.Value));
await _restWrapper.CrudApiRest<Brand, Guid>(Address.BrandController).Create<CreateBrandCommand>(request, token);
_mudDialog.Close(DialogResult.Ok(true));
}
catch (ApiException ex)
{
var exe = await ex.GetContentAsAsync<ApiResult>();
_snackbar.Add(exe != null ? exe.Message : ex.Content, Severity.Error);
}
catch (Exception e)
{
_snackbar.Add(e.Message, Severity.Error);
}
finally
{
IsProcessing = false;
}
}
public async Task SubmitEditAsync()
{
try
{
if (Brand == null)
throw new AppException("برند به درستی ارسال نشده است");
if (PageDto.EnglishName.IsNullOrEmpty())
throw new AppException("لطفا نام برند را وارد کنید");
IsProcessing = true;
var token = await _userUtility.GetBearerTokenAsync();
if (token == null)
throw new AppException("Token is null");
var request = new UpdateBrandCommand(
PageDto.Id,
PageDto.PersianName,
PageDto.EnglishName,
PageDto.Description,
PageDto.HasSpecialPage,
PageDto.PageUrl,
PageDto.Files,
Faqs,
MetaTags.ToDictionary(x => x.Type, x => x.Value));
await _restWrapper.CrudApiRest<Brand, Guid>(Address.BrandController).Update<UpdateBrandCommand>(request, token);
_mudDialog.Close();
}
catch (ApiException ex)
{
var exe = await ex.GetContentAsAsync<ApiResult>();
_snackbar.Add(exe != null ? exe.Message : ex.Content, Severity.Error);
_mudDialog.Cancel();
}
catch (Exception e)
{
_snackbar.Add(e.Message, Severity.Error);
_mudDialog.Cancel();
}
finally
{
IsProcessing = false;
}
}
public string FaqQuestion { get; set; } = string.Empty;
public string FaqAnswer { get; set; } = string.Empty;
public Dictionary<string, string> Faqs = new();
public void AddFaq()
{
try
{
if (FaqAnswer.IsNullOrEmpty())
throw new Exception("لطفا پاسخ را وارد کنید");
if (FaqQuestion.IsNullOrEmpty())
throw new Exception("لطفا سوال را وارد کنید");
Faqs.Add(FaqQuestion, FaqAnswer);
}
catch (Exception e)
{
_snackbar.Add(e.Message, Severity.Error);
}
}
public readonly ObservableCollection<MetaTagSDto> MetaTags = new();
public string MetaTagType { get; set; } = string.Empty;
public string MetaTagValue { get; set; } = string.Empty;
public void AddMetaTag()
{
try
{
if (MetaTagType.IsNullOrEmpty())
throw new Exception("لطفا نوع متا مورد نظر را وارد کنید");
if (MetaTagValue.IsNullOrEmpty())
throw new Exception("لطفا مقدار متا مورد نظر را وارد کنید");
MetaTags.Add(new MetaTagSDto() { Type = MetaTagType, Value = MetaTagValue });
}
catch (Exception e)
{
_snackbar.Add(e.Message, Severity.Error);
}
}
public async Task SelectFileAsync()
{
DialogOptions maxWidth = new DialogOptions() { MaxWidth = MaxWidth.Medium, FullWidth = true, DisableBackdropClick = true };
var dialog = await _dialogService.ShowAsync<StorageDialogBox>("انتخاب عکس برند", maxWidth);
var result = await dialog.Result;
var file = result.Data;
if (file is StorageFileSDto storageFile)
PageDto.Files.Add(storageFile);
}
public void RemoveFile(StorageFileSDto file)
{
PageDto.Files.Remove(file);
}
}

View File

@ -133,33 +133,7 @@
</MudAutocomplete> </MudAutocomplete>
</MudItem> </MudItem>
<MudItem sm="5"> <MudItem sm="5">
<MudSwitch @bind-Value="@ViewModel.IsProductEnable" class="mt-2" Size="Size.Large" T="bool" Label="تخفیف برای محصول خاص" Color="Color.Info" /> <MudSwitch @bind-Value="@ViewModel.IsProductEnable" class="mt-2" Size="Size.Large" T="bool" Label="تخفیف برای غذای خاص" Color="Color.Info" />
</MudItem>
<MudItem sm="7">
<MudAutocomplete Disabled="@ViewModel.IsProductEnable.Not()" ToStringFunc="dto => dto.PersianName" @bind-Value="@ViewModel.SelectedBrand"
SearchFunc="ViewModel.SearchBrand"
T="BrandSDto"
Label="برندها"
Variant="Variant.Outlined">
<ProgressIndicatorInPopoverTemplate>
<MudList Clickable="false">
<MudListItem>
<div class="flex flex-row w-full mx-auto">
<MudProgressCircular class="my-auto mr-1 -ml-4" Size="Size.Small" Indeterminate="true" />
<p class="font-bold my-1 mx-auto text-md">منتظر بمانید</p>
</div>
</MudListItem>
</MudList>
</ProgressIndicatorInPopoverTemplate>
<ItemTemplate Context="e">
<p>@e.PersianName</p>
</ItemTemplate>
</MudAutocomplete>
</MudItem>
<MudItem sm="5">
<MudSwitch @bind-Value="@ViewModel.IsProductEnable" class="mt-2" Size="Size.Large" T="bool" Label="تخفیف برای برند خاص" Color="Color.Info" />
</MudItem> </MudItem>
<MudItem sm="7"> <MudItem sm="7">

View File

@ -40,23 +40,8 @@ public class DiscountActionDialogBoxViewModel : BaseViewModel<DiscountLDto>
IsEditing = true; IsEditing = true;
} }
private bool _isBrandEnable;
public bool IsBrandEnable
{
get => _isBrandEnable;
set
{
_isBrandEnable = value;
if (_isBrandEnable)
{
IsCategoryEnable = false;
IsProductEnable = false;
IsAllEnable = false;
}
}
}
private bool _isProductEnable; private bool _isProductEnable;
public bool IsProductEnable public bool IsProductEnable
{ {
get => _isProductEnable; get => _isProductEnable;
@ -66,12 +51,10 @@ public class DiscountActionDialogBoxViewModel : BaseViewModel<DiscountLDto>
if (_isProductEnable) if (_isProductEnable)
{ {
IsCategoryEnable = false; IsCategoryEnable = false;
IsBrandEnable = false;
IsAllEnable = false; IsAllEnable = false;
} }
} }
} }
private bool _isCategoryEnable; private bool _isCategoryEnable;
public bool IsCategoryEnable public bool IsCategoryEnable
{ {
@ -82,7 +65,6 @@ public class DiscountActionDialogBoxViewModel : BaseViewModel<DiscountLDto>
if (_isCategoryEnable) if (_isCategoryEnable)
{ {
IsProductEnable = false; IsProductEnable = false;
IsBrandEnable = false;
IsAllEnable = false; IsAllEnable = false;
} }
} }
@ -97,7 +79,6 @@ public class DiscountActionDialogBoxViewModel : BaseViewModel<DiscountLDto>
if (_isAllEnable) if (_isAllEnable)
{ {
IsCategoryEnable = false; IsCategoryEnable = false;
IsBrandEnable = false;
IsProductEnable = false; IsProductEnable = false;
} }
} }
@ -142,10 +123,6 @@ public class DiscountActionDialogBoxViewModel : BaseViewModel<DiscountLDto>
if (PageDto.CategoryId != default) if (PageDto.CategoryId != default)
SelectedCategory = new ProductCategorySDto { Id = PageDto.CategoryId, Name = PageDto.CategoryName }; SelectedCategory = new ProductCategorySDto { Id = PageDto.CategoryId, Name = PageDto.CategoryName };
if (PageDto.ProductId != default)
SelectedProduct = new ProductSDto { Id = PageDto.ProductId, PersianName = PageDto.ProductName };
if (PageDto.ProductId != default) if (PageDto.ProductId != default)
SelectedProduct = new ProductSDto { Id = PageDto.ProductId, PersianName = PageDto.ProductName }; SelectedProduct = new ProductSDto { Id = PageDto.ProductId, PersianName = PageDto.ProductName };
@ -181,6 +158,8 @@ public class DiscountActionDialogBoxViewModel : BaseViewModel<DiscountLDto>
} }
public void Cancel() => _mudDialog.Cancel(); public void Cancel() => _mudDialog.Cancel();
public async Task SubmitCreateAsync() public async Task SubmitCreateAsync()
@ -206,13 +185,6 @@ public class DiscountActionDialogBoxViewModel : BaseViewModel<DiscountLDto>
throw new Exception("کالا مورد نظر را برای تخفیف انتخاب نمایید"); throw new Exception("کالا مورد نظر را برای تخفیف انتخاب نمایید");
PageDto.ProductId = SelectedProduct.Id; PageDto.ProductId = SelectedProduct.Id;
} }
else if (IsBrandEnable)
{
PageDto.Type = DiscountType.Brand;
if (SelectedBrand == null)
throw new Exception("برند مورد نظر را برای تخفیف انتخاب نمایید");
PageDto.BrandId = SelectedBrand.Id;
}
var token = await _userUtility.GetBearerTokenAsync(); var token = await _userUtility.GetBearerTokenAsync();
if (token == null) if (token == null)
@ -222,43 +194,16 @@ public class DiscountActionDialogBoxViewModel : BaseViewModel<DiscountLDto>
if(StartDate != null) if(StartDate != null)
PageDto.StartDate = StartDate.Value; PageDto.StartDate = StartDate.Value;
var request = new CreateDiscountCommand(PageDto.Code, var request = PageDto.Adapt<CreateDiscountCommand>();
PageDto.Description, await _restWrapper.CrudApiRest<Discount, Guid>(Address.DiscountController).Create<CreateDiscountCommand>(request, token);
PageDto.DiscountPercent,
PageDto.DiscountAmount,
PageDto.HasCode,
PageDto.AmountType,
PageDto.Type,
PageDto.Count,
PageDto.StartDate,
PageDto.ExpireDate,
PageDto.Immortal,
PageDto.PriceFloor,
PageDto.HasPriceFloor,
PageDto.PriceCeiling,
PageDto.HasPriceCeiling,
PageDto.IsInfinity,
PageDto.UseCount,
PageDto.IsForInvitation,
PageDto.IsSpecialOffer,
PageDto.IsForFirstPurchase,
PageDto.ProductId,
PageDto.CategoryId,
PageDto.BrandId);
await _restWrapper.CrudDtoApiRest<Discount,DiscountLDto, Guid>(Address.DiscountController).Create<CreateDiscountCommand>(request, token);
_snackbar.Add($"ساخت تخفیف با موفقیت انجام شد", Severity.Success); _snackbar.Add($"ساخت تخفیف با موفقیت انجام شد", Severity.Success);
_mudDialog.Close(true); _mudDialog.Close(true);
} }
catch (ApiException ex) catch (ApiException ex)
{ {
if (ex.StatusCode == HttpStatusCode.BadRequest) var exe = await ex.GetContentAsAsync<ApiResult>();
{ _snackbar.Add(exe != null ? exe.Message : ex.Content, Severity.Error);
var exe = await ex.GetContentAsAsync<ApiResult>();
_snackbar.Add(exe != null ? exe.Message : ex.Content, Severity.Error);
}
else
_snackbar.Add(ex.Content, Severity.Error);
_mudDialog.Cancel(); _mudDialog.Cancel();
} }
catch (Exception e) catch (Exception e)
@ -272,7 +217,6 @@ public class DiscountActionDialogBoxViewModel : BaseViewModel<DiscountLDto>
IsProcessing = false; IsProcessing = false;
} }
} }
public async Task SubmitEditAsync() public async Task SubmitEditAsync()
{ {
try try
@ -299,43 +243,12 @@ public class DiscountActionDialogBoxViewModel : BaseViewModel<DiscountLDto>
throw new Exception("کالا مورد نظر را برای تخفیف انتخاب نمایید"); throw new Exception("کالا مورد نظر را برای تخفیف انتخاب نمایید");
PageDto.ProductId = SelectedProduct.Id; PageDto.ProductId = SelectedProduct.Id;
} }
else if (IsBrandEnable)
{
PageDto.Type = DiscountType.Brand;
if (SelectedBrand == null)
throw new Exception("برند مورد نظر را برای تخفیف انتخاب نمایید");
PageDto.BrandId = SelectedBrand.Id;
}
var token = await _userUtility.GetBearerTokenAsync(); var token = await _userUtility.GetBearerTokenAsync();
if (token == null) if (token == null)
throw new Exception("Token is null"); throw new Exception("Token is null");
PageDto.Id = _discountId; PageDto.Id = _discountId;
var request = new UpdateDiscountCommand( var request = PageDto.Adapt<UpdateDiscountCommand>();
PageDto.Id,
PageDto.Code,
PageDto.Description,
PageDto.DiscountPercent,
PageDto.DiscountAmount,
PageDto.HasCode,
PageDto.AmountType,
PageDto.Type,
PageDto.Count,
PageDto.StartDate,
PageDto.ExpireDate,
PageDto.Immortal,
PageDto.PriceFloor,
PageDto.HasPriceFloor,
PageDto.PriceCeiling,
PageDto.HasPriceCeiling,
PageDto.IsInfinity,
PageDto.UseCount,
PageDto.IsForInvitation,
PageDto.IsSpecialOffer,
PageDto.IsForFirstPurchase,
PageDto.ProductId,
PageDto.CategoryId,
PageDto.BrandId);
await _restWrapper.CrudApiRest<Discount, Guid>(Address.DiscountController).Update<UpdateDiscountCommand>(request, token); await _restWrapper.CrudApiRest<Discount, Guid>(Address.DiscountController).Update<UpdateDiscountCommand>(request, token);
_snackbar.Add($"ویرایش تخفیف با موفقیت انجام شد", Severity.Success); _snackbar.Add($"ویرایش تخفیف با موفقیت انجام شد", Severity.Success);
_mudDialog.Close(true); _mudDialog.Close(true);
@ -398,9 +311,9 @@ public class DiscountActionDialogBoxViewModel : BaseViewModel<DiscountLDto>
if (token == null) if (token == null)
throw new Exception("Token is null"); throw new Exception("Token is null");
if (product.IsNullOrEmpty()) if (product.IsNullOrEmpty())
response = await _restWrapper.ProductRestApi.ReadAll(0,null,null,null,token); response = await _restWrapper.ProductRestApi.ReadAll(0,null,null, token);
else else
response = await _restWrapper.ProductRestApi.ReadAll(product,token); response = await _restWrapper.ProductRestApi.ReadAll(product, token);
_products = response.Products; _products = response.Products;
return _products; return _products;
} }
@ -416,29 +329,4 @@ public class DiscountActionDialogBoxViewModel : BaseViewModel<DiscountLDto>
return _products; return _products;
} }
} }
private List<BrandSDto> _brands = new List<BrandSDto>();
public BrandSDto? SelectedBrand;
public async Task<IEnumerable<BrandSDto>> SearchBrand(string brand)
{
try
{
if (brand.IsNullOrEmpty())
_brands = await _restWrapper.BrandRestApi.ReadAll(0);
else
_brands = await _restWrapper.BrandRestApi.ReadAll(brand);
return _brands;
}
catch (ApiException ex)
{
var exe = await ex.GetContentAsAsync<ApiResult>();
_snackbar.Add(exe != null ? exe.Message : ex.Content, Severity.Error);
return _brands;
}
catch (Exception e)
{
_snackbar.Add(e.Message, Severity.Error);
return _brands;
}
}
} }

View File

@ -1,117 +0,0 @@
@inject ISnackbar Snackbar
@inject IRestWrapper RestWrapper
@inject IUserUtility UserUtility
@inject IDialogService DialogService
<MudDialog class="mx-auto">
<DialogContent>
<MudStack>
<MudDivider class="-mt-3" />
<MudStack Spacing="0">
<MudText Typo="Typo.h6">اطلاعات کلی</MudText>
<MudText Typo="Typo.caption">اطلاعات کلی را به دقت وارد کنید</MudText>
</MudStack>
<MudGrid>
<MudItem sm="12" lg="6" md="6">
<MudTextField T="string" Label="عنوان صفحه سوالات متداول" @bind-Value="@ViewModel.PageDto.Title" Variant="Variant.Outlined"></MudTextField>
</MudItem>
<MudItem sm="12" lg="6" md="6">
<MudTextField T="string" Label="اسلاگ صفحه سوالات متداول" @bind-Value="@ViewModel.PageDto.Slug" Variant="Variant.Outlined"></MudTextField>
</MudItem>
<MudItem sm="12" lg="12" md="12">
<MudText Typo="Typo.h6">سوالات متداول</MudText>
<MudText Typo="Typo.caption">می توانید سوالات متداول شهر موردنظر را وارد کنید</MudText>
<MudGrid>
<MudItem lg="5" md="6">
<MudTextField @bind-Value="@ViewModel.Question" T="string" Label="سوال" Variant="Variant.Outlined"></MudTextField>
</MudItem>
<MudItem lg="5" md="6">
<MudTextField @bind-Value="@ViewModel.Answer" T="string" Label="پاسخ" Variant="Variant.Outlined"></MudTextField>
</MudItem>
<MudItem lg="2" md="12">
<MudButton Variant="Variant.Filled"
Size="Size.Large"
Color="Color.Info"
class="mt-2 w-full py-3"
OnClick="ViewModel.AddFaq"
StartIcon="@Icons.Material.Outlined.Add">افزودن</MudButton>
</MudItem>
<MudItem sm="12">
<MudExpansionPanels class="mt-1" Elevation="2">
@foreach (var item in ViewModel.PageDto.Faqs)
{
<MudExpansionPanel>
<TitleContent>
<MudStack Row="true">
<MudIconButton Icon="@Icons.Material.Outlined.Delete"
Size="@Size.Small"
Variant="@Variant.Outlined"
Color="@Color.Error"
OnClick="()=>ViewModel.PageDto.Faqs.Remove(item.Key)" />
<MudText>@item.Key</MudText>
</MudStack>
</TitleContent>
<ChildContent>
@item.Value
</ChildContent>
</MudExpansionPanel>
}
</MudExpansionPanels>
</MudItem>
</MudGrid>
</MudItem>
</MudGrid>
</MudStack>
</DialogContent>
<DialogActions>
<MudStack Row="true" class="mx-4 mb-2 w-full">
@if (ViewModel.IsEditing)
{
<BaseButtonUi class="w-64 rounded-md" IsProcessing="@ViewModel.IsProcessing"
Icon="@Icons.Material.Outlined.Check"
Variant="Variant.Filled" Color="Color.Info"
Content="ثبت ویرایش" OnClickCallback="@ViewModel.SubmitUpdateAsync" />
}
else
{
<BaseButtonUi class="w-64 rounded-md" IsProcessing="@ViewModel.IsProcessing"
Icon="@Icons.Material.Outlined.Check"
Variant="Variant.Filled" Color="Color.Success"
Content="تایید" OnClickCallback="@ViewModel.SubmitAsync" />
}
<MudSpacer/>
<MudButton Variant="Variant.Outlined" Size="Size.Large" Color="Color.Error" OnClick="Cancel">بستن</MudButton>
</MudStack>
</DialogActions>
</MudDialog>
@code
{
[CascadingParameter]
MudDialogInstance MudDialog { get; set; }
void Cancel() => MudDialog.Cancel();
[Parameter]
public BaseFaq? Faq { get; set; }
public FaqActionDialogBoxViewModel ViewModel;
protected override async Task OnInitializedAsync()
{
if (Faq != null)
ViewModel = new FaqActionDialogBoxViewModel(Faq,UserUtility, Snackbar, RestWrapper, MudDialog);
else
ViewModel = new FaqActionDialogBoxViewModel(UserUtility, Snackbar, RestWrapper, MudDialog);
await ViewModel.InitializeAsync();
await base.OnInitializedAsync();
}
}

View File

@ -1,104 +0,0 @@
using Netina.Domain.MartenEntities.Faqs;
namespace Netina.AdminPanel.PWA.Dialogs;
public class FaqActionDialogBoxViewModel : BaseViewModel<BaseFaq>
{
private readonly IRestWrapper _restWrapper;
private readonly ISnackbar _snackbar;
private readonly MudDialogInstance _dialogInstance;
public bool IsEditing = false;
public FaqActionDialogBoxViewModel(IUserUtility userUtility, ISnackbar snackbar, IRestWrapper restWrapper, MudDialogInstance dialogInstance) : base(userUtility)
{
_snackbar = snackbar;
_restWrapper = restWrapper;
_dialogInstance = dialogInstance;
}
public FaqActionDialogBoxViewModel(BaseFaq faq,IUserUtility userUtility, ISnackbar snackbar, IRestWrapper restWrapper, MudDialogInstance dialogInstance) : base(userUtility)
{
PageDto = faq;
IsEditing = true;
_snackbar = snackbar;
_restWrapper = restWrapper;
_dialogInstance = dialogInstance;
}
public string Question { get; set; } = string.Empty;
public string Answer { get; set; } = string.Empty;
public void AddFaq()
{
try
{
if (Question.IsNullOrEmpty())
throw new Exception("سوال را وارد کنید");
if (Answer.IsNullOrEmpty())
throw new Exception("پاسخ را وارد کنید");
PageDto.Faqs.Add(Question,Answer);
}
catch (Exception e)
{
_snackbar.Add(e.Message, Severity.Error);
}
}
public async Task SubmitAsync()
{
try
{
var token = await _userUtility.GetBearerTokenAsync();
if (token == null)
throw new Exception("token is null");
if (PageDto.Slug.IsNullOrEmpty())
throw new Exception("اسلاگ صفحه سوال متداول را وارد کنید");
if (PageDto.Title.IsNullOrEmpty())
throw new Exception("عنوان صفحه سوالات متداول را وارد کنید");
await _restWrapper.FaqApiRest.Create(PageDto, token);
_snackbar.Add("تغییر سوالات متداول با موفقیت انجام شد", Severity.Success);
_dialogInstance.Close(DialogResult.Ok(true));
}
catch (ApiException ex)
{
var exe = await ex.GetContentAsAsync<ApiResult>();
_snackbar.Add(exe != null ? exe.Message : ex.Content, Severity.Error);
}
catch (Exception e)
{
_snackbar.Add(e.Message, Severity.Error);
}
}
public async Task SubmitUpdateAsync()
{
try
{
var token = await _userUtility.GetBearerTokenAsync();
if (token == null)
throw new Exception("token is null");
if (PageDto.Slug.IsNullOrEmpty())
throw new Exception("اسلاگ صفحه سوال متداول را وارد کنید");
if (PageDto.Title.IsNullOrEmpty())
throw new Exception("عنوان صفحه سوالات متداول را وارد کنید");
if (PageDto.Id == default)
throw new Exception("ای دی معتبر نمی باشد");
await _restWrapper.FaqApiRest.Update(PageDto, token);
_snackbar.Add("تغییر سوالات متداول با موفقیت انجام شد", Severity.Success);
_dialogInstance.Close(DialogResult.Ok(true));
}
catch (ApiException ex)
{
var exe = await ex.GetContentAsAsync<ApiResult>();
_snackbar.Add(exe != null ? exe.Message : ex.Content, Severity.Error);
}
catch (Exception e)
{
_snackbar.Add(e.Message, Severity.Error);
}
}
}

View File

@ -1,195 +0,0 @@
@inject ISnackbar Snackbar
@inject IRestWrapper RestWrapper
@inject IUserUtility UserUtility
@inject IDialogService DialogService
<MudDialog class="mx-auto h-screen overflow-y-auto p-0">
<DialogContent>
<MudContainer class="p-0">
<MudStack Row="true">
<MudText Typo="Typo.h6" class="my-auto">افزودن سریع محصول</MudText>
<MudSpacer />
<MudIconButton Icon="@Icons.Material.Filled.Close" OnClick="()=>MudDialog.Close(DialogResult.Ok(true))"></MudIconButton>
</MudStack>
<MudAlert Dense="true" NoIcon="true" Variant="Variant.Outlined" ContentAlignment="HorizontalAlignment.Center" class="mb-4 mt-2" Severity="Severity.Warning">در این صفحه تنها اطلاعات اولیه ثبت میشوند و باید برای تکمیل اطلاعات محصول به صحفه اصلی تغییرات محصول بروید</MudAlert>
<MudStack Row="true" class="no-scrollbar h-full w-full overflow-x-auto">
<MudStack class="min-w-[310px]">
<MudText Typo="Typo.h6"><b>1. انتخاب دسته بندی</b></MudText>
<MudTextField class="-mt-3 flex-none" T="string" Label="جست جو دسته" />
<MudTreeView MultiSelection="false" @bind-SelectedValue="@ViewModel.SelectedCategory" T="ProductCategorySDto" ServerData="ViewModel.LoadCategories" Items="ViewModel.Categories">
<ItemTemplate>
<MudTreeViewItem class="my-1" Value="@context" LoadingIconColor="Color.Info"
Text="@context.Name"
EndTextTypo="@Typo.caption" />
</ItemTemplate>
</MudTreeView>
</MudStack>
<MudDivider Vertical="true" FlexItem="true" class="mx-1" />
<MudStack class="min-w-[310px] sm:w-full">
<MudStack Row="true">
<MudText Typo="Typo.h6">1. افزودن محصول به <b> @ViewModel.SelectedCategory?.Name</b></MudText>
<MudSpacer/>
<MudButton Disabled="@ViewModel.FormEnable.Not()" Variant="Variant.Outlined" Color="Color.Success" StartIcon="@Icons.Material.Filled.Check" OnClick="@ViewModel.SubmitCreateProduct">ثبت محصول</MudButton>
</MudStack>
<MudGrid Spacing="1" class="-ml-1 w-full">
<MudItem xs="12" md="6">
<MudTextField Disabled="@ViewModel.FormEnable.Not()" @bind-Value="@ViewModel.PageDto.PersianName" Variant="Variant.Outlined" T="string" Label="نام فارسی کالا" />
</MudItem>
<MudItem xs="12" md="6">
<MudAutocomplete Disabled="@ViewModel.FormEnable.Not()"
Required="true"
ToStringFunc="dto => dto.PersianName"
Strict="true"
@bind-Value="@ViewModel.SelectedBrand"
SearchFunc="ViewModel.SearchBrand"
@bind-Text="@brandAutocompleteText"
T="BrandSDto"
Label="برند"
Variant="Variant.Outlined">
<NoItemsTemplate>
<MudStack Row="true" class="p-1">
<MudChip Variant="Variant.Text" class="my-auto"
Color="Color.Info">@brandAutocompleteText</MudChip>
<MudSpacer />
<MudIconButton Icon="@Icons.Material.Filled.Add"
Size="@Size.Small"
Variant="@Variant.Outlined"
OnClick="()=>ViewModel.AddBrand(brandAutocompleteText)"
Color="@Color.Secondary" />
</MudStack>
</NoItemsTemplate>
<BeforeItemsTemplate>
@if (!brandAutocompleteText.IsNullOrEmpty())
{
<MudStack Row="true">
<MudChip Variant="Variant.Text" class="my-auto"
Color="Color.Info">@brandAutocompleteText</MudChip>
<MudSpacer />
<MudIconButton Icon="@Icons.Material.Filled.Add"
Size="@Size.Small"
Variant="@Variant.Outlined"
Color="@Color.Secondary" />
</MudStack>
}
</BeforeItemsTemplate>
<ProgressIndicatorInPopoverTemplate>
<MudList Clickable="false">
<MudListItem>
<div class="mx-auto flex w-full flex-row">
<MudProgressCircular class="my-auto -ml-4 mr-1" Size="Size.Small" Indeterminate="true" />
<p class="text-md mx-auto my-1 font-bold">منتظر بمانید</p>
</div>
</MudListItem>
</MudList>
</ProgressIndicatorInPopoverTemplate>
<ItemTemplate Context="e">
<p>@e.PersianName</p>
</ItemTemplate>
</MudAutocomplete>
</MudItem>
<MudItem xs="12" md="6">
<MudTextField Disabled="@ViewModel.FormEnable.Not()" @bind-Value="@ViewModel.PageDto.Stock" Variant="Variant.Outlined" T="int" Label="تعداد موجودی" />
</MudItem>
<MudItem xs="12" md="6">
<MudTextField Disabled="@ViewModel.FormEnable.Not()" @bind-Value="@ViewModel.PageDto.Cost" Format="N0" Variant="Variant.Outlined" T="double" Label="قیمت ( تومان )" />
</MudItem>
</MudGrid>
<MudExpansionPanels DisableBorders="false">
<MudExpansionPanel Text="ویژگی ها ( اختیاری )">
<MudGrid>
<MudItem xs="12" lg="6" md="6">
<MudTextField @bind-Value="@ViewModel.SpecificationTitle" T="string" Label="عنوان" Variant="Variant.Outlined"></MudTextField>
</MudItem>
<MudItem xs="12" lg="6" md="6">
<MudStack Row="true">
<MudTextField @bind-Value="@ViewModel.SpecificationValue" T="string" Label="مقدار" Variant="Variant.Outlined"></MudTextField>
<MudButton Variant="Variant.Filled"
Size="Size.Large"
Color="Color.Info"
class="mt-2 py-2"
OnClick="ViewModel.AddSpecification"
StartIcon="@Icons.Material.Outlined.Add">افزودن</MudButton>
</MudStack>
</MudItem>
<MudItem xs="12">
<MudDataGrid Items="@ViewModel.Specifications" Elevation="0" Outlined="true" Bordered="true" Striped="true" Filterable="false" SortMode="@SortMode.None" Groupable="false">
<Columns>
<PropertyColumn Property="x => x.Title" Title="عنوان" />
<PropertyColumn Property="x => x.Value" Title="مقدار" />
<TemplateColumn T="SpecificationSDto" CellClass="d-flex justify-end">
<CellTemplate>
<MudStack Row>
<MudButton DisableElevation="true"
Size="@Size.Small"
Variant="@Variant.Filled"
OnClick="()=>ViewModel.RemoveSpecification(context.Item)"
Color="@Color.Error"
StartIcon="@Icons.Material.Outlined.Delete">حذف</MudButton>
</MudStack>
</CellTemplate>
</TemplateColumn>
</Columns>
</MudDataGrid>
</MudItem>
</MudGrid>
</MudExpansionPanel>
</MudExpansionPanels>
<MudFileUpload T="IReadOnlyList<IBrowserFile>"
AppendMultipleFiles
OnFilesChanged="@ViewModel.OnInputFileChanged"
Hidden="@false"
Disabled="@ViewModel.FormEnable.Not()"
InputClass="absolute mud-width-full mud-height-full overflow-hidden z-20"
InputStyle="opacity:0"
class="flex-none"
Accept=".png, .jpg"
@ondragenter="@ViewModel.SetDragClass"
@ondragleave="@ViewModel.ClearDragClass"
@ondragend="@ViewModel.ClearDragClass">
<ButtonTemplate>
<MudPaper Height="300px"
Outlined="true"
Class="@ViewModel.DragClass">
<MudText Typo="Typo.h6">
فایل های خود را داخل کادر بکشید یا با کلیک روی کادر انتخاب کنید
</MudText>
@foreach (var file in ViewModel.FileNames)
{
<MudChip Color="Color.Dark" Text="@file" />
}
</MudPaper>
</ButtonTemplate>
</MudFileUpload>
</MudStack>
</MudStack>
</MudContainer>
</DialogContent>
</MudDialog>
@code
{
[CascadingParameter]
MudDialogInstance MudDialog { get; set; }
string brandAutocompleteText = string.Empty;
public FastProductCreateDialogBoxViewModel ViewModel { get; set; }
protected override async Task OnInitializedAsync()
{
ViewModel = new FastProductCreateDialogBoxViewModel(Snackbar, RestWrapper, UserUtility, DialogService, MudDialog);
await ViewModel.InitializeAsync();
await base.OnInitializedAsync();
}
}

View File

@ -1,217 +0,0 @@
using MediatR;
using Microsoft.AspNetCore.Components.Forms;
using Netina.Domain.Entities.Brands;
namespace Netina.AdminPanel.PWA.Dialogs;
public class FastProductCreateDialogBoxViewModel(ISnackbar snackbar, IRestWrapper restWrapper, IUserUtility userUtility, IDialogService dialogService, MudDialogInstance dialogInstance)
: BaseViewModel<ProductLDto>(userUtility)
{
public HashSet<ProductCategorySDto> Categories { get; set; } = new();
public bool FormEnable = false;
private ProductCategorySDto? _selectedCategory;
public ProductCategorySDto? SelectedCategory
{
get => _selectedCategory;
set
{
_selectedCategory = value;
FormEnable = _selectedCategory != null;
}
}
public BrandSDto? SelectedBrand { get; set; }
public override async Task InitializeAsync()
{
var categories = await restWrapper.ProductCategoryRestApi.ReadAll(true);
categories.ForEach(c => Categories.Add(c));
PageDto.Stock = 10;
await base.InitializeAsync();
}
public async Task<HashSet<ProductCategorySDto>> LoadCategories(ProductCategorySDto arg)
{
return arg.Children.ToHashSet();
}
private readonly List<IBrowserFile> Files = new();
public readonly List<string> FileNames = new();
private const string DefaultDragClass = "relative rounded-lg border-2 border-dashed pa-4 mt-4 mud-width-full mud-height-full z-10";
public string DragClass = DefaultDragClass;
public void SetDragClass()
=> DragClass = $"{DefaultDragClass} mud-border-primary";
public void ClearDragClass()
=> DragClass = DefaultDragClass;
public void OnInputFileChanged(InputFileChangeEventArgs e)
{
ClearDragClass();
var files = e.GetMultipleFiles();
foreach (var file in files)
{
FileNames.Add(file.Name);
Files.Add(file);
}
}
private List<BrandSDto> brands = new();
public async Task<IEnumerable<BrandSDto>> SearchBrand(string brand)
{
try
{
if (brands.Count == 0)
brands = await restWrapper.BrandRestApi.ReadAll();
if (brand.IsNullOrEmpty().Not())
return brands.Where(b => b.PersianName.Trim().ToUpper().Contains(brand.Trim().ToUpper()));
return brands;
}
catch (ApiException ex)
{
var exe = await ex.GetContentAsAsync<ApiResult>();
snackbar.Add(exe != null ? exe.Message : ex.Content, Severity.Error);
return brands;
}
catch (Exception e)
{
snackbar.Add(e.Message, Severity.Error);
return brands;
}
}
public void AddBrand(string brandName)
{
if (brandName.IsNullOrEmpty())
return;
var brand = new BrandSDto { PersianName = brandName };
brands.Add(brand);
SelectedBrand = brand;
Task.Run(async () =>
{
var token = await userUtility.GetBearerTokenAsync();
if (token == null)
return;
var command = brand.Adapt<CreateBrandCommand>() with { Files = new() };
var response = await restWrapper.CrudApiRest<Brand, Guid>(Address.BrandController)
.Create(command, token);
brand.Id = response;
snackbar.Add($"افزودن برند {brand.PersianName} با موفقیت انجام شد");
});
}
public void SubmitCreateProduct()
{
try
{
if (SelectedCategory == null)
throw new Exception("دسته بندی انتخاب نشده است");
if (SelectedBrand == null || SelectedBrand.Id == default)
throw new Exception("برند انتخاب نشده است");
if (PageDto.PersianName.IsNullOrEmpty())
throw new Exception("نام فارسی را وارد کنید");
var product = PageDto.Clone();
var brand = SelectedBrand.Clone();
var browserFiles = Files.ToList();
var specifications = Specifications.ToList();
Task.Run(async () =>
{
try
{
var token = await userUtility.GetBearerTokenAsync();
if (token == null)
throw new Exception("Token is null");
var files = new List<StorageFileSDto>();
foreach (var file in browserFiles)
{
using var memoryStream = new MemoryStream();
var stream = file.OpenReadStream();
await stream.CopyToAsync(memoryStream);
var fileUpload = new FileUploadRequest
{
ContentType = file.ContentType,
FileName = file.Name,
FileUploadType = FileUploadType.Image,
StringBaseFile = Convert.ToBase64String(memoryStream.ToArray())
};
var rest = await restWrapper.FileRestApi.UploadFileAsync(fileUpload, token);
files.Add(new StorageFileSDto
{
FileLocation = rest.FileLocation,
FileName = rest.FileName,
FileType = StorageFileType.Image
});
}
product.Cost *= 10;
var command = new CreateProductCommand(product.PersianName, product.EnglishName, product.Summery,
product.ExpertCheck,
product.Tags,
product.Warranty,
true,
product.Cost,
product.PackingCost,
product.Stock,
product.HasExpressDelivery,
product.MaxOrderCount,
product.IsSpecialOffer,
brand.Id,
SelectedCategory.Id,
null,
specifications,
files,
new Dictionary<string, string>(),
new Dictionary<string, string>());
await restWrapper.CrudApiRest<Product, Guid>(Address.ProductController).Create<CreateProductCommand>(command, token);
}
catch (ApiException ex)
{
if (ex.StatusCode != HttpStatusCode.OK)
snackbar.Add(ex.Message, Severity.Error);
}
catch (Exception e)
{
snackbar.Add(e.Message, Severity.Error);
}
});
PageDto = new ProductLDto { Stock = 10 };
FileNames.Clear();
//Specifications.Clear();
Files.Clear();
}
catch (Exception e)
{
snackbar.Add(e.Message, Severity.Error);
}
}
public string SpecificationTitle = string.Empty;
public string SpecificationValue = string.Empty;
public readonly ObservableCollection<SpecificationSDto> Specifications = new ObservableCollection<SpecificationSDto>();
public void AddSpecification()
{
try
{
if (SpecificationTitle.IsNullOrEmpty())
throw new AppException("عنوان ویژگی مورد نظر را وارد کنید");
if (SpecificationValue.IsNullOrEmpty())
throw new AppException("مقدار ویژگی مورد نظر را وارد کنید");
Specifications.Add(new SpecificationSDto { Title = SpecificationTitle.ToString(), Value = SpecificationValue.ToString() });
SpecificationTitle = string.Empty;
SpecificationValue = string.Empty;
}
catch (Exception e)
{
snackbar.Add(e.Message, Severity.Error);
}
}
public void RemoveSpecification(SpecificationSDto specification)
{
var spec = Specifications.FirstOrDefault(s => s.Value == specification.Value && s.Title == specification.Title);
if (spec != null)
Specifications.Remove(spec);
}
}

View File

@ -199,7 +199,6 @@
<BaseButtonUi class="h-12 w-full rounded-md" IsProcessing="@ViewModel.IsProcessing" <BaseButtonUi class="h-12 w-full rounded-md" IsProcessing="@ViewModel.IsProcessing"
Icon="@Icons.Material.Outlined.RemoveCircle" Icon="@Icons.Material.Outlined.RemoveCircle"
Variant="Variant.Outlined" Color="Color.Error" Variant="Variant.Outlined" Color="Color.Error"
OnClickCallback="ViewModel.CancelAsync"
Content="لغو سفارش" /> Content="لغو سفارش" />
</MudItem> </MudItem>

View File

@ -259,41 +259,4 @@ public class OrderActionDialogBoxViewModel : BaseViewModel<OrderLDto>
} }
} }
public async Task CancelAsync()
{
var reference = await _dialogService.ShowQuestionDialog($"ایا از کنسل کردن سفارش اطمینان دارید ?");
var result = await reference.Result;
if (!result.Canceled)
{
try
{
var token = await _userUtility.GetBearerTokenAsync();
if (token == null)
throw new Exception("Token is null");
IsProcessing = true;
await _restWrapper.OrderRestApi.CancelOrderStepAsync(PageDto.Id, token);
_snackbar.Add($"سفارش {PageDto.FactorCode} کنسل شد", Severity.Warning);
_mudDialog.Close(true);
}
catch (ApiException ex)
{
var exe = await ex.GetContentAsAsync<ApiResult>();
_snackbar.Add(exe != null ? exe.Message : ex.Content, Severity.Error);
_mudDialog.Cancel();
}
catch (Exception e)
{
_snackbar.Add(e.Message, Severity.Error);
_mudDialog.Cancel();
}
finally
{
IsProcessing = false;
}
}
}
} }

View File

@ -1,130 +0,0 @@
@inject ISnackbar Snackbar
@inject IRestWrapper RestWrapper
@inject IUserUtility UserUtility
@inject IDialogService DialogService
<MudDialog DisableSidePadding="true" class="mx-auto">
<DialogContent>
<MudContainer class="max-h-[30rem]" Style="overflow-y: scroll">
<MudStack>
<MudDivider class="-mt-3" />
<MudStack Spacing="0">
<MudText Typo="Typo.h6"><b>اطلاعات کلی</b></MudText>
<MudText Typo="Typo.caption">اطلاعات کلی روش ارسال را به دقت وارد کنید</MudText>
</MudStack>
<MudGrid>
<MudItem sm="12" md="6">
<MudTextField T="string" Label="نام" @bind-Value="@ViewModel.PageDto.Title" Variant="Variant.Outlined"></MudTextField>
</MudItem>
<MudItem sm="12" md="6">
<MudTextField T="string" Label="آدرس صفحه" @bind-Value="@ViewModel.PageDto.Slug" Variant="Variant.Outlined"></MudTextField>
</MudItem>
<MudItem sm="12" md="6">
<MudSelect T="bool" @bind-Value="@ViewModel.PageDto.Indexing" Label="ایا صفحه ایندکس شور ؟" ToStringFunc="b=>b.ToPersianString()" Variant="Variant.Outlined" AnchorOrigin="Origin.BottomCenter">
<MudSelectItem T="bool" Value="false" />
<MudSelectItem T="bool" Value="true" />
</MudSelect>
</MudItem>
</MudGrid>
<MudStack Row="true">
<MudStack Spacing="0" class="mt-3">
<MudText Typo="Typo.h6"><b>سکشن ها</b></MudText>
<MudText Typo="Typo.caption">اطلاعات سکشن ها را می توانید تغییر دهید</MudText>
</MudStack>
<MudSpacer />
<MudButton Variant="Variant.Filled"
DisableElevation="true"
StartIcon="@Icons.Material.Outlined.Add"
Color="Color.Secondary"
OnClick="@ViewModel.AddSection"
class="my-auto">افزودن سکشن</MudButton>
</MudStack>
<MudGrid>
<MudItem sm="12">
<MudDataGrid Items="@ViewModel.PageDto.Sections"
T="BasePageSection"
Elevation="0"
Outlined="true"
Bordered="true"
Striped="true"
Filterable="false"
SortMode="@SortMode.None"
Groupable="false">
<Columns>
<PropertyColumn T="BasePageSection" TProperty="string" Property="x => x.Title" Title="عنوان" />
<PropertyColumn T="BasePageSection" TProperty="string" Property="x => x.CTAText" Title="عنوان دکمه" />
<PropertyColumn T="BasePageSection" TProperty="string" Property="x => x.CTARoute" Title="ادرس دکمه" />
<PropertyColumn T="BasePageSection" TProperty="BasePageSectionType" Property="x => x.Type" Title="نوع سکشن" />
<PropertyColumn T="BasePageSection" TProperty="string" Property="x => x.Query" Title="کوئری" />
<TemplateColumn T="BasePageSection" CellClass="d-flex justify-end">
<CellTemplate>
<MudStack Row>
<MudButton DisableElevation="true"
Size="@Size.Small"
Variant="@Variant.Filled"
OnClick="()=>ViewModel.PageDto.Sections.Remove(context.Item)"
Color="@Color.Error"
StartIcon="@Icons.Material.Outlined.Delete">حذف</MudButton>
<MudButton DisableElevation="true"
Size="@Size.Small"
Variant="@Variant.Filled"
OnClick="async()=>await ViewModel.EditSection(context.Item)"
Color="@Color.Info"
StartIcon="@Icons.Material.Outlined.Edit">ویرایش</MudButton>
</MudStack>
</CellTemplate>
</TemplateColumn>
</Columns>
</MudDataGrid>
</MudItem>
</MudGrid>
</MudStack>
</MudContainer>
</DialogContent>
<DialogActions>
<MudStack Row="true" class="w-full mx-4 mb-2">
@if (ViewModel.IsEditing)
{
<BaseButtonUi class="w-64 rounded-md" IsProcessing="@ViewModel.IsProcessing"
Icon="@Icons.Material.Outlined.Check"
Variant="Variant.Filled" Color="Color.Success"
Content="ثبت ویرایش" OnClickCallback="@ViewModel.SubmitEditAsync" />
}
else
{
<BaseButtonUi class="w-64 rounded-md" IsProcessing="@ViewModel.IsProcessing"
Icon="@Icons.Material.Outlined.Check"
Variant="Variant.Filled" Color="Color.Success"
Content="تایید" OnClickCallback="@ViewModel.SubmitCreateAsync" />
}
<MudSpacer />
<MudButton Variant="Variant.Outlined" Size="Size.Large" Color="Color.Error" OnClick="@ViewModel.Cancel">بستن</MudButton>
</MudStack>
</DialogActions>
</MudDialog>
@code {
[CascadingParameter]
MudDialogInstance MudDialog { get; set; }
[Parameter]
public BasePageSDto? Page { get; set; }
public PageActionDialogBoxViewModel ViewModel { get; set; }
protected override async Task OnInitializedAsync()
{
if (Page == null)
ViewModel = new PageActionDialogBoxViewModel(Snackbar, RestWrapper, UserUtility, DialogService, MudDialog);
else
ViewModel = new PageActionDialogBoxViewModel(Snackbar, RestWrapper, UserUtility, DialogService, MudDialog, Page);
await ViewModel.InitializeAsync();
await base.OnInitializedAsync();
}
}

View File

@ -1,215 +0,0 @@
using Netina.Domain.Entities.Blogs;
using Netina.Domain.Entities.Warehouses;
using System.Reflection.Metadata;
namespace Netina.AdminPanel.PWA.Dialogs;
public class PageActionDialogBoxViewModel : BaseViewModel<BasePageLDto>
{
private readonly ISnackbar _snackbar;
private readonly IRestWrapper _restWrapper;
private readonly IUserUtility _userUtility;
private readonly IDialogService _dialogService;
private readonly MudDialogInstance _mudDialog;
public PageActionDialogBoxViewModel(ISnackbar snackbar,
IRestWrapper restWrapper,
IUserUtility userUtility,
IDialogService dialogService,
MudDialogInstance mudDialog) : base(userUtility)
{
_snackbar = snackbar;
_restWrapper = restWrapper;
_userUtility = userUtility;
_dialogService = dialogService;
_mudDialog = mudDialog;
}
public PageActionDialogBoxViewModel(ISnackbar snackbar,
IRestWrapper restWrapper,
IUserUtility userUtility,
IDialogService dialogService,
MudDialogInstance mudDialog,
BasePageSDto page) : base(userUtility)
{
_snackbar = snackbar;
_restWrapper = restWrapper;
_userUtility = userUtility;
_dialogService = dialogService;
_mudDialog = mudDialog;
IsEditing = true;
PageId = page.Id;
}
public override async Task InitializeAsync()
{
try
{
IsProcessing = true;
var token = await _userUtility.GetBearerTokenAsync();
if (token == null)
throw new Exception("Token is null");
var pages = await _restWrapper.PageRestApi.ReadById(PageId, token);
PageDto = pages;
}
catch (ApiException e)
{
var exe = await e.GetContentAsAsync<ApiResult>();
_snackbar.Add(exe != null ? exe.Message : e.Content, Severity.Error);
}
catch (Exception ex)
{
_snackbar.Add(ex.Message, Severity.Error);
}
finally
{
IsProcessing = false;
}
await base.InitializeAsync();
}
public bool IsEditing = false;
public Guid PageId { get; set; }
public void Cancel() => _mudDialog.Cancel();
public async Task AddSection()
{
try
{
DialogOptions maxWidth = new DialogOptions() { MaxWidth = MaxWidth.Medium, FullWidth = true, DisableBackdropClick = true };
var dialog = await _dialogService.ShowAsync<PageSectionActionDialogBox>("افزودن سکشن", maxWidth);
var result = await dialog.Result;
var file = result.Data;
if (file is BasePageSection section)
PageDto.Sections.Add(section);
}
catch (Exception ex)
{
_snackbar.Add(ex.Message, Severity.Error);
}
}
public async Task EditSection(BasePageSection sec)
{
try
{
DialogOptions maxWidth = new DialogOptions() { MaxWidth = MaxWidth.Medium, FullWidth = true, DisableBackdropClick = true };
var parameters = new DialogParameters<PageSectionActionDialogBox>();
parameters.Add(x => x.Page, sec);
var dialog = await _dialogService.ShowAsync<PageSectionActionDialogBox>("ویرایش سکشن",parameters, maxWidth);
var result = await dialog.Result;
var file = result.Data;
if (file is BasePageSection section)
{
PageDto.Sections.Remove(sec);
PageDto.Sections.Add(section);
}
}
catch (Exception ex)
{
_snackbar.Add(ex.Message, Severity.Error);
}
}
public async Task SubmitEditAsync()
{
try
{
IsProcessing = true;
if (PageDto.Id == default)
throw new Exception("Id is null !");
var token = await _userUtility.GetBearerTokenAsync();
if (token == null)
throw new Exception("Token is null");
if (PageDto.Title.IsNullOrEmpty())
throw new Exception("نام را وارد کنید");
var request = new PageActionRequestDto
{
Id = PageDto.Id,
Title = PageDto.Title,
Description = PageDto.Description,
Content = PageDto.Content,
IsCustomPage = PageDto.IsCustomPage,
IsHtmlBasePage = PageDto.IsHtmlBasePage,
Slug = PageDto.Slug,
Data = PageDto.Data,
Indexing = PageDto.Indexing,
Sections = PageDto.Sections
};
await _restWrapper.CrudApiRest<Shipping, Guid>(Address.PageController).Update<PageActionRequestDto>(request, token);
_snackbar.Add($"ویرایش {PageDto.Title} با موفقیت انجام شد", Severity.Success);
_mudDialog.Close(DialogResult.Ok(true));
}
catch (ApiException ex)
{
var exe = await ex.GetContentAsAsync<ApiResult>();
_snackbar.Add(exe != null ? exe.Message : ex.Content, Severity.Error);
_mudDialog.Cancel();
}
catch (Exception e)
{
_snackbar.Add(e.Message, Severity.Error);
_mudDialog.Cancel();
}
finally
{
IsProcessing = false;
}
}
public async Task SubmitCreateAsync()
{
try
{
IsProcessing = true;
var token = await _userUtility.GetBearerTokenAsync();
if (token == null)
throw new Exception("Token is null");
if (PageDto.Title.IsNullOrEmpty())
throw new Exception("نام را وارد کنید");
var request = new PageActionRequestDto
{
Title = PageDto.Title,
Description = PageDto.Description,
Content = PageDto.Content,
IsCustomPage = PageDto.IsCustomPage,
IsHtmlBasePage = PageDto.IsHtmlBasePage,
Slug = PageDto.Slug,
Data = PageDto.Data,
Indexing = PageDto.Indexing,
Sections = PageDto.Sections
};
await _restWrapper.CrudApiRest<Shipping, Guid>(Address.PageController).Create<PageActionRequestDto>(request, token);
_snackbar.Add($"ساخت {PageDto.Title} با موفقیت انجام شد", Severity.Success);
_mudDialog.Close(DialogResult.Ok(true));
}
catch (ApiException ex)
{
var exe = await ex.GetContentAsAsync<ApiResult>();
_snackbar.Add(exe != null ? exe.Message : ex.Content, Severity.Error);
_mudDialog.Cancel();
}
catch (Exception e)
{
_snackbar.Add(e.Message, Severity.Error);
_mudDialog.Cancel();
}
finally
{
IsProcessing = false;
}
}
}

View File

@ -1,150 +0,0 @@
@inject ISnackbar Snackbar
@inject IRestWrapper RestWrapper
@inject IUserUtility UserUtility
@inject IDialogService DialogService
<MudDialog DisableSidePadding="true" class="mx-auto">
<DialogContent>
<MudContainer class="max-h-[30rem]" Style="overflow-y: scroll">
<MudStack>
<MudDivider class="-mt-3" />
<MudStack Spacing="0">
<MudText Typo="Typo.h6"><b>اطلاعات کلی</b></MudText>
<MudText Typo="Typo.caption">اطلاعات کلی سکشن را با دقت وارد کنید</MudText>
</MudStack>
<MudGrid>
<MudItem sm="12" md="6" lg="4">
<MudTextField T="string" Label="عنوان سکشن" @bind-Value="@ViewModel.PageDto.Title" Variant="Variant.Outlined"></MudTextField>
</MudItem>
<MudItem sm="12" md="6" lg="4">
<MudTextField T="string" Label="عنوان دکمه" @bind-Value="@ViewModel.PageDto.CTAText" Variant="Variant.Outlined"></MudTextField>
</MudItem>
<MudItem sm="12" md="6" lg="4">
<MudTextField T="string" Label="آدرس دکمه" @bind-Value="@ViewModel.PageDto.CTARoute" Variant="Variant.Outlined"></MudTextField>
</MudItem>
<MudItem sm="12">
<MudTextField T="string" Label="توضیحاتــ" @bind-Value="@ViewModel.PageDto.Description" Variant="Variant.Outlined"></MudTextField>
</MudItem>
<MudItem sm="12" md="4">
<MudSelect Variant="Variant.Outlined" T="BasePageSectionType"
ToStringFunc="type => type.ToDisplay()"
Label="نوع سکشن"
@bind-Value="@ViewModel.PageDto.Type">
@foreach (var state in Enum.GetValues(typeof(BasePageSectionType)).Cast<BasePageSectionType>())
{
<MudSelectItem T="BasePageSectionType" Value="state"></MudSelectItem>
}
</MudSelect>
</MudItem>
<MudItem sm="12" md="8">
<MudTextField T="string" Label="کوئری" @bind-Value="@ViewModel.PageDto.Query" Variant="Variant.Outlined"></MudTextField>
</MudItem>
</MudGrid>
<MudStack Spacing="0">
<MudText Typo="Typo.h6"><b>ایتم ها</b></MudText>
<MudText Typo="Typo.caption">ایتم های سکشن را به دستی میتوانید تغییر دهید</MudText>
</MudStack>
<MudGrid>
<MudItem sm="12" md="5">
<MudTextField T="string" Label="عنوان ایتم" @bind-Value="@ViewModel.SelectedSectionItem.Title" Variant="Variant.Outlined"></MudTextField>
</MudItem>
<MudItem sm="12" md="7">
<MudTextField T="string" Label="توضیحات ایتم" @bind-Value="@ViewModel.SelectedSectionItem.Description" Variant="Variant.Outlined"></MudTextField>
</MudItem>
<MudItem sm="12" md="8">
<MudTextField T="string" Label="ادرس ایتم" @bind-Value="@ViewModel.SelectedSectionItem.Url" Variant="Variant.Outlined"></MudTextField>
</MudItem>
<MudItem sm="12" md="4">
<MudStack Row="true" class="mt-3">
@if (ViewModel.IsFileSelected)
{
<MudButton Variant="Variant.Filled" Size="Size.Large" Color="Color.Info" OnClick="@ViewModel.SelectFileAsync">تغییر عکس</MudButton>
}
else
{
<MudButton Variant="Variant.Outlined" Size="Size.Large" Color="Color.Info" OnClick="@ViewModel.SelectFileAsync">انتخاب عکس</MudButton>
}
<MudButton Variant="Variant.Outlined" Size="Size.Large" Color="Color.Success" OnClick="@ViewModel.AddItem">افزودن</MudButton>
</MudStack>
</MudItem>
<MudItem sm="12">
<MudDataGrid Items="@ViewModel.PageDto.SectionItems"
T="SectionItem"
Elevation="0"
Outlined="true"
Bordered="true"
Striped="true"
Filterable="false"
SortMode="@SortMode.None"
Groupable="false">
<Columns>
<PropertyColumn T="SectionItem" TProperty="string" Property="x => x.Title" Title="عنوان" />
<PropertyColumn T="SectionItem" TProperty="string" Property="x => x.Url" Title="آدرس" />
<TemplateColumn T="SectionItem" CellClass="d-flex justify-end">
<CellTemplate>
<MudStack Row>
<MudButton DisableElevation="true"
Size="@Size.Small"
Variant="@Variant.Filled"
OnClick="()=>ViewModel.PageDto.SectionItems.Remove(context.Item)"
Color="@Color.Error"
StartIcon="@Icons.Material.Outlined.Delete">حذف</MudButton>
</MudStack>
</CellTemplate>
</TemplateColumn>
</Columns>
</MudDataGrid>
</MudItem>
</MudGrid>
</MudStack>
</MudContainer>
</DialogContent>
<DialogActions>
<MudStack Row="true" class="w-full mx-4 mb-2">
@if (ViewModel.IsEditing)
{
<BaseButtonUi class="w-64 rounded-md" IsProcessing="@ViewModel.IsProcessing"
Icon="@Icons.Material.Outlined.Check"
Variant="Variant.Filled" Color="Color.Success"
Content="ثبت ویرایش" OnClickCallback="@ViewModel.Submit" />
}
else
{
<BaseButtonUi class="w-64 rounded-md" IsProcessing="@ViewModel.IsProcessing"
Icon="@Icons.Material.Outlined.Check"
Variant="Variant.Filled" Color="Color.Success"
Content="تایید" OnClickCallback="@ViewModel.Submit" />
}
<MudSpacer />
<MudButton Variant="Variant.Outlined" Size="Size.Large" Color="Color.Error" OnClick="@ViewModel.Cancel">بستن</MudButton>
</MudStack>
</DialogActions>
</MudDialog>
@code {
[CascadingParameter]
MudDialogInstance MudDialog { get; set; }
[Parameter]
public BasePageSection? Page { get; set; }
public PageSectionActionDialogBoxViewModel ViewModel { get; set; }
protected override async Task OnInitializedAsync()
{
if (Page == null)
ViewModel = new PageSectionActionDialogBoxViewModel(Snackbar, RestWrapper, UserUtility, DialogService, MudDialog);
else
ViewModel = new PageSectionActionDialogBoxViewModel(Snackbar, RestWrapper, UserUtility, DialogService, MudDialog, Page);
await ViewModel.InitializeAsync();
await base.OnInitializedAsync();
}
}

View File

@ -1,78 +0,0 @@
using MudBlazor;
namespace Netina.AdminPanel.PWA.Dialogs;
public class PageSectionActionDialogBoxViewModel : BaseViewModel<BasePageSection>
{
private readonly ISnackbar _snackbar;
private readonly IRestWrapper _restWrapper;
private readonly IUserUtility _userUtility;
private readonly IDialogService _dialogService;
private readonly MudDialogInstance _mudDialog;
public bool IsEditing = false;
public PageSectionActionDialogBoxViewModel(ISnackbar snackbar,
IRestWrapper restWrapper,
IUserUtility userUtility,
IDialogService dialogService,
MudDialogInstance mudDialog) : base(userUtility)
{
_snackbar = snackbar;
_restWrapper = restWrapper;
_userUtility = userUtility;
_dialogService = dialogService;
_mudDialog = mudDialog;
}
public PageSectionActionDialogBoxViewModel(ISnackbar snackbar,
IRestWrapper restWrapper,
IUserUtility userUtility,
IDialogService dialogService,
MudDialogInstance mudDialog,
BasePageSection page) : base(userUtility)
{
_snackbar = snackbar;
_restWrapper = restWrapper;
_userUtility = userUtility;
_dialogService = dialogService;
_mudDialog = mudDialog;
IsEditing = true;
PageDto = page;
}
public void Cancel() => _mudDialog.Cancel();
public void Submit()
{
_snackbar.Add($"ویرایش {PageDto.Title} با موفقیت انجام شد", Severity.Success);
_mudDialog.Close(DialogResult.Ok(PageDto));
}
public SectionItem SelectedSectionItem { get; set; } = new();
public StorageFileSDto SelectedFile { get; set; } = new();
public bool IsFileSelected { get; set; } = false;
public void AddItem()
{
SelectedSectionItem.ImageLocation = SelectedFile.FileLocation;
PageDto.SectionItems.Add(SelectedSectionItem);
SelectedSectionItem = new SectionItem();
SelectedFile = new StorageFileSDto();
IsFileSelected = false;
}
public async Task SelectFileAsync()
{
DialogOptions maxWidth = new DialogOptions() { MaxWidth = MaxWidth.Medium, FullWidth = true, DisableBackdropClick = true };
var dialog = await _dialogService.ShowAsync<StorageDialogBox>("انتخاب عکس", maxWidth);
var result = await dialog.Result;
var file = result.Data;
if (file is StorageFileSDto storageFile)
{
SelectedFile = storageFile;
IsFileSelected = true;
}
}
}

View File

@ -12,10 +12,10 @@
<MudTabPanel class="h-full" Text="اطلاعات کلی" Icon="@Icons.Material.Outlined.Info"> <MudTabPanel class="h-full" Text="اطلاعات کلی" Icon="@Icons.Material.Outlined.Info">
<div class="h-full"> <div class="h-full">
<MudStack Spacing="0" class="mt-4"> <MudStack Spacing="0" class="mt-4">
<MudText Typo="Typo.h6">اطلاعات کلی</MudText> <MudText Typo="Typo.h6">اطلاعات کلی</MudText>
<MudText Typo="Typo.caption">اطلاعات کلی محصول را به دقت وارد کنید</MudText> <MudText Typo="Typo.caption">اطلاعات کلی محصول را به دقت وارد کنید</MudText>
</MudStack> </MudStack>
<MudGrid> <MudGrid>
<MudItem xs="12" lg="4" md="6"> <MudItem xs="12" lg="4" md="6">
@ -106,7 +106,6 @@
</MudGrid> </MudGrid>
</div> </div>
</MudTabPanel> </MudTabPanel>
<MudTabPanel Text="ویژگی های کلی" Icon="@Icons.Material.Outlined.AutoGraph"> <MudTabPanel Text="ویژگی های کلی" Icon="@Icons.Material.Outlined.AutoGraph">
<div class="min-h-[33rem]"> <div class="min-h-[33rem]">
@ -158,7 +157,6 @@
</MudGrid> </MudGrid>
</div> </div>
</MudTabPanel> </MudTabPanel>
<MudTabPanel Text="توضیحات تکمیلی" Icon="@Icons.Material.Outlined.Article"> <MudTabPanel Text="توضیحات تکمیلی" Icon="@Icons.Material.Outlined.Article">
<div class="min-h-[33rem]"> <div class="min-h-[33rem]">
@ -176,187 +174,6 @@
</MudGrid> </MudGrid>
</div> </div>
</MudTabPanel> </MudTabPanel>
<MudTabPanel Text="زیر محصولاتــ" Icon="@Icons.Material.Outlined.ShoppingBag">
<div class="min-h-[33rem] mt-5">
<MudGrid>
<MudItem xs="10">
<MudStack Row="true" class="mb-5">
<MudStack>
<MudText Typo="Typo.h6">زیر محصولات</MudText>
<MudText Typo="Typo.caption">می توانید زیر محصولات مورد نظر را وارد کنید</MudText>
</MudStack>
</MudStack>
</MudItem>
<MudItem xs="2">
<MudButton Variant="Variant.Filled"
Size="Size.Large"
Color="Color.Info"
class="mt-2 w-full py-3"
OnClick="ViewModel.AddSubProduct"
StartIcon="@Icons.Material.Outlined.Add">افزودن</MudButton>
</MudItem>
<MudItem xs="12">
<MudGrid>
<MudItem sm="12">
<MudDataGrid Items="@ViewModel.SubProducts"
T="SubProductSDto"
Elevation="0"
Outlined="true"
Bordered="true"
Striped="true"
Filterable="false"
SortMode="@SortMode.None"
Groupable="false">
<Columns>
<PropertyColumn T="SubProductSDto" TProperty="string" Property="x => x.PersianName" Title="نام" />
<TemplateColumn T="SubProductSDto" CellClass="d-flex justify-end">
<CellTemplate>
<MudStack Row>
<MudButton DisableElevation="true"
Size="@Size.Small"
Variant="@Variant.Filled"
Color="@Color.Info"
OnClick="async()=>await ViewModel.EditSubProduct(context.Item)"
StartIcon="@Icons.Material.Outlined.Edit">ویرایش</MudButton>
<MudButton DisableElevation="true"
Size="@Size.Small"
Variant="@Variant.Filled"
Color="@Color.Error"
OnClick="async()=>await ViewModel.DeleteSubProduct(context.Item)"
StartIcon="@Icons.Material.Outlined.Remove">حذف</MudButton>
</MudStack>
</CellTemplate>
</TemplateColumn>
</Columns>
</MudDataGrid>
</MudItem>
</MudGrid>
</MudItem>
</MudGrid>
</div>
</MudTabPanel>
<MudTabPanel Text="متاتگ و سوالات متداول">
<MudGrid>
<MudItem xs="12">
<MudText Typo="Typo.h6">اطلاعات متا تگ</MudText>
<MudText Typo="Typo.caption">می توانید متا تگ های سئو برای صفحه مورد نظر را وارد کنید</MudText>
<MudGrid>
<MudItem lg="5" md="6">
<MudTextField @bind-Value="@ViewModel.MetaTagType" T="string" Label="نوع" Variant="Variant.Outlined"></MudTextField>
</MudItem>
<MudItem lg="5" md="6">
<MudTextField @bind-Value="@ViewModel.MetaTagValue" T="string" Label="مقدار" Variant="Variant.Outlined"></MudTextField>
</MudItem>
<MudItem lg="2" md="12">
<MudButton Variant="Variant.Filled"
Size="Size.Large"
Color="Color.Info"
class="mt-2 w-full py-3"
OnClick="ViewModel.AddMetaTag"
StartIcon="@Icons.Material.Outlined.Add">افزودن</MudButton>
</MudItem>
<MudItem sm="12">
<MudDataGrid Items="@ViewModel.MetaTags"
T="MetaTagSDto"
Elevation="0"
Outlined="true"
Bordered="true"
Striped="true"
Filterable="false"
SortMode="@SortMode.None"
Groupable="false">
<Columns>
<PropertyColumn T="MetaTagSDto" TProperty="string" Property="x => x.Type" Title="نوع" />
<PropertyColumn T="MetaTagSDto" TProperty="string" Property="x => x.Value" Title="مقدار" />
<TemplateColumn T="MetaTagSDto" CellClass="d-flex justify-end">
<CellTemplate>
<MudStack Row>
<MudButton DisableElevation="true"
Size="@Size.Small"
Variant="@Variant.Filled"
OnClick="() => ViewModel.MetaTags.Remove(context.Item)"
Color="@Color.Error"
StartIcon="@Icons.Material.Outlined.Delete">حذف</MudButton>
</MudStack>
</CellTemplate>
</TemplateColumn>
</Columns>
</MudDataGrid>
</MudItem>
</MudGrid>
<MudText Typo="Typo.h6">سوالات متداول</MudText>
<MudText Typo="Typo.caption">می توانید سوالات متداول شهر موردنظر را وارد کنید</MudText>
<MudGrid class="mt-1">
<MudItem lg="5" md="6">
<MudTextField @bind-Value="@ViewModel.FaqQuestion" T="string" Label="سوال" Variant="Variant.Outlined"></MudTextField>
</MudItem>
<MudItem lg="5" md="6">
<MudTextField @bind-Value="@ViewModel.FaqAnswer" T="string" Label="پاسخ" Variant="Variant.Outlined"></MudTextField>
</MudItem>
<MudItem lg="2" md="12">
<MudButton Variant="Variant.Filled"
Size="Size.Large"
Color="Color.Info"
class="mt-2 w-full py-3"
OnClick="ViewModel.AddFaq"
StartIcon="@Icons.Material.Outlined.Add">افزودن</MudButton>
</MudItem>
<MudItem sm="12">
<MudExpansionPanels class="mt-1" Elevation="2">
@foreach (var item in ViewModel.Faqs)
{
<MudExpansionPanel>
<TitleContent>
<MudStack Row="true">
<MudIconButton Icon="@Icons.Material.Outlined.Delete"
Size="@Size.Small"
Variant="@Variant.Outlined"
Color="@Color.Error"
OnClick="() => ViewModel.Faqs.Remove(item.Key)" />
<MudText>@item.Key</MudText>
</MudStack>
</TitleContent>
<ChildContent>
@item.Value
</ChildContent>
</MudExpansionPanel>
}
</MudExpansionPanels>
</MudItem>
</MudGrid>
</MudItem>
</MudGrid>
</MudTabPanel>
<MudTabPanel Text="تـــــصاویر" Icon="@Icons.Material.Outlined.ImageSearch"> <MudTabPanel Text="تـــــصاویر" Icon="@Icons.Material.Outlined.ImageSearch">
<div class="min-h-[33rem]"> <div class="min-h-[33rem]">
@ -418,12 +235,7 @@
<MudItem xs="12" md="4"> <MudItem xs="12" md="4">
<MudSelect Disabled="@ViewModel.IsSpecialOffer.Not()" T="DiscountAmountType" <MudSelect Disabled="@ViewModel.IsSpecialOffer.Not()" T="DiscountAmountType" ValueChanged="@ViewModel.AmountTypeChanged" Label="نوع تخفیفـــ" ToStringFunc="b=>b.ToDisplay()" Variant="Variant.Outlined" AnchorOrigin="Origin.BottomCenter">
ValueChanged="@ViewModel.AmountTypeChanged"
Label="نوع تخفیفـــ" ToStringFunc="b=>b.ToDisplay()"
Variant="Variant.Outlined"
Value="@ViewModel.Discount.AmountType"
AnchorOrigin="Origin.BottomCenter">
<MudSelectItem T="DiscountAmountType" Value="DiscountAmountType.Percent" /> <MudSelectItem T="DiscountAmountType" Value="DiscountAmountType.Percent" />
<MudSelectItem T="DiscountAmountType" Value="DiscountAmountType.Amount" /> <MudSelectItem T="DiscountAmountType" Value="DiscountAmountType.Amount" />
</MudSelect> </MudSelect>
@ -439,11 +251,11 @@
<MudItem xs="12" sm="6"> <MudItem xs="12" sm="6">
<MudDatePicker Disabled="@ViewModel.IsSpecialOffer.Not()" @bind-Date="@ViewModel.StartDate" DisableToolbar="true" UseShortNames="false" TitleDateFormat="dddd, dd MMMM" Label="تاریخ شروع تخفیفــ" Variant="Variant.Outlined" Culture="@PersianCultureInfo.GetPersianCulture()" /> <MudDatePicker Disabled="@ViewModel.IsSpecialOffer.Not()" @bind-Date="@ViewModel.StartDate" UseShortNames="false" TitleDateFormat="dddd, dd MMMM" Label="تاریخ شروع تخفیفــ" Variant="Variant.Outlined" Culture="@PersianCultureInfo.GetPersianCulture()" />
</MudItem>
</MudItem>
<MudItem xs="12" sm="6"> <MudItem xs="12" sm="6">
<MudDatePicker Disabled="@ViewModel.IsSpecialOffer.Not()" @bind-Date="@ViewModel.ExpireDate" DisableToolbar="true" UseShortNames="false" TitleDateFormat="dddd, dd MMMM" Label="تاریخ پایان تخفیفــ" Variant="Variant.Outlined" Culture="@PersianCultureInfo.GetPersianCulture()" /> <MudDatePicker Disabled="@ViewModel.IsSpecialOffer.Not()" @bind-Date="@ViewModel.ExpireDate" UseShortNames="false" TitleDateFormat="dddd, dd MMMM" Label="تاریخ پایان تخفیفــ" Variant="Variant.Outlined" Culture="@PersianCultureInfo.GetPersianCulture()" />
</MudItem> </MudItem>

View File

@ -1,11 +1,4 @@
using Microsoft.AspNetCore.Components.Web; namespace Netina.AdminPanel.PWA.Dialogs;
using MudBlazor;
using Netina.AdminPanel.PWA.Services.RestServices;
using Netina.Domain.Dtos.LargDtos;
using Netina.Domain.Entities.Products;
using Netina.Domain.Entities.Seo;
namespace Netina.AdminPanel.PWA.Dialogs;
public class ProductActionDialogBoxViewModel : BaseViewModel<ProductLDto> public class ProductActionDialogBoxViewModel : BaseViewModel<ProductLDto>
{ {
@ -68,22 +61,18 @@ public class ProductActionDialogBoxViewModel : BaseViewModel<ProductLDto>
{ {
_isSpecialOffer = value; _isSpecialOffer = value;
PageDto.IsSpecialOffer = value; PageDto.IsSpecialOffer = value;
if (!value) if(!value)
{ {
IsAmountType = value; IsAmountType = value;
IsPercentType = value; IsPercentType = value;
} }
else if (!IsAmountType)
IsPercentType = true;
} }
} }
public string SpecificationTitle = string.Empty; public string SpecificationTitle = string.Empty;
public string SpecificationValue = string.Empty; public string SpecificationValue = string.Empty;
public readonly ObservableCollection<SpecificationSDto> Specifications = []; public readonly ObservableCollection<SpecificationSDto> Specifications = new ObservableCollection<SpecificationSDto>();
public readonly ObservableCollection<StorageFileSDto> Files = []; public readonly ObservableCollection<StorageFileSDto> Files = new ObservableCollection<StorageFileSDto>();
public readonly ObservableCollection<SubProductSDto> SubProducts = [];
public override async Task InitializeAsync() public override async Task InitializeAsync()
@ -98,22 +87,10 @@ public class ProductActionDialogBoxViewModel : BaseViewModel<ProductLDto>
PageDto = productLDto; PageDto = productLDto;
productLDto.Specifications.ForEach(s => Specifications.Add(s)); productLDto.Specifications.ForEach(s => Specifications.Add(s));
productLDto.Files.ForEach(f => Files.Add(f)); productLDto.Files.ForEach(f => Files.Add(f));
productLDto.MetaTags.ForEach(m => MetaTags.Add(m));
SelectedCategory = new ProductCategorySDto { Id = productLDto.CategoryId, Name = productLDto.CategoryName }; SelectedCategory = new ProductCategorySDto { Id = productLDto.CategoryId, Name = productLDto.CategoryName };
SelectedBrand = new BrandSDto { Id = productLDto.BrandId, PersianName = productLDto.BrandName }; SelectedBrand = new BrandSDto { Id = productLDto.BrandId, PersianName = productLDto.BrandName };
PageDto.IsSpecialOffer = productLDto.IsSpecialOffer; PageDto.IsSpecialOffer = productLDto.IsSpecialOffer;
IsSpecialOffer = PageDto.IsSpecialOffer; IsSpecialOffer = PageDto.IsSpecialOffer;
if (!PageDto.Slug.IsNullOrEmpty())
{
var faq = await _restWrapper.FaqApiRest.ReadOne(PageDto.GetWebSiteUrl());
if (faq.Faqs != null)
{
foreach (var pair in faq.Faqs)
Faqs.Add(pair.Key, pair.Value);
}
}
if (productLDto.SpecialOffer != null) if (productLDto.SpecialOffer != null)
{ {
Discount = productLDto.SpecialOffer; Discount = productLDto.SpecialOffer;
@ -131,10 +108,7 @@ public class ProductActionDialogBoxViewModel : BaseViewModel<ProductLDto>
ExpireDate = Discount.ExpireDate; ExpireDate = Discount.ExpireDate;
StartDate = Discount.StartDate; StartDate = Discount.StartDate;
IsSpecialOffer = true;
} }
await FetchSubProducts();
} }
catch (ApiException ex) catch (ApiException ex)
{ {
@ -157,13 +131,6 @@ public class ProductActionDialogBoxViewModel : BaseViewModel<ProductLDto>
}; };
} }
private async Task FetchSubProducts()
{
SubProducts.Clear();
var subProducts = await _restWrapper.ProductRestApi.GetSubProductsAsync(PageDto.Id);
subProducts.ForEach(s => SubProducts.Add(s));
}
public async Task SubmitEditAsync() public async Task SubmitEditAsync()
{ {
try try
@ -191,29 +158,7 @@ public class ProductActionDialogBoxViewModel : BaseViewModel<ProductLDto>
Discount.StartDate = StartDate.Value; Discount.StartDate = StartDate.Value;
PageDto.SpecialOffer = Discount; PageDto.SpecialOffer = Discount;
} }
var request = PageDto.Adapt<UpdateProductCommand>();
var request = new UpdateProductCommand(PageDto.Id,
PageDto.PersianName,
PageDto.EnglishName,
PageDto.Summery,
PageDto.ExpertCheck,
PageDto.Tags,
PageDto.Warranty,
PageDto.BeDisplayed,
PageDto.Cost,
PageDto.PackingCost,
PageDto.Stock,
PageDto.HasExpressDelivery,
PageDto.MaxOrderCount,
PageDto.IsSpecialOffer,
PageDto.BrandId,
PageDto.CategoryId,
PageDto.SpecialOffer ?? new DiscountSDto(),
PageDto.Specifications,
PageDto.Files,
Faqs,
MetaTags.ToDictionary(x => x.Type, x => x.Value));
await _restWrapper.CrudApiRest<Product, Guid>(Address.ProductController).Update<UpdateProductCommand>(request, token); await _restWrapper.CrudApiRest<Product, Guid>(Address.ProductController).Update<UpdateProductCommand>(request, token);
_snackbar.Add($"ویرایش محصول {PageDto.PersianName} با موفقیت انجام شد", Severity.Success); _snackbar.Add($"ویرایش محصول {PageDto.PersianName} با موفقیت انجام شد", Severity.Success);
_mudDialog.Close(); _mudDialog.Close();
@ -233,7 +178,6 @@ public class ProductActionDialogBoxViewModel : BaseViewModel<ProductLDto>
IsProcessing = false; IsProcessing = false;
} }
} }
public async Task SubmitCreateAsync() public async Task SubmitCreateAsync()
{ {
try try
@ -258,28 +202,8 @@ public class ProductActionDialogBoxViewModel : BaseViewModel<ProductLDto>
Discount.StartDate = StartDate.Value; Discount.StartDate = StartDate.Value;
PageDto.SpecialOffer = Discount; PageDto.SpecialOffer = Discount;
} }
var request = new CreateProductCommand( var request = PageDto.Adapt<CreateProductCommand>();
PageDto.PersianName, await _restWrapper.CrudApiRest<Product, Guid>(Address.ProductController).Create<CreateProductCommand>(request, token);
PageDto.EnglishName,
PageDto.Summery,
PageDto.ExpertCheck,
PageDto.Tags,
PageDto.Warranty,
PageDto.BeDisplayed,
PageDto.Cost,
PageDto.PackingCost,
PageDto.Stock,
PageDto.HasExpressDelivery,
PageDto.MaxOrderCount,
PageDto.IsSpecialOffer,
PageDto.BrandId,
PageDto.CategoryId,
PageDto.SpecialOffer ?? new DiscountSDto(),
PageDto.Specifications,
PageDto.Files,
Faqs,
MetaTags.ToDictionary(x => x.Type, x => x.Value));
await _restWrapper.CrudDtoApiRest<Product, ProductLDto, Guid>(Address.ProductController).Create<CreateProductCommand>(request, token);
_snackbar.Add($"ساخت محصول {PageDto.PersianName} با موفقیت انجام شد", Severity.Success); _snackbar.Add($"ساخت محصول {PageDto.PersianName} با موفقیت انجام شد", Severity.Success);
_mudDialog.Close(DialogResult.Ok(true)); _mudDialog.Close(DialogResult.Ok(true));
@ -312,17 +236,15 @@ public class ProductActionDialogBoxViewModel : BaseViewModel<ProductLDto>
case DiscountAmountType.Amount: case DiscountAmountType.Amount:
IsAmountType = true; IsAmountType = true;
IsPercentType = false; IsPercentType = false;
Discount.AmountType = DiscountAmountType.Amount;
break; break;
case DiscountAmountType.Percent: case DiscountAmountType.Percent:
IsAmountType = false; IsAmountType = false;
IsPercentType = true; IsPercentType = true;
Discount.AmountType = DiscountAmountType.Percent;
break; break;
} }
} }
private List<ProductCategorySDto> _productCategories = []; private List<ProductCategorySDto> _productCategories = new List<ProductCategorySDto>();
public ProductCategorySDto? SelectedCategory; public ProductCategorySDto? SelectedCategory;
public async Task<IEnumerable<ProductCategorySDto>> SearchProductCategory(string category) public async Task<IEnumerable<ProductCategorySDto>> SearchProductCategory(string category)
{ {
@ -349,7 +271,7 @@ public class ProductActionDialogBoxViewModel : BaseViewModel<ProductLDto>
} }
} }
private List<BrandSDto> _brands = []; private List<BrandSDto> _brands = new List<BrandSDto>();
public BrandSDto? SelectedBrand; public BrandSDto? SelectedBrand;
public async Task<IEnumerable<BrandSDto>> SearchBrand(string brand) public async Task<IEnumerable<BrandSDto>> SearchBrand(string brand)
{ {
@ -375,47 +297,6 @@ public class ProductActionDialogBoxViewModel : BaseViewModel<ProductLDto>
} }
public string FaqQuestion { get; set; } = string.Empty;
public string FaqAnswer { get; set; } = string.Empty;
public Dictionary<string, string> Faqs = new();
public void AddFaq()
{
try
{
if (FaqAnswer.IsNullOrEmpty())
throw new Exception("لطفا پاسخ را وارد کنید");
if (FaqQuestion.IsNullOrEmpty())
throw new Exception("لطفا سوال را وارد کنید");
Faqs.Add(FaqQuestion, FaqAnswer);
}
catch (Exception e)
{
_snackbar.Add(e.Message, Severity.Error);
}
}
public readonly ObservableCollection<MetaTagSDto> MetaTags = [];
public string MetaTagType { get; set; } = string.Empty;
public string MetaTagValue { get; set; } = string.Empty;
public void AddMetaTag()
{
try
{
if (MetaTagType.IsNullOrEmpty())
throw new Exception("لطفا نوع متا مورد نظر را وارد کنید");
if (MetaTagValue.IsNullOrEmpty())
throw new Exception("لطفا مقدار متا مورد نظر را وارد کنید");
MetaTags.Add(new MetaTagSDto() { Type = MetaTagType, Value = MetaTagValue });
}
catch (Exception e)
{
_snackbar.Add(e.Message, Severity.Error);
}
}
public void AddSpecification() public void AddSpecification()
{ {
try try
@ -434,6 +315,7 @@ public class ProductActionDialogBoxViewModel : BaseViewModel<ProductLDto>
_snackbar.Add(e.Message, Severity.Error); _snackbar.Add(e.Message, Severity.Error);
} }
} }
public void RemoveSpecification(SpecificationSDto specification) public void RemoveSpecification(SpecificationSDto specification)
{ {
var spec = Specifications.FirstOrDefault(s => s.Value == specification.Value && s.Title == specification.Title); var spec = Specifications.FirstOrDefault(s => s.Value == specification.Value && s.Title == specification.Title);
@ -450,78 +332,9 @@ public class ProductActionDialogBoxViewModel : BaseViewModel<ProductLDto>
if (file is StorageFileSDto storageFile) if (file is StorageFileSDto storageFile)
Files.Add(storageFile); Files.Add(storageFile);
} }
public void RemoveFile(StorageFileSDto file) public void RemoveFile(StorageFileSDto file)
{ {
Files.Remove(file); Files.Remove(file);
} }
public async Task AddSubProduct(MouseEventArgs obj)
{
DialogOptions maxWidth = new DialogOptions() { MaxWidth = MaxWidth.Medium, FullWidth = true, DisableBackdropClick = true };
var parameters = new DialogParameters<SubProductActionDialogBox>
{
{ x => x.ProductId, PageDto.Id },
{ x => x.ProductName, PageDto.PersianName }
};
var dialog = await _dialogService.ShowAsync<SubProductActionDialogBox>($"افزودن زیر محصول به {PageDto.PersianName}", parameters, maxWidth);
var result = await dialog.Result;
if (!result.Canceled)
{
await FetchSubProducts();
}
}
public async Task EditSubProduct(SubProductSDto subProduct)
{
DialogOptions maxWidth = new DialogOptions() { MaxWidth = MaxWidth.Medium, FullWidth = true, DisableBackdropClick = true };
var parameters = new DialogParameters<SubProductActionDialogBox>
{
{ x => x.ProductId, PageDto.Id },
{ x => x.ProductName, PageDto.PersianName },
{ x => x.SubProduct , subProduct}
};
var dialog = await _dialogService.ShowAsync<SubProductActionDialogBox>($"افزودن زیر محصول به {PageDto.PersianName}", parameters, maxWidth);
var result = await dialog.Result;
if (!result.Canceled)
{
await FetchSubProducts();
}
}
public async Task DeleteSubProduct(SubProductSDto subProduct)
{
var reference = await _dialogService.ShowQuestionDialog($"آیا از حذف زیر محصول اطمینان دارید ?");
var result = await reference.Result;
if (!result.Canceled)
{
try
{
IsProcessing = true;
var token = await _userUtility.GetBearerTokenAsync();
if (token == null)
throw new AppException("Token is null");
await _restWrapper.CrudDtoApiRest<SubProduct, SubProductSDto, Guid>(Address.SubProductController)
.Delete(subProduct.Id, token);
_snackbar.Add("حذف زیر محصول با موفقیت انجام شد", Severity.Success);
SubProducts.Remove(subProduct);
}
catch (ApiException ex)
{
var exe = await ex.GetContentAsAsync<ApiResult>();
_snackbar.Add(exe != null ? exe.Message : ex.Content, Severity.Error);
}
catch (Exception e)
{
_snackbar.Add(e.Message, Severity.Error);
}
finally
{
IsProcessing = false;
}
}
}
} }

View File

@ -6,233 +6,122 @@
<MudDialog class="mx-auto" DisableSidePadding="true"> <MudDialog class="mx-auto" DisableSidePadding="true">
<DialogContent> <DialogContent>
<MudContainer class="h-full"> <MudContainer class="h-full">
<MudTabs Outlined="true" Elevation="0" Rounded="true" Centered="true"> <MudDivider class="-mt-3" />
<MudTabPanel Text="اطلاعات کلی" Icon="@Icons.Material.Outlined.Info"> <MudStack Spacing="0">
<MudStack Spacing="0">
<MudText Typo="Typo.h6">اطلاعات کلی</MudText> <MudText Typo="Typo.h6">اطلاعات کلی</MudText>
<MudText Typo="Typo.caption">اطلاعات کلی دسته بندی محصول را به دقت وارد کنید</MudText> <MudText Typo="Typo.caption">اطلاعات کلی دسته بندی محصول را به دقت وارد کنید</MudText>
</MudStack> </MudStack>
<MudStack class="overflow-x-hidden overflow-y-hidden"> <MudStack class="mx-5 overflow-x-hidden overflow-y-hidden">
<MudGrid> <MudGrid>
<MudItem sm="12" lg="4" md="6"> <MudItem sm="12" lg="4" md="6">
<MudTextField T="string" @bind-Value="@ViewModel.Name" Label="نام دسته بندی" Variant="Variant.Outlined"></MudTextField> <MudTextField T="string" @bind-Value="@ViewModel.Name" Label="نام دسته بندی" Variant="Variant.Outlined"></MudTextField>
</MudItem> </MudItem>
<MudItem sm="12" lg="4" md="6"> <MudItem sm="12" lg="4" md="6">
<MudSelect T="bool" @bind-Value="@ViewModel.IsMain" Label="آیا دسته بندی اصلی است ؟" ToStringFunc="b=>b.ToPersianString()" Variant="Variant.Outlined" AnchorOrigin="Origin.BottomCenter"> <MudSelect T="bool" @bind-Value="@ViewModel.IsMain" Label="آیا دسته بندی اصلی است ؟" ToStringFunc="b=>b.ToPersianString()" Variant="Variant.Outlined" AnchorOrigin="Origin.BottomCenter">
<MudSelectItem T="bool" Value="true" /> <MudSelectItem T="bool" Value="true" />
<MudSelectItem T="bool" Value="false" /> <MudSelectItem T="bool" Value="false" />
</MudSelect> </MudSelect>
</MudItem> </MudItem>
<MudItem sm="12" lg="4" md="6"> <MudItem sm="12" lg="4" md="6">
<MudAutocomplete Required="true" ToStringFunc="dto => dto.Name" @bind-Value="@ViewModel.SelectedCategory" <MudAutocomplete Required="true" ToStringFunc="dto => dto.Name" @bind-Value="@ViewModel.SelectedCategory"
SearchFunc="ViewModel.SearchCategory" SearchFunc="ViewModel.SearchCategory"
T="ProductCategorySDto" T="ProductCategorySDto"
Label="دسته پدر" Label="دسته پدر"
Variant="Variant.Outlined"> Variant="Variant.Outlined">
<ProgressIndicatorInPopoverTemplate> <ProgressIndicatorInPopoverTemplate>
<MudList Clickable="false"> <MudList Clickable="false">
<MudListItem> <MudListItem>
<div class="flex flex-row w-full mx-auto"> <div class="flex flex-row w-full mx-auto">
<MudProgressCircular class="my-auto mr-1 -ml-4" Size="Size.Small" Indeterminate="true" /> <MudProgressCircular class="my-auto mr-1 -ml-4" Size="Size.Small" Indeterminate="true" />
<p class="font-bold my-1 mx-auto text-md">منتظر بمانید</p> <p class="font-bold my-1 mx-auto text-md">منتظر بمانید</p>
</div>
</MudListItem>
</MudList>
</ProgressIndicatorInPopoverTemplate>
<ItemTemplate Context="e">
<p>@e.Name</p>
</ItemTemplate>
</MudAutocomplete>
</MudItem>
<MudItem sm="12" md="12" lg="12">
<MudStack class="mt-2 mb-4" Spacing="0">
<MudText Typo="Typo.h6">تصاویر برند</MudText>
<MudText Typo="Typo.caption">می توانید برای برند چند تصویر اپلود کنید</MudText>
</MudStack>
<MudStack Row="true">
<MudIconButton HtmlTag="label"
Color="Color.Info"
Variant="Variant.Outlined"
class="w-28 h-28"
Size="Size.Large"
Icon="@Icons.Material.Outlined.Wallpaper"
OnClick="async () => await ViewModel.SelectFileAsync()">
</MudIconButton>
@foreach (var item in ViewModel.Files)
{
<div class="w-28 h-28">
<MudImage Src="@item.GetLink()" Elevation="25" Class="rounded-lg w-28 h-28 absolute" />
<MudIconButton DisableElevation="true"
class="absolute m-1.5"
Size="@Size.Small"
Variant="@Variant.Filled"
OnClick="() => ViewModel.RemoveFile(item)"
Color="@Color.Error"
Icon="@Icons.Material.Outlined.Delete" />
@if (item.IsHeader)
{
<p class="bg-pink-500 px-1.5 py-0.5 absolute bottom-0 mr-2 rounded-lg text-white">هدر</p>
}
@if (item.IsPrimary)
{
<p class="bg-blue-500 px-1.5 py-0.5 absolute bottom-0 mr-2 rounded-lg text-white">اصلی</p>
}
</div> </div>
</MudListItem>
</MudList>
</ProgressIndicatorInPopoverTemplate>
<ItemTemplate Context="e">
<p>@e.Name</p>
</ItemTemplate>
</MudAutocomplete>
</MudItem>
<MudItem sm="12" md="12" lg="12">
<MudStack class="mt-2 mb-4" Spacing="0">
<MudText Typo="Typo.h6">تصاویر برند</MudText>
<MudText Typo="Typo.caption">می توانید برای برند چند تصویر اپلود کنید</MudText>
</MudStack>
<MudStack Row="true">
<MudIconButton HtmlTag="label"
Color="Color.Info"
Variant="Variant.Outlined"
class="w-28 h-28"
Size="Size.Large"
Icon="@Icons.Material.Outlined.Wallpaper"
OnClick="async () => await ViewModel.SelectFileAsync()">
</MudIconButton>
@foreach (var item in ViewModel.Files)
{
<div class="w-28 h-28">
<MudImage Src="@item.GetLink()" Elevation="25" Class="rounded-lg w-28 h-28 absolute" />
<MudIconButton DisableElevation="true"
class="absolute m-1.5"
Size="@Size.Small"
Variant="@Variant.Filled"
OnClick="() => ViewModel.RemoveFile(item)"
Color="@Color.Error"
Icon="@Icons.Material.Outlined.Delete" />
@if (item.IsHeader)
{
<p class="bg-pink-500 px-1.5 py-0.5 absolute bottom-0 mr-2 rounded-lg text-white">هدر</p>
} }
@if (item.IsPrimary)
{
<p class="bg-blue-500 px-1.5 py-0.5 absolute bottom-0 mr-2 rounded-lg text-white">اصلی</p>
}
</div>
}
</MudStack> </MudStack>
</MudItem> </MudItem>
<MudItem sm="12" lg="12" md="12"> <MudItem sm="12" lg="12" md="12">
<MudContainer class="overflow-y-hidden overflow-x-hidden"> <MudContainer class="overflow-y-hidden overflow-x-hidden">
<MudStack class="mt-4 mb-2" Spacing="0"> <MudStack class="mt-4 mb-2" Spacing="0">
<MudText Typo="Typo.h6">توضیحات تکمیلی</MudText> <MudText Typo="Typo.h6">توضیحات تکمیلی</MudText>
<MudText Typo="Typo.caption">می توانید توضیحاتــ تکمیلی محصول را کامل وارد کنید</MudText> <MudText Typo="Typo.caption">می توانید توضیحاتــ تکمیلی محصول را کامل وارد کنید</MudText>
</MudStack> </MudStack>
<div class="!text-black"> <div class="!text-black">
<RichTextEditorUi @bind-Text="@ViewModel.Description" /> <RichTextEditorUi @bind-Text="@ViewModel.Description" />
</div> </div>
</MudContainer> </MudContainer>
</MudItem> </MudItem>
</MudGrid> </MudGrid>
</MudStack> </MudStack>
</MudTabPanel>
<MudTabPanel Text="متاتگ و سوالات متداول">
<MudGrid> <MudStack Row="true" class="w-full mx-4 mb-2">
<MudItem xs="12">
<MudText Typo="Typo.h6">اطلاعات متا تگ</MudText> @if (ViewModel.IsEditing)
<MudText Typo="Typo.caption">می توانید متا تگ های سئو برای صفحه مورد نظر را وارد کنید</MudText> {
<MudGrid> <BaseButtonUi class="w-64 rounded-md" IsProcessing="@ViewModel.IsProcessing"
Icon="@Icons.Material.Outlined.Check"
<MudItem lg="5" md="6"> Variant="Variant.Filled" Color="Color.Success"
<MudTextField @bind-Value="@ViewModel.MetaTagType" T="string" Label="نوع" Variant="Variant.Outlined"></MudTextField> Content="ثبت ویرایش" OnClickCallback="ViewModel.SubmitEditAsync" />
</MudItem> }
else
<MudItem lg="5" md="6"> {
<MudTextField @bind-Value="@ViewModel.MetaTagValue" T="string" Label="مقدار" Variant="Variant.Outlined"></MudTextField> <BaseButtonUi class="w-64 rounded-md" IsProcessing="@ViewModel.IsProcessing"
</MudItem> Icon="@Icons.Material.Outlined.Check"
Variant="Variant.Filled" Color="Color.Success"
<MudItem lg="2" md="12"> Content="تایید" OnClickCallback="ViewModel.SubmitCreateAsync" />
<MudButton Variant="Variant.Filled" }
Size="Size.Large" <MudSpacer />
Color="Color.Info" <MudButton Variant="Variant.Outlined" Size="Size.Large" Color="Color.Error" OnClick="ViewModel.Cancel">بستن</MudButton>
class="mt-2 w-full py-3" </MudStack>
OnClick="ViewModel.AddMetaTag"
StartIcon="@Icons.Material.Outlined.Add">افزودن</MudButton>
</MudItem>
<MudItem sm="12">
<MudDataGrid Items="@ViewModel.MetaTags"
T="MetaTagSDto"
Elevation="0"
Outlined="true"
Bordered="true"
Striped="true"
Filterable="false"
SortMode="@SortMode.None"
Groupable="false">
<Columns>
<PropertyColumn T="MetaTagSDto" TProperty="string" Property="x => x.Type" Title="نوع" />
<PropertyColumn T="MetaTagSDto" TProperty="string" Property="x => x.Value" Title="مقدار" />
<TemplateColumn T="MetaTagSDto" CellClass="d-flex justify-end">
<CellTemplate>
<MudStack Row>
<MudButton DisableElevation="true"
Size="@Size.Small"
Variant="@Variant.Filled"
OnClick="()=>ViewModel.MetaTags.Remove(context.Item)"
Color="@Color.Error"
StartIcon="@Icons.Material.Outlined.Delete">حذف</MudButton>
</MudStack>
</CellTemplate>
</TemplateColumn>
</Columns>
</MudDataGrid>
</MudItem>
</MudGrid>
<MudText Typo="Typo.h6">سوالات متداول</MudText>
<MudText Typo="Typo.caption">می توانید سوالات متداول شهر موردنظر را وارد کنید</MudText>
<MudGrid class="mt-1">
<MudItem lg="5" md="6">
<MudTextField @bind-Value="@ViewModel.FaqQuestion" T="string" Label="سوال" Variant="Variant.Outlined"></MudTextField>
</MudItem>
<MudItem lg="5" md="6">
<MudTextField @bind-Value="@ViewModel.FaqAnswer" T="string" Label="پاسخ" Variant="Variant.Outlined"></MudTextField>
</MudItem>
<MudItem lg="2" md="12">
<MudButton Variant="Variant.Filled"
Size="Size.Large"
Color="Color.Info"
class="mt-2 w-full py-3"
OnClick="ViewModel.AddFaq"
StartIcon="@Icons.Material.Outlined.Add">افزودن</MudButton>
</MudItem>
<MudItem sm="12">
<MudExpansionPanels class="mt-1" Elevation="2">
@foreach (var item in ViewModel.Faqs)
{
<MudExpansionPanel>
<TitleContent>
<MudStack Row="true">
<MudIconButton Icon="@Icons.Material.Outlined.Delete"
Size="@Size.Small"
Variant="@Variant.Outlined"
Color="@Color.Error"
OnClick="() => ViewModel.Faqs.Remove(item.Key)" />
<MudText>@item.Key</MudText>
</MudStack>
</TitleContent>
<ChildContent>
@item.Value
</ChildContent>
</MudExpansionPanel>
}
</MudExpansionPanels>
</MudItem>
</MudGrid>
</MudItem>
</MudGrid>
</MudTabPanel>
</MudTabs>
</MudContainer> </MudContainer>
</DialogContent> </DialogContent>
<DialogActions>
<MudStack Row="true" class="w-full mx-4 mb-2">
@if (ViewModel.IsEditing)
{
<BaseButtonUi class="w-64 rounded-md" IsProcessing="@ViewModel.IsProcessing"
Icon="@Icons.Material.Outlined.Check"
Variant="Variant.Filled" Color="Color.Success"
Content="ثبت ویرایش" OnClickCallback="ViewModel.SubmitEditAsync" />
}
else
{
<BaseButtonUi class="w-64 rounded-md" IsProcessing="@ViewModel.IsProcessing"
Icon="@Icons.Material.Outlined.Check"
Variant="Variant.Filled" Color="Color.Success"
Content="تایید" OnClickCallback="ViewModel.SubmitCreateAsync" />
}
<MudSpacer />
<MudButton Variant="Variant.Outlined" Size="Size.Large" Color="Color.Error" OnClick="ViewModel.Cancel">بستن</MudButton>
</MudStack>
</DialogActions>
</MudDialog> </MudDialog>
@code @code
{ {

View File

@ -1,7 +1,4 @@
using Netina.Common.Models.Mapper; namespace Netina.AdminPanel.PWA.Dialogs;
using Netina.Domain.Entities.Seo;
namespace Netina.AdminPanel.PWA.Dialogs;
public class ProductCategoryActionDialogBoxViewModel:BaseViewModel public class ProductCategoryActionDialogBoxViewModel:BaseViewModel
{ {
@ -35,8 +32,7 @@ public class ProductCategoryActionDialogBoxViewModel:BaseViewModel
public string Description = string.Empty; public string Description = string.Empty;
public bool IsMain; public bool IsMain;
public bool IsEditing = false; public bool IsEditing = false;
public readonly ObservableCollection<StorageFileSDto> Files = new (); public readonly ObservableCollection<StorageFileSDto> Files = new ObservableCollection<StorageFileSDto>();
public readonly ObservableCollection<MetaTagSDto> MetaTags = new();
private ProductCategorySDto? _category = null; private ProductCategorySDto? _category = null;
[Parameter] [Parameter]
@ -63,7 +59,6 @@ public class ProductCategoryActionDialogBoxViewModel:BaseViewModel
var response = await _restWrapper.CrudDtoApiRest<ProductCategory,ProductCategoryLDto,Guid>(Address.ProductCategoryController).ReadOne(Category.Id); var response = await _restWrapper.CrudDtoApiRest<ProductCategory,ProductCategoryLDto,Guid>(Address.ProductCategoryController).ReadOne(Category.Id);
var categoryLDto = response; var categoryLDto = response;
categoryLDto.Files.ForEach(f => Files.Add(f)); categoryLDto.Files.ForEach(f => Files.Add(f));
categoryLDto.MetaTags.ForEach(m=> MetaTags.Add(m));
SelectedCategory = new ProductCategorySDto { Id = categoryLDto.ParentId, Name = categoryLDto.ParentName }; SelectedCategory = new ProductCategorySDto { Id = categoryLDto.ParentId, Name = categoryLDto.ParentName };
Name = categoryLDto.Name; Name = categoryLDto.Name;
Description = categoryLDto.Description; Description = categoryLDto.Description;
@ -99,13 +94,7 @@ public class ProductCategoryActionDialogBoxViewModel:BaseViewModel
var token = await _userUtility.GetBearerTokenAsync(); var token = await _userUtility.GetBearerTokenAsync();
if (token == null) if (token == null)
throw new AppException("Token is null"); throw new AppException("Token is null");
var request = new CreateProductCategoryCommand(Name, var request = new CreateProductCategoryCommand(Name, Description, IsMain, SelectedCategory?.Id ?? default, Files.ToList());
Description,
IsMain,
SelectedCategory?.Id ?? default,
Files.ToList(),
Faqs,
MetaTags.ToDictionary(x => x.Type, x => x.Value));
await _restWrapper.CrudApiRest<ProductCategory, Guid>(Address.ProductCategoryController).Create<CreateProductCategoryCommand>(request, token); await _restWrapper.CrudApiRest<ProductCategory, Guid>(Address.ProductCategoryController).Create<CreateProductCategoryCommand>(request, token);
_mudDialog.Close(DialogResult.Ok(true)); _mudDialog.Close(DialogResult.Ok(true));
} }
@ -138,14 +127,7 @@ public class ProductCategoryActionDialogBoxViewModel:BaseViewModel
IsProcessing = true; IsProcessing = true;
await Task.Delay(1000); await Task.Delay(1000);
var token = await _userUtility.GetBearerTokenAsync(); var token = await _userUtility.GetBearerTokenAsync();
var request = new UpdateProductCategoryCommand(Category.Id, var request = new UpdateProductCategoryCommand(Category.Id, Name, Description, IsMain, SelectedCategory?.Id ?? default, Files.ToList());
Name,
Description,
IsMain,
SelectedCategory?.Id ?? default,
Files.ToList(),
Faqs,
MetaTags.ToDictionary(x => x.Type, x => x.Value));
await _restWrapper.CrudApiRest<ProductCategory, Guid>(Address.ProductCategoryController).Update<UpdateProductCategoryCommand>(request, token); await _restWrapper.CrudApiRest<ProductCategory, Guid>(Address.ProductCategoryController).Update<UpdateProductCategoryCommand>(request, token);
_mudDialog.Close(DialogResult.Ok(true)); _mudDialog.Close(DialogResult.Ok(true));
} }
@ -167,25 +149,6 @@ public class ProductCategoryActionDialogBoxViewModel:BaseViewModel
} }
} }
public string MetaTagType { get; set; } = string.Empty;
public string MetaTagValue { get; set; } = string.Empty;
public void AddMetaTag()
{
try
{
if (MetaTagType.IsNullOrEmpty())
throw new Exception("لطفا نوع متا مورد نظر را وارد کنید");
if (MetaTagValue.IsNullOrEmpty())
throw new Exception("لطفا مقدار متا مورد نظر را وارد کنید");
MetaTags.Add(new MetaTagSDto() { Type = MetaTagType, Value = MetaTagValue });
}
catch (Exception e)
{
_snackbar.Add(e.Message, Severity.Error);
}
}
private List<ProductCategorySDto> _productCategories = new List<ProductCategorySDto>(); private List<ProductCategorySDto> _productCategories = new List<ProductCategorySDto>();
public ProductCategorySDto? SelectedCategory; public ProductCategorySDto? SelectedCategory;
public async Task<IEnumerable<ProductCategorySDto>> SearchCategory(string city) public async Task<IEnumerable<ProductCategorySDto>> SearchCategory(string city)
@ -214,28 +177,6 @@ public class ProductCategoryActionDialogBoxViewModel:BaseViewModel
} }
public string FaqQuestion { get; set; } = string.Empty;
public string FaqAnswer { get; set; } = string.Empty;
public Dictionary<string, string> Faqs = new();
public void AddFaq()
{
try
{
if (FaqAnswer.IsNullOrEmpty())
throw new Exception("لطفا پاسخ را وارد کنید");
if (FaqQuestion.IsNullOrEmpty())
throw new Exception("لطفا سوال را وارد کنید");
Faqs.Add(FaqQuestion, FaqAnswer);
}
catch (Exception e)
{
_snackbar.Add(e.Message, Severity.Error);
}
}
public async Task SelectFileAsync() public async Task SelectFileAsync()
{ {
DialogOptions maxWidth = new DialogOptions() { MaxWidth = MaxWidth.Medium, FullWidth = true, DisableBackdropClick = true }; DialogOptions maxWidth = new DialogOptions() { MaxWidth = MaxWidth.Medium, FullWidth = true, DisableBackdropClick = true };

View File

@ -1,65 +0,0 @@
@inject ISnackbar Snackbar
@inject IRestWrapper RestWrapper
@inject IUserUtility UserUtility
@inject IDialogService DialogService
<MudDialog class="mx-auto">
<DialogContent>
<MudStack>
<MudDivider class="-mt-3" />
<CommentItemTemplate Comment="Review" />
<MudGrid class="-ml-5">
<MudItem sm="11">
<MudTextField @bind-Value="ViewModel.AnswerContent" Lines="4" T="string" Label="پاسخ دادن به نظر" Variant="Variant.Outlined"></MudTextField>
</MudItem>
<MudItem sm="1">
<MudIconButton class="mt-1.5 px-3 py-9"
Icon="@Icons.Material.Outlined.Check"
Variant="Variant.Outlined"
Size="Size.Large"
Color="Color.Info" OnClick="@(async()=>await ViewModel.SubmitAnswer())"></MudIconButton>
</MudItem>
</MudGrid>
</MudStack>
</DialogContent>
<DialogActions>
<MudStack Row="true" class="mx-4 mb-2 w-full">
<BaseButtonUi class="w-64 rounded-md" IsProcessing="@ViewModel.IsProcessing"
Icon="@Icons.Material.Outlined.Check"
Variant="Variant.Filled" Color="Color.Success"
Content="تایید کردن نظر" />
<BaseButtonUi class="w-64 rounded-md" IsProcessing="@ViewModel.IsProcessing"
Icon="@Icons.Material.Outlined.CommentsDisabled"
Variant="Variant.Outlined" Color="Color.Warning"
Content="حذف کردن" />
<MudSpacer />
<MudButton Variant="Variant.Outlined" Size="Size.Large" Color="Color.Error" OnClick="@(ViewModel.Cancel)">بستن</MudButton>
</MudStack>
</DialogActions>
</MudDialog>
@code {
[CascadingParameter]
MudDialogInstance MudDialog { get; set; }
[Parameter]
public CommentSDto? Review { get; set; }
public ReviewActionDialogBoxViewModel ViewModel { get; set; }
protected override async Task OnInitializedAsync()
{
if (Review == null)
ViewModel = new ReviewActionDialogBoxViewModel(Snackbar, RestWrapper, UserUtility, DialogService, MudDialog);
else
ViewModel = new ReviewActionDialogBoxViewModel(Snackbar, RestWrapper, UserUtility, DialogService, MudDialog, Review);
await ViewModel.InitializeAsync();
await base.OnInitializedAsync();
}
}

View File

@ -1,87 +0,0 @@
using MudBlazor;
using Netina.AdminPanel.PWA.Services.RestServices;
namespace Netina.AdminPanel.PWA.Dialogs;
public class ReviewActionDialogBoxViewModel : BaseViewModel<CommentSDto>
{
private readonly ISnackbar _snackbar;
private readonly IRestWrapper _restWrapper;
private readonly IDialogService _dialogService;
private readonly MudDialogInstance _mudDialog;
public ReviewActionDialogBoxViewModel(ISnackbar snackbar,
IRestWrapper restWrapper,
IUserUtility userUtility,
IDialogService dialogService,
MudDialogInstance mudDialog) : base(userUtility)
{
_snackbar = snackbar;
_restWrapper = restWrapper;
_dialogService = dialogService;
_mudDialog = mudDialog;
}
public ReviewActionDialogBoxViewModel(ISnackbar snackbar,
IRestWrapper restWrapper,
IUserUtility userUtility,
IDialogService dialogService,
MudDialogInstance mudDialog,
CommentSDto review) : base(userUtility)
{
_snackbar = snackbar;
_restWrapper = restWrapper;
_dialogService = dialogService;
_mudDialog = mudDialog;
Review = review;
PageDto = Review;
}
private CommentSDto? _review = null;
public CommentSDto? Review
{
get => _review;
set
{
_review = value;
if (_review != null)
{
IsEditing = true;
}
}
}
public void Cancel() => _mudDialog.Cancel();
public bool IsEditing = false;
public string AnswerContent { get; set; } = string.Empty;
public async Task SubmitAnswer()
{
try
{
IsProcessing = true;
var token = await _userUtility.GetBearerTokenAsync();
if (token == null)
throw new Exception("Token is null");
await _restWrapper.ReviewRestApi.CreateAsync(new CreateCommentCommand($"پاسخ به نظر - {PageDto.Title}", AnswerContent,6,false,true,PageDto.Id,null,null,null), token);
}
catch (ApiException ex)
{
var exe = await ex.GetContentAsAsync<ApiResult>();
_snackbar.Add(exe != null ? exe.Message : ex.Content, Severity.Error);
}
catch (Exception e)
{
_snackbar.Add(e.Message, Severity.Error);
}
finally
{
IsProcessing = false;
}
}
}

View File

@ -1,4 +1,6 @@
@inject ISnackbar Snackbar 
@inject ISnackbar Snackbar
@inject IRestWrapper RestWrapper @inject IRestWrapper RestWrapper
@inject IUserUtility UserUtility @inject IUserUtility UserUtility
@inject IDialogService DialogService @inject IDialogService DialogService

View File

@ -115,7 +115,7 @@ public class StorageDialogBoxViewModel : BaseViewModel
IsProcessing = true; IsProcessing = true;
using var memoryStream = new MemoryStream(); using var memoryStream = new MemoryStream();
var file = obj.File; var file = obj.File;
var stream = file.OpenReadStream(8000000); var stream = file.OpenReadStream();
await stream.CopyToAsync(memoryStream); await stream.CopyToAsync(memoryStream);
var fileUpload = new FileUploadRequest var fileUpload = new FileUploadRequest

View File

@ -1,111 +0,0 @@
@inject ISnackbar Snackbar
@inject IRestWrapper RestWrapper
@inject IUserUtility UserUtility
@inject IDialogService DialogService
<MudDialog class="mx-auto">
<DialogContent>
<MudContainer class="h-full p-0">
<MudTabs Outlined="true" Elevation="0" Rounded="true" Centered="true">
<MudTabPanel Text="اطلاعات کلی" Icon="@Icons.Material.Outlined.Info">
<MudStack>
<MudStack Spacing="0">
<MudText Typo="Typo.h6">اطلاعات کلی</MudText>
<MudText Typo="Typo.caption">اطلاعات کلی زیر محصول را به دقت وارد کنید</MudText>
</MudStack>
<MudGrid>
<MudItem xs="12" lg="4" md="4">
<MudSelect Variant="Variant.Outlined" T="ProductDiversity"
ToStringFunc="type => type.ToDisplay()"
Label="نوع تنوع"
@bind-Value="@ViewModel.PageDto.Diversity">
<MudSelectItem T="ProductDiversity" Value="ProductDiversity.None"></MudSelectItem>
<MudSelectItem T="ProductDiversity" Value="ProductDiversity.Color"></MudSelectItem>
<MudSelectItem T="ProductDiversity" Value="ProductDiversity.Guarantee"></MudSelectItem>
<MudSelectItem T="ProductDiversity" Value="ProductDiversity.Size"></MudSelectItem>
</MudSelect>
</MudItem>
<MudItem xs="12" lg="4" md="4">
<MudTextField @bind-Value="@ViewModel.PageDto.DiversityValue" T="string" Label="تنوع" Format="N0" Variant="Variant.Outlined" />
</MudItem>
<MudItem xs="12" lg="4" md="4">
<MudTextField @bind-Value="@ViewModel.PageDto.DiversitySecondaryValue" T="string" Label="مقدار تنوع" Format="N0" Variant="Variant.Outlined" />
</MudItem>
<MudItem xs="12" lg="4" md="6">
<MudTextField @bind-Value="@ViewModel.PageDto.Cost" T="double" Label="قیمت محصول" Adornment="Adornment.End" Format="N0" AdornmentText="ریالــ" Variant="Variant.Outlined" />
</MudItem>
<MudItem xs="12" lg="4" md="6">
<MudTextField @bind-Value="@ViewModel.PageDto.PackingCost" T="double" Label="مبلغ بسته بندی" Format="N0" Adornment="Adornment.End" AdornmentText="ریالــ" Variant="Variant.Outlined" />
</MudItem>
<MudItem xs="12" lg="4" md="6">
<MudTextField @bind-Value="@ViewModel.PageDto.Stock" T="int" Format="N0" Label="موجودی انبار" Variant="Variant.Outlined" />
</MudItem>
<MudItem xs="12" lg="4" md="6">
<MudTextField @bind-Value="@ViewModel.PageDto.MaxOrderCount" T="int" Format="N0" Label="بیشترین خرید" Variant="Variant.Outlined" />
</MudItem>
<MudItem xs="12" lg="4" md="6">
<MudSelect T="bool" @bind-Value="@ViewModel.PageDto.HasExpressDelivery" Label="آیا ارسال سریع دارد ؟" ToStringFunc="b=>b.ToPersianString()" Variant="Variant.Outlined" AnchorOrigin="Origin.BottomCenter">
<MudSelectItem T="bool" Value="true" />
<MudSelectItem T="bool" Value="false" />
</MudSelect>
</MudItem>
</MudGrid>
</MudStack>
</MudTabPanel>
</MudTabs>
</MudContainer>
</DialogContent>
<DialogActions>
<MudStack Row="true" class="w-full mx-4 mb-2">
@if (ViewModel.IsEditing)
{
<BaseButtonUi class="w-64 rounded-md" IsProcessing="@ViewModel.IsProcessing"
Icon="@Icons.Material.Outlined.Check"
Variant="Variant.Filled" Color="Color.Success"
Content="ثبت ویرایش" OnClickCallback="ViewModel.SubmitEditAsync" />
}
else
{
<BaseButtonUi class="w-64 rounded-md" IsProcessing="@ViewModel.IsProcessing"
Icon="@Icons.Material.Outlined.Check"
Variant="Variant.Filled" Color="Color.Success"
Content="تایید" OnClickCallback="ViewModel.SubmitCreateAsync" />
}
<MudSpacer />
<MudButton Variant="Variant.Outlined" Size="Size.Large" Color="Color.Error" OnClick="ViewModel.Cancel">بستن</MudButton>
</MudStack>
</DialogActions>
</MudDialog>
@code {
[CascadingParameter]
MudDialogInstance MudDialog { get; set; }
[Parameter]
public SubProductSDto? SubProduct { get; set; }
[Parameter]
public string ProductName { get; set; } = string.Empty;
[Parameter]
public Guid ProductId { get; set; }
public SubProductActionDialogBoxViewModel ViewModel { get; set; }
protected override async Task OnInitializedAsync()
{
if (ProductId == default || string.IsNullOrEmpty(ProductName))
return;
ViewModel = SubProduct == null ? new SubProductActionDialogBoxViewModel(Snackbar, RestWrapper, UserUtility, DialogService, MudDialog, ProductId, ProductName) :
new SubProductActionDialogBoxViewModel(Snackbar, RestWrapper, UserUtility, DialogService, MudDialog, ProductId, ProductName, SubProduct);
await ViewModel.InitializeAsync();
await base.OnInitializedAsync();
}
}

View File

@ -1,170 +0,0 @@
namespace Netina.AdminPanel.PWA.Dialogs;
public class SubProductActionDialogBoxViewModel : BaseViewModel<SubProductSDto>
{
private readonly ISnackbar _snackbar;
private readonly IRestWrapper _restWrapper;
private readonly IUserUtility _userUtility;
private readonly IDialogService _dialogService;
private readonly MudDialogInstance _mudDialog;
public SubProductActionDialogBoxViewModel(ISnackbar snackbar,
IRestWrapper restWrapper,
IUserUtility userUtility,
IDialogService dialogService,
MudDialogInstance mudDialog,
Guid productId,
string productName) : base(userUtility)
{
ProductId = productId;
ProductName = productName;
_snackbar = snackbar;
_restWrapper = restWrapper;
_userUtility = userUtility;
_dialogService = dialogService;
_mudDialog = mudDialog;
}
public SubProductActionDialogBoxViewModel(ISnackbar snackbar,
IRestWrapper restWrapper,
IUserUtility userUtility,
IDialogService dialogService,
MudDialogInstance mudDialog,
Guid productId,
string productName,
SubProductSDto subProduct) : base(userUtility)
{
_snackbar = snackbar;
_restWrapper = restWrapper;
_userUtility = userUtility;
_dialogService = dialogService;
_mudDialog = mudDialog;
ProductId = productId;
ProductName = productName;
SubProduct = subProduct;
PageDto = subProduct;
}
private SubProductSDto? _subProduct = null;
public SubProductSDto? SubProduct
{
get => _subProduct;
set
{
_subProduct = value;
if (_subProduct != null)
{
IsEditing = true;
}
}
}
public Guid ProductId { get; }
public string ProductName { get; } = string.Empty;
public void Cancel() => _mudDialog.Cancel();
public bool IsEditing = false;
public async Task SubmitCreateAsync()
{
try
{
if (ProductId == default)
throw new AppException("کالای ارسالی اشتباه است");
if (PageDto.Diversity == ProductDiversity.None)
throw new AppException("لطفا نوع تنوع را وارد کنید");
if (PageDto.DiversityValue.IsNullOrEmpty())
throw new AppException("لطفا تنوع را وارد کنید");
PageDto.DiversityDescription = $"{PageDto.Diversity.ToDisplay()} {PageDto.DiversityValue}";
IsProcessing = true;
var token = await _userUtility.GetBearerTokenAsync();
if (token == null)
throw new AppException("Token is null");
var request = new CreateSubProductCommand(
ProductId,
PageDto.Diversity,
PageDto.DiversityValue,
PageDto.DiversitySecondaryValue,
PageDto.DiversityDescription,
PageDto.PersianName,
PageDto.Cost,
PageDto.PackingCost,
PageDto.Stock,
PageDto.HasExpressDelivery,
PageDto.MaxOrderCount,
new List<StorageFileSDto>());
await _restWrapper.CrudApiRest<SubProduct, Guid>(Address.SubProductController).Create<CreateSubProductCommand>(request, token);
_mudDialog.Close(DialogResult.Ok(true));
}
catch (ApiException ex)
{
var exe = await ex.GetContentAsAsync<ApiResult>();
_snackbar.Add(exe != null ? exe.Message : ex.Content, Severity.Error);
}
catch (Exception e)
{
_snackbar.Add(e.Message, Severity.Error);
}
finally
{
IsProcessing = false;
}
}
public async Task SubmitEditAsync()
{
try
{
if (SubProduct == null)
throw new AppException("محصول به درستی ارسال نشده است");
if (ProductId == default)
throw new AppException("کالای ارسالی اشتباه است");
if (PageDto.Diversity == ProductDiversity.None)
throw new AppException("لطفا نوع تنوع را وارد کنید");
if (PageDto.DiversityValue.IsNullOrEmpty())
throw new AppException("لطفا تنوع را وارد کنید");
PageDto.DiversityDescription = $"{PageDto.Diversity.ToDisplay()} {PageDto.DiversityValue}";
IsProcessing = true;
var token = await _userUtility.GetBearerTokenAsync();
if (token == null)
throw new AppException("Token is null");
var request = new UpdateSubProductCommand(
PageDto.Id,
PageDto.ParentId,
PageDto.Diversity,
PageDto.DiversityValue,
PageDto.DiversitySecondaryValue,
PageDto.DiversityDescription,
PageDto.PersianName,
PageDto.Cost,
PageDto.PackingCost,
PageDto.Stock,
PageDto.HasExpressDelivery,
PageDto.MaxOrderCount,
new List<StorageFileSDto>());
await _restWrapper.CrudApiRest<SubProduct, Guid>(Address.SubProductController).Update<UpdateSubProductCommand>(request, token);
_mudDialog.Close();
}
catch (ApiException ex)
{
var exe = await ex.GetContentAsAsync<ApiResult>();
_snackbar.Add(exe != null ? exe.Message : ex.Content, Severity.Error);
_mudDialog.Cancel();
}
catch (Exception e)
{
_snackbar.Add(e.Message, Severity.Error);
_mudDialog.Cancel();
}
finally
{
IsProcessing = false;
}
}
}

View File

@ -5,7 +5,7 @@
@inherits LayoutComponentBase @inherits LayoutComponentBase
@inject NavigationManager NavigationManager @inject NavigationManager NavigationManager
@inject IUserUtility UserUtility @inject IUserUtility UserUtility
@inject IBrowserViewportService BrowserViewportService
<style> <style>
body .pwa-updater[b-pwa-updater] { body .pwa-updater[b-pwa-updater] {
@ -34,14 +34,12 @@
<AuthorizeView> <AuthorizeView>
<Authorized> <Authorized>
<MudRTLProvider RightToLeft="true"> <MudRTLProvider RightToLeft="true">
<MudThemeProvider IsDarkMode="@MainTheme.IsDarkMode" Theme="@MainTheme.MyCustomTheme" /> <MudThemeProvider IsDarkMode="@MainTheme.IsDarkMode" Theme="@MainTheme.MyCustomTheme"/>
<MudDialogProvider /> <MudDialogProvider/>
<MudSnackbarProvider /> <MudSnackbarProvider/>
<MudLayout> <MudLayout>
<MudAppBar Elevation="1" class="py-2"> <MudAppBar class="py-2" Color="Color.Transparent" Fixed="false" Elevation="2">
<MudHidden Breakpoint="Breakpoint.MdAndUp"> <MudHidden Breakpoint="Breakpoint.MdAndUp">
<MudIconButton Icon="@Icons.Material.Filled.Menu" Color="Color.Inherit" OnClick="@ToggleDrawer" Edge="Edge.Start"/> <MudIconButton Icon="@Icons.Material.Filled.Menu" Color="Color.Inherit" OnClick="@ToggleDrawer" Edge="Edge.Start"/>
</MudHidden> </MudHidden>
@ -58,30 +56,43 @@
ToggledIcon="@Icons.Material.Filled.LightMode" ToggledColor="@Color.Default" ToggledTitle="روشن"/> ToggledIcon="@Icons.Material.Filled.LightMode" ToggledColor="@Color.Default" ToggledTitle="روشن"/>
<MudIconButton Size="Size.Medium" Color="Color.Error" OnClick="LogoutAsync" Icon="@Icons.Material.Outlined.ExitToApp"/> <MudIconButton Size="Size.Medium" Color="Color.Error" OnClick="LogoutAsync" Icon="@Icons.Material.Outlined.ExitToApp"/>
</MudAppBar> </MudAppBar>
<MudDrawer @bind-Open="open" ClipMode="DrawerClipMode.Always" Elevation="2">
<SideBarUi /> <MudDrawer @bind-Open="@open" Breakpoint="Breakpoint.MdAndUp" Elevation="1" Variant="@DrawerVariant.Responsive">
<SideBarUi/>
</MudDrawer> </MudDrawer>
<MudMainContent class="bg-[--mud-palette-background-grey] h-screen overflow-y-auto">
@Body <MudGrid Spacing="0">
</MudMainContent>
<div dir="ltr"> <MudItem md="3" lg="2">
<PWAUpdater Text="@_updateText" ButtonCaption="اپدیت کنید" /> <MudHidden Breakpoint="Breakpoint.SmAndDown">
</div> <SideBarUi/>
</MudHidden>
</MudItem>
<MudItem sm="12" md="9" lg="10">
<div>
@Body
</div>
</MudItem>
</MudGrid>
</MudLayout> </MudLayout>
<div dir="ltr">
<PWAUpdater Align="PWAUpdater.Aligns.Buttom" Text="@_updateText" ButtonCaption="اپدیت کنید"/>
</div>
</MudRTLProvider> </MudRTLProvider>
</Authorized> </Authorized>
<NotAuthorized> <NotAuthorized>
<MudRTLProvider RightToLeft="true"> <MudRTLProvider RightToLeft="true">
<MudThemeProvider Theme="@MainTheme.MyCustomTheme" /> <MudThemeProvider Theme="@MainTheme.MyCustomTheme"/>
<MudDialogProvider /> <MudDialogProvider/>
<MudSnackbarProvider /> <MudSnackbarProvider/>
<MudLayout> <MudLayout>
<div> <div>
<LoginPage /> <LoginPage/>
<div dir="ltr"> <div dir="ltr">
<PWAUpdater Text="@_updateText" ButtonCaption="اپدیت کنید" /> <PWAUpdater Text="@_updateText" ButtonCaption="اپدیت کنید"/>
</div> </div>
</div> </div>
</MudLayout> </MudLayout>
@ -114,9 +125,6 @@
protected override async Task OnInitializedAsync() protected override async Task OnInitializedAsync()
{ {
var screen = await BrowserViewportService.GetCurrentBreakpointAsync();
if (screen > Breakpoint.Md)
open = true;
_user = await UserUtility.GetUserAsync(); _user = await UserUtility.GetUserAsync();
await base.OnInitializedAsync(); await base.OnInitializedAsync();
} }

View File

@ -9,8 +9,6 @@ public static class Address
public static string ProductCategoryController = $"/product/category"; public static string ProductCategoryController = $"/product/category";
public static string ProductController = $"/product"; public static string ProductController = $"/product";
public static string BrandController = $"/brand"; public static string BrandController = $"/brand";
public static string SubProductController = $"/sub/product";
public static string FileController => $"/file"; public static string FileController => $"/file";
public static string BlogController => $"/blog"; public static string BlogController => $"/blog";
public static string BlogCategoryController => $"/blog/category"; public static string BlogCategoryController => $"/blog/category";
@ -25,6 +23,4 @@ public static class Address
public static string DashboardController => $"/dashboard"; public static string DashboardController => $"/dashboard";
public static string SettingController => $"/setting"; public static string SettingController => $"/setting";
public static string DistrictController => $"/district"; public static string DistrictController => $"/district";
public static string FaqController => $"/faq";
public static string CommentController => $"/comment";
} }

View File

@ -19,7 +19,7 @@ public class BaseViewModel<TPageDto>
public bool IsProcessing { get; set; } = false; public bool IsProcessing { get; set; } = false;
public TPageDto PageDto { get; set; } public TPageDto PageDto { get; set; }
private string[] _permissions = new string[]{}; private string[] _permissions = new string[]{};
protected readonly IUserUtility _userUtility; private readonly IUserUtility _userUtility;
public bool IsPermitted { get; set; } = false; public bool IsPermitted { get; set; } = false;
public BaseViewModel(IUserUtility userUtility,params string[] permissions) public BaseViewModel(IUserUtility userUtility,params string[] permissions)
{ {

View File

@ -5,8 +5,8 @@
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<ServiceWorkerAssetsManifest>service-worker-assets.js</ServiceWorkerAssetsManifest> <ServiceWorkerAssetsManifest>service-worker-assets.js</ServiceWorkerAssetsManifest>
<AssemblyVersion>1.14.22.43</AssemblyVersion> <AssemblyVersion>1.0.3.3</AssemblyVersion>
<FileVersion>1.14.22.42</FileVersion> <FileVersion>1.0.3.3</FileVersion>
<AssemblyName>$(MSBuildProjectName)</AssemblyName> <AssemblyName>$(MSBuildProjectName)</AssemblyName>
</PropertyGroup> </PropertyGroup>
@ -34,12 +34,6 @@
</EmbeddedResource> </EmbeddedResource>
</ItemGroup> </ItemGroup>
<ItemGroup>
<None Include="wwwroot\assets\vendor\ckeditor5.css.map" />
<None Include="wwwroot\assets\vendor\ckeditor5.js" />
<None Include="wwwroot\assets\vendor\ckeditor5.js.map" />
</ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Append.Blazor.Printing" Version="6.3.0" /> <PackageReference Include="Append.Blazor.Printing" Version="6.3.0" />
<PackageReference Include="Blazored.LocalStorage" Version="4.4.0" /> <PackageReference Include="Blazored.LocalStorage" Version="4.4.0" />
@ -61,7 +55,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\..\Api\Netina.Domain\Netina.Domain.csproj" /> <ProjectReference Include="..\..\Netina\Netina.Domain\Netina.Domain.csproj" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
@ -96,7 +90,6 @@
<Using Include="Netina.Domain.Entities.ProductCategories" /> <Using Include="Netina.Domain.Entities.ProductCategories" />
<Using Include="Netina.Domain.Entities.Products" /> <Using Include="Netina.Domain.Entities.Products" />
<Using Include="Netina.Domain.Enums" /> <Using Include="Netina.Domain.Enums" />
<Using Include="Netina.Domain.Extensions" />
<Using Include="Netina.Domain.MartenEntities.Pages" /> <Using Include="Netina.Domain.MartenEntities.Pages" />
<Using Include="Netina.Domain.MartenEntities.Settings" /> <Using Include="Netina.Domain.MartenEntities.Settings" />
<Using Include="Netina.Domain.Models.Districts" /> <Using Include="Netina.Domain.Models.Districts" />

View File

@ -7,7 +7,7 @@
@inject IUserUtility UserUtility @inject IUserUtility UserUtility
@inject IRestWrapper RestWrapper @inject IRestWrapper RestWrapper
<MudStack class="h-full w-full p-8"> <MudStack class="w-full p-8 h-screen bg-[--mud-palette-background-grey]">
<MudGrid> <MudGrid>
<MudItem xs="12"> <MudItem xs="12">
<MudStack Row="true" class="mb-5"> <MudStack Row="true" class="mb-5">
@ -58,7 +58,7 @@
<MudStack Row="true" class="w-full"> <MudStack Row="true" class="w-full">
<MudPagination Rectangular="true" Variant="Variant.Filled" Count="@ViewModel.PageCount" <MudPagination Rectangular="true" Variant="Variant.Filled" Count="@ViewModel.PageCount"
SelectedChanged="@ViewModel.ChangePageAsync" class="mx-auto my-4" /> SelectedChanged="@ViewModel.ChangePageAsync" class="my-4 mx-auto" />
</MudStack> </MudStack>
</PagerContent> </PagerContent>

View File

@ -9,7 +9,7 @@
@inject IConfiguration Configuration @inject IConfiguration Configuration
@inject IJSRuntime JsRuntime @inject IJSRuntime JsRuntime
<MudStack class="h-full w-full p-8"> <MudStack class="w-full p-8 h-screen bg-[--mud-palette-background-grey]">
<MudGrid> <MudGrid>
<MudItem xs="12"> <MudItem xs="12">
<MudStack Row="true" class="mb-5"> <MudStack Row="true" class="mb-5">
@ -67,7 +67,7 @@
<MudStack Row="true" class="w-full"> <MudStack Row="true" class="w-full">
<MudPagination Rectangular="true" Variant="Variant.Filled" Count="@ViewModel.PageCount" <MudPagination Rectangular="true" Variant="Variant.Filled" Count="@ViewModel.PageCount"
SelectedChanged="@ViewModel.ChangePageAsync" class="mx-auto my-4" /> SelectedChanged="@ViewModel.ChangePageAsync" class="my-4 mx-auto" />
</MudStack> </MudStack>
</PagerContent> </PagerContent>

View File

@ -5,11 +5,9 @@
@inject IRestWrapper RestWrapper @inject IRestWrapper RestWrapper
@inject ISnackbar Snackbar @inject ISnackbar Snackbar
@inject IUserUtility UserUtility @inject IUserUtility UserUtility
@inject IConfiguration Configuration
@inject IJSRuntime JsRuntime
<MudStack class="h-full w-full p-8"> <MudStack class="w-full p-8 h-screen bg-[--mud-palette-background-grey]">
<MudGrid> <MudGrid>
<MudItem xs="12"> <MudItem xs="12">
<MudStack Row="true" class="mb-5"> <MudStack Row="true" class="mb-5">
@ -27,7 +25,7 @@
<MudPaper> <MudPaper>
<MudDataGrid Striped="true" T="BrandSDto" Items="@ViewModel.PageDto" Filterable="false" Loading="@ViewModel.IsProcessing" <MudDataGrid Striped="true" T="BrandSDto" Items="@ViewModel.PageDto" Filterable="false" Loading="@ViewModel.IsProcessing"
CurrentPage="@ViewModel.CurrentPage" CurrentPage="@ViewModel.CurrentPage"
RowsPerPage="10" RowsPerPage="15"
SortMode="@SortMode.None" Groupable="false"> SortMode="@SortMode.None" Groupable="false">
<ToolBarContent> <ToolBarContent>
<MudTextField T="string" Placeholder="جست جو بر اساس نام" Adornment="Adornment.Start" Immediate="true" <MudTextField T="string" Placeholder="جست جو بر اساس نام" Adornment="Adornment.Start" Immediate="true"
@ -39,6 +37,7 @@
<Columns> <Columns>
<PropertyColumn Title="نام برند" Property="arg => arg.PersianName" /> <PropertyColumn Title="نام برند" Property="arg => arg.PersianName" />
<PropertyColumn Title="نام انگلیسی برند" Property="arg => arg.EnglishName" /> <PropertyColumn Title="نام انگلیسی برند" Property="arg => arg.EnglishName" />
<PropertyColumn Title="توضیحاتــ" Property="arg => arg.Description" />
<TemplateColumn Title="صفحه اختصاصی دارد" T="BrandSDto"> <TemplateColumn Title="صفحه اختصاصی دارد" T="BrandSDto">
<CellTemplate> <CellTemplate>
@if (@context.Item.HasSpecialPage) @if (@context.Item.HasSpecialPage)
@ -55,22 +54,15 @@
<TemplateColumn CellClass="d-flex justify-end"> <TemplateColumn CellClass="d-flex justify-end">
<CellTemplate> <CellTemplate>
<MudStack Row="true"> <MudStack Row="true">
<MudIconButton Icon="@Icons.Material.Filled.Link"
Size="@Size.Small"
Variant="@Variant.Outlined"
Color="@Color.Surface"
OnClick="async()=>await ShowBrand(context.Item)" />
<MudIconButton Icon="@Icons.Material.Filled.Edit" <MudIconButton Icon="@Icons.Material.Filled.Edit"
Size="@Size.Small" Size="@Size.Small"
Variant="@Variant.Outlined" Variant="@Variant.Outlined"
Color="@Color.Info" Color="@Color.Info"
OnClick="async () => await ViewModel.EditBrandAsync(context.Item)"></MudIconButton> OnClick="async()=>await ViewModel.EditBrandAsync(context.Item)"></MudIconButton>
<MudIconButton Icon="@Icons.Material.Filled.Delete" <MudIconButton Icon="@Icons.Material.Filled.Delete"
Size="@Size.Small" Size="@Size.Small"
Variant="@Variant.Outlined" Variant="@Variant.Outlined"
OnClick="async () => await ViewModel.DeleteBrandAsync(context.Item.Id)" OnClick="async() => await ViewModel.DeleteBrandAsync(context.Item.Id)"
Color="@Color.Error"></MudIconButton> Color="@Color.Error"></MudIconButton>
</MudStack> </MudStack>
</CellTemplate> </CellTemplate>
@ -80,7 +72,7 @@
<MudStack Row="true" class="w-full"> <MudStack Row="true" class="w-full">
<MudPagination Rectangular="true" Variant="Variant.Filled" Count="@ViewModel.PageCount" <MudPagination Rectangular="true" Variant="Variant.Filled" Count="@ViewModel.PageCount"
SelectedChanged="@ViewModel.ChangePageAsync" class="mx-auto my-4" /> SelectedChanged="@ViewModel.ChangePageAsync" class="my-4 mx-auto" />
</MudStack> </MudStack>
</PagerContent> </PagerContent>
@ -100,13 +92,8 @@
await base.OnInitializedAsync(); await base.OnInitializedAsync();
} }
private async Task ShowBrand(BrandSDto item)
{
var webUrl = Configuration.GetValue<string>("WebSiteUrl") ?? string.Empty;
var slug = WebUtility.UrlEncode(item.Slug.Replace(' ', '-'));
var url = $"{webUrl}/brands/{item.Id}/{slug}";
await JsRuntime.InvokeVoidAsync("open", url, "_blank");
}
} }
@code {
}

View File

@ -2,38 +2,43 @@
namespace Netina.AdminPanel.PWA.Pages; namespace Netina.AdminPanel.PWA.Pages;
public class BrandsPageViewModel( public class BrandsPageViewModel : BaseViewModel<List<BrandSDto>>
NavigationManager navigationManager,
ISnackbar snackbar,
IUserUtility userUtility,
IRestWrapper restWrapper,
IDialogService dialogService) : BaseViewModel<List<BrandSDto>>(userUtility)
{ {
private readonly NavigationManager _navigationManager = navigationManager; private readonly NavigationManager _navigationManager;
private readonly IUserUtility _userUtility = userUtility; private readonly ISnackbar _snackbar;
private readonly IUserUtility _userUtility;
private readonly IDialogService _dialogService;
private readonly IRestWrapper _restWrapper;
public string Search = string.Empty; public string Search = string.Empty;
public int CurrentPage = 0; public int CurrentPage = 0;
public int PageCount = 1; public int PageCount = 1;
public BrandsPageViewModel(NavigationManager navigationManager, ISnackbar snackbar, IUserUtility userUtility, IRestWrapper restWrapper, IDialogService dialogService) : base(userUtility)
{
_navigationManager = navigationManager;
_snackbar = snackbar;
_userUtility = userUtility;
_restWrapper = restWrapper;
_dialogService = dialogService;
}
public override async Task InitializeAsync() public override async Task InitializeAsync()
{ {
try try
{ {
IsProcessing = true; IsProcessing = true;
var dto = await restWrapper.CrudDtoApiRest<Brand, BrandSDto, Guid>(Address.BrandController) var dto = await _restWrapper.CrudDtoApiRest<Brand, BrandSDto, Guid>(Address.BrandController)
.ReadAll(0); .ReadAll(0);
PageDto = dto; PageDto = dto;
if (PageDto.Count == 10)
PageCount = 2;
} }
catch (ApiException ex) catch (ApiException ex)
{ {
var exe = await ex.GetContentAsAsync<ApiResult>(); var exe = await ex.GetContentAsAsync<ApiResult>();
snackbar.Add(exe != null ? exe.Message : ex.Content, Severity.Error); _snackbar.Add(exe != null ? exe.Message : ex.Content, Severity.Error);
} }
catch (Exception e) catch (Exception e)
{ {
snackbar.Add(e.Message, Severity.Error); _snackbar.Add(e.Message, Severity.Error);
} }
finally finally
{ {
@ -46,18 +51,18 @@ public class BrandsPageViewModel(
public async Task AddBrandClicked() public async Task AddBrandClicked()
{ {
DialogOptions maxWidth = new DialogOptions() { MaxWidth = MaxWidth.Medium, FullWidth = true, DisableBackdropClick = true }; DialogOptions maxWidth = new DialogOptions() { MaxWidth = MaxWidth.Medium, FullWidth = true, DisableBackdropClick = true };
await dialogService.ShowAsync<BrandActionDialogBox>("افزودن برند جدید", maxWidth); await _dialogService.ShowAsync<BrandActionDialogBox>("افزودن برند جدید", maxWidth);
} }
public async Task EditBrandAsync(BrandSDto brand) public async Task EditBrandAsync(BrandSDto brand)
{ {
DialogOptions maxWidth = new DialogOptions() { MaxWidth = MaxWidth.Medium, FullWidth = true, DisableBackdropClick = true }; DialogOptions maxWidth = new DialogOptions() { MaxWidth = MaxWidth.Medium, FullWidth = true, DisableBackdropClick = true };
var parameters = new DialogParameters<BrandActionDialogBox> { { x => x.Brand, brand } }; var parameters = new DialogParameters<BrandActionDialogBox> { { x => x.Brand, brand } };
await dialogService.ShowAsync<BrandActionDialogBox>($"ویرایش برند {brand.PersianName}", parameters, maxWidth); await _dialogService.ShowAsync<BrandActionDialogBox>($"ویرایش برند {brand.PersianName}", parameters, maxWidth);
} }
public async Task DeleteBrandAsync(Guid selectedCategoryId) public async Task DeleteBrandAsync(Guid selectedCategoryId)
{ {
var reference = await dialogService.ShowQuestionDialog($"آیا از حذف برند اطمینان دارید ?"); var reference = await _dialogService.ShowQuestionDialog($"آیا از حذف برند اطمینان دارید ?");
var result = await reference.Result; var result = await reference.Result;
if (!result.Canceled) if (!result.Canceled)
{ {
@ -67,20 +72,20 @@ public class BrandsPageViewModel(
IsProcessing = true; IsProcessing = true;
var token = await _userUtility.GetBearerTokenAsync(); var token = await _userUtility.GetBearerTokenAsync();
await restWrapper.CrudDtoApiRest<Brand, BrandSDto, Guid>(Address.BrandController) await _restWrapper.CrudDtoApiRest<Brand, BrandSDto, Guid>(Address.BrandController)
.Delete(selectedCategoryId, token); .Delete(selectedCategoryId, token);
snackbar.Add("حذف برند با موفقیت انجام شد", Severity.Success); _snackbar.Add("حذف برند با موفقیت انجام شد", Severity.Success);
await InitializeAsync(); await InitializeAsync();
} }
catch (ApiException ex) catch (ApiException ex)
{ {
var exe = await ex.GetContentAsAsync<ApiResult>(); var exe = await ex.GetContentAsAsync<ApiResult>();
snackbar.Add(exe != null ? exe.Message : ex.Content, Severity.Error); _snackbar.Add(exe != null ? exe.Message : ex.Content, Severity.Error);
} }
catch (Exception e) catch (Exception e)
{ {
snackbar.Add(e.Message, Severity.Error); _snackbar.Add(e.Message, Severity.Error);
} }
finally finally
{ {
@ -97,7 +102,6 @@ public class BrandsPageViewModel(
await InitializeAsync(); await InitializeAsync();
Search = search; Search = search;
} }
public async Task SearchAsync() public async Task SearchAsync()
{ {
try try
@ -108,19 +112,19 @@ public class BrandsPageViewModel(
CurrentPage = 0; CurrentPage = 0;
PageCount = 1; PageCount = 1;
PageDto.Clear(); PageDto.Clear();
var dto = await restWrapper.BrandRestApi.ReadAll(CurrentPage, Search); var dto = await _restWrapper.BrandRestApi.ReadAll(CurrentPage, Search);
dto.ForEach(d => PageDto.Add(d)); dto.ForEach(d => PageDto.Add(d));
if (PageDto.Count == 10) if (PageDto.Count == 20)
PageCount = 2; PageCount = 2;
} }
catch (ApiException ex) catch (ApiException ex)
{ {
var exe = await ex.GetContentAsAsync<ApiResult>(); var exe = await ex.GetContentAsAsync<ApiResult>();
snackbar.Add(exe != null ? exe.Message : ex.Content, Severity.Error); _snackbar.Add(exe != null ? exe.Message : ex.Content, Severity.Error);
} }
catch (Exception e) catch (Exception e)
{ {
snackbar.Add(e.Message, Severity.Error); _snackbar.Add(e.Message, Severity.Error);
} }
finally finally
{ {
@ -142,27 +146,27 @@ public class BrandsPageViewModel(
List<BrandSDto> dto = new List<BrandSDto>(); List<BrandSDto> dto = new List<BrandSDto>();
if (Search.IsNullOrEmpty()) if (Search.IsNullOrEmpty())
{ {
dto = await restWrapper.CrudDtoApiRest<Brand, BrandSDto, Guid>(Address.BrandController) dto = await _restWrapper.CrudDtoApiRest<Brand, BrandSDto, Guid>(Address.BrandController)
.ReadAll(CurrentPage); .ReadAll(CurrentPage);
} }
else else
{ {
dto = await restWrapper.BrandRestApi.ReadAll(CurrentPage, Search); dto = await _restWrapper.BrandRestApi.ReadAll(CurrentPage, Search);
} }
dto.ForEach(d => PageDto.Add(d)); dto.ForEach(d => PageDto.Add(d));
if (PageDto.Count % 10 == 0) if (PageDto.Count % 20 == 0)
PageCount = CurrentPage + 2; PageCount = CurrentPage + 2;
} }
catch (ApiException ex) catch (ApiException ex)
{ {
var exe = await ex.GetContentAsAsync<ApiResult>(); var exe = await ex.GetContentAsAsync<ApiResult>();
snackbar.Add(exe != null ? exe.Message : ex.Content, Severity.Error); _snackbar.Add(exe != null ? exe.Message : ex.Content, Severity.Error);
} }
catch (Exception e) catch (Exception e)
{ {
snackbar.Add(e.Message, Severity.Error); _snackbar.Add(e.Message, Severity.Error);
} }
finally finally
{ {

View File

@ -5,106 +5,100 @@
@inject ISnackbar Snackbar @inject ISnackbar Snackbar
@inject IUserUtility UserUtility @inject IUserUtility UserUtility
@* <style>
.mud-input-label { <MudStack class="w-full p-8 h-screen bg-[--mud-palette-background-grey]">
background-color: var(--mud-palette-background-grey); <MudGrid>
} <MudItem xs="12">
</style> *@
<MudStack class="h-full w-full p-3 md:p-8">
<MudStack Row="true" class="overflow-x-auto pb-3">
<MudStack Spacing="1" class="min-w-[340px]">
<MudStack Row="true" class="mb-5"> <MudStack Row="true" class="mb-5">
<MudText Typo="Typo.h6" class="my-auto"><b>دسته های اصلی</b></MudText> <MudText Typo="Typo.h4">دسته بندی ها</MudText>
<MudSpacer /> @* <MudChip Color="Color.Info" Variant="Variant.Outlined">124 عدد</MudChip> *@
<MudIconButton Icon="@Icons.Material.Filled.Add"
Size="@Size.Small"
Variant="@Variant.Outlined" <MudSpacer/>
OnClick="()=>ViewModel.ChangeOriginalCategoryVisibility()" <MudButton Variant="Variant.Filled"
Color="@Color.Secondary" /> DisableElevation="true"
StartIcon="@Icons.Material.Outlined.Add"
Color="Color.Secondary"
OnClick="ViewModel.AddProductCategoryClicked"
class="my-auto">افزودن دسته بندی</MudButton>
</MudStack> </MudStack>
@if (ViewModel.OriginalCategoryVisibility) <MudPaper class="!max-h-[80vh] overflow-auto">
{ <MudDataGrid FixedFooter="true" FixedHeader="true" Striped="true"
<MudTextField class="-mt-2 mb-3" T="string" Label="نام دسته بندی" Variant="Variant.Text" Immediate="false" ValueChanged="name => ViewModel.AddFastProductCategory(name)"></MudTextField> T="ProductCategorySDto" Items="@ViewModel.PageDto" CurrentPage="@ViewModel.CurrentPage"
} RowsPerPage="15" Filterable="false" Loading="@ViewModel.IsProcessing"
@foreach (var item in ViewModel.PageDto) SortMode="@SortMode.None" Groupable="false">
{ <ToolBarContent>
<MudCard class="@(item.IsSelected ? "cursor-pointer border-dashed border-2 border-blue-400 " : "cursor-pointer" )" @onclick="()=>ViewModel.SelectCategory(item)"> <MudTextField T="string" Placeholder="جست جو بر اساس نام" Adornment="Adornment.Start" Immediate="true"
<MudCardHeader> AdornmentIcon="@Icons.Material.Filled.Search" IconSize="Size.Medium" class="my-auto"
<CardHeaderContent> @bind-Value="@ViewModel.Search"
<MudText Typo="Typo.body1">@item.Name</MudText> OnAdornmentClick="@ViewModel.SearchAsync"></MudTextField>
</CardHeaderContent> </ToolBarContent>
<CardHeaderActions>
<MudStack Row="true" Spacing="1">
<MudIconButton Icon="@Icons.Material.Filled.Edit"
Size="@Size.Small"
class="mt-1"
Variant="@Variant.Outlined"
OnClick="async () => await ViewModel.EditProductCategoryClicked(item)"
Color="@Color.Info" />
<MudIconButton Icon="@Icons.Material.Filled.Delete" <Columns>
Size="@Size.Small" <HierarchyColumn T="ProductCategorySDto" ButtonDisabledFunc="@(x => x.Description.IsNullOrEmpty())" />
class="mt-1" <PropertyColumn Title="نام دسته" Resizable="false" Property="arg => arg.Name"/>
Variant="@Variant.Outlined" @* <TemplateColumn Title="توضیحاتــ" Resizable="false" T="ProductCategorySDto">
OnClick="async () => await ViewModel.DeleteProductCategoryAsync(item.Id)" <CellTemplate>
Color="@Color.Error" /> <p class="line-clamp-1">@context.Item.Description</p>
</MudStack> </CellTemplate>
</CardHeaderActions> </TemplateColumn> *@
</MudCardHeader> <TemplateColumn Resizable="false" Title="دسته اصلی" T="ProductCategorySDto">
</MudCard> <CellTemplate>
} @if (@context.Item.IsMain)
</MudStack> {
<p>بلی</p>
}
else
{
<p>خیر</p>
}
@foreach (var item in ViewModel.SelectedCategories) </CellTemplate>
{ </TemplateColumn>
<MudStack Spacing="1" class="min-w-[340px]"> <PropertyColumn Title="دسته پدر" Resizable="false" Property="arg => arg.ParentName" />
<MudStack Row="true" class="mb-5"> <TemplateColumn CellClass="d-flex justify-end">
<MudText Typo="Typo.h6" class="my-auto"><b>@item.Name</b></MudText> <CellTemplate>
<MudSpacer /> <MudStack Row="true">
<MudIconButton Icon="@Icons.Material.Filled.Add"
Size="@Size.Small"
Variant="@Variant.Outlined"
OnClick="()=>item.AddNewCatVisibility = !item.AddNewCatVisibility"
Color="@Color.Secondary" />
</MudStack>
@if (item.AddNewCatVisibility)
{
<MudTextField class="-mt-2 mb-3 flex-none" T="string" Label="نام دسته بندی" Variant="Variant.Text" Immediate="false" ValueChanged="name => ViewModel.AddFastProductCategory(name,item.Id)"></MudTextField>
}
@foreach (var child in item.Children)
{
<MudCard class="@(child.IsSelected ? "cursor-pointer border-dashed border-2 border-blue-400 " : "cursor-pointer" )" @onclick="()=>ViewModel.SelectCategory(child)">
<MudCardHeader>
<CardHeaderContent>
<MudText Typo="Typo.body1">@child.Name</MudText>
</CardHeaderContent>
<CardHeaderActions>
<MudStack Row="true" Spacing="1">
<MudIconButton Icon="@Icons.Material.Filled.Edit" <MudIconButton Icon="@Icons.Material.Filled.Edit"
Size="@Size.Small" Size="@Size.Small"
class="mt-1"
Variant="@Variant.Outlined" Variant="@Variant.Outlined"
OnClick="async () => await ViewModel.EditProductCategoryClicked(child)" OnClick="async () => await ViewModel.EditProductCategoryClicked(context.Item)"
Color="@Color.Info" /> Color="@Color.Info"/>
<MudIconButton Icon="@Icons.Material.Filled.Delete" <MudIconButton Icon="@Icons.Material.Filled.Delete"
Size="@Size.Small" Size="@Size.Small"
class="mt-1"
Variant="@Variant.Outlined" Variant="@Variant.Outlined"
OnClick="async () => await ViewModel.DeleteProductCategoryAsync(child.Id)" OnClick="async () => await ViewModel.DeleteProductCategoryAsync(context.Item.Id)"
Color="@Color.Error" /> Color="@Color.Error"/>
</MudStack> </MudStack>
</CardHeaderActions> </CellTemplate>
</MudCardHeader> </TemplateColumn>
</MudCard> </Columns>
}
</MudStack>
}
<ChildRowContent>
<MudCard>
<MudCardHeader>
<CardHeaderContent>
<MudText Typo="Typo.h6">توضیحاتــ</MudText>
</CardHeaderContent>
</MudCardHeader>
<MudCardContent>
<MudText>@context.Item.Description</MudText>
</MudCardContent>
</MudCard>
</ChildRowContent>
<PagerContent>
<MudStack Row="true" class="w-full">
</MudStack> <MudPagination Rectangular="true" Variant="Variant.Filled" Count="@ViewModel.PageCount"
SelectedChanged="@ViewModel.ChangePageAsync" class="my-4 mx-auto"/>
</MudStack>
</PagerContent>
</MudDataGrid>
</MudPaper>
</MudItem>
</MudGrid>
</MudStack> </MudStack>
@code @code

View File

@ -1,36 +1,47 @@
namespace Netina.AdminPanel.PWA.Pages; namespace Netina.AdminPanel.PWA.Pages;
public class CategoriesPageViewModel( public class CategoriesPageViewModel : BaseViewModel<ObservableCollection<ProductCategorySDto>>
NavigationManager navigationManager,
ISnackbar snackbar,
IUserUtility userUtility,
IRestWrapper restWrapper,
IDialogService dialogService)
: BaseViewModel<ObservableCollection<ProductCategorySDto>>(userUtility)
{ {
private readonly NavigationManager _navigationManager = navigationManager; private readonly NavigationManager _navigationManager;
private readonly IUserUtility _userUtility = userUtility; private readonly ISnackbar _snackbar;
private readonly IUserUtility _userUtility;
private readonly IDialogService _dialogService;
private readonly IRestWrapper _restWrapper;
public string Search = string.Empty; public string Search = string.Empty;
public int CurrentPage = 0;
public int PageCount = 1;
public CategoriesPageViewModel(NavigationManager navigationManager, ISnackbar snackbar, IUserUtility userUtility, IRestWrapper restWrapper, IDialogService dialogService) : base(userUtility)
{
_navigationManager = navigationManager;
_snackbar = snackbar;
_userUtility = userUtility;
_restWrapper = restWrapper;
_dialogService = dialogService;
}
public override async Task InitializeAsync() public override async Task InitializeAsync()
{ {
try try
{ {
IsProcessing = true; IsProcessing = true;
CurrentPage = 0;
PageDto.Clear(); PageDto.Clear();
var dto = await restWrapper.ProductCategoryRestApi.ReadAll(true); var dto = await _restWrapper.CrudDtoApiRest<ProductCategory, ProductCategorySDto, Guid>(Address.ProductCategoryController)
dto.ForEach(d => PageDto.Add(d)); .ReadAll(CurrentPage);
dto.ForEach(d=>PageDto.Add(d));
if (PageDto.Count == 15)
PageCount = 2;
} }
catch (ApiException ex) catch (ApiException ex)
{ {
var exe = await ex.GetContentAsAsync<ApiResult>(); var exe = await ex.GetContentAsAsync<ApiResult>();
snackbar.Add(exe != null ? exe.Message : ex.Content, Severity.Error); _snackbar.Add(exe != null ? exe.Message : ex.Content, Severity.Error);
} }
catch (Exception e) catch (Exception e)
{ {
snackbar.Add(e.Message, Severity.Error); _snackbar.Add(e.Message, Severity.Error);
} }
finally finally
{ {
@ -40,11 +51,43 @@ public class CategoriesPageViewModel(
await base.InitializeAsync(); await base.InitializeAsync();
} }
public async Task ChangePageAsync(int page)
{
CurrentPage = page-1;
if (CurrentPage > PageCount-2)
{
try
{
IsProcessing = true;
var dto = await _restWrapper.CrudDtoApiRest<ProductCategory, ProductCategorySDto, Guid>(Address.ProductCategoryController)
.ReadAll(CurrentPage);
dto.ForEach(d => PageDto.Add(d));
if(PageDto.Count % 15==0)
PageCount = CurrentPage + 2;
}
catch (ApiException ex)
{
var exe = await ex.GetContentAsAsync<ApiResult>();
_snackbar.Add(exe != null ? exe.Message : ex.Content, Severity.Error);
}
catch (Exception e)
{
_snackbar.Add(e.Message, Severity.Error);
}
finally
{
IsProcessing = false;
}
}
}
public async Task AddProductCategoryClicked() public async Task AddProductCategoryClicked()
{ {
DialogOptions maxWidth = new DialogOptions() { MaxWidth = MaxWidth.Medium, FullWidth = true, DisableBackdropClick = true }; DialogOptions maxWidth = new DialogOptions() { MaxWidth = MaxWidth.Medium, FullWidth = true, DisableBackdropClick = true };
var dialogResult = await dialogService.ShowAsync<ProductCategoryActionDialogBox>("افزودن دسته جدید", maxWidth); var dialogResult = await _dialogService.ShowAsync<ProductCategoryActionDialogBox>("افزودن دسته جدید", maxWidth);
var result = await dialogResult.Result; var result = await dialogResult.Result;
if (!result.Canceled && result.Data is bool and true) if (!result.Canceled && result.Data is bool and true)
{ {
@ -56,8 +99,8 @@ public class CategoriesPageViewModel(
{ {
DialogOptions maxWidth = new DialogOptions() { MaxWidth = MaxWidth.Medium, FullWidth = true, DisableBackdropClick = true }; DialogOptions maxWidth = new DialogOptions() { MaxWidth = MaxWidth.Medium, FullWidth = true, DisableBackdropClick = true };
var parameters = new DialogParameters<ProductCategoryActionDialogBox>(); var parameters = new DialogParameters<ProductCategoryActionDialogBox>();
parameters.Add(x => x.Category, category); parameters.Add(x=>x.Category,category);
var dialogResult = await dialogService.ShowAsync<ProductCategoryActionDialogBox>($"ویرایش دسته {category.Name}", parameters, maxWidth); var dialogResult = await _dialogService.ShowAsync<ProductCategoryActionDialogBox>($"ویرایش دسته {category.Name}", parameters, maxWidth);
var result = await dialogResult.Result; var result = await dialogResult.Result;
if (!result.Canceled && result.Data is bool and true) if (!result.Canceled && result.Data is bool and true)
{ {
@ -67,7 +110,7 @@ public class CategoriesPageViewModel(
public async Task DeleteProductCategoryAsync(Guid selectedCategoryId) public async Task DeleteProductCategoryAsync(Guid selectedCategoryId)
{ {
var reference = await dialogService.ShowQuestionDialog($"آیا از حذف دسته بندی اطمینان دارید ?"); var reference = await _dialogService.ShowQuestionDialog($"آیا از حذف دسته بندی اطمینان دارید ?");
var result = await reference.Result; var result = await reference.Result;
if (!result.Canceled) if (!result.Canceled)
{ {
@ -77,20 +120,20 @@ public class CategoriesPageViewModel(
IsProcessing = true; IsProcessing = true;
var token = await _userUtility.GetBearerTokenAsync(); var token = await _userUtility.GetBearerTokenAsync();
await restWrapper.CrudDtoApiRest<ProductCategory, ProductCategorySDto, Guid>(Address.ProductCategoryController) await _restWrapper.CrudDtoApiRest<ProductCategory, ProductCategorySDto, Guid>(Address.ProductCategoryController)
.Delete(selectedCategoryId, token); .Delete(selectedCategoryId, token);
snackbar.Add("حذف دسته بندی با موفقیت انجام شد", Severity.Success); _snackbar.Add("حذف دسته بندی با موفقیت انجام شد", Severity.Success);
await InitializeAsync(); await InitializeAsync();
} }
catch (ApiException ex) catch (ApiException ex)
{ {
var exe = await ex.GetContentAsAsync<ApiResult>(); var exe = await ex.GetContentAsAsync<ApiResult>();
snackbar.Add(exe != null ? exe.Message : ex.Content, Severity.Error); _snackbar.Add(exe != null ? exe.Message : ex.Content, Severity.Error);
} }
catch (Exception e) catch (Exception e)
{ {
snackbar.Add(e.Message, Severity.Error); _snackbar.Add(e.Message, Severity.Error);
} }
finally finally
{ {
@ -107,18 +150,22 @@ public class CategoriesPageViewModel(
if (Search.IsNullOrEmpty()) if (Search.IsNullOrEmpty())
throw new AppException("دسته بندی برای جست جو وارد نشده است"); throw new AppException("دسته بندی برای جست جو وارد نشده است");
IsProcessing = true; IsProcessing = true;
CurrentPage = 0;
PageCount = 1;
PageDto.Clear(); PageDto.Clear();
var dto = await restWrapper.ProductCategoryRestApi.ReadAll(Search); var dto = await _restWrapper.ProductCategoryRestApi.ReadAll(Search);
dto.ForEach(d => PageDto.Add(d)); dto.ForEach(d => PageDto.Add(d));
if (PageDto.Count == 15)
PageCount = 2;
} }
catch (ApiException ex) catch (ApiException ex)
{ {
var exe = await ex.GetContentAsAsync<ApiResult>(); var exe = await ex.GetContentAsAsync<ApiResult>();
snackbar.Add(exe != null ? exe.Message : ex.Content, Severity.Error); _snackbar.Add(exe != null ? exe.Message : ex.Content, Severity.Error);
} }
catch (Exception e) catch (Exception e)
{ {
snackbar.Add(e.Message, Severity.Error); _snackbar.Add(e.Message, Severity.Error);
} }
finally finally
{ {
@ -126,92 +173,4 @@ public class CategoriesPageViewModel(
IsProcessing = false; IsProcessing = false;
} }
} }
public List<ProductCategorySDto> SelectedCategories = new();
public void SelectCategory(ProductCategorySDto category)
{
var selected = SelectedCategories.FirstOrDefault(c => c.Id == category.Id);
if (selected != null)
{
UnSelectCategory(selected);
return;
}
var parent = FindParent(category.ParentId, PageDto.ToList());
if (parent != null)
category.Index = parent.Index + 1;
category.IsSelected = true;
var currentSelectedIndex = SelectedCategories.FirstOrDefault(c => c.Index == category.Index);
if (currentSelectedIndex != null)
UnSelectCategory(currentSelectedIndex);
SelectedCategories.Add(category);
}
public bool OriginalCategoryVisibility = false;
public bool ChangeOriginalCategoryVisibility() => OriginalCategoryVisibility = !OriginalCategoryVisibility;
public void AddFastProductCategory(string categoryName, Guid? parentId = null)
{
if (categoryName.IsNullOrEmpty())
return;
ProductCategorySDto category = new ProductCategorySDto { Name = categoryName, IsMain = true };
if (parentId != null)
{
category.IsMain = false;
category.ParentId = parentId.Value;
}
var command = new CreateProductCategoryCommand(category.Name, category.Description, category.IsMain, category.ParentId, new(), new Dictionary<string, string>(), new Dictionary<string, string>());
Task.Run(async () =>
{
var token = await _userUtility.GetBearerTokenAsync();
if (token == null)
return;
var response = await restWrapper.CrudApiRest<ProductCategory, Guid>(Address.ProductCategoryController)
.Create(command, token);
category.Id = response;
});
if (parentId == null)
{
category.IsMain = true;
PageDto.Add(category);
}
else
{
var parent = FindParent(parentId.Value, PageDto.ToList());
if (parent != null)
{
category.Index = parent.Index + 1;
parent.Children.Add(category);
}
}
categoryName = string.Empty;
}
private void UnSelectCategory(ProductCategorySDto category)
{
category.IsSelected = false;
foreach (var selected in SelectedCategories.Where(c => c.ParentId == category.Id).ToList())
UnSelectCategory(selected);
SelectedCategories.Remove(category);
}
private ProductCategorySDto? FindParent(Guid parentId, List<ProductCategorySDto> categories)
{
var parent = categories.FirstOrDefault(c => c.Id == parentId);
if (parent != null)
return parent;
foreach (var category in categories)
{
var founded = FindParent(parentId, category.Children);
if (founded != null)
return founded;
}
return null;
}
} }

View File

@ -1,92 +0,0 @@
@page "/crm/customers"
@inject IDialogService DialogService
@inject NavigationManager NavigationManager
@inject IRestWrapper RestWrapper
@inject ISnackbar Snackbar
@inject IUserUtility UserUtility
@* <MudStack class="h-full w-full p-8">
<MudGrid>
<MudItem xs="12">
<MudStack Row="true" class="mb-5">
<MudText Typo="Typo.h4">مشتریان شما</MudText>
<MudSpacer />
</MudStack>
<MudPaper>
<MudDataGrid Striped="true"
T="CustomerSDto"
Items="@ViewModel.PageDto"
Filterable="false"
Loading="@ViewModel.IsProcessing"
CurrentPage="@ViewModel.CurrentPage"
RowsPerPage="15"
SortMode="@SortMode.None" Groupable="false">
<ToolBarContent>
<MudTextField T="string" Placeholder="جست جو بر اساس نام" Adornment="Adornment.Start" Immediate="true"
AdornmentIcon="@Icons.Material.Filled.Search" IconSize="Size.Medium" class="my-auto"
ValueChanged="@ViewModel.SearchChanged"
Clearable="true"
OnAdornmentClick="@ViewModel.SearchAsync"></MudTextField>
</ToolBarContent>
<Columns>
<PropertyColumn Title="نام برند" Property="arg => arg.PersianName" />
<PropertyColumn Title="نام انگلیسی برند" Property="arg => arg.EnglishName" />
<PropertyColumn Title="توضیحاتــ" Property="arg => arg.Description" />
<TemplateColumn Title="صفحه اختصاصی دارد" T="BrandSDto">
<CellTemplate>
@if (@context.Item.HasSpecialPage)
{
<p>بلی</p>
}
else
{
<p>خیر</p>
}
</CellTemplate>
</TemplateColumn>
<TemplateColumn CellClass="d-flex justify-end">
<CellTemplate>
<MudStack Row="true">
<MudIconButton Icon="@Icons.Material.Filled.Edit"
Size="@Size.Small"
Variant="@Variant.Outlined"
Color="@Color.Info"
OnClick="async()=>await ViewModel.EditBrandAsync(context.Item)"></MudIconButton>
<MudIconButton Icon="@Icons.Material.Filled.Delete"
Size="@Size.Small"
Variant="@Variant.Outlined"
OnClick="async() => await ViewModel.DeleteBrandAsync(context.Item.Id)"
Color="@Color.Error"></MudIconButton>
</MudStack>
</CellTemplate>
</TemplateColumn>
</Columns>
<PagerContent>
<MudStack Row="true" class="w-full">
<MudPagination Rectangular="true" Variant="Variant.Filled" Count="@ViewModel.PageCount"
SelectedChanged="@ViewModel.ChangePageAsync" class="mx-auto my-4" />
</MudStack>
</PagerContent>
</MudDataGrid>
</MudPaper>
</MudItem>
</MudGrid>
</MudStack> *@
@code {
public BrandsPageViewModel ViewModel { get; set; }
protected override async Task OnInitializedAsync()
{
ViewModel = new BrandsPageViewModel(NavigationManager, Snackbar, UserUtility, RestWrapper, DialogService);
await ViewModel.InitializeAsync();
await base.OnInitializedAsync();
}
}

View File

@ -1,121 +0,0 @@
using Netina.Domain.Entities.Brands;
namespace Netina.AdminPanel.PWA.Pages;
public class CustomersPageViewModel(
NavigationManager navigationManager,
ISnackbar snackbar,
IUserUtility userUtility,
IRestWrapper restWrapper,
IDialogService dialogService) : BaseViewModel<ObservableCollection<CustomerSDto>> (userUtility)
{
public string Search = string.Empty;
public int CurrentPage = 0;
public int PageCount = 1;
public override async Task InitializeAsync()
{
try
{
IsProcessing = true;
//var dto = await restWrapper.CrudDtoApiRest<Brand, BrandSDto, Guid>(Address.BrandController)
// .ReadAll(0);
//PageDto = dto;
}
catch (ApiException ex)
{
var exe = await ex.GetContentAsAsync<ApiResult>();
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 SearchChanged(string search)
{
if (search.IsNullOrEmpty() && !Search.IsNullOrEmpty())
await InitializeAsync();
Search = search;
}
public async Task SearchAsync()
{
try
{
if (Search.IsNullOrEmpty())
throw new AppException("نام برند برای جست جو وارد نشده است");
IsProcessing = true;
CurrentPage = 0;
PageCount = 1;
PageDto.Clear();
//var dto = await restWrapper.BrandRestApi.ReadAll(CurrentPage, Search);
//dto.ForEach(d => PageDto.Add(d));
//if (PageDto.Count == 20)
// PageCount = 2;
}
catch (ApiException ex)
{
var exe = await ex.GetContentAsAsync<ApiResult>();
snackbar.Add(exe != null ? exe.Message : ex.Content, Severity.Error);
}
catch (Exception e)
{
snackbar.Add(e.Message, Severity.Error);
}
finally
{
IsProcessing = false;
}
}
public async Task ChangePageAsync(int page)
{
CurrentPage = page - 1;
if (CurrentPage > PageCount - 2)
{
try
{
IsProcessing = true;
List<BrandSDto> dto = new List<BrandSDto>();
if (Search.IsNullOrEmpty())
{
dto = await restWrapper.CrudDtoApiRest<Brand, BrandSDto, Guid>(Address.BrandController)
.ReadAll(CurrentPage);
}
else
{
dto = await restWrapper.BrandRestApi.ReadAll(CurrentPage, Search);
}
//dto.ForEach(d => PageDto.Add(d));
if (PageDto.Count % 20 == 0)
PageCount = CurrentPage + 2;
}
catch (ApiException ex)
{
var exe = await ex.GetContentAsAsync<ApiResult>();
snackbar.Add(exe != null ? exe.Message : ex.Content, Severity.Error);
}
catch (Exception e)
{
snackbar.Add(e.Message, Severity.Error);
}
finally
{
IsProcessing = false;
}
}
}
}

View File

@ -7,7 +7,7 @@
@inject IUserUtility UserUtility @inject IUserUtility UserUtility
@inject IRestWrapper RestWrapper @inject IRestWrapper RestWrapper
<MudStack class="h-full w-full p-8"> <MudStack class="w-full p-8 h-screen bg-[--mud-palette-background-grey]">
<MudGrid> <MudGrid>
<MudItem xs="12"> <MudItem xs="12">
<MudStack Row="true" class="mb-5"> <MudStack Row="true" class="mb-5">
@ -125,7 +125,7 @@
<MudStack Row="true" class="w-full"> <MudStack Row="true" class="w-full">
<MudPagination Rectangular="true" Variant="Variant.Filled" Count="@ViewModel.PageCount" <MudPagination Rectangular="true" Variant="Variant.Filled" Count="@ViewModel.PageCount"
SelectedChanged="@ViewModel.ChangePageAsync" class="mx-auto my-4" /> SelectedChanged="@ViewModel.ChangePageAsync" class="my-4 mx-auto" />
</MudStack> </MudStack>
</PagerContent> </PagerContent>

View File

@ -1,5 +1,4 @@
@page "/setting/faq" @page "/management/faqs"
@attribute [Microsoft.AspNetCore.Authorization.Authorize] @attribute [Microsoft.AspNetCore.Authorization.Authorize]
@inject IDialogService DialogService @inject IDialogService DialogService
@ -8,56 +7,48 @@
@inject IUserUtility UserUtility @inject IUserUtility UserUtility
@inject IRestWrapper RestWrapper @inject IRestWrapper RestWrapper
<MudStack class="h-full w-full p-8"> <MudStack class="w-full p-8 h-screen bg-[--mud-palette-background-grey]">
<MudGrid> <MudGrid>
<MudItem xs="12"> <MudItem xs="12">
<MudStack Row="true" class="mb-5"> <MudStack Row="true" class="mb-8">
<MudText Typo="Typo.h4">سوالات متداول</MudText> <MudText Typo="Typo.h4">سوالات متداول فروشگاه من</MudText>
<MudSpacer /> <MudSpacer />
<MudButton Variant="Variant.Filled" <MudButton Variant="Variant.Filled" Size="Size.Large" Color="Color.Success" OnClick="@ViewModel.SaveAsync">ذخیره سوالات</MudButton>
DisableElevation="true"
StartIcon="@Icons.Material.Outlined.Add"
Color="Color.Secondary"
OnClick="@ViewModel.AddClicked"
class="my-auto">افزودن سوالات متداول جدید</MudButton>
</MudStack> </MudStack>
<MudGrid>
<MudItem sm="4">
<MudTextField T="string" Label="سوال" @bind-Value="@ViewModel.Question" Variant="Variant.Outlined"></MudTextField>
</MudItem>
<MudItem sm="6">
<MudTextField T="string" Label="پاسخ" @bind-Value="@ViewModel.Answer" Variant="Variant.Outlined"></MudTextField>
</MudItem>
<MudItem>
<MudButton class="py-3 mt-2" EndIcon="@Icons.Material.Outlined.Add"
Variant="Variant.Outlined" Size="Size.Large" Color="Color.Info" OnClick="@ViewModel.AddNewQuestion">افزودن</MudButton>
</MudItem>
</MudGrid>
<MudPaper> <MudPaper>
<MudDataGrid FixedFooter="true" FixedHeader="true" Striped="true" <MudExpansionPanels class="mt-8">
T="BaseFaq" Items="@ViewModel.PageDto" Filterable="false" @foreach (var item in ViewModel.PageDto.Faqs)
CurrentPage="@ViewModel.CurrentPage" {
RowsPerPage="20" <MudExpansionPanel>
Loading="@ViewModel.IsProcessing"
SortMode="@SortMode.None" Groupable="false"> <TitleContent>
<Columns>
<PropertyColumn Title="عنوان" Property="arg => arg.Title" />
<PropertyColumn Title="اسلاگ" Property="arg => arg.Slug" />
<TemplateColumn CellClass="d-flex justify-end">
<CellTemplate>
<MudStack Row="true"> <MudStack Row="true">
<MudIconButton Icon="@Icons.Material.Outlined.Delete"
<MudIconButton Icon="@Icons.Material.Filled.Edit"
Size="@Size.Small" Size="@Size.Small"
Variant="@Variant.Outlined" Variant="@Variant.Outlined"
Color="@Color.Info" Color="@Color.Error"
OnClick="async()=>await ViewModel.EditClicked(context.Item)" /> OnClick="()=>ViewModel.RemoveQuestion(item.Key)" />
<MudIconButton Icon="@Icons.Material.Filled.Delete" <MudText>@item.Key</MudText>
Size="@Size.Small" </MudStack>
Variant="@Variant.Outlined" </TitleContent>
OnClick="async () => await ViewModel.DeleteAsync(context.Item.Id)" <ChildContent>
Color="@Color.Error" /> @item.Value
</MudStack> </ChildContent>
</CellTemplate> </MudExpansionPanel>
</TemplateColumn> }
</Columns> </MudExpansionPanels>
<PagerContent>
<MudStack Row="true" class="w-full">
<MudPagination Rectangular="true" Variant="Variant.Filled" Count="@ViewModel.PageCount"
SelectedChanged="@ViewModel.ChangePageAsync" class="mx-auto my-4" />
</MudStack>
</PagerContent>
</MudDataGrid>
</MudPaper> </MudPaper>
</MudItem> </MudItem>
</MudGrid> </MudGrid>
@ -68,7 +59,7 @@
public FaqManagementPageViewModel ViewModel { get; set; } public FaqManagementPageViewModel ViewModel { get; set; }
protected override async Task OnInitializedAsync() protected override async Task OnInitializedAsync()
{ {
ViewModel = new FaqManagementPageViewModel(DialogService, NavigationManager, RestWrapper, Snackbar, UserUtility); ViewModel = new FaqManagementPageViewModel(NavigationManager, Snackbar, UserUtility, RestWrapper, DialogService);
await ViewModel.InitializeAsync(); await ViewModel.InitializeAsync();
await base.OnInitializedAsync(); await base.OnInitializedAsync();
} }

View File

@ -1,25 +1,27 @@
using Netina.Domain.MartenEntities.Faqs; namespace Netina.AdminPanel.PWA.Pages;
namespace Netina.AdminPanel.PWA.Pages; public class FaqManagementPageViewModel : BaseViewModel<FAQPage>
public class FaqManagementPageViewModel(
IDialogService dialogService,
NavigationManager navigationManager,
IRestWrapper restWrapper,
ISnackbar snackbar,
IUserUtility userUtility)
: BaseViewModel<ObservableCollection<BaseFaq>> (userUtility)
{ {
public int CurrentPage = 0; private readonly NavigationManager _navigationManager;
public int PageCount = 2; private readonly ISnackbar _snackbar;
private readonly IUserUtility _userUtility;
private readonly IDialogService _dialogService;
private readonly IRestWrapper _restWrapper;
public override async Task InitializeAsync() public FaqManagementPageViewModel(NavigationManager navigationManager, ISnackbar snackbar, IUserUtility userUtility, IRestWrapper restWrapper, IDialogService dialogService) : base(userUtility)
{ {
await GetEntitiesAsync(); _navigationManager = navigationManager;
await base.InitializeAsync(); _snackbar = snackbar;
_userUtility = userUtility;
_restWrapper = restWrapper;
_dialogService = dialogService;
} }
public async Task GetEntitiesAsync()
public string Question { get; set; } = string.Empty;
public string Answer { get; set; } = string.Empty;
private PageActionRequestDto? _request;
public override async Task InitializeAsync()
{ {
try try
{ {
@ -27,97 +29,109 @@ public class FaqManagementPageViewModel(
if (token == null) if (token == null)
throw new Exception("Token is null"); throw new Exception("Token is null");
IsProcessing = true; IsProcessing = true;
var faqs = await restWrapper.FaqApiRest.GetFaqs(CurrentPage, token); PageDto.Faqs.Clear();
PageDto.Clear(); var typeName = typeof(FAQPage).FullName;
faqs.ForEach(f => PageDto.Add(f)); var dto = await _restWrapper.PageRestApi.ReadByType(typeName, token);
if (PageDto.Count % 20 == 0) if (!dto.Data.IsNullOrEmpty())
PageCount = CurrentPage + 2; {
PageDto = dto.GetData<FAQPage>();
_request = new PageActionRequestDto
{
Title = dto.Title,
Content = dto.Content,
Description = dto.Description,
Id = dto.Id,
IsCustomPage = dto.IsCustomPage,
IsHtmlBasePage = dto.IsHtmlBasePage,
Slug = dto.Slug,
Type = typeof(FAQPage).FullName
};
}
} }
catch (ApiException ex) catch (ApiException ex)
{ {
var exe = await ex.GetContentAsAsync<ApiResult>(); var exe = await ex.GetContentAsAsync<ApiResult>();
if (ex.StatusCode == HttpStatusCode.Unauthorized) _snackbar.Add(exe != null ? exe.Message : ex.Content, Severity.Error);
{
await userUtility.LogoutAsync();
navigationManager.NavigateTo("login", true, true);
}
snackbar.Add(exe != null ? exe.Message : ex.Content, Severity.Error);
} }
catch (Exception e) catch (Exception e)
{ {
snackbar.Add(e.Message, Severity.Error); _snackbar.Add(e.Message, Severity.Error);
} }
finally finally
{ {
IsProcessing = false; IsProcessing = false;
} }
await base.InitializeAsync();
} }
public async Task ChangePageAsync(int page) public async Task SaveAsync()
{ {
CurrentPage = page - 1; try
await GetEntitiesAsync(); {
} var token = await _userUtility.GetBearerTokenAsync();
if (token == null)
public async Task AddClicked() throw new Exception("Token is null");
{ IsProcessing = true;
DialogOptions maxWidth = new DialogOptions() var request = new PageActionRequestDto
{ MaxWidth = MaxWidth.Medium, FullWidth = true, DisableBackdropClick = true }; {
var reference = await dialogService.ShowAsync<FaqActionDialogBox>("افزودن سوالات متداول جدید", maxWidth); Title = "سوالات متداول",
var result = await reference.Result; Content = string.Empty,
if (result.Data is bool and true) Description = string.Empty,
await InitializeAsync(); Data = PageDto,
} IsCustomPage = true,
IsHtmlBasePage = false,
public async Task EditClicked(BaseFaq item) Slug = "faq",
{ Type = typeof(FAQPage).FullName
DialogOptions maxWidth = new DialogOptions() };
{ MaxWidth = MaxWidth.Medium, FullWidth = true, DisableBackdropClick = true }; if (_request != null)
var parameters = new DialogParameters<FaqActionDialogBox>(); {
parameters.Add(x => x.Faq, item); request = _request;
var reference = await dialogService.ShowAsync<FaqActionDialogBox>($"ویرایش سوالات متداول {item.Title}", parameters, maxWidth); }
var result = await reference.Result; request.Data = PageDto;
if (result.Data is bool and true) await _restWrapper.PageRestApi.CreatePage(request, token);
await InitializeAsync(); }
} catch (ApiException ex)
{
public async Task DeleteAsync(Guid selectedId) var exe = await ex.GetContentAsAsync<ApiResult>();
{ _snackbar.Add(exe != null ? exe.Message : ex.Content, Severity.Error);
var reference = await dialogService.ShowQuestionDialog($"آیا از حذف سوالات متداول مورد نظر اطمینان دارید ?"); }
var result = await reference.Result; catch (Exception e)
if (!result.Canceled) {
_snackbar.Add(e.Message, Severity.Error);
}
finally
{ {
try IsProcessing = false;
{
IsProcessing = true;
var token = await _userUtility.GetBearerTokenAsync();
if (token == null)
throw new Exception("Token is null");
await restWrapper.FaqApiRest.Delete(selectedId, token);
await InitializeAsync();
snackbar.Add("حذف سوالات متداول با موفقیت انجام شد", Severity.Success);
}
catch (ApiException ex)
{
var exe = await ex.GetContentAsAsync<ApiResult>();
snackbar.Add(exe != null ? exe.Message : ex.Content, Severity.Error);
}
catch (Exception e)
{
snackbar.Add(e.Message, Severity.Error);
}
finally
{
IsProcessing = false;
}
} }
} }
public void AddNewQuestion()
{
try
{
if (Question.IsNullOrEmpty())
throw new Exception("سوال را وارد کنید");
if (Answer.IsNullOrEmpty())
throw new Exception("پاسخ را وارد کنید");
PageDto.Faqs.Add(Question,Answer);
}
catch (Exception e)
{
_snackbar.Add(e.Message, Severity.Error);
}
}
public void RemoveQuestion(string question)
{
try
{
PageDto.Faqs.Remove(question);
}
catch (Exception e)
{
_snackbar.Add(e.Message, Severity.Error);
}
}
} }

View File

@ -8,72 +8,72 @@
@inject IUserUtility UserUtility @inject IUserUtility UserUtility
@inject IRestWrapper RestWrapper @inject IRestWrapper RestWrapper
<MudStack class="h-full w-full overflow-x-hidden px-0 md:p-5 lg:p-8"> <MudStack class="px-0 md:p-5 lg:p-8 w-full h-screen overflow-x-hidden overflow-y-scroll bg-[--mud-palette-background-grey]">
<MudHidden Breakpoint="Breakpoint.Xs"> <MudHidden Breakpoint="Breakpoint.Xs">
<MudGrid> <MudGrid>
<MudItem xs="12" sm="4" lg="2"> <MudItem xs="12" sm="4" lg="2">
<MudPaper class="m-2 rounded-md p-3" Elevation="2"> <MudPaper class="p-3 m-2 rounded-md" Elevation="2">
<MudText Typo="Typo.body1" class="mb-4">تعداد محصولاتــ</MudText> <MudText Typo="Typo.body1" class="mb-4">تعداد محصولاتــ</MudText>
<MudText Typo="Typo.h3" Align="Align.Center" class="text-amber-600"><b>@ViewModel.PageDto.ProductsCount</b></MudText> <MudText Typo="Typo.h3" Align="Align.Center" class="text-amber-600"><b>@ViewModel.PageDto.ProductsCount</b></MudText>
<MudText Typo="Typo.h6" Align="Align.Center" class="-mt-1 mb-4"><b>عدد</b></MudText> <MudText Typo="Typo.h6" Align="Align.Center" class="mb-4 -mt-1"><b>عدد</b></MudText>
</MudPaper> </MudPaper>
</MudItem> </MudItem>
<MudItem xs="12" sm="4" lg="2"> <MudItem xs="12" sm="4" lg="2">
<MudPaper class="m-2 rounded-md p-3" Elevation="2"> <MudPaper class="p-3 m-2 rounded-md" Elevation="2">
<MudText Typo="Typo.body1" class="mb-4">تعداد بلاگــ ها</MudText> <MudText Typo="Typo.body1" class="mb-4">تعداد بلاگــ ها</MudText>
<MudText Typo="Typo.h3" Align="Align.Center" class="text-blue-600"><b>@ViewModel.PageDto.BlogsCount</b></MudText> <MudText Typo="Typo.h3" Align="Align.Center" class="text-blue-600"><b>@ViewModel.PageDto.BlogsCount</b></MudText>
<MudText Typo="Typo.h6" Align="Align.Center" class="-mt-1 mb-4"><b>عدد</b></MudText> <MudText Typo="Typo.h6" Align="Align.Center" class="mb-4 -mt-1"><b>عدد</b></MudText>
</MudPaper> </MudPaper>
</MudItem> </MudItem>
<MudItem xs="12" sm="4" lg="2"> <MudItem xs="12" sm="4" lg="2">
<MudPaper class="m-2 rounded-md p-3" Elevation="2"> <MudPaper class="p-3 m-2 rounded-md" Elevation="2">
<MudText Typo="Typo.body1" class="mb-4">فروش های امروز</MudText> <MudText Typo="Typo.body1" class="mb-4">فروش های امروز</MudText>
<MudText Typo="Typo.h3" Align="Align.Center" class="text-lime-600"><b>@ViewModel.PageDto.TodayOrdersCount</b></MudText> <MudText Typo="Typo.h3" Align="Align.Center" class="text-lime-600"><b>@ViewModel.PageDto.TodayOrdersCount</b></MudText>
<MudText Typo="Typo.h6" Align="Align.Center" class="-mt-1 mb-4"><b>عدد</b></MudText> <MudText Typo="Typo.h6" Align="Align.Center" class="mb-4 -mt-1"><b>عدد</b></MudText>
</MudPaper> </MudPaper>
</MudItem> </MudItem>
<MudItem xs="12" sm="4" lg="2"> <MudItem xs="12" sm="4" lg="2">
<MudPaper class="m-2 rounded-md p-3" Elevation="2"> <MudPaper class="p-3 m-2 rounded-md" Elevation="2">
<MudText Typo="Typo.body1" class="mb-4">تایید نشده</MudText> <MudText Typo="Typo.body1" class="mb-4">تایید نشده</MudText>
<MudText Typo="Typo.h3" Align="Align.Center" class="text-rose-600"><b>@ViewModel.PageDto.UnSubmittedOrdersCount</b></MudText> <MudText Typo="Typo.h3" Align="Align.Center" class="text-rose-600"><b>@ViewModel.PageDto.UnSubmittedOrdersCount</b></MudText>
<MudText Typo="Typo.h6" Align="Align.Center" class="-mt-1 mb-4"><b>عدد</b></MudText> <MudText Typo="Typo.h6" Align="Align.Center" class="mb-4 -mt-1"><b>عدد</b></MudText>
</MudPaper> </MudPaper>
</MudItem> </MudItem>
<MudItem xs="12" sm="4" lg="2"> <MudItem xs="12" sm="4" lg="2">
<MudPaper class="m-2 rounded-md p-3" Elevation="2"> <MudPaper class="p-3 m-2 rounded-md" Elevation="2">
<MudText Typo="Typo.body1" class="mb-4">تعداد برنـــدها</MudText> <MudText Typo="Typo.body1" class="mb-4">تعداد برنـــدها</MudText>
<MudText Typo="Typo.h3" Align="Align.Center" class="text-gray-600"><b>@ViewModel.PageDto.BrandsCount</b></MudText> <MudText Typo="Typo.h3" Align="Align.Center" class="text-gray-600"><b>@ViewModel.PageDto.BrandsCount</b></MudText>
<MudText Typo="Typo.h6" Align="Align.Center" class="-mt-1 mb-4"><b>عدد</b></MudText> <MudText Typo="Typo.h6" Align="Align.Center" class="mb-4 -mt-1"><b>عدد</b></MudText>
</MudPaper> </MudPaper>
</MudItem> </MudItem>
<MudItem xs="12" sm="4" lg="2"> <MudItem xs="12" sm="4" lg="2">
<MudPaper class="m-2 rounded-md p-3" Elevation="2"> <MudPaper class="p-3 m-2 rounded-md" Elevation="2">
<MudText Typo="Typo.body1" class="mb-4">تعداد مشترکین</MudText> <MudText Typo="Typo.body1" class="mb-4">تعداد مشترکین</MudText>
<MudText Typo="Typo.h3" Align="Align.Center" class="text-purple-600"><b>@ViewModel.PageDto.SubscribersCount</b></MudText> <MudText Typo="Typo.h3" Align="Align.Center" class="text-purple-600"><b>@ViewModel.PageDto.SubscribersCount</b></MudText>
<MudText Typo="Typo.h6" Align="Align.Center" class="-mt-1 mb-4"><b>نفر</b></MudText> <MudText Typo="Typo.h6" Align="Align.Center" class="mb-4 -mt-1"><b>نفر</b></MudText>
</MudPaper> </MudPaper>
</MudItem> </MudItem>
</MudGrid> </MudGrid>
</MudHidden> </MudHidden>
<MudHidden Breakpoint="Breakpoint.SmAndUp"> <MudHidden Breakpoint="Breakpoint.SmAndUp">
<MudStack Row="true" class="no-scrollbar w-screen overflow-x-scroll whitespace-nowrap"> <MudStack Row="true" class="whitespace-nowrap overflow-x-scroll w-screen no-scrollbar">
<MudPaper class="m-2 w-fit rounded-md px-3 pb-5 pt-3" Elevation="2"> <MudPaper class="w-fit p-3 m-2 rounded-md" Elevation="2">
<MudText Typo="Typo.body1" class="mb-6 ml-16">تعداد محصولاتــ</MudText> <MudText Typo="Typo.body1" class="mb-6 ml-16">تعداد محصولاتــ</MudText>
<MudText Typo="Typo.h3" Align="Align.Center" class="text-amber-600"><b>1124</b></MudText> <MudText Typo="Typo.h3" Align="Align.Center" class="text-amber-600"><b>1124</b></MudText>
<MudText Typo="Typo.h6" Align="Align.Center" class="-mt-1"><b>عدد</b></MudText> <MudText Typo="Typo.h6" Align="Align.Center" class="mb-4 -mt-1"><b>عدد</b></MudText>
</MudPaper> </MudPaper>
<MudPaper class="m-2 w-fit rounded-md px-3 pb-5 pt-3" Elevation="2"> <MudPaper class="w-fit p-3 m-2 rounded-md" Elevation="2">
<MudText Typo="Typo.body1" class="mb-6 ml-16">تعداد محصولاتــ</MudText> <MudText Typo="Typo.body1" class="mb-6 ml-16">تعداد محصولاتــ</MudText>
<MudText Typo="Typo.h3" Align="Align.Center" class="text-amber-600"><b>1124</b></MudText> <MudText Typo="Typo.h3" Align="Align.Center" class="text-amber-600"><b>1124</b></MudText>
<MudText Typo="Typo.h6" Align="Align.Center" class="-mt-1"><b>عدد</b></MudText> <MudText Typo="Typo.h6" Align="Align.Center" class="mb-4 -mt-1"><b>عدد</b></MudText>
</MudPaper> </MudPaper>
<MudPaper class="m-2 w-fit rounded-md px-3 pb-5 pt-3" Elevation="2"> <MudPaper class="w-fit p-3 m-2 rounded-md" Elevation="2">
<MudText Typo="Typo.body1" class="mb-6 ml-16">تعداد محصولاتــ</MudText> <MudText Typo="Typo.body1" class="mb-6 ml-16">تعداد محصولاتــ</MudText>
<MudText Typo="Typo.h3" Align="Align.Center" class="text-amber-600"><b>1124</b></MudText> <MudText Typo="Typo.h3" Align="Align.Center" class="text-amber-600"><b>1124</b></MudText>
<MudText Typo="Typo.h6" Align="Align.Center" class="-mt-1"><b>عدد</b></MudText> <MudText Typo="Typo.h6" Align="Align.Center" class="mb-4 -mt-1"><b>عدد</b></MudText>
</MudPaper> </MudPaper>
</MudStack> </MudStack>
</MudHidden> </MudHidden>
@ -85,7 +85,7 @@
Icon="@Icons.Material.Outlined.AddCard" Icon="@Icons.Material.Outlined.AddCard"
Variant="Variant.Outlined" Color="Color.Default" Variant="Variant.Outlined" Color="Color.Default"
OnClickCallback="@ViewModel.AddProductClicked" OnClickCallback="@ViewModel.AddProductClicked"
Content="افزودن سریع محصولات" /> Content="محصول جدید" />
</MudStack> </MudStack>
</MudItem> </MudItem>
@ -96,7 +96,7 @@
Icon="@Icons.Material.Outlined.AddLink" Icon="@Icons.Material.Outlined.AddLink"
Variant="Variant.Outlined" Color="Color.Default" Variant="Variant.Outlined" Color="Color.Default"
OnClickCallback="@ViewModel.AddBlogClicked" OnClickCallback="@ViewModel.AddBlogClicked"
Content="دسته بندی های محصولات" /> Content="بلاگ جدید" />
</MudStack> </MudStack>
</MudItem> </MudItem>
@ -143,7 +143,7 @@
<PagerContent> <PagerContent>
<MudStack Row="true" class="w-full"> <MudStack Row="true" class="w-full">
<MudPagination Rectangular="true" Variant="Variant.Filled" class="mx-auto my-4" /> <MudPagination Rectangular="true" Variant="Variant.Filled" class="my-4 mx-auto" />
</MudStack> </MudStack>
</PagerContent> </PagerContent>

View File

@ -7,19 +7,19 @@
@inject IUserUtility UserUtility @inject IUserUtility UserUtility
@inject IRestWrapper RestWrapper @inject IRestWrapper RestWrapper
<MudStack class="h-full w-full p-8"> <MudStack class="w-full p-8 h-screen bg-[--mud-palette-background-grey]">
<MudGrid> <MudGrid>
<MudItem xs="12"> <MudItem xs="12">
<MudPaper class="px-5 py-5"> <MudPaper class="px-5 py-5">
<MudStack Row="true"> <MudStack Row="true">
<MudStack class="mx-2 mb-5"> <MudStack class="mb-5 mx-2">
<MudText Typo="Typo.h4">jتنظیماتـــ بازاریاب ها</MudText> <MudText Typo="Typo.h4">jتنظیماتـــ بازاریاب ها</MudText>
<MudText Typo="Typo.caption">شما می توانید تنظیمات بازاریاب های خود را ویرایش نمایید</MudText> <MudText Typo="Typo.caption">شما می توانید تنظیمات بازاریاب های خود را ویرایش نمایید</MudText>
</MudStack> </MudStack>
<MudSpacer /> <MudSpacer />
<BaseButtonUi Size="Size.Large" <BaseButtonUi Size="Size.Large"
OnClickCallback="ViewModel.SubmitSettingAsync" OnClickCallback="ViewModel.SubmitSettingAsync"
class="mb-8 mt-2 w-64 rounded-md" class="mt-2 mb-8 w-64 rounded-md"
IsProcessing="@ViewModel.IsProcessing" IsProcessing="@ViewModel.IsProcessing"
Icon="@Icons.Material.Outlined.Check" Icon="@Icons.Material.Outlined.Check"
Content="ثبتـــ اطلاعات" Variant="Variant.Filled" Color="Color.Success" /> Content="ثبتـــ اطلاعات" Variant="Variant.Filled" Color="Color.Success" />

View File

@ -6,7 +6,7 @@
@inject IUserUtility UserUtility @inject IUserUtility UserUtility
@inject IRestWrapper RestWrapper @inject IRestWrapper RestWrapper
<MudStack class="h-full w-full p-8"> <MudStack class="w-full p-8 h-screen bg-[--mud-palette-background-grey]">
<MudGrid> <MudGrid>
<MudItem xs="12"> <MudItem xs="12">
<MudStack Row="true" class="mb-5"> <MudStack Row="true" class="mb-5">
@ -27,7 +27,7 @@
<MudStack Row="true" class="w-full"> <MudStack Row="true" class="w-full">
<MudPagination Rectangular="true" Variant="Variant.Filled" Count="@ViewModel.PageCount" <MudPagination Rectangular="true" Variant="Variant.Filled" Count="@ViewModel.PageCount"
SelectedChanged="@ViewModel.ChangePageAsync" class="mx-auto my-4" /> SelectedChanged="@ViewModel.ChangePageAsync" class="my-4 mx-auto" />
</MudStack> </MudStack>
</PagerContent> </PagerContent>

View File

@ -3,12 +3,12 @@
@page "/notfound" @page "/notfound"
@inject NavigationManager NavigationManager @inject NavigationManager NavigationManager
<div class="h-full w-screen overflow-hidden p-0"> <div class="w-screen h-screen p-0 overflow-hidden bg-[--mud-palette-background]">
<div class="w-fulll h-full"> <div class="h-full w-fulll">
<MudStack class="mx-auto my-auto"> <MudStack class="mx-auto my-auto">
<dotlottie-player src="https://lottie.host/4b415b83-5315-4e7f-b174-d036d9f8612f/4qKuHHyOxk.json" <dotlottie-player src="https://lottie.host/4b415b83-5315-4e7f-b174-d036d9f8612f/4qKuHHyOxk.json"
background="transparent" speed="1" class="mx-auto h-96 w-96 lg:w-[38rem] lg:h-[38rem]" loop autoplay /> background="transparent" speed="1" class="mx-auto w-96 h-96 lg:w-[38rem] lg:h-[38rem]" loop autoplay />
<MudText Typo="Typo.h2" Align="Align.Center"><b>صفحه مورد نظر پیدا نشد</b></MudText> <MudText Typo="Typo.h2" Align="Align.Center"><b>صفحه مورد نظر پیدا نشد</b></MudText>
<MudText Typo="Typo.h5" Align="Align.Center">صفحه مورد نظر شما پیدا نشد یا از بین رفته است ، سریع کام بک بزن به جای قبلی جیگر </MudText> <MudText Typo="Typo.h5" Align="Align.Center">صفحه مورد نظر شما پیدا نشد یا از بین رفته است ، سریع کام بک بزن به جای قبلی جیگر </MudText>
@ -17,7 +17,7 @@
Icon="@Icons.Material.Outlined.Login" Icon="@Icons.Material.Outlined.Login"
OnClickCallback="NavigateToHomeAsync" OnClickCallback="NavigateToHomeAsync"
Color="Color.Default" Color="Color.Default"
class="mx-auto mt-6 w-64 rounded-full" class="w-64 rounded-full mt-6 mx-auto"
Content="کام بکــــ"></BaseButtonUi> Content="کام بکــــ"></BaseButtonUi>
</MudStack> </MudStack>

View File

@ -8,7 +8,7 @@
@inject IRestWrapper RestWrapper @inject IRestWrapper RestWrapper
@inject IBrowserViewportService BrowserViewportService @inject IBrowserViewportService BrowserViewportService
<MudStack class="h-full w-full overflow-x-hidden overflow-y-scroll md:p-5 lg:px-8"> <MudStack class="bg-[--mud-palette-background-grey] h-screen w-full overflow-x-hidden overflow-y-scroll md:p-5 lg:px-8">
<MudHidden Breakpoint="Breakpoint.Xs"> <MudHidden Breakpoint="Breakpoint.Xs">
<MudGrid> <MudGrid>
@ -108,7 +108,7 @@
</MudItem> </MudItem>
</MudGrid> </MudGrid>
</MudHidden> </MudHidden>
<MudPaper> <MudPaper >
<MudDataGrid FixedFooter="true" FixedHeader="true" Striped="true" <MudDataGrid FixedFooter="true" FixedHeader="true" Striped="true"
T="OrderSDto" Items="@ViewModel.MainOrders" CurrentPage="@ViewModel.MainGridCurrentPage" T="OrderSDto" Items="@ViewModel.MainOrders" CurrentPage="@ViewModel.MainGridCurrentPage"
RowsPerPage="20" Filterable="false" Loading="@ViewModel.IsProcessing" RowsPerPage="20" Filterable="false" Loading="@ViewModel.IsProcessing"
@ -116,7 +116,7 @@
<ToolBarContent> <ToolBarContent>
<MudGrid class="collapse md:visible"> <MudGrid class="collapse md:visible">
<MudItem md="5"> <MudItem md="6">
<MudTextField T="string" Placeholder="جست جو بر اساس کد فاکتور" OnClearButtonClick="@ViewModel.SearchAsync" <MudTextField T="string" Placeholder="جست جو بر اساس کد فاکتور" OnClearButtonClick="@ViewModel.SearchAsync"
Adornment="Adornment.Start" Adornment="Adornment.Start"
Immediate="true" Immediate="true"
@ -127,12 +127,12 @@
@bind-Value="@ViewModel.FactorCodeSearch" @bind-Value="@ViewModel.FactorCodeSearch"
OnAdornmentClick="@ViewModel.SearchAsync"></MudTextField> OnAdornmentClick="@ViewModel.SearchAsync"></MudTextField>
</MudItem> </MudItem>
<MudItem md="5"> <MudItem md="6">
<MudAutocomplete ToStringFunc="arg => arg.Title" ValueChanged="@ViewModel.SearchByOrderStatusAsync" <MudAutocomplete ToStringFunc="arg => arg.Title" ValueChanged="@ViewModel.SearchByOrderStatusAsync"
Value="@ViewModel.OrderStatusSearch" Value="@ViewModel.OrderStatusSearch"
SearchFunc="@ViewModel.OrderStatusSearchAsync" SearchFunc="@ViewModel.OrderStatusSearchAsync"
T="FilterOptionDto<OrderStatus>" T="FilterOptionDto<OrderStatus>"
class="my-auto" class="-mt-0.5"
OnClearButtonClick="async () => await ViewModel.SearchByOrderStatusAsync(null)" OnClearButtonClick="async () => await ViewModel.SearchByOrderStatusAsync(null)"
Clearable="true" Clearable="true"
Label="وظعیت سفارش"> Label="وظعیت سفارش">
@ -144,9 +144,6 @@
</ItemTemplate> </ItemTemplate>
</MudAutocomplete> </MudAutocomplete>
</MudItem> </MudItem>
<MudItem md="2">
<MudSwitch class="mt-4" T="bool" Value="@ViewModel.ShowOrderBags" ValueChanged="async (flag) => await ViewModel.ChangeShowOrderBagsAsync(flag) " Label="نمایش سبد خرید ها" Color="Color.Info" />
</MudItem>
</MudGrid> </MudGrid>
</ToolBarContent> </ToolBarContent>
<Columns> <Columns>

View File

@ -85,14 +85,10 @@ public class OrdersPageViewModel : BaseViewModel<OrderDashboardDto>
throw new Exception("Token is null"); throw new Exception("Token is null");
var dto = await _restWrapper.OrderRestApi.ReadAll(MainGridCurrentPage, token, var dto = await _restWrapper.OrderRestApi.ReadAll(MainGridCurrentPage, FactorCodeSearch, null,
FactorCodeSearch, OrderStatusSearch?.Value, null, token);
null,
OrderStatusSearch?.Value,
null,
ShowOrderBags == false ? null : true);
dto.ForEach(d => MainOrders.Add(d)); dto.ForEach(d => MainOrders.Add(d));
if (MainOrders.Count % 15 == 0) if (MainOrders.Count == 15)
MainGridPageCount = MainGridCurrentPage + 2; MainGridPageCount = MainGridCurrentPage + 2;
} }
@ -132,8 +128,6 @@ public class OrdersPageViewModel : BaseViewModel<OrderDashboardDto>
} }
public string? FactorCodeSearch { get; set; } = null; public string? FactorCodeSearch { get; set; } = null;
public bool ShowOrderBags { get; set; } = false;
public async Task SearchAsync() public async Task SearchAsync()
{ {
try try
@ -145,12 +139,8 @@ public class OrdersPageViewModel : BaseViewModel<OrderDashboardDto>
MainOrders.Clear(); MainOrders.Clear();
List<OrderSDto> dto; List<OrderSDto> dto;
dto = await _restWrapper.OrderRestApi.ReadAll(MainGridCurrentPage, token, dto = await _restWrapper.OrderRestApi.ReadAll(MainGridCurrentPage, FactorCodeSearch, null,
FactorCodeSearch, OrderStatusSearch?.Value, null, token);
null,
OrderStatusSearch?.Value,
null,
ShowOrderBags == false ? null : true);
dto.ForEach(d => MainOrders.Add(d)); dto.ForEach(d => MainOrders.Add(d));
if (MainOrders.Count == 15) if (MainOrders.Count == 15)
@ -197,15 +187,10 @@ public class OrdersPageViewModel : BaseViewModel<OrderDashboardDto>
return OrderStatusFilterOptions; return OrderStatusFilterOptions;
return OrderStatusFilterOptions.Where(o => o.Title == orderStatus).ToList(); return OrderStatusFilterOptions.Where(o => o.Title == orderStatus).ToList();
} }
public async Task SearchByOrderStatusAsync(FilterOptionDto<OrderStatus>? arg) public async Task SearchByOrderStatusAsync(FilterOptionDto<OrderStatus>? arg)
{ {
OrderStatusSearch = arg; OrderStatusSearch = arg;
await SearchAsync(); await SearchAsync();
} }
public async Task ChangeShowOrderBagsAsync(bool? arg)
{
ShowOrderBags = arg ?? false;
await SearchAsync();
}
} }

View File

@ -7,11 +7,11 @@
@inject IUserUtility UserUtility @inject IUserUtility UserUtility
@inject IRestWrapper RestWrapper @inject IRestWrapper RestWrapper
<MudStack class="h-full w-full p-8"> <MudStack class="w-full p-8 h-screen bg-[--mud-palette-background-grey]">
<MudPaper class="px-5 py-5"> <MudPaper class="px-5 py-5">
<MudStack> <MudStack>
<MudStack Row="true"> <MudStack Row="true">
<MudStack class="mx-2 mb-5"> <MudStack class="mb-5 mx-2">
<MudText Typo="Typo.h4">تنظیمات برگه ها</MudText> <MudText Typo="Typo.h4">تنظیمات برگه ها</MudText>
<MudText Typo="Typo.caption">برگه های وب سایت خود را ویرایش نمایید</MudText> <MudText Typo="Typo.caption">برگه های وب سایت خود را ویرایش نمایید</MudText>
</MudStack> </MudStack>
@ -19,7 +19,7 @@
<MudSpacer /> <MudSpacer />
@* <BaseButtonUi Size="Size.Large" @* <BaseButtonUi Size="Size.Large"
OnClickCallback="ViewModel.SubmitPagesSettingAsync" OnClickCallback="ViewModel.SubmitPagesSettingAsync"
class="mb-8 mt-2 w-64 rounded-md" class="mt-2 mb-8 w-64 rounded-md"
IsProcessing="@ViewModel.IsProcessing" IsProcessing="@ViewModel.IsProcessing"
Icon="@Icons.Material.Outlined.Check" Icon="@Icons.Material.Outlined.Check"
Content="ثبتـــ اطلاعات" Variant="Variant.Filled" Color="Color.Success" /> *@ Content="ثبتـــ اطلاعات" Variant="Variant.Filled" Color="Color.Success" /> *@
@ -28,13 +28,13 @@
<MudItem xs="6"> <MudItem xs="6">
<MudDivider /> <MudDivider />
<MudText class="mb-5 mt-4" Typo="Typo.h6">افزودن برگه جدید</MudText> <MudText class="mt-4 mb-5" Typo="Typo.h6">افزودن برگه جدید</MudText>
<MudTextField @bind-Value="@ViewModel.NewPageDto.Title" T="string" Label="عنوان" Variant="Variant.Outlined" /> <MudTextField @bind-Value="@ViewModel.NewPageDto.Title" T="string" Label="عنوان" Variant="Variant.Outlined" />
<MudTextField class="my-3" @bind-Value="@ViewModel.NewPageDto.Slug" T="string" Label="اسلاگ" Variant="Variant.Outlined" /> <MudTextField class="my-3" @bind-Value="@ViewModel.NewPageDto.Slug" T="string" Label="اسلاگ" Variant="Variant.Outlined" />
<MudButton class="mt-1 w-full py-3" Variant="Variant.Outlined" Color="Color.Secondary" OnClick="ViewModel.AddPageAsync">افزودن +</MudButton> <MudButton class="w-full py-3 mt-1" Variant="Variant.Outlined" Color="Color.Secondary" OnClick="ViewModel.AddPageAsync">افزودن +</MudButton>
</MudItem> </MudItem>
<MudItem xs="6"> <MudItem xs="6">
@ -46,10 +46,6 @@
<MudStack Row="true"> <MudStack Row="true">
<MudText class="my-auto">@navMenuItem.Title</MudText> <MudText class="my-auto">@navMenuItem.Title</MudText>
<MudSpacer /> <MudSpacer />
<MudIconButton Icon="@Icons.Material.Filled.Edit"
OnClick="async ()=>{await ViewModel.EditPageAsync(navMenuItem);}"
Color="Color.Info"></MudIconButton>
<MudIconButton Icon="@Icons.Material.Filled.Delete" OnClick="async ()=>{await ViewModel.RemovePageAsync(navMenuItem.Id);}" Color="Color.Error"></MudIconButton> <MudIconButton Icon="@Icons.Material.Filled.Delete" OnClick="async ()=>{await ViewModel.RemovePageAsync(navMenuItem.Id);}" Color="Color.Error"></MudIconButton>
</MudStack> </MudStack>
</TitleContent> </TitleContent>

View File

@ -2,16 +2,27 @@
namespace Netina.AdminPanel.PWA.Pages; namespace Netina.AdminPanel.PWA.Pages;
public class PagesManagementPageViewModel( public class PagesManagementPageViewModel : BaseViewModel<ObservableCollection<BasePageSDto>>
NavigationManager navigationManager,
ISnackbar snackbar,
IUserUtility userUtility,
IRestWrapper restWrapper,
IDialogService dialogService)
: BaseViewModel<ObservableCollection<BasePageSDto>>(userUtility)
{ {
private readonly IUserUtility _userUtility = userUtility; private readonly NavigationManager _navigationManager;
private readonly IDialogService _dialogService = dialogService; private readonly ISnackbar _snackbar;
private readonly IUserUtility _userUtility;
private readonly IDialogService _dialogService;
private readonly IRestWrapper _restWrapper;
public PagesManagementPageViewModel(
NavigationManager navigationManager,
ISnackbar snackbar,
IUserUtility userUtility,
IRestWrapper restWrapper,
IDialogService dialogService) : base(userUtility)
{
_navigationManager = navigationManager;
_snackbar = snackbar;
_userUtility = userUtility;
_restWrapper = restWrapper;
_dialogService = dialogService;
}
public override async Task InitializeAsync() public override async Task InitializeAsync()
{ {
@ -21,7 +32,7 @@ public class PagesManagementPageViewModel(
var token = await _userUtility.GetBearerTokenAsync(); var token = await _userUtility.GetBearerTokenAsync();
if (token == null) if (token == null)
throw new Exception("Token is null"); throw new Exception("Token is null");
var pages = await restWrapper.PageRestApi.ReadAll(token); var pages = await _restWrapper.PageRestApi.ReadAll(token);
PageDto.Clear(); PageDto.Clear();
pages.ForEach(p=>PageDto.Add(p)); pages.ForEach(p=>PageDto.Add(p));
} }
@ -31,13 +42,13 @@ public class PagesManagementPageViewModel(
if (e.StatusCode == HttpStatusCode.Unauthorized) if (e.StatusCode == HttpStatusCode.Unauthorized)
{ {
await _userUtility.LogoutAsync(); await _userUtility.LogoutAsync();
navigationManager.NavigateTo("login", true, true); _navigationManager.NavigateTo("login", true, true);
} }
snackbar.Add(exe != null ? exe.Message : e.Content, Severity.Error); _snackbar.Add(exe != null ? exe.Message : e.Content, Severity.Error);
} }
catch (Exception ex) catch (Exception ex)
{ {
snackbar.Add(ex.Message, Severity.Error); _snackbar.Add(ex.Message, Severity.Error);
} }
finally finally
{ {
@ -63,9 +74,9 @@ public class PagesManagementPageViewModel(
if (NewPageDto.Slug.IsNullOrEmpty()) if (NewPageDto.Slug.IsNullOrEmpty())
throw new AppException("اسلاگ صفحه را وارد کنید"); throw new AppException("اسلاگ صفحه را وارد کنید");
await restWrapper.PageRestApi.CreatePage(NewPageDto.DeepClone(), token); await _restWrapper.PageRestApi.CreatePage(NewPageDto.DeepClone(), token);
NewPageDto = new PageActionRequestDto(); NewPageDto = new PageActionRequestDto();
snackbar.Add("برگه مورد نظر با موفقیت افزوده شد", Severity.Success); _snackbar.Add("برگه مورد نظر با موفقیت افزوده شد", Severity.Success);
await InitializeAsync(); await InitializeAsync();
} }
@ -75,13 +86,13 @@ public class PagesManagementPageViewModel(
if (e.StatusCode == HttpStatusCode.Unauthorized) if (e.StatusCode == HttpStatusCode.Unauthorized)
{ {
await _userUtility.LogoutAsync(); await _userUtility.LogoutAsync();
navigationManager.NavigateTo("login", true, true); _navigationManager.NavigateTo("login", true, true);
} }
snackbar.Add(exe != null ? exe.Message : e.Content, Severity.Error); _snackbar.Add(exe != null ? exe.Message : e.Content, Severity.Error);
} }
catch (Exception ex) catch (Exception ex)
{ {
snackbar.Add(ex.Message, Severity.Error); _snackbar.Add(ex.Message, Severity.Error);
} }
finally finally
{ {
@ -89,19 +100,6 @@ public class PagesManagementPageViewModel(
} }
} }
public async Task EditPageAsync(BasePageSDto page)
{
DialogOptions maxWidth = new DialogOptions() { MaxWidth = MaxWidth.Medium, FullWidth = true, DisableBackdropClick = true };
var parameters = new DialogParameters<PageActionDialogBox>();
parameters.Add(x => x.Page, page);
var dialogResult = await dialogService.ShowAsync<PageActionDialogBox>($"ویرایش صفحه {page.Title}", parameters, maxWidth);
var result = await dialogResult.Result;
if (!result.Canceled && result.Data is bool and true)
{
await InitializeAsync();
}
}
public async Task RemovePageAsync(Guid pageId) public async Task RemovePageAsync(Guid pageId)
{ {
try try
@ -111,8 +109,8 @@ public class PagesManagementPageViewModel(
if (token == null) if (token == null)
throw new Exception("Token is null"); throw new Exception("Token is null");
await restWrapper.PageRestApi.DeletePage(pageId, token); await _restWrapper.PageRestApi.DeletePage(pageId, token);
snackbar.Add("برگه مورد نظر با موفقیت حذف شد", Severity.Success); _snackbar.Add("برگه مورد نظر با موفقیت حذف شد", Severity.Success);
await InitializeAsync(); await InitializeAsync();
@ -123,13 +121,13 @@ public class PagesManagementPageViewModel(
if (e.StatusCode == HttpStatusCode.Unauthorized) if (e.StatusCode == HttpStatusCode.Unauthorized)
{ {
await _userUtility.LogoutAsync(); await _userUtility.LogoutAsync();
navigationManager.NavigateTo("login", true, true); _navigationManager.NavigateTo("login", true, true);
} }
snackbar.Add(exe != null ? exe.Message : e.Content, Severity.Error); _snackbar.Add(exe != null ? exe.Message : e.Content, Severity.Error);
} }
catch (Exception ex) catch (Exception ex)
{ {
snackbar.Add(ex.Message, Severity.Error); _snackbar.Add(ex.Message, Severity.Error);
} }
finally finally
{ {

View File

@ -1,131 +0,0 @@
@page "/setting/pages"
@attribute [Microsoft.AspNetCore.Authorization.Authorize]
@inject IDialogService DialogService
@inject NavigationManager NavigationManager
@inject ISnackbar Snackbar
@inject IUserUtility UserUtility
@inject IRestWrapper RestWrapper
<MudStack class="h-full w-full p-8">
<MudStack class="mx-2 mb-5">
<MudText Typo="Typo.h4">تنظیمات برگه ها</MudText>
<MudText Typo="Typo.caption">برگه های وب سایت خود را ویرایش نمایید</MudText>
</MudStack>
<MudPaper class="px-5 py-5">
<MudStack>
<MudGrid>
<MudItem xs="12">
<MudText class="mb-5 mt-4" Typo="Typo.h6">افزودن لینک حذف شده</MudText>
<MudGrid>
<MudItem xs="10">
<MudTextField @bind-Value="@ViewModel.NewDeletedPage.Url" T="string" Label="لینک" Variant="Variant.Outlined" />
</MudItem>
<MudItem xs="2">
<MudButton class="mt-1 w-full py-3" Variant="Variant.Outlined" Color="Color.Secondary" OnClick="ViewModel.AddDeletedPage">افزودن +</MudButton>
</MudItem>
</MudGrid>
</MudItem>
<MudItem xs="12">
<MudDataGrid FixedFooter="true" FixedHeader="true" Striped="true"
T="DeletedPageItem" Items="@ViewModel.DeletedPages" CurrentPage="@ViewModel.DeletedPagesCurrentPage"
RowsPerPage="20" Filterable="false" Loading="@ViewModel.IsProcessing"
SortMode="@SortMode.None" Groupable="false">
<Columns>
<PropertyColumn Title="لینک حذف شده" Property="arg => arg.Url" />
<TemplateColumn CellClass="d-flex justify-end">
<CellTemplate>
<MudStack Row="true">
<MudIconButton Icon="@Icons.Material.Filled.Delete"
Size="@Size.Small"
Variant="@Variant.Outlined"
OnClick="async () => await ViewModel.RemoveDeletedPageAsync(context.Item)"
Color="@Color.Error" />
</MudStack>
</CellTemplate>
</TemplateColumn>
</Columns>
<PagerContent>
<MudStack Row="true" class="w-full">
<MudPagination Rectangular="true" Variant="Variant.Filled" Count="@ViewModel.DeletedPagesCount"
SelectedChanged="@ViewModel.DeletedPagesChangePageAsync" class="mx-auto my-4" />
</MudStack>
</PagerContent>
</MudDataGrid>
</MudItem>
</MudGrid>
</MudStack>
</MudPaper>
<MudPaper class="px-5 py-5">
<MudStack>
<MudGrid>
<MudItem xs="12">
<MudText class="mb-5 mt-4" Typo="Typo.h6">افزودن ریدایرکت جدید</MudText>
<MudGrid>
<MudItem xs="5">
<MudTextField @bind-Value="@ViewModel.NewRedirectItem.OldUrl" T="string" Label="لینک قدیمی" Variant="Variant.Outlined" />
</MudItem>
<MudItem xs="5">
<MudTextField @bind-Value="@ViewModel.NewRedirectItem.NewUrl" T="string" Label="لینک جدید" Variant="Variant.Outlined" />
</MudItem>
<MudItem xs="2">
<MudButton class="mt-1 w-full py-3" Variant="Variant.Outlined" Color="Color.Secondary" OnClick="ViewModel.AddPageAsync">افزودن +</MudButton>
</MudItem>
</MudGrid>
</MudItem>
<MudItem xs="12">
<MudDataGrid FixedFooter="true" FixedHeader="true" Striped="true"
T="RedirectItem" Items="@ViewModel.RedirectItems" CurrentPage="@ViewModel.RedirectItemsCurrentPage"
RowsPerPage="20" Filterable="false" Loading="@ViewModel.IsProcessing"
SortMode="@SortMode.None" Groupable="false">
<Columns>
<PropertyColumn Title="لینک قدیمی" Property="arg => arg.OldUrl" />
<PropertyColumn Title="لینک جدید" Property="arg => arg.NewUrl" />
<TemplateColumn CellClass="d-flex justify-end">
<CellTemplate>
<MudStack Row="true">
<MudIconButton Icon="@Icons.Material.Filled.Delete"
Size="@Size.Small"
Variant="@Variant.Outlined"
OnClick="async () => await ViewModel.RemovePageAsync(context.Item)"
Color="@Color.Error" />
</MudStack>
</CellTemplate>
</TemplateColumn>
</Columns>
<PagerContent>
<MudStack Row="true" class="w-full">
<MudPagination Rectangular="true" Variant="Variant.Filled" Count="@ViewModel.RedirectItemPageCount"
SelectedChanged="@ViewModel.RedirectItemChangePageAsync" class="mx-auto my-4" />
</MudStack>
</PagerContent>
</MudDataGrid>
</MudItem>
</MudGrid>
</MudStack>
</MudPaper>
</MudStack>
@code
{
public PagesSettingPageViewModel ViewModel { get; set; }
protected override async Task OnInitializedAsync()
{
ViewModel = new PagesSettingPageViewModel(NavigationManager, Snackbar, UserUtility, RestWrapper, DialogService);
await ViewModel.InitializeAsync();
await base.OnInitializedAsync();
}
}

View File

@ -1,244 +0,0 @@
namespace Netina.AdminPanel.PWA.Pages;
public class PagesSettingPageViewModel(NavigationManager navigationManager,
ISnackbar snackbar,
IUserUtility userUtility,
IRestWrapper restWrapper,
IDialogService dialogService) : BaseViewModel<PageSetting> (userUtility)
{
public ObservableCollection<RedirectItem> RedirectItems { get; set; } = new ObservableCollection<RedirectItem> ();
public ObservableCollection<DeletedPageItem> DeletedPages { get; set; } = new ObservableCollection<DeletedPageItem> ();
public override async Task InitializeAsync()
{
try
{
IsProcessing = true;
var token = await _userUtility.GetBearerTokenAsync();
if (token == null)
throw new Exception("Token is null");
var pages = await restWrapper.SettingRestApi.GetSettingAsync<PageSetting>(nameof(PageSetting), token);
PageDto = pages;
RedirectItems.Clear();
if (PageDto.RedirectItems.Count > 20)
RedirectItemPageCount = RedirectItemsCurrentPage + 2;
PageDto.RedirectItems.Skip(RedirectItemsCurrentPage * 20).Take(20).ToList().ForEach(a=>RedirectItems.Add(a));
DeletedPages.Clear();
if (PageDto.DeletedPages.Count > 20)
DeletedPagesCount = DeletedPagesCurrentPage + 2;
PageDto.DeletedPages.Skip(DeletedPagesCurrentPage * 20).Take(20).ToList().ForEach(a => DeletedPages.Add(a));
}
catch (ApiException e)
{
var exe = await e.GetContentAsAsync<ApiResult>();
if (e.StatusCode == HttpStatusCode.Unauthorized)
{
await _userUtility.LogoutAsync();
navigationManager.NavigateTo("login", true, true);
}
snackbar.Add(exe != null ? exe.Message : e.Content, Severity.Error);
}
catch (Exception ex)
{
snackbar.Add(ex.Message, Severity.Error);
}
finally
{
IsProcessing = false;
}
await base.InitializeAsync();
}
public int RedirectItemsCurrentPage { get; set; } = 0;
public int RedirectItemPageCount { get; set; } = 0;
public void RedirectItemChangePageAsync(int page)
{
RedirectItemsCurrentPage = page - 1;
if (PageDto.RedirectItems.Count > (RedirectItemsCurrentPage * 20))
RedirectItemPageCount = RedirectItemsCurrentPage + 2;
PageDto.RedirectItems.Skip(RedirectItemsCurrentPage * 20).Take(20).ToList().ForEach(a => RedirectItems.Add(a));
}
public RedirectItem NewRedirectItem { get; set; } = new();
public async Task AddPageAsync()
{
try
{
IsProcessing = true;
var token = await _userUtility.GetBearerTokenAsync();
if (token == null)
throw new Exception("Token is null");
if (NewRedirectItem.OldUrl.IsNullOrEmpty())
throw new AppException("لینک قدیمی را وارد کنید");
if (NewRedirectItem.NewUrl.IsNullOrEmpty())
throw new AppException("لینک جدید را وارد کنید");
var newUrl = StringExtensions.GetSlug(NewRedirectItem.NewUrl);
var oldUrl = StringExtensions.GetSlug(NewRedirectItem.OldUrl);
var item = new RedirectItem
{
NewUrl = newUrl,
OldUrl = oldUrl
};
if (PageDto.RedirectItems.Any(c => c.OldUrl == item.OldUrl))
throw new AppException("لینک مورد نظر قبلا اضافه شده است");
PageDto.RedirectItems.Add(item);
await restWrapper.SettingRestApi.PostSettingAsync(nameof(PageSetting), PageDto, token);
NewRedirectItem = new RedirectItem();
snackbar.Add("لینک ریدایرکت با موفقیت افزوده شد", Severity.Success);
await InitializeAsync();
}
catch (ApiException e)
{
var exe = await e.GetContentAsAsync<ApiResult>();
if (e.StatusCode == HttpStatusCode.Unauthorized)
{
await _userUtility.LogoutAsync();
navigationManager.NavigateTo("login", true, true);
}
snackbar.Add(exe != null ? exe.Message : e.Content, Severity.Error);
}
catch (Exception ex)
{
snackbar.Add(ex.Message, Severity.Error);
}
finally
{
IsProcessing = false;
}
}
public async Task RemovePageAsync(RedirectItem item)
{
try
{
IsProcessing = true;
var token = await _userUtility.GetBearerTokenAsync();
if (token == null)
throw new Exception("Token is null");
PageDto.RedirectItems.Remove(item);
await restWrapper.SettingRestApi.PostSettingAsync(nameof(PageSetting), PageDto, token);
snackbar.Add("لینک ریدایرکت مورد نظر با موفقیت حذف شد", Severity.Success);
await InitializeAsync();
}
catch (ApiException e)
{
var exe = await e.GetContentAsAsync<ApiResult>();
if (e.StatusCode == HttpStatusCode.Unauthorized)
{
await _userUtility.LogoutAsync();
navigationManager.NavigateTo("login", true, true);
}
snackbar.Add(exe != null ? exe.Message : e.Content, Severity.Error);
}
catch (Exception ex)
{
snackbar.Add(ex.Message, Severity.Error);
}
finally
{
IsProcessing = false;
}
}
public DeletedPageItem NewDeletedPage { get; set; } = new();
public async Task AddDeletedPage()
{
try
{
IsProcessing = true;
var token = await _userUtility.GetBearerTokenAsync();
if (token == null)
throw new Exception("Token is null");
if (NewDeletedPage.Url.IsNullOrEmpty())
throw new AppException("لینک حذف شده را وارد کنید");
var item = new DeletedPageItem()
{
Url = NewDeletedPage.Url
};
if (PageDto.DeletedPages.Any(c => c.Url == item.Url))
throw new AppException("لینک مورد نظر قبلا اضافه شده است");
PageDto.DeletedPages.Add(NewDeletedPage);
DeletedPages.Add(NewDeletedPage);
await restWrapper.SettingRestApi.PostSettingAsync(nameof(PageSetting), PageDto, token);
NewRedirectItem = new RedirectItem();
snackbar.Add("لینک حذف با موفقیت افزوده شد", Severity.Success);
await InitializeAsync();
}
catch (ApiException e)
{
var exe = await e.GetContentAsAsync<ApiResult>();
if (e.StatusCode == HttpStatusCode.Unauthorized)
{
await _userUtility.LogoutAsync();
navigationManager.NavigateTo("login", true, true);
}
snackbar.Add(exe != null ? exe.Message : e.Content, Severity.Error);
}
catch (Exception ex)
{
snackbar.Add(ex.Message, Severity.Error);
}
finally
{
IsProcessing = false;
}
}
public async Task RemoveDeletedPageAsync(DeletedPageItem item)
{
try
{
IsProcessing = true;
var token = await _userUtility.GetBearerTokenAsync();
if (token == null)
throw new Exception("Token is null");
PageDto.DeletedPages.Remove(item);
await restWrapper.SettingRestApi.PostSettingAsync(nameof(PageSetting), PageDto, token);
snackbar.Add("لینک مورد نظر با موفقیت حذف شد", Severity.Success);
await InitializeAsync();
}
catch (ApiException e)
{
var exe = await e.GetContentAsAsync<ApiResult>();
if (e.StatusCode == HttpStatusCode.Unauthorized)
{
await _userUtility.LogoutAsync();
navigationManager.NavigateTo("login", true, true);
}
snackbar.Add(exe != null ? exe.Message : e.Content, Severity.Error);
}
catch (Exception ex)
{
snackbar.Add(ex.Message, Severity.Error);
}
finally
{
IsProcessing = false;
}
}
public int DeletedPagesCurrentPage { get; set; } = 0;
public int DeletedPagesCount { get; set; } = 0;
public void DeletedPagesChangePageAsync(int page)
{
DeletedPagesCurrentPage = page - 1;
if (PageDto.RedirectItems.Count > (DeletedPagesCurrentPage * 20))
DeletedPagesCount = DeletedPagesCurrentPage + 2;
PageDto.DeletedPages.Skip(DeletedPagesCurrentPage * 20).Take(20).ToList().ForEach(a => DeletedPages.Add(a));
}
}

View File

@ -7,7 +7,7 @@
@inject IUserUtility UserUtility @inject IUserUtility UserUtility
@inject IRestWrapper RestWrapper @inject IRestWrapper RestWrapper
<MudStack class="h-full w-full p-8"> <MudStack class="w-full p-8 h-screen bg-[--mud-palette-background-grey]">
<MudGrid> <MudGrid>
<MudItem xs="12"> <MudItem xs="12">
<MudStack Row="true" class="mb-5"> <MudStack Row="true" class="mb-5">
@ -73,7 +73,7 @@
<MudStack Row="true" class="w-full"> <MudStack Row="true" class="w-full">
<MudPagination Rectangular="true" Variant="Variant.Filled" Count="@ViewModel.PageCount" <MudPagination Rectangular="true" Variant="Variant.Filled" Count="@ViewModel.PageCount"
SelectedChanged="@ViewModel.ChangePageAsync" class="mx-auto my-4" /> SelectedChanged="@ViewModel.ChangePageAsync" class="my-4 mx-auto" />
</MudStack> </MudStack>
</PagerContent> </PagerContent>

View File

@ -133,7 +133,7 @@ public class ManageNavMenuPageViewModel : BaseViewModel<NavMenuSetting>
var token = await _userUtility.GetBearerTokenAsync(); var token = await _userUtility.GetBearerTokenAsync();
if (token == null) if (token == null)
throw new Exception("Token is null"); throw new Exception("Token is null");
var response = await _restWrapper.ProductRestApi.ReadAll(0,product,null,null,token); var response = await _restWrapper.ProductRestApi.ReadAll(0,product,null, token);
var categories = response.Products; var categories = response.Products;
if (product.IsNullOrEmpty()) if (product.IsNullOrEmpty())
return categories; return categories;

View File

@ -1,243 +0,0 @@
@page "/personaliztion/main"
@attribute [Microsoft.AspNetCore.Authorization.Authorize]
@inject IDialogService DialogService
@inject ISnackbar Snackbar
@inject IUserUtility UserUtility
@inject IRestWrapper RestWrapper
@inject NavigationManager NavigationManager
@inject IConfiguration Configuration
@inject IJSRuntime JsRuntime
<MudStack class="h-full w-full p-8">
<MudPaper class="px-5 py-5">
<MudStack Row="true">
<MudStack class="mx-2 mb-5">
<MudText Typo="Typo.h4">اطلاعات بنر ها وکاتالوگ</MudText>
<MudText Typo="Typo.caption">بنر ها و کاتالوگ در صفحه اصلی و دیگر صفحه ها نمایش داده خواهند شد</MudText>
</MudStack>
<MudSpacer />
<BaseButtonUi Size="Size.Large"
OnClickCallback="ViewModel.SubmitSettingAsync"
class="mb-8 mt-2 w-64 rounded-md"
IsProcessing="@ViewModel.IsProcessing"
Icon="@Icons.Material.Outlined.Check"
Content="ثبتـــ اطلاعات" Variant="Variant.Filled" Color="Color.Success" />
</MudStack>
<MudDivider />
<MudStack class="mt-3">
<MudText Typo="Typo.h6">بنر های سایت شما</MudText>
</MudStack>
<MudGrid>
<MudItem xs="12" md="4">
<MudTextField T="string" @bind-Value="@ViewModel.NewBanner.Title" class="my-2" Variant="Variant.Outlined" Label="عنوان بنر"></MudTextField>
<MudTextField T="string" @bind-Value="@ViewModel.NewBanner.Link" class="my-2" Variant="Variant.Outlined" Label="لینک بنر"></MudTextField>
<MudTextField T="string" @bind-Value="@ViewModel.NewBanner.Description" class="my-2" Variant="Variant.Outlined" Label="توضیحات بنر"></MudTextField>
<MudSelect Variant="Variant.Outlined" class="my-2" T="BannerSection" ToStringFunc="type => type.ToDisplay()" Label="محل قرارگیری بنر" @bind-Value="ViewModel.NewBanner.Section">
@foreach (var state in Enum.GetValues(typeof(BannerSection)).Cast<BannerSection>())
{
<MudSelectItem T="BannerSection" Value="@state"></MudSelectItem>
}
</MudSelect>
@if (ViewModel.NewBanner.ImageLocation.IsNullOrEmpty())
{
<MudButton class="mt-3"
Variant="Variant.Outlined"
FullWidth="true"
Color="Color.Info"
OnClick="@ViewModel.SelectFileAsync">انتخاب تصویر بنر</MudButton>
}
else
{
<MudButton class="mt-3"
Variant="Variant.Filled"
FullWidth="true"
Color="Color.Info"
OnClick="@ViewModel.SelectFileAsync">انتخاب تصویر دیگر</MudButton>
}
<MudButton class="mt-3"
Variant="Variant.Outlined"
FullWidth="true"
Color="Color.Info"
OnClick="@ViewModel.AddBanner">افزودن بنر</MudButton>
</MudItem>
<MudItem xs="12" md="8">
<MudDataGrid Items="@ViewModel.PageDto.Banners"
T="BannerItemModel"
Elevation="0"
Outlined="true"
Bordered="true"
Striped="false"
Dense="true"
Filterable="false"
SortMode="@SortMode.None"
Groupable="false">
<Columns>
<PropertyColumn T="BannerItemModel" TProperty="string" Property="x => x.Title" Title="نام فارسی" />
<TemplateColumn T="BannerItemModel" Title="جایگاه بنر" CellClass="d-flex justify-end">
<CellTemplate>
<MudStack Row="true">
<MudText Align="Align.Center">@context.Item.Section.ToDisplay()</MudText>
</MudStack>
</CellTemplate>
</TemplateColumn>
<PropertyColumn T="BannerItemModel" TProperty="string" Property="x => x.Description" Title="نام انگلیسی" />
<TemplateColumn T="BannerItemModel" CellClass="d-flex justify-end">
<CellTemplate>
<MudStack Row="true">
<MudButton DisableElevation="true"
Size="@Size.Small"
Variant="@Variant.Outlined"
OnClick="async()=>await ShowBannerPhoto(context.Item.ImageLocation)"
Color="@Color.Info"
StartIcon="@Icons.Material.Filled.RemoveRedEye">مشاهده تصویر</MudButton>
<MudButton DisableElevation="true"
Size="@Size.Small"
Variant="@Variant.Outlined"
OnClick="async()=>await ShowBannerLink(context.Item.Link)"
Color="@Color.Info"
StartIcon="@Icons.Material.Outlined.AttachFile">مشاهده لینک</MudButton>
<MudButton DisableElevation="true"
Size="@Size.Small"
Variant="@Variant.Outlined"
OnClick="() => ViewModel.PageDto.Banners.Remove(context.Item)"
Color="@Color.Error"
StartIcon="@Icons.Material.Outlined.Delete">حذف</MudButton>
</MudStack>
</CellTemplate>
</TemplateColumn>
</Columns>
</MudDataGrid>
</MudItem>
</MudGrid>
<MudDivider class="mt-5" />
<MudStack class="mb-1 mt-3" Spacing="0">
<MudText Typo="Typo.h6">کاتالوگ سایت شما</MudText>
<MudText Typo="Typo.caption">کاتالوگ به لیست فهرست مانند صفحه اصلی گفته میشود که تورهای مختلف را نمایش میدهد</MudText>
</MudStack>
<MudGrid>
<MudItem xs="12" sm="6" lg="1">
<MudTextField T="int" @bind-Value="@ViewModel.NewCatalogItem.Row" Variant="Variant.Outlined" Label="ردیف"></MudTextField>
</MudItem>
<MudItem xs="12" sm="6" lg="4">
<MudTextField T="string" @bind-Value="@ViewModel.NewCatalogItem.PersianName" Variant="Variant.Outlined" Label="نام فارسی کاتالوگ"></MudTextField>
</MudItem>
<MudItem xs="12" sm="6" lg="4">
<MudTextField T="string" @bind-Value="@ViewModel.NewCatalogItem.EnglishName" Variant="Variant.Outlined" Label="نام انگلیسی"></MudTextField>
</MudItem>
<MudItem xs="12" sm="6" lg="3">
<MudAutocomplete ToStringFunc="dto => dto.PersianName"
T="CatalogItemModel"
@bind-Value="ViewModel.SelectedCatalog"
MaxItems="306"
SearchFunc="ViewModel.SearchCatalog"
Label="کاتالوگ پدر"
Variant="Variant.Outlined">
<ItemTemplate Context="e">
<p>@e.PersianName</p>
</ItemTemplate>
</MudAutocomplete>
</MudItem>
<MudItem xs="12" sm="6" lg="6">
<MudTextField T="string" @bind-Value="@ViewModel.NewCatalogItem.Query" Variant="Variant.Outlined" Label="کوئری"></MudTextField>
</MudItem>
<MudItem xs="12" sm="6" lg="3">
@if (ViewModel.CatalogImage.IsNullOrEmpty())
{
<MudButton class="mt-3 py-3"
Variant="Variant.Outlined"
FullWidth="true"
Color="Color.Info"
OnClick="@ViewModel.SelectCatalogFileAsync">انتخاب تصویر کاتالوگ</MudButton>
}
else
{
<MudButton class="mt-3 py-3"
Variant="Variant.Filled"
FullWidth="true"
Color="Color.Info"
OnClick="@ViewModel.SelectCatalogFileAsync">انتخاب تصویر دیگر</MudButton>
}
</MudItem>
<MudItem xs="12" sm="6" lg="2">
<MudButton Variant="Variant.Outlined"
FullWidth="true"
class="mt-2 py-3"
Color="Color.Info"
OnClick="@ViewModel.AddCatalogItem">+</MudButton>
</MudItem>
</MudGrid>
<MudDataGrid Items="@ViewModel.PageDto.Catalog"
T="CatalogItemModel"
class="mt-2"
Elevation="0"
Outlined="true"
Bordered="false"
Dense="true"
Striped="false"
Filterable="false"
SortMode="@SortMode.None"
Groupable="false">
<Columns>
<PropertyColumn T="CatalogItemModel" TProperty="int" Property="x => x.Row" Title=" " />
<PropertyColumn T="CatalogItemModel" TProperty="string" Property="x => x.PersianName" Title="نام فارسی" />
<PropertyColumn T="CatalogItemModel" TProperty="string" Property="x => x.ParentName" Title="دسته پدر" />
<PropertyColumn T="CatalogItemModel" TProperty="string" Property="x => x.EnglishName" Title="نام انگلیسی" />
<PropertyColumn T="CatalogItemModel" TProperty="string" Property="x => x.Query" Title="کوئری" />
<TemplateColumn T="CatalogItemModel" CellClass="d-flex justify-end">
<CellTemplate>
<MudStack Row>
<MudButton DisableElevation="true"
Size="@Size.Small"
Variant="@Variant.Outlined"
OnClick="() => ViewModel.PageDto.Catalog.Remove(context.Item)"
Color="@Color.Error"
StartIcon="@Icons.Material.Outlined.Delete">حذف</MudButton>
</MudStack>
</CellTemplate>
</TemplateColumn>
</Columns>
</MudDataGrid>
</MudPaper>
</MudStack>
@code
{
public PersonalizationPageViewModel ViewModel { get; set; }
protected override async Task OnInitializedAsync()
{
ViewModel = new PersonalizationPageViewModel(DialogService, RestWrapper, Snackbar, NavigationManager, UserUtility);
await ViewModel.InitializeAsync();
await base.OnInitializedAsync();
}
private async Task ShowBannerPhoto(string photoUrl)
{
var webUrl = Configuration.GetValue<string>("StorageBaseUrl") ?? string.Empty;
var url = $"{webUrl}/{photoUrl}";
await JsRuntime.InvokeVoidAsyncIgnoreErrors("open", url, "_blank");
}
private async Task ShowBannerLink(string url)
{
await JsRuntime.InvokeVoidAsyncIgnoreErrors("open", url, "_blank");
}
}
}

View File

@ -1,167 +0,0 @@
using System.Net.Http.Json;
namespace Netina.AdminPanel.PWA.Pages.Personalization;
public class PersonalizationPageViewModel(IDialogService dialogService, IRestWrapper restWrapper,
ISnackbar snackbar, NavigationManager navigationManager, IUserUtility userUtility)
: BaseViewModel<PersonalizationSetting>(userUtility: userUtility)
{
public override async Task InitializeAsync()
{
try
{
var token = await userUtility.GetBearerTokenAsync();
if (token == null)
throw new Exception("Token is null");
var personalizationSetting = await restWrapper.SettingRestApi.GetSettingAsync<PersonalizationSetting>(nameof(PersonalizationSetting), token);
personalizationSetting.Catalog = personalizationSetting.Catalog.OrderBy(c => c.Row).ToList();
PageDto = personalizationSetting;
}
catch (ApiException ex)
{
var exe = await ex.GetContentAsAsync<ApiResult>();
if (ex.StatusCode == HttpStatusCode.Unauthorized)
{
await userUtility.LogoutAsync();
navigationManager.NavigateTo("login", true, true);
}
snackbar.Add(exe != null ? exe.Message : ex.Content, Severity.Error);
}
catch (Exception e)
{
snackbar.Add(e.Message, Severity.Error);
}
await base.InitializeAsync();
}
public async Task SubmitSettingAsync()
{
try
{
var token = await userUtility.GetBearerTokenAsync();
if (token == null)
throw new Exception("Token is null");
await restWrapper.SettingRestApi.PostSettingAsync(nameof(PersonalizationSetting), PageDto, token);
snackbar.Add("تنظیمات شخصی سازی با موفقیت تغییر یافت", Severity.Success);
}
catch (ApiException ex)
{
var exe = await ex.GetContentAsAsync<ApiResult>();
if (ex.StatusCode == HttpStatusCode.Unauthorized)
{
await userUtility.LogoutAsync();
navigationManager.NavigateTo("login", true, true);
}
snackbar.Add(exe != null ? exe.Message : ex.Content, Severity.Error);
}
catch (Exception e)
{
snackbar.Add(e.Message, Severity.Error);
}
}
public BannerItemModel NewBanner { get; set; } = new();
public CatalogItemModel NewCatalogItem { get; set; } = new();
public void AddBanner()
{
try
{
if (NewBanner.ImageLocation.IsNullOrEmpty())
throw new Exception("تصویر بنر انتخاب نشده است");
if (NewBanner.Title.IsNullOrEmpty())
throw new Exception("عنوان بنر انتخاب نشده است");
PageDto.Banners.Add(NewBanner);
NewBanner = new BannerItemModel();
}
catch (Exception e)
{
snackbar.Add(e.Message, Severity.Error);
}
}
public async Task SelectFileAsync()
{
DialogOptions maxWidth = new DialogOptions() { MaxWidth = MaxWidth.Large, FullWidth = true, DisableBackdropClick = true };
var dialog = await dialogService.ShowAsync<StorageDialogBox>("انتخاب عکس", maxWidth);
var result = await dialog.Result;
var file = result.Data;
if (file is StorageFileSDto storageFile)
{
NewBanner.ImageLocation = storageFile.FileLocation;
}
}
public CatalogItemModel? SelectedCatalog { get; set; }
public async Task<IEnumerable<CatalogItemModel>> SearchCatalog(string catelogName)
{
try
{
if (catelogName.IsNullOrEmpty())
return PageDto.Catalog;
return PageDto.Catalog.Where(f => f.PersianName.Contains(catelogName));
}
catch (ApiException ex)
{
var exe = await ex.GetContentAsAsync<ApiResult>();
snackbar.Add(exe != null ? exe.Message : ex.Content, Severity.Error);
return new List<CatalogItemModel>();
}
catch (Exception e)
{
snackbar.Add(e.Message, Severity.Error);
return new List<CatalogItemModel>();
}
}
public string CatalogImage { get; set; } = string.Empty;
public async Task SelectCatalogFileAsync()
{
DialogOptions maxWidth = new DialogOptions() { MaxWidth = MaxWidth.Large, FullWidth = true, DisableBackdropClick = true };
var dialog = await dialogService.ShowAsync<StorageDialogBox>("انتخاب عکس", maxWidth);
var result = await dialog.Result;
var file = result.Data;
if (file is StorageFileSDto storageFile)
{
CatalogImage = storageFile.FileLocation;
}
}
public void AddCatalogItem()
{
try
{
if (NewCatalogItem.EnglishName.IsNullOrEmpty())
throw new Exception("نام انگلیسی را وارد کنید");
if (NewCatalogItem.PersianName.IsNullOrEmpty())
throw new Exception("نام فارسی ایتم کاتالوگ را وارد کنید");
if (NewCatalogItem.Query.IsNullOrEmpty())
throw new Exception("کوئری ایتم کاتالوگ را وارد کنید");
if (SelectedCatalog != null)
{
NewCatalogItem.ParentId = SelectedCatalog.Id;
NewCatalogItem.ParentName = SelectedCatalog.PersianName;
}
else
NewCatalogItem.IsMain = true;
if (!CatalogImage.IsNullOrEmpty())
NewCatalogItem.ImageLocation = CatalogImage;
CatalogImage = string.Empty;
NewCatalogItem.Id = Guid.NewGuid();
PageDto.Catalog.Add(NewCatalogItem);
PageDto.Catalog = PageDto.Catalog.OrderBy(c => c.Row).ToList();
NewCatalogItem = new CatalogItemModel();
}
catch (Exception e)
{
snackbar.Add(e.Message, Severity.Error);
}
}
}

View File

@ -7,52 +7,41 @@
@inject IUserUtility UserUtility @inject IUserUtility UserUtility
@inject IRestWrapper RestWrapper @inject IRestWrapper RestWrapper
@inject IBrowserViewportService BrowserViewportService @inject IBrowserViewportService BrowserViewportService
@inject IConfiguration Configuration
@inject IJSRuntime JsRuntime
<MudStack class="h-full w-full p-8"> <MudStack class="bg-[--mud-palette-background-grey] h-screen w-full p-8">
<MudGrid> <MudGrid>
<MudItem xs="12"> <MudItem xs="12">
<MudStack Row="@ViewModel.IsXs.Not()" class="mb-5"> <MudGrid Row="true" class="mb-5">
<MudStack Row="true"> <MudItem xs="12" sm="6" md="8">
<MudText Typo="Typo.h4">محصولاتــــ</MudText> <MudStack Row="true">
<MudChip Color="Color.Info" Variant="Variant.Outlined">@ViewModel.TotalItems عدد</MudChip> <MudText Typo="Typo.h4">محصولاتــــ</MudText>
</MudStack> <MudChip Color="Color.Info" Variant="Variant.Outlined">@ViewModel.TotalItems عدد</MudChip>
@if (@ViewModel.IsXs.Not()) </MudStack>
{ </MudItem>
<MudSpacer /> <MudItem xs="12" sm="6" md="4">
}
<MudStack Row="@ViewModel.IsXs.Not()">
<MudButton Variant="Variant.Filled" <MudButton Variant="Variant.Filled"
DisableElevation="true" DisableElevation="true"
StartIcon="@Icons.Material.Outlined.Add" StartIcon="@Icons.Material.Outlined.Add"
Color="Color.Secondary" Color="Color.Secondary"
OnClick="@ViewModel.AddProductClicked" OnClick="@ViewModel.AddProductClicked"
class="w-full md:my-auto md:w-auto">افزودن محصول</MudButton> class="w-full md:my-auto md:w-auto">افزودن محصول</MudButton>
<MudButton Variant="Variant.Outlined" <MudButton Variant="Variant.Filled"
DisableElevation="true"
StartIcon="@Icons.Material.Outlined.Add"
Color="Color.Info"
OnClick="@ViewModel.AddFastProductClicked"
class="w-full md:my-auto md:w-auto">افزودن سریع محصول</MudButton>
<MudButton Variant="Variant.Outlined"
DisableElevation="true" DisableElevation="true"
StartIcon="@Icons.Material.Outlined.Add" StartIcon="@Icons.Material.Outlined.Add"
Color="Color.Error" Color="Color.Error"
OnClick="@ViewModel.AddDigikalaProductClicked" OnClick="@ViewModel.AddDigikalaProductClicked"
class="w-full md:my-auto md:w-auto">افزودن محصول از دیجیکالا</MudButton> class="w-full md:my-auto md:w-auto">افزودن محصول از دیجیکالا</MudButton>
</MudStack> </MudItem>
</MudStack> </MudGrid>
<MudHidden Breakpoint="Breakpoint.SmAndUp"> <MudHidden Breakpoint="Breakpoint.SmAndUp">
<MudGrid class="mb-3" Row="true"> <MudGrid class="mb-3" Row="true">
<MudItem xs="12" sm="6"> <MudItem xs="12" sm="6">
<MudTextField T="string" Placeholder="جست جو بر اساس نام" Adornment="Adornment.Start" <MudTextField T="string" Placeholder="جست جو بر اساس نام" Adornment="Adornment.Start" Immediate="true"
Immediate="true"
Clearable="true" Clearable="true"
@bind-Value="@ViewModel.Search" ValueChanged="@ViewModel.SearchChanged"
AdornmentIcon="@Icons.Material.Filled.Search" IconSize="Size.Medium" class="my-auto" AdornmentIcon="@Icons.Material.Filled.Search" IconSize="Size.Medium" class="my-auto"
OnAdornmentClick="@ViewModel.GetEntitiesAsync"></MudTextField> OnAdornmentClick="@ViewModel.SearchAsync"></MudTextField>
</MudItem> </MudItem>
<MudItem xs="12" sm="6"> <MudItem xs="12" sm="6">
@ -80,54 +69,49 @@
</MudItem> </MudItem>
</MudGrid> </MudGrid>
</MudHidden> </MudHidden>
<MudPaper> <MudPaper class="!max-h-[80vh] overflow-auto">
<MudDataGrid FixedFooter="true" FixedHeader="true" Striped="true" <MudDataGrid FixedFooter="true" FixedHeader="true" Striped="true"
T="ProductSDto" Items="@ViewModel.PageDto" CurrentPage="@ViewModel.CurrentPage" T="ProductSDto" Items="@ViewModel.PageDto" CurrentPage="@ViewModel.CurrentPage"
RowsPerPage="20" Filterable="false" Loading="@ViewModel.IsProcessing" RowsPerPage="20" Filterable="false" Loading="@ViewModel.IsProcessing"
SortMode="@SortMode.None" Groupable="false"> SortMode="@SortMode.None" Groupable="false">
<ToolBarContent> <ToolBarContent>
<MudGrid class="collapse md:visible"> <MudGrid class="collapse md:visible">
<MudItem xs="12" sm="4"> <MudItem xs="12" sm="6">
<MudTextField T="string" Placeholder="جست جو بر اساس نام" Adornment="Adornment.Start" <MudTextField T="string" Placeholder="جست جو بر اساس نام" Adornment="Adornment.Start" Immediate="true"
Immediate="true" Clearable="true"
Clearable="true" ValueChanged="@ViewModel.SearchChanged"
@bind-Value="@ViewModel.Search" AdornmentIcon="@Icons.Material.Filled.Search" IconSize="Size.Medium" class="my-auto"
AdornmentIcon="@Icons.Material.Filled.Search" IconSize="Size.Medium" class="my-auto" OnAdornmentClick="@ViewModel.SearchAsync"></MudTextField>
OnAdornmentClick="@ViewModel.GetEntitiesAsync"></MudTextField> </MudItem>
</MudItem>
<MudItem xs="12" sm="6"> <MudItem xs="12" sm="6">
<MudAutocomplete class="-mt-0.5" Required="true" ToStringFunc="dto => dto.Name" <MudAutocomplete class="-mt-0.5" Required="true" ToStringFunc="dto => dto.Name"
T="ProductCategorySDto" T="ProductCategorySDto"
Label="بر اساس دسته بندی" Label="بر اساس دسته بندی"
OnClearButtonClick="ViewModel.ClearProductCategorySearch" OnClearButtonClick="ViewModel.ClearProductCategorySearch"
SearchFunc="ViewModel.SearchProductCategory" SearchFunc="ViewModel.SearchProductCategory"
ValueChanged="ViewModel.ProductCategorySelected" ValueChanged="ViewModel.ProductCategorySelected"
Clearable="true"> Clearable="true">
<ProgressIndicatorInPopoverTemplate> <ProgressIndicatorInPopoverTemplate>
<MudList Clickable="false"> <MudList Clickable="false">
<MudListItem> <MudListItem>
<div class="mx-auto flex w-full flex-row"> <div class="mx-auto flex w-full flex-row">
<MudProgressCircular class="my-auto -ml-4 mr-1" Size="Size.Small" Indeterminate="true" /> <MudProgressCircular class="my-auto -ml-4 mr-1" Size="Size.Small" Indeterminate="true" />
<p class="text-md mx-auto my-1 font-bold">منتظر بمانید</p> <p class="text-md mx-auto my-1 font-bold">منتظر بمانید</p>
</div> </div>
</MudListItem> </MudListItem>
</MudList> </MudList>
</ProgressIndicatorInPopoverTemplate> </ProgressIndicatorInPopoverTemplate>
<ItemTemplate Context="e"> <ItemTemplate Context="e">
<p>@e.Name</p> <p>@e.Name</p>
</ItemTemplate> </ItemTemplate>
</MudAutocomplete> </MudAutocomplete>
</MudItem> </MudItem>
<MudItem xs="12" sm="2"> </MudGrid>
<MudSwitch class="mt-3" T="bool"
Value="ViewModel.IsEnable"
ValueChanged="async(flag)=>await ViewModel.ProductEnableChanged(flag)"
Label="فقط محصولات موجود" Color="Color.Info" />
</MudItem>
</MudGrid>
</ToolBarContent> </ToolBarContent>
<Columns> <Columns>
@ -136,8 +120,9 @@
<MudCheckBox ValueChanged="delegate(bool flag) { context.Item.BeDisplayed = flag; ViewModel.DisplayedChanged(context.Item); }" Color="Color.Secondary" Value="@context.Item.BeDisplayed"></MudCheckBox> <MudCheckBox ValueChanged="delegate(bool flag) { context.Item.BeDisplayed = flag; ViewModel.DisplayedChanged(context.Item); }" Color="Color.Secondary" Value="@context.Item.BeDisplayed"></MudCheckBox>
</CellTemplate> </CellTemplate>
</TemplateColumn> </TemplateColumn>
<PropertyColumn Title="نام محصول" Property="arg => arg.PersianName" /> <PropertyColumn Title="نام محصول" Property="arg => arg.PersianName"/>
<PropertyColumn Title="دسته بندی" Property="arg => arg.CategoryName" /> <PropertyColumn Title="دسته بندی" Property="arg => arg.CategoryName"/>
<PropertyColumn Title="برند" Property="arg => arg.BrandName" />
<TemplateColumn T="ProductSDto" Title="پیشنهاد ویژه است"> <TemplateColumn T="ProductSDto" Title="پیشنهاد ویژه است">
<CellTemplate> <CellTemplate>
@if (@context.Item.IsSpecial) @if (@context.Item.IsSpecial)
@ -151,53 +136,24 @@
} }
</CellTemplate> </CellTemplate>
</TemplateColumn> </TemplateColumn>
<TemplateColumn T="ProductSDto" Title="موجود است">
<CellTemplate>
@if (@context.Item.IsEnable)
{
<p>بلی</p>
}
else
{
<p>خیر</p>
}
</CellTemplate>
</TemplateColumn>
<TemplateColumn T="ProductSDto" Title="قیمتــ"> <TemplateColumn T="ProductSDto" Title="قیمتــ">
<CellTemplate> <CellTemplate>
<MudTextField class="-mt-2" <p>@context.Item.Cost.ToString("N0") ریالــ</p>
Format="N0"
T="double"
ValueChanged="async(cost) => await ViewModel.ChangeProductCostAsync(context.Item,cost)"
AdornmentText="ریالــ"
Immediate="false"
AdornmentIcon="@Icons.Material.Filled.Check"
Adornment="Adornment.End"
Value="context.Item.Cost"></MudTextField>
</CellTemplate> </CellTemplate>
</TemplateColumn> </TemplateColumn>
<TemplateColumn CellClass="d-flex justify-end"> <TemplateColumn CellClass="d-flex justify-end">
<CellTemplate> <CellTemplate>
<MudStack Row="true"> <MudStack Row="true">
<MudIconButton Icon="@Icons.Material.Filled.Link"
Size="@Size.Small"
Variant="@Variant.Outlined"
Color="@Color.Surface"
OnClick="async()=>await ShowProduct(context.Item)" />
<MudIconButton Icon="@Icons.Material.Filled.Edit" <MudIconButton Icon="@Icons.Material.Filled.Edit"
Size="@Size.Small" Size="@Size.Small"
Variant="@Variant.Outlined" Variant="@Variant.Outlined"
Color="@Color.Info" Color="@Color.Info"
OnClick="async()=>await ViewModel.EditProductClicked(context.Item)" /> OnClick="async()=>await ViewModel.EditProductClicked(context.Item)"/>
<MudIconButton Icon="@Icons.Material.Filled.Delete" <MudIconButton Icon="@Icons.Material.Filled.Delete"
Size="@Size.Small" Size="@Size.Small"
Variant="@Variant.Outlined" Variant="@Variant.Outlined"
OnClick="async () => await ViewModel.DeleteProductAsync(context.Item.Id)" OnClick="async () => await ViewModel.DeleteProductAsync(context.Item.Id)"
Color="@Color.Error" /> Color="@Color.Error"/>
</MudStack> </MudStack>
</CellTemplate> </CellTemplate>
</TemplateColumn> </TemplateColumn>
@ -206,7 +162,7 @@
<MudStack Row="true" class="w-full"> <MudStack Row="true" class="w-full">
<MudPagination Rectangular="true" Variant="Variant.Filled" Count="@ViewModel.PageCount" <MudPagination Rectangular="true" Variant="Variant.Filled" Count="@ViewModel.PageCount"
SelectedChanged="@ViewModel.ChangePageAsync" class="mx-auto my-4" /> SelectedChanged="@ViewModel.ChangePageAsync" class="mx-auto my-4"/>
</MudStack> </MudStack>
</PagerContent> </PagerContent>
@ -225,12 +181,4 @@
await ViewModel.InitializeAsync(); await ViewModel.InitializeAsync();
await base.OnInitializedAsync(); await base.OnInitializedAsync();
} }
private async Task ShowProduct(ProductSDto item)
{
var webUrl = Configuration.GetValue<string>("WebSiteUrl") ?? string.Empty;
var slug = WebUtility.UrlEncode(item.Slug.Replace(' ', '-'));
var url = $"{webUrl}/products/{item.Id}/{slug}";
await JsRuntime.InvokeVoidAsync("open", url, "_blank");
}
} }

View File

@ -1,34 +1,37 @@
using MudBlazor.Services; using MudBlazor.Services;
using Netina.Domain.Entities.Products;
namespace Netina.AdminPanel.PWA.Pages; namespace Netina.AdminPanel.PWA.Pages;
public class ProductsPageViewModel( public class ProductsPageViewModel : BaseViewModel<ObservableCollection<ProductSDto>>
NavigationManager navigationManager,
ISnackbar snackbar,
IUserUtility userUtility,
IRestWrapper restWrapper,
IDialogService dialogService,
IBrowserViewportService browserViewportService)
: BaseViewModel<ObservableCollection<ProductSDto>>(userUtility)
{ {
private readonly NavigationManager _navigationManager = navigationManager; private readonly NavigationManager _navigationManager;
private readonly IUserUtility _userUtility = userUtility; private readonly ISnackbar _snackbar;
private readonly IUserUtility _userUtility;
private readonly IDialogService _dialogService;
private readonly IBrowserViewportService _browserViewportService;
private readonly IRestWrapper _restWrapper;
public string? Search = string.Empty; public string Search = string.Empty;
public int CurrentPage = 0; public int CurrentPage = 0;
public int PageCount = 1; public int PageCount = 1;
public int TotalItems = 0; public int TotalItems = 0;
public bool IsXs = false;
public bool IsEnable { get; set; } = true;
public override async Task InitializeAsync() public ProductsPageViewModel(NavigationManager navigationManager,
ISnackbar snackbar,
IUserUtility userUtility,
IRestWrapper restWrapper,
IDialogService dialogService,
IBrowserViewportService browserViewportService) : base(userUtility)
{ {
await GetEntitiesAsync(); _navigationManager = navigationManager;
await base.InitializeAsync(); _snackbar = snackbar;
_userUtility = userUtility;
_restWrapper = restWrapper;
_dialogService = dialogService;
_browserViewportService = browserViewportService;
} }
public async Task GetEntitiesAsync() public override async Task InitializeAsync()
{ {
try try
{ {
@ -37,43 +40,81 @@ public class ProductsPageViewModel(
throw new Exception("Token is null"); throw new Exception("Token is null");
IsProcessing = true; IsProcessing = true;
PageDto.Clear(); PageDto.Clear();
var search = Search.IsNullOrEmpty() ? null : Search; var dto = await _restWrapper.ProductRestApi.ReadAll(CurrentPage,null,null, token);
var dto = await restWrapper.ProductRestApi.ReadAll(CurrentPage, search, SelectedCategory?.Id, IsEnable,token);
dto.Products.ForEach(d => PageDto.Add(d)); dto.Products.ForEach(d => PageDto.Add(d));
if (PageDto.Count % 20 == 0) if (PageDto.Count == 20)
PageCount = CurrentPage + 2; PageCount = 2;
TotalItems = dto.Pager.TotalItems; TotalItems = dto.Pager.TotalItems;
IsXs = (await browserViewportService.GetCurrentBreakpointAsync()) == Breakpoint.Xs;
} }
catch (ApiException ex) catch (ApiException ex)
{ {
var exe = await ex.GetContentAsAsync<ApiResult>(); var exe = await ex.GetContentAsAsync<ApiResult>();
snackbar.Add(exe != null ? exe.Message : ex.Content, Severity.Error); _snackbar.Add(exe != null ? exe.Message : ex.Content, Severity.Error);
} }
catch (Exception e) catch (Exception e)
{ {
snackbar.Add(e.Message, Severity.Error); _snackbar.Add(e.Message, Severity.Error);
} }
finally finally
{ {
IsProcessing = false; IsProcessing = false;
} }
await base.InitializeAsync();
} }
public async Task ChangePageAsync(int page) public async Task ChangePageAsync(int page)
{ {
CurrentPage = page - 1; CurrentPage = page - 1;
await GetEntitiesAsync(); if (CurrentPage > PageCount - 2)
{
try
{
var token = await _userUtility.GetBearerTokenAsync();
if (token == null)
throw new Exception("Token is null");
IsProcessing = true;
GetProductsResponseDto dto = new GetProductsResponseDto();
if (Search.IsNullOrEmpty())
{
dto = await _restWrapper.ProductRestApi.ReadAll(CurrentPage,null,null, token);
}
else
{
dto = await _restWrapper.ProductRestApi.ReadAll(CurrentPage, Search,null, token);
}
dto.Products.ForEach(d => PageDto.Add(d));
if (PageDto.Count % 20 == 0)
PageCount = CurrentPage + 2;
}
catch (ApiException ex)
{
var exe = await ex.GetContentAsAsync<ApiResult>();
_snackbar.Add(exe != null ? exe.Message : ex.Content, Severity.Error);
}
catch (Exception e)
{
_snackbar.Add(e.Message, Severity.Error);
}
finally
{
IsProcessing = false;
}
}
} }
public async Task AddProductClicked() public async Task AddProductClicked()
{ {
DialogOptions maxWidth = new DialogOptions() { MaxWidth = MaxWidth.Large, FullWidth = true, DisableBackdropClick = true }; DialogOptions maxWidth = new DialogOptions() { MaxWidth = MaxWidth.Large, FullWidth = true, DisableBackdropClick = true };
var breakPoint = await browserViewportService.GetCurrentBreakpointAsync(); var breakPoint = await _browserViewportService.GetCurrentBreakpointAsync();
if (breakPoint == Breakpoint.Xs) if (breakPoint == Breakpoint.Xs)
maxWidth = new DialogOptions { FullScreen = true, CloseButton = true }; maxWidth = new DialogOptions { FullScreen = true , CloseButton = true};
var dialogResult = await dialogService.ShowAsync<ProductActionDialogBox>("افزودن محصول جدید", maxWidth); var dialogResult = await _dialogService.ShowAsync<ProductActionDialogBox>("افزودن محصول جدید", maxWidth);
var result = await dialogResult.Result; var result = await dialogResult.Result;
if (!result.Canceled && result.Data is bool and true) if (!result.Canceled && result.Data is bool and true)
{ {
@ -81,25 +122,11 @@ public class ProductsPageViewModel(
} }
} }
public async Task AddFastProductClicked()
{
DialogOptions maxWidth = new DialogOptions() { MaxWidth = MaxWidth.Large, FullWidth = true, NoHeader = true, DisableBackdropClick = true, CloseButton = true };
var breakPoint = await browserViewportService.GetCurrentBreakpointAsync();
if (breakPoint == Breakpoint.Xs)
maxWidth = new DialogOptions { FullScreen = true, NoHeader = true, CloseButton = true };
var dialogResult = await dialogService.ShowAsync<FastProductCreateDialogBox>("افزودن محصول جدید", maxWidth);
var result = await dialogResult.Result;
if (!result.Canceled && result.Data is bool and true)
{
await InitializeAsync();
}
}
public async Task AddDigikalaProductClicked() public async Task AddDigikalaProductClicked()
{ {
DialogOptions maxWidth = new DialogOptions() { MaxWidth = MaxWidth.Medium, FullWidth = true, DisableBackdropClick = true }; DialogOptions maxWidth = new DialogOptions() { MaxWidth = MaxWidth.Medium, FullWidth = true, DisableBackdropClick = true };
var dialogResult = await dialogService.ShowAsync<DigikalaProductActionDialogBox>("افزودن محصول جدید", maxWidth); var dialogResult = await _dialogService.ShowAsync<DigikalaProductActionDialogBox>("افزودن محصول جدید", maxWidth);
var result = await dialogResult.Result; var result = await dialogResult.Result;
if (!result.Canceled && result.Data is bool and true) if (!result.Canceled && result.Data is bool and true)
{ {
@ -110,12 +137,9 @@ public class ProductsPageViewModel(
public async Task EditProductClicked(ProductSDto product) public async Task EditProductClicked(ProductSDto product)
{ {
DialogOptions maxWidth = new DialogOptions() { MaxWidth = MaxWidth.Large, FullWidth = true, DisableBackdropClick = true }; DialogOptions maxWidth = new DialogOptions() { MaxWidth = MaxWidth.Large, FullWidth = true, DisableBackdropClick = true };
var breakPoint = await browserViewportService.GetCurrentBreakpointAsync();
if (breakPoint == Breakpoint.Xs)
maxWidth = new DialogOptions { FullScreen = true, CloseButton = true };
var parameters = new DialogParameters<ProductActionDialogBox>(); var parameters = new DialogParameters<ProductActionDialogBox>();
parameters.Add(x => x.Product, product); parameters.Add(x => x.Product, product);
var dialogResult = await dialogService.ShowAsync<ProductActionDialogBox>($"ویرایش محصول {product.PersianName}", parameters, maxWidth); var dialogResult = await _dialogService.ShowAsync<ProductActionDialogBox>($"ویرایش محصول {product.PersianName}", parameters, maxWidth);
var result = await dialogResult.Result; var result = await dialogResult.Result;
if (!result.Canceled && result.Data is bool and true) if (!result.Canceled && result.Data is bool and true)
{ {
@ -125,7 +149,7 @@ public class ProductsPageViewModel(
public async Task DeleteProductAsync(Guid selectedCategoryId) public async Task DeleteProductAsync(Guid selectedCategoryId)
{ {
var reference = await dialogService.ShowQuestionDialog($"آیا از حذف محصول اطمینان دارید ?"); var reference = await _dialogService.ShowQuestionDialog($"آیا از حذف محصول اطمینان دارید ?");
var result = await reference.Result; var result = await reference.Result;
if (!result.Canceled) if (!result.Canceled)
{ {
@ -135,20 +159,20 @@ public class ProductsPageViewModel(
IsProcessing = true; IsProcessing = true;
var token = await _userUtility.GetBearerTokenAsync(); var token = await _userUtility.GetBearerTokenAsync();
await restWrapper.CrudDtoApiRest<Product, ProductSDto, Guid>(Address.ProductController) await _restWrapper.CrudDtoApiRest<Product, ProductSDto, Guid>(Address.ProductController)
.Delete(selectedCategoryId, token); .Delete(selectedCategoryId, token);
snackbar.Add("حذف محصول با موفقیت انجام شد", Severity.Success); _snackbar.Add("حذف محصول با موفقیت انجام شد", Severity.Success);
await InitializeAsync(); await InitializeAsync();
} }
catch (ApiException ex) catch (ApiException ex)
{ {
var exe = await ex.GetContentAsAsync<ApiResult>(); var exe = await ex.GetContentAsAsync<ApiResult>();
snackbar.Add(exe != null ? exe.Message : ex.Content, Severity.Error); _snackbar.Add(exe != null ? exe.Message : ex.Content, Severity.Error);
} }
catch (Exception e) catch (Exception e)
{ {
snackbar.Add(e.Message, Severity.Error); _snackbar.Add(e.Message, Severity.Error);
} }
finally finally
{ {
@ -158,10 +182,52 @@ public class ProductsPageViewModel(
} }
} }
public async Task SearchChanged() public async Task SearchChanged(string search)
{ {
if (Search!=null && !Search.IsNullOrEmpty()) if (search.IsNullOrEmpty() && !Search.IsNullOrEmpty())
await InitializeAsync(); await InitializeAsync();
Search = search;
}
public async Task SearchAsync()
{
try
{
if (Search.IsNullOrEmpty())
throw new AppException("دسته بندی برای جست جو وارد نشده است");
var token = await _userUtility.GetBearerTokenAsync();
if (token == null)
throw new Exception("Token is null");
IsProcessing = true;
CurrentPage = 0;
PageCount = 1;
PageDto.Clear();
GetProductsResponseDto dto;
if (SelectedCategory != null)
dto = await _restWrapper.ProductRestApi.ReadAll(CurrentPage, Search, SelectedCategory.Id, token);
else
dto = await _restWrapper.ProductRestApi.ReadAll(CurrentPage, Search,null, token);
dto.Products.ForEach(d => PageDto.Add(d));
if (PageDto.Count == 20)
PageCount = 2;
}
catch (ApiException ex)
{
var exe = await ex.GetContentAsAsync<ApiResult>();
_snackbar.Add(exe != null ? exe.Message : ex.Content, Severity.Error);
}
catch (Exception e)
{
_snackbar.Add(e.Message, Severity.Error);
}
finally
{
IsProcessing = false;
}
} }
@ -172,22 +238,22 @@ public class ProductsPageViewModel(
try try
{ {
if (category.IsNullOrEmpty()) if (category.IsNullOrEmpty())
_productCategories = await restWrapper.ProductCategoryRestApi.ReadAll(0); _productCategories = await _restWrapper.ProductCategoryRestApi.ReadAll(0);
else else
_productCategories = await restWrapper.ProductCategoryRestApi.ReadAll(category); _productCategories = await _restWrapper.ProductCategoryRestApi.ReadAll(category);
return _productCategories; return _productCategories;
} }
catch (ApiException ex) catch (ApiException ex)
{ {
var exe = await ex.GetContentAsAsync<ApiResult>(); var exe = await ex.GetContentAsAsync<ApiResult>();
if (exe != null) if (exe != null)
snackbar.Add(exe.Message, Severity.Error); _snackbar.Add(exe.Message, Severity.Error);
snackbar.Add(ex.Content, Severity.Error); _snackbar.Add(ex.Content, Severity.Error);
return _productCategories; return _productCategories;
} }
catch (Exception e) catch (Exception e)
{ {
snackbar.Add(e.Message, Severity.Error); _snackbar.Add(e.Message, Severity.Error);
return _productCategories; return _productCategories;
} }
} }
@ -195,13 +261,74 @@ public class ProductsPageViewModel(
public async Task ProductCategorySelected(ProductCategorySDto productCategory) public async Task ProductCategorySelected(ProductCategorySDto productCategory)
{ {
SelectedCategory = productCategory; SelectedCategory = productCategory;
await GetEntitiesAsync(); try
{
if (SelectedCategory == null)
{
return;
}
IsProcessing = true;
var token = await _userUtility.GetBearerTokenAsync();
if (token == null)
throw new Exception("Token is null");
CurrentPage = 0;
PageCount = 1;
PageDto.Clear();
GetProductsResponseDto dto = await _restWrapper.ProductRestApi.ReadAll(CurrentPage, Search, SelectedCategory.Id, token);
dto.Products.ForEach(d => PageDto.Add(d));
if (PageDto.Count == 20)
PageCount = 2;
}
catch (ApiException ex)
{
var exe = await ex.GetContentAsAsync<ApiResult>();
_snackbar.Add(exe != null ? exe.Message : ex.Content, Severity.Error);
}
catch (Exception e)
{
_snackbar.Add(e.Message, Severity.Error);
}
finally
{
IsProcessing = false;
}
} }
public async Task ClearProductCategorySearch() public async Task ClearProductCategorySearch()
{ {
SelectedCategory = null; SelectedCategory = null;
await GetEntitiesAsync(); try
{
IsProcessing = true;
var token = await _userUtility.GetBearerTokenAsync();
if (token == null)
throw new Exception("Token is null");
CurrentPage = 0;
PageCount = 1;
PageDto.Clear();
GetProductsResponseDto dto = await _restWrapper.ProductRestApi.ReadAll(CurrentPage, Search, null, token);
dto.Products.ForEach(d => PageDto.Add(d));
if (PageDto.Count == 20)
PageCount = 2;
}
catch (ApiException ex)
{
var exe = await ex.GetContentAsAsync<ApiResult>();
_snackbar.Add(exe != null ? exe.Message : ex.Content, Severity.Error);
}
catch (Exception e)
{
_snackbar.Add(e.Message, Severity.Error);
}
finally
{
IsProcessing = false;
}
} }
public async Task DisplayedChanged(ProductSDto product) public async Task DisplayedChanged(ProductSDto product)
@ -211,49 +338,16 @@ public class ProductsPageViewModel(
var token = await _userUtility.GetBearerTokenAsync(); var token = await _userUtility.GetBearerTokenAsync();
if (token == null) if (token == null)
throw new Exception("Token is null"); throw new Exception("Token is null");
await restWrapper.ProductRestApi.ChangeDisplayedAsync(product.Id, product.BeDisplayed, token); await _restWrapper.ProductRestApi.ChangeDisplayedAsync(product.Id, product.BeDisplayed, token);
} }
catch (ApiException ex) catch (ApiException ex)
{ {
var exe = await ex.GetContentAsAsync<ApiResult>(); var exe = await ex.GetContentAsAsync<ApiResult>();
snackbar.Add(exe != null ? exe.Message : ex.Content, Severity.Error); _snackbar.Add(exe != null ? exe.Message : ex.Content, Severity.Error);
} }
catch (Exception e) catch (Exception e)
{ {
snackbar.Add(e.Message, Severity.Error); _snackbar.Add(e.Message, Severity.Error);
}
}
public async Task ProductEnableChanged(bool? arg)
{
if (arg == null)
return;
IsEnable = arg.Value;
CurrentPage = 0;
await GetEntitiesAsync();
}
public async Task ChangeProductCostAsync(ProductSDto product,double cost)
{
try
{
var token = await _userUtility.GetBearerTokenAsync();
if (token == null)
throw new Exception("Token is null");
await restWrapper.ProductRestApi.ChangeCostAsync(product.Id, cost, token);
product.Cost = cost;
}
catch (ApiException ex)
{
var exe = await ex.GetContentAsAsync<ApiResult>();
snackbar.Add(exe != null ? exe.Message : ex.Content, Severity.Error);
}
catch (Exception e)
{
snackbar.Add(e.Message, Severity.Error);
} }
} }
} }

View File

@ -1,74 +0,0 @@
@page "/reviews"
@attribute [Microsoft.AspNetCore.Authorization.Authorize]
@inject IDialogService DialogService
@inject NavigationManager NavigationManager
@inject ISnackbar Snackbar
@inject IUserUtility UserUtility
@inject IRestWrapper RestWrapper
<MudStack class="h-full w-full p-8">
<MudGrid>
<MudItem xs="12">
<MudStack Row="true" class="mb-5">
<MudText Typo="Typo.h4">نظراتـــــــ</MudText>
<MudSpacer />
</MudStack>
<MudPaper>
<MudDataGrid FixedFooter="true" FixedHeader="true" Striped="true"
T="CommentSDto" Items="@ViewModel.PageDto" CurrentPage="@ViewModel.CurrentPage"
RowsPerPage="20" Filterable="false" Loading="@ViewModel.IsProcessing"
SortMode="@SortMode.None" Groupable="false">
<Columns>
<PropertyColumn Title="عنوان" Property="arg => arg.Title" />
<PropertyColumn Title="نظر" Property="arg => arg.Content" />
<PropertyColumn Title="نام نظر دهنده" Property="arg => arg.UserFullName" />
<TemplateColumn Title="تاریخ ثبت">
<CellTemplate>
<p>@context.Item.CreatedAt.ToPersianDateTime().ToLongDateString()</p>
</CellTemplate>
</TemplateColumn>
<TemplateColumn CellClass="d-flex justify-end">
<CellTemplate>
<MudStack Row="true">
<MudButton Variant="Variant.Outlined"
class="@(context.Item.IsConfirmed ? "visible":"hidden")"
Color="Color.Primary"
OnClick="@(async()=>await ViewModel.ConfirmAsync(context.Item))">تایید کردن</MudButton>
<MudIconButton Icon="@Icons.Material.Filled.RemoveRedEye"
Size="@Size.Small"
class="px-2"
Variant="@Variant.Outlined"
Color="@Color.Info"
OnClick="@(async()=>await ViewModel.ShowAsync(context.Item))" />
</MudStack>
</CellTemplate>
</TemplateColumn>
</Columns>
<PagerContent>
<MudStack Row="true" class="w-full">
<MudPagination Rectangular="true" Variant="Variant.Filled" Count="@ViewModel.PageCount"
SelectedChanged="@ViewModel.ChangePageAsync" class="mx-auto my-4" />
</MudStack>
</PagerContent>
</MudDataGrid>
</MudPaper>
</MudItem>
</MudGrid>
</MudStack>
@code
{
public ReviewsPageViewModel ViewModel { get; set; }
protected override async Task OnInitializedAsync()
{
ViewModel = new ReviewsPageViewModel(NavigationManager, Snackbar, UserUtility, RestWrapper, DialogService);
await ViewModel.InitializeAsync();
await base.OnInitializedAsync();
}
}

View File

@ -1,125 +0,0 @@
namespace Netina.AdminPanel.PWA.Pages;
public class ReviewsPageViewModel(NavigationManager navigationManager, ISnackbar snackbar, IUserUtility userUtility, IRestWrapper restWrapper, IDialogService dialogService)
: BaseViewModel<ObservableCollection<CommentSDto>>(userUtility)
{
public int CurrentPage = 0;
public int PageCount = 1;
public override async Task InitializeAsync()
{
try
{
IsProcessing = true;
PageDto.Clear();
var token = await _userUtility.GetBearerTokenAsync();
if (token == null)
throw new Exception("Token is null");
var dto = await restWrapper.ReviewRestApi.ReadAll(CurrentPage, token);
dto.ForEach(d => PageDto.Add(d));
if (PageDto.Count == 15)
PageCount = 2;
}
catch (ApiException ex)
{
var exe = await ex.GetContentAsAsync<ApiResult>();
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 ConfirmAsync(CommentSDto review)
{
try
{
IsProcessing = true;
var token = await _userUtility.GetBearerTokenAsync();
if (token == null)
throw new Exception("Token is null");
await restWrapper.ReviewRestApi.ConfirmAsync(review.Id, token);
review.IsConfirmed = true;
}
catch (ApiException ex)
{
var exe = await ex.GetContentAsAsync<ApiResult>();
snackbar.Add(exe != null ? exe.Message : ex.Content, Severity.Error);
}
catch (Exception e)
{
snackbar.Add(e.Message, Severity.Error);
}
finally
{
IsProcessing = false;
}
}
public async Task ShowAsync(CommentSDto review)
{
DialogOptions maxWidth = new DialogOptions() { MaxWidth = MaxWidth.Medium, FullWidth = true, DisableBackdropClick = true };
var parameters = new DialogParameters<ReviewActionDialogBox>();
parameters.Add(x => x.Review, review);
var dialogResult = await dialogService.ShowAsync<ReviewActionDialogBox>($"", parameters, maxWidth);
var result = await dialogResult.Result;
if (!result.Canceled && result.Data is bool and true)
{
await InitializeAsync();
}
}
public async Task ChangePageAsync(int page)
{
CurrentPage = page - 1;
if (CurrentPage > PageCount - 2)
{
try
{
IsProcessing = true;
var token = await _userUtility.GetBearerTokenAsync();
if (token == null)
throw new Exception("Token is null");
List<CommentSDto> dto = new List<CommentSDto>();
dto = await restWrapper.ReviewRestApi.ReadAll(CurrentPage, token);
dto.ForEach(d => PageDto.Add(d));
if (PageDto.Count % 20 == 0)
PageCount = CurrentPage + 2;
}
catch (ApiException ex)
{
var exe = await ex.GetContentAsAsync<ApiResult>();
snackbar.Add(exe != null ? exe.Message : ex.Content, Severity.Error);
}
catch (Exception e)
{
snackbar.Add(e.Message, Severity.Error);
}
finally
{
IsProcessing = false;
}
}
}
}

View File

@ -1,4 +1,4 @@
@page "/product/shipping" @page "/inventory/shipping"
@attribute [Microsoft.AspNetCore.Authorization.Authorize] @attribute [Microsoft.AspNetCore.Authorization.Authorize]
@inject IDialogService DialogService @inject IDialogService DialogService
@ -7,7 +7,7 @@
@inject IUserUtility UserUtility @inject IUserUtility UserUtility
@inject IRestWrapper RestWrapper @inject IRestWrapper RestWrapper
<MudStack class="h-full w-full p-8"> <MudStack class="w-full p-8 h-screen bg-[--mud-palette-background-grey]">
<MudGrid> <MudGrid>
<MudItem xs="12"> <MudItem xs="12">
<MudGrid Row="true" class="mb-5"> <MudGrid Row="true" class="mb-5">
@ -87,7 +87,7 @@
<MudStack Row="true" class="w-full"> <MudStack Row="true" class="w-full">
<MudPagination Rectangular="true" Variant="Variant.Filled" Count="@ViewModel.PageCount" <MudPagination Rectangular="true" Variant="Variant.Filled" Count="@ViewModel.PageCount"
SelectedChanged="@ViewModel.ChangePageAsync" class="mx-auto my-4" /> SelectedChanged="@ViewModel.ChangePageAsync" class="my-4 mx-auto" />
</MudStack> </MudStack>
</PagerContent> </PagerContent>

View File

@ -7,19 +7,19 @@
@inject IUserUtility UserUtility @inject IUserUtility UserUtility
@inject IRestWrapper RestWrapper @inject IRestWrapper RestWrapper
<MudStack class="h-full w-full p-8"> <MudStack class="w-full p-8 h-screen bg-[--mud-palette-background-grey]">
<MudGrid> <MudGrid>
<MudItem xs="12"> <MudItem xs="12">
<MudPaper class="px-5 py-5"> <MudPaper class="px-5 py-5">
<MudStack Row="true"> <MudStack Row="true">
<MudStack class="mx-2 mb-5"> <MudStack class="mb-5 mx-2">
<MudText Typo="Typo.h4">فروشـــــگاه من</MudText> <MudText Typo="Typo.h4">فروشـــــگاه من</MudText>
<MudText Typo="Typo.caption">شما می توانید اطلاعات فروشگاه خود را ویرایش نمایید</MudText> <MudText Typo="Typo.caption">شما می توانید اطلاعات فروشگاه خود را ویرایش نمایید</MudText>
</MudStack> </MudStack>
<MudSpacer/> <MudSpacer/>
<BaseButtonUi Size="Size.Large" <BaseButtonUi Size="Size.Large"
OnClickCallback="ViewModel.SubmitShopSettingAsync" OnClickCallback="ViewModel.SubmitShopSettingAsync"
class="mb-8 mt-2 w-64 rounded-md" class="mt-2 mb-8 w-64 rounded-md"
IsProcessing="@ViewModel.IsProcessing" IsProcessing="@ViewModel.IsProcessing"
Icon="@Icons.Material.Outlined.Check" Icon="@Icons.Material.Outlined.Check"
Content="ثبتـــ اطلاعات" Variant="Variant.Filled" Color="Color.Success" /> Content="ثبتـــ اطلاعات" Variant="Variant.Filled" Color="Color.Success" />
@ -62,9 +62,9 @@
<ProgressIndicatorInPopoverTemplate> <ProgressIndicatorInPopoverTemplate>
<MudList Clickable="false"> <MudList Clickable="false">
<MudListItem> <MudListItem>
<div class="mx-auto flex w-full flex-row"> <div class="flex flex-row w-full mx-auto">
<MudProgressCircular class="my-auto -ml-4 mr-1" Size="Size.Small" Indeterminate="true" /> <MudProgressCircular class="my-auto mr-1 -ml-4" Size="Size.Small" Indeterminate="true" />
<p class="text-md mx-auto my-1 font-bold">منتظر بمانید</p> <p class="font-bold my-1 mx-auto text-md">منتظر بمانید</p>
</div> </div>
</MudListItem> </MudListItem>
</MudList> </MudList>
@ -84,9 +84,9 @@
<ProgressIndicatorInPopoverTemplate> <ProgressIndicatorInPopoverTemplate>
<MudList Clickable="false"> <MudList Clickable="false">
<MudListItem> <MudListItem>
<div class="mx-auto flex w-full flex-row"> <div class="flex flex-row w-full mx-auto">
<MudProgressCircular class="my-auto -ml-4 mr-1" Size="Size.Small" Indeterminate="true" /> <MudProgressCircular class="my-auto mr-1 -ml-4" Size="Size.Small" Indeterminate="true" />
<p class="text-md mx-auto my-1 font-bold">منتظر بمانید</p> <p class="font-bold my-1 mx-auto text-md">منتظر بمانید</p>
</div> </div>
</MudListItem> </MudListItem>
</MudList> </MudList>
@ -111,20 +111,20 @@
<MudText Typo="Typo.body1">سایز لوگو شما باید 512 * 512 باشد و به شکل مربع ، تا جایگیری مناسبی داشته باشد</MudText> <MudText Typo="Typo.body1">سایز لوگو شما باید 512 * 512 باشد و به شکل مربع ، تا جایگیری مناسبی داشته باشد</MudText>
<BaseButtonUi Variant="Variant.Outlined" Content="اپلود و تغییر لوگو" OnClickCallback="async () => await ViewModel.SelectFileAsync()" /> <BaseButtonUi Variant="Variant.Outlined" Content="اپلود و تغییر لوگو" OnClickCallback="async () => await ViewModel.SelectFileAsync()" />
</MudStack> </MudStack>
<MudImage Src="@ViewModel.ShopSetting.LogoUrl" Width="150" Height="150" Elevation="25" Class="ma-4 rounded-lg" /> <MudImage Src="@ViewModel.ShopSetting.LogoUrl" Width="150" Height="150" Elevation="25" Class="rounded-lg ma-4" />
</MudStack> </MudStack>
</MudItem> </MudItem>
</MudGrid> </MudGrid>
</MudPaper> </MudPaper>
<MudPaper class="mt-8 px-5 py-5"> <MudPaper class="px-5 mt-8 py-5">
<MudStack Row="true"> <MudStack Row="true">
<MudStack class="mx-2 mb-5"> <MudStack class="mb-5 mx-2">
<MudText Typo="Typo.h4">تنظیمات درگاه پرداخت</MudText> <MudText Typo="Typo.h4">تنظیمات درگاه پرداخت</MudText>
<MudText Typo="Typo.caption">شما می توانید اطلاعات درگاه پرداخت خود را ویرایش نمایید</MudText> <MudText Typo="Typo.caption">شما می توانید اطلاعات درگاه پرداخت خود را ویرایش نمایید</MudText>
</MudStack> </MudStack>
<MudSpacer /> <MudSpacer />
<BaseButtonUi Size="Size.Large" class="mb-8 mt-2 w-64 rounded-md" <BaseButtonUi Size="Size.Large" class="mt-2 mb-8 w-64 rounded-md"
OnClickCallback="ViewModel.SubmitPaymentSettingAsync" OnClickCallback="ViewModel.SubmitPaymentSettingAsync"
IsProcessing="@ViewModel.IsProcessing" IsProcessing="@ViewModel.IsProcessing"
Icon="@Icons.Material.Outlined.Check" Content="ثبتـــ اطلاعات" Icon="@Icons.Material.Outlined.Check" Content="ثبتـــ اطلاعات"

View File

@ -7,7 +7,7 @@
@inject IUserUtility UserUtility @inject IUserUtility UserUtility
@inject IRestWrapper RestWrapper @inject IRestWrapper RestWrapper
<MudStack class="h-full w-full p-8"> <MudStack class="w-full p-8 h-screen bg-[--mud-palette-background-grey]">
<MudGrid> <MudGrid>
<MudItem xs="12" md="6"> <MudItem xs="12" md="6">
@ -60,7 +60,7 @@
<MudStack Row="true" class="w-full"> <MudStack Row="true" class="w-full">
<MudPagination Rectangular="true" Variant="Variant.Filled" Count="@ViewModel.UsersPageCount" <MudPagination Rectangular="true" Variant="Variant.Filled" Count="@ViewModel.UsersPageCount"
SelectedChanged="@ViewModel.ChangeUserPageAsync" class="mx-auto my-4" /> SelectedChanged="@ViewModel.ChangeUserPageAsync" class="my-4 mx-auto" />
</MudStack> </MudStack>
</PagerContent> </PagerContent>
@ -110,7 +110,7 @@
<MudStack Row="true" class="w-full"> <MudStack Row="true" class="w-full">
<MudPagination Rectangular="true" Variant="Variant.Filled" Count="@ViewModel.RolesPageCount" <MudPagination Rectangular="true" Variant="Variant.Filled" Count="@ViewModel.RolesPageCount"
SelectedChanged="@ViewModel.ChangeRolePageAsync" class="mx-auto my-4"/> SelectedChanged="@ViewModel.ChangeRolePageAsync" class="my-4 mx-auto"/>
</MudStack> </MudStack>
</PagerContent> </PagerContent>

View File

@ -1,9 +1,9 @@
namespace Netina.AdminPanel.PWA.Services.RestServices; namespace Netina.AdminPanel.PWA.Services.RestServices;
public interface ICrudApiRest<T, TKey> where T : class public interface ICrudApiRest<T, in TKey> where T : class
{ {
[Post("")] [Post("")]
Task<TKey> Create<TCreateCommand>([Body] TCreateCommand payload, [Header("Authorization")] string authorization); Task Create<TCreateCommand>([Body] TCreateCommand payload, [Header("Authorization")] string authorization);
[Get("")] [Get("")]
Task<List<T>> ReadAll([Query] int page,[Header("Authorization")] string authorization); Task<List<T>> ReadAll([Query] int page,[Header("Authorization")] string authorization);
@ -24,7 +24,7 @@ public interface ICrudApiRest<T, TKey> where T : class
public interface ICrudDtoApiRest<T, TDto, in TKey> where T : class where TDto : class public interface ICrudDtoApiRest<T, TDto, in TKey> where T : class where TDto : class
{ {
[Post("")] [Post("")]
Task Create<TCreateCommand>([Body] TCreateCommand payload, [Header("Authorization")] string authorization); Task Create([Body] T payload, [Header("Authorization")] string authorization);
[Post("")] [Post("")]
Task Create([Body] TDto payload, [Header("Authorization")] string authorization); Task Create([Body] TDto payload, [Header("Authorization")] string authorization);

View File

@ -1,6 +0,0 @@
namespace Netina.AdminPanel.PWA.Services.RestServices;
public interface ICustomerRestApi
{
}

View File

@ -1,21 +0,0 @@
using Netina.Domain.MartenEntities.Faqs;
namespace Netina.AdminPanel.PWA.Services.RestServices;
public interface IFaqApiRest
{
[Delete("/{id}")]
Task Delete(Guid id, [Header("Authorization")] string token);
[Post("")]
Task Create([Body] BaseFaq faq, [Header("Authorization")] string token);
[Put("")]
Task Update([Body] BaseFaq faq, [Header("Authorization")] string token);
[Get("")]
Task<List<BaseFaq>> GetFaqs([Query]int page,[Header("Authorization")] string token);
[Get("/slug")]
Task<BaseFaq> ReadOne([Query]string slug);
}

View File

@ -3,22 +3,20 @@
public interface IOrderRestApi public interface IOrderRestApi
{ {
[Get("")] [Get("")]
Task<List<OrderSDto>> ReadAll([Query]int page, Task<List<OrderSDto>> ReadAll([Query]int page, [Query] string? factorCode, [Query] long? selectedDate, [Query] OrderStatus? orderStatus, [Query] OrderQueryDateFilter? dateFilter, [Header("Authorization")] string authorization);
[Header("Authorization")] string authorization,
[Query] string? factorCode = null,
[Query] long? selectedDate = null, [Get("")]
[Query] OrderStatus? orderStatus = null, Task<List<OrderSDto>> ReadAll([Query] int page, [Header("Authorization")] string authorization);
[Query] OrderQueryDateFilter? dateFilter = null,
[Query] bool? orderBags = null);
[Get("/{id}")] [Get("/{id}")]
Task<OrderLDto> ReadOne(Guid id, [Header("Authorization")] string authorization); Task<OrderLDto> ReadOne(Guid id, [Header("Authorization")] string authorization);
[Post("/{id}/confirm")] [Post("/{id}/confirm")]
Task<bool> ConfirmOrderStepAsync(Guid id,[Query] OrderStatus nextOrderStatus, [Header("Authorization")] string authorization); Task<bool> ConfirmOrderStepAsync(Guid id,[Query] OrderStatus nextOrderStatus, [Header("Authorization")] string authorization);
[Post("/{id}/cancel")]
Task<bool> CancelOrderStepAsync(Guid id ,[Header("Authorization")] string authorization);
[Post("/{id}/confirm")] [Post("/{id}/confirm")]
Task<bool> ConfirmOrderStepAsync(Guid id, [Query] OrderStatus nextOrderStatus, [Query]string trackingCode, [Header("Authorization")] string authorization); Task<bool> ConfirmOrderStepAsync(Guid id, [Query] OrderStatus nextOrderStatus, [Query]string trackingCode, [Header("Authorization")] string authorization);
[Get("/{id}/invoice")]
Task<HttpContent> GetOrderInvoice(Guid id, [Header("Authorization")] string authorization);
} }

View File

@ -10,7 +10,7 @@ public interface IPageRestApi
Task<BasePageSDto> ReadByType([Query] string type, [Header("Authorization")] string authorization); Task<BasePageSDto> ReadByType([Query] string type, [Header("Authorization")] string authorization);
[Get("/{id}")] [Get("/{id}")]
Task<BasePageLDto> ReadById(Guid id, [Header("Authorization")] string authorization); Task<BasePageSDto> ReadById(Guid id, [Header("Authorization")] string authorization);
[Post("")] [Post("")]
Task CreatePage([Body] PageActionRequestDto request, [Header("Authorization")] string authorization); Task CreatePage([Body] PageActionRequestDto request, [Header("Authorization")] string authorization);

View File

@ -8,8 +8,6 @@ public interface IProductCategoryRestApi
[Get("")] [Get("")]
Task<List<ProductCategorySDto>> ReadAll([Query] int page); Task<List<ProductCategorySDto>> ReadAll([Query] int page);
[Get("")] [Get("")]
Task<List<ProductCategorySDto>> ReadAll([Query] bool sortByMain);
[Get("")]
Task<List<ProductCategorySDto>> ReadAll([Query] int page,[Query]string categoryName); Task<List<ProductCategorySDto>> ReadAll([Query] int page,[Query]string categoryName);
[Get("")] [Get("")]
Task<List<ProductCategorySDto>> ReadAll([Query] string categoryName); Task<List<ProductCategorySDto>> ReadAll([Query] string categoryName);

View File

@ -2,24 +2,17 @@
public interface IProductRestApi public interface IProductRestApi
{ {
[Put("/{productId}/displayed")] [Put("/{productId}")]
Task<bool> ChangeDisplayedAsync(Guid productId, [Query]bool beDisplayed, [Header("Authorization")]string authorization); Task<bool> ChangeDisplayedAsync(Guid productId, [Query]bool beDisplayed, [Header("Authorization")]string authorization);
[Put("/{productId}/cost")]
Task<bool> ChangeCostAsync(Guid productId, [Query] double cost, [Header("Authorization")] string authorization);
[Get("/{productId}")] [Get("/{productId}")]
Task<GetProductResponseDto> ReadOne(Guid productId); Task<GetProductResponseDto> ReadOne(Guid productId);
[Get("/{productId}/sub")]
Task<List<SubProductSDto>> GetSubProductsAsync(Guid productId);
[Get("")] [Get("")]
Task<GetProductsResponseDto> ReadAll([Query] string productName, [Header("Authorization")] string authorization); Task<GetProductsResponseDto> ReadAll([Query] string productName, [Header("Authorization")] string authorization);
[Get("")] [Get("")]
Task<GetProductsResponseDto> ReadAll([Query] int page, [Query] string? productName, [Query] Guid? categoryId, [Query] bool? isActive, [Header("Authorization")] string authorization); Task<GetProductsResponseDto> ReadAll([Query] int page, [Query] string? productName, [Query] Guid? categoryId, [Header("Authorization")] string authorization);
[Get("")] [Get("")]
Task<GetProductsResponseDto> ReadAll([Query] string productName, [Query] Guid categoryId, [Header("Authorization")] string authorization); Task<GetProductsResponseDto> ReadAll([Query] string productName, [Query] Guid categoryId, [Header("Authorization")] string authorization);

View File

@ -14,7 +14,6 @@ public interface IRestWrapper
public IFileRestApi FileRestApi { get; } public IFileRestApi FileRestApi { get; }
public IBlogRestApi BlogRestApi { get; } public IBlogRestApi BlogRestApi { get; }
public IDiscountRestApi DiscountRest { get; } public IDiscountRestApi DiscountRest { get; }
public IReviewRestApi ReviewRestApi { get; }
public IBlogCategoryRestApi BlogCategoryRestApi { get; } public IBlogCategoryRestApi BlogCategoryRestApi { get; }
public IRoleRestApi RoleRestApi { get; } public IRoleRestApi RoleRestApi { get; }
public IOrderRestApi OrderRestApi { get; } public IOrderRestApi OrderRestApi { get; }
@ -24,5 +23,4 @@ public interface IRestWrapper
public IDashboardApiRest DashboardApiRest { get; } public IDashboardApiRest DashboardApiRest { get; }
public ISettingRestApi SettingRestApi { get; } public ISettingRestApi SettingRestApi { get; }
public IDistrictApiRest DistrictApiRest { get; } public IDistrictApiRest DistrictApiRest { get; }
public IFaqApiRest FaqApiRest { get; }
} }

View File

@ -1,17 +0,0 @@
namespace Netina.AdminPanel.PWA.Services.RestServices;
public interface IReviewRestApi
{
[Get("/{id}")]
Task<CommentSDto> ReadOne(Guid id, [Header("Authorization")] string authorization);
[Get("")]
Task<List<CommentSDto>> ReadAll([Query] int page, [Header("Authorization")] string authorization);
[Post("")]
Task<Guid> CreateAsync([Body]CreateCommentCommand request, [Header("Authorization")] string authorization);
[Put("/confirm/{id}")]
Task<Guid> ConfirmAsync(Guid id, [Header("Authorization")] string authorization);
}

View File

@ -1,9 +1,12 @@
namespace Netina.AdminPanel.PWA.Services.RestServices; namespace Netina.AdminPanel.PWA.Services.RestServices;
public class RestWrapper(IConfiguration configuration) : IRestWrapper public class RestWrapper : IRestWrapper
{ {
private string baseApiAddress = configuration.GetValue<string>("ApiUrl") ?? string.Empty; private string baseApiAddress;
public RestWrapper(IConfiguration configuration)
{
baseApiAddress = configuration.GetValue<string>("ApiUrl") ?? string.Empty;
}
private static RefitSettings setting = new RefitSettings(new NewtonsoftJsonContentSerializer(new JsonSerializerSettings private static RefitSettings setting = new RefitSettings(new NewtonsoftJsonContentSerializer(new JsonSerializerSettings
{ {
Formatting = Newtonsoft.Json.Formatting.Indented, Formatting = Newtonsoft.Json.Formatting.Indented,
@ -27,7 +30,6 @@ public class RestWrapper(IConfiguration configuration) : IRestWrapper
public IFileRestApi FileRestApi => RestService.For<IFileRestApi>($"{baseApiAddress}{Address.FileController}", setting); public IFileRestApi FileRestApi => RestService.For<IFileRestApi>($"{baseApiAddress}{Address.FileController}", setting);
public IBlogRestApi BlogRestApi => RestService.For<IBlogRestApi>($"{baseApiAddress}{Address.BlogController}", setting); public IBlogRestApi BlogRestApi => RestService.For<IBlogRestApi>($"{baseApiAddress}{Address.BlogController}", setting);
public IDiscountRestApi DiscountRest => RestService.For<IDiscountRestApi>($"{baseApiAddress}{Address.DiscountController}",setting); public IDiscountRestApi DiscountRest => RestService.For<IDiscountRestApi>($"{baseApiAddress}{Address.DiscountController}",setting);
public IReviewRestApi ReviewRestApi => RestService.For<IReviewRestApi>($"{baseApiAddress}{Address.CommentController}", setting);
public IBlogCategoryRestApi BlogCategoryRestApi => RestService.For<IBlogCategoryRestApi>($"{baseApiAddress}{Address.BlogCategoryController}", setting); public IBlogCategoryRestApi BlogCategoryRestApi => RestService.For<IBlogCategoryRestApi>($"{baseApiAddress}{Address.BlogCategoryController}", setting);
public IRoleRestApi RoleRestApi => RestService.For<IRoleRestApi>($"{baseApiAddress}{Address.RoleController}", setting); public IRoleRestApi RoleRestApi => RestService.For<IRoleRestApi>($"{baseApiAddress}{Address.RoleController}", setting);
public IOrderRestApi OrderRestApi => RestService.For<IOrderRestApi>($"{baseApiAddress}{Address.OrderController}", setting); public IOrderRestApi OrderRestApi => RestService.For<IOrderRestApi>($"{baseApiAddress}{Address.OrderController}", setting);
@ -37,5 +39,4 @@ public class RestWrapper(IConfiguration configuration) : IRestWrapper
public ISettingRestApi SettingRestApi => RestService.For<ISettingRestApi>($"{baseApiAddress}{Address.SettingController}", setting); public ISettingRestApi SettingRestApi => RestService.For<ISettingRestApi>($"{baseApiAddress}{Address.SettingController}", setting);
public IDashboardApiRest DashboardApiRest => RestService.For<IDashboardApiRest>($"{baseApiAddress}{Address.DashboardController}", setting); public IDashboardApiRest DashboardApiRest => RestService.For<IDashboardApiRest>($"{baseApiAddress}{Address.DashboardController}", setting);
public IDistrictApiRest DistrictApiRest => RestService.For<IDistrictApiRest>($"{baseApiAddress}{Address.DistrictController}", setting); public IDistrictApiRest DistrictApiRest => RestService.For<IDistrictApiRest>($"{baseApiAddress}{Address.DistrictController}", setting);
public IFaqApiRest FaqApiRest => RestService.For<IFaqApiRest>($"{baseApiAddress}{Address.FaqController}", setting);
} }

View File

@ -20,8 +20,3 @@
@using Netina.AdminPanel.PWA.Components.Originals @using Netina.AdminPanel.PWA.Components.Originals
@using Netina.Domain.Models.Claims @using Netina.Domain.Models.Claims
@using MudBlazor.Services @using MudBlazor.Services
@using Netina.Domain.MartenEntities.Faqs
@using Netina.AdminPanel.PWA.Components.ItemTemplates
@using Netina.AdminPanel.PWA.Models.Api
@using Netina.AdminPanel.PWA.Models
@using Netina.Domain.Entities.Blogs

File diff suppressed because it is too large Load Diff

View File

@ -1,10 +1,32 @@
{ {
"dependencies": { "dependencies": {
"autoprefixer": "^10.4.21", "@ckeditor/ckeditor5-alignment": "41.0.0",
"@ckeditor/ckeditor5-autoformat": "41.0.0",
"@ckeditor/ckeditor5-basic-styles": "41.0.0",
"@ckeditor/ckeditor5-block-quote": "41.0.0",
"@ckeditor/ckeditor5-editor-classic": "41.0.0",
"@ckeditor/ckeditor5-essentials": "41.0.0",
"@ckeditor/ckeditor5-font": "41.0.0",
"@ckeditor/ckeditor5-heading": "41.0.0",
"@ckeditor/ckeditor5-horizontal-line": "41.0.0",
"@ckeditor/ckeditor5-html-support": "^41.0.0",
"@ckeditor/ckeditor5-image": "41.0.0",
"@ckeditor/ckeditor5-indent": "41.0.0",
"@ckeditor/ckeditor5-link": "41.0.0",
"@ckeditor/ckeditor5-list": "41.0.0",
"@ckeditor/ckeditor5-media-embed": "41.0.0",
"@ckeditor/ckeditor5-paragraph": "41.0.0",
"@ckeditor/ckeditor5-paste-from-office": "41.0.0",
"@ckeditor/ckeditor5-table": "41.0.0",
"@ckeditor/ckeditor5-typing": "41.0.0",
"@ckeditor/ckeditor5-undo": "41.0.0",
"@ckeditor/ckeditor5-upload": "41.0.0",
"@ckeditor/ckeditor5-word-count": "41.0.0",
"autoprefixer": "^10.4.17",
"flowbite": "^2.2.1", "flowbite": "^2.2.1",
"postcss": "^8.5.3", "postcss": "^8.4.33",
"postcss-cli": "^11.0.1", "postcss-cli": "^11.0.0",
"tailwindcss": "^3.4.17" "tailwindcss": "^3.4.3"
}, },
"name": "netina.admin.pwa", "name": "netina.admin.pwa",
"version": "1.0.0", "version": "1.0.0",

View File

@ -29,6 +29,7 @@ module.exports = {
} }
}, },
plugins: [ plugins: [
require('@tailwindcss/typography'),
require('flowbite/plugin') require('flowbite/plugin')
], ],
} }

View File

@ -4,12 +4,10 @@
"versionName": "چرتکه", "versionName": "چرتکه",
"description": "", "description": "",
"features": [ "features": [
"تغییر در صفحه دسته بندی ها", ""
"افزودن صفحه ثبت سریع کالاها"
], ],
"bugFixes": [ "bugFixes": [
"نمایش اطلاعات صحیح در صفحه سفارشات", "نمایش اطلاعات صحیح در صفحه سفارشات",
"رفع مشکلات رایج در صفحات در سایزهای مختلف",
"رفع مشکلات رسپانسیو صفحه سفارشات", "رفع مشکلات رسپانسیو صفحه سفارشات",
"رفع مشکلات رسپانسیو دیالوگ یک سفارش", "رفع مشکلات رسپانسیو دیالوگ یک سفارش",
"رفع مشکلات رسپانسیو دیالوگ محصول" "رفع مشکلات رسپانسیو دیالوگ محصول"

View File

@ -10,15 +10,9 @@
}, },
"WebSiteUrl": "https://vesmeh.com", "WebSiteUrl": "https://vesmeh.com",
"AdminPanelBaseUrl": "https://admin.vesmeh.com", "AdminPanelBaseUrl": "https://admin.vesmeh.com",
"StorageBaseUrl": "https://storage.vesmeh.com", "StorageBaseUrl": "https://storage.vesmeh.com/",
//"ApiUrl": "https://api.vesmeh.com/api", //"ApiUrl": "https://api.vesmeh.com/api"
"ApiUrl": "http://localhost:32770/api", "ApiUrl": "http://localhost:32770/api"
//"WebSiteUrl": "https://bonsaigallery.shop",
//"AdminPanelBaseUrl": "https://admin.bonsaigallery.shop",
//"StorageBaseUrl": "https://storage.bonsaigallery.shop/",
//"ApiUrl": "https://api.bonsaigallery.shop/api",
//"IsShop": true
//"WebSiteUrl": "https://hamyanedalat.com", //"WebSiteUrl": "https://hamyanedalat.com",
//"AdminPanelBaseUrl": "https://admin.hamyanedalat.com", //"AdminPanelBaseUrl": "https://admin.hamyanedalat.com",

View File

@ -12,5 +12,5 @@
"AdminPanelBaseUrl": "https://admin.hamyanedalat.com", "AdminPanelBaseUrl": "https://admin.hamyanedalat.com",
"StorageBaseUrl": "https://storage.hamyanedalat.com", "StorageBaseUrl": "https://storage.hamyanedalat.com",
"ApiUrl": "https://api.hamyanedalat.com/api", "ApiUrl": "https://api.hamyanedalat.com/api",
"IsShop": true "IsShop": false
} }

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,322 +0,0 @@
import {
ClassicEditor,
AccessibilityHelp,
Alignment,
Autoformat,
AutoImage,
AutoLink,
Autosave,
BalloonToolbar,
BlockQuote,
Bold,
CodeBlock,
Essentials,
FindAndReplace,
FontBackgroundColor,
FontColor,
FontFamily,
FontSize,
Heading,
Highlight,
HorizontalLine,
HtmlEmbed,
ImageBlock,
ImageCaption,
ImageInline,
ImageInsert,
ImageInsertViaUrl,
ImageResize,
ImageStyle,
ImageTextAlternative,
ImageToolbar,
ImageUpload,
Indent,
IndentBlock,
Italic,
Link,
LinkImage,
List,
ListProperties,
MediaEmbed,
Paragraph,
PasteFromOffice,
SelectAll,
ShowBlocks,
SimpleUploadAdapter,
SourceEditing,
SpecialCharacters,
SpecialCharactersArrows,
SpecialCharactersCurrency,
SpecialCharactersEssentials,
SpecialCharactersLatin,
SpecialCharactersMathematical,
SpecialCharactersText,
Strikethrough,
Table,
TableCaption,
TableCellProperties,
TableColumnResize,
TableProperties,
TableToolbar,
TextTransformation,
TodoList,
Underline,
Undo
} from '/assets/vendor/ckeditor5.js';
const editorConfig = {
toolbar: {
items: [
'undo',
'redo',
'|',
'sourceEditing',
'showBlocks',
'findAndReplace',
'selectAll',
'|',
'heading',
'|',
'fontSize',
'fontFamily',
'fontColor',
'fontBackgroundColor',
'|',
'bold',
'italic',
'underline',
'strikethrough',
'|',
'specialCharacters',
'horizontalLine',
'link',
'insertImage',
'mediaEmbed',
'insertTable',
'highlight',
'blockQuote',
'codeBlock',
'htmlEmbed',
'|',
'alignment',
'|',
'bulletedList',
'numberedList',
'todoList',
'outdent',
'indent',
'|',
'accessibilityHelp'
],
shouldNotGroupWhenFull: true
},
plugins: [
AccessibilityHelp,
Alignment,
Autoformat,
AutoImage,
AutoLink,
Autosave,
BalloonToolbar,
BlockQuote,
Bold,
CodeBlock,
Essentials,
FindAndReplace,
FontBackgroundColor,
FontColor,
FontFamily,
FontSize,
Heading,
Highlight,
HorizontalLine,
HtmlEmbed,
ImageBlock,
ImageCaption,
ImageInline,
ImageInsert,
ImageInsertViaUrl,
ImageResize,
ImageStyle,
ImageTextAlternative,
ImageToolbar,
ImageUpload,
Indent,
IndentBlock,
Italic,
Link,
LinkImage,
List,
ListProperties,
MediaEmbed,
Paragraph,
PasteFromOffice,
SelectAll,
ShowBlocks,
SimpleUploadAdapter,
SourceEditing,
SpecialCharacters,
SpecialCharactersArrows,
SpecialCharactersCurrency,
SpecialCharactersEssentials,
SpecialCharactersLatin,
SpecialCharactersMathematical,
SpecialCharactersText,
Strikethrough,
Table,
TableCaption,
TableCellProperties,
TableColumnResize,
TableProperties,
TableToolbar,
TextTransformation,
TodoList,
Underline,
Undo
],
simpleUpload: {
uploadUrl: 'https://api.vesmeh.com/api/file/ckeditor',
withCredentials: true,
headers: {
Authorization: 'xuwp4KzU1/YBoevpzgH0cz8+zLKQ+EOaYXeo4JtRxmVIuN7Hqxz97oQ398tNX68+'
}
},
balloonToolbar: ['bold', 'italic', '|', 'link', 'insertImage', '|', 'bulletedList', 'numberedList'],
fontFamily: {
supportAllValues: true
},
fontSize: {
options: [10, 12, 14, 'default', 18, 20, 22],
supportAllValues: true
},
heading: {
options: [
{
model: 'paragraph',
title: 'Paragraph',
class: 'ck-heading_paragraph'
},
{
model: 'heading1',
view: 'h1',
title: 'Heading 1',
class: 'ck-heading_heading1'
},
{
model: 'heading2',
view: 'h2',
title: 'Heading 2',
class: 'ck-heading_heading2'
},
{
model: 'heading3',
view: 'h3',
title: 'Heading 3',
class: 'ck-heading_heading3'
},
{
model: 'heading4',
view: 'h4',
title: 'Heading 4',
class: 'ck-heading_heading4'
},
{
model: 'heading5',
view: 'h5',
title: 'Heading 5',
class: 'ck-heading_heading5'
},
{
model: 'heading6',
view: 'h6',
title: 'Heading 6',
class: 'ck-heading_heading6'
}
]
},
image: {
toolbar: [
'toggleImageCaption',
'imageTextAlternative',
'|',
'imageStyle:inline',
'imageStyle:wrapText',
'imageStyle:breakText',
'|',
'resizeImage'
]
},
link: {
addTargetToExternalLinks: true,
defaultProtocol: 'https://',
decorators: {
toggleDownloadable: {
mode: 'manual',
label: 'Downloadable',
attributes: {
download: 'file'
}
}
}
},
list: {
properties: {
styles: true,
startIndex: true,
reversed: true
}
},
placeholder: 'متن خود را بنویسید یا کپی کنید',
table: {
contentToolbar: ['tableColumn', 'tableRow', 'mergeTableCells', 'tableProperties', 'tableCellProperties']
},
language: {
ui: 'en',
content: 'ar'
}
};
export function initializeCKEditor(data) {
if (!document.querySelector('.editor')) return;
if (window.editor) return;
ClassicEditor.create(document.querySelector('.editor'), editorConfig)
.then(editor => {
window.editor = editor;
window.editor.setData(data);
editor.editing.view.document.on('blur', () => {
if (GLOBAL.DotNetReference) {
GLOBAL.DotNetReference.invokeMethodAsync('MyMethod', window.editor.getData());
}
});
})
.catch(handleSampleError);
}
export function destroyEditor() {
if (window.editor) {
window.editor.destroy();
window.editor = null;
}
}
export function setData(data) {
if (window.editor) {
window.editor.setData(data);
}
}
function handleSampleError(error) {
const issueUrl = 'https://github.com/ckeditor/ckeditor5/issues';
const message = [
'Oops, something went wrong!',
`Please, report the following error on ${issueUrl} with the build id "pws0dnpd0jqj-zi42lsl7aqxa" and the error stack trace:`
].join('\n');
console.error(message);
console.error(error);
}
export var GLOBAL = {
DotNetReference: null,
SetDotnetReference: function (pDotNetReference) {
this.DotNetReference = pDotNetReference;
}
};

View File

@ -91,9 +91,9 @@
--color-primary: rgba(9, 16, 68, 1); --color-primary: rgba(9, 16, 68, 1);
--color-secondary: rgba(229, 159, 46, 1); --color-secondary: rgba(229, 159, 46, 1);
--color-background: rgba(243, 244, 246, 1); --color-background: rgba(243, 244, 246, 1);
} }
} }
.revert-tailwind { .revert-tailwind {
all: initial; all: initial;
} }
@ -113,16 +113,6 @@
scrollbar-width: none; /* Firefox */ scrollbar-width: none; /* Firefox */
} }
.auto-scrollbar {
-ms-overflow-style: auto; /* IE and Edge */
scrollbar-width: auto; /* Firefox */
}
.auto-scrollbar::-webkit-scrollbar {
display: block;
}
.mud-dialog-title { .mud-dialog-title {
font-family: iranyekan !important; font-family: iranyekan !important;
} }
@ -142,7 +132,7 @@ a, .btn-link {
} }
.btn:focus, .btn:active:focus, .btn-link.nav-link:focus, .form-control:focus, .form-check-input:focus { .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; box-shadow: 0 0 0 0.1rem white, 0 0 0 0.25rem #258cfb;
} }
.content { .content {

View File

@ -1,111 +1,5 @@
*, ::before, ::after { /*
--tw-border-spacing-x: 0; ! tailwindcss v3.4.3 | MIT License | https://tailwindcss.com
--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(63 131 248 / 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: ;
--tw-contain-size: ;
--tw-contain-layout: ;
--tw-contain-paint: ;
--tw-contain-style: ;
}
::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(63 131 248 / 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: ;
--tw-contain-size: ;
--tw-contain-layout: ;
--tw-contain-paint: ;
--tw-contain-style: ;
}/*
! tailwindcss v3.4.13 | MIT License | https://tailwindcss.com
*//* *//*
1. Prevent padding and border from affecting element width. (https://github.com/mozdevs/cssremedy/issues/4) 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) 2. Allow adding a border to an element by just adding a border-width. (https://github.com/tailwindcss/tailwindcss/pull/116)
@ -970,7 +864,116 @@ input:checked + .toggle-bg {
--color-primary: rgba(9, 16, 68, 1); --color-primary: rgba(9, 16, 68, 1);
--color-secondary: rgba(229, 159, 46, 1); --color-secondary: rgba(229, 159, 46, 1);
--color-background: rgba(243, 244, 246, 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(63 131 248 / 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: ;
--tw-contain-size: ;
--tw-contain-layout: ;
--tw-contain-paint: ;
--tw-contain-style: ;
}
::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(63 131 248 / 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: ;
--tw-contain-size: ;
--tw-contain-layout: ;
--tw-contain-paint: ;
--tw-contain-style: ;
}
.container { .container {
width: 100%; width: 100%;
} }
@ -1043,9 +1046,6 @@ input:checked + .toggle-bg {
.top-0 { .top-0 {
top: 0px; top: 0px;
} }
.\!z-\[9999\] {
z-index: 9999 !important;
}
.z-10 { .z-10 {
z-index: 10; z-index: 10;
} }
@ -1061,6 +1061,9 @@ input:checked + .toggle-bg {
.z-50 { .z-50 {
z-index: 50; z-index: 50;
} }
.m-1 {
margin: 0.25rem;
}
.m-1\.5 { .m-1\.5 {
margin: 0.375rem; margin: 0.375rem;
} }
@ -1091,6 +1094,10 @@ input:checked + .toggle-bg {
margin-left: 1rem; margin-left: 1rem;
margin-right: 1rem; margin-right: 1rem;
} }
.mx-5 {
margin-left: 1.25rem;
margin-right: 1.25rem;
}
.mx-auto { .mx-auto {
margin-left: auto; margin-left: auto;
margin-right: auto; margin-right: auto;
@ -1125,30 +1132,24 @@ input:checked + .toggle-bg {
.-mb-4 { .-mb-4 {
margin-bottom: -1rem; margin-bottom: -1rem;
} }
.-ml-1 {
margin-left: -0.25rem;
}
.-ml-4 { .-ml-4 {
margin-left: -1rem; margin-left: -1rem;
} }
.-ml-5 {
margin-left: -1.25rem;
}
.-ml-6 { .-ml-6 {
margin-left: -1.5rem; margin-left: -1.5rem;
} }
.-mr-2 { .-mr-2 {
margin-right: -0.5rem; margin-right: -0.5rem;
} }
.-mt-0 {
margin-top: -0px;
}
.-mt-0\.5 { .-mt-0\.5 {
margin-top: -0.125rem; margin-top: -0.125rem;
} }
.-mt-1 { .-mt-1 {
margin-top: -0.25rem; margin-top: -0.25rem;
} }
.-mt-2 {
margin-top: -0.5rem;
}
.-mt-3 { .-mt-3 {
margin-top: -0.75rem; margin-top: -0.75rem;
} }
@ -1182,9 +1183,6 @@ input:checked + .toggle-bg {
.mr-2 { .mr-2 {
margin-right: 0.5rem; margin-right: 0.5rem;
} }
.mr-3 {
margin-right: 0.75rem;
}
.mt-1 { .mt-1 {
margin-top: 0.25rem; margin-top: 0.25rem;
} }
@ -1203,9 +1201,6 @@ input:checked + .toggle-bg {
.mt-4 { .mt-4 {
margin-top: 1rem; margin-top: 1rem;
} }
.mt-5 {
margin-top: 1.25rem;
}
.mt-6 { .mt-6 {
margin-top: 1.5rem; margin-top: 1.5rem;
} }
@ -1215,6 +1210,12 @@ input:checked + .toggle-bg {
.mt-8 { .mt-8 {
margin-top: 2rem; margin-top: 2rem;
} }
.line-clamp-1 {
overflow: hidden;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 1;
}
.block { .block {
display: block; display: block;
} }
@ -1352,12 +1353,6 @@ input:checked + .toggle-bg {
.w-screen { .w-screen {
width: 100vw; width: 100vw;
} }
.min-w-\[310px\] {
min-width: 310px;
}
.min-w-\[340px\] {
min-width: 340px;
}
.flex-1 { .flex-1 {
flex: 1 1 0%; flex: 1 1 0%;
} }
@ -1471,12 +1466,6 @@ input:checked + .toggle-bg {
.overflow-hidden { .overflow-hidden {
overflow: hidden; overflow: hidden;
} }
.overflow-x-auto {
overflow-x: auto;
}
.overflow-y-auto {
overflow-y: auto;
}
.overflow-x-hidden { .overflow-x-hidden {
overflow-x: hidden; overflow-x: hidden;
} }
@ -1544,10 +1533,6 @@ input:checked + .toggle-bg {
.border-dashed { .border-dashed {
border-style: dashed; border-style: dashed;
} }
.border-blue-400 {
--tw-border-opacity: 1;
border-color: rgb(118 169 250 / var(--tw-border-opacity));
}
.border-blue-500 { .border-blue-500 {
--tw-border-opacity: 1; --tw-border-opacity: 1;
border-color: rgb(63 131 248 / var(--tw-border-opacity)); border-color: rgb(63 131 248 / var(--tw-border-opacity));
@ -1663,6 +1648,10 @@ input:checked + .toggle-bg {
padding-left: 0px; padding-left: 0px;
padding-right: 0px; padding-right: 0px;
} }
.px-1 {
padding-left: 0.25rem;
padding-right: 0.25rem;
}
.px-1\.5 { .px-1\.5 {
padding-left: 0.375rem; padding-left: 0.375rem;
padding-right: 0.375rem; padding-right: 0.375rem;
@ -1683,6 +1672,10 @@ input:checked + .toggle-bg {
padding-left: 1.25rem; padding-left: 1.25rem;
padding-right: 1.25rem; padding-right: 1.25rem;
} }
.py-0 {
padding-top: 0px;
padding-bottom: 0px;
}
.py-0\.5 { .py-0\.5 {
padding-top: 0.125rem; padding-top: 0.125rem;
padding-bottom: 0.125rem; padding-bottom: 0.125rem;
@ -1711,22 +1704,9 @@ input:checked + .toggle-bg {
padding-top: 2rem; padding-top: 2rem;
padding-bottom: 2rem; padding-bottom: 2rem;
} }
.py-9 {
padding-top: 2.25rem;
padding-bottom: 2.25rem;
}
.pb-3 {
padding-bottom: 0.75rem;
}
.pb-5 {
padding-bottom: 1.25rem;
}
.pt-2 { .pt-2 {
padding-top: 0.5rem; padding-top: 0.5rem;
} }
.pt-3 {
padding-top: 0.75rem;
}
.pt-4 { .pt-4 {
padding-top: 1rem; padding-top: 1rem;
} }
@ -1951,7 +1931,6 @@ input:checked + .toggle-bg {
url('../assets/fonts/woff/iranyekanwebextrablackfanum.woff') format('woff'), /* FF3.6+, IE9, Chrome6+, Saf5.1+*/ url('../assets/fonts/woff/iranyekanwebextrablackfanum.woff') format('woff'), /* FF3.6+, IE9, Chrome6+, Saf5.1+*/
url('../assets/fonts/ttf/iranyekanwebextrablackfanum.ttf') format('truetype'); url('../assets/fonts/ttf/iranyekanwebextrablackfanum.ttf') format('truetype');
} }
.revert-tailwind { .revert-tailwind {
all: initial; all: initial;
} }
@ -1971,16 +1950,6 @@ input:checked + .toggle-bg {
scrollbar-width: none; /* Firefox */ scrollbar-width: none; /* Firefox */
} }
.auto-scrollbar {
-ms-overflow-style: auto; /* IE and Edge */
scrollbar-width: auto; /* Firefox */
}
.auto-scrollbar::-webkit-scrollbar {
display: block;
}
.mud-dialog-title { .mud-dialog-title {
font-family: iranyekan !important; font-family: iranyekan !important;
} }
@ -2000,7 +1969,7 @@ a, .btn-link {
} }
.btn:focus, .btn:active:focus, .btn-link.nav-link:focus, .form-control:focus, .form-check-input:focus { .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; box-shadow: 0 0 0 0.1rem white, 0 0 0 0.25rem #258cfb;
} }
.content { .content {
@ -2263,10 +2232,6 @@ code {
width: 16rem; width: 16rem;
} }
.sm\:w-full {
width: 100%;
}
.sm\:py-3 { .sm\:py-3 {
padding-top: 0.75rem; padding-top: 0.75rem;
padding-bottom: 0.75rem; padding-bottom: 0.75rem;
@ -2312,10 +2277,6 @@ code {
padding: 1.25rem; padding: 1.25rem;
} }
.md\:p-8 {
padding: 2rem;
}
.md\:px-10 { .md\:px-10 {
padding-left: 2.5rem; padding-left: 2.5rem;
padding-right: 2.5rem; padding-right: 2.5rem;

View File

@ -1,113 +1,5 @@
*, ::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(63 131 248 / 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: ;
--tw-contain-size: ;
--tw-contain-layout: ;
--tw-contain-paint: ;
--tw-contain-style: ;
}
::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(63 131 248 / 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: ;
--tw-contain-size: ;
--tw-contain-layout: ;
--tw-contain-paint: ;
--tw-contain-style: ;
}
/* /*
! tailwindcss v3.4.13 | MIT License | https://tailwindcss.com ! tailwindcss v3.4.3 | MIT License | https://tailwindcss.com
*/ */
/* /*
@ -1027,6 +919,114 @@ input:checked + .toggle-bg {
--color-background: rgba(243, 244, 246, 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(63 131 248 / 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: ;
--tw-contain-size: ;
--tw-contain-layout: ;
--tw-contain-paint: ;
--tw-contain-style: ;
}
::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(63 131 248 / 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: ;
--tw-contain-size: ;
--tw-contain-layout: ;
--tw-contain-paint: ;
--tw-contain-style: ;
}
.container { .container {
width: 100%; width: 100%;
} }
@ -1113,10 +1113,6 @@ input:checked + .toggle-bg {
top: 0px; top: 0px;
} }
.\!z-\[9999\] {
z-index: 9999 !important;
}
.z-10 { .z-10 {
z-index: 10; z-index: 10;
} }
@ -1137,6 +1133,10 @@ input:checked + .toggle-bg {
z-index: 50; z-index: 50;
} }
.m-1 {
margin: 0.25rem;
}
.m-1\.5 { .m-1\.5 {
margin: 0.375rem; margin: 0.375rem;
} }
@ -1175,6 +1175,11 @@ input:checked + .toggle-bg {
margin-right: 1rem; margin-right: 1rem;
} }
.mx-5 {
margin-left: 1.25rem;
margin-right: 1.25rem;
}
.mx-auto { .mx-auto {
margin-left: auto; margin-left: auto;
margin-right: auto; margin-right: auto;
@ -1218,18 +1223,10 @@ input:checked + .toggle-bg {
margin-bottom: -1rem; margin-bottom: -1rem;
} }
.-ml-1 {
margin-left: -0.25rem;
}
.-ml-4 { .-ml-4 {
margin-left: -1rem; margin-left: -1rem;
} }
.-ml-5 {
margin-left: -1.25rem;
}
.-ml-6 { .-ml-6 {
margin-left: -1.5rem; margin-left: -1.5rem;
} }
@ -1238,6 +1235,10 @@ input:checked + .toggle-bg {
margin-right: -0.5rem; margin-right: -0.5rem;
} }
.-mt-0 {
margin-top: -0px;
}
.-mt-0\.5 { .-mt-0\.5 {
margin-top: -0.125rem; margin-top: -0.125rem;
} }
@ -1246,10 +1247,6 @@ input:checked + .toggle-bg {
margin-top: -0.25rem; margin-top: -0.25rem;
} }
.-mt-2 {
margin-top: -0.5rem;
}
.-mt-3 { .-mt-3 {
margin-top: -0.75rem; margin-top: -0.75rem;
} }
@ -1294,10 +1291,6 @@ input:checked + .toggle-bg {
margin-right: 0.5rem; margin-right: 0.5rem;
} }
.mr-3 {
margin-right: 0.75rem;
}
.mt-1 { .mt-1 {
margin-top: 0.25rem; margin-top: 0.25rem;
} }
@ -1322,10 +1315,6 @@ input:checked + .toggle-bg {
margin-top: 1rem; margin-top: 1rem;
} }
.mt-5 {
margin-top: 1.25rem;
}
.mt-6 { .mt-6 {
margin-top: 1.5rem; margin-top: 1.5rem;
} }
@ -1338,6 +1327,13 @@ input:checked + .toggle-bg {
margin-top: 2rem; margin-top: 2rem;
} }
.line-clamp-1 {
overflow: hidden;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 1;
}
.block { .block {
display: block; display: block;
} }
@ -1520,14 +1516,6 @@ input:checked + .toggle-bg {
width: 100vw; width: 100vw;
} }
.min-w-\[310px\] {
min-width: 310px;
}
.min-w-\[340px\] {
min-width: 340px;
}
.flex-1 { .flex-1 {
flex: 1 1 0%; flex: 1 1 0%;
} }
@ -1674,14 +1662,6 @@ input:checked + .toggle-bg {
overflow: hidden; overflow: hidden;
} }
.overflow-x-auto {
overflow-x: auto;
}
.overflow-y-auto {
overflow-y: auto;
}
.overflow-x-hidden { .overflow-x-hidden {
overflow-x: hidden; overflow-x: hidden;
} }
@ -1770,11 +1750,6 @@ input:checked + .toggle-bg {
border-style: dashed; border-style: dashed;
} }
.border-blue-400 {
--tw-border-opacity: 1;
border-color: rgb(118 169 250 / var(--tw-border-opacity));
}
.border-blue-500 { .border-blue-500 {
--tw-border-opacity: 1; --tw-border-opacity: 1;
border-color: rgb(63 131 248 / var(--tw-border-opacity)); border-color: rgb(63 131 248 / var(--tw-border-opacity));
@ -1922,6 +1897,11 @@ input:checked + .toggle-bg {
padding-right: 0px; padding-right: 0px;
} }
.px-1 {
padding-left: 0.25rem;
padding-right: 0.25rem;
}
.px-1\.5 { .px-1\.5 {
padding-left: 0.375rem; padding-left: 0.375rem;
padding-right: 0.375rem; padding-right: 0.375rem;
@ -1947,6 +1927,11 @@ input:checked + .toggle-bg {
padding-right: 1.25rem; padding-right: 1.25rem;
} }
.py-0 {
padding-top: 0px;
padding-bottom: 0px;
}
.py-0\.5 { .py-0\.5 {
padding-top: 0.125rem; padding-top: 0.125rem;
padding-bottom: 0.125rem; padding-bottom: 0.125rem;
@ -1982,27 +1967,10 @@ input:checked + .toggle-bg {
padding-bottom: 2rem; padding-bottom: 2rem;
} }
.py-9 {
padding-top: 2.25rem;
padding-bottom: 2.25rem;
}
.pb-3 {
padding-bottom: 0.75rem;
}
.pb-5 {
padding-bottom: 1.25rem;
}
.pt-2 { .pt-2 {
padding-top: 0.5rem; padding-top: 0.5rem;
} }
.pt-3 {
padding-top: 0.75rem;
}
.pt-4 { .pt-4 {
padding-top: 1rem; padding-top: 1rem;
} }
@ -2321,17 +2289,6 @@ input:checked + .toggle-bg {
/* Firefox */ /* Firefox */
} }
.auto-scrollbar {
-ms-overflow-style: auto;
/* IE and Edge */
scrollbar-width: auto;
/* Firefox */
}
.auto-scrollbar::-webkit-scrollbar {
display: block;
}
.mud-dialog-title { .mud-dialog-title {
font-family: iranyekan !important; font-family: iranyekan !important;
} }
@ -2613,10 +2570,6 @@ code {
width: 16rem; width: 16rem;
} }
.sm\:w-full {
width: 100%;
}
.sm\:py-3 { .sm\:py-3 {
padding-top: 0.75rem; padding-top: 0.75rem;
padding-bottom: 0.75rem; padding-bottom: 0.75rem;
@ -2661,10 +2614,6 @@ code {
padding: 1.25rem; padding: 1.25rem;
} }
.md\:p-8 {
padding: 2rem;
}
.md\:px-10 { .md\:px-10 {
padding-left: 2.5rem; padding-left: 2.5rem;
padding-right: 2.5rem; padding-right: 2.5rem;

File diff suppressed because one or more lines are too long

Some files were not shown because too many files have changed in this diff Show More