feat: full FrontOffice updates - discount store, blog, payment gateway, UI improvements
Build and Deploy to Kubernetes / build-and-deploy (push) Failing after 4m55s
Build and Deploy to Kubernetes / build-and-deploy (push) Failing after 4m55s
- Discount store pages (products, cart, orders, order detail) - Blog pages and services - Payment gateway callback page - AppImage component, EmptyState, LoadingState, PageHeader - DiscountCartService, DiscountOrderService, DiscountProductService - BlogCategoryService, BlogPostService, SitePageService, ImageCacheService - PhoneVerifyForm component - Profile Hub page - UI/UX improvements across all pages - landing.js for homepage - Config and routing updates
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
using Blazored.LocalStorage;
|
||||
using FrontOffice.Main.Utilities;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Microsoft.AspNetCore.Components.Routing;
|
||||
using Microsoft.JSInterop;
|
||||
using MudBlazor;
|
||||
using Microsoft.AspNetCore.Components.Authorization;
|
||||
@@ -16,6 +17,15 @@ public partial class MainLayout : IDisposable
|
||||
private bool _isAuthenticated;
|
||||
private string? _email;
|
||||
private int _cartCount;
|
||||
private int _discountCartCount;
|
||||
private bool _isCompleteRegister;
|
||||
|
||||
// ── Store Context ──
|
||||
private enum StoreContext { None, Regular, Discount }
|
||||
private StoreContext _storeCtx = StoreContext.None;
|
||||
private bool IsInRegularStore => _storeCtx == StoreContext.Regular;
|
||||
private bool IsInDiscountStore => _storeCtx == StoreContext.Discount;
|
||||
private bool IsInAnyStore => _storeCtx != StoreContext.None;
|
||||
|
||||
// متغیرهای بروزرسانی
|
||||
private bool _hasUpdate;
|
||||
@@ -26,6 +36,7 @@ public partial class MainLayout : IDisposable
|
||||
[Inject] private AuthService AuthService { get; set; } = default!;
|
||||
[Inject] private AuthDialogService AuthDialogService { get; set; } = default!;
|
||||
[Inject] private CartService CartService { get; set; } = default!;
|
||||
[Inject] private DiscountCartService DiscountCartService { get; set; } = default!;
|
||||
[Inject] private AppVersionService AppVersionService { get; set; } = default!;
|
||||
|
||||
private void ToggleTheme() => _isDark = !_isDark;
|
||||
@@ -35,20 +46,34 @@ public partial class MainLayout : IDisposable
|
||||
await JSRuntime.InvokeVoidAsync("history.back");
|
||||
}
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
Navigation.LocationChanged += OnLocationChanged;
|
||||
UpdateStoreContext();
|
||||
}
|
||||
|
||||
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||
{
|
||||
if (firstRender)
|
||||
{
|
||||
await JSRuntime.InvokeVoidAsync("changeNavBgOnBodyScroll", "top", null, 1);
|
||||
await CheckAuthStatus();
|
||||
|
||||
await EnforceAuthGuardAsync();
|
||||
|
||||
if (_isAuthenticated)
|
||||
{
|
||||
// بررسی وضعیت ثبتنام کامل
|
||||
_isCompleteRegister = await AuthService.IsCompleteRegisterAsync();
|
||||
|
||||
// لود سبد خرید فقط برای کاربر لاگین شده
|
||||
await CartService.EnsureInitializedAsync();
|
||||
CartService.OnChange += OnCartChanged;
|
||||
_cartCount = CartService.Count;
|
||||
|
||||
await DiscountCartService.EnsureInitializedAsync();
|
||||
DiscountCartService.OnChange += OnDiscountCartChanged;
|
||||
_discountCartCount = DiscountCartService.Count;
|
||||
|
||||
// چک کردن بروزرسانی (بدون نمایش popup - فقط برای نشون دادن آیکون)
|
||||
await CheckForUpdateSilentlyAsync();
|
||||
}
|
||||
@@ -57,6 +82,83 @@ public partial class MainLayout : IDisposable
|
||||
}
|
||||
}
|
||||
|
||||
private void OnLocationChanged(object? sender, LocationChangedEventArgs e)
|
||||
{
|
||||
UpdateStoreContext();
|
||||
_ = InvokeAsync(async () =>
|
||||
{
|
||||
await EnforceAuthGuardAsync();
|
||||
StateHasChanged();
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// If the current route requires authentication and the user is not logged in, redirect to home.
|
||||
/// </summary>
|
||||
private async Task EnforceAuthGuardAsync()
|
||||
{
|
||||
if (_isAuthenticated) return;
|
||||
|
||||
// Re-check in case token was set after initial render
|
||||
_isAuthenticated = await AuthService.IsAuthenticatedAsync();
|
||||
if (_isAuthenticated) return;
|
||||
|
||||
var path = new Uri(Navigation.Uri).AbsolutePath.ToLowerInvariant();
|
||||
if (IsProtectedRoute(path))
|
||||
{
|
||||
Navigation.NavigateTo(RouteConstants.Main.MainPage, replace: true);
|
||||
}
|
||||
}
|
||||
|
||||
private static bool IsProtectedRoute(string path)
|
||||
{
|
||||
// Public routes — no auth needed
|
||||
if (path is "/" or "/register" or "/about" or "/faq" or "/contact"
|
||||
or "/packages" or "/stores" or "/products" or "/categories")
|
||||
return false;
|
||||
if (path.StartsWith("/blog")) return false;
|
||||
if (path.StartsWith("/package/")) return false;
|
||||
if (path.StartsWith("/product/")) return false;
|
||||
if (path == "/discount-store" || path.StartsWith("/discount-store/product/")) return false;
|
||||
|
||||
// Everything else is protected
|
||||
if (path.StartsWith("/profile")) return true;
|
||||
if (path.StartsWith("/commission")) return true;
|
||||
if (path.StartsWith("/network")) return true;
|
||||
if (path.StartsWith("/club")) return true;
|
||||
if (path.StartsWith("/checkout")) return true;
|
||||
if (path.StartsWith("/cart")) return true;
|
||||
if (path.StartsWith("/orders") || path.StartsWith("/order/") || path.StartsWith("/order-tracking/")) return true;
|
||||
if (path.StartsWith("/my-packages") || path.StartsWith("/my-orders") || path.StartsWith("/my-cart")) return true;
|
||||
if (path.StartsWith("/discount-store/cart") || path.StartsWith("/discount-store/checkout")
|
||||
|| path.StartsWith("/discount-store/orders") || path.StartsWith("/discount-store/order/")) return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private void UpdateStoreContext()
|
||||
{
|
||||
var path = new Uri(Navigation.Uri).AbsolutePath.ToLowerInvariant();
|
||||
|
||||
// Discount store routes all start with /discount-store
|
||||
if (path.StartsWith("/discount-store"))
|
||||
{
|
||||
_storeCtx = StoreContext.Discount;
|
||||
}
|
||||
// Regular store routes
|
||||
else if (path.StartsWith("/products") || path.StartsWith("/product/") ||
|
||||
path.StartsWith("/cart") || path.StartsWith("/checkout-summary") ||
|
||||
path.StartsWith("/orders") || path.StartsWith("/order/") ||
|
||||
path.StartsWith("/order-tracking/") || path.StartsWith("/categories"))
|
||||
{
|
||||
_storeCtx = StoreContext.Regular;
|
||||
}
|
||||
else
|
||||
{
|
||||
_storeCtx = StoreContext.None;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// چک کردن بروزرسانی بدون نمایش popup
|
||||
/// </summary>
|
||||
@@ -131,6 +233,12 @@ public partial class MainLayout : IDisposable
|
||||
InvokeAsync(StateHasChanged);
|
||||
}
|
||||
|
||||
private void OnDiscountCartChanged()
|
||||
{
|
||||
_discountCartCount = DiscountCartService.Count;
|
||||
InvokeAsync(StateHasChanged);
|
||||
}
|
||||
|
||||
private async Task CheckAuthStatus()
|
||||
{
|
||||
_isAuthenticated = await AuthService.IsAuthenticatedAsync();
|
||||
@@ -154,6 +262,11 @@ public partial class MainLayout : IDisposable
|
||||
Navigation.NavigateTo(RouteConstants.Profile.Index);
|
||||
}
|
||||
|
||||
private void NavigateToHub()
|
||||
{
|
||||
Navigation.NavigateTo(RouteConstants.Profile.Hub);
|
||||
}
|
||||
|
||||
private async Task Logout()
|
||||
{
|
||||
await AuthService.LogoutAsync();
|
||||
@@ -165,5 +278,7 @@ public partial class MainLayout : IDisposable
|
||||
public void Dispose()
|
||||
{
|
||||
CartService.OnChange -= OnCartChanged;
|
||||
DiscountCartService.OnChange -= OnDiscountCartChanged;
|
||||
Navigation.LocationChanged -= OnLocationChanged;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user