Add product and category management pages
This commit is contained in:
@@ -17,7 +17,7 @@
|
||||
}
|
||||
});
|
||||
}
|
||||
</NotAuthorized>
|
||||
</NotAuthorized>
|
||||
</AuthorizeRouteView>
|
||||
</Found>
|
||||
<NotFound>
|
||||
@@ -27,4 +27,10 @@
|
||||
</LayoutView>
|
||||
</NotFound>
|
||||
</Router>
|
||||
</CascadingAuthenticationState>
|
||||
</CascadingAuthenticationState>
|
||||
|
||||
@code{
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -21,10 +21,15 @@
|
||||
|
||||
<PackageReference Include="Blazored.LocalStorage" Version="4.5.0" />
|
||||
|
||||
<PackageReference Include="Foursat.BackOffice.BFF.Category.Protobuf" Version="0.0.1" />
|
||||
|
||||
<PackageReference Include="Foursat.BackOffice.BFF.Otp.Protobuf" Version="0.0.111" />
|
||||
|
||||
<PackageReference Include="FourSat.BackOffice.BFF.Package.Protobuf" Version="0.0.111" />
|
||||
|
||||
<PackageReference Include="Foursat.BackOffice.BFF.Products.Protobuf" Version="0.0.3" />
|
||||
|
||||
|
||||
<PackageReference Include="Foursat.BackOffice.BFF.Role.Protobuf" Version="0.0.111" />
|
||||
|
||||
<PackageReference Include="Foursat.BackOffice.BFF.User.Protobuf" Version="0.0.111" />
|
||||
|
||||
@@ -6,9 +6,9 @@
|
||||
<MudStack Row="true" AlignItems="AlignItems.Center">
|
||||
<MudText Typo="Typo.subtitle2">فیلتر ها</MudText>
|
||||
<MudSpacer />
|
||||
@if (IsFilterd)
|
||||
@if (IsFiltered)
|
||||
{
|
||||
<MudButton Color="Color.Error" Variant="Variant.Text" Size="Size.Small" OnClick="@(async () => await OnClearFilterClick.InvokeAsync())">خذف فیلتر</MudButton>
|
||||
<MudButton Color="Color.Error" Variant="Variant.Text" Size="Size.Small" OnClick="@(async () => await OnClearFilterClick.InvokeAsync())">حذف فیلتر</MudButton>
|
||||
}
|
||||
</MudStack>
|
||||
<MudItem Style="height:100%;">
|
||||
@@ -32,4 +32,3 @@
|
||||
</MudItem>
|
||||
</MudStack>
|
||||
|
||||
|
||||
|
||||
@@ -3,15 +3,9 @@ using Microsoft.AspNetCore.Components;
|
||||
namespace BackOffice.Common.BaseComponents;
|
||||
public partial class BasePageComponent
|
||||
{
|
||||
[Parameter] public RenderFragment Filters { get; set; }
|
||||
[Parameter] public RenderFragment Content { get; set; }
|
||||
[Parameter] public bool IsFilterd { get; set; }
|
||||
[Parameter] public RenderFragment Filters { get; set; } = default!;
|
||||
[Parameter] public RenderFragment Content { get; set; } = default!;
|
||||
[Parameter] public bool IsFiltered { get; set; }
|
||||
[Parameter] public EventCallback OnSubmitClick { get; set; }
|
||||
[Parameter] public EventCallback OnClearFilterClick { get; set; }
|
||||
private bool _open = true;
|
||||
|
||||
private void ToggleDrawer()
|
||||
{
|
||||
_open = !_open;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,12 +55,17 @@ public partial class DateRangePicker
|
||||
}
|
||||
private async Task OnClickOK()
|
||||
{
|
||||
_picker.CloseAsync();
|
||||
await OnChanged.InvokeAsync(_picker.DateRange);
|
||||
if (_picker.DateRange is not null)
|
||||
{
|
||||
await OnChanged.InvokeAsync(_picker.DateRange);
|
||||
}
|
||||
|
||||
await _picker.CloseAsync();
|
||||
}
|
||||
private async Task OnClickClear()
|
||||
{
|
||||
_picker.CloseAsync();
|
||||
await OnChanged.InvokeAsync(_picker.DateRange);
|
||||
_dateRange = new DateRange();
|
||||
await OnChanged.InvokeAsync(_dateRange);
|
||||
await _picker.CloseAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,23 +2,22 @@
|
||||
using BackOffice.BFF.Otp.Protobuf.Protos.Otp;
|
||||
using BackOffice.BFF.Package.Protobuf.Protos.Package;
|
||||
using BackOffice.BFF.Role.Protobuf.Protos.Role;
|
||||
using BackOffice.BFF.Products.Protobuf.Protos.Products;
|
||||
using BackOffice.BFF.User.Protobuf.Protos.User;
|
||||
using BackOffice.BFF.UserAddress.Protobuf.Protos.UserAddress;
|
||||
using BackOffice.BFF.UserOrder.Protobuf.Protos.UserOrder;
|
||||
using BackOffice.BFF.UserRole.Protobuf.Protos.UserRole;
|
||||
using BackOffice.BFF.Category.Protobuf.Protos.Category;
|
||||
using BackOffice.Common.Utilities;
|
||||
using Blazored.LocalStorage;
|
||||
using Google.Protobuf.Reflection;
|
||||
using Grpc.Core;
|
||||
using Grpc.Core.Interceptors;
|
||||
using Grpc.Net.Client;
|
||||
using Grpc.Net.Client.Web;
|
||||
using Microsoft.AspNetCore.Components.Authorization;
|
||||
using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
|
||||
using MudBlazor.Services;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using static MudBlazor.Colors;
|
||||
|
||||
|
||||
namespace Microsoft.Extensions.DependencyInjection;
|
||||
@@ -48,25 +47,35 @@ public static class ConfigureServices
|
||||
|
||||
|
||||
|
||||
public static IServiceCollection AddGrpcServices(this IServiceCollection services, IConfiguration configuration) //
|
||||
public static IServiceCollection AddGrpcServices(this IServiceCollection services, IConfiguration configuration)
|
||||
{
|
||||
var baseUri = configuration["GwUrl"];
|
||||
Console.WriteLine();
|
||||
Console.WriteLine(baseUri);
|
||||
var httpClient = new HttpClient(new GrpcWebHandler(GrpcWebMode.GrpcWeb, new HttpClientHandler()));
|
||||
httpClient.Timeout = TimeSpan.FromMinutes(10); // TODO Check Timeout
|
||||
var serviceProvider = services.BuildServiceProvider();
|
||||
var channel = CreateAuthenticatedChannel(baseUri, httpClient, serviceProvider);
|
||||
services.AddSingleton<CallInvoker>(sp =>
|
||||
{
|
||||
var config = sp.GetRequiredService<IConfiguration>();
|
||||
var baseUri = config["GwUrl"];
|
||||
|
||||
if (string.IsNullOrWhiteSpace(baseUri))
|
||||
{
|
||||
throw new InvalidOperationException("Configuration value 'GwUrl' is missing or empty.");
|
||||
}
|
||||
|
||||
var httpClient = new HttpClient(new GrpcWebHandler(GrpcWebMode.GrpcWeb, new HttpClientHandler()))
|
||||
{
|
||||
Timeout = TimeSpan.FromMinutes(10)
|
||||
};
|
||||
|
||||
services.AddTransient(sp => new OtpContract.OtpContractClient(channel));
|
||||
services.AddTransient(sp => new PackageContract.PackageContractClient(channel));
|
||||
services.AddTransient(sp => new RoleContract.RoleContractClient(channel));
|
||||
services.AddTransient(sp => new UserContract.UserContractClient(channel));
|
||||
services.AddTransient(sp => new UserAddressContract.UserAddressContractClient(channel));
|
||||
services.AddTransient(sp => new UserOrderContract.UserOrderContractClient(channel));
|
||||
services.AddTransient(sp => new UserRoleContract.UserRoleContractClient(channel));
|
||||
return CreateAuthenticatedChannel(baseUri, httpClient, sp);
|
||||
});
|
||||
|
||||
services.AddTransient(sp => new OtpContract.OtpContractClient(sp.GetRequiredService<CallInvoker>()));
|
||||
services.AddTransient(sp => new PackageContract.PackageContractClient(sp.GetRequiredService<CallInvoker>()));
|
||||
services.AddTransient(sp => new ProductsContract.ProductsContractClient(sp.GetRequiredService<CallInvoker>()));
|
||||
services.AddTransient(sp => new RoleContract.RoleContractClient(sp.GetRequiredService<CallInvoker>()));
|
||||
services.AddTransient(sp => new UserContract.UserContractClient(sp.GetRequiredService<CallInvoker>()));
|
||||
services.AddTransient(sp => new UserAddressContract.UserAddressContractClient(sp.GetRequiredService<CallInvoker>()));
|
||||
services.AddTransient(sp => new UserOrderContract.UserOrderContractClient(sp.GetRequiredService<CallInvoker>()));
|
||||
services.AddTransient(sp => new UserRoleContract.UserRoleContractClient(sp.GetRequiredService<CallInvoker>()));
|
||||
services.AddTransient(sp => new CategoryContract.CategoryContractClient(sp.GetRequiredService<CallInvoker>()));
|
||||
|
||||
return services;
|
||||
}
|
||||
@@ -98,7 +107,6 @@ public static class ConfigureServices
|
||||
MaxReceiveMessageSize = 1000 * 1024 * 1024, // 1 GB
|
||||
MaxSendMessageSize = 1000 * 1024 * 1024 // 1 GB
|
||||
});
|
||||
var invoker = channel.Intercept(new ErrorHandlerInterceptor());
|
||||
return invoker;
|
||||
return channel.Intercept(new ErrorHandlerInterceptor());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
using Grpc.Core.Interceptors;
|
||||
using Grpc.Core;
|
||||
using Grpc.Core;
|
||||
using Grpc.Core.Interceptors;
|
||||
using MudBlazor;
|
||||
|
||||
namespace BackOffice.Common.Utilities;
|
||||
|
||||
public class ErrorHandlerInterceptor : Interceptor
|
||||
{
|
||||
public override AsyncUnaryCall<TResponse> AsyncUnaryCall<TRequest, TResponse>(
|
||||
TRequest request,
|
||||
ClientInterceptorContext<TRequest, TResponse> context,
|
||||
AsyncUnaryCallContinuation<TRequest, TResponse> continuation)
|
||||
TRequest request,
|
||||
ClientInterceptorContext<TRequest, TResponse> context,
|
||||
AsyncUnaryCallContinuation<TRequest, TResponse> continuation)
|
||||
{
|
||||
var call = continuation(request, context);
|
||||
|
||||
@@ -28,8 +29,9 @@ public class ErrorHandlerInterceptor : Interceptor
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
GlobalConstants.ConstSnackbar.Add(ex.Message, severity: MudBlazor.Severity.Error);
|
||||
var message = ex.Message.ExtractUserFriendlyMessage();
|
||||
GlobalConstants.ConstSnackbar?.Add(message, Severity.Error);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,5 @@ public static class GlobalConstants
|
||||
public const string DateTimeFormat = "MMM dd, yyyy - HH:mm";
|
||||
public static string JwtTokenKey = "AuthToken";
|
||||
public const string SuccessMsg = "با موفقیت انجام شد";
|
||||
public static ISnackbar ConstSnackbar;
|
||||
|
||||
}
|
||||
public static ISnackbar? ConstSnackbar { get; set; }
|
||||
}
|
||||
|
||||
@@ -11,4 +11,6 @@ public static class RouteConstance
|
||||
public const string UserOrder = "/UserOrderPage/";
|
||||
public const string UserRole = "/UserRolePage/";
|
||||
public const string UserAddress = "/UserAddressPage/";
|
||||
public const string Products = "/ProductsPage/";
|
||||
public const string Category = "/CategoryPage/";
|
||||
}
|
||||
|
||||
15
src/BackOffice/Pages/AutoComplete/ProductsAutoComplete.razor
Normal file
15
src/BackOffice/Pages/AutoComplete/ProductsAutoComplete.razor
Normal file
@@ -0,0 +1,15 @@
|
||||
@using BackOffice.BFF.Products.Protobuf.Protos.Products
|
||||
|
||||
<MudAutocomplete T="GetAllProductsByFilterResponseModel"
|
||||
Label="@Label"
|
||||
Value="@_item"
|
||||
DebounceInterval="700"
|
||||
ValueChanged="@((e) => OnSelected(e))"
|
||||
ToStringFunc="@(e => e == null ? null : e.Title)"
|
||||
SearchFunc="@Search"
|
||||
Variant="Variant.Outlined"
|
||||
Clearable="true"
|
||||
ShowProgressIndicator="true"
|
||||
CoerceText="false"
|
||||
OnClearButtonClick="()=> OnSelected(null)" />
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
using BackOffice.BFF.Products.Protobuf.Protos.Products;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
|
||||
namespace BackOffice.Pages.AutoComplete;
|
||||
|
||||
public partial class ProductsAutoComplete
|
||||
{
|
||||
[Inject] public ProductsContract.ProductsContractClient ProductsService { get; set; } = default!;
|
||||
|
||||
[Parameter] public long? Value { get; set; }
|
||||
[Parameter] public string? Label { get; set; } = "محصول";
|
||||
[Parameter] public EventCallback<long?> ValueChanged { get; set; }
|
||||
|
||||
private List<GetAllProductsByFilterResponseModel> _items = new();
|
||||
private GetAllProductsByFilterResponseModel? _item;
|
||||
|
||||
protected override async void OnParametersSet()
|
||||
{
|
||||
await base.OnParametersSetAsync();
|
||||
|
||||
if (Value.HasValue && Value.Value > 0)
|
||||
{
|
||||
var getAll = await ProductsService.GetAllProductsByFilterAsync(new GetAllProductsByFilterRequest
|
||||
{
|
||||
Filter = new GetAllProductsByFilterFilter
|
||||
{
|
||||
Id = Value.Value
|
||||
},
|
||||
PaginationState = new PaginationState
|
||||
{
|
||||
PageNumber = 1,
|
||||
PageSize = 1
|
||||
}
|
||||
});
|
||||
|
||||
if (getAll?.Models != null && getAll.Models.Any())
|
||||
{
|
||||
_item = getAll.Models.First();
|
||||
StateHasChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async Task OnSelected(GetAllProductsByFilterResponseModel? model)
|
||||
{
|
||||
if (model == null)
|
||||
{
|
||||
_item = null;
|
||||
await ValueChanged.InvokeAsync(null);
|
||||
}
|
||||
else
|
||||
{
|
||||
_item = model;
|
||||
await ValueChanged.InvokeAsync(model.Id);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<IEnumerable<GetAllProductsByFilterResponseModel>> Search(string value, CancellationToken token)
|
||||
{
|
||||
var request = new GetAllProductsByFilterRequest
|
||||
{
|
||||
Filter = new GetAllProductsByFilterFilter
|
||||
{
|
||||
Title = string.IsNullOrWhiteSpace(value) ? null : value
|
||||
},
|
||||
PaginationState = new PaginationState
|
||||
{
|
||||
PageNumber = 1,
|
||||
PageSize = 9
|
||||
}
|
||||
};
|
||||
|
||||
var getAll = await ProductsService.GetAllProductsByFilterAsync(request);
|
||||
_items = getAll?.Models?.ToList() ?? new List<GetAllProductsByFilterResponseModel>();
|
||||
|
||||
return _items;
|
||||
}
|
||||
}
|
||||
|
||||
83
src/BackOffice/Pages/Category/CategoryMainPage.razor
Normal file
83
src/BackOffice/Pages/Category/CategoryMainPage.razor
Normal file
@@ -0,0 +1,83 @@
|
||||
@attribute [Route(RouteConstance.Category)]
|
||||
|
||||
@using BackOffice.BFF.Category.Protobuf.Protos.Category
|
||||
@using BackOffice.Common.BaseComponents
|
||||
@using DataModel = BackOffice.BFF.Category.Protobuf.Protos.Category.GetAllCategoryByFilterResponseModel
|
||||
|
||||
<BasePageComponent @ref="_basePage" OnClearFilterClick="OnFilterCleared" OnSubmitClick="OnFilterSubmit">
|
||||
<Filters>
|
||||
<MudTextField T="string" Clearable="true" Label="عنوان" @bind-Value="@_request.Filter.Title" Variant="Variant.Outlined" Margin="Margin.Dense" />
|
||||
</Filters>
|
||||
<Content>
|
||||
<MudDataGrid T="DataModel"
|
||||
ServerData="@(new Func<GridState<DataModel>, Task<GridData<DataModel>>>(ServerReload))"
|
||||
Hover="true"
|
||||
@ref="_gridData"
|
||||
Height="72vh">
|
||||
<ColGroup>
|
||||
<col />
|
||||
<col />
|
||||
<col />
|
||||
<col />
|
||||
<col />
|
||||
<col style="width: 80px;" />
|
||||
</ColGroup>
|
||||
<ToolBarContent>
|
||||
<MudText>مدیریت دستهبندیها</MudText>
|
||||
<MudSpacer />
|
||||
<MudStack Spacing="2" Row="true" Justify="Justify.Center" AlignItems="AlignItems.Center">
|
||||
<MudButton Variant="Variant.Filled"
|
||||
Color="Color.Primary"
|
||||
Size="Size.Large"
|
||||
ButtonType="ButtonType.Button"
|
||||
OnClick="CreateNew"
|
||||
Style="cursor:pointer;">
|
||||
افزودن
|
||||
</MudButton>
|
||||
</MudStack>
|
||||
</ToolBarContent>
|
||||
<Columns>
|
||||
<PropertyColumn Property="x => x.Id" Title="شناسه" />
|
||||
<PropertyColumn Property="x => x.Name" Title="نام لاتین" />
|
||||
<PropertyColumn Property="x => x.Title" Title="عنوان" />
|
||||
<PropertyColumn Property="x => x.ParentId" Title="شناسه والد" />
|
||||
<TemplateColumn Title="فعال؟">
|
||||
<CellTemplate>
|
||||
<MudChip Color="@(context.Item.IsActive ? Color.Success : Color.Error)"
|
||||
Variant="Variant.Filled"
|
||||
Size="Size.Small">
|
||||
@(context.Item.IsActive ? "فعال" : "غیرفعال")
|
||||
</MudChip>
|
||||
</CellTemplate>
|
||||
</TemplateColumn>
|
||||
<TemplateColumn StickyLeft="true" Title="عملیات" CellStyle="text-wrap: nowrap;" HeaderStyle="text-wrap: nowrap;">
|
||||
<CellTemplate>
|
||||
<MudStack Row="true" AlignItems="AlignItems.Center">
|
||||
<MudTooltip Text="ویرایش">
|
||||
<MudIconButton Icon="@Icons.Material.Filled.EditNote"
|
||||
Size="Size.Small"
|
||||
ButtonType="ButtonType.Button"
|
||||
OnClick="@(() => Update(context.Item))"
|
||||
Style="cursor:pointer;" />
|
||||
</MudTooltip>
|
||||
|
||||
<MudTooltip Text="حذف">
|
||||
<MudIconButton Icon="@Icons.Material.Filled.DeleteOutline"
|
||||
Size="Size.Small"
|
||||
ButtonType="ButtonType.Button"
|
||||
OnClick="@(() => OnDelete(context.Item))"
|
||||
Style="cursor:pointer;" />
|
||||
</MudTooltip>
|
||||
</MudStack>
|
||||
</CellTemplate>
|
||||
</TemplateColumn>
|
||||
</Columns>
|
||||
<PagerContent>
|
||||
<MudDataGridPager T="DataModel"
|
||||
PageSizeOptions="@(new int[] { 30, 60, 90 })"
|
||||
InfoFormat="سطر {first_item} تا {last_item} از {all_items}"
|
||||
RowsPerPageString="تعداد سطرهای صفحه" />
|
||||
</PagerContent>
|
||||
</MudDataGrid>
|
||||
</Content>
|
||||
</BasePageComponent>
|
||||
120
src/BackOffice/Pages/Category/CategoryMainPage.razor.cs
Normal file
120
src/BackOffice/Pages/Category/CategoryMainPage.razor.cs
Normal file
@@ -0,0 +1,120 @@
|
||||
using BackOffice.BFF.Category.Protobuf.Protos.Category;
|
||||
using BackOffice.Common.BaseComponents;
|
||||
using Mapster;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using MudBlazor;
|
||||
using DataModel = BackOffice.BFF.Category.Protobuf.Protos.Category.GetAllCategoryByFilterResponseModel;
|
||||
|
||||
namespace BackOffice.Pages.Category;
|
||||
|
||||
public partial class CategoryMainPage
|
||||
{
|
||||
[Inject] public CategoryContract.CategoryContractClient CategoryContract { get; set; } = default!;
|
||||
|
||||
private BasePageComponent _basePage = default!;
|
||||
private MudDataGrid<DataModel> _gridData = default!;
|
||||
private GetAllCategoryByFilterRequest _request = new() { Filter = new() };
|
||||
|
||||
private async Task<GridData<DataModel>> ServerReload(GridState<DataModel> state)
|
||||
{
|
||||
_request.Filter ??= new();
|
||||
_request.PaginationState ??= new();
|
||||
_request.PaginationState.PageNumber = state.Page + 1;
|
||||
_request.PaginationState.PageSize = state.PageSize;
|
||||
|
||||
var result = await CategoryContract.GetAllCategoryByFilterAsync(_request);
|
||||
if (result != null && result.Models != null && result.Models.Any())
|
||||
{
|
||||
return new GridData<DataModel>
|
||||
{
|
||||
Items = result.Models.ToList(),
|
||||
TotalItems = (int)result.MetaData.TotalCount
|
||||
};
|
||||
}
|
||||
|
||||
return new GridData<DataModel>();
|
||||
}
|
||||
|
||||
public async Task CreateNew()
|
||||
{
|
||||
var dialog = await DialogService.ShowAsync<CreateOrUpdateCategoryDialog>(
|
||||
"افزودن دستهبندی",
|
||||
new DialogParameters<CreateOrUpdateCategoryDialog>
|
||||
{
|
||||
{ x => x.Model, new CreateNewCategoryRequest { IsActive = true } }
|
||||
},
|
||||
new DialogOptions { CloseButton = true, FullWidth = true, MaxWidth = MaxWidth.Small });
|
||||
|
||||
var result = await dialog.Result;
|
||||
if (!result.Canceled)
|
||||
{
|
||||
await ReloadData();
|
||||
Snackbar.Add("دستهبندی با موفقیت ایجاد شد.", Severity.Success);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task Update(DataModel model)
|
||||
{
|
||||
var getResponse = await CategoryContract.GetCategoryAsync(new GetCategoryRequest { Id = model.Id });
|
||||
|
||||
var editModel = getResponse.Adapt<UpdateCategoryRequest>();
|
||||
|
||||
var dialog = await DialogService.ShowAsync<CreateOrUpdateCategoryDialog>(
|
||||
"ویرایش دستهبندی",
|
||||
new DialogParameters<CreateOrUpdateCategoryDialog>
|
||||
{
|
||||
{ x => x.EditModel, editModel }
|
||||
},
|
||||
new DialogOptions { CloseButton = true, FullWidth = true, MaxWidth = MaxWidth.Small });
|
||||
|
||||
var result = await dialog.Result;
|
||||
if (!result.Canceled)
|
||||
{
|
||||
await ReloadData();
|
||||
Snackbar.Add("دستهبندی با موفقیت ویرایش شد.", Severity.Success);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task OnDelete(DataModel model)
|
||||
{
|
||||
var options = new DialogOptions { CloseOnEscapeKey = true, MaxWidth = MaxWidth.Small };
|
||||
bool? result = await DialogService.ShowMessageBox(
|
||||
"اخطار",
|
||||
"آیا از حذف این دستهبندی مطمئن هستید؟",
|
||||
yesText: "حذف",
|
||||
cancelText: "لغو",
|
||||
options: options);
|
||||
|
||||
if (result == true)
|
||||
{
|
||||
await CategoryContract.DeleteCategoryAsync(new DeleteCategoryRequest { Id = model.Id });
|
||||
await ReloadData();
|
||||
Snackbar.Add("دستهبندی با موفقیت حذف شد.", Severity.Success);
|
||||
}
|
||||
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
private async Task ReloadData()
|
||||
{
|
||||
if (_gridData != null)
|
||||
{
|
||||
await _gridData.ReloadServerData();
|
||||
}
|
||||
}
|
||||
|
||||
public async Task OnFilterSubmit()
|
||||
{
|
||||
_basePage.IsFiltered = true;
|
||||
StateHasChanged();
|
||||
await ReloadData();
|
||||
}
|
||||
|
||||
public async Task OnFilterCleared()
|
||||
{
|
||||
_basePage.IsFiltered = false;
|
||||
StateHasChanged();
|
||||
_request = new GetAllCategoryByFilterRequest { Filter = new GetAllCategoryByFilterFilter() };
|
||||
await ReloadData();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
@using BackOffice.BFF.Category.Protobuf.Protos.Category
|
||||
@using Microsoft.AspNetCore.Components.Forms
|
||||
|
||||
<MudDialog>
|
||||
<DialogContent>
|
||||
<MudStack Spacing="2">
|
||||
<MudTextField T="string"
|
||||
@bind-Value="Name"
|
||||
Label="نام لاتین"
|
||||
Variant="Variant.Outlined"
|
||||
Margin="Margin.Dense" />
|
||||
|
||||
<MudTextField T="string"
|
||||
@bind-Value="Title"
|
||||
Label="عنوان"
|
||||
Variant="Variant.Outlined"
|
||||
Margin="Margin.Dense" />
|
||||
|
||||
<MudTextField T="string"
|
||||
@bind-Value="Description"
|
||||
Label="توضیحات"
|
||||
Variant="Variant.Outlined"
|
||||
Margin="Margin.Dense"
|
||||
Lines="3"
|
||||
TextArea="true" />
|
||||
|
||||
<MudNumericField T="long?"
|
||||
@bind-Value="ParentId"
|
||||
HideSpinButtons="true"
|
||||
Label="شناسه والد (اختیاری)"
|
||||
Variant="Variant.Outlined"
|
||||
Margin="Margin.Dense" />
|
||||
|
||||
<MudNumericField T="int"
|
||||
@bind-Value="SortOrder"
|
||||
HideSpinButtons="true"
|
||||
Label="ترتیب نمایش"
|
||||
Variant="Variant.Outlined"
|
||||
Margin="Margin.Dense" />
|
||||
|
||||
<MudCheckBox T="bool" @bind-Checked="IsActive" Label="فعال" />
|
||||
</MudStack>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<MudButton OnClick="Cancel">لغو</MudButton>
|
||||
<MudButton Color="Color.Primary" OnClick="Save">ثبت</MudButton>
|
||||
</DialogActions>
|
||||
</MudDialog>
|
||||
@@ -0,0 +1,86 @@
|
||||
using BackOffice.BFF.Category.Protobuf.Protos.Category;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using MudBlazor;
|
||||
|
||||
namespace BackOffice.Pages.Category;
|
||||
|
||||
public partial class CreateOrUpdateCategoryDialog
|
||||
{
|
||||
[CascadingParameter] private IMudDialogInstance MudDialog { get; set; } = default!;
|
||||
[Inject] public CategoryContract.CategoryContractClient CategoryContract { get; set; } = default!;
|
||||
|
||||
[Parameter] public CreateNewCategoryRequest? Model { get; set; }
|
||||
[Parameter] public UpdateCategoryRequest? EditModel { get; set; }
|
||||
|
||||
private bool IsEdit => EditModel != null;
|
||||
|
||||
private string Name { get; set; } = string.Empty;
|
||||
private string Title { get; set; } = string.Empty;
|
||||
private string? Description { get; set; }
|
||||
private long? ParentId { get; set; }
|
||||
private bool IsActive { get; set; } = true;
|
||||
private int SortOrder { get; set; }
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
if (IsEdit && EditModel != null)
|
||||
{
|
||||
Name = EditModel.Name;
|
||||
Title = EditModel.Title;
|
||||
Description = EditModel.Description;
|
||||
ParentId = EditModel.ParentId;
|
||||
IsActive = EditModel.IsActive;
|
||||
SortOrder = EditModel.SortOrder;
|
||||
}
|
||||
else if (Model != null)
|
||||
{
|
||||
Name = Model.Name;
|
||||
Title = Model.Title;
|
||||
Description = Model.Description;
|
||||
ParentId = Model.ParentId;
|
||||
IsActive = Model.IsActive;
|
||||
SortOrder = Model.SortOrder;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task Save()
|
||||
{
|
||||
if (IsEdit && EditModel != null)
|
||||
{
|
||||
var request = new UpdateCategoryRequest
|
||||
{
|
||||
Id = EditModel.Id,
|
||||
Name = Name,
|
||||
Title = Title,
|
||||
Description = Description,
|
||||
ParentId = ParentId,
|
||||
IsActive = IsActive,
|
||||
SortOrder = SortOrder
|
||||
};
|
||||
|
||||
await CategoryContract.UpdateCategoryAsync(request);
|
||||
}
|
||||
else
|
||||
{
|
||||
var request = new CreateNewCategoryRequest
|
||||
{
|
||||
Name = Name,
|
||||
Title = Title,
|
||||
Description = Description,
|
||||
ParentId = ParentId,
|
||||
IsActive = IsActive,
|
||||
SortOrder = SortOrder
|
||||
};
|
||||
|
||||
await CategoryContract.CreateNewCategoryAsync(request);
|
||||
}
|
||||
|
||||
MudDialog.Close(DialogResult.Ok(true));
|
||||
}
|
||||
|
||||
private void Cancel()
|
||||
{
|
||||
MudDialog.Cancel();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,6 @@ public partial class LoginPage
|
||||
[Inject] public OtpContract.OtpContractClient OtpContract { get; set; }
|
||||
private async Task OnSubmitClick()
|
||||
{
|
||||
Console.WriteLine(OtpContract == null);
|
||||
await _form.Validate();
|
||||
if (!_form.IsValid)
|
||||
return;
|
||||
@@ -31,11 +30,12 @@ public partial class LoginPage
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Snackbar.Add(message: ex.Message, severity: Severity.Error, null);
|
||||
var message = ex.Message.ExtractUserFriendlyMessage();
|
||||
Snackbar.Add(message: message, severity: Severity.Error);
|
||||
}
|
||||
|
||||
_isLoading = false;
|
||||
StateHasChanged();
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,7 +45,8 @@ public partial class VerifyCodePage
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Snackbar.Add(message: ex.Message, severity: Severity.Error, null);
|
||||
var message = ex.Message.ExtractUserFriendlyMessage();
|
||||
Snackbar.Add(message: message, severity: Severity.Error);
|
||||
}
|
||||
|
||||
_isLoading = false;
|
||||
@@ -68,7 +69,8 @@ public partial class VerifyCodePage
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Snackbar.Add(message: ex.Message, severity: Severity.Error, null);
|
||||
var message = ex.Message.ExtractUserFriendlyMessage();
|
||||
Snackbar.Add(message: message, severity: Severity.Error);
|
||||
}
|
||||
|
||||
_isLoading = false;
|
||||
@@ -94,4 +96,4 @@ public partial class VerifyCodePage
|
||||
}
|
||||
}), null, 1000, 1000);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -5,7 +5,7 @@
|
||||
@using BackOffice.Common.BaseComponents
|
||||
@using DataModel = BackOffice.BFF.Package.Protobuf.Protos.Package.GetAllPackageByFilterResponseModel
|
||||
|
||||
<BackOffice.Common.BaseComponents.BasePageComponent @ref="_basePage" OnClearFilterClick="OnFilterCleard" OnSubmitClick="OnFilterSubmit">
|
||||
<BackOffice.Common.BaseComponents.BasePageComponent @ref="_basePage" OnClearFilterClick="OnFilterCleared" OnSubmitClick="OnFilterSubmit">
|
||||
<Filters>
|
||||
<MudTextField T="string" Clearable="true" Label="عنوان" @bind-Value="@_request.Filter.Title" Variant="Variant.Outlined" Margin="Margin.Dense" />
|
||||
</Filters>
|
||||
@@ -93,4 +93,3 @@
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -82,16 +82,16 @@ public partial class PackageMainPage
|
||||
|
||||
public async Task OnFilterSubmit()
|
||||
{
|
||||
_basePage.IsFilterd = true;
|
||||
_basePage.IsFiltered = true;
|
||||
StateHasChanged();
|
||||
ReLoadData();
|
||||
}
|
||||
|
||||
public async Task OnFilterCleard()
|
||||
public async Task OnFilterCleared()
|
||||
{
|
||||
_basePage.IsFilterd = false;
|
||||
_basePage.IsFiltered = false;
|
||||
StateHasChanged();
|
||||
_request = new() { Filter = new() { } };
|
||||
ReLoadData();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
87
src/BackOffice/Pages/Products/Components/CreateDialog.razor
Normal file
87
src/BackOffice/Pages/Products/Components/CreateDialog.razor
Normal file
@@ -0,0 +1,87 @@
|
||||
@using BackOffice.BFF.Products.Protobuf.Protos.Products
|
||||
@using Microsoft.AspNetCore.Components.Forms
|
||||
@using Tizzani.MudBlazor.HtmlEditor
|
||||
@using BackOffice.Common.BaseComponents
|
||||
|
||||
<MudDialog>
|
||||
<DialogContent>
|
||||
<MudStack Spacing="3">
|
||||
<MudStack Justify="Justify.Center" AlignItems="AlignItems.Center">
|
||||
@if (!string.IsNullOrWhiteSpace(_mainImagePreview))
|
||||
{
|
||||
<Image Src="@(_mainImagePreview)" Width="220" Height="140" ObjectPosition="ObjectPosition.Center" ObjectFit="ObjectFit.Cover" />
|
||||
}
|
||||
else
|
||||
{
|
||||
<MudPaper Class="d-flex align-center justify-center" Style="width:220px;height:140px;">
|
||||
<MudText Typo="Typo.caption">تصویری انتخاب نشده است</MudText>
|
||||
</MudPaper>
|
||||
}
|
||||
|
||||
<MudFileUpload T="IBrowserFile" Accept="image/*" FilesChanged="OnMainImageSelected">
|
||||
<ActivatorContent>
|
||||
<MudButton HtmlTag="label"
|
||||
Variant="Variant.Filled"
|
||||
Color="Color.Primary"
|
||||
ButtonType="ButtonType.Button"
|
||||
StartIcon="@Icons.Material.Filled.Image"
|
||||
Style="cursor:pointer;">
|
||||
انتخاب تصویر اصلی
|
||||
</MudButton>
|
||||
</ActivatorContent>
|
||||
<SelectedTemplate>
|
||||
@if (context != null)
|
||||
{
|
||||
<MudText Class="mt-2" Typo="Typo.subtitle2">
|
||||
<MudTooltip Text="@context.Name" Inline="true">
|
||||
@context.Name
|
||||
</MudTooltip>
|
||||
</MudText>
|
||||
}
|
||||
else
|
||||
{
|
||||
<MudText Class="mt-2" Typo="Typo.subtitle2">فایلی انتخاب نشده</MudText>
|
||||
}
|
||||
</SelectedTemplate>
|
||||
</MudFileUpload>
|
||||
</MudStack>
|
||||
|
||||
<MudStack Row="true" AlignItems="AlignItems.Center">
|
||||
<MudItem xs="6">
|
||||
<MudTextField T="string" @bind-Value="Model.Title" Disabled="_isLoading" Label="عنوان" Variant="Variant.Outlined" Margin="Margin.Dense" />
|
||||
</MudItem>
|
||||
<MudItem xs="6">
|
||||
<MudNumericField T="long" HideSpinButtons="true" @bind-Value="Model.Price" Format="N0" Immediate="true" Disabled="_isLoading" Label="قیمت" Variant="Variant.Outlined" Margin="Margin.Dense" />
|
||||
</MudItem>
|
||||
</MudStack>
|
||||
|
||||
<MudNumericField T="int" HideSpinButtons="true" @bind-Value="Model.Discount" Disabled="_isLoading" Label="تخفیف (%)" Variant="Variant.Outlined" Margin="Margin.Dense" />
|
||||
|
||||
<MudTextField T="string" @bind-Value="Model.ShortInfomation" Disabled="_isLoading" Label="خلاصه" Variant="Variant.Outlined" Margin="Margin.Dense" />
|
||||
|
||||
<MudHtmlEditor @bind-Html="Model.FullInformation">
|
||||
<MudHtmlToolbarOptions InsertImage="false" />
|
||||
</MudHtmlEditor>
|
||||
|
||||
<MudStack Spacing="1">
|
||||
<MudText Typo="Typo.subtitle2">تصویر بندانگشتی</MudText>
|
||||
<MudFileUpload T="IBrowserFile" Accept="image/*" FilesChanged="OnThumbnailSelected">
|
||||
<ActivatorContent>
|
||||
<MudButton HtmlTag="label"
|
||||
Variant="Variant.Outlined"
|
||||
Color="Color.Secondary"
|
||||
ButtonType="ButtonType.Button"
|
||||
StartIcon="@Icons.Material.Filled.Image"
|
||||
Style="cursor:pointer;">
|
||||
انتخاب تصویر بندانگشتی (اختیاری)
|
||||
</MudButton>
|
||||
</ActivatorContent>
|
||||
</MudFileUpload>
|
||||
</MudStack>
|
||||
</MudStack>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<MudButton OnClick="Cancel" Disabled="_isLoading">لغو</MudButton>
|
||||
<MudButton Color="Color.Primary" OnClick="CallCreateMethod" Disabled="_isLoading">ثبت</MudButton>
|
||||
</DialogActions>
|
||||
</MudDialog>
|
||||
@@ -0,0 +1,91 @@
|
||||
using BackOffice.BFF.Products.Protobuf.Protos.Products;
|
||||
using Google.Protobuf;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Microsoft.AspNetCore.Components.Forms;
|
||||
using MudBlazor;
|
||||
|
||||
namespace BackOffice.Pages.Products.Components;
|
||||
|
||||
public partial class CreateDialog
|
||||
{
|
||||
[CascadingParameter] IMudDialogInstance MudDialog { get; set; } = default!;
|
||||
[Inject] public ProductsContract.ProductsContractClient ProductsContract { get; set; } = default!;
|
||||
[Parameter] public CreateNewProductsRequest Model { get; set; } = default!;
|
||||
|
||||
private IBrowserFile? _mainImageFile;
|
||||
private IBrowserFile? _thumbnailImageFile;
|
||||
private readonly long _maxAllowedSize = (1024 * 1024) * 5;
|
||||
private bool _isLoading;
|
||||
private string? _mainImagePreview;
|
||||
|
||||
private async Task OnMainImageSelected(IBrowserFile? file)
|
||||
{
|
||||
_mainImageFile = file;
|
||||
if (file != null)
|
||||
{
|
||||
var buffer = new byte[file.Size];
|
||||
await file.OpenReadStream(_maxAllowedSize).ReadAsync(buffer);
|
||||
_mainImagePreview = $"data:{file.ContentType};base64," + Convert.ToBase64String(buffer);
|
||||
StateHasChanged();
|
||||
}
|
||||
}
|
||||
|
||||
private async Task OnThumbnailSelected(IBrowserFile? file)
|
||||
{
|
||||
_thumbnailImageFile = file;
|
||||
}
|
||||
|
||||
public async void CallCreateMethod()
|
||||
{
|
||||
_isLoading = true;
|
||||
StateHasChanged();
|
||||
|
||||
if (string.IsNullOrWhiteSpace(Model.Title))
|
||||
{
|
||||
Snackbar.Add("لطفا عنوان را وارد کنید!", Severity.Warning);
|
||||
_isLoading = false;
|
||||
StateHasChanged();
|
||||
return;
|
||||
}
|
||||
|
||||
if (_mainImageFile != null)
|
||||
{
|
||||
var buffer = new byte[_mainImageFile.Size];
|
||||
await _mainImageFile.OpenReadStream(_maxAllowedSize).ReadAsync(buffer);
|
||||
Model.ImageFile = new ImageFileModel
|
||||
{
|
||||
File = ByteString.CopyFrom(buffer),
|
||||
Mime = _mainImageFile.ContentType,
|
||||
FileName = Path.GetFileNameWithoutExtension(_mainImageFile.Name)
|
||||
};
|
||||
}
|
||||
|
||||
if (_thumbnailImageFile != null)
|
||||
{
|
||||
var buffer = new byte[_thumbnailImageFile.Size];
|
||||
await _thumbnailImageFile.OpenReadStream(_maxAllowedSize).ReadAsync(buffer);
|
||||
Model.ThumbnailFile = new ImageFileModel
|
||||
{
|
||||
File = ByteString.CopyFrom(buffer),
|
||||
Mime = _thumbnailImageFile.ContentType,
|
||||
FileName = Path.GetFileNameWithoutExtension(_thumbnailImageFile.Name)
|
||||
};
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
await ProductsContract.CreateNewProductsAsync(Model);
|
||||
Submit();
|
||||
}
|
||||
catch
|
||||
{
|
||||
Snackbar.Add("خطای سرور", Severity.Error);
|
||||
}
|
||||
|
||||
_isLoading = false;
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
void Submit() => MudDialog.Close(DialogResult.Ok(true));
|
||||
void Cancel() => MudDialog.Cancel();
|
||||
}
|
||||
83
src/BackOffice/Pages/Products/Components/GalleryDialog.razor
Normal file
83
src/BackOffice/Pages/Products/Components/GalleryDialog.razor
Normal file
@@ -0,0 +1,83 @@
|
||||
@using BackOffice.BFF.Products.Protobuf.Protos.Products
|
||||
@using Microsoft.AspNetCore.Components.Forms
|
||||
|
||||
<MudDialog>
|
||||
<DialogContent>
|
||||
<MudStack Spacing="3">
|
||||
<MudText Typo="Typo.h6">گالری تصاویر - @ProductTitle</MudText>
|
||||
|
||||
<MudGrid>
|
||||
<MudItem xs="12" md="4">
|
||||
<MudStack Spacing="2">
|
||||
<MudTextField @bind-Value="_title"
|
||||
Label="عنوان تصویر"
|
||||
Variant="Variant.Outlined"
|
||||
Margin="Margin.Dense" />
|
||||
|
||||
<MudFileUpload T="IBrowserFile" Accept="image/*" FilesChanged="OnImageSelected">
|
||||
<ActivatorContent>
|
||||
<MudButton HtmlTag="label"
|
||||
Variant="Variant.Filled"
|
||||
Color="Color.Primary"
|
||||
ButtonType="ButtonType.Button"
|
||||
StartIcon="@Icons.Material.Filled.Image"
|
||||
Style="cursor:pointer;">
|
||||
انتخاب تصویر
|
||||
</MudButton>
|
||||
</ActivatorContent>
|
||||
<SelectedTemplate>
|
||||
@if (context != null)
|
||||
{
|
||||
<MudText Class="mt-1" Typo="Typo.caption">@context.Name</MudText>
|
||||
}
|
||||
else
|
||||
{
|
||||
<MudText Class="mt-1" Typo="Typo.caption">فایلی انتخاب نشده</MudText>
|
||||
}
|
||||
</SelectedTemplate>
|
||||
</MudFileUpload>
|
||||
|
||||
@if (!string.IsNullOrWhiteSpace(_previewImage))
|
||||
{
|
||||
<MudPaper Class="pa-1">
|
||||
<img src="@_previewImage" alt="پیشنمایش" style="width:100%; height:160px; object-fit:cover;" />
|
||||
</MudPaper>
|
||||
}
|
||||
|
||||
<MudButton Color="Color.Primary" OnClick="AddImage" Disabled="_isUploading">افزودن به گالری</MudButton>
|
||||
</MudStack>
|
||||
</MudItem>
|
||||
|
||||
<MudItem xs="12" md="8">
|
||||
@if (Items?.Count > 0)
|
||||
{
|
||||
<MudGrid>
|
||||
@foreach (var item in Items)
|
||||
{
|
||||
<MudItem xs="6" sm="4" md="3">
|
||||
<MudPaper Class="pa-2">
|
||||
<img src="@item.ImageThumbnailPath" alt="@item.Title" style="width:100%; height:120px; object-fit:cover;" />
|
||||
<MudText Typo="Typo.caption" Class="mt-1">@item.Title</MudText>
|
||||
<MudStack Row="true" Justify="Justify.FlexEnd">
|
||||
<MudIconButton Icon="@Icons.Material.Filled.DeleteOutline"
|
||||
Color="Color.Error"
|
||||
Size="Size.Small"
|
||||
OnClick="@(() => RemoveImage(item))" />
|
||||
</MudStack>
|
||||
</MudPaper>
|
||||
</MudItem>
|
||||
}
|
||||
</MudGrid>
|
||||
}
|
||||
else
|
||||
{
|
||||
<MudText Typo="Typo.caption">هنوز تصویری برای این محصول ثبت نشده است.</MudText>
|
||||
}
|
||||
</MudItem>
|
||||
</MudGrid>
|
||||
</MudStack>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<MudButton OnClick="Close">بستن</MudButton>
|
||||
</DialogActions>
|
||||
</MudDialog>
|
||||
129
src/BackOffice/Pages/Products/Components/GalleryDialog.razor.cs
Normal file
129
src/BackOffice/Pages/Products/Components/GalleryDialog.razor.cs
Normal file
@@ -0,0 +1,129 @@
|
||||
using BackOffice.BFF.Products.Protobuf.Protos.Products;
|
||||
using Google.Protobuf;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Microsoft.AspNetCore.Components.Forms;
|
||||
using MudBlazor;
|
||||
|
||||
namespace BackOffice.Pages.Products.Components;
|
||||
|
||||
public partial class GalleryDialog
|
||||
{
|
||||
[CascadingParameter] IMudDialogInstance MudDialog { get; set; } = default!;
|
||||
[Inject] public ProductsContract.ProductsContractClient ProductsContract { get; set; } = default!;
|
||||
|
||||
[Parameter] public long ProductId { get; set; }
|
||||
[Parameter] public string ProductTitle { get; set; } = string.Empty;
|
||||
|
||||
private List<GalleryItemViewModel> Items { get; set; } = new List<GalleryItemViewModel>();
|
||||
private IBrowserFile? _file;
|
||||
private string? _title;
|
||||
private readonly long _maxAllowedSize = (1024 * 1024) * 5;
|
||||
private bool _isUploading;
|
||||
private string? _previewImage;
|
||||
private byte[]? _imageBuffer;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(_title))
|
||||
_title = ProductTitle;
|
||||
|
||||
await LoadGallery();
|
||||
}
|
||||
|
||||
private async Task LoadGallery()
|
||||
{
|
||||
var response = await ProductsContract.GetProductGalleryAsync(new GetProductGalleryRequest
|
||||
{
|
||||
ProductId = ProductId
|
||||
});
|
||||
|
||||
Items = response?.Items?
|
||||
.Select(x => new GalleryItemViewModel
|
||||
{
|
||||
ProductGalleryId = x.ProductGalleryId,
|
||||
ProductImageId = x.ProductImageId,
|
||||
Title = x.Title,
|
||||
ImagePath = x.ImagePath,
|
||||
ImageThumbnailPath = x.ImageThumbnailPath
|
||||
})
|
||||
.ToList() ?? new List<GalleryItemViewModel>();
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
private async Task OnImageSelected(IBrowserFile? file)
|
||||
{
|
||||
_file = file;
|
||||
_previewImage = null;
|
||||
_imageBuffer = null;
|
||||
|
||||
if (file != null)
|
||||
{
|
||||
var buffer = new byte[file.Size];
|
||||
await file.OpenReadStream(_maxAllowedSize).ReadAsync(buffer);
|
||||
_imageBuffer = buffer;
|
||||
_previewImage = $"data:{file.ContentType};base64," + Convert.ToBase64String(buffer);
|
||||
StateHasChanged();
|
||||
}
|
||||
}
|
||||
|
||||
private async Task AddImage()
|
||||
{
|
||||
if (_file == null)
|
||||
return;
|
||||
|
||||
_isUploading = true;
|
||||
StateHasChanged();
|
||||
|
||||
if (_imageBuffer == null)
|
||||
{
|
||||
var buffer = new byte[_file.Size];
|
||||
await _file.OpenReadStream(_maxAllowedSize).ReadAsync(buffer);
|
||||
_imageBuffer = buffer;
|
||||
}
|
||||
|
||||
var request = new AddProductImageRequest
|
||||
{
|
||||
ProductId = ProductId,
|
||||
Title = _title ?? string.Empty,
|
||||
ImageFile = new ImageFileModel
|
||||
{
|
||||
File = ByteString.CopyFrom(_imageBuffer),
|
||||
Mime = _file.ContentType,
|
||||
FileName = Path.GetFileNameWithoutExtension(_file.Name)
|
||||
}
|
||||
};
|
||||
|
||||
await ProductsContract.AddProductImageAsync(request);
|
||||
|
||||
_file = null;
|
||||
_title = string.Empty;
|
||||
_previewImage = null;
|
||||
_imageBuffer = null;
|
||||
|
||||
await LoadGallery();
|
||||
|
||||
_isUploading = false;
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
private async Task RemoveImage(GalleryItemViewModel item)
|
||||
{
|
||||
await ProductsContract.RemoveProductImageAsync(new RemoveProductImageRequest
|
||||
{
|
||||
ProductGalleryId = item.ProductGalleryId
|
||||
});
|
||||
|
||||
await LoadGallery();
|
||||
}
|
||||
|
||||
private void Close() => MudDialog.Close();
|
||||
|
||||
private class GalleryItemViewModel
|
||||
{
|
||||
public long ProductGalleryId { get; set; }
|
||||
public long ProductImageId { get; set; }
|
||||
public string Title { get; set; }
|
||||
public string ImagePath { get; set; }
|
||||
public string ImageThumbnailPath { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
@using BackOffice.Common.BaseComponents
|
||||
|
||||
<MudDialog>
|
||||
<DialogContent>
|
||||
<MudStack Spacing="2" AlignItems="AlignItems.Center">
|
||||
<MudText Typo="Typo.h6">@Title</MudText>
|
||||
@if (!string.IsNullOrWhiteSpace(ImageUrl))
|
||||
{
|
||||
<Image Src="@ImageUrl"
|
||||
Width="400"
|
||||
Height="260"
|
||||
ObjectPosition="ObjectPosition.Center"
|
||||
ObjectFit="ObjectFit.Cover" />
|
||||
}
|
||||
else
|
||||
{
|
||||
<MudText Typo="Typo.caption">تصویری برای نمایش وجود ندارد.</MudText>
|
||||
}
|
||||
</MudStack>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<MudButton OnClick="Close">بستن</MudButton>
|
||||
</DialogActions>
|
||||
</MudDialog>
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using MudBlazor;
|
||||
|
||||
namespace BackOffice.Pages.Products.Components;
|
||||
|
||||
public partial class ImagePreviewDialog
|
||||
{
|
||||
[CascadingParameter] IMudDialogInstance MudDialog { get; set; } = default!;
|
||||
|
||||
[Parameter] public string ImageUrl { get; set; } = string.Empty;
|
||||
[Parameter] public string Title { get; set; } = string.Empty;
|
||||
|
||||
private void Close() => MudDialog.Close();
|
||||
}
|
||||
|
||||
73
src/BackOffice/Pages/Products/Components/UpdateDialog.razor
Normal file
73
src/BackOffice/Pages/Products/Components/UpdateDialog.razor
Normal file
@@ -0,0 +1,73 @@
|
||||
@using BackOffice.BFF.Products.Protobuf.Protos.Products
|
||||
@using Microsoft.AspNetCore.Components.Forms
|
||||
@using Tizzani.MudBlazor.HtmlEditor
|
||||
@using BackOffice.Common.BaseComponents
|
||||
|
||||
<MudDialog>
|
||||
<DialogContent>
|
||||
<MudStack Spacing="3">
|
||||
<MudStack Justify="Justify.Center" AlignItems="AlignItems.Center">
|
||||
@if (!string.IsNullOrWhiteSpace(_mainImagePreview))
|
||||
{
|
||||
<Image Src="@(_mainImagePreview)" Width="220" Height="140" ObjectPosition="ObjectPosition.Center" ObjectFit="ObjectFit.Cover" />
|
||||
}
|
||||
else
|
||||
{
|
||||
<MudPaper Class="d-flex align-center justify-center" Style="width:220px;height:140px;">
|
||||
<MudText Typo="Typo.caption">تصویری انتخاب نشده است</MudText>
|
||||
</MudPaper>
|
||||
}
|
||||
|
||||
<MudFileUpload T="IBrowserFile" Accept="image/*" FilesChanged="OnMainImageSelected">
|
||||
<ActivatorContent>
|
||||
<MudButton HtmlTag="label"
|
||||
Variant="Variant.Filled"
|
||||
Color="Color.Primary"
|
||||
ButtonType="ButtonType.Button"
|
||||
StartIcon="@Icons.Material.Filled.Image"
|
||||
Style="cursor:pointer;">
|
||||
تغییر تصویر اصلی
|
||||
</MudButton>
|
||||
</ActivatorContent>
|
||||
</MudFileUpload>
|
||||
</MudStack>
|
||||
|
||||
<MudStack Row="true" AlignItems="AlignItems.Center">
|
||||
<MudItem xs="6">
|
||||
<MudTextField T="string" @bind-Value="Model.Title" Disabled="_isLoading" Label="عنوان" Variant="Variant.Outlined" Margin="Margin.Dense" />
|
||||
</MudItem>
|
||||
<MudItem xs="6">
|
||||
<MudNumericField T="long" HideSpinButtons="true" @bind-Value="Model.Price" Format="N0" Immediate="true" Disabled="_isLoading" Label="قیمت" Variant="Variant.Outlined" Margin="Margin.Dense" />
|
||||
</MudItem>
|
||||
</MudStack>
|
||||
|
||||
<MudNumericField T="int" HideSpinButtons="true" @bind-Value="Model.Discount" Disabled="_isLoading" Label="تخفیف (%)" Variant="Variant.Outlined" Margin="Margin.Dense" />
|
||||
|
||||
<MudTextField T="string" @bind-Value="Model.ShortInfomation" Disabled="_isLoading" Label="خلاصه" Variant="Variant.Outlined" Margin="Margin.Dense" />
|
||||
|
||||
<MudHtmlEditor @bind-Html="Model.FullInformation">
|
||||
<MudHtmlToolbarOptions InsertImage="false" />
|
||||
</MudHtmlEditor>
|
||||
|
||||
<MudStack Spacing="1">
|
||||
<MudText Typo="Typo.subtitle2">تصویر بندانگشتی</MudText>
|
||||
<MudFileUpload T="IBrowserFile" Accept="image/*" FilesChanged="OnThumbnailSelected">
|
||||
<ActivatorContent>
|
||||
<MudButton HtmlTag="label"
|
||||
Variant="Variant.Outlined"
|
||||
Color="Color.Secondary"
|
||||
ButtonType="ButtonType.Button"
|
||||
StartIcon="@Icons.Material.Filled.Image"
|
||||
Style="cursor:pointer;">
|
||||
تغییر تصویر بندانگشتی (اختیاری)
|
||||
</MudButton>
|
||||
</ActivatorContent>
|
||||
</MudFileUpload>
|
||||
</MudStack>
|
||||
</MudStack>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<MudButton OnClick="Cancel" Disabled="_isLoading">لغو</MudButton>
|
||||
<MudButton Color="Color.Primary" OnClick="@CallUpdateMethod" Disabled="_isLoading">ویرایش</MudButton>
|
||||
</DialogActions>
|
||||
</MudDialog>
|
||||
@@ -0,0 +1,97 @@
|
||||
using BackOffice.BFF.Products.Protobuf.Protos.Products;
|
||||
using Google.Protobuf;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Microsoft.AspNetCore.Components.Forms;
|
||||
using MudBlazor;
|
||||
|
||||
namespace BackOffice.Pages.Products.Components;
|
||||
|
||||
public partial class UpdateDialog
|
||||
{
|
||||
[CascadingParameter] IMudDialogInstance MudDialog { get; set; } = default!;
|
||||
[Inject] public ProductsContract.ProductsContractClient ProductsContract { get; set; } = default!;
|
||||
[Parameter] public UpdateProductsRequest Model { get; set; } = default!;
|
||||
|
||||
private IBrowserFile? _mainImageFile;
|
||||
private IBrowserFile? _thumbnailImageFile;
|
||||
private readonly long _maxAllowedSize = (1024 * 1024) * 5;
|
||||
private bool _isLoading;
|
||||
private string? _mainImagePreview;
|
||||
|
||||
private async Task OnMainImageSelected(IBrowserFile? file)
|
||||
{
|
||||
_mainImageFile = file;
|
||||
if (file != null)
|
||||
{
|
||||
var buffer = new byte[file.Size];
|
||||
await file.OpenReadStream(_maxAllowedSize).ReadAsync(buffer);
|
||||
_mainImagePreview = $"data:{file.ContentType};base64," + Convert.ToBase64String(buffer);
|
||||
StateHasChanged();
|
||||
}
|
||||
}
|
||||
|
||||
private async Task OnThumbnailSelected(IBrowserFile? file)
|
||||
{
|
||||
_thumbnailImageFile = file;
|
||||
}
|
||||
|
||||
protected override Task OnInitializedAsync()
|
||||
{
|
||||
_mainImagePreview = Model.ImagePath;
|
||||
return base.OnInitializedAsync();
|
||||
}
|
||||
|
||||
public async void CallUpdateMethod()
|
||||
{
|
||||
_isLoading = true;
|
||||
StateHasChanged();
|
||||
|
||||
if (string.IsNullOrWhiteSpace(Model.Title))
|
||||
{
|
||||
Snackbar.Add("لطفا عنوان را وارد کنید!", Severity.Warning);
|
||||
_isLoading = false;
|
||||
StateHasChanged();
|
||||
return;
|
||||
}
|
||||
|
||||
if (_mainImageFile != null)
|
||||
{
|
||||
var buffer = new byte[_mainImageFile.Size];
|
||||
await _mainImageFile.OpenReadStream(_maxAllowedSize).ReadAsync(buffer);
|
||||
Model.ImageFile = new ImageFileModel
|
||||
{
|
||||
File = ByteString.CopyFrom(buffer),
|
||||
Mime = _mainImageFile.ContentType,
|
||||
FileName = Path.GetFileNameWithoutExtension(_mainImageFile.Name)
|
||||
};
|
||||
}
|
||||
|
||||
if (_thumbnailImageFile != null)
|
||||
{
|
||||
var buffer = new byte[_thumbnailImageFile.Size];
|
||||
await _thumbnailImageFile.OpenReadStream(_maxAllowedSize).ReadAsync(buffer);
|
||||
Model.ThumbnailFile = new ImageFileModel
|
||||
{
|
||||
File = ByteString.CopyFrom(buffer),
|
||||
Mime = _thumbnailImageFile.ContentType,
|
||||
FileName = Path.GetFileNameWithoutExtension(_thumbnailImageFile.Name)
|
||||
};
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
await ProductsContract.UpdateProductsAsync(Model);
|
||||
Submit();
|
||||
}
|
||||
catch
|
||||
{
|
||||
Snackbar.Add("خطای سرور", Severity.Error);
|
||||
}
|
||||
|
||||
_isLoading = false;
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
void Submit() => MudDialog.Close(DialogResult.Ok(true));
|
||||
void Cancel() => MudDialog.Cancel();
|
||||
}
|
||||
85
src/BackOffice/Pages/Products/ProductsMainPage.razor
Normal file
85
src/BackOffice/Pages/Products/ProductsMainPage.razor
Normal file
@@ -0,0 +1,85 @@
|
||||
@attribute [Route(RouteConstance.Products)]
|
||||
|
||||
@using BackOffice.BFF.Products.Protobuf.Protos.Products
|
||||
@using BackOffice.Common.BaseComponents
|
||||
@using BackOffice.Pages.Products.Components
|
||||
@using DataModel = BackOffice.BFF.Products.Protobuf.Protos.Products.GetAllProductsByFilterResponseModel
|
||||
|
||||
<BasePageComponent @ref="_basePage" OnClearFilterClick="OnFilterCleared" OnSubmitClick="OnFilterSubmit">
|
||||
<Filters>
|
||||
<MudTextField T="string" Clearable="true" Label="عنوان" @bind-Value="@_request.Filter.Title" Variant="Variant.Outlined" Margin="Margin.Dense" />
|
||||
</Filters>
|
||||
<Content>
|
||||
<MudDataGrid T="DataModel" ServerData="@(new Func<GridState<DataModel>, Task<GridData<DataModel>>>(ServerReload))"
|
||||
Hover="true" @ref="_gridData" Height="72vh">
|
||||
<ColGroup>
|
||||
<col />
|
||||
<col />
|
||||
<col />
|
||||
<col style="width: 58px;" />
|
||||
</ColGroup>
|
||||
<ToolBarContent>
|
||||
<MudText>مدیریت محصولات</MudText>
|
||||
<MudSpacer />
|
||||
<MudStack Spacing="2" Row="true" Justify="Justify.Center" AlignItems="AlignItems.Center">
|
||||
<MudButton Variant="Variant.Filled" Color="Color.Primary" Size="Size.Large" ButtonType="ButtonType.Button" OnClick="CreateNew" Style="cursor:pointer;">افزودن</MudButton>
|
||||
</MudStack>
|
||||
</ToolBarContent>
|
||||
<Columns>
|
||||
<PropertyColumn Property="x => x.Id" Title="شناسه" />
|
||||
|
||||
<PropertyColumn Property="x => x.Title" Title="عنوان" CellStyle="text-wrap: nowrap;" HeaderStyle="text-wrap: nowrap;">
|
||||
<CellTemplate>
|
||||
<MudStack Row="true" AlignItems="AlignItems.Center">
|
||||
<MudTooltip Text="پیشنمایش تصویر">
|
||||
<div style="cursor:pointer"
|
||||
@onclick="@(() => OpenImagePreview(context.Item.ImagePath, context.Item.Title))">
|
||||
<Image Src="@context.Item.ImagePath"
|
||||
Width="25"
|
||||
Height="25"
|
||||
ObjectPosition="ObjectPosition.Center"
|
||||
ObjectFit="ObjectFit.Fill" />
|
||||
</div>
|
||||
</MudTooltip>
|
||||
@if (string.IsNullOrWhiteSpace(context.Item.Title))
|
||||
{
|
||||
<MudText Typo="Typo.inherit">-</MudText>
|
||||
}
|
||||
else
|
||||
{
|
||||
<MudTooltip Text="@(context.Item.Title)" Arrow="true">
|
||||
<MudText Typo="Typo.inherit" Style="text-wrap: nowrap;">
|
||||
@(context.Item.Title.Truncate(20, true))
|
||||
</MudText>
|
||||
</MudTooltip>
|
||||
}
|
||||
</MudStack>
|
||||
</CellTemplate>
|
||||
</PropertyColumn>
|
||||
|
||||
<PropertyColumn Property="x => x.Price" Title="قیمت" />
|
||||
|
||||
<TemplateColumn StickyLeft="true" Title="عملیات" CellStyle="text-wrap: nowrap;" HeaderStyle="text-wrap: nowrap;">
|
||||
<CellTemplate>
|
||||
<MudStack Row="true" AlignItems="AlignItems.Center">
|
||||
<MudTooltip Text="ویرایش">
|
||||
<MudIconButton Icon="@Icons.Material.Filled.EditNote" Size="Size.Small" ButtonType="ButtonType.Button" OnClick="@(() => Update(context.Item))" Style="cursor:pointer;" />
|
||||
</MudTooltip>
|
||||
|
||||
<MudTooltip Text="حذف">
|
||||
<MudIconButton Icon="@Icons.Material.Filled.DeleteOutline" Size="Size.Small" ButtonType="ButtonType.Button" OnClick="@(() => OnDelete(context.Item))" Style="cursor:pointer;" />
|
||||
</MudTooltip>
|
||||
|
||||
<MudTooltip Text="گالری تصاویر">
|
||||
<MudIconButton Icon="@Icons.Material.Filled.Collections" Size="Size.Small" ButtonType="ButtonType.Button" OnClick="@(() => OpenGallery(context.Item))" Style="cursor:pointer;" />
|
||||
</MudTooltip>
|
||||
</MudStack>
|
||||
</CellTemplate>
|
||||
</TemplateColumn>
|
||||
</Columns>
|
||||
<PagerContent>
|
||||
<MudDataGridPager T="DataModel" PageSizeOptions=@(new int[] { 30, 60, 90 }) />
|
||||
</PagerContent>
|
||||
</MudDataGrid>
|
||||
</Content>
|
||||
</BasePageComponent>
|
||||
123
src/BackOffice/Pages/Products/ProductsMainPage.razor.cs
Normal file
123
src/BackOffice/Pages/Products/ProductsMainPage.razor.cs
Normal file
@@ -0,0 +1,123 @@
|
||||
using BackOffice.BFF.Products.Protobuf.Protos.Products;
|
||||
using BackOffice.Common.BaseComponents;
|
||||
using BackOffice.Pages.Products.Components;
|
||||
using Mapster;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using MudBlazor;
|
||||
using DataModel = BackOffice.BFF.Products.Protobuf.Protos.Products.GetAllProductsByFilterResponseModel;
|
||||
|
||||
namespace BackOffice.Pages.Products;
|
||||
|
||||
public partial class ProductsMainPage
|
||||
{
|
||||
[Inject] public ProductsContract.ProductsContractClient ProductsContract { get; set; } = default!;
|
||||
|
||||
private bool _isLoading = true;
|
||||
private MudDataGrid<DataModel> _gridData;
|
||||
private BasePageComponent _basePage;
|
||||
private GetAllProductsByFilterRequest _request = new() { Filter = new() };
|
||||
|
||||
private async Task<GridData<DataModel>> ServerReload(GridState<DataModel> state)
|
||||
{
|
||||
_request.Filter ??= new();
|
||||
_request.PaginationState ??= new();
|
||||
_request.PaginationState.PageNumber = state.Page + 1;
|
||||
_request.PaginationState.PageSize = state.PageSize;
|
||||
|
||||
var result = await ProductsContract.GetAllProductsByFilterAsync(_request);
|
||||
if (result != null && result.Models != null && result.Models.Any())
|
||||
{
|
||||
return new GridData<DataModel> { Items = result.Models.ToList(), TotalItems = (int)result.MetaData.TotalCount };
|
||||
}
|
||||
|
||||
return new GridData<DataModel>();
|
||||
}
|
||||
|
||||
public async Task Update(DataModel model)
|
||||
{
|
||||
var parameters = new DialogParameters<UpdateDialog> { { x => x.Model, model.Adapt<UpdateProductsRequest>() } };
|
||||
|
||||
var dialog = await DialogService.ShowAsync<UpdateDialog>("ویرایش محصول", parameters, new DialogOptions { CloseButton = true, FullWidth = true, MaxWidth = MaxWidth.Small });
|
||||
var result = await dialog.Result;
|
||||
|
||||
if (!result.Canceled)
|
||||
{
|
||||
ReLoadData();
|
||||
Snackbar.Add("عملیات با موفقیت انجام شد", Severity.Success);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task OnDelete(DataModel model)
|
||||
{
|
||||
var options = new DialogOptions { CloseOnEscapeKey = true, MaxWidth = MaxWidth.Small };
|
||||
bool? result = await DialogService.ShowMessageBox(
|
||||
"اخطار",
|
||||
"آیا از حذف این مورد مطمئن هستید؟",
|
||||
yesText: "حذف", cancelText: "لغو",
|
||||
options: options);
|
||||
if (result == true)
|
||||
{
|
||||
await ProductsContract.DeleteProductsAsync(new DeleteProductsRequest { Id = model.Id });
|
||||
ReLoadData();
|
||||
}
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
public async void ReLoadData()
|
||||
{
|
||||
if (_gridData != null)
|
||||
await _gridData.ReloadServerData();
|
||||
}
|
||||
|
||||
public async Task CreateNew()
|
||||
{
|
||||
var dialog = await DialogService.ShowAsync<CreateDialog>("افزودن محصول", new DialogParameters<CreateDialog> { { x => x.Model, new CreateNewProductsRequest() } }, new DialogOptions { CloseButton = true, FullWidth = true, MaxWidth = MaxWidth.Small });
|
||||
var result = await dialog.Result;
|
||||
if (!result.Canceled)
|
||||
{
|
||||
ReLoadData();
|
||||
Snackbar.Add("عملیات با موفقیت انجام شد", Severity.Success);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task OnFilterSubmit()
|
||||
{
|
||||
_basePage.IsFiltered = true;
|
||||
StateHasChanged();
|
||||
ReLoadData();
|
||||
}
|
||||
|
||||
public async Task OnFilterCleared()
|
||||
{
|
||||
_basePage.IsFiltered = false;
|
||||
StateHasChanged();
|
||||
_request = new GetAllProductsByFilterRequest { Filter = new() };
|
||||
ReLoadData();
|
||||
}
|
||||
|
||||
public async Task OpenGallery(DataModel model)
|
||||
{
|
||||
var parameters = new DialogParameters<GalleryDialog>
|
||||
{
|
||||
{ x => x.ProductId, model.Id },
|
||||
{ x => x.ProductTitle, model.Title }
|
||||
};
|
||||
await DialogService.ShowAsync<GalleryDialog>("گالری تصاویر", parameters,
|
||||
new DialogOptions { CloseButton = true, FullWidth = true, MaxWidth = MaxWidth.Medium });
|
||||
}
|
||||
|
||||
public async Task OpenImagePreview(string imagePath, string title)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(imagePath))
|
||||
return;
|
||||
|
||||
var parameters = new DialogParameters<ImagePreviewDialog>
|
||||
{
|
||||
{ x => x.ImageUrl, imagePath },
|
||||
{ x => x.Title, title }
|
||||
};
|
||||
|
||||
await DialogService.ShowAsync<ImagePreviewDialog>("پیشنمایش تصویر محصول", parameters,
|
||||
new DialogOptions { CloseButton = true, MaxWidth = MaxWidth.Medium, FullWidth = true });
|
||||
}
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
@@ -15,7 +15,7 @@ namespace BackOffice.Pages.Role.Components
|
||||
public UpdateRoleRequest Model { get; set; } = new();
|
||||
|
||||
[CascadingParameter]
|
||||
MudDialogInstance MudDialog { get; set; }
|
||||
IMudDialogInstance MudDialog { get; set; }
|
||||
|
||||
public async void CallUpdateMethod()
|
||||
{
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
@using BackOffice.Common.BaseComponents
|
||||
@using DataModel = BackOffice.BFF.Role.Protobuf.Protos.Role.GetAllRoleByFilterResponseModel
|
||||
|
||||
<BackOffice.Common.BaseComponents.BasePageComponent @ref="_basePage" OnClearFilterClick="OnFilterCleard" OnSubmitClick="OnFilterSubmit">
|
||||
<BackOffice.Common.BaseComponents.BasePageComponent @ref="_basePage" OnClearFilterClick="OnFilterCleared" OnSubmitClick="OnFilterSubmit">
|
||||
<Filters>
|
||||
<MudTextField T="string" Clearable="true" Label="عنوان" @bind-Value="@_request.Filter.Title" Variant="Variant.Outlined" Margin="Margin.Dense" />
|
||||
</Filters>
|
||||
@@ -57,4 +57,3 @@
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -81,16 +81,16 @@ public partial class RoleMainPage
|
||||
}
|
||||
public async Task OnFilterSubmit()
|
||||
{
|
||||
_basePage.IsFilterd = true;
|
||||
_basePage.IsFiltered = true;
|
||||
StateHasChanged();
|
||||
ReLoadData();
|
||||
}
|
||||
|
||||
public async Task OnFilterCleard()
|
||||
public async Task OnFilterCleared()
|
||||
{
|
||||
_basePage.IsFilterd = false;
|
||||
_basePage.IsFiltered = false;
|
||||
StateHasChanged();
|
||||
_request = new() { Filter = new() { } };
|
||||
ReLoadData();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ namespace BackOffice.Pages.User.Components;
|
||||
public partial class UserRoleDialog
|
||||
{
|
||||
[Parameter] public long UserId { get; set; }
|
||||
[CascadingParameter] MudDialogInstance MudDialog { get; set; }
|
||||
[CascadingParameter] IMudDialogInstance MudDialog { get; set; }
|
||||
MudForm _form;
|
||||
private bool _isLoading;
|
||||
private bool _isFirstLoad = true;
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
@using BackOffice.Common.BaseComponents
|
||||
@using DataModel = BackOffice.BFF.User.Protobuf.Protos.User.GetAllUserByFilterResponseModel
|
||||
|
||||
<BackOffice.Common.BaseComponents.BasePageComponent @ref="_basePage" OnClearFilterClick="OnFilterCleard" OnSubmitClick="OnFilterSubmit">
|
||||
<BackOffice.Common.BaseComponents.BasePageComponent @ref="_basePage" OnClearFilterClick="OnFilterCleared" OnSubmitClick="OnFilterSubmit">
|
||||
<Filters>
|
||||
<MudTextField T="string" Clearable="true" Label="نام" @bind-Value="@_request.Filter.FirstName" Variant="Variant.Outlined" Margin="Margin.Dense" />
|
||||
<MudTextField T="string" Clearable="true" Label="نام خانوادگی" @bind-Value="@_request.Filter.LastName" Variant="Variant.Outlined" Margin="Margin.Dense" />
|
||||
@@ -64,4 +64,3 @@
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -51,30 +51,6 @@ public partial class UserMainPage
|
||||
if (_gridData != null)
|
||||
await _gridData.ReloadServerData();
|
||||
}
|
||||
private async Task Searchfirstname(string? firstname)
|
||||
{
|
||||
_request.Filter ??= new();
|
||||
_request.Filter.FirstName = string.IsNullOrWhiteSpace(firstname) ? default : firstname;
|
||||
ReLoadData();
|
||||
}
|
||||
private async Task Searchlastname(string? lastname)
|
||||
{
|
||||
_request.Filter ??= new();
|
||||
_request.Filter.LastName = string.IsNullOrWhiteSpace(lastname) ? default : lastname;
|
||||
ReLoadData();
|
||||
}
|
||||
private async Task SearchNationalCode(string? nationalcode)
|
||||
{
|
||||
_request.Filter ??= new();
|
||||
_request.Filter.NationalCode = string.IsNullOrWhiteSpace(nationalcode) ? default : nationalcode;
|
||||
ReLoadData();
|
||||
}
|
||||
private async Task SearchMobile(string? mobile)
|
||||
{
|
||||
_request.Filter ??= new();
|
||||
_request.Filter.Mobile = string.IsNullOrWhiteSpace(mobile) ? default : mobile;
|
||||
ReLoadData();
|
||||
}
|
||||
public async Task OnclickUserRoleDialog(long userid)
|
||||
{
|
||||
var dialog = await DialogService.ShowAsync<UserRoleDialog>($"نقش های کاربر", new DialogParameters<UserRoleDialog>() { { x => x.UserId, userid } }, new DialogOptions() { CloseButton = true, FullWidth = true, MaxWidth = MaxWidth.Small });
|
||||
@@ -87,16 +63,16 @@ public partial class UserMainPage
|
||||
}
|
||||
public async Task OnFilterSubmit()
|
||||
{
|
||||
_basePage.IsFilterd = true;
|
||||
_basePage.IsFiltered = true;
|
||||
StateHasChanged();
|
||||
ReLoadData();
|
||||
}
|
||||
|
||||
public async Task OnFilterCleard()
|
||||
public async Task OnFilterCleared()
|
||||
{
|
||||
_basePage.IsFilterd = false;
|
||||
_basePage.IsFiltered = false;
|
||||
StateHasChanged();
|
||||
_request = new() { Filter = new() { } };
|
||||
ReLoadData();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ public partial class CreateDialog
|
||||
{
|
||||
[Inject] public UserAddressContract.UserAddressContractClient UserAddressContract { get; set; }
|
||||
[Parameter] public CreateNewUserAddressRequest Model { get; set; } = new();
|
||||
[CascadingParameter] MudDialogInstance MudDialog { get; set; }
|
||||
[CascadingParameter] IMudDialogInstance MudDialog { get; set; }
|
||||
|
||||
private bool _isLoading = false;
|
||||
|
||||
@@ -49,9 +49,8 @@ public partial class CreateDialog
|
||||
Submit();
|
||||
|
||||
}
|
||||
catch (RpcException ex)
|
||||
catch (RpcException)
|
||||
{
|
||||
Console.WriteLine(ex);
|
||||
Snackbar.Add("خطای سرور", Severity.Error);
|
||||
}
|
||||
|
||||
@@ -60,4 +59,4 @@ public partial class CreateDialog
|
||||
}
|
||||
void Submit() => MudDialog.Close(DialogResult.Ok(true));
|
||||
void Cancel() => MudDialog.Cancel();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ namespace BackOffice.Pages.UserAddress.Components
|
||||
public UpdateUserAddressRequest Model { get; set; } = new();
|
||||
|
||||
[CascadingParameter]
|
||||
MudDialogInstance MudDialog { get; set; }
|
||||
IMudDialogInstance MudDialog { get; set; }
|
||||
public async void CallUpdateMethod()
|
||||
{
|
||||
_isLoading = true;
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
@using BackOffice.Common.BaseComponents
|
||||
@using DataModel = BackOffice.BFF.UserAddress.Protobuf.Protos.UserAddress.GetAllUserAddressByFilterResponseModel
|
||||
|
||||
<BackOffice.Common.BaseComponents.BasePageComponent @ref="_basePage" OnClearFilterClick="OnFilterCleard" OnSubmitClick="OnFilterSubmit">
|
||||
<BackOffice.Common.BaseComponents.BasePageComponent @ref="_basePage" OnClearFilterClick="OnFilterCleared" OnSubmitClick="OnFilterSubmit">
|
||||
<Filters>
|
||||
<MudTextField T="string" Clearable="true" Label="عنوان" @bind-Value="@_request.Filter.Title" Variant="Variant.Outlined" Margin="Margin.Dense" />
|
||||
</Filters>
|
||||
@@ -54,4 +54,3 @@
|
||||
</BackOffice.Common.BaseComponents.BasePageComponent>
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -83,16 +83,16 @@ public partial class UserAddressMainPage
|
||||
}
|
||||
public async Task OnFilterSubmit()
|
||||
{
|
||||
_basePage.IsFilterd = true;
|
||||
_basePage.IsFiltered = true;
|
||||
StateHasChanged();
|
||||
ReLoadData();
|
||||
}
|
||||
|
||||
public async Task OnFilterCleard()
|
||||
public async Task OnFilterCleared()
|
||||
{
|
||||
_basePage.IsFilterd = false;
|
||||
_basePage.IsFiltered = false;
|
||||
StateHasChanged();
|
||||
_request = new() { Filter = new() { } };
|
||||
ReLoadData();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
@using BackOffice.Common.BaseComponents
|
||||
@using DataModel = BackOffice.BFF.UserOrder.Protobuf.Protos.UserOrder.GetAllUserOrderByFilterResponseModel
|
||||
|
||||
<BackOffice.Common.BaseComponents.BasePageComponent @ref="_basePage" OnClearFilterClick="OnFilterCleard" OnSubmitClick="OnFilterSubmit">
|
||||
<BackOffice.Common.BaseComponents.BasePageComponent @ref="_basePage" OnClearFilterClick="OnFilterCleared" OnSubmitClick="OnFilterSubmit">
|
||||
<Filters>
|
||||
<MudNumericField HideSpinButtons="true" T="long?" Clearable="true" Label="قیمت" @bind-Value="@_request.Filter.Price" Variant="Variant.Outlined" Margin="Margin.Dense" />
|
||||
</Filters>
|
||||
@@ -65,4 +65,3 @@
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -56,16 +56,16 @@ public partial class UserOrderMainPage
|
||||
}
|
||||
public async Task OnFilterSubmit()
|
||||
{
|
||||
_basePage.IsFilterd = true;
|
||||
_basePage.IsFiltered = true;
|
||||
StateHasChanged();
|
||||
ReLoadData();
|
||||
}
|
||||
|
||||
public async Task OnFilterCleard()
|
||||
public async Task OnFilterCleared()
|
||||
{
|
||||
_basePage.IsFilterd = false;
|
||||
_basePage.IsFiltered = false;
|
||||
StateHasChanged();
|
||||
_request = new() { Filter = new() { } };
|
||||
ReLoadData();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ public partial class CreateDialog
|
||||
{
|
||||
[Inject] public UserRoleContract.UserRoleContractClient UserRoleContract { get; set; }
|
||||
[Parameter] public CreateNewUserRoleRequest Model { get; set; } = new();
|
||||
[CascadingParameter] MudDialogInstance MudDialog { get; set; }
|
||||
[CascadingParameter] IMudDialogInstance MudDialog { get; set; }
|
||||
|
||||
private bool _isLoading = false;
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ namespace BackOffice.Pages.UserRole.Components
|
||||
public UpdateUserRoleRequest Model { get; set; } = new();
|
||||
|
||||
[CascadingParameter]
|
||||
MudDialogInstance MudDialog { get; set; }
|
||||
IMudDialogInstance MudDialog { get; set; }
|
||||
|
||||
public async void CallUpdateMethod()
|
||||
{
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
@using BackOffice.Common.BaseComponents
|
||||
@using DataModel = BackOffice.BFF.UserRole.Protobuf.Protos.UserRole.GetAllUserRoleByFilterResponseModel
|
||||
|
||||
<BackOffice.Common.BaseComponents.BasePageComponent @ref="_basePage" OnClearFilterClick="OnFilterCleard" OnSubmitClick="OnFilterSubmit">
|
||||
<BackOffice.Common.BaseComponents.BasePageComponent @ref="_basePage" OnClearFilterClick="OnFilterCleared" OnSubmitClick="OnFilterSubmit">
|
||||
<Filters>
|
||||
<MudNumericField T="long?" HideSpinButtons="true" Clearable="true" Label="شناسه" @bind-Value="@_request.Filter.Id" Variant="Variant.Outlined" Margin="Margin.Dense" />
|
||||
</Filters>
|
||||
@@ -53,4 +53,3 @@
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -83,16 +83,16 @@ public partial class UserRoleMainPage
|
||||
}
|
||||
public async Task OnFilterSubmit()
|
||||
{
|
||||
_basePage.IsFilterd = true;
|
||||
_basePage.IsFiltered = true;
|
||||
StateHasChanged();
|
||||
ReLoadData();
|
||||
}
|
||||
|
||||
public async Task OnFilterCleard()
|
||||
public async Task OnFilterCleared()
|
||||
{
|
||||
_basePage.IsFilterd = false;
|
||||
_basePage.IsFiltered = false;
|
||||
StateHasChanged();
|
||||
_request = new() { Filter = new() { } };
|
||||
ReLoadData();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
104
src/BackOffice/Shared/CustomMudTheme.cs
Normal file
104
src/BackOffice/Shared/CustomMudTheme.cs
Normal file
@@ -0,0 +1,104 @@
|
||||
using MudBlazor;
|
||||
|
||||
namespace BackOffice.Shared;
|
||||
|
||||
public static class CustomMudTheme
|
||||
{
|
||||
public static MudTheme CustomMudBlazorTheme { get; set; } = new()
|
||||
{
|
||||
PaletteLight = new PaletteLight()
|
||||
{
|
||||
Primary = "#0380C0",
|
||||
Secondary = "#5E4DF9",
|
||||
PrimaryContrastText = "#FFFFFF",
|
||||
AppbarText = Colors.Gray.Darken4,
|
||||
Background = "#F5F5F5",
|
||||
AppbarBackground = "#F5F5F5",
|
||||
TextPrimary = Colors.Gray.Darken3,
|
||||
Surface = "#FFFFFF",
|
||||
Divider = "#B2BFCB",
|
||||
DrawerBackground = "#FFFFFF",
|
||||
DrawerText = Colors.Gray.Darken3,
|
||||
DrawerIcon = Colors.Gray.Darken2,
|
||||
},
|
||||
LayoutProperties = new LayoutProperties
|
||||
{
|
||||
DefaultBorderRadius = "12px",
|
||||
AppbarHeight = "56px",
|
||||
DrawerWidthLeft = "260px",
|
||||
DrawerWidthRight = "260px"
|
||||
},
|
||||
Typography = new Typography
|
||||
{
|
||||
Default = new DefaultTypography()
|
||||
{
|
||||
FontFamily = new[] { "Vazir", "Tahoma", "Segoe UI", "Arial", "sans-serif" }
|
||||
},
|
||||
H1 = new H1Typography()
|
||||
{
|
||||
FontFamily = new[] { "Vazir" }, FontSize = "2rem", LineHeight = "1.70", FontWeight = "800",
|
||||
LetterSpacing = "normal"
|
||||
},
|
||||
H2 = new H2Typography()
|
||||
{
|
||||
FontFamily = new[] { "Vazir" }, FontSize = "1.875rem", LineHeight = "1.65", FontWeight = "800",
|
||||
LetterSpacing = "normal"
|
||||
},
|
||||
H3 = new H3Typography()
|
||||
{
|
||||
FontFamily = new[] { "Vazir" }, FontSize = "1.5rem", LineHeight = "1.60", FontWeight = "800",
|
||||
LetterSpacing = "normal"
|
||||
},
|
||||
H4 = new H4Typography()
|
||||
{
|
||||
FontFamily = new[] { "Vazir" }, FontSize = "1.25rem", LineHeight = "1.55", FontWeight = "800",
|
||||
LetterSpacing = "normal"
|
||||
},
|
||||
H5 = new H5Typography()
|
||||
{
|
||||
FontFamily = new[] { "Vazir" }, FontSize = "1.125rem", LineHeight = "1.50", FontWeight = "800",
|
||||
LetterSpacing = "normal"
|
||||
},
|
||||
H6 = new H6Typography()
|
||||
{
|
||||
FontFamily = new[] { "Vazir" }, FontSize = "1rem", LineHeight = "1.45", FontWeight = "800",
|
||||
LetterSpacing = "normal"
|
||||
},
|
||||
Subtitle1 = new Subtitle1Typography()
|
||||
{
|
||||
FontFamily = new[] { "Vazir" }, FontSize = "1rem", LineHeight = "1.62", FontWeight = "500",
|
||||
LetterSpacing = "normal"
|
||||
},
|
||||
Subtitle2 = new Subtitle2Typography()
|
||||
{
|
||||
FontFamily = new[] { "Vazir" }, FontSize = "0.875rem", LineHeight = "1.60", FontWeight = "500",
|
||||
LetterSpacing = "normal"
|
||||
},
|
||||
Body1 = new Body1Typography()
|
||||
{
|
||||
FontFamily = new[] { "Vazir" }, FontSize = "1rem", LineHeight = "1.85", FontWeight = "400",
|
||||
LetterSpacing = "normal"
|
||||
},
|
||||
Body2 = new Body2Typography()
|
||||
{
|
||||
FontFamily = new[] { "Vazir" }, FontSize = "0.875rem", LineHeight = "1.80", FontWeight = "400",
|
||||
LetterSpacing = "normal"
|
||||
},
|
||||
Caption = new CaptionTypography()
|
||||
{
|
||||
FontFamily = new[] { "Vazir" }, FontSize = "0.75rem", LineHeight = "1.60", FontWeight = "400",
|
||||
LetterSpacing = "normal"
|
||||
},
|
||||
Overline = new OverlineTypography()
|
||||
{
|
||||
FontFamily = new[] { "Vazir" }, FontSize = "0.75rem", LineHeight = "1.60", FontWeight = "500",
|
||||
LetterSpacing = "normal"
|
||||
},
|
||||
Button = new ButtonTypography()
|
||||
{
|
||||
FontFamily = new[] { "Vazir" }, FontSize = "0.875rem", LineHeight = "1.60", FontWeight = "600",
|
||||
LetterSpacing = "normal", TextTransform = "none"
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
@inherits LayoutComponentBase
|
||||
|
||||
<MudRTLProvider RightToLeft="true">
|
||||
<MudThemeProvider Theme="CustomTheme" />
|
||||
<MudThemeProvider Theme="CustomMudTheme.CustomMudBlazorTheme" />
|
||||
<MudDialogProvider />
|
||||
<MudSnackbarProvider />
|
||||
|
||||
@@ -13,24 +13,3 @@
|
||||
</MudMainContent>
|
||||
</MudLayout>
|
||||
</MudRTLProvider>
|
||||
|
||||
|
||||
@code {
|
||||
|
||||
|
||||
MudTheme CustomTheme = new MudTheme()
|
||||
{
|
||||
Typography = new Typography()
|
||||
{
|
||||
Default = new Default()
|
||||
{
|
||||
FontFamily = new[] { "IRANSans" }
|
||||
|
||||
}
|
||||
},
|
||||
LayoutProperties = new()
|
||||
{
|
||||
DrawerWidthRight = "250px"
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -4,14 +4,14 @@
|
||||
@attribute [AllowAnonymous]
|
||||
|
||||
<MudRTLProvider RightToLeft="true">
|
||||
<MudThemeProvider Theme="CustomTheme" />
|
||||
<MudThemeProvider Theme="CustomMudTheme.CustomMudBlazorTheme" />
|
||||
<MudDialogProvider />
|
||||
<MudSnackbarProvider />
|
||||
<MudPopoverProvider />
|
||||
<MudLayout>
|
||||
<MudAppBar>
|
||||
<MudAppBar Elevation="1" Color="Color.Surface">
|
||||
<MudIconButton Icon="@Icons.Material.Filled.Menu" Color="Color.Inherit" Edge="Edge.Start" OnClick="@((e) => DrawerToggle())" />
|
||||
مدیریت
|
||||
<MudText Class="mx-2" Typo="Typo.h6">پنل مدیریت فرصت</MudText>
|
||||
<MudSpacer />
|
||||
<AuthorizeView>
|
||||
<Authorized>
|
||||
@@ -33,4 +33,3 @@
|
||||
</MudLayout>
|
||||
</MudRTLProvider>
|
||||
|
||||
|
||||
|
||||
@@ -1,27 +1,24 @@
|
||||
using BackOffice.Common.Utilities;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Microsoft.AspNetCore.Components.Authorization;
|
||||
using MudBlazor;
|
||||
|
||||
namespace BackOffice.Shared;
|
||||
|
||||
public partial class MainLayout
|
||||
{
|
||||
bool _drawerOpen = false;
|
||||
private string Details { get; set; }
|
||||
|
||||
private bool _drawerOpen;
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
base.OnInitialized();
|
||||
GlobalConstants.ConstSnackbar = Snackbar;
|
||||
}
|
||||
|
||||
void DrawerToggle()
|
||||
{
|
||||
_drawerOpen = !_drawerOpen;
|
||||
}
|
||||
|
||||
MudTheme CustomTheme = new MudTheme()
|
||||
{
|
||||
Typography = new Typography()
|
||||
{
|
||||
Default = new Default()
|
||||
{
|
||||
FontFamily = new[] { "IRANSans" }
|
||||
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,19 +1,57 @@
|
||||
@using BackOffice.BFF.Package.Protobuf.Protos.Package
|
||||
@using Microsoft.AspNetCore.Components.Authorization
|
||||
@using Microsoft.AspNetCore.Components.Authorization
|
||||
|
||||
<MudNavMenu Bordered="false" Class="nav-menu">
|
||||
<MudText Class="nav-menu__title" Typo="Typo.subtitle2">منوی اصلی</MudText>
|
||||
<MudDivider Class="mb-2" />
|
||||
|
||||
<MudNavLink Match="NavLinkMatch.Prefix"
|
||||
Href="/"
|
||||
Icon="@Icons.Material.Filled.Dashboard">
|
||||
داشبورد
|
||||
</MudNavLink>
|
||||
|
||||
<MudNavMenu Bordered="true">
|
||||
<MudNavLink Match="NavLinkMatch.Prefix" Href="/">داشبورد</MudNavLink>
|
||||
<AuthorizeView Roles="Administrator">
|
||||
<Authorized>
|
||||
<MudNavLink Match="NavLinkMatch.Prefix" Href="@(RouteConstance.Package)">مدیریت پکیج</MudNavLink>
|
||||
<MudNavLink Match="NavLinkMatch.Prefix" Href="@(RouteConstance.UserPage)">مدیریت کاربر</MudNavLink>
|
||||
<MudNavLink Match="NavLinkMatch.Prefix" Href="@(RouteConstance.Role)">مدیریت نقش</MudNavLink>
|
||||
|
||||
<MudNavLink Match="NavLinkMatch.Prefix"
|
||||
Href="@(RouteConstance.Package)"
|
||||
Icon="@Icons.Material.Filled.Inventory2">
|
||||
مدیریت پکیج
|
||||
</MudNavLink>
|
||||
|
||||
<MudNavLink Match="NavLinkMatch.Prefix"
|
||||
Href="@(RouteConstance.Products)"
|
||||
Icon="@Icons.Material.Filled.ShoppingBag">
|
||||
مدیریت محصول
|
||||
</MudNavLink>
|
||||
|
||||
<MudNavLink Match="NavLinkMatch.Prefix"
|
||||
Href="@(RouteConstance.Category)"
|
||||
Icon="@Icons.Material.Filled.Category">
|
||||
مدیریت دستهبندی
|
||||
</MudNavLink>
|
||||
|
||||
<MudNavLink Match="NavLinkMatch.Prefix"
|
||||
Href="@(RouteConstance.UserPage)"
|
||||
Icon="@Icons.Material.Filled.People">
|
||||
مدیریت کاربر
|
||||
</MudNavLink>
|
||||
|
||||
<MudNavLink Match="NavLinkMatch.Prefix"
|
||||
Href="@(RouteConstance.Role)"
|
||||
Icon="@Icons.Material.Filled.AdminPanelSettings">
|
||||
مدیریت نقش
|
||||
</MudNavLink>
|
||||
</Authorized>
|
||||
</AuthorizeView>
|
||||
|
||||
|
||||
<MudNavLink Match="NavLinkMatch.Prefix" OnClick="Signout">خروج از حساب</MudNavLink>
|
||||
|
||||
<MudDivider Class="my-2" />
|
||||
|
||||
<MudNavLink Match="NavLinkMatch.Prefix"
|
||||
Color="Color.Error"
|
||||
Icon="@Icons.Material.Filled.Logout"
|
||||
OnClick="Signout">
|
||||
خروج از حساب
|
||||
</MudNavLink>
|
||||
</MudNavMenu>
|
||||
|
||||
|
||||
@@ -24,4 +62,4 @@
|
||||
await LocalStorageService.RemoveItemAsync("AuthToken");
|
||||
Navigation.NavigateTo("/Login");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
.nav-menu {
|
||||
padding: 1.5rem 0.5rem 1.5rem 0.5rem;
|
||||
}
|
||||
|
||||
.nav-menu__title {
|
||||
padding: 0 0.75rem 0.25rem 0.75rem;
|
||||
color: rgba(0, 0, 0, 0.6);
|
||||
}
|
||||
|
||||
.nav-menu .mud-divider {
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
.nav-menu .mud-nav-link {
|
||||
margin: 0.15rem 0.4rem;
|
||||
border-radius: 999px;
|
||||
padding-inline: 0.75rem 1rem;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.nav-menu .mud-nav-link .mud-nav-link-text {
|
||||
margin-right: 0.5rem;
|
||||
}
|
||||
|
||||
.nav-menu .mud-nav-link.mud-nav-link-active {
|
||||
background-color: rgba(3, 128, 192, 0.12);
|
||||
color: #0380C0;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.nav-menu .mud-nav-link.mud-nav-link-active .mud-nav-link-icon {
|
||||
color: #0380C0;
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
@using MudBlazor
|
||||
@using Mapster
|
||||
@using DateTimeConverterCL
|
||||
@using Microsoft.AspNetCore.Components.Authorization
|
||||
|
||||
|
||||
@attribute [Authorize(Roles = "Administrator, Admin, Author")]
|
||||
@@ -20,3 +21,4 @@
|
||||
@inject IJSRuntime jsRuntime
|
||||
@inject NavigationManager Navigation
|
||||
@inject ILocalStorageService LocalStorageService
|
||||
@inject AuthenticationStateProvider AuthenticationStateProvider
|
||||
|
||||
@@ -9,6 +9,17 @@
|
||||
url('../fonts/ttf/IRANSansWeb(FaNum)_Medium.ttf') format('truetype');
|
||||
}
|
||||
|
||||
html, body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
height: 100%;
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: "Vazir", "IRANSans", Tahoma, "Segoe UI", Arial, sans-serif;
|
||||
}
|
||||
|
||||
.loading-progress {
|
||||
position: relative;
|
||||
display: block;
|
||||
@@ -79,4 +90,4 @@ h1:focus {
|
||||
|
||||
.blazor-error-boundary::after {
|
||||
content: "An error has occurred."
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user