change to comment

subProduct
Amir Hossein Khademi 2024-09-25 17:08:35 +03:30
parent 0fea79efe6
commit 4b13db02aa
12 changed files with 394 additions and 4 deletions

View File

@ -28,6 +28,12 @@
</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">

View File

@ -97,8 +97,11 @@ public class ProductActionDialogBoxViewModel : BaseViewModel<ProductLDto>
if (!PageDto.Slug.IsNullOrEmpty())
{
var faq = await _restWrapper.FaqApiRest.ReadOne(PageDto.GetWebSiteUrl());
foreach (var pair in faq.Faqs)
Faqs.Add(pair.Key, pair.Value);
if (faq.Faqs != null)
{
foreach (var pair in faq.Faqs)
Faqs.Add(pair.Key, pair.Value);
}
}
if (productLDto.SpecialOffer != null)

View File

@ -0,0 +1,79 @@
@inject ISnackbar Snackbar
@inject IRestWrapper RestWrapper
@inject IUserUtility UserUtility
@inject IDialogService DialogService
<MudDialog class="mx-auto">
<DialogContent>
<MudStack>
<MudDivider class="-mt-3" />
<MudGrid>
<MudItem sm="8">
<MudField Label="عنوان" Variant="Variant.Outlined">@ViewModel.PageDto.Title</MudField>
</MudItem>
<MudItem sm="4">
<MudField Label="نام نام خانوادگی" Variant="Variant.Outlined">@ViewModel.PageDto.UserFullName</MudField>
</MudItem>
<MudItem sm="12">
<MudTextField @bind-Value="@ViewModel.PageDto.Content" Lines="4" T="string" Label="متن نظر" Variant="Variant.Outlined"></MudTextField>
</MudItem>
</MudGrid>
<MudPaper>
</MudPaper>
<MudDivider class="my-1" />
<MudGrid>
<MudItem sm="11">
<MudTextField @bind-Value="ViewModel.AnswerContent" Lines="4" T="string" Label="پاسخ دادن به نظر" Variant="Variant.Outlined"></MudTextField>
</MudItem>
<MudItem sm="1">
<MudButton class="mt-2 py-7 mr-1"
FullWidth="true"
Variant="Variant.Outlined"
Size="Size.Large"
Color="Color.Info" OnClick="@(async()=>await ViewModel.SubmitAnswer())">ثبت</MudButton>
</MudItem>
</MudGrid>
</MudStack>
</DialogContent>
<DialogActions>
<MudStack Row="true" class="w-full mx-4 mb-2">
<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

@ -0,0 +1,87 @@
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

@ -24,4 +24,5 @@ public static class Address
public static string SettingController => $"/setting";
public static string DistrictController => $"/district";
public static string FaqController => $"/faq";
public static string CommentController => $"/comment";
}

View File

@ -5,8 +5,8 @@
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<ServiceWorkerAssetsManifest>service-worker-assets.js</ServiceWorkerAssetsManifest>
<AssemblyVersion>1.3.12.16</AssemblyVersion>
<FileVersion>1.3.12.16</FileVersion>
<AssemblyVersion>1.4.14.19</AssemblyVersion>
<FileVersion>1.4.14.19</FileVersion>
<AssemblyName>$(MSBuildProjectName)</AssemblyName>
</PropertyGroup>

View File

@ -0,0 +1,67 @@
@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" />
<TemplateColumn CellClass="d-flex justify-end">
<CellTemplate>
<MudStack Row="true">
<MudButton Variant="Variant.Outlined"
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

@ -0,0 +1,125 @@
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

@ -14,6 +14,7 @@ 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; }

View File

@ -0,0 +1,17 @@
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

@ -27,6 +27,7 @@ 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);

View File

@ -1178,6 +1178,9 @@ input:checked + .toggle-bg {
.mb-8 {
margin-bottom: 2rem;
}
.ml-1 {
margin-left: 0.25rem;
}
.ml-16 {
margin-left: 4rem;
}