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(); }); } /// /// If the current route requires authentication and the user is not logged in, redirect to home. /// 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; } } /// /// چک کردن بروزرسانی بدون نمایش popup /// private async Task CheckForUpdateSilentlyAsync() { try { _versionCheckResult = await AppVersionService.CheckVersionAsync(ignoreSkipped: true); if (_versionCheckResult.HasNewVersion && !string.IsNullOrEmpty(_versionCheckResult.NewVersion)) { _hasUpdate = true; _newVersion = _versionCheckResult.NewVersion; } } catch { // در صورت خطا نادیده بگیر } } /// /// باز کردن دیالوگ بروزرسانی /// 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 { { 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("بروزرسانی", 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; } }