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
<Router AppAssembly="@typeof(App).Assembly">
<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
@implements IAsyncDisposable
<head>
<link rel="stylesheet" href="assets/vendor/ckeditor5-content.css" />
<link rel="stylesheet" href="css/content-styles.css" />
</head>
<style>
.ck-content * {
@ -16,9 +15,65 @@
</style>
<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
{
await JsRuntime.InvokeVoidAsync("setData", Text);
await JsRuntime.InvokeVoidAsync("window.setData", Text);
isTextSeted = true;
}
catch (Exception e)
@ -59,23 +114,20 @@
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
var lDotNetReference = DotNetObjectReference.Create(this);
await JsRuntime.InvokeVoidAsync("GLOBAL.SetDotnetReference", lDotNetReference);
await JsRuntime.InvokeVoidAsync("initializeCKEditor", Text);
await base.OnAfterRenderAsync(firstRender);
}
var lDotNetReference = DotNetObjectReference.Create(this);
await JsRuntime.InvokeVoidAsync("GLOBAL.SetDotnetReference", lDotNetReference);
await JsRuntime.InvokeVoidAsync("window.lunchEditor", Text);
await base.OnAfterRenderAsync(firstRender);
}
public void Dispose()
{
JsRuntime.InvokeVoidAsync("destroyEditor", Text);
JsRuntime.InvokeVoidAsync("window.destroyEditor", Text);
}
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 IRestWrapper RestWrapper
@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>
@if (isShop)
{
@ -22,18 +21,9 @@
Icon="@Icons.Material.Outlined.AllInbox">دسته بندی محصولاتـــ</MudNavLink>
<MudNavLink Href="product/brands"
Icon="@Icons.Custom.Brands.Facebook">برند محصولاتــــ</MudNavLink>
<MudNavLink Href="product/shipping"
Icon="@Icons.Material.Outlined.AirportShuttle">روش های ارسال</MudNavLink>
</MudNavGroup>
}
<MudNavGroup Title="نظرات و امتیازاتـــ" Expanded="false"
Icon="@Icons.Material.Outlined.Comment">
<MudNavLink Href="reviews"
Icon="@Icons.Material.Filled.Comment">مدیریت نظراتـــ</MudNavLink>
</MudNavGroup>
<MudNavGroup Title="وبلاگــــ" Expanded="false"
Icon="@Icons.Material.Outlined.Web">
@ -46,12 +36,7 @@
<MudNavGroup Title="مدیریت برگه ها" Expanded="false"
Icon="@Icons.Material.Outlined.Pages">
<MudNavLink Href="management/pages" Icon="@Icons.Material.Filled.Pageview">برگه ها</MudNavLink>
<MudNavLink Href="setting/faq" 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>
<MudNavLink Href="management/faqs" Icon="@Icons.Material.Filled.ManageAccounts">سوالات متداول</MudNavLink>
</MudNavGroup>
@if (isShop)
@ -66,6 +51,18 @@
</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)
{
<MudNavGroup Title="باشگاه مشتریانـــ" Expanded="false"
@ -73,16 +70,23 @@
<MudNavLink Href="customers"
Icon="@Icons.Material.Outlined.PeopleAlt">مشترکین</MudNavLink>
<MudNavLink Href="smspanel"
Icon="@Icons.Material.Outlined.Sms">پنل پیامکی</MudNavLink>
<MudNavLink Href="newsletler"
Icon="@Icons.Material.Outlined.Newspaper">خبرنامه</MudNavLink>
</MudNavGroup>
}
@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">
<MudNavLink Href="management/shop" Icon="@Icons.Material.Filled.Shop2">فروشگاه</MudNavLink>
<MudNavLink Href="management/marketer" Icon="@Icons.Material.Filled.Person4">بازاریاب ها</MudNavLink>
<MudNavLink Href="personalization/nav" Icon="@Icons.Material.Filled.MenuOpen">فهرست ها</MudNavLink>
</MudNavGroup>
}
else
@ -97,7 +101,7 @@
<MudNavLink Href="setting/users" Icon="@Icons.Material.Filled.ManageAccounts">نقش ها و کاربران</MudNavLink>
</MudNavGroup>
</MudNavMenu>
<p class="bottom-0 mx-auto align-bottom">Version : @version</p>
<p class="bottom-0 align-bottom mx-auto">Version : @version</p>
</MudStack>
@code
@ -108,27 +112,20 @@
{
try
{
try
_permissions = await UserUtility.GetPermissionsAsync() ?? new List<string>();
var token = await UserUtility.GetBearerTokenAsync();
if (token == null)
{
_permissions = await UserUtility.GetPermissionsAsync() ?? new List<string>();
var token = await UserUtility.GetBearerTokenAsync();
if (token == null)
{
await UserUtility.LogoutAsync();
NavigationManager.NavigateTo("login", true, true);
return;
}
await UserUtility.LogoutAsync();
NavigationManager.NavigateTo("login", true, true);
return;
}
var rest = await RestWrapper.SettingRestApi.GetSettingAsync<NetinaSetting>(nameof(NetinaSetting), token);
if (rest.WebSiteType == 0)
isShop = true;
else
isShop = false;
}
catch (Exception e)
{
Snackbar.Add("در دریافت اطلاعات مشکلی رخ داده است", Severity.Error);
}
var rest = await RestWrapper.SettingRestApi.GetSettingAsync<NetinaSetting>(nameof(NetinaSetting), token);
if (rest.WebSiteType == 0)
isShop = true;
else
isShop = false;
await base.OnInitializedAsync();
}

View File

@ -30,9 +30,9 @@
<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 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>
@ -63,6 +63,7 @@
<div class="min-h-[33rem]">
<MudStack class="mt-4" Spacing="0">
<MudText Typo="Typo.h6">متن بلاگ</MudText>
<MudText Typo="Typo.caption">می توانید کتن کامل بلاگــــ خود را کامل وارد کنید</MudText>
</MudStack>
@ -78,7 +79,7 @@
<MudTabPanel Text="تـــــصاویر" Icon="@Icons.Material.Outlined.ImageSearch">
<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.caption">می توانید برای محصول چند تصویر اپلود کنید</MudText>
@ -87,15 +88,15 @@
<MudIconButton HtmlTag="label"
Color="Color.Info"
Variant="Variant.Outlined"
class="h-28 w-28"
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="h-28 w-28">
<MudImage Src="@item.GetLink()" Elevation="25" Class="absolute h-28 w-28 rounded-lg" />
<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"
@ -106,11 +107,11 @@
Icon="@Icons.Material.Outlined.Delete" />
@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)
{
<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>
}
@ -123,7 +124,7 @@
</MudContainer>
</DialogContent>
<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)
{

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 IUserUtility UserUtility
@ -23,7 +27,7 @@
</MudStack>
</DialogContent>
<DialogActions>
<MudStack Row="true" class="mx-4 mb-2 w-full">
<MudStack Row="true" class="w-full mx-4 mb-2">
@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 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>
<MudDivider class="-mt-3" />
<MudStack Spacing="0">
<MudStack>
<MudStack Spacing="0">
<MudText Typo="Typo.h6">اطلاعات کلی</MudText>
<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.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>
<MudText Typo="Typo.h6">تصاویر برند</MudText>
<MudText Typo="Typo.caption">می توانید برای برند چند تصویر اپلود کنید</MudText>
</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>
<MudItem xs="12">
<MudText Typo="Typo.h6">اطلاعات متا تگ</MudText>
<MudText Typo="Typo.caption">می توانید متا تگ های سئو برای صفحه مورد نظر را وارد کنید</MudText>
<MudGrid>
</MudStack>
</MudItem>
<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>
</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>
</MudGrid>
</MudStack>
</DialogContent>
<DialogActions>
<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"
Variant="Variant.Filled" Color="Color.Success"
Content="ثبت ویرایش" OnClickCallback="ViewModel.SubmitEditAsync" />
Content="ثبت ویرایش" OnClickCallback="SubmitEditAsync" />
}
else
{
<BaseButtonUi class="w-64 rounded-md" IsProcessing="@ViewModel.IsProcessing"
<BaseButtonUi class="w-64 rounded-md" IsProcessing="@_isProcessing"
Icon="@Icons.Material.Outlined.Check"
Variant="Variant.Filled" Color="Color.Success"
Content="تایید" OnClickCallback="ViewModel.SubmitCreateAsync" />
Content="تایید" OnClickCallback="SubmitCreateAsync" />
}
<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>
</DialogActions>
</MudDialog>
@code {
[CascadingParameter]
MudDialogInstance MudDialog { get; set; }
[CascadingParameter] MudDialogInstance MudDialog { get; set; }
[Parameter]
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 OnInitializedAsync()
protected override async Task OnParametersSetAsync()
{
ViewModel = Brand == null ? new BrandActionDialogBoxViewModel(Snackbar, RestWrapper, UserUtility, DialogService, MudDialog) :
new BrandActionDialogBoxViewModel(Snackbar, RestWrapper, UserUtility, DialogService, MudDialog, Brand);
await ViewModel.InitializeAsync();
await base.OnInitializedAsync();
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.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>
</MudItem>
<MudItem sm="5">
<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" />
<MudSwitch @bind-Value="@ViewModel.IsProductEnable" class="mt-2" Size="Size.Large" T="bool" Label="تخفیف برای غذای خاص" Color="Color.Info" />
</MudItem>
<MudItem sm="7">

View File

@ -40,23 +40,8 @@ public class DiscountActionDialogBoxViewModel : BaseViewModel<DiscountLDto>
IsEditing = true;
}
private bool _isBrandEnable;
public bool IsBrandEnable
{
get => _isBrandEnable;
set
{
_isBrandEnable = value;
if (_isBrandEnable)
{
IsCategoryEnable = false;
IsProductEnable = false;
IsAllEnable = false;
}
}
}
private bool _isProductEnable;
public bool IsProductEnable
{
get => _isProductEnable;
@ -66,12 +51,10 @@ public class DiscountActionDialogBoxViewModel : BaseViewModel<DiscountLDto>
if (_isProductEnable)
{
IsCategoryEnable = false;
IsBrandEnable = false;
IsAllEnable = false;
}
}
}
private bool _isCategoryEnable;
public bool IsCategoryEnable
{
@ -82,7 +65,6 @@ public class DiscountActionDialogBoxViewModel : BaseViewModel<DiscountLDto>
if (_isCategoryEnable)
{
IsProductEnable = false;
IsBrandEnable = false;
IsAllEnable = false;
}
}
@ -97,7 +79,6 @@ public class DiscountActionDialogBoxViewModel : BaseViewModel<DiscountLDto>
if (_isAllEnable)
{
IsCategoryEnable = false;
IsBrandEnable = false;
IsProductEnable = false;
}
}
@ -142,10 +123,6 @@ public class DiscountActionDialogBoxViewModel : BaseViewModel<DiscountLDto>
if (PageDto.CategoryId != default)
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)
SelectedProduct = new ProductSDto { Id = PageDto.ProductId, PersianName = PageDto.ProductName };
@ -181,6 +158,8 @@ public class DiscountActionDialogBoxViewModel : BaseViewModel<DiscountLDto>
}
public void Cancel() => _mudDialog.Cancel();
public async Task SubmitCreateAsync()
@ -206,13 +185,6 @@ public class DiscountActionDialogBoxViewModel : BaseViewModel<DiscountLDto>
throw new Exception("کالا مورد نظر را برای تخفیف انتخاب نمایید");
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();
if (token == null)
@ -222,43 +194,16 @@ public class DiscountActionDialogBoxViewModel : BaseViewModel<DiscountLDto>
if(StartDate != null)
PageDto.StartDate = StartDate.Value;
var request = new CreateDiscountCommand(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.CrudDtoApiRest<Discount,DiscountLDto, Guid>(Address.DiscountController).Create<CreateDiscountCommand>(request, token);
var request = PageDto.Adapt<CreateDiscountCommand>();
await _restWrapper.CrudApiRest<Discount, Guid>(Address.DiscountController).Create<CreateDiscountCommand>(request, token);
_snackbar.Add($"ساخت تخفیف با موفقیت انجام شد", Severity.Success);
_mudDialog.Close(true);
}
catch (ApiException ex)
{
if (ex.StatusCode == HttpStatusCode.BadRequest)
{
var exe = await ex.GetContentAsAsync<ApiResult>();
_snackbar.Add(exe != null ? exe.Message : ex.Content, Severity.Error);
}
else
_snackbar.Add(ex.Content, Severity.Error);
var exe = await ex.GetContentAsAsync<ApiResult>();
_snackbar.Add(exe != null ? exe.Message : ex.Content, Severity.Error);
_mudDialog.Cancel();
}
catch (Exception e)
@ -272,7 +217,6 @@ public class DiscountActionDialogBoxViewModel : BaseViewModel<DiscountLDto>
IsProcessing = false;
}
}
public async Task SubmitEditAsync()
{
try
@ -299,43 +243,12 @@ public class DiscountActionDialogBoxViewModel : BaseViewModel<DiscountLDto>
throw new Exception("کالا مورد نظر را برای تخفیف انتخاب نمایید");
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();
if (token == null)
throw new Exception("Token is null");
PageDto.Id = _discountId;
var request = new 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);
var request = PageDto.Adapt<UpdateDiscountCommand>();
await _restWrapper.CrudApiRest<Discount, Guid>(Address.DiscountController).Update<UpdateDiscountCommand>(request, token);
_snackbar.Add($"ویرایش تخفیف با موفقیت انجام شد", Severity.Success);
_mudDialog.Close(true);
@ -398,9 +311,9 @@ public class DiscountActionDialogBoxViewModel : BaseViewModel<DiscountLDto>
if (token == null)
throw new Exception("Token is null");
if (product.IsNullOrEmpty())
response = await _restWrapper.ProductRestApi.ReadAll(0,null,null,null,token);
response = await _restWrapper.ProductRestApi.ReadAll(0,null,null, token);
else
response = await _restWrapper.ProductRestApi.ReadAll(product,token);
response = await _restWrapper.ProductRestApi.ReadAll(product, token);
_products = response.Products;
return _products;
}
@ -416,29 +329,4 @@ public class DiscountActionDialogBoxViewModel : BaseViewModel<DiscountLDto>
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"
Icon="@Icons.Material.Outlined.RemoveCircle"
Variant="Variant.Outlined" Color="Color.Error"
OnClickCallback="ViewModel.CancelAsync"
Content="لغو سفارش" />
</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">
<div class="h-full">
<MudStack Spacing="0" class="mt-4">
<MudText Typo="Typo.h6">اطلاعات کلی</MudText>
<MudText Typo="Typo.caption">اطلاعات کلی محصول را به دقت وارد کنید</MudText>
</MudStack>
<MudGrid>
<MudItem xs="12" lg="4" md="6">
@ -106,7 +106,6 @@
</MudGrid>
</div>
</MudTabPanel>
<MudTabPanel Text="ویژگی های کلی" Icon="@Icons.Material.Outlined.AutoGraph">
<div class="min-h-[33rem]">
@ -158,7 +157,6 @@
</MudGrid>
</div>
</MudTabPanel>
<MudTabPanel Text="توضیحات تکمیلی" Icon="@Icons.Material.Outlined.Article">
<div class="min-h-[33rem]">
@ -176,187 +174,6 @@
</MudGrid>
</div>
</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">
<div class="min-h-[33rem]">
@ -418,12 +235,7 @@
<MudItem xs="12" md="4">
<MudSelect Disabled="@ViewModel.IsSpecialOffer.Not()" T="DiscountAmountType"
ValueChanged="@ViewModel.AmountTypeChanged"
Label="نوع تخفیفـــ" ToStringFunc="b=>b.ToDisplay()"
Variant="Variant.Outlined"
Value="@ViewModel.Discount.AmountType"
AnchorOrigin="Origin.BottomCenter">
<MudSelect Disabled="@ViewModel.IsSpecialOffer.Not()" T="DiscountAmountType" ValueChanged="@ViewModel.AmountTypeChanged" Label="نوع تخفیفـــ" ToStringFunc="b=>b.ToDisplay()" Variant="Variant.Outlined" AnchorOrigin="Origin.BottomCenter">
<MudSelectItem T="DiscountAmountType" Value="DiscountAmountType.Percent" />
<MudSelectItem T="DiscountAmountType" Value="DiscountAmountType.Amount" />
</MudSelect>
@ -439,11 +251,11 @@
<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()" />
</MudItem>
<MudDatePicker Disabled="@ViewModel.IsSpecialOffer.Not()" @bind-Date="@ViewModel.StartDate" UseShortNames="false" TitleDateFormat="dddd, dd MMMM" Label="تاریخ شروع تخفیفــ" Variant="Variant.Outlined" Culture="@PersianCultureInfo.GetPersianCulture()" />
</MudItem>
<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>

View File

@ -1,11 +1,4 @@
using Microsoft.AspNetCore.Components.Web;
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;
namespace Netina.AdminPanel.PWA.Dialogs;
public class ProductActionDialogBoxViewModel : BaseViewModel<ProductLDto>
{
@ -68,22 +61,18 @@ public class ProductActionDialogBoxViewModel : BaseViewModel<ProductLDto>
{
_isSpecialOffer = value;
PageDto.IsSpecialOffer = value;
if (!value)
if(!value)
{
IsAmountType = value;
IsPercentType = value;
}
else if (!IsAmountType)
IsPercentType = true;
}
}
public string SpecificationTitle = string.Empty;
public string SpecificationValue = string.Empty;
public readonly ObservableCollection<SpecificationSDto> Specifications = [];
public readonly ObservableCollection<StorageFileSDto> Files = [];
public readonly ObservableCollection<SubProductSDto> SubProducts = [];
public readonly ObservableCollection<SpecificationSDto> Specifications = new ObservableCollection<SpecificationSDto>();
public readonly ObservableCollection<StorageFileSDto> Files = new ObservableCollection<StorageFileSDto>();
public override async Task InitializeAsync()
@ -98,22 +87,10 @@ public class ProductActionDialogBoxViewModel : BaseViewModel<ProductLDto>
PageDto = productLDto;
productLDto.Specifications.ForEach(s => Specifications.Add(s));
productLDto.Files.ForEach(f => Files.Add(f));
productLDto.MetaTags.ForEach(m => MetaTags.Add(m));
SelectedCategory = new ProductCategorySDto { Id = productLDto.CategoryId, Name = productLDto.CategoryName };
SelectedBrand = new BrandSDto { Id = productLDto.BrandId, PersianName = productLDto.BrandName };
PageDto.IsSpecialOffer = productLDto.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)
{
Discount = productLDto.SpecialOffer;
@ -131,10 +108,7 @@ public class ProductActionDialogBoxViewModel : BaseViewModel<ProductLDto>
ExpireDate = Discount.ExpireDate;
StartDate = Discount.StartDate;
IsSpecialOffer = true;
}
await FetchSubProducts();
}
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()
{
try
@ -191,29 +158,7 @@ public class ProductActionDialogBoxViewModel : BaseViewModel<ProductLDto>
Discount.StartDate = StartDate.Value;
PageDto.SpecialOffer = Discount;
}
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));
var request = PageDto.Adapt<UpdateProductCommand>();
await _restWrapper.CrudApiRest<Product, Guid>(Address.ProductController).Update<UpdateProductCommand>(request, token);
_snackbar.Add($"ویرایش محصول {PageDto.PersianName} با موفقیت انجام شد", Severity.Success);
_mudDialog.Close();
@ -233,7 +178,6 @@ public class ProductActionDialogBoxViewModel : BaseViewModel<ProductLDto>
IsProcessing = false;
}
}
public async Task SubmitCreateAsync()
{
try
@ -258,28 +202,8 @@ public class ProductActionDialogBoxViewModel : BaseViewModel<ProductLDto>
Discount.StartDate = StartDate.Value;
PageDto.SpecialOffer = Discount;
}
var request = new CreateProductCommand(
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.CrudDtoApiRest<Product, ProductLDto, Guid>(Address.ProductController).Create<CreateProductCommand>(request, token);
var request = PageDto.Adapt<CreateProductCommand>();
await _restWrapper.CrudApiRest<Product, Guid>(Address.ProductController).Create<CreateProductCommand>(request, token);
_snackbar.Add($"ساخت محصول {PageDto.PersianName} با موفقیت انجام شد", Severity.Success);
_mudDialog.Close(DialogResult.Ok(true));
@ -312,17 +236,15 @@ public class ProductActionDialogBoxViewModel : BaseViewModel<ProductLDto>
case DiscountAmountType.Amount:
IsAmountType = true;
IsPercentType = false;
Discount.AmountType = DiscountAmountType.Amount;
break;
case DiscountAmountType.Percent:
IsAmountType = false;
IsPercentType = true;
Discount.AmountType = DiscountAmountType.Percent;
break;
}
}
private List<ProductCategorySDto> _productCategories = [];
private List<ProductCategorySDto> _productCategories = new List<ProductCategorySDto>();
public ProductCategorySDto? SelectedCategory;
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 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()
{
try
@ -434,6 +315,7 @@ public class ProductActionDialogBoxViewModel : BaseViewModel<ProductLDto>
_snackbar.Add(e.Message, Severity.Error);
}
}
public void RemoveSpecification(SpecificationSDto specification)
{
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)
Files.Add(storageFile);
}
public void RemoveFile(StorageFileSDto 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">
<DialogContent>
<MudContainer class="h-full">
<MudTabs Outlined="true" Elevation="0" Rounded="true" Centered="true">
<MudTabPanel Text="اطلاعات کلی" Icon="@Icons.Material.Outlined.Info">
<MudStack Spacing="0">
<MudDivider class="-mt-3" />
<MudStack Spacing="0">
<MudText Typo="Typo.h6">اطلاعات کلی</MudText>
<MudText Typo="Typo.caption">اطلاعات کلی دسته بندی محصول را به دقت وارد کنید</MudText>
</MudStack>
<MudStack class="overflow-x-hidden overflow-y-hidden">
<MudGrid>
<MudItem sm="12" lg="4" md="6">
<MudTextField T="string" @bind-Value="@ViewModel.Name" Label="نام دسته بندی" Variant="Variant.Outlined"></MudTextField>
</MudItem>
<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">
<MudSelectItem T="bool" Value="true" />
<MudSelectItem T="bool" Value="false" />
</MudSelect>
</MudItem>
<MudItem sm="12" lg="4" md="6">
<MudAutocomplete Required="true" ToStringFunc="dto => dto.Name" @bind-Value="@ViewModel.SelectedCategory"
SearchFunc="ViewModel.SearchCategory"
T="ProductCategorySDto"
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.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>
}
<MudText Typo="Typo.h6">اطلاعات کلی</MudText>
<MudText Typo="Typo.caption">اطلاعات کلی دسته بندی محصول را به دقت وارد کنید</MudText>
</MudStack>
<MudStack class="mx-5 overflow-x-hidden overflow-y-hidden">
<MudGrid>
<MudItem sm="12" lg="4" md="6">
<MudTextField T="string" @bind-Value="@ViewModel.Name" Label="نام دسته بندی" Variant="Variant.Outlined"></MudTextField>
</MudItem>
<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">
<MudSelectItem T="bool" Value="true" />
<MudSelectItem T="bool" Value="false" />
</MudSelect>
</MudItem>
<MudItem sm="12" lg="4" md="6">
<MudAutocomplete Required="true" ToStringFunc="dto => dto.Name" @bind-Value="@ViewModel.SelectedCategory"
SearchFunc="ViewModel.SearchCategory"
T="ProductCategorySDto"
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.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>
</MudItem>
<MudItem sm="12" lg="12" md="12">
<MudContainer class="overflow-y-hidden overflow-x-hidden">
<MudStack class="mt-4 mb-2" Spacing="0">
</MudStack>
</MudItem>
<MudItem sm="12" lg="12" md="12">
<MudContainer class="overflow-y-hidden overflow-x-hidden">
<MudStack class="mt-4 mb-2" Spacing="0">
<MudText Typo="Typo.h6">توضیحات تکمیلی</MudText>
<MudText Typo="Typo.caption">می توانید توضیحاتــ تکمیلی محصول را کامل وارد کنید</MudText>
</MudStack>
<div class="!text-black">
<RichTextEditorUi @bind-Text="@ViewModel.Description" />
</div>
</MudContainer>
</MudItem>
<MudText Typo="Typo.h6">توضیحات تکمیلی</MudText>
<MudText Typo="Typo.caption">می توانید توضیحاتــ تکمیلی محصول را کامل وارد کنید</MudText>
</MudStack>
<div class="!text-black">
<RichTextEditorUi @bind-Text="@ViewModel.Description" />
</div>
</MudContainer>
</MudItem>
</MudGrid>
</MudStack>
</MudTabPanel>
</MudGrid>
</MudStack>
<MudTabPanel Text="متاتگ و سوالات متداول">
<MudGrid>
<MudItem xs="12">
<MudStack Row="true" class="w-full mx-4 mb-2">
<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>
</MudTabs>
@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>
</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
{

View File

@ -1,7 +1,4 @@
using Netina.Common.Models.Mapper;
using Netina.Domain.Entities.Seo;
namespace Netina.AdminPanel.PWA.Dialogs;
namespace Netina.AdminPanel.PWA.Dialogs;
public class ProductCategoryActionDialogBoxViewModel:BaseViewModel
{
@ -35,8 +32,7 @@ public class ProductCategoryActionDialogBoxViewModel:BaseViewModel
public string Description = string.Empty;
public bool IsMain;
public bool IsEditing = false;
public readonly ObservableCollection<StorageFileSDto> Files = new ();
public readonly ObservableCollection<MetaTagSDto> MetaTags = new();
public readonly ObservableCollection<StorageFileSDto> Files = new ObservableCollection<StorageFileSDto>();
private ProductCategorySDto? _category = null;
[Parameter]
@ -63,7 +59,6 @@ public class ProductCategoryActionDialogBoxViewModel:BaseViewModel
var response = await _restWrapper.CrudDtoApiRest<ProductCategory,ProductCategoryLDto,Guid>(Address.ProductCategoryController).ReadOne(Category.Id);
var categoryLDto = response;
categoryLDto.Files.ForEach(f => Files.Add(f));
categoryLDto.MetaTags.ForEach(m=> MetaTags.Add(m));
SelectedCategory = new ProductCategorySDto { Id = categoryLDto.ParentId, Name = categoryLDto.ParentName };
Name = categoryLDto.Name;
Description = categoryLDto.Description;
@ -99,13 +94,7 @@ public class ProductCategoryActionDialogBoxViewModel:BaseViewModel
var token = await _userUtility.GetBearerTokenAsync();
if (token == null)
throw new AppException("Token is null");
var request = new CreateProductCategoryCommand(Name,
Description,
IsMain,
SelectedCategory?.Id ?? default,
Files.ToList(),
Faqs,
MetaTags.ToDictionary(x => x.Type, x => x.Value));
var request = new CreateProductCategoryCommand(Name, Description, IsMain, SelectedCategory?.Id ?? default, Files.ToList());
await _restWrapper.CrudApiRest<ProductCategory, Guid>(Address.ProductCategoryController).Create<CreateProductCategoryCommand>(request, token);
_mudDialog.Close(DialogResult.Ok(true));
}
@ -138,14 +127,7 @@ public class ProductCategoryActionDialogBoxViewModel:BaseViewModel
IsProcessing = true;
await Task.Delay(1000);
var token = await _userUtility.GetBearerTokenAsync();
var request = new UpdateProductCategoryCommand(Category.Id,
Name,
Description,
IsMain,
SelectedCategory?.Id ?? default,
Files.ToList(),
Faqs,
MetaTags.ToDictionary(x => x.Type, x => x.Value));
var request = new UpdateProductCategoryCommand(Category.Id, Name, Description, IsMain, SelectedCategory?.Id ?? default, Files.ToList());
await _restWrapper.CrudApiRest<ProductCategory, Guid>(Address.ProductCategoryController).Update<UpdateProductCategoryCommand>(request, token);
_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>();
public ProductCategorySDto? SelectedCategory;
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()
{
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 IUserUtility UserUtility
@inject IDialogService DialogService

View File

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

View File

@ -9,8 +9,6 @@ public static class Address
public static string ProductCategoryController = $"/product/category";
public static string ProductController = $"/product";
public static string BrandController = $"/brand";
public static string SubProductController = $"/sub/product";
public static string FileController => $"/file";
public static string BlogController => $"/blog";
public static string BlogCategoryController => $"/blog/category";
@ -25,6 +23,4 @@ public static class Address
public static string DashboardController => $"/dashboard";
public static string SettingController => $"/setting";
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 TPageDto PageDto { get; set; }
private string[] _permissions = new string[]{};
protected readonly IUserUtility _userUtility;
private readonly IUserUtility _userUtility;
public bool IsPermitted { get; set; } = false;
public BaseViewModel(IUserUtility userUtility,params string[] permissions)
{

View File

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

View File

@ -7,7 +7,7 @@
@inject IUserUtility UserUtility
@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>
<MudItem xs="12">
<MudStack Row="true" class="mb-5">
@ -58,7 +58,7 @@
<MudStack Row="true" class="w-full">
<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>
</PagerContent>

View File

@ -9,7 +9,7 @@
@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>
<MudItem xs="12">
<MudStack Row="true" class="mb-5">
@ -67,7 +67,7 @@
<MudStack Row="true" class="w-full">
<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>
</PagerContent>

View File

@ -5,11 +5,9 @@
@inject IRestWrapper RestWrapper
@inject ISnackbar Snackbar
@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>
<MudItem xs="12">
<MudStack Row="true" class="mb-5">
@ -27,7 +25,7 @@
<MudPaper>
<MudDataGrid Striped="true" T="BrandSDto" Items="@ViewModel.PageDto" Filterable="false" Loading="@ViewModel.IsProcessing"
CurrentPage="@ViewModel.CurrentPage"
RowsPerPage="10"
RowsPerPage="15"
SortMode="@SortMode.None" Groupable="false">
<ToolBarContent>
<MudTextField T="string" Placeholder="جست جو بر اساس نام" Adornment="Adornment.Start" Immediate="true"
@ -39,6 +37,7 @@
<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)
@ -55,22 +54,15 @@
<TemplateColumn CellClass="d-flex justify-end">
<CellTemplate>
<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"
Size="@Size.Small"
Variant="@Variant.Outlined"
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"
Size="@Size.Small"
Variant="@Variant.Outlined"
OnClick="async () => await ViewModel.DeleteBrandAsync(context.Item.Id)"
OnClick="async() => await ViewModel.DeleteBrandAsync(context.Item.Id)"
Color="@Color.Error"></MudIconButton>
</MudStack>
</CellTemplate>
@ -80,7 +72,7 @@
<MudStack Row="true" class="w-full">
<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>
</PagerContent>
@ -100,13 +92,8 @@
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;
public class BrandsPageViewModel(
NavigationManager navigationManager,
ISnackbar snackbar,
IUserUtility userUtility,
IRestWrapper restWrapper,
IDialogService dialogService) : BaseViewModel<List<BrandSDto>>(userUtility)
public class BrandsPageViewModel : BaseViewModel<List<BrandSDto>>
{
private readonly NavigationManager _navigationManager = navigationManager;
private readonly IUserUtility _userUtility = userUtility;
private readonly NavigationManager _navigationManager;
private readonly ISnackbar _snackbar;
private readonly IUserUtility _userUtility;
private readonly IDialogService _dialogService;
private readonly IRestWrapper _restWrapper;
public string Search = string.Empty;
public int CurrentPage = 0;
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()
{
try
{
IsProcessing = true;
var dto = await restWrapper.CrudDtoApiRest<Brand, BrandSDto, Guid>(Address.BrandController)
var dto = await _restWrapper.CrudDtoApiRest<Brand, BrandSDto, Guid>(Address.BrandController)
.ReadAll(0);
PageDto = dto;
if (PageDto.Count == 10)
PageCount = 2;
}
catch (ApiException ex)
{
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)
{
snackbar.Add(e.Message, Severity.Error);
_snackbar.Add(e.Message, Severity.Error);
}
finally
{
@ -46,18 +51,18 @@ public class BrandsPageViewModel(
public async Task AddBrandClicked()
{
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)
{
DialogOptions maxWidth = new DialogOptions() { MaxWidth = MaxWidth.Medium, FullWidth = true, DisableBackdropClick = true };
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)
{
var reference = await dialogService.ShowQuestionDialog($"آیا از حذف برند اطمینان دارید ?");
var reference = await _dialogService.ShowQuestionDialog($"آیا از حذف برند اطمینان دارید ?");
var result = await reference.Result;
if (!result.Canceled)
{
@ -67,20 +72,20 @@ public class BrandsPageViewModel(
IsProcessing = true;
var token = await _userUtility.GetBearerTokenAsync();
await restWrapper.CrudDtoApiRest<Brand, BrandSDto, Guid>(Address.BrandController)
await _restWrapper.CrudDtoApiRest<Brand, BrandSDto, Guid>(Address.BrandController)
.Delete(selectedCategoryId, token);
snackbar.Add("حذف برند با موفقیت انجام شد", Severity.Success);
_snackbar.Add("حذف برند با موفقیت انجام شد", Severity.Success);
await InitializeAsync();
}
catch (ApiException ex)
{
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)
{
snackbar.Add(e.Message, Severity.Error);
_snackbar.Add(e.Message, Severity.Error);
}
finally
{
@ -97,7 +102,6 @@ public class BrandsPageViewModel(
await InitializeAsync();
Search = search;
}
public async Task SearchAsync()
{
try
@ -108,19 +112,19 @@ public class BrandsPageViewModel(
CurrentPage = 0;
PageCount = 1;
PageDto.Clear();
var dto = await restWrapper.BrandRestApi.ReadAll(CurrentPage, Search);
var dto = await _restWrapper.BrandRestApi.ReadAll(CurrentPage, Search);
dto.ForEach(d => PageDto.Add(d));
if (PageDto.Count == 10)
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);
_snackbar.Add(exe != null ? exe.Message : ex.Content, Severity.Error);
}
catch (Exception e)
{
snackbar.Add(e.Message, Severity.Error);
_snackbar.Add(e.Message, Severity.Error);
}
finally
{
@ -142,27 +146,27 @@ public class BrandsPageViewModel(
List<BrandSDto> dto = new List<BrandSDto>();
if (Search.IsNullOrEmpty())
{
dto = await restWrapper.CrudDtoApiRest<Brand, BrandSDto, Guid>(Address.BrandController)
dto = await _restWrapper.CrudDtoApiRest<Brand, BrandSDto, Guid>(Address.BrandController)
.ReadAll(CurrentPage);
}
else
{
dto = await restWrapper.BrandRestApi.ReadAll(CurrentPage, Search);
dto = await _restWrapper.BrandRestApi.ReadAll(CurrentPage, Search);
}
dto.ForEach(d => PageDto.Add(d));
if (PageDto.Count % 10 == 0)
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);
_snackbar.Add(exe != null ? exe.Message : ex.Content, Severity.Error);
}
catch (Exception e)
{
snackbar.Add(e.Message, Severity.Error);
_snackbar.Add(e.Message, Severity.Error);
}
finally
{

View File

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

View File

@ -1,36 +1,47 @@
namespace Netina.AdminPanel.PWA.Pages;
public class CategoriesPageViewModel(
NavigationManager navigationManager,
ISnackbar snackbar,
IUserUtility userUtility,
IRestWrapper restWrapper,
IDialogService dialogService)
: BaseViewModel<ObservableCollection<ProductCategorySDto>>(userUtility)
public class CategoriesPageViewModel : BaseViewModel<ObservableCollection<ProductCategorySDto>>
{
private readonly NavigationManager _navigationManager = navigationManager;
private readonly IUserUtility _userUtility = userUtility;
private readonly NavigationManager _navigationManager;
private readonly ISnackbar _snackbar;
private readonly IUserUtility _userUtility;
private readonly IDialogService _dialogService;
private readonly IRestWrapper _restWrapper;
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()
{
try
{
IsProcessing = true;
CurrentPage = 0;
PageDto.Clear();
var dto = await restWrapper.ProductCategoryRestApi.ReadAll(true);
dto.ForEach(d => PageDto.Add(d));
var dto = await _restWrapper.CrudDtoApiRest<ProductCategory, ProductCategorySDto, Guid>(Address.ProductCategoryController)
.ReadAll(CurrentPage);
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);
_snackbar.Add(exe != null ? exe.Message : ex.Content, Severity.Error);
}
catch (Exception e)
{
snackbar.Add(e.Message, Severity.Error);
_snackbar.Add(e.Message, Severity.Error);
}
finally
{
@ -40,11 +51,43 @@ public class CategoriesPageViewModel(
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()
{
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;
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 };
var parameters = new DialogParameters<ProductCategoryActionDialogBox>();
parameters.Add(x => x.Category, category);
var dialogResult = await dialogService.ShowAsync<ProductCategoryActionDialogBox>($"ویرایش دسته {category.Name}", parameters, maxWidth);
parameters.Add(x=>x.Category,category);
var dialogResult = await _dialogService.ShowAsync<ProductCategoryActionDialogBox>($"ویرایش دسته {category.Name}", parameters, maxWidth);
var result = await dialogResult.Result;
if (!result.Canceled && result.Data is bool and true)
{
@ -67,7 +110,7 @@ public class CategoriesPageViewModel(
public async Task DeleteProductCategoryAsync(Guid selectedCategoryId)
{
var reference = await dialogService.ShowQuestionDialog($"آیا از حذف دسته بندی اطمینان دارید ?");
var reference = await _dialogService.ShowQuestionDialog($"آیا از حذف دسته بندی اطمینان دارید ?");
var result = await reference.Result;
if (!result.Canceled)
{
@ -77,20 +120,20 @@ public class CategoriesPageViewModel(
IsProcessing = true;
var token = await _userUtility.GetBearerTokenAsync();
await restWrapper.CrudDtoApiRest<ProductCategory, ProductCategorySDto, Guid>(Address.ProductCategoryController)
await _restWrapper.CrudDtoApiRest<ProductCategory, ProductCategorySDto, Guid>(Address.ProductCategoryController)
.Delete(selectedCategoryId, token);
snackbar.Add("حذف دسته بندی با موفقیت انجام شد", Severity.Success);
_snackbar.Add("حذف دسته بندی با موفقیت انجام شد", Severity.Success);
await InitializeAsync();
}
catch (ApiException ex)
{
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)
{
snackbar.Add(e.Message, Severity.Error);
_snackbar.Add(e.Message, Severity.Error);
}
finally
{
@ -107,18 +150,22 @@ public class CategoriesPageViewModel(
if (Search.IsNullOrEmpty())
throw new AppException("دسته بندی برای جست جو وارد نشده است");
IsProcessing = true;
CurrentPage = 0;
PageCount = 1;
PageDto.Clear();
var dto = await restWrapper.ProductCategoryRestApi.ReadAll(Search);
var dto = await _restWrapper.ProductCategoryRestApi.ReadAll(Search);
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);
_snackbar.Add(exe != null ? exe.Message : ex.Content, Severity.Error);
}
catch (Exception e)
{
snackbar.Add(e.Message, Severity.Error);
_snackbar.Add(e.Message, Severity.Error);
}
finally
{
@ -126,92 +173,4 @@ public class CategoriesPageViewModel(
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 IRestWrapper RestWrapper
<MudStack class="h-full w-full p-8">
<MudStack class="w-full p-8 h-screen bg-[--mud-palette-background-grey]">
<MudGrid>
<MudItem xs="12">
<MudStack Row="true" class="mb-5">
@ -125,7 +125,7 @@
<MudStack Row="true" class="w-full">
<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>
</PagerContent>

View File

@ -1,5 +1,4 @@
@page "/setting/faq"
@page "/management/faqs"
@attribute [Microsoft.AspNetCore.Authorization.Authorize]
@inject IDialogService DialogService
@ -8,56 +7,48 @@
@inject IUserUtility UserUtility
@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>
<MudItem xs="12">
<MudStack Row="true" class="mb-5">
<MudText Typo="Typo.h4">سوالات متداول</MudText>
<MudStack Row="true" class="mb-8">
<MudText Typo="Typo.h4">سوالات متداول فروشگاه من</MudText>
<MudSpacer />
<MudButton Variant="Variant.Filled"
DisableElevation="true"
StartIcon="@Icons.Material.Outlined.Add"
Color="Color.Secondary"
OnClick="@ViewModel.AddClicked"
class="my-auto">افزودن سوالات متداول جدید</MudButton>
<MudButton Variant="Variant.Filled" Size="Size.Large" Color="Color.Success" OnClick="@ViewModel.SaveAsync">ذخیره سوالات</MudButton>
</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>
<MudDataGrid FixedFooter="true" FixedHeader="true" Striped="true"
T="BaseFaq" Items="@ViewModel.PageDto" Filterable="false"
CurrentPage="@ViewModel.CurrentPage"
RowsPerPage="20"
Loading="@ViewModel.IsProcessing"
SortMode="@SortMode.None" Groupable="false">
<Columns>
<PropertyColumn Title="عنوان" Property="arg => arg.Title" />
<PropertyColumn Title="اسلاگ" Property="arg => arg.Slug" />
<TemplateColumn CellClass="d-flex justify-end">
<CellTemplate>
<MudExpansionPanels class="mt-8">
@foreach (var item in ViewModel.PageDto.Faqs)
{
<MudExpansionPanel>
<TitleContent>
<MudStack Row="true">
<MudIconButton Icon="@Icons.Material.Filled.Edit"
<MudIconButton Icon="@Icons.Material.Outlined.Delete"
Size="@Size.Small"
Variant="@Variant.Outlined"
Color="@Color.Info"
OnClick="async()=>await ViewModel.EditClicked(context.Item)" />
<MudIconButton Icon="@Icons.Material.Filled.Delete"
Size="@Size.Small"
Variant="@Variant.Outlined"
OnClick="async () => await ViewModel.DeleteAsync(context.Item.Id)"
Color="@Color.Error" />
</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>
Color="@Color.Error"
OnClick="()=>ViewModel.RemoveQuestion(item.Key)" />
<MudText>@item.Key</MudText>
</MudStack>
</TitleContent>
<ChildContent>
@item.Value
</ChildContent>
</MudExpansionPanel>
}
</MudExpansionPanels>
</MudPaper>
</MudItem>
</MudGrid>
@ -68,7 +59,7 @@
public FaqManagementPageViewModel ViewModel { get; set; }
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 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(
IDialogService dialogService,
NavigationManager navigationManager,
IRestWrapper restWrapper,
ISnackbar snackbar,
IUserUtility userUtility)
: BaseViewModel<ObservableCollection<BaseFaq>> (userUtility)
public class FaqManagementPageViewModel : BaseViewModel<FAQPage>
{
public int CurrentPage = 0;
public int PageCount = 2;
private readonly NavigationManager _navigationManager;
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();
await base.InitializeAsync();
_navigationManager = navigationManager;
_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
{
@ -27,97 +29,109 @@ public class FaqManagementPageViewModel(
if (token == null)
throw new Exception("Token is null");
IsProcessing = true;
var faqs = await restWrapper.FaqApiRest.GetFaqs(CurrentPage, token);
PageDto.Clear();
faqs.ForEach(f => PageDto.Add(f));
if (PageDto.Count % 20 == 0)
PageCount = CurrentPage + 2;
PageDto.Faqs.Clear();
var typeName = typeof(FAQPage).FullName;
var dto = await _restWrapper.PageRestApi.ReadByType(typeName, token);
if (!dto.Data.IsNullOrEmpty())
{
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)
{
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);
_snackbar.Add(exe != null ? exe.Message : ex.Content, Severity.Error);
}
catch (Exception e)
{
snackbar.Add(e.Message, Severity.Error);
_snackbar.Add(e.Message, Severity.Error);
}
finally
{
IsProcessing = false;
}
await base.InitializeAsync();
}
public async Task ChangePageAsync(int page)
public async Task SaveAsync()
{
CurrentPage = page - 1;
await GetEntitiesAsync();
}
public async Task AddClicked()
{
DialogOptions maxWidth = new DialogOptions()
{ MaxWidth = MaxWidth.Medium, FullWidth = true, DisableBackdropClick = true };
var reference = await dialogService.ShowAsync<FaqActionDialogBox>("افزودن سوالات متداول جدید", maxWidth);
var result = await reference.Result;
if (result.Data is bool and true)
await InitializeAsync();
}
public async Task EditClicked(BaseFaq item)
{
DialogOptions maxWidth = new DialogOptions()
{ MaxWidth = MaxWidth.Medium, FullWidth = true, DisableBackdropClick = true };
var parameters = new DialogParameters<FaqActionDialogBox>();
parameters.Add(x => x.Faq, item);
var reference = await dialogService.ShowAsync<FaqActionDialogBox>($"ویرایش سوالات متداول {item.Title}", parameters, maxWidth);
var result = await reference.Result;
if (result.Data is bool and true)
await InitializeAsync();
}
public async Task DeleteAsync(Guid selectedId)
{
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;
var request = new PageActionRequestDto
{
Title = "سوالات متداول",
Content = string.Empty,
Description = string.Empty,
Data = PageDto,
IsCustomPage = true,
IsHtmlBasePage = false,
Slug = "faq",
Type = typeof(FAQPage).FullName
};
if (_request != null)
{
request = _request;
}
request.Data = PageDto;
await _restWrapper.PageRestApi.CreatePage(request, 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
{
try
{
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;
}
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 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">
<MudGrid>
<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.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>
</MudItem>
<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.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>
</MudItem>
<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.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>
</MudItem>
<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.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>
</MudItem>
<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.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>
</MudItem>
<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.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>
</MudItem>
</MudGrid>
</MudHidden>
<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.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 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.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 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.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>
</MudStack>
</MudHidden>
@ -85,7 +85,7 @@
Icon="@Icons.Material.Outlined.AddCard"
Variant="Variant.Outlined" Color="Color.Default"
OnClickCallback="@ViewModel.AddProductClicked"
Content="افزودن سریع محصولات" />
Content="محصول جدید" />
</MudStack>
</MudItem>
@ -96,7 +96,7 @@
Icon="@Icons.Material.Outlined.AddLink"
Variant="Variant.Outlined" Color="Color.Default"
OnClickCallback="@ViewModel.AddBlogClicked"
Content="دسته بندی های محصولات" />
Content="بلاگ جدید" />
</MudStack>
</MudItem>
@ -143,7 +143,7 @@
<PagerContent>
<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>
</PagerContent>

View File

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

View File

@ -6,7 +6,7 @@
@inject IUserUtility UserUtility
@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>
<MudItem xs="12">
<MudStack Row="true" class="mb-5">
@ -27,7 +27,7 @@
<MudStack Row="true" class="w-full">
<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>
</PagerContent>

View File

@ -3,12 +3,12 @@
@page "/notfound"
@inject NavigationManager NavigationManager
<div class="h-full w-screen overflow-hidden p-0">
<div class="w-fulll h-full">
<div class="w-screen h-screen p-0 overflow-hidden bg-[--mud-palette-background]">
<div class="h-full w-fulll">
<MudStack class="mx-auto my-auto">
<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.h5" Align="Align.Center">صفحه مورد نظر شما پیدا نشد یا از بین رفته است ، سریع کام بک بزن به جای قبلی جیگر </MudText>
@ -17,7 +17,7 @@
Icon="@Icons.Material.Outlined.Login"
OnClickCallback="NavigateToHomeAsync"
Color="Color.Default"
class="mx-auto mt-6 w-64 rounded-full"
class="w-64 rounded-full mt-6 mx-auto"
Content="کام بکــــ"></BaseButtonUi>
</MudStack>

View File

@ -8,7 +8,7 @@
@inject IRestWrapper RestWrapper
@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">
<MudGrid>
@ -108,7 +108,7 @@
</MudItem>
</MudGrid>
</MudHidden>
<MudPaper>
<MudPaper >
<MudDataGrid FixedFooter="true" FixedHeader="true" Striped="true"
T="OrderSDto" Items="@ViewModel.MainOrders" CurrentPage="@ViewModel.MainGridCurrentPage"
RowsPerPage="20" Filterable="false" Loading="@ViewModel.IsProcessing"
@ -116,7 +116,7 @@
<ToolBarContent>
<MudGrid class="collapse md:visible">
<MudItem md="5">
<MudItem md="6">
<MudTextField T="string" Placeholder="جست جو بر اساس کد فاکتور" OnClearButtonClick="@ViewModel.SearchAsync"
Adornment="Adornment.Start"
Immediate="true"
@ -127,12 +127,12 @@
@bind-Value="@ViewModel.FactorCodeSearch"
OnAdornmentClick="@ViewModel.SearchAsync"></MudTextField>
</MudItem>
<MudItem md="5">
<MudItem md="6">
<MudAutocomplete ToStringFunc="arg => arg.Title" ValueChanged="@ViewModel.SearchByOrderStatusAsync"
Value="@ViewModel.OrderStatusSearch"
SearchFunc="@ViewModel.OrderStatusSearchAsync"
T="FilterOptionDto<OrderStatus>"
class="my-auto"
class="-mt-0.5"
OnClearButtonClick="async () => await ViewModel.SearchByOrderStatusAsync(null)"
Clearable="true"
Label="وظعیت سفارش">
@ -144,9 +144,6 @@
</ItemTemplate>
</MudAutocomplete>
</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>
</ToolBarContent>
<Columns>

View File

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

View File

@ -7,11 +7,11 @@
@inject IUserUtility UserUtility
@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">
<MudStack>
<MudStack Row="true">
<MudStack class="mx-2 mb-5">
<MudStack class="mb-5 mx-2">
<MudText Typo="Typo.h4">تنظیمات برگه ها</MudText>
<MudText Typo="Typo.caption">برگه های وب سایت خود را ویرایش نمایید</MudText>
</MudStack>
@ -19,7 +19,7 @@
<MudSpacer />
@* <BaseButtonUi Size="Size.Large"
OnClickCallback="ViewModel.SubmitPagesSettingAsync"
class="mb-8 mt-2 w-64 rounded-md"
class="mt-2 mb-8 w-64 rounded-md"
IsProcessing="@ViewModel.IsProcessing"
Icon="@Icons.Material.Outlined.Check"
Content="ثبتـــ اطلاعات" Variant="Variant.Filled" Color="Color.Success" /> *@
@ -28,13 +28,13 @@
<MudItem xs="6">
<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 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 xs="6">
@ -46,10 +46,6 @@
<MudStack Row="true">
<MudText class="my-auto">@navMenuItem.Title</MudText>
<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>
</MudStack>
</TitleContent>

View File

@ -2,16 +2,27 @@
namespace Netina.AdminPanel.PWA.Pages;
public class PagesManagementPageViewModel(
NavigationManager navigationManager,
ISnackbar snackbar,
IUserUtility userUtility,
IRestWrapper restWrapper,
IDialogService dialogService)
: BaseViewModel<ObservableCollection<BasePageSDto>>(userUtility)
public class PagesManagementPageViewModel : BaseViewModel<ObservableCollection<BasePageSDto>>
{
private readonly IUserUtility _userUtility = userUtility;
private readonly IDialogService _dialogService = dialogService;
private readonly NavigationManager _navigationManager;
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()
{
@ -21,7 +32,7 @@ public class PagesManagementPageViewModel(
var token = await _userUtility.GetBearerTokenAsync();
if (token == null)
throw new Exception("Token is null");
var pages = await restWrapper.PageRestApi.ReadAll(token);
var pages = await _restWrapper.PageRestApi.ReadAll(token);
PageDto.Clear();
pages.ForEach(p=>PageDto.Add(p));
}
@ -31,13 +42,13 @@ public class PagesManagementPageViewModel(
if (e.StatusCode == HttpStatusCode.Unauthorized)
{
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)
{
snackbar.Add(ex.Message, Severity.Error);
_snackbar.Add(ex.Message, Severity.Error);
}
finally
{
@ -63,9 +74,9 @@ public class PagesManagementPageViewModel(
if (NewPageDto.Slug.IsNullOrEmpty())
throw new AppException("اسلاگ صفحه را وارد کنید");
await restWrapper.PageRestApi.CreatePage(NewPageDto.DeepClone(), token);
await _restWrapper.PageRestApi.CreatePage(NewPageDto.DeepClone(), token);
NewPageDto = new PageActionRequestDto();
snackbar.Add("برگه مورد نظر با موفقیت افزوده شد", Severity.Success);
_snackbar.Add("برگه مورد نظر با موفقیت افزوده شد", Severity.Success);
await InitializeAsync();
}
@ -75,13 +86,13 @@ public class PagesManagementPageViewModel(
if (e.StatusCode == HttpStatusCode.Unauthorized)
{
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)
{
snackbar.Add(ex.Message, Severity.Error);
_snackbar.Add(ex.Message, Severity.Error);
}
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)
{
try
@ -111,8 +109,8 @@ public class PagesManagementPageViewModel(
if (token == null)
throw new Exception("Token is null");
await restWrapper.PageRestApi.DeletePage(pageId, token);
snackbar.Add("برگه مورد نظر با موفقیت حذف شد", Severity.Success);
await _restWrapper.PageRestApi.DeletePage(pageId, token);
_snackbar.Add("برگه مورد نظر با موفقیت حذف شد", Severity.Success);
await InitializeAsync();
@ -123,13 +121,13 @@ public class PagesManagementPageViewModel(
if (e.StatusCode == HttpStatusCode.Unauthorized)
{
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)
{
snackbar.Add(ex.Message, Severity.Error);
_snackbar.Add(ex.Message, Severity.Error);
}
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 IRestWrapper RestWrapper
<MudStack class="h-full w-full p-8">
<MudStack class="w-full p-8 h-screen bg-[--mud-palette-background-grey]">
<MudGrid>
<MudItem xs="12">
<MudStack Row="true" class="mb-5">
@ -73,7 +73,7 @@
<MudStack Row="true" class="w-full">
<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>
</PagerContent>

View File

@ -133,7 +133,7 @@ public class ManageNavMenuPageViewModel : BaseViewModel<NavMenuSetting>
var token = await _userUtility.GetBearerTokenAsync();
if (token == 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;
if (product.IsNullOrEmpty())
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 IRestWrapper RestWrapper
@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>
<MudItem xs="12">
<MudStack Row="@ViewModel.IsXs.Not()" class="mb-5">
<MudStack Row="true">
<MudText Typo="Typo.h4">محصولاتــــ</MudText>
<MudChip Color="Color.Info" Variant="Variant.Outlined">@ViewModel.TotalItems عدد</MudChip>
</MudStack>
@if (@ViewModel.IsXs.Not())
{
<MudSpacer />
}
<MudStack Row="@ViewModel.IsXs.Not()">
<MudGrid Row="true" class="mb-5">
<MudItem xs="12" sm="6" md="8">
<MudStack Row="true">
<MudText Typo="Typo.h4">محصولاتــــ</MudText>
<MudChip Color="Color.Info" Variant="Variant.Outlined">@ViewModel.TotalItems عدد</MudChip>
</MudStack>
</MudItem>
<MudItem xs="12" sm="6" md="4">
<MudButton Variant="Variant.Filled"
DisableElevation="true"
StartIcon="@Icons.Material.Outlined.Add"
Color="Color.Secondary"
OnClick="@ViewModel.AddProductClicked"
class="w-full md:my-auto md:w-auto">افزودن محصول</MudButton>
<MudButton Variant="Variant.Outlined"
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"
<MudButton Variant="Variant.Filled"
DisableElevation="true"
StartIcon="@Icons.Material.Outlined.Add"
Color="Color.Error"
OnClick="@ViewModel.AddDigikalaProductClicked"
class="w-full md:my-auto md:w-auto">افزودن محصول از دیجیکالا</MudButton>
</MudStack>
</MudStack>
</MudItem>
</MudGrid>
<MudHidden Breakpoint="Breakpoint.SmAndUp">
<MudGrid class="mb-3" Row="true">
<MudItem xs="12" sm="6">
<MudTextField T="string" Placeholder="جست جو بر اساس نام" Adornment="Adornment.Start"
Immediate="true"
<MudTextField T="string" Placeholder="جست جو بر اساس نام" Adornment="Adornment.Start" Immediate="true"
Clearable="true"
@bind-Value="@ViewModel.Search"
ValueChanged="@ViewModel.SearchChanged"
AdornmentIcon="@Icons.Material.Filled.Search" IconSize="Size.Medium" class="my-auto"
OnAdornmentClick="@ViewModel.GetEntitiesAsync"></MudTextField>
OnAdornmentClick="@ViewModel.SearchAsync"></MudTextField>
</MudItem>
<MudItem xs="12" sm="6">
@ -80,54 +69,49 @@
</MudItem>
</MudGrid>
</MudHidden>
<MudPaper>
<MudPaper class="!max-h-[80vh] overflow-auto">
<MudDataGrid FixedFooter="true" FixedHeader="true" Striped="true"
T="ProductSDto" Items="@ViewModel.PageDto" CurrentPage="@ViewModel.CurrentPage"
RowsPerPage="20" Filterable="false" Loading="@ViewModel.IsProcessing"
SortMode="@SortMode.None" Groupable="false">
<ToolBarContent>
<MudGrid class="collapse md:visible">
<MudGrid class="collapse md:visible">
<MudItem xs="12" sm="4">
<MudTextField T="string" Placeholder="جست جو بر اساس نام" Adornment="Adornment.Start"
Immediate="true"
Clearable="true"
@bind-Value="@ViewModel.Search"
AdornmentIcon="@Icons.Material.Filled.Search" IconSize="Size.Medium" class="my-auto"
OnAdornmentClick="@ViewModel.GetEntitiesAsync"></MudTextField>
</MudItem>
<MudItem xs="12" sm="6">
<MudTextField T="string" Placeholder="جست جو بر اساس نام" Adornment="Adornment.Start" Immediate="true"
Clearable="true"
ValueChanged="@ViewModel.SearchChanged"
AdornmentIcon="@Icons.Material.Filled.Search" IconSize="Size.Medium" class="my-auto"
OnAdornmentClick="@ViewModel.SearchAsync"></MudTextField>
</MudItem>
<MudItem xs="12" sm="6">
<MudAutocomplete class="-mt-0.5" Required="true" ToStringFunc="dto => dto.Name"
T="ProductCategorySDto"
Label="بر اساس دسته بندی"
OnClearButtonClick="ViewModel.ClearProductCategorySearch"
SearchFunc="ViewModel.SearchProductCategory"
ValueChanged="ViewModel.ProductCategorySelected"
Clearable="true">
<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.Name</p>
</ItemTemplate>
</MudAutocomplete>
</MudItem>
<MudItem xs="12" sm="2">
<MudSwitch class="mt-3" T="bool"
Value="ViewModel.IsEnable"
ValueChanged="async(flag)=>await ViewModel.ProductEnableChanged(flag)"
Label="فقط محصولات موجود" Color="Color.Info" />
</MudItem>
</MudGrid>
<MudItem xs="12" sm="6">
<MudAutocomplete class="-mt-0.5" Required="true" ToStringFunc="dto => dto.Name"
T="ProductCategorySDto"
Label="بر اساس دسته بندی"
OnClearButtonClick="ViewModel.ClearProductCategorySearch"
SearchFunc="ViewModel.SearchProductCategory"
ValueChanged="ViewModel.ProductCategorySelected"
Clearable="true">
<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.Name</p>
</ItemTemplate>
</MudAutocomplete>
</MudItem>
</MudGrid>
</ToolBarContent>
<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>
</CellTemplate>
</TemplateColumn>
<PropertyColumn Title="نام محصول" Property="arg => arg.PersianName" />
<PropertyColumn Title="دسته بندی" Property="arg => arg.CategoryName" />
<PropertyColumn Title="نام محصول" Property="arg => arg.PersianName"/>
<PropertyColumn Title="دسته بندی" Property="arg => arg.CategoryName"/>
<PropertyColumn Title="برند" Property="arg => arg.BrandName" />
<TemplateColumn T="ProductSDto" Title="پیشنهاد ویژه است">
<CellTemplate>
@if (@context.Item.IsSpecial)
@ -151,53 +136,24 @@
}
</CellTemplate>
</TemplateColumn>
<TemplateColumn T="ProductSDto" Title="موجود است">
<CellTemplate>
@if (@context.Item.IsEnable)
{
<p>بلی</p>
}
else
{
<p>خیر</p>
}
</CellTemplate>
</TemplateColumn>
<TemplateColumn T="ProductSDto" Title="قیمتــ">
<CellTemplate>
<MudTextField class="-mt-2"
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>
<p>@context.Item.Cost.ToString("N0") ریالــ</p>
</CellTemplate>
</TemplateColumn>
<TemplateColumn CellClass="d-flex justify-end">
<CellTemplate>
<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"
Size="@Size.Small"
Variant="@Variant.Outlined"
Color="@Color.Info"
OnClick="async()=>await ViewModel.EditProductClicked(context.Item)" />
OnClick="async()=>await ViewModel.EditProductClicked(context.Item)"/>
<MudIconButton Icon="@Icons.Material.Filled.Delete"
Size="@Size.Small"
Variant="@Variant.Outlined"
OnClick="async () => await ViewModel.DeleteProductAsync(context.Item.Id)"
Color="@Color.Error" />
Color="@Color.Error"/>
</MudStack>
</CellTemplate>
</TemplateColumn>
@ -206,7 +162,7 @@
<MudStack Row="true" class="w-full">
<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>
</PagerContent>
@ -225,12 +181,4 @@
await ViewModel.InitializeAsync();
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 Netina.Domain.Entities.Products;
namespace Netina.AdminPanel.PWA.Pages;
public class ProductsPageViewModel(
NavigationManager navigationManager,
ISnackbar snackbar,
IUserUtility userUtility,
IRestWrapper restWrapper,
IDialogService dialogService,
IBrowserViewportService browserViewportService)
: BaseViewModel<ObservableCollection<ProductSDto>>(userUtility)
public class ProductsPageViewModel : BaseViewModel<ObservableCollection<ProductSDto>>
{
private readonly NavigationManager _navigationManager = navigationManager;
private readonly IUserUtility _userUtility = userUtility;
private readonly NavigationManager _navigationManager;
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 PageCount = 1;
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();
await base.InitializeAsync();
_navigationManager = navigationManager;
_snackbar = snackbar;
_userUtility = userUtility;
_restWrapper = restWrapper;
_dialogService = dialogService;
_browserViewportService = browserViewportService;
}
public async Task GetEntitiesAsync()
public override async Task InitializeAsync()
{
try
{
@ -37,43 +40,81 @@ public class ProductsPageViewModel(
throw new Exception("Token is null");
IsProcessing = true;
PageDto.Clear();
var search = Search.IsNullOrEmpty() ? null : Search;
var dto = await restWrapper.ProductRestApi.ReadAll(CurrentPage, search, SelectedCategory?.Id, IsEnable,token);
var dto = await _restWrapper.ProductRestApi.ReadAll(CurrentPage,null,null, token);
dto.Products.ForEach(d => PageDto.Add(d));
if (PageDto.Count % 20 == 0)
PageCount = CurrentPage + 2;
if (PageDto.Count == 20)
PageCount = 2;
TotalItems = dto.Pager.TotalItems;
IsXs = (await browserViewportService.GetCurrentBreakpointAsync()) == Breakpoint.Xs;
}
catch (ApiException ex)
{
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)
{
snackbar.Add(e.Message, Severity.Error);
_snackbar.Add(e.Message, Severity.Error);
}
finally
{
IsProcessing = false;
}
await base.InitializeAsync();
}
public async Task ChangePageAsync(int page)
{
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()
{
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)
maxWidth = new DialogOptions { FullScreen = true, CloseButton = true };
var dialogResult = await dialogService.ShowAsync<ProductActionDialogBox>("افزودن محصول جدید", maxWidth);
maxWidth = new DialogOptions { FullScreen = true , CloseButton = true};
var dialogResult = await _dialogService.ShowAsync<ProductActionDialogBox>("افزودن محصول جدید", maxWidth);
var result = await dialogResult.Result;
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()
{
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;
if (!result.Canceled && result.Data is bool and true)
{
@ -110,12 +137,9 @@ public class ProductsPageViewModel(
public async Task EditProductClicked(ProductSDto product)
{
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>();
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;
if (!result.Canceled && result.Data is bool and true)
{
@ -125,7 +149,7 @@ public class ProductsPageViewModel(
public async Task DeleteProductAsync(Guid selectedCategoryId)
{
var reference = await dialogService.ShowQuestionDialog($"آیا از حذف محصول اطمینان دارید ?");
var reference = await _dialogService.ShowQuestionDialog($"آیا از حذف محصول اطمینان دارید ?");
var result = await reference.Result;
if (!result.Canceled)
{
@ -135,20 +159,20 @@ public class ProductsPageViewModel(
IsProcessing = true;
var token = await _userUtility.GetBearerTokenAsync();
await restWrapper.CrudDtoApiRest<Product, ProductSDto, Guid>(Address.ProductController)
await _restWrapper.CrudDtoApiRest<Product, ProductSDto, Guid>(Address.ProductController)
.Delete(selectedCategoryId, token);
snackbar.Add("حذف محصول با موفقیت انجام شد", Severity.Success);
_snackbar.Add("حذف محصول با موفقیت انجام شد", Severity.Success);
await InitializeAsync();
}
catch (ApiException ex)
{
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)
{
snackbar.Add(e.Message, Severity.Error);
_snackbar.Add(e.Message, Severity.Error);
}
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();
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
{
if (category.IsNullOrEmpty())
_productCategories = await restWrapper.ProductCategoryRestApi.ReadAll(0);
_productCategories = await _restWrapper.ProductCategoryRestApi.ReadAll(0);
else
_productCategories = await restWrapper.ProductCategoryRestApi.ReadAll(category);
_productCategories = await _restWrapper.ProductCategoryRestApi.ReadAll(category);
return _productCategories;
}
catch (ApiException ex)
{
var exe = await ex.GetContentAsAsync<ApiResult>();
if (exe != null)
snackbar.Add(exe.Message, Severity.Error);
snackbar.Add(ex.Content, Severity.Error);
_snackbar.Add(exe.Message, Severity.Error);
_snackbar.Add(ex.Content, Severity.Error);
return _productCategories;
}
catch (Exception e)
{
snackbar.Add(e.Message, Severity.Error);
_snackbar.Add(e.Message, Severity.Error);
return _productCategories;
}
}
@ -195,13 +261,74 @@ public class ProductsPageViewModel(
public async Task ProductCategorySelected(ProductCategorySDto 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()
{
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)
@ -211,49 +338,16 @@ public class ProductsPageViewModel(
var token = await _userUtility.GetBearerTokenAsync();
if (token == 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)
{
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)
{
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);
_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]
@inject IDialogService DialogService
@ -7,7 +7,7 @@
@inject IUserUtility UserUtility
@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>
<MudItem xs="12">
<MudGrid Row="true" class="mb-5">
@ -87,7 +87,7 @@
<MudStack Row="true" class="w-full">
<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>
</PagerContent>

View File

@ -7,19 +7,19 @@
@inject IUserUtility UserUtility
@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>
<MudItem xs="12">
<MudPaper class="px-5 py-5">
<MudStack Row="true">
<MudStack class="mx-2 mb-5">
<MudStack class="mb-5 mx-2">
<MudText Typo="Typo.h4">فروشـــــگاه من</MudText>
<MudText Typo="Typo.caption">شما می توانید اطلاعات فروشگاه خود را ویرایش نمایید</MudText>
</MudStack>
<MudSpacer/>
<BaseButtonUi Size="Size.Large"
OnClickCallback="ViewModel.SubmitShopSettingAsync"
class="mb-8 mt-2 w-64 rounded-md"
class="mt-2 mb-8 w-64 rounded-md"
IsProcessing="@ViewModel.IsProcessing"
Icon="@Icons.Material.Outlined.Check"
Content="ثبتـــ اطلاعات" Variant="Variant.Filled" Color="Color.Success" />
@ -62,9 +62,9 @@
<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 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>
@ -84,9 +84,9 @@
<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 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>
@ -111,20 +111,20 @@
<MudText Typo="Typo.body1">سایز لوگو شما باید 512 * 512 باشد و به شکل مربع ، تا جایگیری مناسبی داشته باشد</MudText>
<BaseButtonUi Variant="Variant.Outlined" Content="اپلود و تغییر لوگو" OnClickCallback="async () => await ViewModel.SelectFileAsync()" />
</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>
</MudItem>
</MudGrid>
</MudPaper>
<MudPaper class="mt-8 px-5 py-5">
<MudPaper class="px-5 mt-8 py-5">
<MudStack Row="true">
<MudStack class="mx-2 mb-5">
<MudStack class="mb-5 mx-2">
<MudText Typo="Typo.h4">تنظیمات درگاه پرداخت</MudText>
<MudText Typo="Typo.caption">شما می توانید اطلاعات درگاه پرداخت خود را ویرایش نمایید</MudText>
</MudStack>
<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"
IsProcessing="@ViewModel.IsProcessing"
Icon="@Icons.Material.Outlined.Check" Content="ثبتـــ اطلاعات"

View File

@ -7,7 +7,7 @@
@inject IUserUtility UserUtility
@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>
<MudItem xs="12" md="6">
@ -60,7 +60,7 @@
<MudStack Row="true" class="w-full">
<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>
</PagerContent>
@ -110,7 +110,7 @@
<MudStack Row="true" class="w-full">
<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>
</PagerContent>

View File

@ -1,9 +1,9 @@
namespace Netina.AdminPanel.PWA.Services.RestServices;
public interface ICrudApiRest<T, TKey> where T : class
public interface ICrudApiRest<T, in TKey> where T : class
{
[Post("")]
Task<TKey> Create<TCreateCommand>([Body] TCreateCommand payload, [Header("Authorization")] string authorization);
Task Create<TCreateCommand>([Body] TCreateCommand payload, [Header("Authorization")] string authorization);
[Get("")]
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
{
[Post("")]
Task Create<TCreateCommand>([Body] TCreateCommand payload, [Header("Authorization")] string authorization);
Task Create([Body] T payload, [Header("Authorization")] string authorization);
[Post("")]
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
{
[Get("")]
Task<List<OrderSDto>> ReadAll([Query]int page,
[Header("Authorization")] string authorization,
[Query] string? factorCode = null,
[Query] long? selectedDate = null,
[Query] OrderStatus? orderStatus = null,
[Query] OrderQueryDateFilter? dateFilter = null,
[Query] bool? orderBags = null);
Task<List<OrderSDto>> ReadAll([Query]int page, [Query] string? factorCode, [Query] long? selectedDate, [Query] OrderStatus? orderStatus, [Query] OrderQueryDateFilter? dateFilter, [Header("Authorization")] string authorization);
[Get("")]
Task<List<OrderSDto>> ReadAll([Query] int page, [Header("Authorization")] string authorization);
[Get("/{id}")]
Task<OrderLDto> ReadOne(Guid id, [Header("Authorization")] string authorization);
[Post("/{id}/confirm")]
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")]
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);
[Get("/{id}")]
Task<BasePageLDto> ReadById(Guid id, [Header("Authorization")] string authorization);
Task<BasePageSDto> ReadById(Guid id, [Header("Authorization")] string authorization);
[Post("")]
Task CreatePage([Body] PageActionRequestDto request, [Header("Authorization")] string authorization);

View File

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

View File

@ -2,24 +2,17 @@
public interface IProductRestApi
{
[Put("/{productId}/displayed")]
[Put("/{productId}")]
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}")]
Task<GetProductResponseDto> ReadOne(Guid productId);
[Get("/{productId}/sub")]
Task<List<SubProductSDto>> GetSubProductsAsync(Guid productId);
[Get("")]
Task<GetProductsResponseDto> ReadAll([Query] string productName, [Header("Authorization")] string authorization);
[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("")]
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 IBlogRestApi BlogRestApi { get; }
public IDiscountRestApi DiscountRest { get; }
public IReviewRestApi ReviewRestApi { get; }
public IBlogCategoryRestApi BlogCategoryRestApi { get; }
public IRoleRestApi RoleRestApi { get; }
public IOrderRestApi OrderRestApi { get; }
@ -24,5 +23,4 @@ public interface IRestWrapper
public IDashboardApiRest DashboardApiRest { get; }
public ISettingRestApi SettingRestApi { 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;
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
{
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 IBlogRestApi BlogRestApi => RestService.For<IBlogRestApi>($"{baseApiAddress}{Address.BlogController}", 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 IRoleRestApi RoleRestApi => RestService.For<IRoleRestApi>($"{baseApiAddress}{Address.RoleController}", 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 IDashboardApiRest DashboardApiRest => RestService.For<IDashboardApiRest>($"{baseApiAddress}{Address.DashboardController}", 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.Domain.Models.Claims
@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": {
"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",
"postcss": "^8.5.3",
"postcss-cli": "^11.0.1",
"tailwindcss": "^3.4.17"
"postcss": "^8.4.33",
"postcss-cli": "^11.0.0",
"tailwindcss": "^3.4.3"
},
"name": "netina.admin.pwa",
"version": "1.0.0",

View File

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

View File

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

View File

@ -10,15 +10,9 @@
},
"WebSiteUrl": "https://vesmeh.com",
"AdminPanelBaseUrl": "https://admin.vesmeh.com",
"StorageBaseUrl": "https://storage.vesmeh.com",
//"ApiUrl": "https://api.vesmeh.com/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
"StorageBaseUrl": "https://storage.vesmeh.com/",
//"ApiUrl": "https://api.vesmeh.com/api"
"ApiUrl": "http://localhost:32770/api"
//"WebSiteUrl": "https://hamyanedalat.com",
//"AdminPanelBaseUrl": "https://admin.hamyanedalat.com",

View File

@ -12,5 +12,5 @@
"AdminPanelBaseUrl": "https://admin.hamyanedalat.com",
"StorageBaseUrl": "https://storage.hamyanedalat.com",
"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-secondary: rgba(229, 159, 46, 1);
--color-background: rgba(243, 244, 246, 1);
}
}
.revert-tailwind {
all: initial;
}
@ -113,16 +113,6 @@
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 {
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 {
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 {

View File

@ -1,111 +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
*//*
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)
@ -970,7 +864,116 @@ input:checked + .toggle-bg {
--color-primary: rgba(9, 16, 68, 1);
--color-secondary: rgba(229, 159, 46, 1);
--color-background: rgba(243, 244, 246, 1);
}
*, ::before, ::after {
--tw-border-spacing-x: 0;
--tw-border-spacing-y: 0;
--tw-translate-x: 0;
--tw-translate-y: 0;
--tw-rotate: 0;
--tw-skew-x: 0;
--tw-skew-y: 0;
--tw-scale-x: 1;
--tw-scale-y: 1;
--tw-pan-x: ;
--tw-pan-y: ;
--tw-pinch-zoom: ;
--tw-scroll-snap-strictness: proximity;
--tw-gradient-from-position: ;
--tw-gradient-via-position: ;
--tw-gradient-to-position: ;
--tw-ordinal: ;
--tw-slashed-zero: ;
--tw-numeric-figure: ;
--tw-numeric-spacing: ;
--tw-numeric-fraction: ;
--tw-ring-inset: ;
--tw-ring-offset-width: 0px;
--tw-ring-offset-color: #fff;
--tw-ring-color: rgb(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 {
width: 100%;
}
@ -1043,9 +1046,6 @@ input:checked + .toggle-bg {
.top-0 {
top: 0px;
}
.\!z-\[9999\] {
z-index: 9999 !important;
}
.z-10 {
z-index: 10;
}
@ -1061,6 +1061,9 @@ input:checked + .toggle-bg {
.z-50 {
z-index: 50;
}
.m-1 {
margin: 0.25rem;
}
.m-1\.5 {
margin: 0.375rem;
}
@ -1091,6 +1094,10 @@ input:checked + .toggle-bg {
margin-left: 1rem;
margin-right: 1rem;
}
.mx-5 {
margin-left: 1.25rem;
margin-right: 1.25rem;
}
.mx-auto {
margin-left: auto;
margin-right: auto;
@ -1125,30 +1132,24 @@ input:checked + .toggle-bg {
.-mb-4 {
margin-bottom: -1rem;
}
.-ml-1 {
margin-left: -0.25rem;
}
.-ml-4 {
margin-left: -1rem;
}
.-ml-5 {
margin-left: -1.25rem;
}
.-ml-6 {
margin-left: -1.5rem;
}
.-mr-2 {
margin-right: -0.5rem;
}
.-mt-0 {
margin-top: -0px;
}
.-mt-0\.5 {
margin-top: -0.125rem;
}
.-mt-1 {
margin-top: -0.25rem;
}
.-mt-2 {
margin-top: -0.5rem;
}
.-mt-3 {
margin-top: -0.75rem;
}
@ -1182,9 +1183,6 @@ input:checked + .toggle-bg {
.mr-2 {
margin-right: 0.5rem;
}
.mr-3 {
margin-right: 0.75rem;
}
.mt-1 {
margin-top: 0.25rem;
}
@ -1203,9 +1201,6 @@ input:checked + .toggle-bg {
.mt-4 {
margin-top: 1rem;
}
.mt-5 {
margin-top: 1.25rem;
}
.mt-6 {
margin-top: 1.5rem;
}
@ -1215,6 +1210,12 @@ input:checked + .toggle-bg {
.mt-8 {
margin-top: 2rem;
}
.line-clamp-1 {
overflow: hidden;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 1;
}
.block {
display: block;
}
@ -1352,12 +1353,6 @@ input:checked + .toggle-bg {
.w-screen {
width: 100vw;
}
.min-w-\[310px\] {
min-width: 310px;
}
.min-w-\[340px\] {
min-width: 340px;
}
.flex-1 {
flex: 1 1 0%;
}
@ -1471,12 +1466,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;
}
@ -1544,10 +1533,6 @@ input:checked + .toggle-bg {
.border-dashed {
border-style: dashed;
}
.border-blue-400 {
--tw-border-opacity: 1;
border-color: rgb(118 169 250 / var(--tw-border-opacity));
}
.border-blue-500 {
--tw-border-opacity: 1;
border-color: rgb(63 131 248 / var(--tw-border-opacity));
@ -1663,6 +1648,10 @@ input:checked + .toggle-bg {
padding-left: 0px;
padding-right: 0px;
}
.px-1 {
padding-left: 0.25rem;
padding-right: 0.25rem;
}
.px-1\.5 {
padding-left: 0.375rem;
padding-right: 0.375rem;
@ -1683,6 +1672,10 @@ input:checked + .toggle-bg {
padding-left: 1.25rem;
padding-right: 1.25rem;
}
.py-0 {
padding-top: 0px;
padding-bottom: 0px;
}
.py-0\.5 {
padding-top: 0.125rem;
padding-bottom: 0.125rem;
@ -1711,22 +1704,9 @@ input:checked + .toggle-bg {
padding-top: 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 {
padding-top: 0.5rem;
}
.pt-3 {
padding-top: 0.75rem;
}
.pt-4 {
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/ttf/iranyekanwebextrablackfanum.ttf') format('truetype');
}
.revert-tailwind {
all: initial;
}
@ -1971,16 +1950,6 @@ input:checked + .toggle-bg {
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 {
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 {
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 {
@ -2263,10 +2232,6 @@ code {
width: 16rem;
}
.sm\:w-full {
width: 100%;
}
.sm\:py-3 {
padding-top: 0.75rem;
padding-bottom: 0.75rem;
@ -2312,10 +2277,6 @@ code {
padding: 1.25rem;
}
.md\:p-8 {
padding: 2rem;
}
.md\:px-10 {
padding-left: 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);
}
*, ::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 {
width: 100%;
}
@ -1113,10 +1113,6 @@ input:checked + .toggle-bg {
top: 0px;
}
.\!z-\[9999\] {
z-index: 9999 !important;
}
.z-10 {
z-index: 10;
}
@ -1137,6 +1133,10 @@ input:checked + .toggle-bg {
z-index: 50;
}
.m-1 {
margin: 0.25rem;
}
.m-1\.5 {
margin: 0.375rem;
}
@ -1175,6 +1175,11 @@ input:checked + .toggle-bg {
margin-right: 1rem;
}
.mx-5 {
margin-left: 1.25rem;
margin-right: 1.25rem;
}
.mx-auto {
margin-left: auto;
margin-right: auto;
@ -1218,18 +1223,10 @@ input:checked + .toggle-bg {
margin-bottom: -1rem;
}
.-ml-1 {
margin-left: -0.25rem;
}
.-ml-4 {
margin-left: -1rem;
}
.-ml-5 {
margin-left: -1.25rem;
}
.-ml-6 {
margin-left: -1.5rem;
}
@ -1238,6 +1235,10 @@ input:checked + .toggle-bg {
margin-right: -0.5rem;
}
.-mt-0 {
margin-top: -0px;
}
.-mt-0\.5 {
margin-top: -0.125rem;
}
@ -1246,10 +1247,6 @@ input:checked + .toggle-bg {
margin-top: -0.25rem;
}
.-mt-2 {
margin-top: -0.5rem;
}
.-mt-3 {
margin-top: -0.75rem;
}
@ -1294,10 +1291,6 @@ input:checked + .toggle-bg {
margin-right: 0.5rem;
}
.mr-3 {
margin-right: 0.75rem;
}
.mt-1 {
margin-top: 0.25rem;
}
@ -1322,10 +1315,6 @@ input:checked + .toggle-bg {
margin-top: 1rem;
}
.mt-5 {
margin-top: 1.25rem;
}
.mt-6 {
margin-top: 1.5rem;
}
@ -1338,6 +1327,13 @@ input:checked + .toggle-bg {
margin-top: 2rem;
}
.line-clamp-1 {
overflow: hidden;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 1;
}
.block {
display: block;
}
@ -1520,14 +1516,6 @@ input:checked + .toggle-bg {
width: 100vw;
}
.min-w-\[310px\] {
min-width: 310px;
}
.min-w-\[340px\] {
min-width: 340px;
}
.flex-1 {
flex: 1 1 0%;
}
@ -1674,14 +1662,6 @@ input:checked + .toggle-bg {
overflow: hidden;
}
.overflow-x-auto {
overflow-x: auto;
}
.overflow-y-auto {
overflow-y: auto;
}
.overflow-x-hidden {
overflow-x: hidden;
}
@ -1770,11 +1750,6 @@ input:checked + .toggle-bg {
border-style: dashed;
}
.border-blue-400 {
--tw-border-opacity: 1;
border-color: rgb(118 169 250 / var(--tw-border-opacity));
}
.border-blue-500 {
--tw-border-opacity: 1;
border-color: rgb(63 131 248 / var(--tw-border-opacity));
@ -1922,6 +1897,11 @@ input:checked + .toggle-bg {
padding-right: 0px;
}
.px-1 {
padding-left: 0.25rem;
padding-right: 0.25rem;
}
.px-1\.5 {
padding-left: 0.375rem;
padding-right: 0.375rem;
@ -1947,6 +1927,11 @@ input:checked + .toggle-bg {
padding-right: 1.25rem;
}
.py-0 {
padding-top: 0px;
padding-bottom: 0px;
}
.py-0\.5 {
padding-top: 0.125rem;
padding-bottom: 0.125rem;
@ -1982,27 +1967,10 @@ input:checked + .toggle-bg {
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 {
padding-top: 0.5rem;
}
.pt-3 {
padding-top: 0.75rem;
}
.pt-4 {
padding-top: 1rem;
}
@ -2321,17 +2289,6 @@ input:checked + .toggle-bg {
/* Firefox */
}
.auto-scrollbar {
-ms-overflow-style: auto;
/* IE and Edge */
scrollbar-width: auto;
/* Firefox */
}
.auto-scrollbar::-webkit-scrollbar {
display: block;
}
.mud-dialog-title {
font-family: iranyekan !important;
}
@ -2613,10 +2570,6 @@ code {
width: 16rem;
}
.sm\:w-full {
width: 100%;
}
.sm\:py-3 {
padding-top: 0.75rem;
padding-bottom: 0.75rem;
@ -2661,10 +2614,6 @@ code {
padding: 1.25rem;
}
.md\:p-8 {
padding: 2rem;
}
.md\:px-10 {
padding-left: 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