feat : add image for product category and brands

release
Amir Hossein Khademi 2024-02-28 13:37:26 +03:30
parent 25ade7ce1c
commit 7f267a882c
5 changed files with 220 additions and 32 deletions

View File

@ -5,6 +5,7 @@
@inject ISnackbar Snackbar
@inject IRestWrapper RestWrapper
@inject IUserUtility UserUtility
@inject IDialogService DialogService
<MudDialog class="mx-auto">
<DialogContent>
@ -34,6 +35,46 @@
<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>
<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" />
<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>
}
</MudStack>
</MudItem>
</MudGrid>
</MudStack>
@ -66,6 +107,7 @@
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;
@ -74,18 +116,42 @@
private bool _isEditing;
private string _pageUrl = string.Empty;
protected override Task OnParametersSetAsync()
protected override async Task OnParametersSetAsync()
{
if (Brand != null)
{
_isEditing = true;
_hasSpecialPage = Brand.HasSpecialPage;
_description = Brand.Description;
_englishName = Brand.EnglishName;
_persianName = Brand.PersianName;
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;
}
}
return base.OnParametersSetAsync();
await base.OnParametersSetAsync();
}
private async Task SubmitCreateAsync()
@ -96,7 +162,9 @@
throw new AppException("لطفا نام برند را وارد کنید");
_isProcessing = true;
var token = await UserUtility.GetBearerTokenAsync();
var request = new CreateBrandCommand(_persianName,_englishName, _description, _hasSpecialPage, string.Empty, new List<StorageFileSDto>());
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));
}
@ -125,9 +193,10 @@
if (_englishName.IsNullOrEmpty())
throw new AppException("لطفا نام برند را وارد کنید");
_isProcessing = true;
await Task.Delay(1000);
var token = await UserUtility.GetBearerTokenAsync();
var request = new UpdateBrandCommand(Brand.Id, _persianName,_englishName, _description, _hasSpecialPage, string.Empty , new List<StorageFileSDto>());
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();
}
@ -148,4 +217,20 @@
_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,6 +1,7 @@
@inject ISnackbar Snackbar
@inject IRestWrapper RestWrapper
@inject IUserUtility UserUtility
@inject IDialogService DialogService
<MudDialog class="mx-auto" DisableSidePadding="true">
<DialogContent>
@ -23,7 +24,7 @@
</MudItem>
<MudItem sm="12" lg="4" md="6">
<MudAutocomplete Required="true" ToStringFunc="dto => dto.Name" @bind-Value="@ViewModel.SelectedCategory"
SearchFunc="ViewModel.SearchCity"
SearchFunc="ViewModel.SearchCategory"
T="ProductCategorySDto"
Label="دسته پدر"
Variant="Variant.Outlined">
@ -42,6 +43,46 @@
</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="max-h-[20rem] lg:max-h-[25rem] overflow-y-scroll overflow-x-hidden">
<MudStack class="mt-4 mb-2" Spacing="0">
@ -90,12 +131,13 @@
[Parameter]
public ProductCategorySDto? Category { get; set; }
protected override Task OnInitializedAsync()
protected override async Task OnInitializedAsync()
{
if (Category == null)
ViewModel = new ProductCategoryActionDialogBoxViewModel(Snackbar, RestWrapper, UserUtility, MudDialog);
ViewModel = new ProductCategoryActionDialogBoxViewModel(Snackbar, RestWrapper, UserUtility, MudDialog,DialogService);
else
ViewModel = new ProductCategoryActionDialogBoxViewModel(Snackbar, RestWrapper, UserUtility, MudDialog,Category);
return base.OnInitializedAsync();
ViewModel = new ProductCategoryActionDialogBoxViewModel(Snackbar, RestWrapper, UserUtility, MudDialog, DialogService, Category);
await ViewModel.InitializeAsync();
await base.OnInitializedAsync();
}
}

View File

@ -1,4 +1,11 @@
namespace NetinaShop.AdminPanel.PWA.Dialogs;
using MediatR;
using NetinaShop.Common.Models.Mapper;
using NetinaShop.Domain.Dtos.LargDtos;
using NetinaShop.Domain.Entities.Discounts;
using NetinaShop.Domain.Entities.Products;
using System.Linq.Dynamic.Core.Tokenizer;
namespace NetinaShop.AdminPanel.PWA.Dialogs;
public class ProductCategoryActionDialogBoxViewModel:BaseViewModel
{
@ -6,21 +13,24 @@ public class ProductCategoryActionDialogBoxViewModel:BaseViewModel
private readonly IRestWrapper _restWrapper;
private readonly IUserUtility _userUtility;
private readonly MudDialogInstance _mudDialog;
private readonly IDialogService _dialogService;
public ProductCategoryActionDialogBoxViewModel(ISnackbar snackbar, IRestWrapper restWrapper, IUserUtility userUtility, MudDialogInstance mudDialog)
public ProductCategoryActionDialogBoxViewModel(ISnackbar snackbar, IRestWrapper restWrapper, IUserUtility userUtility, MudDialogInstance mudDialog, IDialogService dialogService)
{
_snackbar = snackbar;
_restWrapper = restWrapper;
_userUtility = userUtility;
_mudDialog = mudDialog;
_dialogService = dialogService;
}
public ProductCategoryActionDialogBoxViewModel(ISnackbar snackbar, IRestWrapper restWrapper, IUserUtility userUtility, MudDialogInstance mudDialog,ProductCategorySDto category)
public ProductCategoryActionDialogBoxViewModel(ISnackbar snackbar, IRestWrapper restWrapper, IUserUtility userUtility, MudDialogInstance mudDialog, IDialogService dialogService,ProductCategorySDto category)
{
_snackbar = snackbar;
_restWrapper = restWrapper;
_userUtility = userUtility;
_mudDialog = mudDialog;
_dialogService = dialogService;
Category = category;
}
public void Cancel() => _mudDialog.Cancel();
@ -29,6 +39,7 @@ public class ProductCategoryActionDialogBoxViewModel:BaseViewModel
public string Description = string.Empty;
public bool IsMain;
public bool IsEditing = false;
public readonly ObservableCollection<StorageFileSDto> Files = new ObservableCollection<StorageFileSDto>();
private ProductCategorySDto? _category = null;
[Parameter]
@ -40,13 +51,46 @@ public class ProductCategoryActionDialogBoxViewModel:BaseViewModel
_category = value;
if (_category != null)
{
Name = _category.Name;
Description = _category.Description;
IsEditing = true;
}
}
}
public override async Task InitializeAsync()
{
if (IsEditing && Category != null)
{
try
{
IsProcessing = true;
var response = await _restWrapper.CrudDtoApiRest<ProductCategory,ProductCategoryLDto,Guid>(Address.ProductCategoryController).ReadOne(Category.Id);
var categoryLDto = response;
categoryLDto.Files.ForEach(f => Files.Add(f));
SelectedCategory = new ProductCategorySDto { Id = categoryLDto.ParentId, Name = categoryLDto.ParentName };
Name = categoryLDto.Name;
Description = categoryLDto.Description;
IsMain = categoryLDto.IsMain;
}
catch (ApiException ex)
{
var exe = await ex.GetContentAsAsync<ApiResult>();
if (exe != null)
_snackbar.Add(exe.Message, Severity.Error);
_snackbar.Add(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
@ -55,7 +99,9 @@ public class ProductCategoryActionDialogBoxViewModel:BaseViewModel
throw new AppException("لطفا نام دسته را وارد کنید");
IsProcessing = true;
var token = await _userUtility.GetBearerTokenAsync();
var request = new CreateProductCategoryCommand(Name, Description, IsMain, SelectedCategory?.Id ?? default, new List<StorageFileSDto>());
if (token == null)
throw new AppException("Token is null");
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));
}
@ -88,7 +134,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, new List<StorageFileSDto>());
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));
}
@ -112,7 +158,7 @@ public class ProductCategoryActionDialogBoxViewModel:BaseViewModel
private List<ProductCategorySDto> _productCategories = new List<ProductCategorySDto>();
public ProductCategorySDto? SelectedCategory;
public async Task<IEnumerable<ProductCategorySDto>> SearchCity(string city)
public async Task<IEnumerable<ProductCategorySDto>> SearchCategory(string city)
{
try
{
@ -136,4 +182,20 @@ public class ProductCategoryActionDialogBoxViewModel:BaseViewModel
return _productCategories;
}
}
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

@ -13,6 +13,9 @@ public interface ICrudApiRest<T, in TKey> where T : class
[Get("/{key}")]
Task<T> ReadOne(TKey key, [Header("Authorization")] string authorization);
[Get("/{key}")]
Task<T> ReadOne(TKey key);
[Put("")]
Task Update<TUpdateCommand>([Body] TUpdateCommand payload, [Header("Authorization")] string authorization);

View File

@ -1,20 +1,16 @@
{
"version": "0.17.18.25",
"versionNumber": 0.101623,
"versionNumber": 0.171825,
"versionName": "چرتکه",
"description": "",
"features": [
"افزودن خبرنامه",
"افزودن نام انگلیسی برند",
"افزودن دیالوگ اپدیت جدید",
"افزودن تخفیف همکاری در فروش",
"افزودن قابلیت تغییر نمایش سریع کالا"
"افزودن تم دارک",
"تکمیل پروسه سفارش گیری",
"قابلیت افزودن تصویر به برند ها",
"قابلیت افزودن تصویر به دسته بندی محصولات"
],
"bugFixes": [
"حل مشکلات امنیتی",
"حل مشکل ویرایش کالا",
"حل مشکل فیلترهای کالاها",
"حل مشکل رسپانسیو صفحه اصلی",
"حل مشکل انتخاب دسته بندی در صفحه کالاها"
"رفع مشکلات رسپانسیو"
]
}