feat: full FrontOffice updates - discount store, blog, payment gateway, UI improvements
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:
masoodafar-web
2026-02-16 00:51:39 +03:30
parent f0d1156457
commit 6db83ccd90
104 changed files with 7668 additions and 1370 deletions
+180 -38
View File
@@ -9,10 +9,10 @@
<MudSnackbarProvider/>
<MudLayout>
<!-- AppBar -->
<MudAppBar Elevation="0" Color="Color.Transparent" Dense="true" Class="py-2" id="top">
<MudAppBar Elevation="1" Color="Color.Surface" Dense="true" Class="py-2" id="top">
<MudContainer MaxWidth="MaxWidth.Large" Class="d-flex align-center justify-space-between w-100">
<MudHidden Breakpoint="Breakpoint.SmAndUp">
<MudHidden Breakpoint="Breakpoint.MdAndUp">
<MudIconButton Class="d-inline"
Icon="@Icons.Material.Filled.Menu"
OnClick="@ToggleDrawer"/>
@@ -21,7 +21,7 @@
<div class="d-flex align-center gap-2">
<MudLink Href="@(RouteConstants.Main.MainPage)" Underline="Underline.None">
<MudStack Row="true" Spacing="3" AlignItems="AlignItems.Center">
<MudHidden Breakpoint="Breakpoint.SmAndUp" Invert="true">
<MudHidden Breakpoint="Breakpoint.MdAndUp" Invert="true">
<MudImage ObjectFit="ObjectFit.Cover"
ObjectPosition="ObjectPosition.Center"
Width="32"
@@ -32,37 +32,66 @@
<MudText Typo="Typo.h6">کارا بازار سلامت</MudText>
</MudStack>
</MudLink>
@* ── Store context badge (desktop) ── *@
@if (IsInRegularStore)
{
<MudChip T="string" Color="Color.Success" Variant="Variant.Filled" Size="Size.Small"
Class="d-none d-md-flex" Icon="@Icons.Material.Filled.Storefront">فروشگاه</MudChip>
}
else if (IsInDiscountStore)
{
<MudChip T="string" Color="Color.Error" Variant="Variant.Filled" Size="Size.Small"
Class="d-none d-md-flex" Icon="@Icons.Material.Filled.Loyalty">فروشگاه تخفیفی</MudChip>
}
</div>
<div class="d-none d-md-flex align-center gap-10">
@if (_isAuthenticated)
@if (IsInRegularStore && _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>
@* ── Regular store nav ── *@
<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>
else if (IsInDiscountStore && _isAuthenticated)
{
@* ── Discount store nav ── *@
<MudLink Href="@(RouteConstants.DiscountStore.Products)" Typo="Typo.subtitle1" Class="mud-link">محصولات تخفیفی</MudLink>
<MudLink Href="@(RouteConstants.DiscountStore.Cart)" Typo="Typo.subtitle1" Class="mud-link">سبد خرید</MudLink>
<MudLink Href="@(RouteConstants.DiscountStore.Orders)" Typo="Typo.subtitle1" Class="mud-link">سفارشات من</MudLink>
}
else
{
@* ── Default global nav (not inside any store) ── *@
@if (_isAuthenticated)
{
<MudLink Href="@(RouteConstants.Gateway.StoreChooser)" Typo="Typo.subtitle1" Class="mud-link">فروشگاه‌ها</MudLink>
}
}
<MudLink Href="@(RouteConstants.FAQ.Index)" Typo="Typo.subtitle1" Class="mud-link">سوالات متداول</MudLink>
<MudLink Href="@(RouteConstants.Blog.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)
{
@* <MudBadge Content="@_cartCount" Color="Color.Error" Overlap="true" Visible="@(_cartCount > 0)"> *@
@* *@
@* </MudBadge> *@
<MudIconButton Icon="@Icons.Material.Filled.ShoppingCart" Color="@(_cartCount > 0?Color.Success:Color.Inherit)"
Href="@(RouteConstants.Store.Cart)" />
@* ── Cart icon: only visible when inside a store ── *@
@if (IsInRegularStore)
{
<MudIconButton Icon="@Icons.Material.Filled.ShoppingCart"
Color="@(_cartCount > 0 ? Color.Success : Color.Inherit)"
Href="@(RouteConstants.Store.Cart)" />
}
else if (IsInDiscountStore)
{
<MudIconButton Icon="@Icons.Material.Filled.ShoppingCart"
Color="@(_discountCartCount > 0 ? Color.Error : Color.Inherit)"
Href="@(RouteConstants.DiscountStore.Cart)" />
}
@* دکمه بروزرسانی *@
@if (_hasUpdate)
{
@@ -74,7 +103,10 @@
</MudBadge>
}
<MudMenu Icon="@Icons.Material.Filled.Person" Color="Color.Inherit" Size="Size.Medium">
<MudMenuItem OnClick="NavigateToProfile" Disabled="@(!AuthService.IsCompleteRegister())">
<MudMenuItem OnClick="NavigateToProfile" Disabled="@(!_isCompleteRegister)" Icon="@Icons.Material.Outlined.Dashboard">
داشبورد
</MudMenuItem>
<MudMenuItem OnClick="NavigateToHub" Disabled="@(!_isCompleteRegister)" Icon="@Icons.Material.Outlined.Person">
پروفایل
</MudMenuItem>
<MudDivider/>
@@ -110,19 +142,49 @@
<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>
@if (IsInRegularStore)
{
<MudText Typo="Typo.overline" Class="mud-text-secondary">فروشگاه</MudText>
<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>
<MudDivider Class="my-1" />
<MudLink Href="@(RouteConstants.Gateway.StoreChooser)" Typo="Typo.subtitle1"
OnClick="() => _drawerOpen=false" Class="mud-text-secondary">
← بازگشت به فروشگاه‌ها
</MudLink>
}
else if (IsInDiscountStore)
{
<MudText Typo="Typo.overline" Style="color:var(--mud-palette-error);">فروشگاه تخفیفی</MudText>
<MudLink Href="@(RouteConstants.DiscountStore.Products)" Typo="Typo.subtitle1"
OnClick="() => _drawerOpen=false">محصولات تخفیفی</MudLink>
<MudLink Href="@(RouteConstants.DiscountStore.Cart)" Typo="Typo.subtitle1"
OnClick="() => _drawerOpen=false">سبد خرید</MudLink>
<MudLink Href="@(RouteConstants.DiscountStore.Orders)" Typo="Typo.subtitle1"
OnClick="() => _drawerOpen=false">سفارشات من</MudLink>
<MudDivider Class="my-1" />
<MudLink Href="@(RouteConstants.Gateway.StoreChooser)" Typo="Typo.subtitle1"
OnClick="() => _drawerOpen=false" Class="mud-text-secondary">
← بازگشت به فروشگاه‌ها
</MudLink>
}
else
{
<MudLink Href="@(RouteConstants.Gateway.StoreChooser)" Typo="Typo.subtitle1"
OnClick="() => _drawerOpen=false">فروشگاه‌ها</MudLink>
}
<MudDivider Class="my-1" />
}
<MudLink Href="@(RouteConstants.FAQ.Index)" Typo="Typo.subtitle1" OnClick="() => _drawerOpen=false">
سوالات متداول
</MudLink>
<MudLink Href="@(RouteConstants.Blog.Index)" Typo="Typo.subtitle1" OnClick="() => _drawerOpen=false">
بلاگ
</MudLink>
<MudLink Href="@(RouteConstants.About.Index)" Typo="Typo.subtitle1" OnClick="() => _drawerOpen=false">
درباره ما
</MudLink>
@@ -165,13 +227,93 @@
</MudStack>
</MudDrawer>
<MudMainContent>
<MudMainContent Class="main-content-wrapper">
@Body
@if (DeviceDetector.IsDesktop())
{
<MudHidden Breakpoint="Breakpoint.SmAndDown">
<Footer/>
}
</MudHidden>
</MudMainContent>
<!-- Mobile Bottom Navigation -->
<MudHidden Breakpoint="Breakpoint.MdAndUp">
<MudPaper Class="bottom-nav" Elevation="8">
<MudStack Row="true" Justify="Justify.SpaceAround" AlignItems="AlignItems.Center" Class="py-1">
@if (IsInRegularStore && _isAuthenticated)
{
@* ── Regular store bottom nav ── *@
<MudLink Href="@(RouteConstants.Store.Products)" Class="bottom-nav-item">
<MudIcon Icon="@Icons.Material.Outlined.Storefront" Size="Size.Medium" />
<MudText Typo="Typo.caption">محصولات</MudText>
</MudLink>
<MudLink Href="@(RouteConstants.Store.Cart)" Class="bottom-nav-item">
<MudIcon Icon="@Icons.Material.Outlined.ShoppingCart" Size="Size.Medium" Color="@(_cartCount > 0 ? Color.Success : Color.Default)" />
<MudText Typo="Typo.caption">سبد خرید</MudText>
</MudLink>
<MudLink Href="@(RouteConstants.Store.Orders)" Class="bottom-nav-item">
<MudIcon Icon="@Icons.Material.Outlined.Receipt" Size="Size.Medium" />
<MudText Typo="Typo.caption">سفارشات</MudText>
</MudLink>
<MudLink Href="@(RouteConstants.Profile.Index)" Class="bottom-nav-item">
<MudIcon Icon="@Icons.Material.Outlined.Home" Size="Size.Medium" />
<MudText Typo="Typo.caption">داشبورد</MudText>
</MudLink>
}
else if (IsInDiscountStore && _isAuthenticated)
{
@* ── Discount store bottom nav ── *@
<MudLink Href="@(RouteConstants.DiscountStore.Products)" Class="bottom-nav-item">
<MudIcon Icon="@Icons.Material.Outlined.Loyalty" Size="Size.Medium" Color="Color.Error" />
<MudText Typo="Typo.caption">محصولات</MudText>
</MudLink>
<MudLink Href="@(RouteConstants.DiscountStore.Cart)" Class="bottom-nav-item">
<MudIcon Icon="@Icons.Material.Outlined.ShoppingCart" Size="Size.Medium" Color="@(_discountCartCount > 0 ? Color.Error : Color.Default)" />
<MudText Typo="Typo.caption">سبد خرید</MudText>
</MudLink>
<MudLink Href="@(RouteConstants.DiscountStore.Orders)" Class="bottom-nav-item">
<MudIcon Icon="@Icons.Material.Outlined.Receipt" Size="Size.Medium" />
<MudText Typo="Typo.caption">سفارشات</MudText>
</MudLink>
<MudLink Href="@(RouteConstants.Profile.Index)" Class="bottom-nav-item">
<MudIcon Icon="@Icons.Material.Outlined.Home" Size="Size.Medium" />
<MudText Typo="Typo.caption">داشبورد</MudText>
</MudLink>
}
else
{
@* ── Default bottom nav (outside stores) ── *@
<MudLink Href="@(RouteConstants.Profile.Index)" Class="bottom-nav-item">
<MudIcon Icon="@Icons.Material.Outlined.Home" Size="Size.Medium" />
<MudText Typo="Typo.caption">خانه</MudText>
</MudLink>
@if (_isAuthenticated)
{
<MudLink Href="@(RouteConstants.Gateway.StoreChooser)" Class="bottom-nav-item">
<MudIcon Icon="@Icons.Material.Outlined.Store" Size="Size.Medium" />
<MudText Typo="Typo.caption">فروشگاه‌ها</MudText>
</MudLink>
}
<MudLink Href="@(RouteConstants.Blog.Index)" Class="bottom-nav-item">
<MudIcon Icon="@Icons.Material.Outlined.Article" Size="Size.Medium" />
<MudText Typo="Typo.caption">بلاگ</MudText>
</MudLink>
@if (_isAuthenticated)
{
<MudLink Href="@(RouteConstants.Profile.Hub)" Class="bottom-nav-item">
<MudIcon Icon="@Icons.Material.Outlined.Person" Size="Size.Medium" />
<MudText Typo="Typo.caption">پروفایل</MudText>
</MudLink>
}
else
{
<MudLink Class="bottom-nav-item" @onclick="OpenAuthDialog">
<MudIcon Icon="@Icons.Material.Outlined.Login" Size="Size.Medium" />
<MudText Typo="Typo.caption">ورود</MudText>
</MudLink>
}
}
</MudStack>
</MudPaper>
</MudHidden>
</MudLayout>
</MudRTLProvider>