Merge branch 'main' into kub-stage
# Conflicts: # .gitea/workflows/kub-deploy.yml
This commit is contained in:
25
src/.dockerignore
Normal file
25
src/.dockerignore
Normal file
@@ -0,0 +1,25 @@
|
||||
**/.dockerignore
|
||||
**/.env
|
||||
**/.git
|
||||
**/.gitignore
|
||||
**/.project
|
||||
**/.settings
|
||||
**/.toolstarget
|
||||
**/.vs
|
||||
**/.vscode
|
||||
**/.idea
|
||||
**/*.*proj.user
|
||||
**/*.dbmdl
|
||||
**/*.jfm
|
||||
**/azds.yaml
|
||||
**/bin
|
||||
**/charts
|
||||
**/docker-compose*
|
||||
**/Dockerfile*
|
||||
**/node_modules
|
||||
**/npm-debug.log
|
||||
**/obj
|
||||
**/secrets.dev.yaml
|
||||
**/values.dev.yaml
|
||||
LICENSE
|
||||
README.md
|
||||
@@ -51,6 +51,8 @@ public static class ConfigureServices
|
||||
services.AddScoped<CategoryService>();
|
||||
services.AddScoped<OrderService>();
|
||||
services.AddScoped<WalletService>();
|
||||
// Package service
|
||||
services.AddScoped<PackageService>();
|
||||
// New services for Club, Network, Commission
|
||||
services.AddScoped<ClubMembershipService>();
|
||||
services.AddScoped<NetworkMembershipService>();
|
||||
|
||||
24
src/FrontOffice.Main/Dockerfile
Normal file
24
src/FrontOffice.Main/Dockerfile
Normal file
@@ -0,0 +1,24 @@
|
||||
FROM mcr.microsoft.com/dotnet/aspnet:9.0 AS base
|
||||
USER $APP_UID
|
||||
WORKDIR /app
|
||||
EXPOSE 8080
|
||||
EXPOSE 8081
|
||||
|
||||
FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build
|
||||
ARG BUILD_CONFIGURATION=Release
|
||||
WORKDIR /src
|
||||
COPY ["FrontOffice.Main/NuGet.config", "NuGet.config"]
|
||||
COPY ["FrontOffice.Main/FrontOffice.Main.csproj", "FrontOffice.Main/"]
|
||||
RUN dotnet restore "FrontOffice.Main/FrontOffice.Main.csproj" --configfile NuGet.config
|
||||
COPY . .
|
||||
WORKDIR "/src/FrontOffice.Main"
|
||||
RUN dotnet build "./FrontOffice.Main.csproj" -c $BUILD_CONFIGURATION -o /app/build
|
||||
|
||||
FROM build AS publish
|
||||
ARG BUILD_CONFIGURATION=Release
|
||||
RUN dotnet publish "./FrontOffice.Main.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false
|
||||
|
||||
FROM base AS final
|
||||
WORKDIR /app
|
||||
COPY --from=publish /app/publish .
|
||||
ENTRYPOINT ["dotnet", "FrontOffice.Main.dll"]
|
||||
@@ -5,18 +5,24 @@
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<UserSecretsId>6dab807c-c6d8-4711-bf64-11c69e8d39f4</UserSecretsId>
|
||||
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="DateTimeConverterCL" Version="1.0.0" />
|
||||
<PackageReference Include="Foursat.FrontOffice.BFF.Package.Protobuf" Version="0.0.112" />
|
||||
<PackageReference Include="Foursat.FrontOffice.BFF.Products.Protobuf" Version="0.0.15" />
|
||||
<PackageReference Include="Foursat.FrontOffice.BFF.Transaction.Protobuf" Version="0.0.111" />
|
||||
<PackageReference Include="Foursat.FrontOffice.BFF.Category.Protobuf" Version="0.0.12" />
|
||||
<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.114" />
|
||||
<PackageReference Include="Foursat.FrontOffice.BFF.ShopingCart.Protobuf" Version="0.0.15" />
|
||||
<PackageReference Include="Foursat.FrontOffice.BFF.ClubMembership.Protobuf" Version="0.0.3" />
|
||||
<PackageReference Include="Foursat.FrontOffice.BFF.Commission.Protobuf" Version="0.0.2" />
|
||||
<PackageReference Include="Foursat.FrontOffice.BFF.DiscountShop.Protobuf" Version="0.0.2" />
|
||||
<PackageReference Include="Foursat.FrontOffice.BFF.NetworkMembership.Protobuf" Version="0.0.2" />
|
||||
<PackageReference Include="Foursat.FrontOffice.BFF.Package.Protobuf" Version="0.0.113" />
|
||||
<PackageReference Include="Foursat.FrontOffice.BFF.Products.Protobuf" Version="0.0.17" />
|
||||
<PackageReference Include="Foursat.FrontOffice.BFF.Transaction.Protobuf" Version="0.0.112" />
|
||||
<PackageReference Include="Foursat.FrontOffice.BFF.Category.Protobuf" Version="0.0.13" />
|
||||
<PackageReference Include="Foursat.FrontOffice.BFF.User.Protobuf" Version="0.0.117" />
|
||||
<PackageReference Include="Foursat.FrontOffice.BFF.UserAddress.Protobuf" Version="0.0.115" />
|
||||
<PackageReference Include="Foursat.FrontOffice.BFF.UserOrder.Protobuf" Version="0.0.115" />
|
||||
<PackageReference Include="Foursat.FrontOffice.BFF.ShopingCart.Protobuf" Version="0.0.16" />
|
||||
<PackageReference Include="Foursat.FrontOffice.BFF.UserWallet.Protobuf" Version="0.0.15" />
|
||||
<!-- UserWallet moved to ProjectReference for latest proto -->
|
||||
<PackageReference Include="MudBlazor" Version="8.14.0" />
|
||||
<PackageReference Include="Blazored.LocalStorage" Version="4.5.0" />
|
||||
@@ -29,17 +35,24 @@
|
||||
</ItemGroup>
|
||||
|
||||
<!-- New Proto Projects (local references until NuGet publish) -->
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\FrontOffice.BFF\src\Protobufs\FrontOffice.BFF.ClubMembership.Protobuf\FrontOffice.BFF.ClubMembership.Protobuf.csproj" />
|
||||
<ProjectReference Include="..\..\..\FrontOffice.BFF\src\Protobufs\FrontOffice.BFF.Commission.Protobuf\FrontOffice.BFF.Commission.Protobuf.csproj" />
|
||||
<ProjectReference Include="..\..\..\FrontOffice.BFF\src\Protobufs\FrontOffice.BFF.NetworkMembership.Protobuf\FrontOffice.BFF.NetworkMembership.Protobuf.csproj" />
|
||||
<ProjectReference Include="..\..\..\FrontOffice.BFF\src\Protobufs\FrontOffice.BFF.DiscountShop.Protobuf\FrontOffice.BFF.DiscountShop.Protobuf.csproj" />
|
||||
<ProjectReference Include="..\..\..\FrontOffice.BFF\src\Protobufs\FrontOffice.BFF.UserWallet.Protobuf\FrontOffice.BFF.UserWallet.Protobuf.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<!-- <ItemGroup>-->
|
||||
<!-- <ProjectReference Include="..\..\..\FrontOffice.BFF\src\Protobufs\FrontOffice.BFF.ClubMembership.Protobuf\FrontOffice.BFF.ClubMembership.Protobuf.csproj" />-->
|
||||
<!-- <ProjectReference Include="..\..\..\FrontOffice.BFF\src\Protobufs\FrontOffice.BFF.Commission.Protobuf\FrontOffice.BFF.Commission.Protobuf.csproj" />-->
|
||||
<!-- <ProjectReference Include="..\..\..\FrontOffice.BFF\src\Protobufs\FrontOffice.BFF.NetworkMembership.Protobuf\FrontOffice.BFF.NetworkMembership.Protobuf.csproj" />-->
|
||||
<!-- <ProjectReference Include="..\..\..\FrontOffice.BFF\src\Protobufs\FrontOffice.BFF.DiscountShop.Protobuf\FrontOffice.BFF.DiscountShop.Protobuf.csproj" />-->
|
||||
<!-- <ProjectReference Include="..\..\..\FrontOffice.BFF\src\Protobufs\FrontOffice.BFF.UserWallet.Protobuf\FrontOffice.BFF.UserWallet.Protobuf.csproj" />-->
|
||||
<!-- </ItemGroup>-->
|
||||
<!-- -->
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Components" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
<ItemGroup>
|
||||
<Content Include="..\.dockerignore">
|
||||
<Link>.dockerignore</Link>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
18
src/FrontOffice.Main/NuGet.config
Normal file
18
src/FrontOffice.Main/NuGet.config
Normal file
@@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
<packageSources>
|
||||
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" protocolVersion="3" />
|
||||
<add key="FourSat" value="https://git.afrino.co/api/packages/FourSat/nuget/index.json" />
|
||||
<add key="Afrino" value="https://git.afrino.co/api/packages/Afrino/nuget/index.json" />
|
||||
</packageSources>
|
||||
<packageSourceCredentials>
|
||||
<FourSat>
|
||||
<add key="Username" value="masoud" />
|
||||
<add key="ClearTextPassword" value="87zH26nbqT" />
|
||||
</FourSat>
|
||||
<Afrino>
|
||||
<add key="Username" value="systemuser" />
|
||||
<add key="ClearTextPassword" value="sZSA7PTiv3pUSQZ" />
|
||||
</Afrino>
|
||||
</packageSourceCredentials>
|
||||
</configuration>
|
||||
201
src/FrontOffice.Main/Pages/Package/MyPackages.razor
Normal file
201
src/FrontOffice.Main/Pages/Package/MyPackages.razor
Normal file
@@ -0,0 +1,201 @@
|
||||
@attribute [Route(RouteConstants.Package.MyPackages)]
|
||||
|
||||
<PageTitle>پکیجهای من</PageTitle>
|
||||
|
||||
<MudContainer MaxWidth="MaxWidth.Large" Class="py-8">
|
||||
<!-- Breadcrumb -->
|
||||
<MudBreadcrumbs Items="_breadcrumbItems" Class="mb-4" />
|
||||
|
||||
<!-- Header -->
|
||||
<MudStack Class="mb-6">
|
||||
<MudText Typo="Typo.h4">پکیجهای من</MudText>
|
||||
<MudText Typo="Typo.body1" Class="mud-text-secondary">
|
||||
وضعیت پکیجهای خریداری شده و عضویت باشگاه مشتریان
|
||||
</MudText>
|
||||
</MudStack>
|
||||
|
||||
@if (_isLoading)
|
||||
{
|
||||
<MudStack AlignItems="AlignItems.Center" Class="py-16">
|
||||
<MudProgressCircular Color="Color.Primary" Indeterminate="true" Size="Size.Large" />
|
||||
<MudText Typo="Typo.body1" Class="mud-text-secondary mt-2">در حال بارگذاری...</MudText>
|
||||
</MudStack>
|
||||
}
|
||||
else if (_userStatus == null || !_userStatus.HasPurchasedPackage)
|
||||
{
|
||||
<!-- No Package Purchased -->
|
||||
<MudPaper Elevation="2" Class="pa-8 text-center">
|
||||
<MudStack AlignItems="AlignItems.Center" Spacing="4">
|
||||
<MudIcon Icon="@Icons.Material.Filled.CardGiftcard" Size="Size.Large" Color="Color.Primary" Style="font-size: 80px;" />
|
||||
<MudText Typo="Typo.h5">شما هنوز پکیجی خریداری نکردهاید</MudText>
|
||||
<MudText Typo="Typo.body1" Class="mud-text-secondary" Style="max-width: 500px;">
|
||||
با خرید پکیج طلایی، به باشگاه مشتریان بپیوندید و از مزایای ویژه مانند کمیسیون هفتگی و شبکهسازی بهرهمند شوید.
|
||||
</MudText>
|
||||
<MudButton Variant="Variant.Filled"
|
||||
Color="Color.Primary"
|
||||
Size="Size.Large"
|
||||
StartIcon="@Icons.Material.Filled.ShoppingCart"
|
||||
OnClick="@(() => Navigation.NavigateTo(RouteConstants.Package.List))">
|
||||
مشاهده پکیجها
|
||||
</MudButton>
|
||||
</MudStack>
|
||||
</MudPaper>
|
||||
}
|
||||
else
|
||||
{
|
||||
<MudGrid Spacing="4">
|
||||
<!-- Package Status Card -->
|
||||
<MudItem xs="12" md="6">
|
||||
<MudPaper Elevation="2" Class="pa-6 h-100">
|
||||
<MudStack Spacing="3">
|
||||
<MudStack Row="true" AlignItems="AlignItems.Center" Spacing="2">
|
||||
<MudIcon Icon="@Icons.Material.Filled.Inventory2" Color="Color.Primary" />
|
||||
<MudText Typo="Typo.h6">وضعیت پکیج</MudText>
|
||||
</MudStack>
|
||||
|
||||
<MudDivider />
|
||||
|
||||
<MudStack Spacing="2">
|
||||
<MudStack Row="true" Justify="Justify.SpaceBetween">
|
||||
<MudText Typo="Typo.body2" Class="mud-text-secondary">نوع پکیج:</MudText>
|
||||
<MudText Typo="Typo.body2">پکیج طلایی</MudText>
|
||||
</MudStack>
|
||||
|
||||
<MudStack Row="true" Justify="Justify.SpaceBetween">
|
||||
<MudText Typo="Typo.body2" Class="mud-text-secondary">روش خرید:</MudText>
|
||||
<MudChip T="string" Size="Size.Small" Color="@GetPurchaseMethodColor(_userStatus.PurchaseMethod)">
|
||||
@GetPurchaseMethodText(_userStatus.PurchaseMethod)
|
||||
</MudChip>
|
||||
</MudStack>
|
||||
|
||||
@if (_userStatus.PurchaseDate.HasValue)
|
||||
{
|
||||
<MudStack Row="true" Justify="Justify.SpaceBetween">
|
||||
<MudText Typo="Typo.body2" Class="mud-text-secondary">تاریخ خرید:</MudText>
|
||||
<MudText Typo="Typo.body2">@_userStatus.PurchaseDate.Value.ToLocalTime().ToString("yyyy/MM/dd")</MudText>
|
||||
</MudStack>
|
||||
}
|
||||
|
||||
<MudStack Row="true" Justify="Justify.SpaceBetween">
|
||||
<MudText Typo="Typo.body2" Class="mud-text-secondary">موجودی کیف پول:</MudText>
|
||||
<MudText Typo="Typo.body2" Color="Color.Success">@FormatPrice(_userStatus.WalletBalance)</MudText>
|
||||
</MudStack>
|
||||
</MudStack>
|
||||
</MudStack>
|
||||
</MudPaper>
|
||||
</MudItem>
|
||||
|
||||
<!-- Club Membership Card -->
|
||||
<MudItem xs="12" md="6">
|
||||
<MudPaper Elevation="2" Class="pa-6 h-100">
|
||||
<MudStack Spacing="3">
|
||||
<MudStack Row="true" AlignItems="AlignItems.Center" Spacing="2">
|
||||
<MudIcon Icon="@Icons.Material.Filled.CardMembership" Color="Color.Secondary" />
|
||||
<MudText Typo="Typo.h6">عضویت باشگاه</MudText>
|
||||
</MudStack>
|
||||
|
||||
<MudDivider />
|
||||
|
||||
@if (_userStatus.IsClubMemberActive)
|
||||
{
|
||||
<MudAlert Severity="Severity.Success" Dense="true" Icon="@Icons.Material.Filled.CheckCircle">
|
||||
عضویت باشگاه مشتریان شما فعال است
|
||||
</MudAlert>
|
||||
|
||||
<MudStack Spacing="2">
|
||||
<MudButton Variant="Variant.Outlined"
|
||||
Color="Color.Primary"
|
||||
FullWidth="true"
|
||||
StartIcon="@Icons.Material.Filled.AccountTree"
|
||||
OnClick="@(() => Navigation.NavigateTo(RouteConstants.Network.Statistics))">
|
||||
مشاهده شبکه
|
||||
</MudButton>
|
||||
|
||||
<MudButton Variant="Variant.Outlined"
|
||||
Color="Color.Success"
|
||||
FullWidth="true"
|
||||
StartIcon="@Icons.Material.Filled.Payments"
|
||||
OnClick="@(() => Navigation.NavigateTo(RouteConstants.Commission.Dashboard))">
|
||||
کمیسیونهای من
|
||||
</MudButton>
|
||||
</MudStack>
|
||||
}
|
||||
else if (_userStatus.CanActivateClubMembership)
|
||||
{
|
||||
<MudAlert Severity="Severity.Info" Dense="true" Icon="@Icons.Material.Filled.Info">
|
||||
شما میتوانید عضویت باشگاه را فعال کنید
|
||||
</MudAlert>
|
||||
|
||||
<MudButton Variant="Variant.Filled"
|
||||
Color="Color.Primary"
|
||||
FullWidth="true"
|
||||
Size="Size.Large"
|
||||
StartIcon="@Icons.Material.Filled.CardMembership"
|
||||
OnClick="@(() => Navigation.NavigateTo(RouteConstants.Club.Membership))">
|
||||
فعالسازی باشگاه مشتریان
|
||||
</MudButton>
|
||||
}
|
||||
else
|
||||
{
|
||||
<MudAlert Severity="Severity.Warning" Dense="true" Icon="@Icons.Material.Filled.Warning">
|
||||
موجودی کیف پول شما برای فعالسازی کافی نیست
|
||||
</MudAlert>
|
||||
|
||||
<MudText Typo="Typo.body2" Class="mud-text-secondary">
|
||||
برای فعالسازی باشگاه مشتریان، موجودی کیف پول شما باید حداقل ۵۶ میلیون تومان باشد.
|
||||
</MudText>
|
||||
}
|
||||
</MudStack>
|
||||
</MudPaper>
|
||||
</MudItem>
|
||||
|
||||
<!-- Benefits Card -->
|
||||
<MudItem xs="12">
|
||||
<MudPaper Elevation="2" Class="pa-6">
|
||||
<MudStack Spacing="3">
|
||||
<MudStack Row="true" AlignItems="AlignItems.Center" Spacing="2">
|
||||
<MudIcon Icon="@Icons.Material.Filled.Stars" Color="Color.Warning" />
|
||||
<MudText Typo="Typo.h6">مزایای پکیج طلایی</MudText>
|
||||
</MudStack>
|
||||
|
||||
<MudDivider />
|
||||
|
||||
<MudGrid Spacing="3">
|
||||
<MudItem xs="12" sm="6" md="3">
|
||||
<MudPaper Outlined="true" Class="pa-4 text-center">
|
||||
<MudIcon Icon="@Icons.Material.Filled.Group" Color="Color.Primary" Size="Size.Large" />
|
||||
<MudText Typo="Typo.subtitle2" Class="mt-2">شبکهسازی نامحدود</MudText>
|
||||
<MudText Typo="Typo.caption" Class="mud-text-secondary">دعوت دوستان و ساخت تیم</MudText>
|
||||
</MudPaper>
|
||||
</MudItem>
|
||||
|
||||
<MudItem xs="12" sm="6" md="3">
|
||||
<MudPaper Outlined="true" Class="pa-4 text-center">
|
||||
<MudIcon Icon="@Icons.Material.Filled.Payments" Color="Color.Success" Size="Size.Large" />
|
||||
<MudText Typo="Typo.subtitle2" Class="mt-2">کمیسیون هفتگی</MudText>
|
||||
<MudText Typo="Typo.caption" Class="mud-text-secondary">دریافت سهم از فروش شبکه</MudText>
|
||||
</MudPaper>
|
||||
</MudItem>
|
||||
|
||||
<MudItem xs="12" sm="6" md="3">
|
||||
<MudPaper Outlined="true" Class="pa-4 text-center">
|
||||
<MudIcon Icon="@Icons.Material.Filled.ShoppingBag" Color="Color.Secondary" Size="Size.Large" />
|
||||
<MudText Typo="Typo.subtitle2" Class="mt-2">فروشگاه تخفیفی</MudText>
|
||||
<MudText Typo="Typo.caption" Class="mud-text-secondary">خرید با تخفیف ویژه</MudText>
|
||||
</MudPaper>
|
||||
</MudItem>
|
||||
|
||||
<MudItem xs="12" sm="6" md="3">
|
||||
<MudPaper Outlined="true" Class="pa-4 text-center">
|
||||
<MudIcon Icon="@Icons.Material.Filled.Support" Color="Color.Info" Size="Size.Large" />
|
||||
<MudText Typo="Typo.subtitle2" Class="mt-2">پشتیبانی ۲۴ ساعته</MudText>
|
||||
<MudText Typo="Typo.caption" Class="mud-text-secondary">پشتیبانی اولویتدار</MudText>
|
||||
</MudPaper>
|
||||
</MudItem>
|
||||
</MudGrid>
|
||||
</MudStack>
|
||||
</MudPaper>
|
||||
</MudItem>
|
||||
</MudGrid>
|
||||
}
|
||||
</MudContainer>
|
||||
70
src/FrontOffice.Main/Pages/Package/MyPackages.razor.cs
Normal file
70
src/FrontOffice.Main/Pages/Package/MyPackages.razor.cs
Normal file
@@ -0,0 +1,70 @@
|
||||
using FrontOffice.Main.Utilities;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using MudBlazor;
|
||||
|
||||
namespace FrontOffice.Main.Pages.Package;
|
||||
|
||||
public partial class MyPackages : ComponentBase
|
||||
{
|
||||
[Inject] private PackageService PackageService { get; set; } = default!;
|
||||
|
||||
private UserPackageStatusDto? _userStatus;
|
||||
private bool _isLoading = true;
|
||||
|
||||
private List<BreadcrumbItem> _breadcrumbItems = new()
|
||||
{
|
||||
new BreadcrumbItem("صفحه اصلی", RouteConstants.Main.MainPage),
|
||||
new BreadcrumbItem("پروفایل", RouteConstants.Profile.Index),
|
||||
new BreadcrumbItem("پکیجهای من", null, disabled: true)
|
||||
};
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
await LoadDataAsync();
|
||||
}
|
||||
|
||||
private async Task LoadDataAsync()
|
||||
{
|
||||
_isLoading = true;
|
||||
|
||||
try
|
||||
{
|
||||
_userStatus = await PackageService.GetUserPackageStatusAsync();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
#if DEBUG
|
||||
Console.WriteLine($"Error loading user package status: {ex.Message}");
|
||||
#endif
|
||||
}
|
||||
finally
|
||||
{
|
||||
_isLoading = false;
|
||||
}
|
||||
}
|
||||
|
||||
private static string GetPurchaseMethodText(string? method)
|
||||
{
|
||||
return method switch
|
||||
{
|
||||
"DayaLoan" => "وام دایا",
|
||||
"DirectPurchase" => "پرداخت مستقیم",
|
||||
_ => "نامشخص"
|
||||
};
|
||||
}
|
||||
|
||||
private static Color GetPurchaseMethodColor(string? method)
|
||||
{
|
||||
return method switch
|
||||
{
|
||||
"DayaLoan" => Color.Info,
|
||||
"DirectPurchase" => Color.Success,
|
||||
_ => Color.Default
|
||||
};
|
||||
}
|
||||
|
||||
private static string FormatPrice(long price)
|
||||
{
|
||||
return string.Format("{0:N0} تومان", price);
|
||||
}
|
||||
}
|
||||
139
src/FrontOffice.Main/Pages/Package/Packages.razor
Normal file
139
src/FrontOffice.Main/Pages/Package/Packages.razor
Normal file
@@ -0,0 +1,139 @@
|
||||
@attribute [Route(RouteConstants.Package.List)]
|
||||
|
||||
<PageTitle>پکیجها</PageTitle>
|
||||
|
||||
<MudContainer MaxWidth="MaxWidth.Large" Class="py-8">
|
||||
<!-- Header -->
|
||||
<MudStack Class="mb-6">
|
||||
<MudText Typo="Typo.h4">پکیجهای سرمایهگذاری</MudText>
|
||||
<MudText Typo="Typo.body1" Class="mud-text-secondary">
|
||||
با خرید پکیج طلایی، به باشگاه مشتریان بپیوندید و از مزایای ویژه بهرهمند شوید.
|
||||
</MudText>
|
||||
</MudStack>
|
||||
|
||||
@if (_isLoading)
|
||||
{
|
||||
<MudStack AlignItems="AlignItems.Center" Class="py-16">
|
||||
<MudProgressCircular Color="Color.Primary" Indeterminate="true" Size="Size.Large" />
|
||||
<MudText Typo="Typo.body1" Class="mud-text-secondary mt-2">در حال بارگذاری پکیجها...</MudText>
|
||||
</MudStack>
|
||||
}
|
||||
else if (!_packages.Any())
|
||||
{
|
||||
<MudStack AlignItems="AlignItems.Center" Class="py-16">
|
||||
<MudIcon Icon="@Icons.Material.Filled.Inventory2" Size="Size.Large" Color="Color.Default" />
|
||||
<MudText Typo="Typo.h6" Class="mt-2">هیچ پکیجی یافت نشد</MudText>
|
||||
<MudText Typo="Typo.body2" Class="mud-text-secondary">در حال حاضر پکیجی برای نمایش وجود ندارد.</MudText>
|
||||
</MudStack>
|
||||
}
|
||||
else
|
||||
{
|
||||
<!-- User Status Card (if logged in) -->
|
||||
@if (_userStatus != null && _userStatus.HasPurchasedPackage)
|
||||
{
|
||||
<MudAlert Severity="Severity.Success" Class="mb-6" Icon="@Icons.Material.Filled.CheckCircle">
|
||||
<MudText>
|
||||
شما قبلاً پکیج طلایی را خریداری کردهاید.
|
||||
@if (_userStatus.IsClubMemberActive)
|
||||
{
|
||||
<span>عضویت باشگاه شما فعال است.</span>
|
||||
}
|
||||
else
|
||||
{
|
||||
<MudLink Href="@RouteConstants.Club.Membership" Class="mx-2">فعالسازی باشگاه</MudLink>
|
||||
}
|
||||
</MudText>
|
||||
</MudAlert>
|
||||
}
|
||||
|
||||
<!-- Packages Grid -->
|
||||
<MudGrid Spacing="4">
|
||||
@foreach (var package in _packages)
|
||||
{
|
||||
<MudItem xs="12" sm="6" md="4">
|
||||
<MudCard Class="h-100 package-card" Elevation="3">
|
||||
<!-- Package Image -->
|
||||
<MudCardMedia Image="@package.ImageUrl"
|
||||
Title="@package.Title"
|
||||
Height="200" />
|
||||
|
||||
<MudCardContent>
|
||||
<MudStack Spacing="2">
|
||||
<MudText Typo="Typo.h5">@package.Title</MudText>
|
||||
<MudText Typo="Typo.body2" Class="mud-text-secondary" Style="min-height: 60px;">
|
||||
@TruncateDescription(package.Description)
|
||||
</MudText>
|
||||
|
||||
<!-- Price -->
|
||||
<MudStack Row="true" AlignItems="AlignItems.Center" Class="mt-2">
|
||||
<MudIcon Icon="@Icons.Material.Filled.Sell" Color="Color.Success" Size="Size.Small" />
|
||||
<MudText Typo="Typo.h6" Color="Color.Success">@package.FormattedPrice</MudText>
|
||||
</MudStack>
|
||||
|
||||
<!-- Features Preview -->
|
||||
<MudStack Spacing="1" Class="mt-2">
|
||||
<MudStack Row="true" Spacing="1" AlignItems="AlignItems.Center">
|
||||
<MudIcon Icon="@Icons.Material.Filled.Check" Size="Size.Small" Color="Color.Primary" />
|
||||
<MudText Typo="Typo.caption">عضویت در باشگاه مشتریان</MudText>
|
||||
</MudStack>
|
||||
<MudStack Row="true" Spacing="1" AlignItems="AlignItems.Center">
|
||||
<MudIcon Icon="@Icons.Material.Filled.Check" Size="Size.Small" Color="Color.Primary" />
|
||||
<MudText Typo="Typo.caption">دریافت کمیسیون هفتگی</MudText>
|
||||
</MudStack>
|
||||
<MudStack Row="true" Spacing="1" AlignItems="AlignItems.Center">
|
||||
<MudIcon Icon="@Icons.Material.Filled.Check" Size="Size.Small" Color="Color.Primary" />
|
||||
<MudText Typo="Typo.caption">شبکهسازی نامحدود</MudText>
|
||||
</MudStack>
|
||||
</MudStack>
|
||||
</MudStack>
|
||||
</MudCardContent>
|
||||
|
||||
<MudCardActions Class="pa-4">
|
||||
<MudButton Variant="Variant.Outlined"
|
||||
Color="Color.Primary"
|
||||
FullWidth="true"
|
||||
OnClick="@(() => ViewPackageDetails(package.Id))">
|
||||
مشاهده جزئیات
|
||||
</MudButton>
|
||||
</MudCardActions>
|
||||
</MudCard>
|
||||
</MudItem>
|
||||
}
|
||||
</MudGrid>
|
||||
|
||||
<!-- Info Section -->
|
||||
<MudPaper Elevation="0" Class="pa-6 mt-8 rounded-xl" Style="background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);">
|
||||
<MudGrid Spacing="4">
|
||||
<MudItem xs="12" md="8">
|
||||
<MudStack Spacing="2">
|
||||
<MudText Typo="Typo.h5" Style="color: white;">چرا پکیج طلایی؟</MudText>
|
||||
<MudText Typo="Typo.body1" Style="color: rgba(255,255,255,0.9);">
|
||||
با خرید پکیج طلایی، علاوه بر دسترسی به محصولات ویژه، میتوانید در شبکه فروش شرکت کنید
|
||||
و از کمیسیونهای هفتگی بهرهمند شوید. هر چه شبکه شما گستردهتر، درآمد شما بیشتر!
|
||||
</MudText>
|
||||
</MudStack>
|
||||
</MudItem>
|
||||
<MudItem xs="12" md="4" Class="d-flex align-center justify-center">
|
||||
<MudButton Variant="Variant.Filled"
|
||||
Color="Color.Default"
|
||||
Size="Size.Large"
|
||||
StartIcon="@Icons.Material.Filled.HelpOutline"
|
||||
OnClick="@(() => Navigation.NavigateTo(RouteConstants.FAQ.Index))">
|
||||
سوالات متداول
|
||||
</MudButton>
|
||||
</MudItem>
|
||||
</MudGrid>
|
||||
</MudPaper>
|
||||
}
|
||||
</MudContainer>
|
||||
|
||||
<style>
|
||||
.package-card {
|
||||
transition: transform 0.2s ease-in-out, box-shadow 0.2s ease-in-out;
|
||||
}
|
||||
|
||||
.package-card:hover {
|
||||
transform: translateY(-4px);
|
||||
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.15) !important;
|
||||
}
|
||||
</style>
|
||||
54
src/FrontOffice.Main/Pages/Package/Packages.razor.cs
Normal file
54
src/FrontOffice.Main/Pages/Package/Packages.razor.cs
Normal file
@@ -0,0 +1,54 @@
|
||||
using FrontOffice.Main.Utilities;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
|
||||
namespace FrontOffice.Main.Pages.Package;
|
||||
|
||||
public partial class Packages : ComponentBase
|
||||
{
|
||||
[Inject] private PackageService PackageService { get; set; } = default!;
|
||||
|
||||
private List<PackageDto> _packages = new();
|
||||
private UserPackageStatusDto? _userStatus;
|
||||
private bool _isLoading = true;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
await LoadDataAsync();
|
||||
}
|
||||
|
||||
private async Task LoadDataAsync()
|
||||
{
|
||||
_isLoading = true;
|
||||
|
||||
try
|
||||
{
|
||||
// Load packages
|
||||
_packages = await PackageService.GetAllPackagesAsync();
|
||||
|
||||
// Load user status (if authenticated)
|
||||
_userStatus = await PackageService.GetUserPackageStatusAsync();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
#if DEBUG
|
||||
Console.WriteLine($"Error loading packages: {ex.Message}");
|
||||
#endif
|
||||
}
|
||||
finally
|
||||
{
|
||||
_isLoading = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void ViewPackageDetails(long packageId)
|
||||
{
|
||||
Navigation.NavigateTo(RouteConstants.Package.Detail + packageId);
|
||||
}
|
||||
|
||||
private static string TruncateDescription(string description, int maxLength = 100)
|
||||
{
|
||||
if (string.IsNullOrEmpty(description)) return string.Empty;
|
||||
if (description.Length <= maxLength) return description;
|
||||
return description[..maxLength] + "...";
|
||||
}
|
||||
}
|
||||
70
src/FrontOffice.Main/Pages/Profile/ChangePassword.razor
Normal file
70
src/FrontOffice.Main/Pages/Profile/ChangePassword.razor
Normal file
@@ -0,0 +1,70 @@
|
||||
@attribute [Route(RouteConstants.Profile.ChangePassword)]
|
||||
|
||||
<PageTitle>تغییر رمز عبور</PageTitle>
|
||||
|
||||
<MudContainer MaxWidth="MaxWidth.Small" Class="py-6">
|
||||
<MudStack Spacing="3">
|
||||
<MudStack Row="true" Justify="Justify.SpaceBetween" AlignItems="AlignItems.Center">
|
||||
<MudText Typo="Typo.h5">تغییر رمز عبور</MudText>
|
||||
<MudButton Variant="Variant.Text" StartIcon="@Icons.Material.Filled.ArrowBack" Href="@RouteConstants.Profile.Settings">بازگشت</MudButton>
|
||||
</MudStack>
|
||||
|
||||
<MudPaper Elevation="2" Class="pa-4 rounded-lg">
|
||||
<MudStack Spacing="3">
|
||||
@if (_success)
|
||||
{
|
||||
<MudAlert Severity="Severity.Success" Variant="Variant.Filled">
|
||||
رمز عبور با موفقیت تغییر کرد
|
||||
</MudAlert>
|
||||
}
|
||||
else
|
||||
{
|
||||
<MudTextField T="string" @bind-Value="_currentPassword"
|
||||
Label="رمز عبور فعلی"
|
||||
InputType="InputType.Password"
|
||||
Required="true"
|
||||
RequiredError="رمز عبور فعلی الزامی است"
|
||||
Variant="Variant.Outlined" />
|
||||
|
||||
<MudTextField T="string" @bind-Value="_newPassword"
|
||||
Label="رمز عبور جدید"
|
||||
InputType="InputType.Password"
|
||||
Required="true"
|
||||
RequiredError="رمز عبور جدید الزامی است"
|
||||
HelperText="حداقل 8 کاراکتر شامل حروف و اعداد"
|
||||
Variant="Variant.Outlined" />
|
||||
|
||||
<MudTextField T="string" @bind-Value="_confirmPassword"
|
||||
Label="تکرار رمز عبور جدید"
|
||||
InputType="InputType.Password"
|
||||
Required="true"
|
||||
RequiredError="تکرار رمز عبور الزامی است"
|
||||
Variant="Variant.Outlined" />
|
||||
|
||||
@if (!string.IsNullOrEmpty(_error))
|
||||
{
|
||||
<MudAlert Severity="Severity.Error" Variant="Variant.Outlined">@_error</MudAlert>
|
||||
}
|
||||
|
||||
<MudStack Row="true" Justify="Justify.FlexEnd" Class="mt-2">
|
||||
<MudButton Variant="Variant.Filled"
|
||||
Color="Color.Primary"
|
||||
OnClick="ChangePasswordAsync"
|
||||
Disabled="_saving"
|
||||
StartIcon="@Icons.Material.Filled.Lock">
|
||||
@if (_saving)
|
||||
{
|
||||
<MudProgressCircular Size="Size.Small" Indeterminate="true" Class="me-2" />
|
||||
<span>در حال ذخیره...</span>
|
||||
}
|
||||
else
|
||||
{
|
||||
<span>تغییر رمز عبور</span>
|
||||
}
|
||||
</MudButton>
|
||||
</MudStack>
|
||||
}
|
||||
</MudStack>
|
||||
</MudPaper>
|
||||
</MudStack>
|
||||
</MudContainer>
|
||||
77
src/FrontOffice.Main/Pages/Profile/ChangePassword.razor.cs
Normal file
77
src/FrontOffice.Main/Pages/Profile/ChangePassword.razor.cs
Normal file
@@ -0,0 +1,77 @@
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using MudBlazor;
|
||||
|
||||
namespace FrontOffice.Main.Pages.Profile;
|
||||
|
||||
public partial class ChangePassword : ComponentBase
|
||||
{
|
||||
private string _currentPassword = string.Empty;
|
||||
private string _newPassword = string.Empty;
|
||||
private string _confirmPassword = string.Empty;
|
||||
private string _error = string.Empty;
|
||||
private bool _saving;
|
||||
private bool _success;
|
||||
|
||||
private async Task ChangePasswordAsync()
|
||||
{
|
||||
_error = string.Empty;
|
||||
|
||||
// Validation
|
||||
if (string.IsNullOrWhiteSpace(_currentPassword))
|
||||
{
|
||||
_error = "رمز عبور فعلی را وارد کنید";
|
||||
return;
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(_newPassword))
|
||||
{
|
||||
_error = "رمز عبور جدید را وارد کنید";
|
||||
return;
|
||||
}
|
||||
|
||||
if (_newPassword.Length < 8)
|
||||
{
|
||||
_error = "رمز عبور جدید باید حداقل 8 کاراکتر باشد";
|
||||
return;
|
||||
}
|
||||
|
||||
if (_newPassword != _confirmPassword)
|
||||
{
|
||||
_error = "رمز عبور جدید و تکرار آن یکسان نیستند";
|
||||
return;
|
||||
}
|
||||
|
||||
if (_currentPassword == _newPassword)
|
||||
{
|
||||
_error = "رمز عبور جدید باید متفاوت از رمز فعلی باشد";
|
||||
return;
|
||||
}
|
||||
|
||||
_saving = true;
|
||||
try
|
||||
{
|
||||
// TODO: Call UserContract.ChangePasswordAsync when available
|
||||
// var request = new ChangePasswordRequest
|
||||
// {
|
||||
// CurrentPassword = _currentPassword,
|
||||
// NewPassword = _newPassword
|
||||
// };
|
||||
// await UserContract.ChangePasswordAsync(request);
|
||||
|
||||
// Simulate API call
|
||||
await Task.Delay(500);
|
||||
|
||||
_success = true;
|
||||
Snackbar.Add("رمز عبور با موفقیت تغییر کرد", Severity.Success);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_error = ex.Message;
|
||||
Snackbar.Add($"خطا در تغییر رمز عبور: {ex.Message}", Severity.Error);
|
||||
}
|
||||
finally
|
||||
{
|
||||
_saving = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -101,10 +101,24 @@
|
||||
}
|
||||
</MudList>
|
||||
<MudDivider Class="my-2" />
|
||||
<MudStack Row="true" Justify="Justify.SpaceBetween">
|
||||
<MudText Typo="Typo.subtitle2">مبلغ قابل پرداخت</MudText>
|
||||
<MudText Typo="Typo.subtitle2" Color="Color.Primary">@FormatPrice(Cart.Total)</MudText>
|
||||
|
||||
@* نمایش جزئیات مالی با مالیات *@
|
||||
<MudStack Spacing="1">
|
||||
<MudStack Row="true" Justify="Justify.SpaceBetween">
|
||||
<MudText Typo="Typo.body2">جمع کالاها:</MudText>
|
||||
<MudText Typo="Typo.body2">@FormatPrice(Cart.Total)</MudText>
|
||||
</MudStack>
|
||||
<MudStack Row="true" Justify="Justify.SpaceBetween">
|
||||
<MudText Typo="Typo.body2" Class="mud-text-secondary">مالیات بر ارزش افزوده (۹%):</MudText>
|
||||
<MudText Typo="Typo.body2" Class="mud-text-secondary">@FormatPrice(CalculateVAT())</MudText>
|
||||
</MudStack>
|
||||
<MudDivider Class="my-1" />
|
||||
<MudStack Row="true" Justify="Justify.SpaceBetween">
|
||||
<MudText Typo="Typo.subtitle1" Style="font-weight: bold;">مبلغ قابل پرداخت:</MudText>
|
||||
<MudText Typo="Typo.subtitle1" Color="Color.Primary" Style="font-weight: bold;">@FormatPrice(Cart.Total + CalculateVAT())</MudText>
|
||||
</MudStack>
|
||||
</MudStack>
|
||||
|
||||
<MudButton Disabled="@(!CanPlaceOrder)" Class="mt-3 w-100-mobile" Variant="Variant.Filled" Color="Color.Primary" OnClick="PlaceOrder" StartIcon="@Icons.Material.Filled.CheckCircle">ثبت سفارش</MudButton>
|
||||
}
|
||||
</MudPaper>
|
||||
|
||||
@@ -91,6 +91,11 @@ public partial class CheckoutSummary : ComponentBase
|
||||
|
||||
private static string FormatPrice(long price) => string.Format("{0:N0} تومان", price);
|
||||
|
||||
/// <summary>
|
||||
/// محاسبه مالیات بر ارزش افزوده (۹%)
|
||||
/// </summary>
|
||||
private long CalculateVAT() => (long)(Cart.Total * 0.09);
|
||||
|
||||
private static string GetProductImageUrl(string? imageUrl)
|
||||
=> string.IsNullOrWhiteSpace(imageUrl) ? "/images/product-placeholder.svg" : imageUrl;
|
||||
}
|
||||
@@ -74,7 +74,29 @@ else
|
||||
</MudStack>
|
||||
</MudHidden>
|
||||
<MudDivider Class="my-2" />
|
||||
<MudText Typo="Typo.h6" Align="Align.End">مبلغ کل: @FormatPrice(_order.FactorDetails.Sum(s=>s.UnitPrice.Value*s.Count.Value))</MudText>
|
||||
|
||||
@* نمایش جزئیات مالی *@
|
||||
@{
|
||||
var subtotal = _order.FactorDetails.Sum(s => s.UnitPrice.Value * s.Count.Value);
|
||||
var vatAmount = (long)(subtotal * 0.09);
|
||||
var totalWithVat = subtotal + vatAmount;
|
||||
}
|
||||
<MudStack Spacing="1" Class="pa-2" Style="background-color: var(--mud-palette-background-grey); border-radius: 8px;">
|
||||
<MudStack Row="true" Justify="Justify.SpaceBetween">
|
||||
<MudText Typo="Typo.body2">جمع کالاها:</MudText>
|
||||
<MudText Typo="Typo.body2">@FormatPrice(subtotal)</MudText>
|
||||
</MudStack>
|
||||
|
||||
<MudStack Row="true" Justify="Justify.SpaceBetween">
|
||||
<MudText Typo="Typo.body2" Class="mud-text-secondary">مالیات بر ارزش افزوده (۹%):</MudText>
|
||||
<MudText Typo="Typo.body2" Class="mud-text-secondary">@FormatPrice(vatAmount)</MudText>
|
||||
</MudStack>
|
||||
<MudDivider Class="my-1" />
|
||||
<MudStack Row="true" Justify="Justify.SpaceBetween">
|
||||
<MudText Typo="Typo.subtitle1" Style="font-weight: bold;">مبلغ قابل پرداخت:</MudText>
|
||||
<MudText Typo="Typo.subtitle1" Color="Color.Primary" Style="font-weight: bold;">@FormatPrice(totalWithVat)</MudText>
|
||||
</MudStack>
|
||||
</MudStack>
|
||||
</MudStack>
|
||||
</MudPaper>
|
||||
</MudContainer>
|
||||
|
||||
102
src/FrontOffice.Main/Pages/Store/OrderTracking.razor
Normal file
102
src/FrontOffice.Main/Pages/Store/OrderTracking.razor
Normal file
@@ -0,0 +1,102 @@
|
||||
@using FrontOffice.BFF.UserOrder.Protobuf.Protos.UserOrder
|
||||
@attribute [Route(RouteConstants.Store.OrderTracking + "{id:long}")]
|
||||
|
||||
<PageTitle>پیگیری سفارش</PageTitle>
|
||||
|
||||
<MudContainer MaxWidth="MaxWidth.Medium" Class="py-6">
|
||||
@if (_loading)
|
||||
{
|
||||
<MudStack AlignItems="AlignItems.Center">
|
||||
<MudProgressCircular Indeterminate="true" Color="Color.Primary" />
|
||||
<MudText Class="mt-2 mud-text-secondary">در حال بارگذاری...</MudText>
|
||||
</MudStack>
|
||||
}
|
||||
else if (_order is null)
|
||||
{
|
||||
<MudAlert Severity="Severity.Warning">سفارش یافت نشد.</MudAlert>
|
||||
<MudButton Variant="Variant.Text" StartIcon="@Icons.Material.Filled.ArrowBack"
|
||||
Href="@RouteConstants.Store.Orders">
|
||||
بازگشت به سفارشها
|
||||
</MudButton>
|
||||
}
|
||||
else
|
||||
{
|
||||
<MudStack Spacing="3">
|
||||
<MudStack Row="true" Justify="Justify.SpaceBetween" AlignItems="AlignItems.Center">
|
||||
<MudText Typo="Typo.h5">پیگیری سفارش #@_order.Id</MudText>
|
||||
<MudButton Variant="Variant.Text" StartIcon="@Icons.Material.Filled.ArrowBack"
|
||||
Href="@(RouteConstants.Store.OrderDetail + id)">
|
||||
جزئیات سفارش
|
||||
</MudButton>
|
||||
</MudStack>
|
||||
|
||||
@* Timeline سفارش *@
|
||||
<MudPaper Elevation="2" Class="pa-4 rounded-lg">
|
||||
<MudText Typo="Typo.h6" Class="mb-4">وضعیت سفارش</MudText>
|
||||
|
||||
<MudTimeline TimelinePosition="TimelinePosition.Start">
|
||||
@foreach (var step in _trackingSteps)
|
||||
{
|
||||
<MudTimelineItem Color="@(step.IsCompleted ? Color.Success : (step.IsCurrent ? Color.Primary : Color.Default))"
|
||||
Variant="@(step.IsCompleted || step.IsCurrent ? Variant.Filled : Variant.Outlined)"
|
||||
Size="Size.Medium">
|
||||
<ItemContent>
|
||||
<MudStack Spacing="0">
|
||||
<MudText Typo="Typo.subtitle1"
|
||||
Color="@(step.IsCompleted ? Color.Success : (step.IsCurrent ? Color.Primary : Color.Default))">
|
||||
@step.Title
|
||||
</MudText>
|
||||
<MudText Typo="Typo.caption" Class="mud-text-secondary">@step.Description</MudText>
|
||||
@if (!string.IsNullOrEmpty(step.Date))
|
||||
{
|
||||
<MudText Typo="Typo.caption" Class="mud-text-secondary mt-1">
|
||||
<MudIcon Icon="@Icons.Material.Filled.Schedule" Size="Size.Small" Class="me-1" />
|
||||
@step.Date
|
||||
</MudText>
|
||||
}
|
||||
</MudStack>
|
||||
</ItemContent>
|
||||
</MudTimelineItem>
|
||||
}
|
||||
</MudTimeline>
|
||||
</MudPaper>
|
||||
|
||||
@* اطلاعات ارسال *@
|
||||
<MudPaper Elevation="2" Class="pa-4 rounded-lg">
|
||||
<MudText Typo="Typo.h6" Class="mb-3">اطلاعات ارسال</MudText>
|
||||
|
||||
<MudGrid>
|
||||
<MudItem xs="12" sm="6">
|
||||
<MudStack Spacing="1">
|
||||
<MudText Typo="Typo.caption" Class="mud-text-secondary">آدرس تحویل</MudText>
|
||||
<MudText>@(_order.UserAddressText ?? "---")</MudText>
|
||||
</MudStack>
|
||||
</MudItem>
|
||||
<MudItem xs="12" sm="6">
|
||||
<MudStack Spacing="1">
|
||||
<MudText Typo="Typo.caption" Class="mud-text-secondary">روش پرداخت</MudText>
|
||||
<MudText>@GetPaymentMethodText(_order.PaymentMethod)</MudText>
|
||||
</MudStack>
|
||||
</MudItem>
|
||||
</MudGrid>
|
||||
</MudPaper>
|
||||
|
||||
@* پشتیبانی *@
|
||||
<MudPaper Elevation="1" Class="pa-4 rounded-lg" Style="background-color: var(--mud-palette-background-grey);">
|
||||
<MudStack Row="true" AlignItems="AlignItems.Center" Spacing="3">
|
||||
<MudIcon Icon="@Icons.Material.Filled.HeadsetMic" Size="Size.Large" Color="Color.Primary" />
|
||||
<MudStack Spacing="0">
|
||||
<MudText Typo="Typo.subtitle1">سوالی دارید؟</MudText>
|
||||
<MudText Typo="Typo.body2" Class="mud-text-secondary">
|
||||
با پشتیبانی ما تماس بگیرید: ۰۲۱-۱۲۳۴۵۶۷۸
|
||||
</MudText>
|
||||
</MudStack>
|
||||
<MudSpacer />
|
||||
<MudButton Variant="Variant.Outlined" Color="Color.Primary" Href="@RouteConstants.Contact.Index">
|
||||
تماس با ما
|
||||
</MudButton>
|
||||
</MudStack>
|
||||
</MudPaper>
|
||||
</MudStack>
|
||||
}
|
||||
</MudContainer>
|
||||
125
src/FrontOffice.Main/Pages/Store/OrderTracking.razor.cs
Normal file
125
src/FrontOffice.Main/Pages/Store/OrderTracking.razor.cs
Normal file
@@ -0,0 +1,125 @@
|
||||
using FrontOffice.BFF.UserOrder.Protobuf.Protos.UserOrder;
|
||||
using FrontOffice.Main.Utilities;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
|
||||
namespace FrontOffice.Main.Pages.Store;
|
||||
|
||||
public partial class OrderTracking : ComponentBase
|
||||
{
|
||||
[Inject] private OrderService OrderService { get; set; } = default!;
|
||||
|
||||
[Parameter] public long id { get; set; }
|
||||
|
||||
private GetUserOrderResponse? _order;
|
||||
private bool _loading = true;
|
||||
private List<TrackingStep> _trackingSteps = new();
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
await LoadOrderAsync();
|
||||
}
|
||||
|
||||
private async Task LoadOrderAsync()
|
||||
{
|
||||
_loading = true;
|
||||
StateHasChanged();
|
||||
|
||||
try
|
||||
{
|
||||
var response = await OrderService.GetOrderAsync(id);
|
||||
if (response is not null)
|
||||
{
|
||||
_order = response;
|
||||
BuildTrackingSteps();
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
_loading = false;
|
||||
StateHasChanged();
|
||||
}
|
||||
}
|
||||
|
||||
private void BuildTrackingSteps()
|
||||
{
|
||||
if (_order is null) return;
|
||||
|
||||
// Build tracking steps based on PaymentStatus
|
||||
var isPaid = _order.PaymentStatus == PaymentStatus.Success;
|
||||
|
||||
_trackingSteps = new List<TrackingStep>
|
||||
{
|
||||
new()
|
||||
{
|
||||
Title = "ثبت سفارش",
|
||||
Description = "سفارش شما با موفقیت ثبت شد",
|
||||
IsCompleted = true,
|
||||
Date = FormatDate(_order.PaymentDate)
|
||||
},
|
||||
new()
|
||||
{
|
||||
Title = "در انتظار پرداخت",
|
||||
Description = "منتظر تایید پرداخت هستیم",
|
||||
IsCompleted = isPaid,
|
||||
IsCurrent = !isPaid,
|
||||
Date = isPaid ? FormatDate(_order.PaymentDate) : ""
|
||||
},
|
||||
new()
|
||||
{
|
||||
Title = "تایید پرداخت",
|
||||
Description = "پرداخت شما تایید شد",
|
||||
IsCompleted = isPaid,
|
||||
IsCurrent = false,
|
||||
Date = isPaid ? FormatDate(_order.PaymentDate) : ""
|
||||
},
|
||||
new()
|
||||
{
|
||||
Title = "در حال پردازش",
|
||||
Description = "سفارش شما در حال آمادهسازی است",
|
||||
IsCompleted = false,
|
||||
IsCurrent = isPaid,
|
||||
Date = ""
|
||||
},
|
||||
new()
|
||||
{
|
||||
Title = "ارسال شده",
|
||||
Description = "سفارش شما به پست تحویل داده شد",
|
||||
IsCompleted = false,
|
||||
IsCurrent = false,
|
||||
Date = ""
|
||||
},
|
||||
new()
|
||||
{
|
||||
Title = "تحویل داده شده",
|
||||
Description = "سفارش به دست شما رسید",
|
||||
IsCompleted = false,
|
||||
IsCurrent = false,
|
||||
Date = ""
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static string FormatDate(Google.Protobuf.WellKnownTypes.Timestamp? timestamp)
|
||||
{
|
||||
if (timestamp is null) return "";
|
||||
var date = timestamp.ToDateTime();
|
||||
var persianCalendar = new System.Globalization.PersianCalendar();
|
||||
return $"{persianCalendar.GetYear(date)}/{persianCalendar.GetMonth(date):00}/{persianCalendar.GetDayOfMonth(date):00}";
|
||||
}
|
||||
|
||||
private static string GetPaymentMethodText(PaymentMethod method) => method switch
|
||||
{
|
||||
PaymentMethod.Ipg => "پرداخت آنلاین",
|
||||
PaymentMethod.Wallet => "کیف پول",
|
||||
_ => "نامشخص"
|
||||
};
|
||||
|
||||
private class TrackingStep
|
||||
{
|
||||
public string Title { get; set; } = "";
|
||||
public string Description { get; set; } = "";
|
||||
public bool IsCompleted { get; set; }
|
||||
public bool IsCurrent { get; set; }
|
||||
public string Date { get; set; } = "";
|
||||
}
|
||||
}
|
||||
121
src/FrontOffice.Main/Utilities/PackageService.cs
Normal file
121
src/FrontOffice.Main/Utilities/PackageService.cs
Normal file
@@ -0,0 +1,121 @@
|
||||
using FrontOffice.BFF.Package.Protobuf.Protos.Package;
|
||||
|
||||
namespace FrontOffice.Main.Utilities;
|
||||
|
||||
/// <summary>
|
||||
/// Package data transfer object for UI display
|
||||
/// </summary>
|
||||
public record PackageDto(
|
||||
long Id,
|
||||
string Title,
|
||||
string Description,
|
||||
string ImageUrl,
|
||||
long Price)
|
||||
{
|
||||
public string FormattedPrice => string.Format("{0:N0} تومان", Price);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// User's package purchase status
|
||||
/// </summary>
|
||||
public record UserPackageStatusDto(
|
||||
bool HasPurchasedPackage,
|
||||
string? PurchaseMethod, // DayaLoan, DirectPurchase, or null
|
||||
bool IsClubMemberActive,
|
||||
long WalletBalance,
|
||||
bool CanActivateClubMembership,
|
||||
DateTime? PurchaseDate);
|
||||
|
||||
/// <summary>
|
||||
/// Service for managing packages in FrontOffice
|
||||
/// </summary>
|
||||
public class PackageService
|
||||
{
|
||||
private readonly PackageContract.PackageContractClient _client;
|
||||
|
||||
public PackageService(PackageContract.PackageContractClient client)
|
||||
{
|
||||
_client = client;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get all available packages
|
||||
/// </summary>
|
||||
public async Task<List<PackageDto>> GetAllPackagesAsync(CancellationToken ct = default)
|
||||
{
|
||||
try
|
||||
{
|
||||
var request = new GetAllPackageByFilterRequest
|
||||
{
|
||||
PaginationState = new PaginationState
|
||||
{
|
||||
PageNumber = 1,
|
||||
PageSize = 100
|
||||
}
|
||||
};
|
||||
|
||||
var response = await _client.GetAllPackageByFilterAsync(request, cancellationToken: ct);
|
||||
|
||||
return response.Models
|
||||
.Select(m => new PackageDto(
|
||||
m.Id,
|
||||
m.Title,
|
||||
m.Description,
|
||||
UrlUtility.DownloadUrl + m.ImagePath,
|
||||
m.Price))
|
||||
.ToList();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
#if DEBUG
|
||||
Console.WriteLine($"Error fetching packages: {ex.Message}");
|
||||
#endif
|
||||
return new List<PackageDto>();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get a single package by ID
|
||||
/// </summary>
|
||||
public async Task<PackageDto?> GetPackageByIdAsync(long id, CancellationToken ct = default)
|
||||
{
|
||||
try
|
||||
{
|
||||
var response = await _client.GetPackageAsync(
|
||||
new GetPackageRequest { Id = id },
|
||||
cancellationToken: ct);
|
||||
|
||||
if (response == null) return null;
|
||||
|
||||
return new PackageDto(
|
||||
response.Id,
|
||||
response.Title,
|
||||
response.Description,
|
||||
UrlUtility.DownloadUrl + response.ImagePath,
|
||||
response.Price);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
#if DEBUG
|
||||
Console.WriteLine($"Error fetching package {id}: {ex.Message}");
|
||||
#endif
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get user's package purchase status (Mock for now - needs BFF implementation)
|
||||
/// </summary>
|
||||
public Task<UserPackageStatusDto> GetUserPackageStatusAsync(CancellationToken ct = default)
|
||||
{
|
||||
// TODO: Connect to GetUserPackageStatus RPC when available in FrontOffice.BFF
|
||||
// For now, return a mock status
|
||||
return Task.FromResult(new UserPackageStatusDto(
|
||||
HasPurchasedPackage: false,
|
||||
PurchaseMethod: null,
|
||||
IsClubMemberActive: false,
|
||||
WalletBalance: 0,
|
||||
CanActivateClubMembership: false,
|
||||
PurchaseDate: null));
|
||||
}
|
||||
}
|
||||
@@ -18,6 +18,7 @@ public static class RouteConstants
|
||||
public const string Personal = "/profile/personal";
|
||||
public const string Addresses = "/profile/addresses";
|
||||
public const string Settings = "/profile/settings";
|
||||
public const string ChangePassword = "/profile/change-password";
|
||||
public const string Tree = "/profile/tree";
|
||||
public const string Wallet = "/profile/wallet";
|
||||
}
|
||||
@@ -43,7 +44,10 @@ public static class RouteConstants
|
||||
|
||||
public static class Package
|
||||
{
|
||||
public const string List = "/packages";
|
||||
public const string Detail = "/package/";
|
||||
public const string MyPackages = "/my-packages";
|
||||
public const string Purchase = "/purchase-package/";
|
||||
}
|
||||
|
||||
public static class About
|
||||
@@ -74,6 +78,7 @@ public static class RouteConstants
|
||||
public const string CheckoutSummary = "/checkout-summary";
|
||||
public const string Orders = "/orders";
|
||||
public const string OrderDetail = "/order/"; // usage: /order/{id}
|
||||
public const string OrderTracking = "/order-tracking/"; // usage: /order-tracking/{id}
|
||||
public const string Categories = "/categories";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"GwUrl": "https://fogw.kbs1.ir",
|
||||
"GwUrl": "http://backoffice-bff-svc",
|
||||
// "GwUrl": "https://localhost:34781",
|
||||
"DownloadUrl": "https://dl.afrino.co",
|
||||
"EncryptionSettings": {
|
||||
|
||||
Reference in New Issue
Block a user