Skip to content

Commit

Permalink
finished product features
Browse files Browse the repository at this point in the history
  • Loading branch information
neozhu committed Feb 11, 2022
1 parent 997bce8 commit d031ceb
Show file tree
Hide file tree
Showing 6 changed files with 146 additions and 74 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -40,13 +40,29 @@ IMapper mapper
}
public async Task<Result> Handle(ImportProductsCommand request, CancellationToken cancellationToken)
{
//TODO:Implementing ImportProductsCommandHandler method

var result = await _excelService.ImportAsync(request.Data, mappers: new Dictionary<string, Func<DataRow, ProductDto, object>>
{
//ex. { _localizer["Name"], (row,item) => item.Name = row[_localizer["Name"]]?.ToString() },

{ _localizer["Product Name"], (row,item) => item.Name = row[_localizer["Product Name"]]?.ToString() },
{ _localizer["Description"], (row,item) => item.Description = row[_localizer["Description"]]?.ToString() },
{ _localizer["Unit"], (row,item) => item.Unit = row[_localizer["Unit"]]?.ToString() },
{ _localizer["Price of unit"], (row,item) => item.Price =row.IsNull(_localizer["Price of unit"])? 0m:Convert.ToDecimal(row[_localizer["Price of unit"]]) },
{ _localizer["Pictures"], (row,item) => item.Pictures =row.IsNull(_localizer["Pictures"])? null:row[_localizer["Pictures"]].ToString().Split(",").ToList() },
}, _localizer["Products"]);
throw new System.NotImplementedException();
if (result.Succeeded)
{
foreach(var dto in result.Data)
{
var item = _mapper.Map<Product>(dto);
await _context.Products.AddAsync(item,cancellationToken);
}
await _context.SaveChangesAsync(cancellationToken);
return Result.Success();
}
else
{
return Result.Failure(result.Errors);
}
}
public async Task<byte[]> Handle(CreateProductsTemplateCommand request, CancellationToken cancellationToken)
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Licensed to the .NET Foundation under one or more agreements.
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

namespace CleanArchitecture.Blazor.Application.Features.Products.Commands.Import;
Expand All @@ -7,11 +7,11 @@ public class ImportProductsCommandValidator : AbstractValidator<ImportProductsCo
{
public ImportProductsCommandValidator()
{
//TODO:Implementing ImportProductCommandValidator method
//ex. RuleFor(v => v.Data)
// .NotNull()
// .NotEmpty();
throw new System.NotImplementedException();

RuleFor(v => v.Data)
.NotNull()
.NotEmpty();

}
}

Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Licensed to the .NET Foundation under one or more agreements.
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.


Expand All @@ -8,10 +8,10 @@ namespace CleanArchitecture.Blazor.Application.Features.Products.Queries.Export;

public class ExportProductsQuery : IRequest<byte[]>
{
public string FilterRules { get; set; }
public string Sort { get; set; } = "Id";
public string Order { get; set; } = "desc";
}
public string OrderBy { get; set; } = "Id";
public string SortDirection { get; set; } = "Desc";
public string Keyword { get; set; } = String.Empty;
}

public class ExportProductsQueryHandler :
IRequestHandler<ExportProductsQuery, byte[]>
Expand All @@ -36,16 +36,18 @@ IStringLocalizer<ExportProductsQueryHandler> localizer

public async Task<byte[]> Handle(ExportProductsQuery request, CancellationToken cancellationToken)
{
//TODO:Implementing ExportProductsQueryHandler method
var filters = PredicateBuilder.FromFilter<Product>(request.FilterRules);
var data = await _context.Products.Where(filters)
.OrderBy("{request.Sort} {request.Order}")
var data = await _context.Products.Where(x=>x.Name.Contains(request.Keyword) || x.Description.Contains(request.Keyword))
.OrderBy($"{request.OrderBy} {request.SortDirection}")
.ProjectTo<ProductDto>(_mapper.ConfigurationProvider)
.ToListAsync(cancellationToken);
var result = await _excelService.ExportAsync(data,
new Dictionary<string, Func<ProductDto, object>>()
{
//{ _localizer["Id"], item => item.Id },
{ _localizer["Product Name"], item => item.Name },
{ _localizer["Description"], item => item.Description },
{ _localizer["Price of unit"], item => item.Price },
{ _localizer["Unit"], item => item.Unit },
{ _localizer["Pictures"], item => item.Pictures!=null?string.Join(",",item.Pictures):null },
}
, _localizer["Products"]);
return result;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ IStringLocalizer<ProductsWithPaginationQueryHandler> localizer

public async Task<PaginatedData<ProductDto>> Handle(ProductsWithPaginationQuery request, CancellationToken cancellationToken)
{
var data = await _context.Products.Where(x=>x.Name.Contains(request.Keyword))
var data = await _context.Products.Where(x=>x.Name.Contains(request.Keyword) || x.Description.Contains(request.Keyword))
.OrderBy($"{request.OrderBy} {request.SortDirection}")
.ProjectTo<ProductDto>(_mapper.ConfigurationProvider)
.PaginatedDataAsync(request.PageNumber, request.PageSize);
Expand Down
139 changes: 87 additions & 52 deletions src/Blazor.Server.UI/Pages/Products/Products.razor
Original file line number Diff line number Diff line change
@@ -1,16 +1,21 @@
@page "/pages/products"
@using Blazor.Server.UI.Components.Dialogs
@using CleanArchitecture.Blazor.Application.Features.Products.Commands.Delete
@using CleanArchitecture.Blazor.Application.Features.Products.Commands.Import
@using CleanArchitecture.Blazor.Application.Features.Products.DTOs
@using CleanArchitecture.Blazor.Application.Features.Products.Queries.Export
@using CleanArchitecture.Blazor.Application.Features.Products.Queries.Pagination
@using CleanArchitecture.Blazor.Application.Features.Products.Commands.AddEdit

@inject IJSRuntime JS
@inject IStringLocalizer<Products> L
<PageTitle>@Title</PageTitle>
<style>
.mud-table-toolbar {
height: 84px !important;
}
</style>

<MudTable ServerData="@(new Func<TableState, Task<TableData<ProductDto>>>(ServerReload))"
FixedHeader="true"
FixedFooter="true"
Expand All @@ -21,48 +26,52 @@
Hover="true" @ref="_table">
<ToolBarContent>
<div class="justify-start pt-3">
<MudText Typo="Typo.h6">Product</MudText>
<MudButton DisableElevation Variant="Variant.Outlined"
Size="Size.Small"
OnClick="@(()=>OnRefresh())"
StartIcon="@Icons.Material.Filled.Refresh" IconColor="Color.Surface" Color="Color.Primary"
Style="margin-right: 5px;">@L["Refresh"]</MudButton>
@if (_canCreate)
{
<MudButton DisableElevation Variant="Variant.Outlined" Color="Color.Primary"
StartIcon="@Icons.Material.Filled.Add"
Size="Size.Small"
Style="margin-right: 5px;"
OnClick="OnCreate"
IconColor="Color.Surface">@L["Create"]</MudButton>
}
@if (_canDelete)
{
<MudButton DisableElevation Variant="Variant.Outlined" Color="Color.Error"
StartIcon="@Icons.Material.Filled.Delete"
Disabled="@(!(_selectedItems.Count>0))"
Size="Size.Small"
Style="margin-right: 5px;"
OnClick="OnDeleteChecked"
IconColor="Color.Surface">@L["Delete"]</MudButton>
}
@if (_canImport)
{
<MudButton DisableElevation Variant="Variant.Outlined" Color="Color.Primary"
StartIcon="@Icons.Material.Filled.Upload"
Size="Size.Small"
Style="margin-right: 5px;"
IconColor="Color.Surface">@L["Import Data"]</MudButton>
}
@if (_canExport)
{
<MudButton DisableElevation Variant="Variant.Outlined" Color="Color.Primary"
StartIcon="@Icons.Material.Filled.Download"
Size="Size.Small"
Style="margin-right: 5px;"
IconColor="Color.Surface">@L["Export Data"]</MudButton>
}
</div>
<MudText Typo="Typo.h6">Product</MudText>
<MudButton DisableElevation Variant="Variant.Outlined"
Size="Size.Small"
OnClick="@(()=>OnRefresh())"
StartIcon="@Icons.Material.Filled.Refresh" IconColor="Color.Surface" Color="Color.Primary"
Style="margin-right: 5px;">@L["Refresh"]</MudButton>
@if (_canCreate)
{
<MudButton DisableElevation Variant="Variant.Outlined" Color="Color.Primary"
StartIcon="@Icons.Material.Filled.Add"
Size="Size.Small"
Style="margin-right: 5px;"
OnClick="OnCreate"
IconColor="Color.Surface">@L["Create"]</MudButton>
}
@if (_canDelete)
{
<MudButton DisableElevation Variant="Variant.Outlined" Color="Color.Error"
StartIcon="@Icons.Material.Filled.Delete"
Disabled="@(!(_selectedItems.Count>0))"
Size="Size.Small"
Style="margin-right: 5px;"
OnClick="OnDeleteChecked"
IconColor="Color.Surface">@L["Delete"]</MudButton>
}
@if (_canImport)
{
<InputFile id="importdataInput" OnChange="OnImportData" hidden accept=".xlsx" />
<MudButton DisableElevation Variant="Variant.Outlined" Color="Color.Primary"
StartIcon="@Icons.Material.Filled.Upload"
Size="Size.Small"
Style="margin-right: 5px;"
for="importdataInput"
HtmlTag="label"
IconColor="Color.Surface">@L["Import Data"]</MudButton>
}
@if (_canExport)
{
<MudButton DisableElevation Variant="Variant.Outlined" Color="Color.Primary"
StartIcon="@Icons.Material.Filled.Download"
Size="Size.Small"
Style="margin-right: 5px;"
OnClick="OnExport"
IconColor="Color.Surface">@L["Export Data"]</MudButton>
}
</div>
<MudSpacer />
<MudTextField T="string" ValueChanged="@(s=>OnSearch(s))" Placeholder="Search" Adornment="Adornment.Start"
AdornmentIcon="@Icons.Material.Filled.Search" IconSize="Size.Medium" Class="mt-0"></MudTextField>
Expand Down Expand Up @@ -181,7 +190,7 @@
}
private async Task OnCreate()
{
var command=new AddEditProductCommand();
var command = new AddEditProductCommand();
var parameters = new DialogParameters
{
{ nameof(_ProductFormDialog.model),command },
Expand All @@ -199,14 +208,14 @@
private async Task OnEdit(ProductDto dto)
{
var command = new AddEditProductCommand()
{
Id=dto.Id,
Name=dto.Name,
Description = dto.Description,
Pictures = dto.Pictures,
Unit=dto.Unit,
Price=dto.Price
};
{
Id = dto.Id,
Name = dto.Name,
Description = dto.Description,
Pictures = dto.Pictures,
Unit = dto.Unit,
Price = dto.Price
};
var parameters = new DialogParameters
{
{ nameof(_ProductFormDialog.model),command },
Expand Down Expand Up @@ -253,10 +262,36 @@
var state = await dialog.Result;
if (!state.Cancelled)
{
var command = new DeleteCheckedProductsCommand() { Id =_selectedItems.Select(x=>x.Id).ToArray() };
var command = new DeleteCheckedProductsCommand() { Id = _selectedItems.Select(x => x.Id).ToArray() };
var result = await _mediator.Send(command);
await _table.ReloadServerData();
Snackbar.Add($"Deleted successfully", MudBlazor.Severity.Info);
}
}
private async Task OnExport()
{

var request = new ExportProductsQuery()
{
Keyword = _searchString,
OrderBy = string.IsNullOrEmpty(_table.TableContext.SortFieldLabel) ? "Id" : _table.TableContext.SortFieldLabel,
SortDirection = (_table.TableContext.SortDirection == SortDirection.None ? SortDirection.Descending.ToString() : _table.TableContext.SortDirection.ToString()),
};
var result = await _mediator.Send(request);
using var streamRef = new DotNetStreamReference(new MemoryStream(result));
await JS.InvokeVoidAsync("downloadFileFromStream", $"{L["Products"]}.xlsx", streamRef);
}
private async Task OnImportData(InputFileChangeEventArgs e)
{
var stream = new MemoryStream();
await e.File.OpenReadStream().CopyToAsync(stream);
var command=new ImportProductsCommand()
{
Data=stream.ToArray(),
FileName= e.File.Name
};
var result = await _mediator.Send(command);
await _table.ReloadServerData();
Snackbar.Add($"Import data successfully", MudBlazor.Severity.Info);
}
}
21 changes: 20 additions & 1 deletion src/Blazor.Server.UI/Pages/_Layout.cshtml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,26 @@
<script src="_content/MudBlazor/MudBlazor.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/apexcharts"></script>
<script src="~/js/apex-chart-wrapper.js"></script>
@await RenderSectionAsync("scripts",false)
<script type="text/javascript">
async function downloadFileFromStream(fileName, contentStreamReference) {
const arrayBuffer = await contentStreamReference.arrayBuffer();
const blob = new Blob([arrayBuffer]);
const url = URL.createObjectURL(blob);
triggerFileDownload(fileName, url);
URL.revokeObjectURL(url);
}
function triggerFileDownload(fileName, url) {
const anchorElement = document.createElement('a');
anchorElement.href = url;
anchorElement.download = fileName ?? '';
anchorElement.click();
anchorElement.remove();
}
</script>
</body>
</html>

0 comments on commit d031ceb

Please sign in to comment.