Files
FrontOffice/src/FrontOffice.Main/Shared/MainLayout.razor.cs
T
masoodafar-web 6db83ccd90
Build and Deploy to Kubernetes / build-and-deploy (push) Failing after 4m55s
feat: full FrontOffice updates - discount store, blog, payment gateway, UI improvements
- 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
2026-02-16 00:51:39 +03:30

284 lines
10 KiB
C#

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;
namespace FrontOffice.Main.Shared;
public partial class MainLayout : IDisposable
{
private const string TokenStorageKey = "auth:token";
private MudThemeProvider _mudThemeProvider;
private bool _isDark;
private bool _drawerOpen;
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;
private string? _newVersion;
private VersionCheckResult? _versionCheckResult;
[Inject] private ILocalStorageService LocalStorage { get; set; } = default!;
[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;
private void ToggleDrawer() => _drawerOpen = !_drawerOpen;
private async void Back()
{
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();
}
StateHasChanged();
}
}
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>
private async Task CheckForUpdateSilentlyAsync()
{
try
{
_versionCheckResult = await AppVersionService.CheckVersionAsync(ignoreSkipped: true);
if (_versionCheckResult.HasNewVersion && !string.IsNullOrEmpty(_versionCheckResult.NewVersion))
{
_hasUpdate = true;
_newVersion = _versionCheckResult.NewVersion;
}
}
catch
{
// در صورت خطا نادیده بگیر
}
}
/// <summary>
/// باز کردن دیالوگ بروزرسانی
/// </summary>
private async Task OpenUpdateDialog()
{
if (_versionCheckResult == null || string.IsNullOrEmpty(_versionCheckResult.NewVersion))
return;
// ثبت زمان نمایش دیالوگ
await AppVersionService.RecordDialogShownAsync();
var dialogOptions = new DialogOptions
{
BackdropClick = !_versionCheckResult.IsForceUpdate,
CloseOnEscapeKey = !_versionCheckResult.IsForceUpdate,
CloseButton = !_versionCheckResult.IsForceUpdate,
MaxWidth = MaxWidth.Small,
FullWidth = true
};
var parameters = new DialogParameters<ReleaseNotesDialog>
{
{ x => x.OldVersion, _versionCheckResult.OldVersion },
{ x => x.NewVersion, _versionCheckResult.NewVersion },
{ x => x.ReleaseNotes, _versionCheckResult.ReleaseNotes },
{ x => x.UpdateMessage, _versionCheckResult.UpdateMessage },
{ x => x.IsForceUpdate, _versionCheckResult.IsForceUpdate }
};
var dialog = await DialogService.ShowAsync<ReleaseNotesDialog>("بروزرسانی", parameters, dialogOptions);
var result = await dialog.Result;
if (result is { Canceled: false, Data: bool shouldUpdate })
{
if (shouldUpdate)
{
await AppVersionService.ApplyUpdateAsync(_versionCheckResult.NewVersion);
Navigation.NavigateTo(Navigation.Uri, forceLoad: true);
}
else
{
await AppVersionService.SkipVersionAsync(_versionCheckResult.NewVersion);
// نمایش آپدیت همچنان باقی بمونه (hasUpdate true بمونه)
}
}
}
private void OnCartChanged()
{
_cartCount = CartService.Count;
InvokeAsync(StateHasChanged);
}
private void OnDiscountCartChanged()
{
_discountCartCount = DiscountCartService.Count;
InvokeAsync(StateHasChanged);
}
private async Task CheckAuthStatus()
{
_isAuthenticated = await AuthService.IsAuthenticatedAsync();
}
private async Task OpenAuthDialog()
{
await AuthDialogService.ShowAuthDialogAsync();
await CheckAuthStatus();
if (_isAuthenticated)
{
Snackbar.Add(GlobalConstants.SuccessMsg, Severity.Success);
}
StateHasChanged();
Navigation.NavigateTo(RouteConstants.Main.MainPage);
}
private void NavigateToProfile()
{
Navigation.NavigateTo(RouteConstants.Profile.Index);
}
private void NavigateToHub()
{
Navigation.NavigateTo(RouteConstants.Profile.Hub);
}
private async Task Logout()
{
await AuthService.LogoutAsync();
_isAuthenticated = false;
_cartCount = 0;
StateHasChanged();
}
public void Dispose()
{
CartService.OnChange -= OnCartChanged;
DiscountCartService.OnChange -= OnDiscountCartChanged;
Navigation.LocationChanged -= OnLocationChanged;
}
}