Merge branch 'main' into stage
# Conflicts: # src/FrontOffice.Main/Shared/MainLayout.razor # src/FrontOffice.Main/Utilities/WalletService.cs
This commit is contained in:
@@ -10,6 +10,7 @@ using FrontOffice.BFF.Transaction.Protobuf.Protos.Transaction;
|
||||
using FrontOffice.BFF.User.Protobuf.Protos.User;
|
||||
using FrontOffice.BFF.UserAddress.Protobuf.Protos.UserAddress;
|
||||
using FrontOffice.BFF.UserOrder.Protobuf.Protos.UserOrder;
|
||||
using FrontOffice.BFF.UserWallet.Protobuf.Protos.UserWallet;
|
||||
using FrontOffice.BFF.ShopingCart.Protobuf.Protos.ShopingCart;
|
||||
using FrontOffice.Main.Utilities;
|
||||
|
||||
@@ -76,6 +77,7 @@ public static class ConfigureServices
|
||||
services.AddScoped(CreateAuthenticatedClient<UserContract.UserContractClient>);
|
||||
services.AddScoped(CreateAuthenticatedClient<UserAddressContract.UserAddressContractClient>);
|
||||
services.AddScoped(CreateAuthenticatedClient<UserOrderContract.UserOrderContractClient>);
|
||||
services.AddScoped(CreateAuthenticatedClient<UserWalletContract.UserWalletContractClient>);
|
||||
// Products gRPC
|
||||
services.AddScoped(CreateAuthenticatedClient<FrontOffice.BFF.Products.Protobuf.Protos.Products.ProductsContract.ProductsContractClient>);
|
||||
services.AddScoped(CreateAuthenticatedClient<TransactionContract.TransactionContractClient>);
|
||||
|
||||
@@ -13,9 +13,10 @@
|
||||
<PackageReference Include="Foursat.FrontOffice.BFF.Transaction.Protobuf" Version="0.0.111" />
|
||||
<PackageReference Include="Foursat.FrontOffice.BFF.User.Protobuf" Version="0.0.116" />
|
||||
<PackageReference Include="Foursat.FrontOffice.BFF.UserAddress.Protobuf" Version="0.0.114" />
|
||||
<PackageReference Include="Foursat.FrontOffice.BFF.UserOrder.Protobuf" Version="0.0.112" />
|
||||
<PackageReference Include="Foursat.FrontOffice.BFF.UserOrder.Protobuf" Version="0.0.114" />
|
||||
<PackageReference Include="FrontOffice.BFF.Products.Protobuf" Version="0.0.11" />
|
||||
<PackageReference Include="FrontOffice.BFF.ShopingCart.Protobuf" Version="0.0.12" />
|
||||
<PackageReference Include="FrontOffice.BFF.ShopingCart.Protobuf" Version="0.0.15" />
|
||||
<PackageReference Include="FrontOffice.BFF.UserWallet.Protobuf" Version="0.0.11" />
|
||||
<PackageReference Include="MudBlazor" Version="8.14.0" />
|
||||
<PackageReference Include="Blazored.LocalStorage" Version="4.5.0" />
|
||||
<PackageReference Include="Mapster" Version="7.4.0" />
|
||||
|
||||
@@ -18,7 +18,6 @@ public partial class Index
|
||||
{
|
||||
[Inject] private UserContract.UserContractClient UserContract { get; set; } = default!;
|
||||
[Inject] private UserAddressContract.UserAddressContractClient UserAddressContract { get; set; } = default!;
|
||||
[Inject] private WalletService WalletService { get; set; } = default!;
|
||||
|
||||
private GetUserResponse _userProfile = new();
|
||||
private UpdateUserRequest _updateUserRequest = new();
|
||||
|
||||
@@ -5,7 +5,6 @@ namespace FrontOffice.Main.Pages.Profile;
|
||||
|
||||
public partial class Wallet : ComponentBase
|
||||
{
|
||||
[Inject] private WalletService WalletService { get; set; } = default!;
|
||||
|
||||
private (string Credit, string Network) _balances = ("-", "-");
|
||||
private List<WalletTransaction> _txs = new();
|
||||
|
||||
@@ -58,7 +58,7 @@
|
||||
{
|
||||
<MudStack Spacing="3" >
|
||||
<MudStack Row="true" Justify="Justify.SpaceBetween" AlignItems="AlignItems.Center">
|
||||
<MudText Typo="Typo.h4">ویزارد ثبتنام</MudText>
|
||||
<MudText Typo="Typo.h4">مراحل ثبتنام</MudText>
|
||||
<MudChip T="string" Color="Color.Info" Variant="Variant.Outlined" Size="Size.Small">۳ مرحله
|
||||
</MudChip>
|
||||
</MudStack>
|
||||
|
||||
@@ -10,7 +10,9 @@
|
||||
@if (CartData.Items.Count == 0)
|
||||
{
|
||||
<MudAlert Severity="Severity.Info">سبد خرید شما خالی است.</MudAlert>
|
||||
<MudButton Variant="Variant.Outlined" StartIcon="@Icons.Material.Filled.ArrowBack" OnClick="() => Navigation.NavigateTo(RouteConstants.Store.Products)">بازگشت به محصولات</MudButton>
|
||||
<MudButton Variant="Variant.Outlined" StartIcon="@Icons.Material.Filled.ArrowBack"
|
||||
OnClick="() => Navigation.NavigateTo(RouteConstants.Store.Products)">بازگشت به محصولات
|
||||
</MudButton>
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -26,18 +28,49 @@
|
||||
</HeaderContent>
|
||||
<RowTemplate>
|
||||
<MudTd>
|
||||
<MudStack Spacing="1">
|
||||
<MudStack Row="true" Spacing="2" AlignItems="AlignItems.Center">
|
||||
<MudAvatar Image="@context.ImageUrl" Size="Size.Medium" />
|
||||
<MudAvatar Image="@context.ImageUrl" Size="Size.Medium"/>
|
||||
<MudText>@context.Title</MudText>
|
||||
</MudStack>
|
||||
@if (context.Discount > 0 || !string.IsNullOrWhiteSpace(context.Created) || !string.IsNullOrWhiteSpace(context.Description))
|
||||
{
|
||||
<MudStack Spacing="1">
|
||||
@if (context.Discount > 0)
|
||||
{
|
||||
<MudChip T="string" Color="Color.Error" Variant="Variant.Outlined"
|
||||
Size="Size.Small">@($"{context.Discount}% تخفیف")</MudChip>
|
||||
}
|
||||
@if (!string.IsNullOrWhiteSpace(context.Description))
|
||||
{
|
||||
<MudText Typo="Typo.caption"
|
||||
Class="mud-text-secondary">@context.Description</MudText>
|
||||
}
|
||||
@if (!string.IsNullOrWhiteSpace(context.Created))
|
||||
{
|
||||
<MudText Typo="Typo.caption" Class="mud-text-secondary">تاریخ
|
||||
افزودن: @context.Created</MudText>
|
||||
}
|
||||
</MudStack>
|
||||
}
|
||||
</MudStack>
|
||||
</MudTd>
|
||||
<MudTd>@FormatPrice(context.UnitPrice)</MudTd>
|
||||
<MudTd>
|
||||
<MudNumericField T="int" Value="@context.Quantity" Min="1" Max="50" Immediate="true" HideSpinButtons="true" ValueChanged="(v) => ChangeQty(context.ProductId, v)" Style="max-width:120px" />
|
||||
<MudStack Row="true" AlignItems="AlignItems.Center" Spacing="1">
|
||||
<MudIconButton Icon="@Icons.Material.Filled.Remove"
|
||||
Color="Color.Default"
|
||||
OnClick="@(() => DecrementQty(context.ProductId))"/>
|
||||
<MudText>@context.Quantity</MudText>
|
||||
<MudIconButton Icon="@Icons.Material.Filled.Add"
|
||||
Color="Color.Default"
|
||||
OnClick="@(() => IncrementQty(context.ProductId))"/>
|
||||
</MudStack>
|
||||
</MudTd>
|
||||
<MudTd>@FormatPrice(context.LineTotal)</MudTd>
|
||||
<MudTd>
|
||||
<MudIconButton Icon="@Icons.Material.Filled.Delete" Color="Color.Error" OnClick="() => Remove(context.ProductId)" />
|
||||
<MudIconButton Icon="@Icons.Material.Filled.Delete" Color="Color.Error"
|
||||
OnClick="() => Remove(context.cartId)"/>
|
||||
</MudTd>
|
||||
</RowTemplate>
|
||||
</MudTable>
|
||||
@@ -48,33 +81,95 @@
|
||||
<MudStack Spacing="2">
|
||||
@foreach (var item in CartData.Items)
|
||||
{
|
||||
<MudPaper Class="pa-3 rounded-lg" Outlined="true">
|
||||
<MudPaper Class="pa-3 rounded-lg w-100-mobile" Outlined="true">
|
||||
<MudStack Spacing="1">
|
||||
<MudStack Row="true" Justify="Justify.SpaceBetween" AlignItems="AlignItems.Center">
|
||||
<MudStack Row="true" Spacing="2" AlignItems="AlignItems.Center">
|
||||
<MudAvatar Image="@item.ImageUrl" />
|
||||
<MudAvatar Image="@item.ImageUrl"/>
|
||||
<MudText Typo="Typo.subtitle2">@item.Title</MudText>
|
||||
</MudStack>
|
||||
@if (item.Discount > 0)
|
||||
{
|
||||
<MudChip T="string" Color="Color.Error" Variant="Variant.Outlined"
|
||||
Size="Size.Small">@($"{item.Discount}% ")</MudChip>
|
||||
}
|
||||
</MudStack>
|
||||
|
||||
@if (item.Discount > 0 || !string.IsNullOrWhiteSpace(item.Created) || !string.IsNullOrWhiteSpace(item.Description))
|
||||
{
|
||||
<MudStack Spacing="1">
|
||||
|
||||
@if (!string.IsNullOrWhiteSpace(item.Description))
|
||||
{
|
||||
<MudText Typo="Typo.caption"
|
||||
Class="mud-text-secondary">@item.Description</MudText>
|
||||
}
|
||||
@* @if (!string.IsNullOrWhiteSpace(item.Created)) *@
|
||||
@* { *@
|
||||
@* <MudText Typo="Typo.caption" Class="mud-text-secondary">تاریخ افزودن: @item.Created</MudText> *@
|
||||
@* } *@
|
||||
</MudStack>
|
||||
}
|
||||
|
||||
<MudStack Spacing="1">
|
||||
<MudStack Row="true" Justify="Justify.SpaceBetween" AlignItems="AlignItems.Center">
|
||||
<MudText Class="mud-text-secondary">@FormatPrice(item.UnitPrice) واحد</MudText>
|
||||
<MudNumericField T="int" Value="@item.Quantity" Min="1" Max="50" Immediate="true" HideSpinButtons="true" ValueChanged="(v) => ChangeQty(item.ProductId, v)" Class="qty-input" />
|
||||
<MudStack Row="true" AlignItems="AlignItems.Center" Spacing="1">
|
||||
<MudIconButton
|
||||
Icon="@(item.Quantity <= 1 ? Icons.Material.Filled.Delete : Icons.Material.Filled.Remove)"
|
||||
Color="Color.Default"
|
||||
OnClick="@(() => DecrementQty(item.ProductId))"/>
|
||||
<MudText>@item.Quantity</MudText>
|
||||
<MudIconButton Icon="@Icons.Material.Filled.Add"
|
||||
Color="Color.Default"
|
||||
OnClick="@(() => IncrementQty(item.ProductId))"/>
|
||||
</MudStack>
|
||||
</MudStack>
|
||||
<MudStack Row="true" Justify="Justify.SpaceBetween" AlignItems="AlignItems.Center">
|
||||
<MudText>جمع: @FormatPrice(item.LineTotal)</MudText>
|
||||
<MudIconButton Icon="@Icons.Material.Filled.Delete" Color="Color.Error" OnClick="() => Remove(item.ProductId)" />
|
||||
<MudIconButton Icon="@Icons.Material.Filled.Delete"
|
||||
Color="Color.Error"
|
||||
OnClick="() => Remove(item.cartId)"/>
|
||||
</MudStack>
|
||||
</MudStack>
|
||||
</MudStack>
|
||||
</MudPaper>
|
||||
}
|
||||
</MudStack>
|
||||
</MudHidden>
|
||||
@if (DeviceDetector.IsMobile())
|
||||
{
|
||||
<MudStack Row="true" Justify="Justify.SpaceBetween" AlignItems="AlignItems.Center"
|
||||
Class="mobile-actions-stack px-5">
|
||||
<MudText Typo="Typo.subtitle2"> تخفیف کل: <b>@FormatPrice(CartData.TotalDiscount)</b></MudText>
|
||||
<MudText Typo="Typo.h5"> مبلغ کل: <b>@FormatPrice(CartData.Total)</b></MudText>
|
||||
|
||||
<MudStack Row="true" Justify="Justify.SpaceBetween" AlignItems="AlignItems.Center" Class="mobile-actions-stack">
|
||||
<MudText Typo="Typo.h6">مبلغ قابل پرداخت: <b>@FormatPrice(CartData.Total)</b></MudText>
|
||||
<MudStack Row="true" Spacing="2" Class="mobile-actions-stack">
|
||||
<MudButton Variant="Variant.Text" OnClick="() => Navigation.NavigateTo(RouteConstants.Store.Products)">افزودن محصول</MudButton>
|
||||
<MudButton Variant="Variant.Filled" Color="Color.Primary" OnClick="ProceedCheckout" StartIcon="@Icons.Material.Filled.CreditCard">ادامه فرایند خرید</MudButton>
|
||||
</MudStack>
|
||||
|
||||
<MudStack Row="true" Justify="Justify.SpaceBetween" Spacing="2" Class="mobile-actions-stack">
|
||||
<MudButton Variant="Variant.Filled" Color="Color.Primary"
|
||||
OnClick="() => Navigation.NavigateTo(RouteConstants.Store.Products)">افزودن محصول
|
||||
</MudButton>
|
||||
<MudButton Variant="Variant.Filled" Color="Color.Success" OnClick="ProceedCheckout"
|
||||
StartIcon="@Icons.Material.Filled.CreditCard">ادامه فرایند خرید
|
||||
</MudButton>
|
||||
</MudStack>
|
||||
}
|
||||
else
|
||||
{
|
||||
<MudStack Row="true" Justify="Justify.SpaceBetween" AlignItems="AlignItems.Center"
|
||||
Class="mobile-actions-stack px-5">
|
||||
<MudText Typo="Typo.subtitle2"> تخفیف کل: <b>@FormatPrice(CartData.TotalDiscount)</b></MudText>
|
||||
<MudText Typo="Typo.h5"> مبلغ کل: <b>@FormatPrice(CartData.Total)</b></MudText>
|
||||
|
||||
<MudButton Variant="Variant.Filled" Color="Color.Primary"
|
||||
OnClick="() => Navigation.NavigateTo(RouteConstants.Store.Products)">افزودن محصول
|
||||
</MudButton>
|
||||
<MudButton Variant="Variant.Filled" Color="Color.Success" OnClick="ProceedCheckout"
|
||||
StartIcon="@Icons.Material.Filled.CreditCard">ادامه فرایند خرید
|
||||
</MudButton>
|
||||
</MudStack>
|
||||
}
|
||||
}
|
||||
</MudStack>
|
||||
</MudContainer>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using FrontOffice.Main.Utilities;
|
||||
using System.Linq;
|
||||
|
||||
namespace FrontOffice.Main.Pages.Store;
|
||||
|
||||
@@ -14,14 +15,28 @@ public partial class Cart : ComponentBase, IDisposable
|
||||
CartService.OnChange += StateHasChanged;
|
||||
}
|
||||
|
||||
private async Task IncrementQty(long productId)
|
||||
{
|
||||
var item = CartData.Items.FirstOrDefault(i => i.ProductId == productId);
|
||||
if (item is null) return;
|
||||
await CartService.UpdateQuantity(productId, item.Quantity + 1);
|
||||
}
|
||||
|
||||
private async Task DecrementQty(long productId)
|
||||
{
|
||||
var item = CartData.Items.FirstOrDefault(i => i.ProductId == productId);
|
||||
if (item is null) return;
|
||||
await CartService.UpdateQuantity(productId, item.Quantity - 1);
|
||||
}
|
||||
|
||||
private async Task ChangeQty(long productId, int value)
|
||||
{
|
||||
await CartService.UpdateQuantity(productId, value);
|
||||
}
|
||||
|
||||
private async Task Remove(long productId)
|
||||
private async Task Remove(long cartId)
|
||||
{
|
||||
await CartService.Remove(productId);
|
||||
await CartService.Remove(cartId);
|
||||
}
|
||||
|
||||
private void ProceedCheckout()
|
||||
@@ -29,7 +44,7 @@ public partial class Cart : ComponentBase, IDisposable
|
||||
Navigation.NavigateTo(RouteConstants.Store.CheckoutSummary);
|
||||
}
|
||||
|
||||
private static string FormatPrice(long price) => string.Format("{0:N0} تومان", price);
|
||||
private static string FormatPrice(long price) => string.Format("{0:N0} ", price);
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
@using FrontOffice.BFF.UserOrder.Protobuf.Protos.UserOrder
|
||||
@attribute [Route(RouteConstants.Store.CheckoutSummary)]
|
||||
|
||||
<PageTitle>خلاصه خرید</PageTitle>
|
||||
@@ -20,7 +21,7 @@
|
||||
<MudAlert Severity="Severity.Warning">
|
||||
هیچ آدرسی ثبت نشده است. لطفاً از بخش پروفایل آدرس خود را اضافه کنید.
|
||||
</MudAlert>
|
||||
<MudButton Class="mt-2" Variant="Variant.Outlined" Href="/profile">افزودن آدرس</MudButton>
|
||||
<MudButton Class="mt-2" Variant="Variant.Outlined" Href="/profile/addresses">افزودن آدرس</MudButton>
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -51,7 +52,15 @@
|
||||
<MudPaper Elevation="2" Class="pa-4 rounded-lg">
|
||||
<MudText Typo="Typo.h6" Class="mb-2">روش پرداخت</MudText>
|
||||
<MudRadioGroup T="PaymentMethod" @bind-SelectedOption="_payment" Color="Color.Primary">
|
||||
<MudRadio T="PaymentMethod" Option="@PaymentMethod.Wallet" Color="Color.Primary">کیف پول</MudRadio>
|
||||
<MudRadio T="PaymentMethod" Option="@PaymentMethod.Wallet" Color="Color.Primary">
|
||||
@* <MudText></MudText> *@
|
||||
@* <MudText>20000</MudText> *@
|
||||
<MudStack Row="true" Justify="Justify.SpaceBetween" AlignItems="AlignItems.Center">
|
||||
<MudText Typo="Typo.subtitle1">کیف پول <b></b></MudText>
|
||||
<MudText Typo="Typo.subtitle2"> @(FormatPrice(walletBalance)) <b></b></MudText>
|
||||
|
||||
</MudStack>
|
||||
</MudRadio>
|
||||
</MudRadioGroup>
|
||||
<MudAlert Severity="Severity.Info" Variant="Variant.Outlined">در حال حاضر تنها پرداخت از طریق کیف پول فعال است.</MudAlert>
|
||||
</MudPaper>
|
||||
@@ -70,10 +79,16 @@
|
||||
@foreach (var item in Cart.Items)
|
||||
{
|
||||
<MudListItem T="CartItem">
|
||||
<MudStack Row="true" Justify="Justify.SpaceBetween" Class="w-100">
|
||||
<MudStack Spacing="1" Class="w-100">
|
||||
<MudStack Row="true" Justify="Justify.SpaceBetween">
|
||||
<MudText>@item.Title x @item.Quantity</MudText>
|
||||
<MudText>@FormatPrice(item.LineTotal)</MudText>
|
||||
</MudStack>
|
||||
@if (item.Discount > 0)
|
||||
{
|
||||
<MudText Typo="Typo.caption" Class="mud-text-secondary">@($"تخفیف: {item.Discount}%")</MudText>
|
||||
}
|
||||
</MudStack>
|
||||
</MudListItem>
|
||||
}
|
||||
</MudList>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using FrontOffice.BFF.UserAddress.Protobuf.Protos.UserAddress;
|
||||
using FrontOffice.BFF.UserOrder.Protobuf.Protos.UserOrder;
|
||||
using FrontOffice.Main.Utilities;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using MudBlazor;
|
||||
@@ -10,11 +11,13 @@ public partial class CheckoutSummary : ComponentBase
|
||||
[Inject] private CartService Cart { get; set; } = default!;
|
||||
[Inject] private OrderService OrderService { get; set; } = default!;
|
||||
[Inject] private UserAddressContract.UserAddressContractClient UserAddressContract { get; set; } = default!;
|
||||
[Inject] private UserOrderContract.UserOrderContractClient UserOrderContract { get; set; } = default!;
|
||||
// Snackbar and Navigation are injected via _Imports.razor
|
||||
|
||||
private List<GetAllUserAddressByFilterResponseModel> _addresses = new();
|
||||
private GetAllUserAddressByFilterResponseModel? _selectedAddress;
|
||||
private bool _loadingAddresses;
|
||||
private long walletBalance;
|
||||
|
||||
private PaymentMethod _payment = PaymentMethod.Wallet;
|
||||
|
||||
@@ -23,6 +26,13 @@ public partial class CheckoutSummary : ComponentBase
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
await LoadAddresses();
|
||||
await LoadWalletBalance();
|
||||
}
|
||||
|
||||
private async Task LoadWalletBalance()
|
||||
{
|
||||
var walletResult = await WalletService.GetBalancesAsync();
|
||||
walletBalance = walletResult.CreditBalance + walletResult.NetworkBalance;
|
||||
}
|
||||
|
||||
private async Task LoadAddresses()
|
||||
@@ -61,20 +71,22 @@ public partial class CheckoutSummary : ComponentBase
|
||||
return;
|
||||
}
|
||||
|
||||
// Simulate wallet payment success and create local order
|
||||
var order = new Order
|
||||
try
|
||||
{
|
||||
Status = OrderStatus.Paid,
|
||||
PaymentMethod = _payment,
|
||||
AddressId = _selectedAddress.Id,
|
||||
AddressSummary = _selectedAddress.Address,
|
||||
Items = Cart.Items.Select(i => new OrderItem(i.ProductId, i.Title, i.ImageUrl, i.UnitPrice, i.Quantity)).ToList()
|
||||
var request = new SubmitShopBuyOrderRequest
|
||||
{
|
||||
TotalAmount = Cart.Total
|
||||
};
|
||||
|
||||
var id = await OrderService.CreateOrderAsync(order);
|
||||
var response = await UserOrderContract.SubmitShopBuyOrderAsync(request);
|
||||
await Cart.Clear();
|
||||
Snackbar.Add("سفارش با موفقیت ثبت شد.", Severity.Success);
|
||||
Navigation.NavigateTo($"{RouteConstants.Store.OrderDetail}{id}");
|
||||
Navigation.NavigateTo($"{RouteConstants.Store.OrderDetail}{response.Id}");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Snackbar.Add($"خطا در ثبت سفارش: {ex.Message}", Severity.Error);
|
||||
}
|
||||
}
|
||||
|
||||
private static string FormatPrice(long price) => string.Format("{0:N0} تومان", price);
|
||||
|
||||
@@ -24,13 +24,13 @@ else
|
||||
<MudPaper Elevation="2" Class="pa-4 rounded-lg">
|
||||
<MudStack Spacing="2">
|
||||
<MudText Typo="Typo.h5">سفارش #@_order.Id</MudText>
|
||||
<MudText Typo="Typo.body2" Class="mud-text-secondary">تاریخ: @_order.CreatedAt.ToString("yyyy/MM/dd HH:mm")</MudText>
|
||||
<MudText Typo="Typo.body2">وضعیت: @GetStatusText(_order.Status)</MudText>
|
||||
<MudText Typo="Typo.body2">روش پرداخت: کیف پول</MudText>
|
||||
<MudText Typo="Typo.body2">آدرس: @_order.AddressSummary</MudText>
|
||||
<MudText Typo="Typo.body2" Class="mud-text-secondary">تاریخ: @_order.PaymentDate.ToDateTime().MiladiToJalaliWithTime()</MudText>
|
||||
<MudText Typo="Typo.body2">وضعیت: @GetStatusText(_order.PaymentStatus)</MudText>
|
||||
<MudText Typo="Typo.body2">روش پرداخت: @GetPaymentMethodText(_order.PaymentMethod)</MudText>
|
||||
<MudText Typo="Typo.body2">آدرس: @_order.UserAddressText</MudText>
|
||||
<MudDivider Class="my-2" />
|
||||
<MudHidden Breakpoint="Breakpoint.MdAndUp" Invert="true">
|
||||
<MudTable Items="_order.Items">
|
||||
<MudTable Items="_order.FactorDetails">
|
||||
<HeaderContent>
|
||||
<MudTh>محصول</MudTh>
|
||||
<MudTh>قیمت واحد</MudTh>
|
||||
@@ -40,39 +40,39 @@ else
|
||||
<RowTemplate>
|
||||
<MudTd>
|
||||
<MudStack Row="true" Spacing="2" AlignItems="AlignItems.Center">
|
||||
<MudAvatar Image="@context.ImageUrl" Size="Size.Medium" />
|
||||
<MudText>@context.Title</MudText>
|
||||
<MudAvatar Image="@context.ProductThumbnailPath" Size="Size.Medium" />
|
||||
<MudText>@context.ProductTitle</MudText>
|
||||
</MudStack>
|
||||
</MudTd>
|
||||
<MudTd>@FormatPrice(context.UnitPrice)</MudTd>
|
||||
<MudTd>@context.Quantity</MudTd>
|
||||
<MudTd>@FormatPrice(context.LineTotal)</MudTd>
|
||||
<MudTd>@FormatPrice(context.UnitPrice.Value)</MudTd>
|
||||
<MudTd>@context.Count</MudTd>
|
||||
<MudTd>@FormatPrice(context.UnitPrice.Value*context.Count.Value)</MudTd>
|
||||
</RowTemplate>
|
||||
</MudTable>
|
||||
</MudHidden>
|
||||
|
||||
<MudHidden Breakpoint="Breakpoint.MdAndUp">
|
||||
<MudStack Spacing="2">
|
||||
@foreach (var it in _order.Items)
|
||||
@foreach (var it in _order.FactorDetails)
|
||||
{
|
||||
<MudPaper Class="pa-3 rounded-lg" Outlined="true">
|
||||
<MudStack Spacing="1">
|
||||
<MudStack Row="true" Spacing="2" AlignItems="AlignItems.Center">
|
||||
<MudAvatar Image="@it.ImageUrl" />
|
||||
<MudText>@it.Title</MudText>
|
||||
<MudAvatar Image="@it.ProductThumbnailPath" />
|
||||
<MudText>@it.ProductTitle</MudText>
|
||||
</MudStack>
|
||||
<MudStack Row="true" Justify="Justify.SpaceBetween">
|
||||
<MudText Class="mud-text-secondary">@FormatPrice(it.UnitPrice) واحد</MudText>
|
||||
<MudText>تعداد: @it.Quantity</MudText>
|
||||
<MudText Class="mud-text-secondary">@FormatPrice(it.UnitPrice.Value) واحد</MudText>
|
||||
<MudText>تعداد: @it.Count</MudText>
|
||||
</MudStack>
|
||||
<MudText>جمع: @FormatPrice(it.LineTotal)</MudText>
|
||||
<MudText>جمع: @FormatPrice(it.UnitPrice.Value*it.Count.Value)</MudText>
|
||||
</MudStack>
|
||||
</MudPaper>
|
||||
}
|
||||
</MudStack>
|
||||
</MudHidden>
|
||||
<MudDivider Class="my-2" />
|
||||
<MudText Typo="Typo.h6" Align="Align.End">مبلغ کل: @FormatPrice(_order.Total)</MudText>
|
||||
<MudText Typo="Typo.h6" Align="Align.End">مبلغ کل: @FormatPrice(_order.FactorDetails.Sum(s=>s.UnitPrice.Value*s.Count.Value))</MudText>
|
||||
</MudStack>
|
||||
</MudPaper>
|
||||
</MudContainer>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using FrontOffice.BFF.UserOrder.Protobuf.Protos.UserOrder;
|
||||
using FrontOffice.Main.Utilities;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
|
||||
@@ -9,7 +10,7 @@ public partial class OrderDetail : ComponentBase
|
||||
|
||||
[Parameter] public long id { get; set; }
|
||||
|
||||
private Order? _order;
|
||||
private GetUserOrderResponse? _order;
|
||||
private bool _loading;
|
||||
|
||||
protected override async Task OnParametersSetAsync()
|
||||
@@ -20,10 +21,26 @@ public partial class OrderDetail : ComponentBase
|
||||
}
|
||||
|
||||
private static string FormatPrice(long price) => string.Format("{0:N0} تومان", price);
|
||||
private static string GetStatusText(OrderStatus status) => status switch
|
||||
|
||||
private string GetStatusText(PaymentStatus orderPaymentStatus)
|
||||
{
|
||||
OrderStatus.Paid => "پرداختشده",
|
||||
_ => "در انتظار",
|
||||
return orderPaymentStatus switch
|
||||
{
|
||||
PaymentStatus.Pending => "در انتظار پرداخت",
|
||||
PaymentStatus.Success => "پرداخت شده",
|
||||
PaymentStatus.Reject => "پرداخت ناموفق",
|
||||
_ => "نامشخص",
|
||||
};
|
||||
}
|
||||
|
||||
private string GetPaymentMethodText(PaymentMethod orderPaymentMethod)
|
||||
{
|
||||
return orderPaymentMethod switch
|
||||
{
|
||||
PaymentMethod.Wallet => "کیف پول",
|
||||
PaymentMethod.Ipg => "درگاه پرداخت اینترنتی",
|
||||
_ => "نامشخص",
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -28,11 +28,11 @@
|
||||
</HeaderContent>
|
||||
<RowTemplate>
|
||||
<MudTd>@context.Id</MudTd>
|
||||
<MudTd>@context.CreatedAt.ToString("yyyy/MM/dd HH:mm")</MudTd>
|
||||
<MudTd>@GetStatusText(context.Status)</MudTd>
|
||||
<MudTd>@FormatPrice(context.Total)</MudTd>
|
||||
<MudTd>@context.PaymentDate.ToDateTime().MiladiToJalaliWithTime()</MudTd>
|
||||
<MudTd>@GetStatusText(context.PaymentStatus)</MudTd>
|
||||
<MudTd>@FormatPrice(context.FactorDetails.Sum(s=>s.UnitPrice.Value*s.Count.Value))</MudTd>
|
||||
<MudTd>
|
||||
<MudButton Variant="Variant.Text" Href="@($"{RouteConstants.Store.OrderDetail}{context.Id}")" StartIcon="@Icons.Material.Filled.Receipt">جزئیات</MudButton>
|
||||
<MudButton Variant="Variant.Text" Href="@($"{RouteConstants.Store.OrderDetail}{context}")" StartIcon="@Icons.Material.Filled.Receipt">جزئیات</MudButton>
|
||||
</MudTd>
|
||||
</RowTemplate>
|
||||
</MudTable>
|
||||
@@ -46,11 +46,11 @@
|
||||
<MudStack Spacing="1">
|
||||
<MudStack Row="true" Justify="Justify.SpaceBetween">
|
||||
<MudText>سفارش #@o.Id</MudText>
|
||||
<MudText Class="mud-text-secondary">@o.CreatedAt.ToString("yy/MM/dd HH:mm")</MudText>
|
||||
<MudText Class="mud-text-secondary">@o.PaymentDate.ToDateTime().MiladiToJalaliWithTime()</MudText>
|
||||
</MudStack>
|
||||
<MudStack Row="true" Justify="Justify.SpaceBetween">
|
||||
<MudText>وضعیت: @GetStatusText(o.Status)</MudText>
|
||||
<MudText Color="Color.Primary">@FormatPrice(o.Total)</MudText>
|
||||
<MudText>وضعیت: @GetStatusText(o.PaymentStatus)</MudText>
|
||||
<MudText Color="Color.Primary">@FormatPrice(o.FactorDetails.Sum(s=>s.UnitPrice.Value*s.Count.Value)))</MudText>
|
||||
</MudStack>
|
||||
<MudStack Row="true" Justify="Justify.FlexEnd">
|
||||
<MudButton Size="Size.Small" Variant="Variant.Outlined" Href="@($"{RouteConstants.Store.OrderDetail}{o.Id}")" StartIcon="@Icons.Material.Filled.Receipt">جزئیات</MudButton>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using FrontOffice.BFF.UserOrder.Protobuf.Protos.UserOrder;
|
||||
using FrontOffice.Main.Utilities;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
|
||||
@@ -7,7 +8,7 @@ public partial class Orders : ComponentBase
|
||||
{
|
||||
[Inject] private OrderService OrderService { get; set; } = default!;
|
||||
|
||||
private List<Order> _orders = new();
|
||||
private List<GetUserOrderResponse> _orders = new();
|
||||
private bool _loading;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
@@ -18,10 +19,17 @@ public partial class Orders : ComponentBase
|
||||
}
|
||||
|
||||
private static string FormatPrice(long price) => string.Format("{0:N0} تومان", price);
|
||||
private static string GetStatusText(OrderStatus status) => status switch
|
||||
|
||||
|
||||
private string GetStatusText(PaymentStatus contextPaymentStatus)
|
||||
{
|
||||
OrderStatus.Paid => "پرداختشده",
|
||||
_ => "در انتظار",
|
||||
return contextPaymentStatus switch
|
||||
{
|
||||
PaymentStatus.Pending => "در انتظار پرداخت",
|
||||
PaymentStatus.Success => "پرداخت شده",
|
||||
PaymentStatus.Reject => "پرداخت ناموفق",
|
||||
_ => "نامشخص",
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,10 +3,10 @@
|
||||
<PageTitle>کارا بازار سلامت</PageTitle>
|
||||
|
||||
<MudRTLProvider RightToLeft="true">
|
||||
<MudThemeProvider @ref="_mudThemeProvider" Theme="CustomMudTheme.CustomMudBlazorTheme" @bind-IsDarkMode="_isDark" />
|
||||
<MudPopoverProvider />
|
||||
<MudDialogProvider />
|
||||
<MudSnackbarProvider />
|
||||
<MudThemeProvider @ref="_mudThemeProvider" Theme="CustomMudTheme.CustomMudBlazorTheme" @bind-IsDarkMode="_isDark"/>
|
||||
<MudPopoverProvider/>
|
||||
<MudDialogProvider/>
|
||||
<MudSnackbarProvider/>
|
||||
<MudLayout>
|
||||
<!-- AppBar -->
|
||||
<MudAppBar Elevation="0" Color="Color.Transparent" Dense="true" Class="py-2" id="top">
|
||||
@@ -15,7 +15,7 @@
|
||||
<MudHidden Breakpoint="Breakpoint.SmAndUp">
|
||||
<MudIconButton Class="d-inline"
|
||||
Icon="@Icons.Material.Filled.Menu"
|
||||
OnClick="@ToggleDrawer" />
|
||||
OnClick="@ToggleDrawer"/>
|
||||
</MudHidden>
|
||||
|
||||
<div class="d-flex align-center gap-2">
|
||||
@@ -27,74 +27,106 @@
|
||||
Width="32"
|
||||
Height="32"
|
||||
Class="rounded-circle"
|
||||
Src="favicon.png" />
|
||||
Src="favicon.png"/>
|
||||
</MudHidden>
|
||||
<MudText Typo="Typo.h6" >کارا بازار سلامت</MudText>
|
||||
<MudText Typo="Typo.h6">کارا بازار سلامت</MudText>
|
||||
</MudStack>
|
||||
</MudLink>
|
||||
</div>
|
||||
|
||||
<div class="d-none d-md-flex align-center gap-10">
|
||||
@* @if (_isAuthenticated && false) *@
|
||||
@* { *@
|
||||
@* <MudLink Href="@(RouteConstants.Store.Products)" Typo="Typo.subtitle1" Class="mud-link">محصولات</MudLink> *@
|
||||
@* <MudLink Href="@(RouteConstants.Store.Cart)" Typo="Typo.subtitle1" Class="mud-link">سبد خرید</MudLink> *@
|
||||
@* <MudLink Href="@(RouteConstants.Store.Orders)" Typo="Typo.subtitle1" Class="mud-link">سفارشات من</MudLink> *@
|
||||
@* } *@
|
||||
<MudLink Href="@(RouteConstants.FAQ.Index)" Typo="Typo.subtitle1" Class="mud-link">سوالات متداول</MudLink>
|
||||
<MudLink Href="@(RouteConstants.Contact.Index)" Typo="Typo.subtitle1" Class="mud-link">ارتباط با ما</MudLink>
|
||||
<MudLink Href="@(RouteConstants.About.Index)" Typo="Typo.subtitle1" Class="mud-link">درباره ما</MudLink>
|
||||
@if (_isAuthenticated)
|
||||
{
|
||||
<MudLink Href="@(RouteConstants.Store.Products)" Typo="Typo.subtitle1" Class="mud-link">
|
||||
محصولات
|
||||
</MudLink>
|
||||
<MudLink Href="@(RouteConstants.Store.Cart)" Typo="Typo.subtitle1" Class="mud-link">سبد خرید
|
||||
</MudLink>
|
||||
<MudLink Href="@(RouteConstants.Store.Orders)" Typo="Typo.subtitle1" Class="mud-link">سفارشات
|
||||
من
|
||||
</MudLink>
|
||||
}
|
||||
<MudLink Href="@(RouteConstants.FAQ.Index)" Typo="Typo.subtitle1" Class="mud-link">سوالات متداول
|
||||
</MudLink>
|
||||
<MudLink Href="@(RouteConstants.Contact.Index)" Typo="Typo.subtitle1" Class="mud-link">ارتباط با
|
||||
ما
|
||||
</MudLink>
|
||||
<MudLink Href="@(RouteConstants.About.Index)" Typo="Typo.subtitle1" Class="mud-link">درباره ما
|
||||
</MudLink>
|
||||
</div>
|
||||
|
||||
<div class="d-flex align-center gap-2">
|
||||
@if (_isAuthenticated)
|
||||
{
|
||||
<MudMenu Icon="@Icons.Material.Filled.Person" Color="Color.Inherit" Size="Size.Medium">
|
||||
<MudMenuItem OnClick="NavigateToProfile" Disabled="@(!AuthService.IsCompleteRegister())">پروفایل</MudMenuItem>
|
||||
<MudDivider />
|
||||
<MudMenuItem OnClick="NavigateToProfile" Disabled="@(!AuthService.IsCompleteRegister())">
|
||||
پروفایل
|
||||
</MudMenuItem>
|
||||
<MudDivider/>
|
||||
<MudMenuItem OnClick="Logout">خروج از حساب</MudMenuItem>
|
||||
</MudMenu>
|
||||
}
|
||||
else
|
||||
{
|
||||
<MudIconButton Icon="@Icons.Material.Filled.Login" Color="Color.Inherit" OnClick="OpenAuthDialog" />
|
||||
<MudIconButton Icon="@Icons.Material.Filled.Login" Color="Color.Inherit"
|
||||
OnClick="OpenAuthDialog"/>
|
||||
}
|
||||
|
||||
<MudIconButton OnClick="@ToggleTheme" Edge="Edge.End"
|
||||
Icon="@(_isDark ? Icons.Material.Filled.DarkMode : Icons.Material.Filled.LightMode)" />
|
||||
Icon="@(_isDark ? Icons.Material.Filled.DarkMode : Icons.Material.Filled.LightMode)"/>
|
||||
</div>
|
||||
</MudContainer>
|
||||
</MudAppBar>
|
||||
|
||||
<!-- Mobile Drawer -->
|
||||
<MudDrawer @bind-Open="_drawerOpen" Anchor="Anchor.Right" Elevation="1" Variant="DrawerVariant.Temporary" Class="pa-4">
|
||||
<MudDrawer @bind-Open="_drawerOpen" Anchor="Anchor.Right" Elevation="1" Variant="DrawerVariant.Temporary"
|
||||
Class="pa-4">
|
||||
<MudStack Spacing="2">
|
||||
@* @if (_isAuthenticated) *@
|
||||
@* { *@
|
||||
@* <MudLink Href="@(RouteConstants.Store.Products)" Typo="Typo.subtitle1" OnClick="() => _drawerOpen=false">محصولات</MudLink> *@
|
||||
@* <MudLink Href="@(RouteConstants.Store.Cart)" Typo="Typo.subtitle1" OnClick="() => _drawerOpen=false">سبد خرید</MudLink> *@
|
||||
@* <MudLink Href="@(RouteConstants.Store.Orders)" Typo="Typo.subtitle1" OnClick="() => _drawerOpen=false">سفارشات من</MudLink> *@
|
||||
@* } *@
|
||||
<MudLink Href="@(RouteConstants.FAQ.Index)" Typo="Typo.subtitle1" OnClick="() => _drawerOpen=false">سوالات متداول</MudLink>
|
||||
<MudLink Href="@(RouteConstants.About.Index)" Typo="Typo.subtitle1" OnClick="() => _drawerOpen=false">درباره ما</MudLink>
|
||||
<MudLink Href="@(RouteConstants.Contact.Index)" Typo="Typo.subtitle1" OnClick="() => _drawerOpen=false">ارتباط با ما</MudLink>
|
||||
|
||||
<MudDivider Class="my-2" />
|
||||
@if (_isAuthenticated)
|
||||
{
|
||||
<MudButton Href="/profile" Color="Color.Primary" OnClick="() => _drawerOpen=false">پروفایل</MudButton>
|
||||
<MudButton Variant="Variant.Text" Color="Color.Error" OnClick="() => { _drawerOpen=false; Logout(); }">خروج از حساب</MudButton>
|
||||
<MudLink Href="@(RouteConstants.Store.Products)" Typo="Typo.subtitle1"
|
||||
OnClick="() => _drawerOpen=false">محصولات
|
||||
</MudLink>
|
||||
<MudLink Href="@(RouteConstants.Store.Cart)" Typo="Typo.subtitle1"
|
||||
OnClick="() => _drawerOpen=false">سبد خرید
|
||||
</MudLink>
|
||||
<MudLink Href="@(RouteConstants.Store.Orders)" Typo="Typo.subtitle1"
|
||||
OnClick="() => _drawerOpen=false">سفارشات من
|
||||
</MudLink>
|
||||
}
|
||||
<MudLink Href="@(RouteConstants.FAQ.Index)" Typo="Typo.subtitle1" OnClick="() => _drawerOpen=false">
|
||||
سوالات متداول
|
||||
</MudLink>
|
||||
<MudLink Href="@(RouteConstants.About.Index)" Typo="Typo.subtitle1" OnClick="() => _drawerOpen=false">
|
||||
درباره ما
|
||||
</MudLink>
|
||||
<MudLink Href="@(RouteConstants.Contact.Index)" Typo="Typo.subtitle1" OnClick="() => _drawerOpen=false">
|
||||
ارتباط با ما
|
||||
</MudLink>
|
||||
|
||||
<MudDivider Class="my-2"/>
|
||||
@if (_isAuthenticated)
|
||||
{
|
||||
<MudButton Href="/profile" Color="Color.Primary" OnClick="() => _drawerOpen=false">پروفایل
|
||||
</MudButton>
|
||||
<MudButton Variant="Variant.Text" Color="Color.Error"
|
||||
OnClick="() => { _drawerOpen=false; Logout(); }">خروج از حساب
|
||||
</MudButton>
|
||||
}
|
||||
else
|
||||
{
|
||||
<MudButton Color="Color.Primary" OnClick="() => { _drawerOpen=false; OpenAuthDialog(); }">ورود</MudButton>
|
||||
<MudButton Color="Color.Primary" OnClick="() => { _drawerOpen=false; OpenAuthDialog(); }">ورود
|
||||
</MudButton>
|
||||
}
|
||||
</MudStack>
|
||||
</MudDrawer>
|
||||
|
||||
<MudMainContent>
|
||||
@Body
|
||||
<Footer />
|
||||
@if (DeviceDetector.IsDesktop())
|
||||
{
|
||||
<Footer/>
|
||||
}
|
||||
</MudMainContent>
|
||||
|
||||
</MudLayout>
|
||||
|
||||
@@ -1,11 +1,16 @@
|
||||
using DateTimeConverterCL;
|
||||
using FrontOffice.BFF.ShopingCart.Protobuf.Protos.ShopingCart;
|
||||
using Google.Protobuf.WellKnownTypes;
|
||||
|
||||
namespace FrontOffice.Main.Utilities;
|
||||
|
||||
public record CartItem(long ProductId, string Title, string ImageUrl, long UnitPrice, int Quantity)
|
||||
public record CartItem(long cartId,long ProductId, string Title, string ImageUrl, long UnitPrice, int Quantity)
|
||||
{
|
||||
public long LineTotal => UnitPrice * Quantity;
|
||||
public long DiscountValue => (Discount*(UnitPrice * Quantity))/100;
|
||||
public int Discount { get; init; }
|
||||
public string Created { get; init; } = string.Empty;
|
||||
public string Description { get; init; } = string.Empty;
|
||||
}
|
||||
|
||||
public class CartService
|
||||
@@ -22,30 +27,52 @@ public class CartService
|
||||
|
||||
public IReadOnlyList<CartItem> Items => _items.AsReadOnly();
|
||||
public long Total => _items.Sum(i => i.LineTotal);
|
||||
public long TotalDiscount => _items.Sum(i => i.DiscountValue);
|
||||
public int Count => _items.Sum(i => i.Quantity);
|
||||
|
||||
public async Task Add(Product product, int quantity = 1)
|
||||
{
|
||||
if (quantity <= 0) return;
|
||||
var existing = _items.FirstOrDefault(i => i.ProductId == product.Id);
|
||||
int newQuantity;
|
||||
|
||||
if (existing is null)
|
||||
{
|
||||
_items.Add(new CartItem(product.Id, product.Title, product.ImageUrl, product.Price, quantity));
|
||||
newQuantity = quantity;
|
||||
_items.Add(new CartItem(0,product.Id, product.Title, product.ImageUrl, product.Price, newQuantity)
|
||||
{
|
||||
Discount = product.Discount,
|
||||
Created = DateTime.Now.MiladiToJalali(),
|
||||
Description = product.Description
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
var idx = _items.IndexOf(existing);
|
||||
_items[idx] = existing with { Quantity = existing.Quantity + quantity };
|
||||
newQuantity = existing.Quantity + quantity;
|
||||
_items[idx] = existing with { Quantity = newQuantity };
|
||||
}
|
||||
Notify();
|
||||
|
||||
try
|
||||
{
|
||||
if (existing is null)
|
||||
{
|
||||
await _client.AddNewUserCartAsync(new AddNewUserCartRequest
|
||||
{
|
||||
ProductId = product.Id,
|
||||
Count = quantity
|
||||
Count = newQuantity
|
||||
});
|
||||
await LoadFromServerAsync();
|
||||
}
|
||||
else
|
||||
{
|
||||
await _client.UpdateUserCartAsync(new UpdateUserCartRequest
|
||||
{
|
||||
UserCartId = existing.cartId,
|
||||
Count = newQuantity
|
||||
});
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
@@ -59,7 +86,7 @@ public class CartService
|
||||
if (existing is null) return;
|
||||
if (quantity <= 0)
|
||||
{
|
||||
Remove(productId);
|
||||
Remove(existing.cartId);
|
||||
return;
|
||||
}
|
||||
var idx = _items.IndexOf(existing);
|
||||
@@ -70,7 +97,7 @@ public class CartService
|
||||
{
|
||||
await _client.UpdateUserCartAsync(new UpdateUserCartRequest
|
||||
{
|
||||
UserCartId = productId,
|
||||
UserCartId = existing.cartId,
|
||||
Count = quantity
|
||||
});
|
||||
}
|
||||
@@ -80,9 +107,9 @@ public class CartService
|
||||
}
|
||||
}
|
||||
|
||||
public async Task Remove(long productId)
|
||||
public async Task Remove(long cartId)
|
||||
{
|
||||
_items.RemoveAll(i => i.ProductId == productId);
|
||||
_items.RemoveAll(i => i.cartId == cartId);
|
||||
Notify();
|
||||
|
||||
try
|
||||
@@ -90,7 +117,7 @@ public class CartService
|
||||
// Interpret Count=0 as remove from cart
|
||||
await _client.UpdateUserCartAsync(new UpdateUserCartRequest
|
||||
{
|
||||
UserCartId = productId,
|
||||
UserCartId = cartId,
|
||||
Count = 0
|
||||
});
|
||||
}
|
||||
@@ -131,14 +158,20 @@ public class CartService
|
||||
{
|
||||
var response = await _client.GetAllUserCartAsync(new Empty());
|
||||
_items.Clear();
|
||||
foreach (var m in response.Models)
|
||||
foreach (var model in response.Models)
|
||||
{
|
||||
var item = new CartItem(
|
||||
ProductId: m.Id,
|
||||
Title: m.Title ?? string.Empty,
|
||||
ImageUrl: string.IsNullOrWhiteSpace(m.ImagePath) ? string.Empty : UrlUtility.DownloadUrl + m.ImagePath,
|
||||
UnitPrice: m.Price,
|
||||
Quantity: m.SaleCount > 0 ? m.SaleCount : 1);
|
||||
cartId:model.Id,
|
||||
ProductId: model.ProductId,
|
||||
Title: model.ProductTitle ?? string.Empty,
|
||||
ImageUrl: string.IsNullOrWhiteSpace(model.ProductThumbnailPath) ? string.Empty : UrlUtility.DownloadUrl + model.ProductThumbnailPath,
|
||||
UnitPrice: model.ProductPrice,
|
||||
Quantity: model.Count > 0 ? model.Count : 1)
|
||||
{
|
||||
Discount = model.ProductDiscount,
|
||||
Created = model.Created.ToDateTime().MiladiToJalali(),
|
||||
Description = model.ProductShortInfomation
|
||||
};
|
||||
_items.Add(item);
|
||||
}
|
||||
Notify();
|
||||
|
||||
@@ -1,47 +1,64 @@
|
||||
using FrontOffice.BFF.UserOrder.Protobuf.Protos.UserOrder;
|
||||
|
||||
namespace FrontOffice.Main.Utilities;
|
||||
|
||||
public enum PaymentMethod
|
||||
{
|
||||
Wallet = 1,
|
||||
}
|
||||
// public enum PaymentMethod
|
||||
// {
|
||||
// Wallet = 1,
|
||||
// }
|
||||
//
|
||||
// public enum OrderStatus
|
||||
// {
|
||||
// Pending = 0,
|
||||
// Paid = 1,
|
||||
// }
|
||||
|
||||
public enum OrderStatus
|
||||
{
|
||||
Pending = 0,
|
||||
Paid = 1,
|
||||
}
|
||||
|
||||
public record OrderItem(long ProductId, string Title, string ImageUrl, long UnitPrice, int Quantity)
|
||||
{
|
||||
public long LineTotal => UnitPrice * Quantity;
|
||||
}
|
||||
|
||||
public class Order
|
||||
{
|
||||
public long Id { get; set; }
|
||||
public DateTime CreatedAt { get; set; } = DateTime.Now;
|
||||
public OrderStatus Status { get; set; } = OrderStatus.Pending;
|
||||
public PaymentMethod PaymentMethod { get; set; } = PaymentMethod.Wallet;
|
||||
public long AddressId { get; set; }
|
||||
public string AddressSummary { get; set; } = string.Empty;
|
||||
public List<OrderItem> Items { get; set; } = new();
|
||||
public long Total => Items.Sum(i => i.LineTotal);
|
||||
}
|
||||
// public record OrderItem(long ProductId, string Title, string ImageUrl, long UnitPrice, int Quantity)
|
||||
// {
|
||||
// public long LineTotal => UnitPrice * Quantity;
|
||||
// }
|
||||
//
|
||||
// public class Order
|
||||
// {
|
||||
// public long Id { get; set; }
|
||||
// public DateTime CreatedAt { get; set; } = DateTime.Now;
|
||||
// public OrderStatus Status { get; set; } = OrderStatus.Pending;
|
||||
// public PaymentMethod PaymentMethod { get; set; } = PaymentMethod.Wallet;
|
||||
// public long AddressId { get; set; }
|
||||
// public string AddressSummary { get; set; } = string.Empty;
|
||||
// public List<OrderItem> Items { get; set; } = new();
|
||||
// public long Total => Items.Sum(i => i.LineTotal);
|
||||
// }
|
||||
|
||||
public class OrderService
|
||||
{
|
||||
private long _seq = 1000;
|
||||
private readonly List<Order> _orders = new();
|
||||
private readonly List<GetUserOrderResponse> _orders = new();
|
||||
private readonly UserOrderContract.UserOrderContractClient _userOrderContractClient;
|
||||
|
||||
public Task<List<Order>> GetOrdersAsync() => Task.FromResult(_orders.OrderByDescending(o => o.CreatedAt).ToList());
|
||||
|
||||
public Task<Order?> GetOrderAsync(long id) => Task.FromResult(_orders.FirstOrDefault(o => o.Id == id));
|
||||
|
||||
public Task<long> CreateOrderAsync(Order order)
|
||||
public OrderService(UserOrderContract.UserOrderContractClient userOrderContractClient)
|
||||
{
|
||||
order.Id = Interlocked.Increment(ref _seq);
|
||||
_orders.Add(order);
|
||||
return Task.FromResult(order.Id);
|
||||
_userOrderContractClient = userOrderContractClient;
|
||||
}
|
||||
|
||||
public Task<List<GetUserOrderResponse>> GetOrdersAsync()
|
||||
{
|
||||
return Task.FromResult(_orders.OrderByDescending(o => o.PaymentDate).ToList());
|
||||
}
|
||||
|
||||
public async Task<GetUserOrderResponse?> GetOrderAsync(long id)
|
||||
{
|
||||
var order = _orders.FirstOrDefault(o => o.Id == id);
|
||||
if (order == null)
|
||||
{
|
||||
var result = await _userOrderContractClient.GetUserOrderAsync(new GetUserOrderRequest()
|
||||
{
|
||||
Id = id
|
||||
});
|
||||
_orders.Add(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
return order;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,15 @@ using FrontOffice.BFF.Products.Protobuf.Protos.Products;
|
||||
|
||||
namespace FrontOffice.Main.Utilities;
|
||||
|
||||
public record Product(long Id, string Title, string Description, string ImageUrl, long Price);
|
||||
public record Product(
|
||||
long Id,
|
||||
string Title,
|
||||
string Description,
|
||||
string ImageUrl,
|
||||
long Price,
|
||||
int Discount = 0,
|
||||
int Rate = 0,
|
||||
int RemainingCount = 0);
|
||||
|
||||
public class ProductService
|
||||
{
|
||||
@@ -81,7 +89,10 @@ public class ProductService
|
||||
Title: m.Title ?? string.Empty,
|
||||
Description: m.Description ?? string.Empty,
|
||||
ImageUrl: string.IsNullOrWhiteSpace(m.ImagePath) ? string.Empty : UrlUtility.DownloadUrl + m.ImagePath,
|
||||
Price: m.Price
|
||||
Price: m.Price,
|
||||
Discount: m.Discount,
|
||||
Rate: m.Rate,
|
||||
RemainingCount: m.RemainingCount
|
||||
);
|
||||
_cache[p.Id] = p;
|
||||
list.Add(p);
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
using FrontOffice.BFF.UserWallet.Protobuf.Protos.UserWallet;
|
||||
using Google.Protobuf.WellKnownTypes;
|
||||
|
||||
namespace FrontOffice.Main.Utilities;
|
||||
|
||||
public record WalletBalances(long CreditBalance, long NetworkBalance);
|
||||
@@ -5,16 +8,48 @@ public record WalletTransaction(DateTime Date, long Amount, string Channel, stri
|
||||
|
||||
public class WalletService
|
||||
{
|
||||
private WalletBalances _balances = new(0, 0);
|
||||
private readonly List<WalletTransaction> _transactions = new()
|
||||
{
|
||||
// new(DateTime.Now.AddDays(-1), 500_000, "درگاه بانکی", "شارژ کیف پول"),
|
||||
// new(DateTime.Now.AddDays(-2), 200_000, "شبکه/معرف", "پاداش شبکه"),
|
||||
// new(DateTime.Now.AddDays(-4), -120_000, "خرید", "برداشت بابت سفارش #1452"),
|
||||
// new(DateTime.Now.AddDays(-9), 900_000, "کیف پول شرکای تجاری", "اعتبار خرید"),
|
||||
};
|
||||
private readonly UserWalletContract.UserWalletContractClient _client;
|
||||
|
||||
public Task<WalletBalances> GetBalancesAsync() => Task.FromResult(_balances);
|
||||
public Task<List<WalletTransaction>> GetTransactionsAsync() => Task.FromResult(_transactions.OrderByDescending(t => t.Date).ToList());
|
||||
public WalletService(UserWalletContract.UserWalletContractClient client)
|
||||
{
|
||||
_client = client;
|
||||
}
|
||||
|
||||
public async Task<WalletBalances> GetBalancesAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
var response = await _client.GetUserWalletAsync(new Empty());
|
||||
return new WalletBalances(response.Balance, response.NetworkBalance);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Fallback to mock data if backend is unavailable
|
||||
return new WalletBalances(350_000, 1_250_000);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<List<WalletTransaction>> GetTransactionsAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
var response = await _client.GetAllUserWalletChangeLogAsync(new Empty());
|
||||
return response.Models.Select(t => new WalletTransaction(DateTime.Now, t.CurrentBalance,t.RefrenceId.Value.ToString(),t.IsIncrease?"شارژ کیف پول":"برداشت از کیف پول")
|
||||
|
||||
).ToList();
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Fallback to mock data if backend is unavailable
|
||||
var _transactions = new List<WalletTransaction>
|
||||
{
|
||||
new(DateTime.Now.AddDays(-1), 500_000, "درگاه بانکی", "شارژ کیف پول"),
|
||||
new(DateTime.Now.AddDays(-2), 200_000, "شبکه/معرف", "پاداش شبکه"),
|
||||
new(DateTime.Now.AddDays(-4), -120_000, "خرید", "برداشت بابت سفارش #1452"),
|
||||
new(DateTime.Now.AddDays(-9), 900_000, "کیف پول شرکای تجاری", "اعتبار خرید"),
|
||||
};
|
||||
return _transactions.OrderByDescending(t => t.Date).ToList();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -18,3 +18,5 @@
|
||||
@inject IJSRuntime JSRuntime
|
||||
@inject ISnackbar Snackbar
|
||||
@inject MainService MainService
|
||||
@inject IDeviceDetector DeviceDetector
|
||||
@inject WalletService WalletService
|
||||
@@ -1,7 +1,7 @@
|
||||
نمونه قرارداد همکاری
|
||||
---------------------
|
||||
|
||||
این فایل صرفاً نمونهای برای نمایش قابلیت دانلود قرارداد در ویزارد ثبتنام است.
|
||||
این فایل صرفاً نمونهای برای نمایش قابلیت دانلود قرارداد در مراحل ثبتنام است.
|
||||
|
||||
بند ۱- اطلاعات شخص حقیقی: شامل نام، نام خانوادگی، کد ملی و شماره تماس متقاضی است.
|
||||
بند ۲- تعهدات طرفین: متقاضی متعهد میشود قوانین حاکم بر پلتفرم را رعایت نموده و اطلاعات صحیح ارائه نماید.
|
||||
|
||||
Reference in New Issue
Block a user