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,192 +1,280 @@
|
||||
@attribute [Route(RouteConstants.About.Index)]
|
||||
@inject NavigationManager Navigation
|
||||
@inject SitePageService SitePageService
|
||||
|
||||
<PageTitle>درباره ما | کارا بازار سلامت</PageTitle>
|
||||
|
||||
<!-- Hero Section -->
|
||||
<section class="about-hero-section py-16">
|
||||
<MudContainer MaxWidth="MaxWidth.Large">
|
||||
<MudGrid Justify="Justify.Center" Spacing="4">
|
||||
<MudItem xs="12" md="6">
|
||||
<MudChip T="string" Color="Color.Secondary" Variant="Variant.Filled" Class="mb-2">درباره کارا بازار سلامت</MudChip>
|
||||
<MudStack Spacing="3">
|
||||
<MudText Typo="Typo.h2" Class="mb-3">
|
||||
پلتفرم هوشمند تیمسازی و مدیریت فروش
|
||||
</MudText>
|
||||
<MudText Typo="Typo.body1" Class="mud-text-secondary mb-4">
|
||||
ما با ارائه ابزارهای نوآورانه، به کسبوکارها کمک میکنیم تا تیمهای فروش خود را گسترش دهند و به صورت کارآمد مدیریت کنند.
|
||||
</MudText>
|
||||
<MudStack Row="true" Spacing="2">
|
||||
<MudButton Variant="Variant.Filled"
|
||||
Color="Color.Primary"
|
||||
Size="Size.Large"
|
||||
OnClick="() => Navigation.NavigateTo(RouteConstants.Main.MainPage)">
|
||||
شروع کنید
|
||||
</MudButton>
|
||||
<MudButton Variant="Variant.Outlined"
|
||||
Color="Color.Primary"
|
||||
Size="Size.Large"
|
||||
OnClick="ScrollToContact">
|
||||
تماس با ما
|
||||
</MudButton>
|
||||
</MudStack>
|
||||
</MudStack>
|
||||
</MudItem>
|
||||
<MudItem xs="12" md="6">
|
||||
<MudPaper Class="pa-8 rounded-xl" Style="background: radial-gradient(600px 280px at 120% 0, #daccff 0, transparent 60%), radial-gradient(600px 280px at -10% 100%, #ffe2f2 0, transparent 60%), linear-gradient(180deg, #fff, #fbfaff);">
|
||||
<MudImage Src="images/team-work.jpg"
|
||||
Alt="جلسه تیم فروش"
|
||||
ObjectFit="ObjectFit.Cover"
|
||||
ObjectPosition="ObjectPosition.Center"
|
||||
Style="width:100%"
|
||||
Class="rounded-xl" />
|
||||
</MudPaper>
|
||||
</MudItem>
|
||||
</MudGrid>
|
||||
@if (_loading)
|
||||
{
|
||||
<MudContainer MaxWidth="MaxWidth.Large" Class="py-16">
|
||||
<LoadingState />
|
||||
</MudContainer>
|
||||
</section>
|
||||
|
||||
<MudStack Spacing="8">
|
||||
|
||||
<!-- Mission & Vision -->
|
||||
<section class="py-12">
|
||||
}
|
||||
else
|
||||
{
|
||||
<!-- Hero Section -->
|
||||
<section class="about-hero-section py-16">
|
||||
<MudContainer MaxWidth="MaxWidth.Large">
|
||||
<MudText Typo="Typo.h3" Align="Align.Center" Class="mb-8">چشمانداز و مأموریت ما</MudText>
|
||||
<MudGrid Spacing="4" Justify="Justify.Center">
|
||||
<MudGrid Justify="Justify.Center" Spacing="4">
|
||||
<MudItem xs="12" md="6">
|
||||
<MudPaper Elevation="3" Class="pa-6 text-center h-100">
|
||||
<MudIcon Icon="@Icons.Material.Filled.Visibility" Size="Size.Large" Color="Color.Primary" Class="mb-4" />
|
||||
<MudText Typo="Typo.h5" Class="mb-3">چشمانداز</MudText>
|
||||
<MudText Typo="Typo.body1" Class="mud-text-secondary">
|
||||
تبدیل شدن به پیشروترین پلتفرم مدیریت تیمهای فروش در منطقه، با ارائه راهکارهای هوشمند و کاربرپسند برای کسبوکارهای کوچک و بزرگ.
|
||||
<MudChip T="string" Color="Color.Secondary" Variant="Variant.Filled" Class="mb-2">درباره کارا بازار سلامت</MudChip>
|
||||
<MudStack Spacing="3">
|
||||
<MudText Typo="Typo.h2" Class="mb-3">
|
||||
@(_page?.HeroTitle ?? "پلتفرم هوشمند تیمسازی و مدیریت فروش")
|
||||
</MudText>
|
||||
</MudPaper>
|
||||
<MudText Typo="Typo.body1" Class="mud-text-secondary mb-4">
|
||||
@(_page?.HeroSubtitle ?? "ما با ارائه ابزارهای نوآورانه، به کسبوکارها کمک میکنیم تا تیمهای فروش خود را گسترش دهند و به صورت کارآمد مدیریت کنند.")
|
||||
</MudText>
|
||||
<MudStack Row="true" Spacing="2" Class="flex-wrap">
|
||||
<MudButton Variant="Variant.Filled"
|
||||
Color="Color.Primary"
|
||||
Size="Size.Large"
|
||||
OnClick="() => Navigation.NavigateTo(RouteConstants.Main.MainPage)">
|
||||
شروع کنید
|
||||
</MudButton>
|
||||
<MudButton Variant="Variant.Outlined"
|
||||
Color="Color.Primary"
|
||||
Size="Size.Large"
|
||||
OnClick="() => Navigation.NavigateTo(RouteConstants.Contact.Index)">
|
||||
تماس با ما
|
||||
</MudButton>
|
||||
</MudStack>
|
||||
</MudStack>
|
||||
</MudItem>
|
||||
<MudItem xs="12" md="6">
|
||||
<MudPaper Elevation="3" Class="pa-6 text-center h-100">
|
||||
<MudIcon Icon="@Icons.Material.Filled.TrackChanges" Size="Size.Large" Color="Color.Success" Class="mb-4" />
|
||||
<MudText Typo="Typo.h5" Class="mb-3">مأموریت</MudText>
|
||||
<MudText Typo="Typo.body1" Class="mud-text-secondary">
|
||||
توانمندسازی کسبوکارها از طریق فناوریهای نوین، سادهسازی فرآیندهای پیچیده و ایجاد کارا بازار سلامتهای جدید برای رشد و توسعه پایدار.
|
||||
</MudText>
|
||||
<MudPaper Class="pa-8 rounded-xl" Style="background: radial-gradient(600px 280px at 120% 0, #daccff 0, transparent 60%), radial-gradient(600px 280px at -10% 100%, #ffe2f2 0, transparent 60%), linear-gradient(180deg, #fff, #fbfaff);">
|
||||
<AppImage Path="@(_page?.HeroImagePath ?? "images/team-work.jpg")"
|
||||
Alt="جلسه تیم فروش"
|
||||
ObjectFit="ObjectFit.Cover"
|
||||
ObjectPosition="ObjectPosition.Center"
|
||||
Style="width:100%"
|
||||
Class="rounded-xl" />
|
||||
</MudPaper>
|
||||
</MudItem>
|
||||
</MudGrid>
|
||||
</MudContainer>
|
||||
</section>
|
||||
|
||||
<!-- Company Values -->
|
||||
<section class="py-12 bg-grey-50">
|
||||
<MudContainer MaxWidth="MaxWidth.Large">
|
||||
<MudText Typo="Typo.h3" Align="Align.Center" Class="mb-8">ارزشهای ما</MudText>
|
||||
<MudGrid Spacing="3" Justify="Justify.Center">
|
||||
<MudItem xs="12" sm="6" md="4">
|
||||
<MudPaper Elevation="2" Class="pa-4 rounded-xl text-center">
|
||||
<MudIcon Icon="@Icons.Material.Filled.Security" Size="Size.Large" Color="Color.Info" Class="mb-3" />
|
||||
<MudText Typo="Typo.h6" Class="mb-2">صداقت و شفافیت</MudText>
|
||||
<MudText Typo="Typo.body2" Class="mud-text-secondary">
|
||||
در تمامی تعاملات خود با مشتریان و همکاران، صداقت و شفافیت را سرلوحه کار خود قرار دادهایم.
|
||||
</MudText>
|
||||
</MudPaper>
|
||||
</MudItem>
|
||||
<MudItem xs="12" sm="6" md="4">
|
||||
<MudPaper Elevation="2" Class="pa-4 rounded-xl text-center">
|
||||
<MudIcon Icon="@Icons.Material.Filled.Lightbulb" Size="Size.Large" Color="Color.Warning" Class="mb-3" />
|
||||
<MudText Typo="Typo.h6" Class="mb-2">نوآوری</MudText>
|
||||
<MudText Typo="Typo.body2" Class="mud-text-secondary">
|
||||
همواره در پی یافتن راهکارهای جدید و بهبود فرآیندها هستیم تا بهترین تجربه را برای کاربران فراهم کنیم.
|
||||
</MudText>
|
||||
</MudPaper>
|
||||
</MudItem>
|
||||
<MudItem xs="12" sm="6" md="4">
|
||||
<MudPaper Elevation="2" Class="pa-4 rounded-xl text-center">
|
||||
<MudIcon Icon="@Icons.Material.Filled.Group" Size="Size.Large" Color="Color.Success" Class="mb-3" />
|
||||
<MudText Typo="Typo.h6" Class="mb-2">مشتریمداری</MudText>
|
||||
<MudText Typo="Typo.body2" Class="mud-text-secondary">
|
||||
رضایت و موفقیت مشتریان اولویت اصلی ما است و تمامی تصمیمات خود را بر اساس نیازهای آنها میگیریم.
|
||||
</MudText>
|
||||
</MudPaper>
|
||||
</MudItem>
|
||||
<MudItem xs="12" sm="6" md="4">
|
||||
<MudPaper Elevation="2" Class="pa-4 rounded-xl text-center">
|
||||
<MudIcon Icon="@Icons.Material.Filled.Verified" Size="Size.Large" Color="Color.Primary" Class="mb-3" />
|
||||
<MudText Typo="Typo.h6" Class="mb-2">کیفیت</MudText>
|
||||
<MudText Typo="Typo.body2" Class="mud-text-secondary">
|
||||
به کیفیت محصولات و خدمات خود افتخار میکنیم و همواره استانداردهای بالایی را رعایت میکنیم.
|
||||
</MudText>
|
||||
</MudPaper>
|
||||
</MudItem>
|
||||
<MudItem xs="12" sm="6" md="4">
|
||||
<MudPaper Elevation="2" Class="pa-4 rounded-xl text-center">
|
||||
<MudIcon Icon="@Icons.Material.Filled.AccessTime" Size="Size.Large" Color="Color.Secondary" Class="mb-3" />
|
||||
<MudText Typo="Typo.h6" Class="mb-2">پاسخگویی</MudText>
|
||||
<MudText Typo="Typo.body2" Class="mud-text-secondary">
|
||||
به سرعت به نیازهای مشتریان پاسخ میدهیم و پشتیبانی ۲۴ ساعته را فراهم کردهایم.
|
||||
</MudText>
|
||||
</MudPaper>
|
||||
</MudItem>
|
||||
<MudItem xs="12" sm="6" md="4">
|
||||
<MudPaper Elevation="2" Class="pa-4 rounded-xl text-center">
|
||||
<MudIcon Icon="@Icons.Material.Filled.EmergencyRecording" Size="Size.Large" Color="Color.Error" Class="mb-3" />
|
||||
<MudText Typo="Typo.h6" Class="mb-2">پایداری</MudText>
|
||||
<MudText Typo="Typo.body2" Class="mud-text-secondary">
|
||||
به دنبال ایجاد ارزش بلندمدت برای مشتریان و جامعه هستیم و به توسعه پایدار متعهد هستیم.
|
||||
</MudText>
|
||||
</MudPaper>
|
||||
</MudItem>
|
||||
</MudGrid>
|
||||
</MudContainer>
|
||||
</section>
|
||||
<MudStack Spacing="8">
|
||||
|
||||
<!-- Team Section -->
|
||||
<section class="pb-12 bg-grey-50">
|
||||
<MudContainer MaxWidth="MaxWidth.Large">
|
||||
<MudText Typo="Typo.h3" Align="Align.Center" Class="mb-8">تیم ما</MudText>
|
||||
<MudGrid Spacing="4" Justify="Justify.Center">
|
||||
<MudItem xs="12" sm="6" md="4">
|
||||
<MudPaper Elevation="3" Class="pa-4 text-center">
|
||||
<MudAvatar Size="Size.Large" Class="mb-3">
|
||||
<MudImage ObjectFit="ObjectFit.Cover"
|
||||
ObjectPosition="ObjectPosition.Center"
|
||||
Src="images/avatar3.jpg" />
|
||||
</MudAvatar>
|
||||
<MudText Typo="Typo.h6" Class="mb-1">علی رضایی</MudText>
|
||||
<MudText Typo="Typo.body2" Class="mud-text-secondary mb-2">مدیرعامل</MudText>
|
||||
<MudText Typo="Typo.caption" Class="mud-text-secondary">
|
||||
بیش از ۱۰ سال تجربه در حوزه فناوری و مدیریت کسبوکار
|
||||
</MudText>
|
||||
</MudPaper>
|
||||
</MudItem>
|
||||
<MudItem xs="12" sm="6" md="4">
|
||||
<MudPaper Elevation="3" Class="pa-4 text-center">
|
||||
<MudAvatar Size="Size.Large" Class="mb-3">
|
||||
<MudImage ObjectFit="ObjectFit.Cover"
|
||||
ObjectPosition="ObjectPosition.Center"
|
||||
Src="images/avatar4.jpg" />
|
||||
</MudAvatar>
|
||||
<MudText Typo="Typo.h6" Class="mb-1">مریم احمدی</MudText>
|
||||
<MudText Typo="Typo.body2" Class="mud-text-secondary mb-2">مدیر محصول</MudText>
|
||||
<MudText Typo="Typo.caption" Class="mud-text-secondary">
|
||||
متخصص در طراحی تجربه کاربری و توسعه محصول
|
||||
</MudText>
|
||||
</MudPaper>
|
||||
</MudItem>
|
||||
<MudItem xs="12" sm="6" md="4">
|
||||
<MudPaper Elevation="3" Class="pa-4 text-center">
|
||||
<MudAvatar Size="Size.Large" Class="mb-3">
|
||||
<MudImage ObjectFit="ObjectFit.Cover"
|
||||
ObjectPosition="ObjectPosition.Center"
|
||||
Src="images/avatar5.jpg" />
|
||||
</MudAvatar>
|
||||
<MudText Typo="Typo.h6" Class="mb-1">حسن کریمی</MudText>
|
||||
<MudText Typo="Typo.body2" Class="mud-text-secondary mb-2">مدیر فنی</MudText>
|
||||
<MudText Typo="Typo.caption" Class="mud-text-secondary">
|
||||
مهندس نرمافزار با تخصص در معماری سیستمهای توزیعشده
|
||||
</MudText>
|
||||
</MudPaper>
|
||||
</MudItem>
|
||||
</MudGrid>
|
||||
</MudContainer>
|
||||
</section>
|
||||
</MudStack>
|
||||
<!-- Mission & Vision -->
|
||||
<section class="py-12">
|
||||
<MudContainer MaxWidth="MaxWidth.Large">
|
||||
<MudText Typo="Typo.h3" Align="Align.Center" Class="mb-8">چشمانداز و مأموریت ما</MudText>
|
||||
<MudGrid Spacing="4" Justify="Justify.Center">
|
||||
<MudItem xs="12" md="6">
|
||||
<MudPaper Elevation="2" Class="pa-6 text-center h-100">
|
||||
<MudIcon Icon="@Icons.Material.Filled.Visibility" Size="Size.Large" Color="Color.Primary" Class="mb-4" />
|
||||
<MudText Typo="Typo.h5" Class="mb-3">
|
||||
@(_visionSection?.Title ?? "چشمانداز")
|
||||
</MudText>
|
||||
@if (!string.IsNullOrWhiteSpace(_visionSection?.HtmlContent))
|
||||
{
|
||||
<MudText Typo="Typo.body1" Class="mud-text-secondary">
|
||||
@((MarkupString)_visionSection.HtmlContent)
|
||||
</MudText>
|
||||
}
|
||||
else
|
||||
{
|
||||
<MudText Typo="Typo.body1" Class="mud-text-secondary">
|
||||
تبدیل شدن به پیشروترین پلتفرم مدیریت تیمهای فروش در منطقه، با ارائه راهکارهای هوشمند و کاربرپسند برای کسبوکارهای کوچک و بزرگ.
|
||||
</MudText>
|
||||
}
|
||||
</MudPaper>
|
||||
</MudItem>
|
||||
<MudItem xs="12" md="6">
|
||||
<MudPaper Elevation="2" Class="pa-6 text-center h-100">
|
||||
<MudIcon Icon="@Icons.Material.Filled.TrackChanges" Size="Size.Large" Color="Color.Success" Class="mb-4" />
|
||||
<MudText Typo="Typo.h5" Class="mb-3">
|
||||
@(_missionSection?.Title ?? "مأموریت")
|
||||
</MudText>
|
||||
@if (!string.IsNullOrWhiteSpace(_missionSection?.HtmlContent))
|
||||
{
|
||||
<MudText Typo="Typo.body1" Class="mud-text-secondary">
|
||||
@((MarkupString)_missionSection.HtmlContent)
|
||||
</MudText>
|
||||
}
|
||||
else
|
||||
{
|
||||
<MudText Typo="Typo.body1" Class="mud-text-secondary">
|
||||
توانمندسازی کسبوکارها از طریق فناوریهای نوین، سادهسازی فرآیندهای پیچیده و ایجاد کارا بازار سلامتهای جدید برای رشد و توسعه پایدار.
|
||||
</MudText>
|
||||
}
|
||||
</MudPaper>
|
||||
</MudItem>
|
||||
</MudGrid>
|
||||
</MudContainer>
|
||||
</section>
|
||||
|
||||
<!-- Company Values -->
|
||||
<section class="py-12 bg-grey-50">
|
||||
<MudContainer MaxWidth="MaxWidth.Large">
|
||||
<MudText Typo="Typo.h3" Align="Align.Center" Class="mb-8">ارزشهای ما</MudText>
|
||||
<MudGrid Spacing="3" Justify="Justify.Center">
|
||||
@if (_valueSections.Any())
|
||||
{
|
||||
@foreach (var value in _valueSections)
|
||||
{
|
||||
<MudItem xs="12" sm="6" md="4">
|
||||
<MudPaper Elevation="2" Class="pa-4 rounded-xl text-center">
|
||||
@if (!string.IsNullOrWhiteSpace(value.IconName))
|
||||
{
|
||||
<MudIcon Icon="@value.IconName" Size="Size.Large" Color="Color.Primary" Class="mb-3" />
|
||||
}
|
||||
<MudText Typo="Typo.h6" Class="mb-2">@value.Title</MudText>
|
||||
@if (!string.IsNullOrWhiteSpace(value.HtmlContent))
|
||||
{
|
||||
<MudText Typo="Typo.body2" Class="mud-text-secondary">
|
||||
@((MarkupString)value.HtmlContent)
|
||||
</MudText>
|
||||
}
|
||||
</MudPaper>
|
||||
</MudItem>
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@* Fallback: hardcoded values *@
|
||||
<MudItem xs="12" sm="6" md="4">
|
||||
<MudPaper Elevation="2" Class="pa-4 rounded-xl text-center">
|
||||
<MudIcon Icon="@Icons.Material.Filled.Security" Size="Size.Large" Color="Color.Info" Class="mb-3" />
|
||||
<MudText Typo="Typo.h6" Class="mb-2">صداقت و شفافیت</MudText>
|
||||
<MudText Typo="Typo.body2" Class="mud-text-secondary">
|
||||
در تمامی تعاملات خود با مشتریان و همکاران، صداقت و شفافیت را سرلوحه کار خود قرار دادهایم.
|
||||
</MudText>
|
||||
</MudPaper>
|
||||
</MudItem>
|
||||
<MudItem xs="12" sm="6" md="4">
|
||||
<MudPaper Elevation="2" Class="pa-4 rounded-xl text-center">
|
||||
<MudIcon Icon="@Icons.Material.Filled.Lightbulb" Size="Size.Large" Color="Color.Warning" Class="mb-3" />
|
||||
<MudText Typo="Typo.h6" Class="mb-2">نوآوری</MudText>
|
||||
<MudText Typo="Typo.body2" Class="mud-text-secondary">
|
||||
همواره در پی یافتن راهکارهای جدید و بهبود فرآیندها هستیم تا بهترین تجربه را برای کاربران فراهم کنیم.
|
||||
</MudText>
|
||||
</MudPaper>
|
||||
</MudItem>
|
||||
<MudItem xs="12" sm="6" md="4">
|
||||
<MudPaper Elevation="2" Class="pa-4 rounded-xl text-center">
|
||||
<MudIcon Icon="@Icons.Material.Filled.Group" Size="Size.Large" Color="Color.Success" Class="mb-3" />
|
||||
<MudText Typo="Typo.h6" Class="mb-2">مشتریمداری</MudText>
|
||||
<MudText Typo="Typo.body2" Class="mud-text-secondary">
|
||||
رضایت و موفقیت مشتریان اولویت اصلی ما است و تمامی تصمیمات خود را بر اساس نیازهای آنها میگیریم.
|
||||
</MudText>
|
||||
</MudPaper>
|
||||
</MudItem>
|
||||
<MudItem xs="12" sm="6" md="4">
|
||||
<MudPaper Elevation="2" Class="pa-4 rounded-xl text-center">
|
||||
<MudIcon Icon="@Icons.Material.Filled.Verified" Size="Size.Large" Color="Color.Primary" Class="mb-3" />
|
||||
<MudText Typo="Typo.h6" Class="mb-2">کیفیت</MudText>
|
||||
<MudText Typo="Typo.body2" Class="mud-text-secondary">
|
||||
به کیفیت محصولات و خدمات خود افتخار میکنیم و همواره استانداردهای بالایی را رعایت میکنیم.
|
||||
</MudText>
|
||||
</MudPaper>
|
||||
</MudItem>
|
||||
<MudItem xs="12" sm="6" md="4">
|
||||
<MudPaper Elevation="2" Class="pa-4 rounded-xl text-center">
|
||||
<MudIcon Icon="@Icons.Material.Filled.AccessTime" Size="Size.Large" Color="Color.Secondary" Class="mb-3" />
|
||||
<MudText Typo="Typo.h6" Class="mb-2">پاسخگویی</MudText>
|
||||
<MudText Typo="Typo.body2" Class="mud-text-secondary">
|
||||
به سرعت به نیازهای مشتریان پاسخ میدهیم و پشتیبانی ۲۴ ساعته را فراهم کردهایم.
|
||||
</MudText>
|
||||
</MudPaper>
|
||||
</MudItem>
|
||||
<MudItem xs="12" sm="6" md="4">
|
||||
<MudPaper Elevation="2" Class="pa-4 rounded-xl text-center">
|
||||
<MudIcon Icon="@Icons.Material.Filled.EmergencyRecording" Size="Size.Large" Color="Color.Error" Class="mb-3" />
|
||||
<MudText Typo="Typo.h6" Class="mb-2">پایداری</MudText>
|
||||
<MudText Typo="Typo.body2" Class="mud-text-secondary">
|
||||
به دنبال ایجاد ارزش بلندمدت برای مشتریان و جامعه هستیم و به توسعه پایدار متعهد هستیم.
|
||||
</MudText>
|
||||
</MudPaper>
|
||||
</MudItem>
|
||||
}
|
||||
</MudGrid>
|
||||
</MudContainer>
|
||||
</section>
|
||||
|
||||
<!-- Team Section -->
|
||||
<section class="pb-12 bg-grey-50">
|
||||
<MudContainer MaxWidth="MaxWidth.Large">
|
||||
<MudText Typo="Typo.h3" Align="Align.Center" Class="mb-8">تیم ما</MudText>
|
||||
<MudGrid Spacing="4" Justify="Justify.Center">
|
||||
@if (_teamSections.Any())
|
||||
{
|
||||
@foreach (var member in _teamSections)
|
||||
{
|
||||
<MudItem xs="12" sm="6" md="4">
|
||||
<MudPaper Elevation="2" Class="pa-4 text-center">
|
||||
<MudAvatar Size="Size.Large" Class="mb-3">
|
||||
@if (!string.IsNullOrWhiteSpace(member.ImagePath))
|
||||
{
|
||||
<AppImage Path="@member.ImagePath"
|
||||
ObjectFit="ObjectFit.Cover"
|
||||
ObjectPosition="ObjectPosition.Center" />
|
||||
}
|
||||
else
|
||||
{
|
||||
<MudIcon Icon="@Icons.Material.Filled.Person" />
|
||||
}
|
||||
</MudAvatar>
|
||||
<MudText Typo="Typo.h6" Class="mb-1">@member.Title</MudText>
|
||||
@if (!string.IsNullOrWhiteSpace(member.Subtitle))
|
||||
{
|
||||
<MudText Typo="Typo.body2" Class="mud-text-secondary mb-2">@member.Subtitle</MudText>
|
||||
}
|
||||
@if (!string.IsNullOrWhiteSpace(member.HtmlContent))
|
||||
{
|
||||
<MudText Typo="Typo.caption" Class="mud-text-secondary">
|
||||
@((MarkupString)member.HtmlContent)
|
||||
</MudText>
|
||||
}
|
||||
</MudPaper>
|
||||
</MudItem>
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@* Fallback: hardcoded team *@
|
||||
<MudItem xs="12" sm="6" md="4">
|
||||
<MudPaper Elevation="2" Class="pa-4 text-center">
|
||||
<MudAvatar Size="Size.Large" Class="mb-3">
|
||||
<MudImage ObjectFit="ObjectFit.Cover" ObjectPosition="ObjectPosition.Center" Src="images/avatar3.jpg" />
|
||||
</MudAvatar>
|
||||
<MudText Typo="Typo.h6" Class="mb-1">علی رضایی</MudText>
|
||||
<MudText Typo="Typo.body2" Class="mud-text-secondary mb-2">مدیرعامل</MudText>
|
||||
<MudText Typo="Typo.caption" Class="mud-text-secondary">
|
||||
بیش از ۱۰ سال تجربه در حوزه فناوری و مدیریت کسبوکار
|
||||
</MudText>
|
||||
</MudPaper>
|
||||
</MudItem>
|
||||
<MudItem xs="12" sm="6" md="4">
|
||||
<MudPaper Elevation="2" Class="pa-4 text-center">
|
||||
<MudAvatar Size="Size.Large" Class="mb-3">
|
||||
<MudImage ObjectFit="ObjectFit.Cover" ObjectPosition="ObjectPosition.Center" Src="images/avatar4.jpg" />
|
||||
</MudAvatar>
|
||||
<MudText Typo="Typo.h6" Class="mb-1">مریم احمدی</MudText>
|
||||
<MudText Typo="Typo.body2" Class="mud-text-secondary mb-2">مدیر محصول</MudText>
|
||||
<MudText Typo="Typo.caption" Class="mud-text-secondary">
|
||||
متخصص در طراحی تجربه کاربری و توسعه محصول
|
||||
</MudText>
|
||||
</MudPaper>
|
||||
</MudItem>
|
||||
<MudItem xs="12" sm="6" md="4">
|
||||
<MudPaper Elevation="2" Class="pa-4 text-center">
|
||||
<MudAvatar Size="Size.Large" Class="mb-3">
|
||||
<MudImage ObjectFit="ObjectFit.Cover" ObjectPosition="ObjectPosition.Center" Src="images/avatar5.jpg" />
|
||||
</MudAvatar>
|
||||
<MudText Typo="Typo.h6" Class="mb-1">حسن کریمی</MudText>
|
||||
<MudText Typo="Typo.body2" Class="mud-text-secondary mb-2">مدیر فنی</MudText>
|
||||
<MudText Typo="Typo.caption" Class="mud-text-secondary">
|
||||
مهندس نرمافزار با تخصص در معماری سیستمهای توزیعشده
|
||||
</MudText>
|
||||
</MudPaper>
|
||||
</MudItem>
|
||||
}
|
||||
</MudGrid>
|
||||
</MudContainer>
|
||||
</section>
|
||||
</MudStack>
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,37 @@
|
||||
using FrontOffice.Main.Utilities;
|
||||
|
||||
namespace FrontOffice.Main.Pages;
|
||||
|
||||
public partial class About
|
||||
{
|
||||
private void ScrollToContact()
|
||||
private bool _loading = true;
|
||||
private SitePageDto? _page;
|
||||
private SitePageSectionDto? _visionSection;
|
||||
private SitePageSectionDto? _missionSection;
|
||||
private List<SitePageSectionDto> _valueSections = new();
|
||||
private List<SitePageSectionDto> _teamSections = new();
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
// TODO: Implement smooth scroll to contact section
|
||||
try
|
||||
{
|
||||
_page = await SitePageService.GetByKeyAsync("about");
|
||||
|
||||
if (_page != null)
|
||||
{
|
||||
_visionSection = _page.GetSection("vision");
|
||||
_missionSection = _page.GetSection("mission");
|
||||
_valueSections = _page.GetSections("value-").ToList();
|
||||
_teamSections = _page.GetSections("team-").ToList();
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Fallback: page remains null → hardcoded content will render
|
||||
}
|
||||
finally
|
||||
{
|
||||
_loading = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,172 @@
|
||||
@attribute [Route(RouteConstants.Blog.Index)]
|
||||
|
||||
<PageTitle>بلاگ | کارا بازار سلامت</PageTitle>
|
||||
|
||||
@* ═══════════════════════════════════════════════
|
||||
BLOG HEADER
|
||||
═══════════════════════════════════════════════ *@
|
||||
<section class="blog-hero">
|
||||
<MudContainer MaxWidth="MaxWidth.Large">
|
||||
<div class="text-center">
|
||||
<MudText Typo="Typo.h3" Class="dash-hero-name">بلاگ</MudText>
|
||||
<MudText Typo="Typo.body1" Class="dash-hero-sub mt-2">
|
||||
آخرین مطالب، آموزشها و اخبار کارا بازار سلامت
|
||||
</MudText>
|
||||
</div>
|
||||
</MudContainer>
|
||||
</section>
|
||||
|
||||
@* ═══════════════════════════════════════════════
|
||||
SEARCH + FILTERS
|
||||
═══════════════════════════════════════════════ *@
|
||||
<MudContainer MaxWidth="MaxWidth.Large" Class="py-6">
|
||||
|
||||
<MudPaper Elevation="0" Class="pa-4 rounded-xl mb-6" Style="border:1px solid var(--mud-palette-divider);">
|
||||
<MudGrid Spacing="3" AlignItems="AlignItems.Center">
|
||||
<MudItem xs="12" sm="6" md="5">
|
||||
<MudTextField @bind-Value="_searchTerm"
|
||||
Placeholder="جستجو در مقالات..."
|
||||
Variant="Variant.Outlined"
|
||||
Adornment="Adornment.Start"
|
||||
AdornmentIcon="@Icons.Material.Filled.Search"
|
||||
Immediate="false"
|
||||
OnKeyUp="OnSearchKeyUp"
|
||||
Class="rounded-lg" />
|
||||
</MudItem>
|
||||
<MudItem xs="12" sm="6" md="5">
|
||||
<MudSelect T="long?" Value="_selectedCategoryId"
|
||||
Placeholder="همه دستهبندیها"
|
||||
Variant="Variant.Outlined"
|
||||
Class="rounded-lg"
|
||||
Clearable="true"
|
||||
ValueChanged="OnCategoryChanged">
|
||||
@foreach (var cat in _categories)
|
||||
{
|
||||
<MudSelectItem T="long?" Value="@cat.Id">
|
||||
@cat.Title
|
||||
@if (cat.PostCount > 0)
|
||||
{
|
||||
<MudText Typo="Typo.caption" Class="mud-text-secondary mr-2" Style="display:inline;">(@cat.PostCount)</MudText>
|
||||
}
|
||||
</MudSelectItem>
|
||||
}
|
||||
</MudSelect>
|
||||
</MudItem>
|
||||
<MudItem xs="12" md="2">
|
||||
<MudButton Variant="Variant.Filled"
|
||||
Color="Color.Primary"
|
||||
FullWidth="true"
|
||||
Class="rounded-lg"
|
||||
StartIcon="@Icons.Material.Filled.Search"
|
||||
OnClick="SearchPosts">
|
||||
جستجو
|
||||
</MudButton>
|
||||
</MudItem>
|
||||
</MudGrid>
|
||||
</MudPaper>
|
||||
|
||||
@* ═══════════════════════════════════════════════
|
||||
BLOG POSTS GRID
|
||||
═══════════════════════════════════════════════ *@
|
||||
@if (_isLoading)
|
||||
{
|
||||
<LoadingState />
|
||||
}
|
||||
else if (!_posts.Any())
|
||||
{
|
||||
<MudPaper Elevation="0" Class="pa-12 text-center rounded-xl" Style="border:1px dashed var(--mud-palette-divider);">
|
||||
<MudIcon Icon="@Icons.Material.Outlined.Article" Size="Size.Large" Class="mud-text-secondary mb-3" Style="font-size:3.5rem;" />
|
||||
<MudText Typo="Typo.h6" Class="mud-text-secondary">مقالهای یافت نشد</MudText>
|
||||
<MudText Typo="Typo.body2" Class="mud-text-secondary mt-1">
|
||||
@if (!string.IsNullOrWhiteSpace(_searchTerm) || _selectedCategoryId.HasValue)
|
||||
{
|
||||
<span>فیلترها را تغییر دهید یا عبارت دیگری جستجو کنید.</span>
|
||||
}
|
||||
else
|
||||
{
|
||||
<span>بهزودی مقالات جدید منتشر خواهد شد.</span>
|
||||
}
|
||||
</MudText>
|
||||
</MudPaper>
|
||||
}
|
||||
else
|
||||
{
|
||||
<MudGrid Spacing="4">
|
||||
@foreach (var post in _posts)
|
||||
{
|
||||
<MudItem xs="12" sm="6" md="4">
|
||||
<MudPaper Elevation="1" Class="rounded-xl blog-card-v2 cursor-pointer" Style="overflow:hidden;"
|
||||
@onclick="() => NavigateToPost(post.Slug)">
|
||||
@* Thumbnail *@
|
||||
<div class="blog-thumb" style="height:200px; background:#f0f0f0;">
|
||||
@if (!string.IsNullOrWhiteSpace(post.ThumbnailUrl))
|
||||
{
|
||||
<AppImage Path="@post.ThumbnailUrl"
|
||||
Alt="@post.Title"
|
||||
ObjectFit="ObjectFit.Cover"
|
||||
Style="width:100%; height:200px;" />
|
||||
}
|
||||
else
|
||||
{
|
||||
<div style="height:200px; display:flex; align-items:center; justify-content:center; background:linear-gradient(135deg,#6366f1,#a78bfa);">
|
||||
<MudIcon Icon="@Icons.Material.Filled.Article" Size="Size.Large" Style="color:rgba(255,255,255,.4);" />
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
||||
@* Content *@
|
||||
<div class="pa-4">
|
||||
@if (post.Categories.Any())
|
||||
{
|
||||
<MudChip T="string" Size="Size.Small" Variant="Variant.Outlined"
|
||||
Color="Color.Primary" Class="mb-2">
|
||||
@post.Categories.First().Title
|
||||
</MudChip>
|
||||
}
|
||||
|
||||
<MudText Typo="Typo.h6" Class="mb-1 blog-title-clamp">
|
||||
@post.Title
|
||||
</MudText>
|
||||
|
||||
@if (!string.IsNullOrWhiteSpace(post.Summary))
|
||||
{
|
||||
<MudText Typo="Typo.body2" Class="mud-text-secondary mb-3 blog-summary-clamp">
|
||||
@post.Summary
|
||||
</MudText>
|
||||
}
|
||||
|
||||
<MudStack Row="true" AlignItems="AlignItems.Center" Class="mt-auto">
|
||||
@if (post.PublishedAt.HasValue)
|
||||
{
|
||||
<MudText Typo="Typo.caption" Class="mud-text-secondary">
|
||||
<MudIcon Icon="@Icons.Material.Filled.CalendarToday" Size="Size.Small" Class="ml-1" />
|
||||
@post.PublishedAt.Value.ToString("yyyy/MM/dd")
|
||||
</MudText>
|
||||
}
|
||||
<MudSpacer />
|
||||
<MudText Typo="Typo.caption" Class="mud-text-secondary">
|
||||
<MudIcon Icon="@Icons.Material.Filled.Visibility" Size="Size.Small" Class="ml-1" />
|
||||
@post.ViewCount.ToString("N0")
|
||||
</MudText>
|
||||
</MudStack>
|
||||
</div>
|
||||
</MudPaper>
|
||||
</MudItem>
|
||||
}
|
||||
</MudGrid>
|
||||
|
||||
@* ── Pagination ── *@
|
||||
@if (_totalPages > 1)
|
||||
{
|
||||
<div class="d-flex justify-center mt-8">
|
||||
<MudPagination Count="@_totalPages"
|
||||
Selected="@_currentPage"
|
||||
SelectedChanged="OnPageChanged"
|
||||
Color="Color.Primary"
|
||||
Variant="Variant.Outlined"
|
||||
Class="rounded-lg" />
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
||||
</MudContainer>
|
||||
@@ -0,0 +1,91 @@
|
||||
using FrontOffice.Main.Utilities;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Microsoft.AspNetCore.Components.Web;
|
||||
|
||||
namespace FrontOffice.Main.Pages.Blog;
|
||||
|
||||
public partial class Index
|
||||
{
|
||||
[Inject] private BlogPostService BlogPostService { get; set; } = default!;
|
||||
[Inject] private BlogCategoryService BlogCategoryService { get; set; } = default!;
|
||||
|
||||
// ── State ──
|
||||
private List<BlogPostCardDto> _posts = new();
|
||||
private List<BlogCategoryDto> _categories = new();
|
||||
private string? _searchTerm;
|
||||
private long? _selectedCategoryId;
|
||||
private int _currentPage = 1;
|
||||
private int _totalPages;
|
||||
private bool _isLoading = true;
|
||||
private const int PageSize = 9;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
// Load categories and posts in parallel
|
||||
var categoriesTask = BlogCategoryService.GetActiveCategoriesAsync();
|
||||
var postsTask = LoadPostsAsync();
|
||||
|
||||
_categories = await categoriesTask;
|
||||
await postsTask;
|
||||
}
|
||||
|
||||
private async Task LoadPostsAsync()
|
||||
{
|
||||
_isLoading = true;
|
||||
StateHasChanged();
|
||||
|
||||
try
|
||||
{
|
||||
var result = await BlogPostService.GetPublishedPostsAsync(
|
||||
page: _currentPage,
|
||||
pageSize: PageSize,
|
||||
search: _searchTerm,
|
||||
categoryId: _selectedCategoryId);
|
||||
|
||||
_posts = result.Posts;
|
||||
_totalPages = result.TotalPages;
|
||||
}
|
||||
catch
|
||||
{
|
||||
_posts = new();
|
||||
_totalPages = 0;
|
||||
}
|
||||
finally
|
||||
{
|
||||
_isLoading = false;
|
||||
StateHasChanged();
|
||||
}
|
||||
}
|
||||
|
||||
private async Task SearchPosts()
|
||||
{
|
||||
_currentPage = 1;
|
||||
await LoadPostsAsync();
|
||||
}
|
||||
|
||||
private async Task OnSearchKeyUp(KeyboardEventArgs e)
|
||||
{
|
||||
if (e.Key == "Enter")
|
||||
{
|
||||
await SearchPosts();
|
||||
}
|
||||
}
|
||||
|
||||
private async Task OnCategoryChanged(long? categoryId)
|
||||
{
|
||||
_selectedCategoryId = categoryId;
|
||||
_currentPage = 1;
|
||||
await LoadPostsAsync();
|
||||
}
|
||||
|
||||
private async Task OnPageChanged(int page)
|
||||
{
|
||||
_currentPage = page;
|
||||
await LoadPostsAsync();
|
||||
}
|
||||
|
||||
private void NavigateToPost(string slug)
|
||||
{
|
||||
Navigation.NavigateTo($"/blog/{slug}");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
@page "/blog/{Slug}"
|
||||
|
||||
<PageTitle>@(_post?.Title ?? "مقاله") | بلاگ</PageTitle>
|
||||
|
||||
@if (_isLoading)
|
||||
{
|
||||
<MudContainer MaxWidth="MaxWidth.Medium" Class="py-12">
|
||||
<LoadingState />
|
||||
</MudContainer>
|
||||
}
|
||||
else if (_post == null)
|
||||
{
|
||||
<MudContainer MaxWidth="MaxWidth.Medium" Class="py-12">
|
||||
<EmptyState Icon="@Icons.Material.Filled.SearchOff"
|
||||
Title="مقاله یافت نشد"
|
||||
Description="این مقاله حذف شده یا آدرس اشتباه است."
|
||||
ActionText="بازگشت به بلاگ"
|
||||
ActionHref="/blog" />
|
||||
</MudContainer>
|
||||
}
|
||||
else
|
||||
{
|
||||
@* ═══ Featured Image Header ═══ *@
|
||||
@if (!string.IsNullOrWhiteSpace(_post.FeaturedImagePath))
|
||||
{
|
||||
<div class="blog-detail-hero">
|
||||
<AppImage Path="@_post.FeaturedImagePath"
|
||||
Alt="@_post.Title"
|
||||
ObjectFit="ObjectFit.Cover"
|
||||
Style="width:100%; height:100%;" />
|
||||
<div class="blog-detail-hero-overlay"></div>
|
||||
</div>
|
||||
}
|
||||
|
||||
<MudContainer MaxWidth="MaxWidth.Medium" Class="py-6">
|
||||
@* ── Breadcrumb ── *@
|
||||
<MudStack Row="true" Spacing="1" AlignItems="AlignItems.Center" Class="mb-4">
|
||||
<MudLink Href="/" Typo="Typo.caption" Class="mud-text-secondary">خانه</MudLink>
|
||||
<MudIcon Icon="@Icons.Material.Filled.ChevronLeft" Size="Size.Small" Class="mud-text-secondary" />
|
||||
<MudLink Href="/blog" Typo="Typo.caption" Class="mud-text-secondary">بلاگ</MudLink>
|
||||
<MudIcon Icon="@Icons.Material.Filled.ChevronLeft" Size="Size.Small" Class="mud-text-secondary" />
|
||||
<MudText Typo="Typo.caption" Class="mud-text-secondary">@_post.Title</MudText>
|
||||
</MudStack>
|
||||
|
||||
@* ── Article Header ── *@
|
||||
<MudPaper Elevation="0" Class="pa-0 mb-6">
|
||||
@if (_post.Categories.Any())
|
||||
{
|
||||
<MudStack Row="true" Spacing="1" Class="mb-3 flex-wrap">
|
||||
@foreach (var cat in _post.Categories)
|
||||
{
|
||||
<MudChip T="string" Size="Size.Small" Variant="Variant.Filled"
|
||||
Color="Color.Primary" Class="rounded-pill"
|
||||
OnClick="() => NavigateToCategoryFilter(cat.Id)">
|
||||
@cat.Title
|
||||
</MudChip>
|
||||
}
|
||||
</MudStack>
|
||||
}
|
||||
|
||||
<MudText Typo="Typo.h4" Class="mb-3 fw-bold" Style="line-height:1.6;">
|
||||
@_post.Title
|
||||
</MudText>
|
||||
|
||||
@if (!string.IsNullOrWhiteSpace(_post.Summary))
|
||||
{
|
||||
<MudText Typo="Typo.subtitle1" Class="mud-text-secondary mb-4" Style="line-height:1.8;">
|
||||
@_post.Summary
|
||||
</MudText>
|
||||
}
|
||||
|
||||
<MudStack Row="true" Spacing="3" AlignItems="AlignItems.Center" Class="mb-4 flex-wrap">
|
||||
@if (_post.PublishedAt.HasValue)
|
||||
{
|
||||
<MudStack Row="true" Spacing="1" AlignItems="AlignItems.Center">
|
||||
<MudIcon Icon="@Icons.Material.Filled.CalendarToday" Size="Size.Small" Color="Color.Primary" />
|
||||
<MudText Typo="Typo.body2" Class="mud-text-secondary">
|
||||
@_post.PublishedAt.Value.ToString("yyyy/MM/dd")
|
||||
</MudText>
|
||||
</MudStack>
|
||||
}
|
||||
<MudStack Row="true" Spacing="1" AlignItems="AlignItems.Center">
|
||||
<MudIcon Icon="@Icons.Material.Filled.Visibility" Size="Size.Small" Color="Color.Primary" />
|
||||
<MudText Typo="Typo.body2" Class="mud-text-secondary">
|
||||
@_post.ViewCount.ToString("N0") بازدید
|
||||
</MudText>
|
||||
</MudStack>
|
||||
</MudStack>
|
||||
|
||||
<MudDivider Class="mb-6" />
|
||||
</MudPaper>
|
||||
|
||||
@* ── Article Content ── *@
|
||||
<MudPaper Elevation="0" Class="blog-content mb-8">
|
||||
@((MarkupString)_post.HtmlContent)
|
||||
</MudPaper>
|
||||
|
||||
@* ── Tags ── *@
|
||||
@if (_post.Tags.Any())
|
||||
{
|
||||
<MudDivider Class="mb-4" />
|
||||
<MudStack Row="true" Spacing="1" AlignItems="AlignItems.Center" Class="mb-6 flex-wrap">
|
||||
<MudIcon Icon="@Icons.Material.Filled.LocalOffer" Size="Size.Small" Class="mud-text-secondary ml-2" />
|
||||
@foreach (var tag in _post.Tags)
|
||||
{
|
||||
<MudChip T="string" Size="Size.Small" Variant="Variant.Outlined"
|
||||
Class="rounded-pill">
|
||||
@tag.Title
|
||||
</MudChip>
|
||||
}
|
||||
</MudStack>
|
||||
}
|
||||
|
||||
@* ── Back to Blog ── *@
|
||||
<div class="text-center mt-6 mb-4">
|
||||
<MudButton Variant="Variant.Outlined" Color="Color.Primary" OnClick="GoBack"
|
||||
Class="rounded-pill" StartIcon="@Icons.Material.Filled.ArrowForward">
|
||||
بازگشت به بلاگ
|
||||
</MudButton>
|
||||
</div>
|
||||
</MudContainer>
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
using FrontOffice.Main.Utilities;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Microsoft.JSInterop;
|
||||
|
||||
namespace FrontOffice.Main.Pages.Blog;
|
||||
|
||||
public partial class Post
|
||||
{
|
||||
[Inject] private IJSRuntime JS { get; set; } = default!;
|
||||
[Parameter] public string Slug { get; set; } = string.Empty;
|
||||
|
||||
[Inject] private BlogPostService BlogPostService { get; set; } = default!;
|
||||
|
||||
private BlogPostDetailDto? _post;
|
||||
private bool _isLoading = true;
|
||||
|
||||
protected override async Task OnParametersSetAsync()
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(Slug)) return;
|
||||
|
||||
_isLoading = true;
|
||||
StateHasChanged();
|
||||
|
||||
try
|
||||
{
|
||||
_post = await BlogPostService.GetBySlugAsync(Slug);
|
||||
|
||||
// Fire-and-forget: increment view count
|
||||
if (_post != null)
|
||||
{
|
||||
_ = BlogPostService.IncrementViewCountAsync(_post.Id);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
_post = null;
|
||||
}
|
||||
finally
|
||||
{
|
||||
_isLoading = false;
|
||||
StateHasChanged();
|
||||
}
|
||||
}
|
||||
|
||||
private void NavigateToCategoryFilter(long categoryId)
|
||||
{
|
||||
Navigation.NavigateTo($"/blog?category={categoryId}");
|
||||
}
|
||||
|
||||
private async Task GoBack() => await JS.InvokeVoidAsync("history.back");
|
||||
}
|
||||
@@ -5,10 +5,11 @@
|
||||
<PageTitle>تکمیل خرید</PageTitle>
|
||||
|
||||
<MudContainer MaxWidth="MaxWidth.Large" Class="py-6">
|
||||
<PageHeader Title="تکمیل خرید" BackHref="@RouteConstants.Package.List" />
|
||||
<MudGrid Spacing="4">
|
||||
<!-- Header -->
|
||||
<MudItem xs="12">
|
||||
<MudPaper Elevation="4" Class="pa-6">
|
||||
<MudPaper Elevation="2" Class="pa-4 rounded-lg">
|
||||
<MudStack Spacing="3">
|
||||
<MudStack Row="true" AlignItems="AlignItems.Center" Spacing="3">
|
||||
<MudIcon Icon="@Icons.Material.Filled.ShoppingCart" Size="Size.Large" Color="Color.Primary" />
|
||||
@@ -23,7 +24,7 @@
|
||||
<MudItem xs="12" md="8">
|
||||
<MudStack>
|
||||
<!-- Package Details -->
|
||||
<MudPaper Elevation="4" Class="pa-6">
|
||||
<MudPaper Elevation="2" Class="pa-4 rounded-lg">
|
||||
<MudText Typo="Typo.h5" Class="mb-4">جزئیات پکیج</MudText>
|
||||
|
||||
@if (_selectedPackage != null)
|
||||
@@ -33,9 +34,9 @@
|
||||
<MudGrid Spacing="3">
|
||||
<MudItem xs="12" md="4">
|
||||
<MudPaper Class="pa-2 rounded-xl" Style="background: radial-gradient(600px 280px at 120% 0, #daccff 0, transparent 60%), radial-gradient(600px 280px at -10% 100%, #ffe2f2 0, transparent 60%), linear-gradient(180deg, #fff, #fbfaff);">
|
||||
<MudImage Src="@_selectedPackage.Image"
|
||||
<AppImage Path="@_selectedPackage.Image"
|
||||
Alt="@_selectedPackage.Title"
|
||||
Height="150"
|
||||
ImgHeight="150"
|
||||
ObjectFit="ObjectFit.Cover"
|
||||
ObjectPosition="ObjectPosition.Center"
|
||||
Style="width:100%"
|
||||
@@ -67,7 +68,7 @@
|
||||
</MudPaper>
|
||||
|
||||
<!-- Address Selection -->
|
||||
<MudPaper Elevation="4" Class="pa-6">
|
||||
<MudPaper Elevation="2" Class="pa-4 rounded-lg">
|
||||
<MudText Typo="Typo.h5" Class="mb-4">انتخاب آدرس</MudText>
|
||||
|
||||
@if (_isLoadingAddresses)
|
||||
@@ -149,7 +150,7 @@
|
||||
<MudItem xs="12" md="4">
|
||||
<MudStack Spacing="4">
|
||||
<!-- Discount Code Section -->
|
||||
<MudPaper Elevation="4" Class="pa-6">
|
||||
<MudPaper Elevation="2" Class="pa-4 rounded-lg">
|
||||
<MudText Typo="Typo.h5" Class="mb-4">کد تخفیف</MudText>
|
||||
<MudStack Spacing="3">
|
||||
<MudTextField @bind-Value="_discountCode"
|
||||
@@ -176,7 +177,7 @@
|
||||
<!-- Order Summary -->
|
||||
@if (_selectedPackage != null)
|
||||
{
|
||||
<MudPaper Elevation="4" Class="pa-6">
|
||||
<MudPaper Elevation="2" Class="pa-4 rounded-lg">
|
||||
<MudText Typo="Typo.h5" Class="mb-4">خلاصه سفارش</MudText>
|
||||
|
||||
<MudStack Spacing="3">
|
||||
|
||||
@@ -59,7 +59,7 @@ public partial class Checkout
|
||||
Id: response.Id,
|
||||
Title: response.Title,
|
||||
Body: response.Description,
|
||||
Image: UrlUtility.DownloadUrl + response.ImagePath,
|
||||
Image: response.ImagePath ?? string.Empty,
|
||||
Price: response.Price
|
||||
);
|
||||
_finalPrice = _selectedPackage.Price;
|
||||
|
||||
@@ -3,15 +3,13 @@
|
||||
@using MudBlazor
|
||||
@inject ClubConfigurationService ClubConfigService
|
||||
@inject IDialogService DialogService
|
||||
@inject IJSRuntime JS
|
||||
|
||||
<PageTitle>ویژگیهای باشگاه مشتریان</PageTitle>
|
||||
|
||||
<MudContainer MaxWidth="MaxWidth.Large" 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.Club.Membership">بازگشت</MudButton>
|
||||
</MudStack>
|
||||
<PageHeader Title="ویژگیهای باشگاه مشتریان" BackHref="@RouteConstants.Club.Membership" />
|
||||
|
||||
<!-- توضیحات کلی باشگاه -->
|
||||
<MudPaper Elevation="2" Class="pa-4 rounded-lg">
|
||||
@@ -30,13 +28,13 @@
|
||||
|
||||
@if (_isLoading)
|
||||
{
|
||||
<MudProgressLinear Color="Color.Primary" Indeterminate="true" />
|
||||
<LoadingState Message="در حال دریافت ویژگیها..." />
|
||||
}
|
||||
else if (_features == null || !_features.Any())
|
||||
{
|
||||
<MudAlert Severity="Severity.Info">
|
||||
هنوز ویژگیای برای شما فعال نشده است.
|
||||
</MudAlert>
|
||||
<EmptyState Icon="@Icons.Material.Filled.Stars"
|
||||
Title="هنوز ویژگیای برای شما فعال نشده است"
|
||||
Description="با خرید پکیج یا ارتقاء عضویت، ویژگیهای اختصاصی فعال میشوند." />
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -73,7 +71,7 @@
|
||||
FullWidth="true"
|
||||
Size="Size.Large"
|
||||
StartIcon="@Icons.Material.Filled.ArrowBack"
|
||||
Href="@RouteConstants.Club.Membership">
|
||||
OnClick="GoBack">
|
||||
بازگشت به صفحه باشگاه
|
||||
</MudButton>
|
||||
</MudStack>
|
||||
@@ -190,4 +188,6 @@
|
||||
_selectedFeature = feature;
|
||||
_showDetailDialog = true;
|
||||
}
|
||||
|
||||
private async Task GoBack() => await JS.InvokeVoidAsync("history.back");
|
||||
}
|
||||
|
||||
@@ -7,14 +7,11 @@
|
||||
|
||||
<MudContainer MaxWidth="MaxWidth.Large" 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.Index">بازگشت</MudButton>
|
||||
</MudStack>
|
||||
<PageHeader Title="عضویت باشگاه مشتریان" BackHref="@RouteConstants.Profile.Index" />
|
||||
|
||||
@if (_isLoading)
|
||||
{
|
||||
<MudProgressLinear Color="Color.Primary" Indeterminate="true" />
|
||||
<LoadingState Message="در حال دریافت اطلاعات عضویت..." />
|
||||
}
|
||||
else if (_membership is not null)
|
||||
{
|
||||
|
||||
@@ -8,10 +8,7 @@
|
||||
|
||||
<MudContainer MaxWidth="MaxWidth.Large" 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.Index">بازگشت</MudButton>
|
||||
</MudStack>
|
||||
<PageHeader Title="پاداشهای من" BackHref="@RouteConstants.Profile.Index" />
|
||||
|
||||
<!-- فیلترها -->
|
||||
<MudPaper Elevation="2" Class="pa-3 rounded-lg">
|
||||
@@ -52,7 +49,7 @@
|
||||
|
||||
@if (_isLoading)
|
||||
{
|
||||
<MudProgressLinear Color="Color.Primary" Indeterminate="true" />
|
||||
<LoadingState Message="در حال دریافت پاداشها..." />
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -7,10 +7,7 @@
|
||||
|
||||
<MudContainer MaxWidth="MaxWidth.Large" 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.Commission.Dashboard">بازگشت</MudButton>
|
||||
</MudStack>
|
||||
<PageHeader Title="گزارش هفتگی پاداش" BackHref="@RouteConstants.Commission.Dashboard" />
|
||||
|
||||
<!-- انتخاب هفته -->
|
||||
<MudPaper Elevation="2" Class="pa-3 rounded-lg">
|
||||
@@ -50,7 +47,7 @@
|
||||
|
||||
@if (_isLoading)
|
||||
{
|
||||
<MudProgressLinear Color="Color.Primary" Indeterminate="true" />
|
||||
<LoadingState Message="در حال دریافت گزارش..." />
|
||||
}
|
||||
else if (_weeklyBalance is not null)
|
||||
{
|
||||
@@ -76,11 +73,11 @@
|
||||
<MudGrid Spacing="2">
|
||||
|
||||
<MudItem xs="6">
|
||||
<MudPaper Elevation="3" Class="pa-4 rounded-lg text-center" Style="background: linear-gradient(135deg, #e8f5e9 0%, #c8e6c9 100%);">
|
||||
<MudPaper Elevation="2" Class="pa-4 rounded-lg text-center bg-success-soft stat-card-ds">
|
||||
<MudStack Spacing="1" AlignItems="AlignItems.Center">
|
||||
<MudIcon Icon="@Icons.Material.Filled.ChevronRight" Color="Color.Success" Size="Size.Large" />
|
||||
<MudText Typo="Typo.subtitle2" Color="Color.Success">تیم دوم</MudText>
|
||||
<MudText Typo="Typo.h5" Color="Color.Success" Style="font-weight: bold;">@_weeklyBalance.RightBalanceFormatted</MudText>
|
||||
<MudText Typo="Typo.h5" Color="Color.Success" Class="dash-stat-value">@_weeklyBalance.RightBalanceFormatted</MudText>
|
||||
<MudProgressLinear Color="Color.Success"
|
||||
Value="@GetRightPercentage()"
|
||||
Size="Size.Medium"
|
||||
@@ -93,11 +90,11 @@
|
||||
</MudPaper>
|
||||
</MudItem>
|
||||
<MudItem xs="6">
|
||||
<MudPaper Elevation="3" Class="pa-4 rounded-lg text-center" Style="background: linear-gradient(135deg, #e3f2fd 0%, #bbdefb 100%);">
|
||||
<MudPaper Elevation="2" Class="pa-4 rounded-lg text-center bg-info-soft stat-card-ds">
|
||||
<MudStack Spacing="1" AlignItems="AlignItems.Center">
|
||||
<MudIcon Icon="@Icons.Material.Filled.ChevronLeft" Color="Color.Info" Size="Size.Large"/>
|
||||
<MudText Typo="Typo.subtitle2" Color="Color.Info">تیم اول</MudText>
|
||||
<MudText Typo="Typo.h5" Color="Color.Info" Style="font-weight: bold;">@_weeklyBalance.LeftBalanceFormatted</MudText>
|
||||
<MudText Typo="Typo.h5" Color="Color.Info" Class="dash-stat-value">@_weeklyBalance.LeftBalanceFormatted</MudText>
|
||||
<MudProgressLinear Color="Color.Info"
|
||||
Value="@GetLeftPercentage()"
|
||||
Size="Size.Medium"
|
||||
@@ -114,7 +111,7 @@
|
||||
|
||||
<!-- محاسبات پاداش - فشردهتر -->
|
||||
<MudPaper Elevation="2" Class="pa-4 rounded-lg">
|
||||
<MudText Typo="Typo.subtitle1" Class="mb-2" Style="font-weight: bold;">محاسبات پاداش</MudText>
|
||||
<MudText Typo="Typo.subtitle1" Class="mb-2 fw-bold">محاسبات پاداش</MudText>
|
||||
<MudSimpleTable Dense="true" Hover="true" Style="background: transparent;">
|
||||
<tbody>
|
||||
<tr>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
@attribute [Route(RouteConstants.Contact.Index)]
|
||||
@inject SitePageService SitePageService
|
||||
|
||||
<PageTitle>ارتباط با ما | کارا بازار سلامت</PageTitle>
|
||||
|
||||
@@ -8,10 +9,10 @@
|
||||
<MudStack AlignItems="AlignItems.Center" Spacing="4">
|
||||
<MudChip T="string" Color="Color.Secondary" Variant="Variant.Filled" Class="mb-2">ارتباط با ما</MudChip>
|
||||
<MudText Typo="Typo.h2" Align="Align.Center" Class="mb-3">
|
||||
آماده شنیدن صدای شما هستیم
|
||||
@(_page?.HeroTitle ?? "آماده شنیدن صدای شما هستیم")
|
||||
</MudText>
|
||||
<MudText Typo="Typo.body1" Align="Align.Center" Class="mud-text-secondary mb-6" Style="max-width:600px">
|
||||
سوالات، پیشنهادات یا انتقادات خود را با ما در میان بگذارید. تیم ما آماده پاسخگویی به شماست.
|
||||
@(_page?.HeroSubtitle ?? "سوالات، پیشنهادات یا انتقادات خود را با ما در میان بگذارید. تیم ما آماده پاسخگویی به شماست.")
|
||||
</MudText>
|
||||
</MudStack>
|
||||
</MudContainer>
|
||||
@@ -25,7 +26,7 @@
|
||||
<MudGrid Spacing="6">
|
||||
<!-- Contact Form -->
|
||||
<MudItem xs="12" lg="8">
|
||||
<MudPaper Elevation="3" Class="pa-6">
|
||||
<MudPaper Elevation="2" Class="pa-6">
|
||||
<MudText Typo="Typo.h5" Class="mb-6">فرم تماس</MudText>
|
||||
|
||||
<MudForm @ref="_form" Model="_contactForm">
|
||||
@@ -72,12 +73,12 @@
|
||||
Variant="Variant.Outlined"
|
||||
Required="true"
|
||||
RequiredError="انتخاب موضوع الزامی است.">
|
||||
<MudSelectItem Value="@("general")">عمومی</MudSelectItem>
|
||||
<MudSelectItem Value="@("support")">پشتیبانی فنی</MudSelectItem>
|
||||
<MudSelectItem Value="@("sales")">فروش و قیمتگذاری</MudSelectItem>
|
||||
<MudSelectItem Value="@("partnership")">شریک تجاری</MudSelectItem>
|
||||
<MudSelectItem Value="@("complaint")">شکایت</MudSelectItem>
|
||||
<MudSelectItem Value="@("suggestion")">پیشنهاد</MudSelectItem>
|
||||
<MudSelectItem T="string" Value="@("general")">عمومی</MudSelectItem>
|
||||
<MudSelectItem T="string" Value="@("support")">پشتیبانی فنی</MudSelectItem>
|
||||
<MudSelectItem T="string" Value="@("sales")">فروش و قیمتگذاری</MudSelectItem>
|
||||
<MudSelectItem T="string" Value="@("partnership")">شریک تجاری</MudSelectItem>
|
||||
<MudSelectItem T="string" Value="@("complaint")">شکایت</MudSelectItem>
|
||||
<MudSelectItem T="string" Value="@("suggestion")">پیشنهاد</MudSelectItem>
|
||||
</MudSelect>
|
||||
</MudItem>
|
||||
|
||||
@@ -123,7 +124,7 @@
|
||||
<MudItem xs="12" lg="4">
|
||||
<MudStack Spacing="4">
|
||||
<!-- Contact Details -->
|
||||
<MudPaper Elevation="3" Class="pa-6">
|
||||
<MudPaper Elevation="2" Class="pa-6">
|
||||
<MudText Typo="Typo.h6" Class="mb-4">اطلاعات تماس</MudText>
|
||||
|
||||
<MudStack Spacing="4">
|
||||
@@ -132,7 +133,7 @@
|
||||
<div>
|
||||
<MudText Typo="Typo.body2" >آدرس</MudText>
|
||||
<MudText Typo="Typo.caption" Class="mud-text-secondary">
|
||||
کرج مهرویلا میدان مادر ساختمان بزرگمهر طبقه ۴ واحد ۱۶
|
||||
@(_contactAddress ?? "کرج مهرویلا میدان مادر ساختمان بزرگمهر طبقه ۴ واحد ۱۶")
|
||||
</MudText>
|
||||
</div>
|
||||
</MudStack>
|
||||
@@ -141,7 +142,7 @@
|
||||
<MudIcon Icon="@Icons.Material.Filled.Phone" Color="Color.Success" Size="Size.Large" />
|
||||
<div>
|
||||
<MudText Typo="Typo.body2" >تلفن</MudText>
|
||||
<MudText Typo="Typo.caption" Class="mud-text-secondary">026-34233563</MudText>
|
||||
<MudText Typo="Typo.caption" Class="mud-text-secondary">@(_contactPhone ?? "026-34233563")</MudText>
|
||||
</div>
|
||||
</MudStack>
|
||||
|
||||
@@ -149,7 +150,7 @@
|
||||
<MudIcon Icon="@Icons.Material.Filled.Email" Color="Color.Info" Size="Size.Large" />
|
||||
<div>
|
||||
<MudText Typo="Typo.body2" >ایمیل</MudText>
|
||||
<MudText Typo="Typo.caption" Class="mud-text-secondary">info@kbs1.co</MudText>
|
||||
<MudText Typo="Typo.caption" Class="mud-text-secondary">@(_contactEmail ?? "info@kbs1.co")</MudText>
|
||||
</div>
|
||||
</MudStack>
|
||||
|
||||
@@ -158,8 +159,7 @@
|
||||
<div>
|
||||
<MudText Typo="Typo.body2" >ساعات کاری</MudText>
|
||||
<MudText Typo="Typo.caption" Class="mud-text-secondary">
|
||||
شنبه تا پنجشنبه<br />
|
||||
۹ صبح تا ۶ عصر
|
||||
@((MarkupString)(_contactHours ?? "شنبه تا پنجشنبه<br />۹ صبح تا ۶ عصر"))
|
||||
</MudText>
|
||||
</div>
|
||||
</MudStack>
|
||||
@@ -167,14 +167,14 @@
|
||||
</MudPaper>
|
||||
|
||||
<!-- Social Media -->
|
||||
<MudPaper Elevation="3" Class="pa-6">
|
||||
<MudPaper Elevation="2" Class="pa-6">
|
||||
<MudText Typo="Typo.h6" Class="mb-4">شبکههای اجتماعی</MudText>
|
||||
|
||||
<MudStack Spacing="3">
|
||||
<MudButton Variant="Variant.Outlined"
|
||||
Color="Color.Inherit"
|
||||
StartIcon="@Icons.Custom.Brands.Telegram"
|
||||
Href="https://t.me/kbs1"
|
||||
Href="@(_socialTelegram ?? "https://t.me/kbs1")"
|
||||
Target="_blank"
|
||||
FullWidth="true">
|
||||
تلگرام
|
||||
@@ -183,7 +183,7 @@
|
||||
<MudButton Variant="Variant.Outlined"
|
||||
Color="Color.Inherit"
|
||||
StartIcon="@Icons.Custom.Brands.Instagram"
|
||||
Href="https://instagram.com/kbs1"
|
||||
Href="@(_socialInstagram ?? "https://instagram.com/kbs1")"
|
||||
Target="_blank"
|
||||
FullWidth="true">
|
||||
اینستاگرام
|
||||
@@ -192,7 +192,7 @@
|
||||
<MudButton Variant="Variant.Outlined"
|
||||
Color="Color.Inherit"
|
||||
StartIcon="@Icons.Custom.Brands.LinkedIn"
|
||||
Href="https://linkedin.com/company/kbs1"
|
||||
Href="@(_socialLinkedin ?? "https://linkedin.com/company/kbs1")"
|
||||
Target="_blank"
|
||||
FullWidth="true">
|
||||
لینکدین
|
||||
@@ -201,7 +201,7 @@
|
||||
<MudButton Variant="Variant.Outlined"
|
||||
Color="Color.Inherit"
|
||||
StartIcon="@Icons.Custom.Brands.WhatsApp"
|
||||
Href="https://wa.me/989123456789"
|
||||
Href="@(_socialWhatsapp ?? "https://wa.me/989123456789")"
|
||||
Target="_blank"
|
||||
FullWidth="true">
|
||||
واتساپ
|
||||
@@ -219,14 +219,14 @@
|
||||
<MudContainer MaxWidth="MaxWidth.Large">
|
||||
<MudText Typo="Typo.h4" Align="Align.Center" Class="mb-8">موقعیت مکانی</MudText>
|
||||
|
||||
<MudPaper Elevation="3" Class="pa-4 overflow-hidden">
|
||||
<MudPaper Elevation="2" Class="pa-4 overflow-hidden">
|
||||
<!-- Placeholder for Map -->
|
||||
<div style="height: 400px; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); display: flex; align-items: center; justify-content: center;">
|
||||
<div class="contact-map-placeholder" style="height: 400px; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); display: flex; align-items: center; justify-content: center; border-radius: 12px;">
|
||||
<MudStack AlignItems="AlignItems.Center" Spacing="3">
|
||||
<MudIcon Icon="@Icons.Material.Filled.Map" Size="Size.Large" Style="color: white;" />
|
||||
<MudText Typo="Typo.h6" Style="color: white;">نقشه موقعیت مکانی</MudText>
|
||||
<MudText Typo="Typo.body2" Style="color: rgba(255,255,255,0.8);" Align="Align.Center">
|
||||
کرج مهرویلا میدان مادر ساختمان بزرگمهر طبقه ۴ واحد ۱۶
|
||||
@(_contactAddress ?? "کرج مهرویلا میدان مادر ساختمان بزرگمهر طبقه ۴ واحد ۱۶")
|
||||
</MudText>
|
||||
</MudStack>
|
||||
</div>
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
using FluentValidation;
|
||||
using FrontOffice.Main.Utilities;
|
||||
using MudBlazor;
|
||||
using Severity = MudBlazor.Severity;
|
||||
|
||||
namespace FrontOffice.Main.Pages;
|
||||
|
||||
public partial class Contact
|
||||
{
|
||||
private ContactForm _contactForm = new();
|
||||
@@ -10,6 +12,60 @@ public partial class Contact
|
||||
private bool _isSubmitting;
|
||||
private readonly ContactFormValidator _contactFormValidator = new();
|
||||
|
||||
// Dynamic CMS data
|
||||
private SitePageDto? _page;
|
||||
private string? _contactAddress;
|
||||
private string? _contactPhone;
|
||||
private string? _contactEmail;
|
||||
private string? _contactHours;
|
||||
private string? _socialTelegram;
|
||||
private string? _socialInstagram;
|
||||
private string? _socialLinkedin;
|
||||
private string? _socialWhatsapp;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
_page = await SitePageService.GetByKeyAsync("contact");
|
||||
|
||||
if (_page != null)
|
||||
{
|
||||
// Load contact info from CMS section
|
||||
var contactInfoSection = _page.GetSection("contact-info");
|
||||
if (contactInfoSection != null)
|
||||
{
|
||||
var contactData = contactInfoSection.GetExtraData<ContactInfoData>();
|
||||
if (contactData != null)
|
||||
{
|
||||
_contactAddress = contactData.Address;
|
||||
_contactPhone = contactData.Phone;
|
||||
_contactEmail = contactData.Email;
|
||||
_contactHours = contactData.Hours;
|
||||
}
|
||||
}
|
||||
|
||||
// Load social media links from CMS section
|
||||
var socialSection = _page.GetSection("social-media");
|
||||
if (socialSection != null)
|
||||
{
|
||||
var socialData = socialSection.GetExtraData<SocialMediaData>();
|
||||
if (socialData != null)
|
||||
{
|
||||
_socialTelegram = socialData.Telegram;
|
||||
_socialInstagram = socialData.Instagram;
|
||||
_socialLinkedin = socialData.Linkedin;
|
||||
_socialWhatsapp = socialData.Whatsapp;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Fallback: all values remain null → hardcoded defaults will render
|
||||
}
|
||||
}
|
||||
|
||||
private async Task SubmitContactForm()
|
||||
{
|
||||
if (_form is null) return;
|
||||
@@ -55,14 +111,12 @@ public partial class Contact
|
||||
|
||||
private void CallSupport()
|
||||
{
|
||||
// TODO: Initiate phone call or show phone number
|
||||
Snackbar.Add("شماره تماس: ۰۲۱-۱۲۳۴۵۶۷۸", Severity.Info);
|
||||
Snackbar.Add($"شماره تماس: {_contactPhone ?? "026-34233563"}", Severity.Info);
|
||||
}
|
||||
|
||||
private void SendEmail()
|
||||
{
|
||||
// TODO: Open email client or redirect to email page
|
||||
Snackbar.Add("ایمیل: info@kbs1.co", Severity.Info);
|
||||
Snackbar.Add($"ایمیل: {_contactEmail ?? "info@kbs1.co"}", Severity.Info);
|
||||
}
|
||||
|
||||
public class ContactForm
|
||||
@@ -87,4 +141,21 @@ public partial class Contact
|
||||
RuleFor(x => x.Message).NotEmpty().MinimumLength(10).WithMessage("پیام باید حداقل ۱۰ کاراکتر باشد");
|
||||
}
|
||||
}
|
||||
|
||||
// DTO classes for ExtraData JSON deserialization
|
||||
private class ContactInfoData
|
||||
{
|
||||
public string? Address { get; set; }
|
||||
public string? Phone { get; set; }
|
||||
public string? Email { get; set; }
|
||||
public string? Hours { get; set; }
|
||||
}
|
||||
|
||||
private class SocialMediaData
|
||||
{
|
||||
public string? Telegram { get; set; }
|
||||
public string? Instagram { get; set; }
|
||||
public string? Linkedin { get; set; }
|
||||
public string? Whatsapp { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,190 @@
|
||||
@attribute [Route(RouteConstants.DiscountStore.Cart)]
|
||||
|
||||
<PageTitle>سبد خرید تخفیفی</PageTitle>
|
||||
|
||||
<MudContainer MaxWidth="MaxWidth.Large" Class="py-6">
|
||||
<MudStack Spacing="3">
|
||||
<PageHeader Title="سبد خرید تخفیفی" BackHref="@RouteConstants.DiscountStore.Products" />
|
||||
|
||||
@if (DiscountCart.Items.Count == 0)
|
||||
{
|
||||
<MudAlert Severity="Severity.Info">سبد خرید تخفیفی شما خالی است.</MudAlert>
|
||||
<MudButton Variant="Variant.Outlined" StartIcon="@Icons.Material.Filled.ArrowBack"
|
||||
OnClick="() => Navigation.NavigateTo(RouteConstants.DiscountStore.Products)">
|
||||
بازگشت به فروشگاه تخفیفی
|
||||
</MudButton>
|
||||
}
|
||||
else
|
||||
{
|
||||
<!-- Desktop Table -->
|
||||
<MudHidden Breakpoint="Breakpoint.MdAndUp" Invert="true">
|
||||
<MudPaper Elevation="1" Class="pa-4 rounded-lg">
|
||||
<MudTable Items="DiscountCart.Items">
|
||||
<HeaderContent>
|
||||
<MudTh>محصول</MudTh>
|
||||
<MudTh>قیمت واحد</MudTh>
|
||||
<MudTh>سقف تخفیف</MudTh>
|
||||
<MudTh>تعداد</MudTh>
|
||||
<MudTh>تخفیف</MudTh>
|
||||
<MudTh>قیمت نهایی</MudTh>
|
||||
<MudTh></MudTh>
|
||||
</HeaderContent>
|
||||
<RowTemplate>
|
||||
<MudTd>
|
||||
<MudStack Row="true" Spacing="2" AlignItems="AlignItems.Center">
|
||||
<AppImage Path="@GetImageUrl(context.ImageUrl)" Alt="@context.Title"
|
||||
ImgWidth="64" ImgHeight="64" Class="product-thumb" />
|
||||
<MudText>@context.Title</MudText>
|
||||
</MudStack>
|
||||
</MudTd>
|
||||
<MudTd>@FormatPrice(context.UnitPrice)</MudTd>
|
||||
<MudTd>
|
||||
<MudChip T="string" Color="Color.Error" Variant="Variant.Outlined" Size="Size.Small">
|
||||
تا @context.MaxDiscountPercent%
|
||||
</MudChip>
|
||||
</MudTd>
|
||||
<MudTd>
|
||||
<MudStack Row="true" AlignItems="AlignItems.Center" Spacing="1">
|
||||
<MudIconButton Icon="@Icons.Material.Filled.Remove" Color="Color.Default"
|
||||
OnClick="@(() => DecrementQty(context.ProductId))" />
|
||||
<MudText>@context.Quantity</MudText>
|
||||
<MudIconButton Icon="@Icons.Material.Filled.Add" Color="Color.Default"
|
||||
OnClick="@(() => IncrementQty(context.ProductId))" />
|
||||
</MudStack>
|
||||
</MudTd>
|
||||
<MudTd>
|
||||
@if (context.DiscountAmount > 0)
|
||||
{
|
||||
<MudText Color="Color.Success">@FormatPrice(context.DiscountAmount)-</MudText>
|
||||
}
|
||||
else
|
||||
{
|
||||
<MudText Class="mud-text-secondary">—</MudText>
|
||||
}
|
||||
</MudTd>
|
||||
<MudTd>@FormatPrice(context.FinalPrice)</MudTd>
|
||||
<MudTd>
|
||||
<MudIconButton Icon="@Icons.Material.Filled.Delete" Color="Color.Error"
|
||||
OnClick="() => Remove(context.ProductId)" />
|
||||
</MudTd>
|
||||
</RowTemplate>
|
||||
</MudTable>
|
||||
</MudPaper>
|
||||
</MudHidden>
|
||||
|
||||
<!-- Mobile Cards -->
|
||||
<MudHidden Breakpoint="Breakpoint.MdAndUp">
|
||||
<MudStack Spacing="2">
|
||||
@foreach (var item in DiscountCart.Items)
|
||||
{
|
||||
<MudPaper Class="pa-3 rounded-lg w-100-mobile" Outlined="true">
|
||||
<MudStack Spacing="1">
|
||||
<MudStack Row="true" Justify="Justify.SpaceBetween" AlignItems="AlignItems.Center">
|
||||
<MudStack Row="true" Spacing="2" AlignItems="AlignItems.Center">
|
||||
<AppImage Path="@GetImageUrl(item.ImageUrl)" Alt="@item.Title"
|
||||
ImgWidth="50" ImgHeight="50" Class="rounded-circle" />
|
||||
<MudText Typo="Typo.subtitle2">@item.Title</MudText>
|
||||
</MudStack>
|
||||
<MudChip T="string" Color="Color.Error" Variant="Variant.Outlined" Size="Size.Small">
|
||||
تا @item.MaxDiscountPercent%
|
||||
</MudChip>
|
||||
</MudStack>
|
||||
|
||||
<MudStack Spacing="1">
|
||||
<MudStack Row="true" Justify="Justify.SpaceBetween" AlignItems="AlignItems.Center">
|
||||
<MudText Class="mud-text-secondary">@FormatPrice(item.UnitPrice) واحد</MudText>
|
||||
<MudStack Row="true" AlignItems="AlignItems.Center" Spacing="1">
|
||||
<MudIconButton
|
||||
Icon="@(item.Quantity <= 1 ? Icons.Material.Filled.Delete : Icons.Material.Filled.Remove)"
|
||||
Color="Color.Default"
|
||||
OnClick="@(() => DecrementQty(item.ProductId))" />
|
||||
<MudText>@item.Quantity</MudText>
|
||||
<MudIconButton Icon="@Icons.Material.Filled.Add"
|
||||
Color="Color.Default"
|
||||
OnClick="@(() => IncrementQty(item.ProductId))" />
|
||||
</MudStack>
|
||||
</MudStack>
|
||||
<MudStack Row="true" Justify="Justify.SpaceBetween" AlignItems="AlignItems.Center">
|
||||
@if (item.DiscountAmount > 0)
|
||||
{
|
||||
<MudText Typo="Typo.caption" Color="Color.Success">تخفیف: @FormatPrice(item.DiscountAmount)-</MudText>
|
||||
}
|
||||
<MudText>جمع: @FormatPrice(item.FinalPrice)</MudText>
|
||||
<MudIconButton Icon="@Icons.Material.Filled.Delete" Color="Color.Error"
|
||||
OnClick="() => Remove(item.ProductId)" />
|
||||
</MudStack>
|
||||
</MudStack>
|
||||
</MudStack>
|
||||
</MudPaper>
|
||||
}
|
||||
</MudStack>
|
||||
</MudHidden>
|
||||
|
||||
<!-- Summary -->
|
||||
@if (DeviceDetector.IsMobile())
|
||||
{
|
||||
<MudStack Spacing="1" Class="mobile-actions-stack px-5">
|
||||
<MudStack Row="true" Justify="Justify.SpaceBetween" AlignItems="AlignItems.Center">
|
||||
<MudText Typo="Typo.body2">جمع کل:</MudText>
|
||||
<MudText Typo="Typo.body2">@FormatPrice(DiscountCart.TotalPrice) تومان</MudText>
|
||||
</MudStack>
|
||||
@if (DiscountCart.TotalDiscount > 0)
|
||||
{
|
||||
<MudStack Row="true" Justify="Justify.SpaceBetween" AlignItems="AlignItems.Center">
|
||||
<MudText Typo="Typo.caption" Color="Color.Success">سقف تخفیف قابل اعمال:</MudText>
|
||||
<MudText Typo="Typo.caption" Color="Color.Success">@FormatPrice(DiscountCart.TotalDiscount)- تومان</MudText>
|
||||
</MudStack>
|
||||
}
|
||||
<MudStack Row="true" Justify="Justify.SpaceBetween" AlignItems="AlignItems.Center">
|
||||
<MudText Typo="Typo.h6" Class="fw-bold">حداقل پرداخت:</MudText>
|
||||
<MudText Typo="Typo.h6" Color="Color.Primary" Class="fw-bold">@FormatPrice(DiscountCart.FinalPrice) تومان</MudText>
|
||||
</MudStack>
|
||||
</MudStack>
|
||||
|
||||
<MudStack Row="true" Justify="Justify.SpaceBetween" Spacing="2" Class="mobile-actions-stack">
|
||||
<MudButton Variant="Variant.Filled" Color="Color.Primary"
|
||||
OnClick="() => Navigation.NavigateTo(RouteConstants.DiscountStore.Products)">
|
||||
افزودن محصول
|
||||
</MudButton>
|
||||
<MudButton Variant="Variant.Filled" Color="Color.Success" OnClick="ProceedCheckout"
|
||||
StartIcon="@Icons.Material.Filled.CreditCard">ادامه خرید</MudButton>
|
||||
</MudStack>
|
||||
}
|
||||
else
|
||||
{
|
||||
<MudPaper Class="pa-4 rounded-lg" Style="background-color: var(--mud-palette-background-grey);">
|
||||
<MudStack Spacing="1">
|
||||
<MudStack Row="true" Justify="Justify.SpaceBetween">
|
||||
<MudText Typo="Typo.body2">جمع کل:</MudText>
|
||||
<MudText Typo="Typo.body2">@FormatPrice(DiscountCart.TotalPrice) تومان</MudText>
|
||||
</MudStack>
|
||||
@if (DiscountCart.TotalDiscount > 0)
|
||||
{
|
||||
<MudStack Row="true" Justify="Justify.SpaceBetween">
|
||||
<MudText Typo="Typo.body2" Color="Color.Success">سقف تخفیف قابل اعمال:</MudText>
|
||||
<MudText Typo="Typo.body2" Color="Color.Success">@FormatPrice(DiscountCart.TotalDiscount)- تومان</MudText>
|
||||
</MudStack>
|
||||
}
|
||||
<MudDivider Class="my-1" />
|
||||
<MudStack Row="true" Justify="Justify.SpaceBetween">
|
||||
<MudText Typo="Typo.subtitle1" Class="fw-bold">حداقل مبلغ پرداخت درگاه:</MudText>
|
||||
<MudText Typo="Typo.subtitle1" Color="Color.Primary" Class="fw-bold">@FormatPrice(DiscountCart.FinalPrice) تومان</MudText>
|
||||
</MudStack>
|
||||
<MudText Typo="Typo.caption" Class="mud-text-secondary">
|
||||
مبلغ دقیق پرداخت در مرحله تسویه مشخص خواهد شد.
|
||||
</MudText>
|
||||
</MudStack>
|
||||
</MudPaper>
|
||||
|
||||
<MudStack Row="true" Justify="Justify.FlexEnd" Spacing="2" Class="mt-3">
|
||||
<MudButton Variant="Variant.Outlined" Color="Color.Primary"
|
||||
OnClick="() => Navigation.NavigateTo(RouteConstants.DiscountStore.Products)">
|
||||
افزودن محصول
|
||||
</MudButton>
|
||||
<MudButton Variant="Variant.Filled" Color="Color.Success" OnClick="ProceedCheckout"
|
||||
StartIcon="@Icons.Material.Filled.CreditCard">ادامه فرایند خرید</MudButton>
|
||||
</MudStack>
|
||||
}
|
||||
}
|
||||
</MudStack>
|
||||
</MudContainer>
|
||||
@@ -0,0 +1,56 @@
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using FrontOffice.Main.Utilities;
|
||||
|
||||
namespace FrontOffice.Main.Pages.DiscountStore;
|
||||
|
||||
public partial class Cart : IDisposable
|
||||
{
|
||||
[Inject] private DiscountCartService DiscountCart { get; set; } = default!;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
await DiscountCart.EnsureInitializedAsync();
|
||||
DiscountCart.OnChange += StateHasChanged;
|
||||
}
|
||||
|
||||
private async Task IncrementQty(long productId)
|
||||
{
|
||||
var item = DiscountCart.Items.FirstOrDefault(i => i.ProductId == productId);
|
||||
if (item is null) return;
|
||||
await DiscountCart.UpdateQuantityAsync(productId, item.Quantity + 1);
|
||||
}
|
||||
|
||||
private async Task DecrementQty(long productId)
|
||||
{
|
||||
var item = DiscountCart.Items.FirstOrDefault(i => i.ProductId == productId);
|
||||
if (item is null) return;
|
||||
if (item.Quantity <= 1)
|
||||
{
|
||||
await DiscountCart.RemoveAsync(productId);
|
||||
}
|
||||
else
|
||||
{
|
||||
await DiscountCart.UpdateQuantityAsync(productId, item.Quantity - 1);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task Remove(long productId)
|
||||
{
|
||||
await DiscountCart.RemoveAsync(productId);
|
||||
}
|
||||
|
||||
private void ProceedCheckout()
|
||||
{
|
||||
Navigation.NavigateTo(RouteConstants.DiscountStore.Checkout);
|
||||
}
|
||||
|
||||
private static string FormatPrice(long price) => $"{price:N0} ";
|
||||
|
||||
private static string GetImageUrl(string? imageUrl)
|
||||
=> string.IsNullOrWhiteSpace(imageUrl) ? "/images/product-placeholder.svg" : imageUrl.TrimStart('/');
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
DiscountCart.OnChange -= StateHasChanged;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,193 @@
|
||||
@using CMSMicroservice.Protobuf.Protos.UserAddress
|
||||
@attribute [Route(RouteConstants.DiscountStore.Checkout)]
|
||||
|
||||
<PageTitle>تسویه حساب فروشگاه تخفیفی</PageTitle>
|
||||
|
||||
<MudContainer MaxWidth="MaxWidth.Large" Class="py-6">
|
||||
<PageHeader Title="تسویه حساب تخفیفی" BackHref="@RouteConstants.DiscountStore.Cart" />
|
||||
<MudGrid Spacing="3">
|
||||
<!-- Left Column: Address + Payment Settings -->
|
||||
<MudItem xs="12" md="8">
|
||||
<!-- Address Selection -->
|
||||
<MudPaper Elevation="2" Class="pa-4 rounded-lg mb-3">
|
||||
<MudText Typo="Typo.h6" Class="mb-2">انتخاب آدرس</MudText>
|
||||
|
||||
@if (_loadingAddresses)
|
||||
{
|
||||
<MudStack AlignItems="AlignItems.Center" Class="py-4">
|
||||
<MudProgressCircular Indeterminate="true" Color="Color.Primary" />
|
||||
<MudText Class="mt-2 mud-text-secondary">در حال بارگذاری آدرسها...</MudText>
|
||||
</MudStack>
|
||||
}
|
||||
else if (_addresses.Count == 0)
|
||||
{
|
||||
<MudAlert Severity="Severity.Warning">
|
||||
هیچ آدرسی ثبت نشده است. لطفاً از بخش پروفایل آدرس خود را اضافه کنید.
|
||||
</MudAlert>
|
||||
<MudButton Class="mt-2" Variant="Variant.Outlined" Href="/profile/addresses">افزودن آدرس</MudButton>
|
||||
}
|
||||
else
|
||||
{
|
||||
<MudStack Spacing="1">
|
||||
@foreach (var address in _addresses)
|
||||
{
|
||||
<MudPaper Outlined="@(_selectedAddress?.Id != address.Id)"
|
||||
Elevation="@(_selectedAddress?.Id == address.Id ? 2 : 0)"
|
||||
Class="pa-3 rounded-xl cursor-pointer"
|
||||
Style="@(_selectedAddress?.Id == address.Id ? "border: 2px solid var(--mud-palette-primary);" : "")"
|
||||
@onclick="() => _selectedAddress = address">
|
||||
<MudStack Row="true" Justify="Justify.SpaceBetween" AlignItems="AlignItems.Center">
|
||||
<MudStack>
|
||||
<MudText Typo="Typo.subtitle2">@address.Title</MudText>
|
||||
<MudText Typo="Typo.body2" Class="mud-text-secondary">@address.Address</MudText>
|
||||
</MudStack>
|
||||
@if (address.IsDefault)
|
||||
{
|
||||
<MudChip T="string" Color="Color.Success" Variant="Variant.Outlined">پیشفرض</MudChip>
|
||||
}
|
||||
</MudStack>
|
||||
</MudPaper>
|
||||
}
|
||||
</MudStack>
|
||||
}
|
||||
</MudPaper>
|
||||
|
||||
<!-- Discount Balance (Hybrid Payment) -->
|
||||
<MudPaper Elevation="2" Class="pa-4 rounded-lg mb-3">
|
||||
<MudStack Row="true" Spacing="2" AlignItems="AlignItems.Center" Class="mb-3">
|
||||
<MudIcon Icon="@Icons.Material.Filled.Loyalty" Color="Color.Secondary" />
|
||||
<MudText Typo="Typo.h6">پرداخت از کیف تخفیفی</MudText>
|
||||
</MudStack>
|
||||
|
||||
<MudStack Spacing="2">
|
||||
<MudStack Row="true" Justify="Justify.SpaceBetween" AlignItems="AlignItems.Center" Class="flex-wrap">
|
||||
<MudText Typo="Typo.body2">موجودی کیف تخفیفی شما:</MudText>
|
||||
<MudText Typo="Typo.subtitle1" Color="Color.Secondary" Class="fw-bold">
|
||||
@FormatPrice(_discountBalance) تومان
|
||||
</MudText>
|
||||
</MudStack>
|
||||
|
||||
<MudStack Row="true" Justify="Justify.SpaceBetween" AlignItems="AlignItems.Center" Class="flex-wrap">
|
||||
<MudText Typo="Typo.body2">سقف مجاز تخفیف روی این سفارش:</MudText>
|
||||
<MudText Typo="Typo.subtitle2" Color="Color.Success">
|
||||
@FormatPrice(MaxAllowedDiscount) تومان
|
||||
</MudText>
|
||||
</MudStack>
|
||||
|
||||
<MudDivider />
|
||||
|
||||
<MudText Typo="Typo.body2" Class="mud-text-secondary">
|
||||
مبلغی که از کیف تخفیفی کسر شود (باقیمانده از درگاه پرداخت میشود):
|
||||
</MudText>
|
||||
|
||||
<MudSlider T="long" @bind-Value="_discountBalanceToUse"
|
||||
Min="0" Max="@MaxUsable"
|
||||
Step="1000"
|
||||
Color="Color.Secondary"
|
||||
Immediate="true">
|
||||
استفاده از @FormatPrice(_discountBalanceToUse) تومان
|
||||
</MudSlider>
|
||||
|
||||
<MudNumericField T="long" @bind-Value="_discountBalanceToUse"
|
||||
Min="0" Max="@MaxUsable"
|
||||
Label="مبلغ دلخواه (تومان)" Variant="Variant.Outlined"
|
||||
Margin="Margin.Dense" Immediate="true" />
|
||||
|
||||
@if (_discountBalanceToUse > 0)
|
||||
{
|
||||
<MudAlert Severity="Severity.Info" Variant="Variant.Outlined" Dense="true">
|
||||
مبلغ @FormatPrice(_discountBalanceToUse) تومان از کیف تخفیفی کسر و
|
||||
مبلغ @FormatPrice(GatewayAmount) تومان از درگاه پرداخت دریافت خواهد شد.
|
||||
</MudAlert>
|
||||
}
|
||||
</MudStack>
|
||||
</MudPaper>
|
||||
|
||||
<!-- Notes -->
|
||||
<MudPaper Elevation="2" Class="pa-4 rounded-lg">
|
||||
<MudText Typo="Typo.h6" Class="mb-2">توضیحات سفارش</MudText>
|
||||
<MudTextField T="string" @bind-Value="_notes" Lines="3"
|
||||
Placeholder="توضیحات اختیاری..."
|
||||
Variant="Variant.Outlined" />
|
||||
</MudPaper>
|
||||
</MudItem>
|
||||
|
||||
<!-- Right Column: Order Summary -->
|
||||
<MudItem xs="12" md="4">
|
||||
<MudPaper Elevation="2" Class="pa-4 rounded-lg" Style="position:sticky; top:80px;">
|
||||
<MudText Typo="Typo.h6" Class="mb-2">خلاصه سفارش</MudText>
|
||||
|
||||
@if (DiscountCart.Items.Count == 0)
|
||||
{
|
||||
<MudAlert Severity="Severity.Info">سبد خرید شما خالی است.</MudAlert>
|
||||
}
|
||||
else
|
||||
{
|
||||
<MudList T="string" Dense="true">
|
||||
@foreach (var item in DiscountCart.Items)
|
||||
{
|
||||
<MudListItem T="string">
|
||||
<MudListItemText>
|
||||
<MudStack Spacing="1">
|
||||
<MudStack Row="true" Justify="Justify.SpaceBetween" AlignItems="AlignItems.Center">
|
||||
<AppImage Path="@GetImageUrl(item.ImageUrl)" Alt="@item.Title"
|
||||
ImgWidth="40" ImgHeight="40" Class="rounded-circle" />
|
||||
<MudText Typo="Typo.subtitle2" Style="flex:1; margin:0 8px;">@item.Title</MudText>
|
||||
<MudText Typo="Typo.subtitle2">@FormatPrice(item.FinalPrice)</MudText>
|
||||
</MudStack>
|
||||
<MudStack Row="true" Justify="Justify.SpaceBetween" AlignItems="AlignItems.Center">
|
||||
<MudText Typo="Typo.caption" Class="mud-text-secondary">
|
||||
@item.Quantity × @FormatPrice(item.UnitPrice)
|
||||
</MudText>
|
||||
@if (item.MaxDiscountPercent > 0)
|
||||
{
|
||||
<MudText Typo="Typo.caption" Color="Color.Error">تا @item.MaxDiscountPercent% تخفیف</MudText>
|
||||
}
|
||||
</MudStack>
|
||||
</MudStack>
|
||||
</MudListItemText>
|
||||
</MudListItem>
|
||||
}
|
||||
</MudList>
|
||||
|
||||
<MudDivider Class="my-2" />
|
||||
|
||||
<MudStack Spacing="1">
|
||||
<MudStack Row="true" Justify="Justify.SpaceBetween">
|
||||
<MudText Typo="Typo.body2">جمع کل:</MudText>
|
||||
<MudText Typo="Typo.body2">@FormatPrice(DiscountCart.TotalPrice)</MudText>
|
||||
</MudStack>
|
||||
|
||||
@if (_discountBalanceToUse > 0)
|
||||
{
|
||||
<MudStack Row="true" Justify="Justify.SpaceBetween">
|
||||
<MudText Typo="Typo.body2" Color="Color.Success">از کیف تخفیفی:</MudText>
|
||||
<MudText Typo="Typo.body2" Color="Color.Success">@FormatPrice(_discountBalanceToUse)-</MudText>
|
||||
</MudStack>
|
||||
}
|
||||
|
||||
<MudDivider Class="my-1" />
|
||||
|
||||
<MudStack Row="true" Justify="Justify.SpaceBetween">
|
||||
<MudText Typo="Typo.subtitle1" Class="fw-bold">پرداخت از درگاه:</MudText>
|
||||
<MudText Typo="Typo.subtitle1" Color="Color.Primary" Class="fw-bold">
|
||||
@FormatPrice(GatewayAmount) تومان
|
||||
</MudText>
|
||||
</MudStack>
|
||||
|
||||
<MudText Typo="Typo.caption" Class="mud-text-secondary">
|
||||
مالیات بر ارزش افزوده صرفاً بر مبلغ درگاه محاسبه خواهد شد.
|
||||
</MudText>
|
||||
</MudStack>
|
||||
|
||||
<MudButton Disabled="@(!CanPlaceOrder || _placing)" Class="mt-3 w-100-mobile"
|
||||
Variant="Variant.Filled" Color="Color.Primary"
|
||||
OnClick="PlaceOrder" FullWidth="true"
|
||||
StartIcon="@Icons.Material.Filled.CheckCircle">
|
||||
@(_placing ? "در حال ثبت سفارش..." : "ثبت و پرداخت سفارش")
|
||||
</MudButton>
|
||||
}
|
||||
</MudPaper>
|
||||
</MudItem>
|
||||
</MudGrid>
|
||||
</MudContainer>
|
||||
@@ -0,0 +1,146 @@
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using CMSMicroservice.Protobuf.Protos.UserAddress;
|
||||
using FrontOffice.Main.Utilities;
|
||||
using MudBlazor;
|
||||
|
||||
namespace FrontOffice.Main.Pages.DiscountStore;
|
||||
|
||||
public partial class Checkout
|
||||
{
|
||||
[Inject] private DiscountCartService DiscountCart { get; set; } = default!;
|
||||
[Inject] private DiscountOrderService DiscountOrderService { get; set; } = default!;
|
||||
[Inject] private UserAddressContract.UserAddressContractClient UserAddressContract { get; set; } = default!;
|
||||
|
||||
private List<CustomerAddressModel> _addresses = new();
|
||||
private CustomerAddressModel? _selectedAddress;
|
||||
private bool _loadingAddresses;
|
||||
|
||||
private long _discountBalance;
|
||||
private long _discountBalanceToUse;
|
||||
private string? _notes;
|
||||
private bool _placing;
|
||||
|
||||
/// <summary>
|
||||
/// Maximum discount allowed based on cart items' MaxDiscountPercent
|
||||
/// </summary>
|
||||
private long MaxAllowedDiscount => DiscountCart.TotalDiscount;
|
||||
|
||||
/// <summary>
|
||||
/// Maximum the user can actually use = min(balance, allowed discount)
|
||||
/// </summary>
|
||||
private long MaxUsable => Math.Min(_discountBalance, MaxAllowedDiscount);
|
||||
|
||||
/// <summary>
|
||||
/// Amount to be charged via payment gateway
|
||||
/// </summary>
|
||||
private long GatewayAmount => DiscountCart.TotalPrice - _discountBalanceToUse;
|
||||
|
||||
private bool CanPlaceOrder => DiscountCart.Items.Count > 0 && _selectedAddress is not null;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
await DiscountCart.EnsureInitializedAsync();
|
||||
|
||||
var addressTask = LoadAddresses();
|
||||
var balanceTask = LoadDiscountBalance();
|
||||
await Task.WhenAll(addressTask, balanceTask);
|
||||
|
||||
// Default: use maximum possible discount
|
||||
_discountBalanceToUse = MaxUsable;
|
||||
}
|
||||
|
||||
private async Task LoadDiscountBalance()
|
||||
{
|
||||
try
|
||||
{
|
||||
var balances = await WalletService.GetBalancesAsync();
|
||||
_discountBalance = balances.DiscountBalance;
|
||||
}
|
||||
catch
|
||||
{
|
||||
_discountBalance = 0;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task LoadAddresses()
|
||||
{
|
||||
_loadingAddresses = true;
|
||||
try
|
||||
{
|
||||
var response = await UserAddressContract.GetCustomerAddressesAsync(new());
|
||||
if (response?.Models?.Any() == true)
|
||||
{
|
||||
_addresses = response.Models.ToList();
|
||||
_selectedAddress = _addresses.FirstOrDefault(a => a.IsDefault) ?? _addresses.First();
|
||||
}
|
||||
else
|
||||
{
|
||||
_addresses = new();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Snackbar.Add($"خطا در بارگذاری آدرسها: {ex.Message}", Severity.Error);
|
||||
_addresses = new();
|
||||
}
|
||||
finally
|
||||
{
|
||||
_loadingAddresses = false;
|
||||
await InvokeAsync(StateHasChanged);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task PlaceOrder()
|
||||
{
|
||||
if (!CanPlaceOrder || _selectedAddress is null)
|
||||
{
|
||||
Snackbar.Add("لطفاً آدرس را انتخاب کنید.", Severity.Warning);
|
||||
return;
|
||||
}
|
||||
|
||||
_placing = true;
|
||||
try
|
||||
{
|
||||
// Clamp the discount balance to use
|
||||
var discountToUse = Math.Min(_discountBalanceToUse, MaxUsable);
|
||||
|
||||
var result = await DiscountOrderService.PlaceOrderAsync(
|
||||
_selectedAddress.Id,
|
||||
discountToUse,
|
||||
_notes);
|
||||
|
||||
if (!result.Success)
|
||||
{
|
||||
Snackbar.Add(result.Message, Severity.Error);
|
||||
return;
|
||||
}
|
||||
|
||||
// If there's a gateway payment URL, redirect to it
|
||||
if (!string.IsNullOrWhiteSpace(result.PaymentUrl) && result.GatewayAmount > 0)
|
||||
{
|
||||
Snackbar.Add("در حال انتقال به درگاه پرداخت...", Severity.Info);
|
||||
await DiscountCart.ClearAsync();
|
||||
Navigation.NavigateTo(result.PaymentUrl, forceLoad: true);
|
||||
return;
|
||||
}
|
||||
|
||||
// If fully paid via discount balance (no gateway needed)
|
||||
await DiscountCart.ClearAsync();
|
||||
Snackbar.Add("سفارش با موفقیت ثبت شد!", Severity.Success);
|
||||
Navigation.NavigateTo($"{RouteConstants.DiscountStore.OrderDetail}{result.OrderId}");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Snackbar.Add($"خطا در ثبت سفارش: {ex.Message}", Severity.Error);
|
||||
}
|
||||
finally
|
||||
{
|
||||
_placing = false;
|
||||
}
|
||||
}
|
||||
|
||||
private static string FormatPrice(long price) => $"{price:N0}";
|
||||
|
||||
private static string GetImageUrl(string? imageUrl)
|
||||
=> string.IsNullOrWhiteSpace(imageUrl) ? "/images/product-placeholder.svg" : imageUrl.TrimStart('/');
|
||||
}
|
||||
@@ -0,0 +1,198 @@
|
||||
@attribute [Route("/discount-store/order/{Id:long}")]
|
||||
|
||||
<PageTitle>جزئیات سفارش تخفیفی</PageTitle>
|
||||
|
||||
@if (!string.IsNullOrEmpty(_paymentMessage))
|
||||
{
|
||||
<MudContainer MaxWidth="MaxWidth.Medium" Class="pt-4">
|
||||
<MudAlert Severity="@_paymentSeverity" Variant="Variant.Filled" Class="mb-2"
|
||||
CloseIconClicked="() => _paymentMessage = null" ShowCloseIcon="true">
|
||||
@_paymentMessage
|
||||
</MudAlert>
|
||||
</MudContainer>
|
||||
}
|
||||
|
||||
@if (_loading)
|
||||
{
|
||||
<MudContainer MaxWidth="MaxWidth.Medium" Class="py-6">
|
||||
<LoadingState />
|
||||
</MudContainer>
|
||||
}
|
||||
else if (_order is null)
|
||||
{
|
||||
<MudContainer MaxWidth="MaxWidth.Medium" Class="py-6">
|
||||
<EmptyState Icon="@Icons.Material.Filled.SearchOff"
|
||||
Title="سفارش مورد نظر یافت نشد."
|
||||
ActionText="بازگشت به لیست سفارشها"
|
||||
ActionHref="@RouteConstants.DiscountStore.Orders" />
|
||||
</MudContainer>
|
||||
}
|
||||
else
|
||||
{
|
||||
<MudContainer MaxWidth="MaxWidth.Large" Class="py-6">
|
||||
<!-- Header -->
|
||||
<PageHeader Title="@($"سفارش #{_order.OrderNumber}")" BackHref="@RouteConstants.DiscountStore.Orders" />
|
||||
<MudStack Row="true" Spacing="2" Class="flex-wrap mb-4">
|
||||
<MudChip T="string" Color="@(_order.PaymentCompleted ? Color.Success : Color.Warning)"
|
||||
Variant="Variant.Filled">
|
||||
@(_order.PaymentCompleted ? "پرداخت شده" : "در انتظار پرداخت")
|
||||
</MudChip>
|
||||
<MudChip T="string" Color="@DiscountOrderService.GetDeliveryStatusColor(_order.DeliveryStatus)"
|
||||
Variant="Variant.Outlined">
|
||||
@DiscountOrderService.GetDeliveryStatusText(_order.DeliveryStatus)
|
||||
</MudChip>
|
||||
</MudStack>
|
||||
|
||||
<MudPaper Elevation="2" Class="pa-4 rounded-lg">
|
||||
<MudStack Spacing="2">
|
||||
<MudText Typo="Typo.caption" Class="mud-text-secondary">
|
||||
تاریخ ثبت: @FormatDate(_order.Created)
|
||||
</MudText>
|
||||
|
||||
@* ── Address ── *@
|
||||
@if (_order.Address is not null)
|
||||
{
|
||||
<MudText Typo="Typo.body2">
|
||||
<b>آدرس:</b> @_order.Address.Title — @_order.Address.Address
|
||||
</MudText>
|
||||
@if (!string.IsNullOrWhiteSpace(_order.Address.PostalCode))
|
||||
{
|
||||
<MudText Typo="Typo.caption" Class="mud-text-secondary">کد پستی: @_order.Address.PostalCode</MudText>
|
||||
}
|
||||
}
|
||||
|
||||
<MudDivider Class="my-2" />
|
||||
|
||||
@* ── Desktop: Table ── *@
|
||||
<MudHidden Breakpoint="Breakpoint.MdAndUp" Invert="true">
|
||||
<MudText Typo="Typo.h6" Class="mb-2">اقلام سفارش</MudText>
|
||||
<MudTable Items="_order.Items" Dense="true">
|
||||
<HeaderContent>
|
||||
<MudTh>محصول</MudTh>
|
||||
<MudTh>قیمت واحد</MudTh>
|
||||
<MudTh>تعداد</MudTh>
|
||||
<MudTh>سقف تخفیف</MudTh>
|
||||
<MudTh>تخفیف</MudTh>
|
||||
<MudTh>قیمت نهایی</MudTh>
|
||||
</HeaderContent>
|
||||
<RowTemplate>
|
||||
<MudTd>@context.Title</MudTd>
|
||||
<MudTd>@FormatPrice(context.UnitPrice)</MudTd>
|
||||
<MudTd>@context.Count</MudTd>
|
||||
<MudTd>
|
||||
@if (context.MaxDiscountPercent > 0)
|
||||
{
|
||||
<MudChip T="string" Size="Size.Small" Color="Color.Error" Variant="Variant.Outlined">@context.MaxDiscountPercent%</MudChip>
|
||||
}
|
||||
</MudTd>
|
||||
<MudTd>
|
||||
@if (context.DiscountAmount > 0)
|
||||
{
|
||||
<MudText Color="Color.Success">@FormatPrice(context.DiscountAmount)-</MudText>
|
||||
}
|
||||
else
|
||||
{
|
||||
<MudText Class="mud-text-secondary">—</MudText>
|
||||
}
|
||||
</MudTd>
|
||||
<MudTd>@FormatPrice(context.FinalPrice)</MudTd>
|
||||
</RowTemplate>
|
||||
</MudTable>
|
||||
</MudHidden>
|
||||
|
||||
@* ── Mobile: Cards ── *@
|
||||
<MudHidden Breakpoint="Breakpoint.MdAndUp">
|
||||
<MudText Typo="Typo.h6" Class="mb-2">اقلام سفارش</MudText>
|
||||
<MudStack Spacing="2">
|
||||
@foreach (var item in _order.Items)
|
||||
{
|
||||
<MudPaper Class="pa-3 rounded-lg" Outlined="true">
|
||||
<MudStack Spacing="1">
|
||||
<MudText Typo="Typo.subtitle2">@item.Title</MudText>
|
||||
<MudStack Row="true" Justify="Justify.SpaceBetween">
|
||||
<MudText Typo="Typo.body2" Class="mud-text-secondary">قیمت واحد:</MudText>
|
||||
<MudText Typo="Typo.body2">@FormatPrice(item.UnitPrice)</MudText>
|
||||
</MudStack>
|
||||
<MudStack Row="true" Justify="Justify.SpaceBetween">
|
||||
<MudText Typo="Typo.body2" Class="mud-text-secondary">تعداد:</MudText>
|
||||
<MudText Typo="Typo.body2">@item.Count</MudText>
|
||||
</MudStack>
|
||||
@if (item.DiscountAmount > 0)
|
||||
{
|
||||
<MudStack Row="true" Justify="Justify.SpaceBetween">
|
||||
<MudText Typo="Typo.body2" Color="Color.Success">تخفیف (@item.MaxDiscountPercent%):</MudText>
|
||||
<MudText Typo="Typo.body2" Color="Color.Success">@FormatPrice(item.DiscountAmount)-</MudText>
|
||||
</MudStack>
|
||||
}
|
||||
<MudStack Row="true" Justify="Justify.SpaceBetween">
|
||||
<MudText Typo="Typo.subtitle2">قیمت نهایی:</MudText>
|
||||
<MudText Typo="Typo.subtitle2" Color="Color.Primary">@FormatPrice(item.FinalPrice)</MudText>
|
||||
</MudStack>
|
||||
</MudStack>
|
||||
</MudPaper>
|
||||
}
|
||||
</MudStack>
|
||||
</MudHidden>
|
||||
|
||||
<MudDivider Class="my-2" />
|
||||
|
||||
@* ── Financial Summary ── *@
|
||||
<MudStack Spacing="1" Class="pa-3" Style="background-color: var(--mud-palette-background-grey); border-radius: 8px;">
|
||||
<MudText Typo="Typo.h6" Class="mb-1">خلاصه مالی</MudText>
|
||||
<MudStack Row="true" Justify="Justify.SpaceBetween">
|
||||
<MudText Typo="Typo.body2">جمع کل:</MudText>
|
||||
<MudText Typo="Typo.body2">@FormatPrice(_order.TotalPrice)</MudText>
|
||||
</MudStack>
|
||||
|
||||
@if (_order.DiscountBalanceUsed > 0)
|
||||
{
|
||||
<MudStack Row="true" Justify="Justify.SpaceBetween">
|
||||
<MudText Typo="Typo.body2" Color="Color.Success">از کیف تخفیفی:</MudText>
|
||||
<MudText Typo="Typo.body2" Color="Color.Success">@FormatPrice(_order.DiscountBalanceUsed)-</MudText>
|
||||
</MudStack>
|
||||
}
|
||||
|
||||
<MudDivider Class="my-1" />
|
||||
|
||||
<MudStack Row="true" Justify="Justify.SpaceBetween">
|
||||
<MudText Typo="Typo.subtitle1" Class="fw-bold">پرداخت درگاه:</MudText>
|
||||
<MudText Typo="Typo.subtitle1" Color="Color.Primary" Class="fw-bold">
|
||||
@FormatPrice(_order.GatewayAmount)
|
||||
</MudText>
|
||||
</MudStack>
|
||||
</MudStack>
|
||||
|
||||
@* ── Tracking / Transaction ── *@
|
||||
@if (!string.IsNullOrWhiteSpace(_order.TrackingCode))
|
||||
{
|
||||
<MudStack Row="true" Justify="Justify.SpaceBetween">
|
||||
<MudText Typo="Typo.body2">کد رهگیری:</MudText>
|
||||
<MudText Typo="Typo.body2" Class="fw-semibold">@_order.TrackingCode</MudText>
|
||||
</MudStack>
|
||||
}
|
||||
@if (!string.IsNullOrWhiteSpace(_order.TransactionId))
|
||||
{
|
||||
<MudStack Row="true" Justify="Justify.SpaceBetween">
|
||||
<MudText Typo="Typo.caption" Class="mud-text-secondary">شناسه تراکنش:</MudText>
|
||||
<MudText Typo="Typo.caption" Class="mud-text-secondary">@_order.TransactionId</MudText>
|
||||
</MudStack>
|
||||
}
|
||||
|
||||
@* ── Notes ── *@
|
||||
@if (!string.IsNullOrWhiteSpace(_order.Notes))
|
||||
{
|
||||
<MudDivider Class="my-1" />
|
||||
<MudText Typo="Typo.body2" Class="mud-text-secondary">
|
||||
<b>توضیحات:</b> @_order.Notes
|
||||
</MudText>
|
||||
}
|
||||
@if (!string.IsNullOrWhiteSpace(_order.AdminNotes))
|
||||
{
|
||||
<MudAlert Severity="Severity.Info" Variant="Variant.Outlined" Dense="true">
|
||||
<b>پیام مدیر:</b> @_order.AdminNotes
|
||||
</MudAlert>
|
||||
}
|
||||
</MudStack>
|
||||
</MudPaper>
|
||||
</MudContainer>
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using DateTimeConverterCL;
|
||||
using FrontOffice.Main.Utilities;
|
||||
|
||||
namespace FrontOffice.Main.Pages.DiscountStore;
|
||||
|
||||
public partial class OrderDetail
|
||||
{
|
||||
[Parameter] public long Id { get; set; }
|
||||
|
||||
[SupplyParameterFromQuery(Name = "payment")]
|
||||
public string? PaymentResult { get; set; }
|
||||
|
||||
[Inject] private DiscountOrderService DiscountOrderService { get; set; } = default!;
|
||||
|
||||
private DiscountOrderDetail? _order;
|
||||
private bool _loading = true;
|
||||
private string? _paymentMessage;
|
||||
private MudBlazor.Severity _paymentSeverity;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
// نمایش پیام نتیجه پرداخت (بعد از بازگشت از درگاه)
|
||||
if (!string.IsNullOrEmpty(PaymentResult))
|
||||
{
|
||||
switch (PaymentResult.ToLower())
|
||||
{
|
||||
case "success":
|
||||
_paymentMessage = "پرداخت با موفقیت انجام شد! سفارش شما ثبت نهایی شد.";
|
||||
_paymentSeverity = MudBlazor.Severity.Success;
|
||||
break;
|
||||
case "failed":
|
||||
_paymentMessage = "پرداخت ناموفق بود. مبلغ رزرو شده آزاد خواهد شد.";
|
||||
_paymentSeverity = MudBlazor.Severity.Error;
|
||||
break;
|
||||
case "error":
|
||||
_paymentMessage = "خطایی در پردازش پرداخت رخ داد. لطفاً با پشتیبانی تماس بگیرید.";
|
||||
_paymentSeverity = MudBlazor.Severity.Warning;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
await LoadOrderAsync();
|
||||
}
|
||||
|
||||
private async Task LoadOrderAsync()
|
||||
{
|
||||
_loading = true;
|
||||
try
|
||||
{
|
||||
_order = await DiscountOrderService.GetOrderByIdAsync(Id);
|
||||
}
|
||||
catch
|
||||
{
|
||||
Snackbar.Add("خطا در بارگذاری سفارش", MudBlazor.Severity.Error);
|
||||
}
|
||||
finally
|
||||
{
|
||||
_loading = false;
|
||||
}
|
||||
}
|
||||
|
||||
private static string FormatPrice(long price) => $"{price:N0} تومان";
|
||||
|
||||
private static string FormatDate(DateTime date)
|
||||
{
|
||||
try
|
||||
{
|
||||
return date.ToLocalTime().MiladiToJalaliWithTime();
|
||||
}
|
||||
catch
|
||||
{
|
||||
return date.ToString("yyyy/MM/dd");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,130 @@
|
||||
@attribute [Route(RouteConstants.DiscountStore.Orders)]
|
||||
|
||||
<PageTitle>سفارشهای فروشگاه تخفیفی</PageTitle>
|
||||
|
||||
<MudContainer MaxWidth="MaxWidth.Large" Class="py-6">
|
||||
<MudStack Spacing="3">
|
||||
<PageHeader Title="سفارشهای تخفیفی" BackHref="@RouteConstants.DiscountStore.Products" />
|
||||
|
||||
@if (_loading)
|
||||
{
|
||||
<LoadingState />
|
||||
}
|
||||
else if (_orders.Count == 0)
|
||||
{
|
||||
<MudAlert Severity="Severity.Info">هنوز سفارشی ثبت نشده است.</MudAlert>
|
||||
<MudButton Variant="Variant.Outlined" StartIcon="@Icons.Material.Filled.Store"
|
||||
Href="@RouteConstants.DiscountStore.Products">
|
||||
مشاهده فروشگاه تخفیفی
|
||||
</MudButton>
|
||||
}
|
||||
else
|
||||
{
|
||||
<!-- Desktop Table -->
|
||||
<MudHidden Breakpoint="Breakpoint.MdAndUp" Invert="true">
|
||||
<MudPaper Elevation="1" Class="pa-4 rounded-lg">
|
||||
<MudTable Items="_orders">
|
||||
<HeaderContent>
|
||||
<MudTh>شماره سفارش</MudTh>
|
||||
<MudTh>تعداد اقلام</MudTh>
|
||||
<MudTh>مبلغ کل</MudTh>
|
||||
<MudTh>از کیف تخفیفی</MudTh>
|
||||
<MudTh>درگاه</MudTh>
|
||||
<MudTh>وضعیت پرداخت</MudTh>
|
||||
<MudTh>وضعیت ارسال</MudTh>
|
||||
<MudTh>تاریخ</MudTh>
|
||||
<MudTh></MudTh>
|
||||
</HeaderContent>
|
||||
<RowTemplate>
|
||||
<MudTd>@context.OrderNumber</MudTd>
|
||||
<MudTd>@context.ItemsCount</MudTd>
|
||||
<MudTd>@FormatPrice(context.TotalPrice)</MudTd>
|
||||
<MudTd>
|
||||
@if (context.DiscountBalanceUsed > 0)
|
||||
{
|
||||
<MudText Color="Color.Success">@FormatPrice(context.DiscountBalanceUsed)</MudText>
|
||||
}
|
||||
else
|
||||
{
|
||||
<MudText Class="mud-text-secondary">—</MudText>
|
||||
}
|
||||
</MudTd>
|
||||
<MudTd>@FormatPrice(context.GatewayAmount)</MudTd>
|
||||
<MudTd>
|
||||
<MudChip T="string" Size="Size.Small"
|
||||
Color="@(context.PaymentCompleted ? Color.Success : Color.Warning)"
|
||||
Variant="Variant.Filled">
|
||||
@(context.PaymentCompleted ? "پرداخت شده" : "در انتظار پرداخت")
|
||||
</MudChip>
|
||||
</MudTd>
|
||||
<MudTd>
|
||||
<MudChip T="string" Size="Size.Small"
|
||||
Color="@DiscountOrderService.GetDeliveryStatusColor(context.DeliveryStatus)"
|
||||
Variant="Variant.Outlined">
|
||||
@DiscountOrderService.GetDeliveryStatusText(context.DeliveryStatus)
|
||||
</MudChip>
|
||||
</MudTd>
|
||||
<MudTd>@FormatDate(context.Created)</MudTd>
|
||||
<MudTd>
|
||||
<MudButton Size="Size.Small" Variant="Variant.Outlined" Color="Color.Primary"
|
||||
OnClick="() => ViewOrder(context.Id)">
|
||||
جزئیات
|
||||
</MudButton>
|
||||
</MudTd>
|
||||
</RowTemplate>
|
||||
</MudTable>
|
||||
</MudPaper>
|
||||
</MudHidden>
|
||||
|
||||
<!-- Mobile Cards -->
|
||||
<MudHidden Breakpoint="Breakpoint.MdAndUp">
|
||||
<MudStack Spacing="2">
|
||||
@foreach (var order in _orders)
|
||||
{
|
||||
<MudPaper Class="pa-3 rounded-lg cursor-pointer" Outlined="true"
|
||||
@onclick="() => ViewOrder(order.Id)">
|
||||
<MudStack Spacing="1">
|
||||
<MudStack Row="true" Justify="Justify.SpaceBetween" AlignItems="AlignItems.Center">
|
||||
<MudText Typo="Typo.subtitle2">سفارش #@order.OrderNumber</MudText>
|
||||
<MudChip T="string" Size="Size.Small"
|
||||
Color="@(order.PaymentCompleted ? Color.Success : Color.Warning)"
|
||||
Variant="Variant.Filled">
|
||||
@(order.PaymentCompleted ? "پرداخت شده" : "در انتظار")
|
||||
</MudChip>
|
||||
</MudStack>
|
||||
<MudStack Row="true" Justify="Justify.SpaceBetween">
|
||||
<MudText Typo="Typo.caption" Class="mud-text-secondary">@FormatDate(order.Created)</MudText>
|
||||
<MudChip T="string" Size="Size.Small"
|
||||
Color="@DiscountOrderService.GetDeliveryStatusColor(order.DeliveryStatus)"
|
||||
Variant="Variant.Outlined">
|
||||
@DiscountOrderService.GetDeliveryStatusText(order.DeliveryStatus)
|
||||
</MudChip>
|
||||
</MudStack>
|
||||
<MudDivider />
|
||||
<MudStack Row="true" Justify="Justify.SpaceBetween">
|
||||
<MudText Typo="Typo.body2">@order.ItemsCount قلم</MudText>
|
||||
<MudText Typo="Typo.body2" Class="fw-semibold">@FormatPrice(order.TotalPrice) تومان</MudText>
|
||||
</MudStack>
|
||||
@if (order.DiscountBalanceUsed > 0)
|
||||
{
|
||||
<MudText Typo="Typo.caption" Color="Color.Success">
|
||||
از کیف تخفیفی: @FormatPrice(order.DiscountBalanceUsed) تومان
|
||||
</MudText>
|
||||
}
|
||||
</MudStack>
|
||||
</MudPaper>
|
||||
}
|
||||
</MudStack>
|
||||
</MudHidden>
|
||||
|
||||
@if (_totalPages > 1)
|
||||
{
|
||||
<MudStack AlignItems="AlignItems.Center" Class="mt-4">
|
||||
<MudPagination Count="@_totalPages" Selected="@_currentPage"
|
||||
SelectedChanged="OnPageChanged" Color="Color.Primary"
|
||||
Variant="Variant.Outlined" />
|
||||
</MudStack>
|
||||
}
|
||||
}
|
||||
</MudStack>
|
||||
</MudContainer>
|
||||
@@ -0,0 +1,65 @@
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using DateTimeConverterCL;
|
||||
using FrontOffice.Main.Utilities;
|
||||
|
||||
namespace FrontOffice.Main.Pages.DiscountStore;
|
||||
|
||||
public partial class Orders
|
||||
{
|
||||
[Inject] private DiscountOrderService DiscountOrderService { get; set; } = default!;
|
||||
|
||||
private List<DiscountOrderSummary> _orders = new();
|
||||
private int _currentPage = 1;
|
||||
private int _totalPages;
|
||||
private bool _loading = true;
|
||||
private const int PageSize = 10;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
await LoadOrdersAsync();
|
||||
}
|
||||
|
||||
private async Task LoadOrdersAsync()
|
||||
{
|
||||
_loading = true;
|
||||
try
|
||||
{
|
||||
var result = await DiscountOrderService.GetUserOrdersAsync(_currentPage, PageSize);
|
||||
_orders = result.Orders;
|
||||
_totalPages = result.TotalPages;
|
||||
}
|
||||
catch
|
||||
{
|
||||
Snackbar.Add("خطا در بارگذاری سفارشها", MudBlazor.Severity.Error);
|
||||
}
|
||||
finally
|
||||
{
|
||||
_loading = false;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task OnPageChanged(int page)
|
||||
{
|
||||
_currentPage = page;
|
||||
await LoadOrdersAsync();
|
||||
}
|
||||
|
||||
private void ViewOrder(long orderId)
|
||||
{
|
||||
Navigation.NavigateTo($"{RouteConstants.DiscountStore.OrderDetail}{orderId}");
|
||||
}
|
||||
|
||||
private static string FormatPrice(long price) => $"{price:N0}";
|
||||
|
||||
private static string FormatDate(DateTime date)
|
||||
{
|
||||
try
|
||||
{
|
||||
return date.ToLocalTime().MiladiToJalaliWithTime();
|
||||
}
|
||||
catch
|
||||
{
|
||||
return date.ToString("yyyy/MM/dd");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
@attribute [Route("/discount-store/product/{Id:long}")]
|
||||
|
||||
<PageTitle>@(_product?.Title ?? "محصول تخفیفی")</PageTitle>
|
||||
|
||||
<MudContainer MaxWidth="MaxWidth.Large" Class="py-4 py-md-6">
|
||||
@if (_loading)
|
||||
{
|
||||
<LoadingState />
|
||||
}
|
||||
else if (_product is null)
|
||||
{
|
||||
<EmptyState Icon="@Icons.Material.Filled.SearchOff"
|
||||
Title="محصول مورد نظر یافت نشد."
|
||||
ActionText="بازگشت به فروشگاه تخفیفی"
|
||||
ActionHref="@RouteConstants.DiscountStore.Products" />
|
||||
}
|
||||
else
|
||||
{
|
||||
<!-- Breadcrumb -->
|
||||
<PageHeader Title="جزئیات محصول تخفیفی" BackHref="@RouteConstants.DiscountStore.Products" />
|
||||
|
||||
<MudGrid Spacing="4">
|
||||
<!-- Image Gallery -->
|
||||
<MudItem xs="12" md="5">
|
||||
<MudPaper Class="pa-2 rounded-xl" Elevation="1">
|
||||
<AppImage Path="@_selectedImage" Alt="@_product.Title"
|
||||
ObjectFit="ObjectFit.Contain"
|
||||
Style="width:100%; max-height:400px; border-radius:12px;" />
|
||||
|
||||
@if (_product.Images.Count > 1)
|
||||
{
|
||||
<MudStack Row="true" Spacing="1" Class="mt-2 flex-wrap" Justify="Justify.Center">
|
||||
@foreach (var img in _product.Images)
|
||||
{
|
||||
<span @onclick="() => _selectedImage = img.ImageUrl" style="cursor:pointer">
|
||||
<AppImage Path="@img.ThumbnailUrl" Alt="@(img.Title ?? "")"
|
||||
ImgWidth="60" ImgHeight="60"
|
||||
ObjectFit="ObjectFit.Cover"
|
||||
Class="rounded-lg"
|
||||
Style="@($"border: 2px solid {(img.ImageUrl == _selectedImage ? "var(--mud-palette-primary)" : "transparent")};")"
|
||||
/>
|
||||
</span>
|
||||
}
|
||||
</MudStack>
|
||||
}
|
||||
</MudPaper>
|
||||
</MudItem>
|
||||
|
||||
<!-- Product Info -->
|
||||
<MudItem xs="12" md="7">
|
||||
<MudStack Spacing="3">
|
||||
<MudText Typo="Typo.h5" Class="fw-bold">@_product.Title</MudText>
|
||||
|
||||
<!-- Categories -->
|
||||
@if (_product.Categories.Any())
|
||||
{
|
||||
<MudStack Row="true" Spacing="1" Class="flex-wrap">
|
||||
@foreach (var cat in _product.Categories)
|
||||
{
|
||||
<MudChip T="string" Color="Color.Info" Variant="Variant.Outlined" Size="Size.Small">@cat.Title</MudChip>
|
||||
}
|
||||
</MudStack>
|
||||
}
|
||||
|
||||
<!-- Price & Discount -->
|
||||
<MudPaper Class="pa-4 rounded-lg discount-price-box" Elevation="0">
|
||||
<MudStack Spacing="2">
|
||||
<MudStack Row="true" Justify="Justify.SpaceBetween" AlignItems="AlignItems.Center">
|
||||
<MudText Typo="Typo.body2" Class="mud-text-secondary">قیمت محصول:</MudText>
|
||||
<MudText Typo="Typo.h5" Color="Color.Primary" Class="fw-bold">
|
||||
@($"{_product.Price:N0}") تومان
|
||||
</MudText>
|
||||
</MudStack>
|
||||
@if (_product.MaxDiscountPercent > 0)
|
||||
{
|
||||
<MudStack Row="true" Justify="Justify.SpaceBetween" AlignItems="AlignItems.Center">
|
||||
<MudText Typo="Typo.body2" Class="mud-text-secondary">سقف پرداخت از کیف تخفیفی:</MudText>
|
||||
<MudChip T="string" Color="Color.Error" Variant="Variant.Filled" Size="Size.Small">
|
||||
تا @_product.MaxDiscountPercent% (تا @($"{_product.Price * _product.MaxDiscountPercent / 100:N0}") تومان)
|
||||
</MudChip>
|
||||
</MudStack>
|
||||
}
|
||||
</MudStack>
|
||||
</MudPaper>
|
||||
|
||||
<!-- Stock & Stats -->
|
||||
<MudStack Row="true" Spacing="3" Class="flex-wrap">
|
||||
<MudChip T="string" Variant="Variant.Outlined" Size="Size.Small"
|
||||
Color="@(_product.RemainingCount > 0 ? Color.Success : Color.Error)"
|
||||
Icon="@Icons.Material.Filled.Inventory">
|
||||
@(_product.RemainingCount > 0 ? $"موجود ({_product.RemainingCount} عدد)" : "ناموجود")
|
||||
</MudChip>
|
||||
<MudChip T="string" Variant="Variant.Outlined" Size="Size.Small" Color="Color.Default"
|
||||
Icon="@Icons.Material.Filled.Visibility">
|
||||
@_product.ViewCount بازدید
|
||||
</MudChip>
|
||||
</MudStack>
|
||||
|
||||
<!-- Short Info -->
|
||||
@if (!string.IsNullOrWhiteSpace(_product.ShortInfo))
|
||||
{
|
||||
<MudText Typo="Typo.body1" Class="mud-text-secondary">@_product.ShortInfo</MudText>
|
||||
}
|
||||
|
||||
<!-- Add to Cart -->
|
||||
<MudStack Row="true" Spacing="2" AlignItems="AlignItems.Center" Class="flex-wrap">
|
||||
<MudNumericField T="int" @bind-Value="_quantity" Min="1"
|
||||
Max="@(_product.RemainingCount > 0 ? _product.RemainingCount : 1)"
|
||||
Label="تعداد" Variant="Variant.Outlined" Margin="Margin.Dense"
|
||||
Style="width:100px;" />
|
||||
<MudButton Variant="Variant.Filled" Color="Color.Success"
|
||||
StartIcon="@Icons.Material.Filled.AddShoppingCart"
|
||||
OnClick="AddToCart"
|
||||
Disabled="@(_product.RemainingCount <= 0 || _addingToCart)"
|
||||
Size="Size.Large">
|
||||
@(_addingToCart ? "در حال افزودن..." : "افزودن به سبد")
|
||||
</MudButton>
|
||||
<MudButton Variant="Variant.Outlined" Color="Color.Primary"
|
||||
StartIcon="@Icons.Material.Filled.ShoppingCart"
|
||||
Href="@RouteConstants.DiscountStore.Cart">
|
||||
مشاهده سبد
|
||||
</MudButton>
|
||||
</MudStack>
|
||||
</MudStack>
|
||||
</MudItem>
|
||||
</MudGrid>
|
||||
|
||||
<!-- Full Information -->
|
||||
@if (!string.IsNullOrWhiteSpace(_product.FullInfo))
|
||||
{
|
||||
<MudPaper Elevation="1" Class="pa-4 pa-md-6 mt-6 rounded-lg">
|
||||
<MudText Typo="Typo.h6" Class="mb-3">توضیحات محصول</MudText>
|
||||
<MudDivider Class="mb-4" />
|
||||
<div class="blog-content">
|
||||
@((MarkupString)_product.FullInfo)
|
||||
</div>
|
||||
</MudPaper>
|
||||
}
|
||||
}
|
||||
</MudContainer>
|
||||
@@ -0,0 +1,64 @@
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using FrontOffice.Main.Utilities;
|
||||
|
||||
namespace FrontOffice.Main.Pages.DiscountStore;
|
||||
|
||||
public partial class ProductDetail
|
||||
{
|
||||
[Parameter] public long Id { get; set; }
|
||||
|
||||
[Inject] private DiscountProductService DiscountProductService { get; set; } = default!;
|
||||
[Inject] private DiscountCartService DiscountCartService { get; set; } = default!;
|
||||
|
||||
private DiscountProductDetail? _product;
|
||||
private string _selectedImage = string.Empty;
|
||||
private int _quantity = 1;
|
||||
private bool _loading = true;
|
||||
private bool _addingToCart;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
await LoadProductAsync();
|
||||
}
|
||||
|
||||
private async Task LoadProductAsync()
|
||||
{
|
||||
_loading = true;
|
||||
try
|
||||
{
|
||||
_product = await DiscountProductService.GetByIdAsync(Id);
|
||||
if (_product is not null)
|
||||
{
|
||||
_selectedImage = _product.Images.FirstOrDefault()?.ImageUrl
|
||||
?? _product.ThumbnailUrl;
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
Snackbar.Add("خطا در بارگذاری محصول", MudBlazor.Severity.Error);
|
||||
}
|
||||
finally
|
||||
{
|
||||
_loading = false;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task AddToCart()
|
||||
{
|
||||
if (_product is null) return;
|
||||
_addingToCart = true;
|
||||
try
|
||||
{
|
||||
await DiscountCartService.AddAsync(_product.Id, _quantity);
|
||||
Snackbar.Add($"{_product.Title} به سبد خرید اضافه شد", MudBlazor.Severity.Success);
|
||||
}
|
||||
catch
|
||||
{
|
||||
Snackbar.Add("خطا در افزودن به سبد خرید", MudBlazor.Severity.Error);
|
||||
}
|
||||
finally
|
||||
{
|
||||
_addingToCart = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
@attribute [Route(RouteConstants.DiscountStore.Products)]
|
||||
|
||||
<PageTitle>فروشگاه تخفیفی</PageTitle>
|
||||
|
||||
<MudContainer MaxWidth="MaxWidth.Large" Class="py-6">
|
||||
<!-- Hero -->
|
||||
<MudPaper Class="discount-hero pa-6 pa-md-8 mb-4 rounded-xl" Elevation="0">
|
||||
<MudStack AlignItems="AlignItems.Center" Spacing="2">
|
||||
<MudIcon Icon="@Icons.Material.Filled.Loyalty" Size="Size.Large" Class="dash-hero-name" />
|
||||
<MudText Typo="Typo.h5" Align="Align.Center" Class="dash-hero-name">فروشگاه تخفیفی</MudText>
|
||||
<MudText Typo="Typo.body2" Align="Align.Center" Class="dash-hero-sub">
|
||||
خرید با استفاده از موجودی کیف پول تخفیفی
|
||||
</MudText>
|
||||
</MudStack>
|
||||
</MudPaper>
|
||||
|
||||
<!-- Filters -->
|
||||
<MudPaper Elevation="1" Class="pa-3 pa-md-4 mb-4 rounded-lg">
|
||||
<MudGrid Spacing="2" AlignItems="AlignItems.Center">
|
||||
<MudItem xs="12" sm="5">
|
||||
<MudTextField @bind-Value="_search"
|
||||
Placeholder="جستجو در محصولات..."
|
||||
AdornmentIcon="@Icons.Material.Filled.Search"
|
||||
Adornment="Adornment.Start"
|
||||
Immediate="true"
|
||||
OnKeyUp="OnSearchKeyUp"
|
||||
Variant="Variant.Outlined"
|
||||
Margin="Margin.Dense" />
|
||||
</MudItem>
|
||||
<MudItem xs="8" sm="5">
|
||||
<MudSelect T="long?" Value="_selectedCategoryId" ValueChanged="OnCategoryChanged"
|
||||
Label="دستهبندی" Variant="Variant.Outlined" Margin="Margin.Dense"
|
||||
Clearable="true" AnchorOrigin="Origin.BottomCenter">
|
||||
@foreach (var cat in _categories)
|
||||
{
|
||||
<MudSelectItem T="long?" Value="@((long?)cat.Id)">@cat.Title (@cat.ProductCount)</MudSelectItem>
|
||||
}
|
||||
</MudSelect>
|
||||
</MudItem>
|
||||
<MudItem xs="4" sm="2" Class="d-flex gap-2">
|
||||
<MudButton Variant="Variant.Filled" Color="Color.Primary" FullWidth="true"
|
||||
StartIcon="@Icons.Material.Filled.Search" OnClick="SearchProducts"
|
||||
Style="height:40px;">جستجو</MudButton>
|
||||
</MudItem>
|
||||
<MudItem xs="12" Class="d-flex justify-start justify-md-end gap-2">
|
||||
<MudButton Size="Size.Small" Variant="Variant.Filled" Color="Color.Primary"
|
||||
StartIcon="@Icons.Material.Filled.ShoppingCart"
|
||||
Href="@RouteConstants.DiscountStore.Cart">
|
||||
سبد خرید
|
||||
@if (DiscountCart.Count > 0)
|
||||
{
|
||||
<MudBadge Content="@DiscountCart.Count" Color="Color.Error" Overlap="true" Class="ms-2" />
|
||||
}
|
||||
</MudButton>
|
||||
</MudItem>
|
||||
</MudGrid>
|
||||
</MudPaper>
|
||||
|
||||
<!-- Loading -->
|
||||
@if (_loading)
|
||||
{
|
||||
<MudStack AlignItems="AlignItems.Center" Class="py-8">
|
||||
<MudProgressCircular Color="Color.Primary" Indeterminate="true" />
|
||||
<MudText Class="mt-2 mud-text-secondary">در حال بارگذاری...</MudText>
|
||||
</MudStack>
|
||||
}
|
||||
else if (_result.Products.Count == 0)
|
||||
{
|
||||
<MudAlert Severity="Severity.Info" Class="my-4">محصولی یافت نشد.</MudAlert>
|
||||
}
|
||||
else
|
||||
{
|
||||
<!-- Products Grid -->
|
||||
<MudGrid Spacing="1">
|
||||
@foreach (var p in _result.Products)
|
||||
{
|
||||
<MudItem xs="6" sm="6" md="3"
|
||||
onclick="@(() => NavigateToProduct(p.Id))">
|
||||
<MudCard Class="rounded-lg h-100 d-flex flex-column overflow-hidden"
|
||||
Style="cursor:pointer;height: 300px">
|
||||
<MudCardContent Class="d-flex flex-column pa-1 h-100">
|
||||
<div style="height: 60%;background-image: url('@(string.IsNullOrWhiteSpace(p.ThumbnailUrl) ? "/images/product-placeholder.svg" : p.ThumbnailUrl)');background-size: cover; background-position: center;border-radius: 0.5rem; position: relative;">
|
||||
@if (p.RemainingCount <= 0)
|
||||
{
|
||||
<div style="position:absolute;top:0;left:0;right:0;bottom:0;background:rgba(0,0,0,0.5);display:flex;align-items:center;justify-content:center;border-radius:0.5rem;">
|
||||
<MudChip T="string" Color="Color.Error" Variant="Variant.Filled" Size="Size.Small">ناموجود</MudChip>
|
||||
</div>
|
||||
}
|
||||
else if (p.RemainingCount <= 5)
|
||||
{
|
||||
<MudChip T="string" Color="Color.Warning" Variant="Variant.Filled" Size="Size.Small"
|
||||
Style="position:absolute;top:8px;right:8px;">
|
||||
فقط @p.RemainingCount عدد
|
||||
</MudChip>
|
||||
}
|
||||
@if (p.MaxDiscountPercent > 0)
|
||||
{
|
||||
<MudChip T="string" Color="Color.Error" Variant="Variant.Filled" Size="Size.Small"
|
||||
Style="position:absolute;top:8px;left:8px;">
|
||||
تا @p.MaxDiscountPercent% تخفیف
|
||||
</MudChip>
|
||||
}
|
||||
</div>
|
||||
<div class="pa-1 flex-grow-1 d-flex flex-column justify-space-between">
|
||||
<MudText Typo="Typo.subtitle1">@p.Title</MudText>
|
||||
<MudText Typo="Typo.subtitle2" Color="Color.Primary">@FormatPrice(p.Price)</MudText>
|
||||
</div>
|
||||
</MudCardContent>
|
||||
<MudCardActions Class="mt-auto d-flex justify-space-between pa-2">
|
||||
<MudButton Variant="Variant.Filled" Color="Color.Primary"
|
||||
OnClick="@(() => AddToCart(p))"
|
||||
StartIcon="@Icons.Material.Filled.AddShoppingCart"
|
||||
Disabled="@(p.RemainingCount <= 0)">
|
||||
@(p.RemainingCount <= 0 ? "ناموجود" : "افزودن")
|
||||
</MudButton>
|
||||
</MudCardActions>
|
||||
</MudCard>
|
||||
</MudItem>
|
||||
}
|
||||
</MudGrid>
|
||||
|
||||
<!-- Pagination -->
|
||||
@if (_result.TotalPages > 1)
|
||||
{
|
||||
<div class="d-flex justify-center mt-4">
|
||||
<MudPagination Count="@_result.TotalPages" Selected="@_currentPage"
|
||||
SelectedChanged="OnPageChanged"
|
||||
Color="Color.Primary" Variant="Variant.Filled"
|
||||
BoundaryCount="1" MiddleCount="3" />
|
||||
</div>
|
||||
}
|
||||
}
|
||||
</MudContainer>
|
||||
@@ -0,0 +1,87 @@
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Microsoft.AspNetCore.Components.Web;
|
||||
using FrontOffice.Main.Utilities;
|
||||
|
||||
namespace FrontOffice.Main.Pages.DiscountStore;
|
||||
|
||||
public partial class Products : ComponentBase, IDisposable
|
||||
{
|
||||
[Inject] private DiscountProductService ProductService { get; set; } = default!;
|
||||
[Inject] private DiscountCartService DiscountCart { get; set; } = default!;
|
||||
|
||||
private string _search = string.Empty;
|
||||
private long? _selectedCategoryId;
|
||||
private int _currentPage = 1;
|
||||
private bool _loading;
|
||||
private const int PageSize = 12;
|
||||
|
||||
private DiscountProductListResult _result = new(new(), 0, 0, 1);
|
||||
private List<DiscountCategoryNode> _categories = new();
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
_loading = true;
|
||||
await DiscountCart.EnsureInitializedAsync();
|
||||
DiscountCart.OnChange += StateHasChanged;
|
||||
var categoriesTask = ProductService.GetCategoriesAsync();
|
||||
var productsTask = ProductService.GetProductsAsync(page: 1, pageSize: PageSize);
|
||||
await Task.WhenAll(categoriesTask, productsTask);
|
||||
_categories = categoriesTask.Result;
|
||||
_result = productsTask.Result;
|
||||
_loading = false;
|
||||
}
|
||||
|
||||
private async Task LoadProductsAsync()
|
||||
{
|
||||
_loading = true;
|
||||
StateHasChanged();
|
||||
_result = await ProductService.GetProductsAsync(
|
||||
page: _currentPage,
|
||||
pageSize: PageSize,
|
||||
search: string.IsNullOrWhiteSpace(_search) ? null : _search,
|
||||
categoryId: _selectedCategoryId);
|
||||
_loading = false;
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
private async Task SearchProducts() => await LoadProductsAsync();
|
||||
|
||||
private async Task OnSearchKeyUp(KeyboardEventArgs e)
|
||||
{
|
||||
if (e.Key == "Enter")
|
||||
{
|
||||
_currentPage = 1;
|
||||
await LoadProductsAsync();
|
||||
}
|
||||
}
|
||||
|
||||
private async Task OnCategoryChanged(long? value)
|
||||
{
|
||||
_selectedCategoryId = value;
|
||||
_currentPage = 1;
|
||||
await LoadProductsAsync();
|
||||
}
|
||||
|
||||
private async Task OnPageChanged(int page)
|
||||
{
|
||||
_currentPage = page;
|
||||
await LoadProductsAsync();
|
||||
}
|
||||
|
||||
private async Task AddToCart(DiscountProductCard p)
|
||||
{
|
||||
await DiscountCart.AddAsync(p.Id);
|
||||
}
|
||||
|
||||
private void NavigateToProduct(long id)
|
||||
{
|
||||
Navigation.NavigateTo($"{RouteConstants.DiscountStore.ProductDetail}{id}");
|
||||
}
|
||||
|
||||
private static string FormatPrice(long price) => $"{price:N0} تومان";
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
DiscountCart.OnChange -= StateHasChanged;
|
||||
}
|
||||
}
|
||||
@@ -116,7 +116,7 @@
|
||||
<!-- Contact Support -->
|
||||
<section class="py-12 bg-grey-50">
|
||||
<MudContainer MaxWidth="MaxWidth.Large">
|
||||
<MudPaper Elevation="3" Class="pa-8 text-center">
|
||||
<MudPaper Elevation="2" Class="pa-8 text-center">
|
||||
<MudIcon Icon="@Icons.Material.Filled.ContactSupport" Size="Size.Large" Color="Color.Primary" Class="mb-4" />
|
||||
<MudText Typo="Typo.h4" Class="mb-3">سوال شما پاسخ داده نشد؟</MudText>
|
||||
<MudText Typo="Typo.body1" Class="mud-text-secondary mb-6">
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
@attribute [Route(RouteConstants.Gateway.CartChooser)]
|
||||
|
||||
<PageTitle>سبد خرید</PageTitle>
|
||||
|
||||
<MudContainer MaxWidth="MaxWidth.Medium" Class="py-6 py-md-10">
|
||||
<PageHeader Title="سبد خرید" BackHref="@RouteConstants.Profile.Index" />
|
||||
<MudStack AlignItems="AlignItems.Center" Spacing="4">
|
||||
<MudIcon Icon="@Icons.Material.Filled.ShoppingCart" Size="Size.Large" Color="Color.Primary" />
|
||||
<MudText Typo="Typo.body1" Align="Align.Center" Class="mud-text-secondary">
|
||||
سبد خرید کدام فروشگاه را میخواهید مشاهده کنید؟
|
||||
</MudText>
|
||||
|
||||
<MudGrid Spacing="4" Justify="Justify.Center" Class="mt-4">
|
||||
<MudItem xs="12" sm="6">
|
||||
<MudLink Href="@RouteConstants.Store.Cart" Underline="Underline.None" Class="store-chooser-link">
|
||||
<MudPaper Elevation="2" Class="pa-6 rounded-xl text-center store-chooser-card store-chooser-regular">
|
||||
<MudAvatar Size="Size.Large" Class="mx-auto mb-3 gateway-avatar-sm-store">
|
||||
<MudIcon Icon="@Icons.Material.Filled.Storefront" Size="Size.Large" Class="text-brand-store" />
|
||||
</MudAvatar>
|
||||
<MudText Typo="Typo.h6" Class="fw-semibold">سبد خرید فروشگاه</MudText>
|
||||
@if (_cartCount > 0)
|
||||
{
|
||||
<MudChip T="string" Color="Color.Success" Variant="Variant.Filled" Size="Size.Small" Class="mt-2">
|
||||
@_cartCount محصول
|
||||
</MudChip>
|
||||
}
|
||||
else
|
||||
{
|
||||
<MudText Typo="Typo.caption" Class="mud-text-secondary mt-1">سبد خالی</MudText>
|
||||
}
|
||||
</MudPaper>
|
||||
</MudLink>
|
||||
</MudItem>
|
||||
|
||||
<MudItem xs="12" sm="6">
|
||||
<MudLink Href="@RouteConstants.DiscountStore.Cart" Underline="Underline.None" Class="store-chooser-link">
|
||||
<MudPaper Elevation="2" Class="pa-6 rounded-xl text-center store-chooser-card store-chooser-discount">
|
||||
<MudAvatar Size="Size.Large" Class="mx-auto mb-3 gateway-avatar-sm-discount">
|
||||
<MudIcon Icon="@Icons.Material.Filled.Loyalty" Size="Size.Large" Class="text-brand-discount" />
|
||||
</MudAvatar>
|
||||
<MudText Typo="Typo.h6" Class="fw-semibold">سبد خرید تخفیفی</MudText>
|
||||
@if (_discountCartCount > 0)
|
||||
{
|
||||
<MudChip T="string" Color="Color.Error" Variant="Variant.Filled" Size="Size.Small" Class="mt-2">
|
||||
@_discountCartCount محصول
|
||||
</MudChip>
|
||||
}
|
||||
else
|
||||
{
|
||||
<MudText Typo="Typo.caption" Class="mud-text-secondary mt-1">سبد خالی</MudText>
|
||||
}
|
||||
</MudPaper>
|
||||
</MudLink>
|
||||
</MudItem>
|
||||
</MudGrid>
|
||||
|
||||
<MudButton Variant="Variant.Text" StartIcon="@Icons.Material.Filled.ArrowBack"
|
||||
OnClick="GoBack" Class="mt-4">
|
||||
بازگشت به داشبورد
|
||||
</MudButton>
|
||||
</MudStack>
|
||||
</MudContainer>
|
||||
@@ -0,0 +1,47 @@
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Microsoft.JSInterop;
|
||||
using FrontOffice.Main.Utilities;
|
||||
|
||||
namespace FrontOffice.Main.Pages.Gateway;
|
||||
|
||||
public partial class CartChooser : IDisposable
|
||||
{
|
||||
[Inject] private CartService CartService { get; set; } = default!;
|
||||
[Inject] private DiscountCartService DiscountCartService { get; set; } = default!;
|
||||
[Inject] private IJSRuntime JS { get; set; } = default!;
|
||||
|
||||
private int _cartCount;
|
||||
private int _discountCartCount;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
await CartService.EnsureInitializedAsync();
|
||||
await DiscountCartService.EnsureInitializedAsync();
|
||||
|
||||
_cartCount = CartService.Count;
|
||||
_discountCartCount = DiscountCartService.Count;
|
||||
|
||||
CartService.OnChange += OnCartChanged;
|
||||
DiscountCartService.OnChange += OnDiscountCartChanged;
|
||||
}
|
||||
|
||||
private void OnCartChanged()
|
||||
{
|
||||
_cartCount = CartService.Count;
|
||||
InvokeAsync(StateHasChanged);
|
||||
}
|
||||
|
||||
private void OnDiscountCartChanged()
|
||||
{
|
||||
_discountCartCount = DiscountCartService.Count;
|
||||
InvokeAsync(StateHasChanged);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
CartService.OnChange -= OnCartChanged;
|
||||
DiscountCartService.OnChange -= OnDiscountCartChanged;
|
||||
}
|
||||
|
||||
private async Task GoBack() => await JS.InvokeVoidAsync("history.back");
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
@attribute [Route(RouteConstants.Gateway.OrdersChooser)]
|
||||
@inject IJSRuntime JS
|
||||
|
||||
<PageTitle>سفارشات من</PageTitle>
|
||||
|
||||
<MudContainer MaxWidth="MaxWidth.Medium" Class="py-6 py-md-10">
|
||||
<PageHeader Title="سفارشات من" BackHref="@RouteConstants.Profile.Index" />
|
||||
<MudStack AlignItems="AlignItems.Center" Spacing="4">
|
||||
<MudIcon Icon="@Icons.Material.Filled.Receipt" Size="Size.Large" Color="Color.Primary" />
|
||||
<MudText Typo="Typo.body1" Align="Align.Center" Class="mud-text-secondary">
|
||||
سفارشات کدام فروشگاه را میخواهید مشاهده کنید؟
|
||||
</MudText>
|
||||
|
||||
<MudGrid Spacing="4" Justify="Justify.Center" Class="mt-4">
|
||||
<MudItem xs="12" sm="6">
|
||||
<MudLink Href="@RouteConstants.Store.Orders" Underline="Underline.None" Class="store-chooser-link">
|
||||
<MudPaper Elevation="2" Class="pa-6 rounded-xl text-center store-chooser-card store-chooser-regular">
|
||||
<MudAvatar Size="Size.Large" Class="mx-auto mb-3 gateway-avatar-sm-store">
|
||||
<MudIcon Icon="@Icons.Material.Filled.Storefront" Size="Size.Large" Class="text-brand-store" />
|
||||
</MudAvatar>
|
||||
<MudText Typo="Typo.h6" Class="fw-semibold">سفارشات فروشگاه</MudText>
|
||||
<MudText Typo="Typo.caption" Class="mud-text-secondary mt-1">سفارشات خرید معمولی</MudText>
|
||||
</MudPaper>
|
||||
</MudLink>
|
||||
</MudItem>
|
||||
|
||||
<MudItem xs="12" sm="6">
|
||||
<MudLink Href="@RouteConstants.DiscountStore.Orders" Underline="Underline.None" Class="store-chooser-link">
|
||||
<MudPaper Elevation="2" Class="pa-6 rounded-xl text-center store-chooser-card store-chooser-discount">
|
||||
<MudAvatar Size="Size.Large" Class="mx-auto mb-3 gateway-avatar-sm-discount">
|
||||
<MudIcon Icon="@Icons.Material.Filled.Loyalty" Size="Size.Large" Class="text-brand-discount" />
|
||||
</MudAvatar>
|
||||
<MudText Typo="Typo.h6" Class="fw-semibold">سفارشات فروشگاه تخفیفی</MudText>
|
||||
<MudText Typo="Typo.caption" Class="mud-text-secondary mt-1">سفارشات خرید تخفیفی</MudText>
|
||||
</MudPaper>
|
||||
</MudLink>
|
||||
</MudItem>
|
||||
</MudGrid>
|
||||
|
||||
<MudButton Variant="Variant.Text" StartIcon="@Icons.Material.Filled.ArrowBack"
|
||||
OnClick="GoBack" Class="mt-4">
|
||||
بازگشت به داشبورد
|
||||
</MudButton>
|
||||
</MudStack>
|
||||
</MudContainer>
|
||||
|
||||
@code {
|
||||
private async Task GoBack() => await JS.InvokeVoidAsync("history.back");
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
@attribute [Route(RouteConstants.Gateway.StoreChooser)]
|
||||
|
||||
<PageTitle>فروشگاهها</PageTitle>
|
||||
|
||||
<MudContainer MaxWidth="MaxWidth.Medium" Class="py-6 py-md-10">
|
||||
<PageHeader Title="انتخاب فروشگاه" BackHref="@RouteConstants.Profile.Index" />
|
||||
<MudStack AlignItems="AlignItems.Center" Spacing="4">
|
||||
<MudText Typo="Typo.body1" Align="Align.Center" Class="mud-text-secondary" Style="max-width:500px;">
|
||||
برای خرید، یکی از فروشگاهها را انتخاب کنید. هر فروشگاه سبد خرید و سفارشات مجزای خود را دارد.
|
||||
</MudText>
|
||||
|
||||
<MudGrid Spacing="4" Justify="Justify.Center" Class="mt-4">
|
||||
<!-- Regular Store -->
|
||||
<MudItem xs="12" sm="6">
|
||||
<MudLink Href="@RouteConstants.Store.Products" Underline="Underline.None" Class="store-chooser-link">
|
||||
<MudPaper Elevation="2" Class="pa-6 rounded-xl text-center store-chooser-card store-chooser-regular">
|
||||
<MudAvatar Size="Size.Large" Class="mx-auto mb-3 gateway-avatar-store">
|
||||
<MudIcon Icon="@Icons.Material.Filled.Storefront" Size="Size.Large" Class="text-brand-store" />
|
||||
</MudAvatar>
|
||||
<MudText Typo="Typo.h5" Class="fw-bold">فروشگاه</MudText>
|
||||
<MudText Typo="Typo.body2" Class="mud-text-secondary mt-2">
|
||||
خرید محصولات با پرداخت از کیف پول اعتباری
|
||||
</MudText>
|
||||
@if (_cartCount > 0)
|
||||
{
|
||||
<MudChip T="string" Color="Color.Success" Variant="Variant.Filled" Size="Size.Small" Class="mt-3">
|
||||
@_cartCount محصول در سبد خرید
|
||||
</MudChip>
|
||||
}
|
||||
</MudPaper>
|
||||
</MudLink>
|
||||
</MudItem>
|
||||
|
||||
<!-- Discount Store -->
|
||||
<MudItem xs="12" sm="6">
|
||||
<MudLink Href="@RouteConstants.DiscountStore.Products" Underline="Underline.None" Class="store-chooser-link">
|
||||
<MudPaper Elevation="2" Class="pa-6 rounded-xl text-center store-chooser-card store-chooser-discount">
|
||||
<MudAvatar Size="Size.Large" Class="mx-auto mb-3 gateway-avatar-discount">
|
||||
<MudIcon Icon="@Icons.Material.Filled.Loyalty" Size="Size.Large" Class="text-brand-discount" />
|
||||
</MudAvatar>
|
||||
<MudText Typo="Typo.h5" Class="fw-bold">فروشگاه تخفیفی</MudText>
|
||||
<MudText Typo="Typo.body2" Class="mud-text-secondary mt-2">
|
||||
خرید با استفاده از موجودی کیف تخفیفی + درگاه پرداخت
|
||||
</MudText>
|
||||
@if (_discountCartCount > 0)
|
||||
{
|
||||
<MudChip T="string" Color="Color.Error" Variant="Variant.Filled" Size="Size.Small" Class="mt-3">
|
||||
@_discountCartCount محصول در سبد خرید
|
||||
</MudChip>
|
||||
}
|
||||
</MudPaper>
|
||||
</MudLink>
|
||||
</MudItem>
|
||||
</MudGrid>
|
||||
</MudStack>
|
||||
</MudContainer>
|
||||
@@ -0,0 +1,43 @@
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using FrontOffice.Main.Utilities;
|
||||
|
||||
namespace FrontOffice.Main.Pages.Gateway;
|
||||
|
||||
public partial class StoreChooser : IDisposable
|
||||
{
|
||||
[Inject] private CartService CartService { get; set; } = default!;
|
||||
[Inject] private DiscountCartService DiscountCartService { get; set; } = default!;
|
||||
|
||||
private int _cartCount;
|
||||
private int _discountCartCount;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
await CartService.EnsureInitializedAsync();
|
||||
await DiscountCartService.EnsureInitializedAsync();
|
||||
|
||||
_cartCount = CartService.Count;
|
||||
_discountCartCount = DiscountCartService.Count;
|
||||
|
||||
CartService.OnChange += OnCartChanged;
|
||||
DiscountCartService.OnChange += OnDiscountCartChanged;
|
||||
}
|
||||
|
||||
private void OnCartChanged()
|
||||
{
|
||||
_cartCount = CartService.Count;
|
||||
InvokeAsync(StateHasChanged);
|
||||
}
|
||||
|
||||
private void OnDiscountCartChanged()
|
||||
{
|
||||
_discountCartCount = DiscountCartService.Count;
|
||||
InvokeAsync(StateHasChanged);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
CartService.OnChange -= OnCartChanged;
|
||||
DiscountCartService.OnChange -= OnDiscountCartChanged;
|
||||
}
|
||||
}
|
||||
@@ -1,354 +1,343 @@
|
||||
@attribute [Route(RouteConstants.Main.MainPage)]
|
||||
@inject NavigationManager Navigation
|
||||
@inject IJSRuntime JS
|
||||
|
||||
<PageTitle>صفحه اصلی</PageTitle>
|
||||
<PageTitle>صفحه اصلی | کارا بازار سلامت</PageTitle>
|
||||
|
||||
<!-- HERO -->
|
||||
<section id="hero" class="hero-section">
|
||||
<MudContainer MaxWidth="MaxWidth.Large" Class="py-16">
|
||||
<MudGrid Justify="Justify.Center" Spacing="3">
|
||||
<MudItem xs="12" md="6">
|
||||
<MudChip T="string" Color="Color.Secondary" Variant="Variant.Filled" Class="mb-3">پیشنهاد ویژه برای شروع</MudChip>
|
||||
<MudStack Spacing="2">
|
||||
<MudText Typo="Typo.h1">
|
||||
با دعوت از دوستان خود، از خریدهای واقعی پاداش بگیرید
|
||||
</MudText>
|
||||
<MudText Typo="Typo.body1" Class="mud-text-secondary mb-6">
|
||||
ثبتنام آسان، تجربهٔ سریع و شفاف. همین امروز حساب بساز و با دعوت دوستانت، امتیاز و پاداش دریافت کن.
|
||||
</MudText>
|
||||
@* ═══════════════════════════════════════════════
|
||||
1. HERO — Bold, minimal, centered
|
||||
═══════════════════════════════════════════════ *@
|
||||
<section class="hero-gradient py-12 py-md-16">
|
||||
<MudContainer MaxWidth="MaxWidth.Medium">
|
||||
<MudStack AlignItems="AlignItems.Center" Spacing="4" Class="text-center">
|
||||
<MudChip T="string" Color="Color.Default" Variant="Variant.Filled"
|
||||
Class="pulse-chip hero-chip-glass" Size="Size.Small">
|
||||
🌿 پلتفرم سلامتمحور فروش و تیمسازی
|
||||
</MudChip>
|
||||
|
||||
<MudStack Row="true" Spacing="3" Class="mb-2">
|
||||
<MudButton Variant="Variant.Outlined"
|
||||
Color="Color.Primary"
|
||||
Size="Size.Large"
|
||||
Class="mud-ripple rounded-pill"
|
||||
OnClick="@(() => Navigation.NavigateTo("/pricing"))">مشاهده قیمتها</MudButton>
|
||||
<MudButton Variant="Variant.Filled"
|
||||
Color="Color.Primary"
|
||||
Size="Size.Large"
|
||||
Class="mud-ripple rounded-pill"
|
||||
OnClick="@(() => NavigateToRegistrationWizard())">شروع کن</MudButton>
|
||||
</MudStack>
|
||||
<MudDivider Class="my-2" Style="width: 90%;" />
|
||||
<MudStack Row="true" Spacing="1">
|
||||
<MudChip T="string"
|
||||
Color="Color.Info"
|
||||
Variant="Variant.Outlined"
|
||||
Class="mb-3">ثبتنام زیر ۲ دقیقه</MudChip>
|
||||
<MudChip T="string"
|
||||
Color="Color.Info"
|
||||
Variant="Variant.Outlined"
|
||||
Class="mb-3">پشتیبانی ۷×۲۴</MudChip>
|
||||
<MudChip T="string"
|
||||
Color="Color.Info"
|
||||
Variant="Variant.Outlined"
|
||||
Class="mb-3">پرداخت ایمن</MudChip>
|
||||
<MudText Typo="Typo.h1" Class="hero-title" Style="max-width:680px;">
|
||||
رشد تیم، فروش واقعی، پاداش شفاف
|
||||
</MudText>
|
||||
|
||||
<MudText Typo="Typo.body1" Class="hero-subtitle" Style="max-width:520px;">
|
||||
با دعوت از دوستان، از خریدهای واقعی محصولات سلامت پاداش بگیرید. ثبتنام سریع، داشبورد لحظهای.
|
||||
</MudText>
|
||||
|
||||
<MudStack Row="true" Spacing="2" Class="mt-2 flex-wrap" Justify="Justify.Center">
|
||||
<MudButton Variant="Variant.Filled"
|
||||
Class="rounded-pill hero-cta-primary"
|
||||
Size="Size.Large"
|
||||
OnClick="NavigateToRegistrationWizard">
|
||||
شروع رایگان
|
||||
</MudButton>
|
||||
<MudButton Variant="Variant.Outlined"
|
||||
Class="rounded-pill hero-cta-outline"
|
||||
Size="Size.Large"
|
||||
OnClick="@(() => Navigation.NavigateTo("/blog"))">
|
||||
آخرین اخبار
|
||||
</MudButton>
|
||||
</MudStack>
|
||||
|
||||
@* ── Trust badges ── *@
|
||||
<MudStack Row="true" Spacing="4" Class="mt-4 flex-wrap" Justify="Justify.Center" AlignItems="AlignItems.Center">
|
||||
@foreach (var badge in _trustBadges)
|
||||
{
|
||||
<MudStack Row="true" Spacing="1" AlignItems="AlignItems.Center">
|
||||
<MudIcon Icon="@badge.Icon" Size="Size.Small" Style="color:rgba(255,255,255,.7);" />
|
||||
<MudText Typo="Typo.caption" Style="color:rgba(255,255,255,.8);">@badge.Text</MudText>
|
||||
</MudStack>
|
||||
}
|
||||
</MudStack>
|
||||
</MudStack>
|
||||
</MudContainer>
|
||||
</section>
|
||||
|
||||
@* ═══════════════════════════════════════════════
|
||||
1b. FEATURED POST BANNER — below hero
|
||||
═══════════════════════════════════════════════ *@
|
||||
@if (_latestPosts.Any())
|
||||
{
|
||||
var featured = _latestPosts.First();
|
||||
<section class="py-4" style="background:var(--mud-palette-surface);">
|
||||
<MudContainer MaxWidth="MaxWidth.Medium">
|
||||
<MudPaper Elevation="1" Class="landing-blog-banner rounded-xl cursor-pointer pa-3"
|
||||
@onclick="() => NavigateToPost(featured.Slug)">
|
||||
<MudStack Row="true" Spacing="3" AlignItems="AlignItems.Center">
|
||||
@if (!string.IsNullOrWhiteSpace(featured.ThumbnailUrl))
|
||||
{
|
||||
<AppImage Path="@featured.ThumbnailUrl"
|
||||
Alt="@featured.Title"
|
||||
ObjectFit="ObjectFit.Cover"
|
||||
Class="landing-blog-thumb"
|
||||
Fallback="@Icons.Material.Filled.Article" />
|
||||
}
|
||||
else
|
||||
{
|
||||
<MudAvatar Variant="Variant.Filled" Color="Color.Primary" Size="Size.Large" Class="rounded-lg" Style="min-width:64px;">
|
||||
<MudIcon Icon="@Icons.Material.Filled.Article" />
|
||||
</MudAvatar>
|
||||
}
|
||||
<MudStack Spacing="1" Style="flex:1; min-width:0;">
|
||||
<MudChip T="string" Size="Size.Small" Variant="Variant.Outlined" Color="Color.Primary">
|
||||
🔥 جدیدترین مطلب
|
||||
</MudChip>
|
||||
<MudText Typo="Typo.subtitle1" Class="landing-blog-title">@featured.Title</MudText>
|
||||
@if (!string.IsNullOrWhiteSpace(featured.Summary))
|
||||
{
|
||||
<MudText Typo="Typo.body2" Class="landing-blog-summary mud-text-secondary">@featured.Summary</MudText>
|
||||
}
|
||||
</MudStack>
|
||||
<MudIcon Icon="@Icons.Material.Filled.ChevronLeft" Class="mud-text-secondary d-none d-sm-flex" />
|
||||
</MudStack>
|
||||
</MudItem>
|
||||
</MudPaper>
|
||||
</MudContainer>
|
||||
</section>
|
||||
}
|
||||
|
||||
<MudItem xs="12" md="6">
|
||||
<MudPaper Class="pa-8 rounded-xl" Style="background: radial-gradient(600px 280px at 120% 0, #daccff 0, transparent 60%), radial-gradient(600px 280px at -10% 100%, #ffe2f2 0, transparent 60%), linear-gradient(180deg, #fff, #fbfaff);">
|
||||
<MudImage Src="images/team-meeting.jpg"
|
||||
Alt="جلسه تیم فروش"
|
||||
ObjectFit="ObjectFit.Cover"
|
||||
ObjectPosition="ObjectPosition.Center"
|
||||
Style="width:100%"
|
||||
Class="rounded-xl" />
|
||||
</MudPaper>
|
||||
</MudItem>
|
||||
@* ═══════════════════════════════════════════════
|
||||
2. HOW IT WORKS — 3 numbered steps
|
||||
═══════════════════════════════════════════════ *@
|
||||
<section class="section-landing">
|
||||
<MudContainer MaxWidth="MaxWidth.Large">
|
||||
<div class="text-center mb-8 fade-in-up">
|
||||
<MudText Typo="Typo.h3">سه گام تا شروع</MudText>
|
||||
<MudText Typo="Typo.body1" Class="mud-text-secondary mt-2">
|
||||
بدون پیچیدگی، سریع و آسان
|
||||
</MudText>
|
||||
</div>
|
||||
|
||||
<MudGrid Spacing="4" Justify="Justify.Center">
|
||||
@foreach (var (step, i) in _steps.Select((s, i) => (s, i)))
|
||||
{
|
||||
<MudItem xs="12" sm="4">
|
||||
<MudPaper Elevation="0" Class="pa-5 rounded-xl feature-card-v2 text-center fade-in-up" data-delay="@(i * 150)">
|
||||
<MudAvatar Size="Size.Large" Color="Color.Primary" Variant="Variant.Filled" Class="mx-auto mb-3 landing-step-num">
|
||||
<MudText Typo="Typo.h5" Style="color:#fff;font-weight:800;">@(i + 1)</MudText>
|
||||
</MudAvatar>
|
||||
<MudText Typo="Typo.h6" Class="mb-1">@step.Title</MudText>
|
||||
<MudText Typo="Typo.body2" Class="mud-text-secondary">@step.Desc</MudText>
|
||||
</MudPaper>
|
||||
</MudItem>
|
||||
}
|
||||
</MudGrid>
|
||||
</MudContainer>
|
||||
</section>
|
||||
<MudStack Spacing="4">
|
||||
|
||||
<!-- WHYUS -->
|
||||
<section class="whyus-section">
|
||||
<MudContainer MaxWidth="MaxWidth.Large" Class="whyus-section">
|
||||
|
||||
<MudText Typo="Typo.h4" GutterBottom="true">
|
||||
چرا کاربران ما را انتخاب میکنند؟
|
||||
</MudText>
|
||||
<MudText Typo="Typo.subtitle1" Class="mud-text-secondary mb-8">
|
||||
سه دلیل روشن برای شروع امروز.
|
||||
@* ═══════════════════════════════════════════════
|
||||
3. FEATURES — 6 cards with icons
|
||||
═══════════════════════════════════════════════ *@
|
||||
<section class="section-landing" style="background:var(--mud-palette-background-gray);">
|
||||
<MudContainer MaxWidth="MaxWidth.Large">
|
||||
<div class="text-center mb-8 fade-in-up">
|
||||
<MudText Typo="Typo.h3">چرا کارا بازار سلامت؟</MudText>
|
||||
<MudText Typo="Typo.body1" Class="mud-text-secondary mt-2" Style="max-width:540px;margin:0 auto;">
|
||||
ابزارهایی ساده و قدرتمند برای رشد کسبوکار شما
|
||||
</MudText>
|
||||
</div>
|
||||
|
||||
<MudGrid Spacing="3" Justify="Justify.Center">
|
||||
|
||||
<MudItem xs="12" sm="6" md="4">
|
||||
<MudCard Class="feature-card rounded-xl pa-4" Outlined="true">
|
||||
<MudStack>
|
||||
<MudStack Row="true">
|
||||
<MudIconButton Icon="@Icons.Material.Outlined.VerifiedUser"
|
||||
Variant="Variant.Outlined"
|
||||
Color="Color.Primary"
|
||||
Size="Size.Small" />
|
||||
<MudText Typo="Typo.h6" Align="Align.Center" Class="mb-2">ثبتنام سریع و ساده</MudText>
|
||||
</MudStack>
|
||||
|
||||
<MudText Class="ps-10 mud-text-secondary">
|
||||
در چند گام کوتاه، حسابت را بساز و شروع کن.
|
||||
</MudText>
|
||||
</MudStack>
|
||||
</MudCard>
|
||||
</MudItem>
|
||||
|
||||
<MudItem xs="12" sm="6" md="4">
|
||||
<MudCard Class="feature-card rounded-xl pa-4" Outlined="true">
|
||||
<MudStack>
|
||||
<MudStack Row="true">
|
||||
<MudIconButton Icon="@Icons.Material.Outlined.StarBorder"
|
||||
Variant="Variant.Outlined"
|
||||
Color="Color.Primary"
|
||||
Size="Size.Small" />
|
||||
<MudText Typo="Typo.h6" Align="Align.Center" Class="mb-2">مزایا و پاداشهای شفاف</MudText>
|
||||
</MudStack>
|
||||
|
||||
<MudText Class="ps-10 mud-text-secondary">
|
||||
قوانین روشن، دسترسی آسان به سوابق و گزارشها.
|
||||
</MudText>
|
||||
</MudStack>
|
||||
</MudCard>
|
||||
</MudItem>
|
||||
|
||||
<MudItem xs="12" sm="6" md="4">
|
||||
<MudCard Class="feature-card rounded-xl pa-4" Outlined="true">
|
||||
<MudStack>
|
||||
<MudStack Row="true">
|
||||
<MudIconButton Icon="@Icons.Material.Outlined.Devices"
|
||||
Variant="Variant.Outlined"
|
||||
Color="Color.Primary"
|
||||
Size="Size.Small" />
|
||||
<MudText Typo="Typo.h6" Align="Align.Center" Class="mb-2">اپلیکیشن واکنشگرا</MudText>
|
||||
</MudStack>
|
||||
|
||||
<MudText Class="ps-10 mud-text-secondary">
|
||||
تجربهای روان در موبایل و دسکتاپ.
|
||||
</MudText>
|
||||
</MudStack>
|
||||
</MudCard>
|
||||
</MudItem>
|
||||
</MudGrid>
|
||||
|
||||
</MudContainer>
|
||||
</section>
|
||||
|
||||
@* <!-- FEATURES: معرفی پکیجها -->
|
||||
<section id="features" class="py-20">
|
||||
<MudContainer MaxWidth="MaxWidth.Large">
|
||||
<MudText Typo="Typo.h4" GutterBottom="true">
|
||||
پکیجهای سرمایه گذاری
|
||||
</MudText>
|
||||
<MudText Typo="Typo.subtitle1" Class="mud-text-secondary mb-8">
|
||||
بر اساس اندازهٔ تیم خود انتخاب کنید.
|
||||
</MudText>
|
||||
@if (_isLoadingPackages)
|
||||
<MudGrid Spacing="3" Justify="Justify.Center">
|
||||
@foreach (var (icon, title, desc, delay) in _features)
|
||||
{
|
||||
<MudStack AlignItems="AlignItems.Center" Class="py-8">
|
||||
<MudProgressCircular Color="Color.Primary" Indeterminate="true" Size="Size.Large" />
|
||||
<MudText Typo="Typo.body1" Class="mud-text-secondary mt-2">در حال بارگذاری پکیجها...</MudText>
|
||||
</MudStack>
|
||||
<MudItem xs="12" sm="6" md="4">
|
||||
<MudPaper Elevation="0" Class="pa-5 rounded-xl feature-card-v2 fade-in-up" data-delay="@delay">
|
||||
<MudStack Spacing="2">
|
||||
<MudAvatar Color="Color.Primary" Variant="Variant.Filled" Size="Size.Medium" Class="mb-1">
|
||||
<MudIcon Icon="@icon" />
|
||||
</MudAvatar>
|
||||
<MudText Typo="Typo.h6">@title</MudText>
|
||||
<MudText Typo="Typo.body2" Class="mud-text-secondary">@desc</MudText>
|
||||
</MudStack>
|
||||
</MudPaper>
|
||||
</MudItem>
|
||||
}
|
||||
else if (_packs.Any())
|
||||
</MudGrid>
|
||||
</MudContainer>
|
||||
</section>
|
||||
|
||||
@* ═══════════════════════════════════════════════
|
||||
4. STATS — Counter cards
|
||||
═══════════════════════════════════════════════ *@
|
||||
<section class="section-landing">
|
||||
<MudContainer MaxWidth="MaxWidth.Medium">
|
||||
<MudGrid Spacing="3" Justify="Justify.Center">
|
||||
@foreach (var stat in _stats)
|
||||
{
|
||||
<MudGrid Spacing="4" Justify="Justify.Center" Class="stretch-grid">
|
||||
@foreach (var p in _packs)
|
||||
{
|
||||
<MudItem xs="12" md="4" Class="d-flex">
|
||||
<MudCard>
|
||||
<MudCardMedia Image="@p.Image"
|
||||
Title="@p.Title"
|
||||
Height="300" />
|
||||
<MudCardContent>
|
||||
<MudText Typo="Typo.h5" Class="mb-3">@(p.Title)</MudText>
|
||||
@((MarkupString)p.Body)
|
||||
</MudCardContent>
|
||||
<MudCardActions Class="ma-2">
|
||||
<MudText Typo="Typo.h5"
|
||||
Color="Color.Success"
|
||||
Align="Align.End">@(p.Price.ToThousands().ToCurrencyUnitIRT())</MudText>
|
||||
<MudItem xs="6" sm="3">
|
||||
<MudPaper Elevation="2" Class="pa-4 rounded-xl stat-card fade-in-up text-center">
|
||||
<MudText Class="stat-number" Color="@stat.Color" id="@stat.ElementId">@stat.Display</MudText>
|
||||
<MudText Typo="Typo.caption" Class="mud-text-secondary mt-1">@stat.Label</MudText>
|
||||
</MudPaper>
|
||||
</MudItem>
|
||||
}
|
||||
</MudGrid>
|
||||
</MudContainer>
|
||||
</section>
|
||||
|
||||
@* ═══════════════════════════════════════════════
|
||||
5. LATEST BLOG POSTS
|
||||
═══════════════════════════════════════════════ *@
|
||||
@if (_latestPosts.Any())
|
||||
{
|
||||
<section class="section-landing" style="background:var(--mud-palette-background-gray);">
|
||||
<MudContainer MaxWidth="MaxWidth.Large">
|
||||
<div class="text-center mb-8 fade-in-up">
|
||||
<MudText Typo="Typo.h3">آخرین مقالات</MudText>
|
||||
<MudText Typo="Typo.body1" Class="mud-text-secondary mt-2">
|
||||
جدیدترین مطالب و اخبار کارا بازار سلامت
|
||||
</MudText>
|
||||
</div>
|
||||
|
||||
<MudGrid Spacing="4" Justify="Justify.Center">
|
||||
@foreach (var post in _latestPosts.Take(2))
|
||||
{
|
||||
<MudItem xs="12" sm="6" md="6">
|
||||
<MudPaper Elevation="1" Class="rounded-xl blog-card-v2 cursor-pointer fade-in-up" Style="overflow:hidden;"
|
||||
@onclick="() => NavigateToPost(post.Slug)">
|
||||
<div class="blog-thumb" style="height:180px; background:#f0f0f0;">
|
||||
@if (!string.IsNullOrWhiteSpace(post.ThumbnailUrl))
|
||||
{
|
||||
<AppImage Path="@post.ThumbnailUrl"
|
||||
Alt="@post.Title"
|
||||
ObjectFit="ObjectFit.Cover"
|
||||
Style="width:100%; height:180px;" />
|
||||
}
|
||||
else
|
||||
{
|
||||
<div style="height:180px; display:flex; align-items:center; justify-content:center; background:linear-gradient(135deg,#6366f1,#a78bfa);">
|
||||
<MudIcon Icon="@Icons.Material.Filled.Article" Size="Size.Large" Style="color:rgba(255,255,255,.5);" />
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
<div class="pa-4">
|
||||
@if (post.Categories.Any())
|
||||
{
|
||||
<MudChip T="string" Size="Size.Small" Variant="Variant.Outlined" Color="Color.Primary" Class="mb-2">
|
||||
@post.Categories.First().Title
|
||||
</MudChip>
|
||||
}
|
||||
<MudText Typo="Typo.h6" Class="mb-1" Style="display:-webkit-box; -webkit-line-clamp:2; -webkit-box-orient:vertical; overflow:hidden;">
|
||||
@post.Title
|
||||
</MudText>
|
||||
@if (!string.IsNullOrWhiteSpace(post.Summary))
|
||||
{
|
||||
<MudText Typo="Typo.body2" Class="mud-text-secondary mb-2" Style="display:-webkit-box; -webkit-line-clamp:2; -webkit-box-orient:vertical; overflow:hidden;">
|
||||
@post.Summary
|
||||
</MudText>
|
||||
}
|
||||
<MudStack Row="true" Spacing="2" AlignItems="AlignItems.Center" Class="mt-2">
|
||||
@if (post.PublishedAt.HasValue)
|
||||
{
|
||||
<MudText Typo="Typo.caption" Class="mud-text-secondary">
|
||||
<MudIcon Icon="@Icons.Material.Filled.CalendarToday" Size="Size.Small" Class="ml-1" />
|
||||
@post.PublishedAt.Value.ToString("yyyy/MM/dd")
|
||||
</MudText>
|
||||
}
|
||||
<MudSpacer />
|
||||
<MudButton Variant="Variant.Filled"
|
||||
Color="Color.Primary"
|
||||
OnClick="@(() => NavigateToPackage(p.Id))">مشاهده جزئیات</MudButton>
|
||||
</MudCardActions>
|
||||
</MudCard>
|
||||
</MudItem>
|
||||
}
|
||||
</MudGrid>
|
||||
}
|
||||
else
|
||||
{
|
||||
<MudStack AlignItems="AlignItems.Center" Class="py-8">
|
||||
<MudText Typo="Typo.body1" Class="mud-text-secondary">هیچ پکیجی یافت نشد.</MudText>
|
||||
</MudStack>
|
||||
}
|
||||
</MudContainer>
|
||||
</section>
|
||||
*@
|
||||
<!-- STATS -->
|
||||
<section class="stats-strip">
|
||||
<MudContainer MaxWidth="MaxWidth.Large">
|
||||
<MudText Typo="Typo.h4" Align="Align.Center" GutterBottom="true">
|
||||
کارا بازار سلامت چطور کار میکند؟
|
||||
</MudText>
|
||||
<MudText Typo="Typo.subtitle1" Align="Align.Center" Class="mud-text-secondary mb-8">
|
||||
سه گام روشن تا شروع یک ماجراجویی جدید
|
||||
</MudText>
|
||||
<MudGrid>
|
||||
<MudItem xs="12" lg="6">
|
||||
<MudStack AlignItems="AlignItems.Start">
|
||||
<MudPaper Outlined="true" Class="pa-6 rounded-xl">
|
||||
<MudTimeline>
|
||||
<MudTimelineItem Color="Color.Info" Size="Size.Small">
|
||||
<ItemOpposite>
|
||||
<MudText Color="Color.Info" Typo="Typo.h5">ثبتنام</MudText>
|
||||
</ItemOpposite>
|
||||
<ItemContent>
|
||||
<MudText Color="Color.Info" Typo="Typo.h6" GutterBottom="true">مرحله اول</MudText>
|
||||
<MudText>یک حساب بساز و وارد شو.</MudText>
|
||||
</ItemContent>
|
||||
</MudTimelineItem>
|
||||
|
||||
<MudTimelineItem Color="Color.Success" Size="Size.Small">
|
||||
<ItemOpposite>
|
||||
<MudText Color="Color.Success" Typo="Typo.h5">دعوت دوستان</MudText>
|
||||
</ItemOpposite>
|
||||
<ItemContent>
|
||||
<MudText Align="Align.End" Color="Color.Success" Typo="Typo.h6" GutterBottom="true">مرحله دوم</MudText>
|
||||
<MudText Align="Align.End">لینک دعوتت را به اشتراک بگذار.</MudText>
|
||||
</ItemContent>
|
||||
</MudTimelineItem>
|
||||
|
||||
<MudTimelineItem Color="Color.Error" Size="Size.Small">
|
||||
<ItemOpposite>
|
||||
<MudText Color="Color.Error" Typo="Typo.h5">دریافت پاداش</MudText>
|
||||
</ItemOpposite>
|
||||
<ItemContent>
|
||||
<MudText Color="Color.Error" Typo="Typo.h6" GutterBottom="true">مرحله سوم</MudText>
|
||||
<MudText>از خریدهای واقعی دوستانت پاداش بگیر.</MudText>
|
||||
</ItemContent>
|
||||
</MudTimelineItem>
|
||||
</MudTimeline>
|
||||
<MudText Typo="Typo.caption" Class="mud-text-secondary">
|
||||
<MudIcon Icon="@Icons.Material.Filled.Visibility" Size="Size.Small" Class="ml-1" />
|
||||
@post.ViewCount
|
||||
</MudText>
|
||||
</MudStack>
|
||||
</div>
|
||||
</MudPaper>
|
||||
</MudStack>
|
||||
</MudItem>
|
||||
<MudItem xs="1">
|
||||
<MudDivider Vertical="true" />
|
||||
</MudItem>
|
||||
<MudItem xs="12" lg="5" Class="d-flex align-center">
|
||||
<MudStack>
|
||||
<MudGrid Spacing="4" Justify="Justify.SpaceAround">
|
||||
<MudItem xs="6">
|
||||
<MudPaper Elevation="2" Class="pa-4 rounded-xl ">
|
||||
<MudText Typo="Typo.h4" Align="Align.Center" Color="Color.Success">+۵۰٪</MudText>
|
||||
<MudText Typo="Typo.caption" HtmlTag="div" Align="Align.Center" Color="Color.Info">رشد میانگین تیم</MudText>
|
||||
</MudPaper>
|
||||
</MudItem>
|
||||
<MudItem xs="6">
|
||||
<MudPaper Elevation="2" Class="pa-4 rounded-xl text-center">
|
||||
<MudText Typo="Typo.h4" Align="Align.Center" Color="Color.Primary">۹۹٫۹٪</MudText>
|
||||
<MudText Typo="Typo.caption" HtmlTag="div" Align="Align.Center" Color="Color.Info">آپتایم سرویس</MudText>
|
||||
</MudPaper>
|
||||
</MudItem>
|
||||
<MudItem xs="6">
|
||||
<MudPaper Elevation="2" Class="pa-4 rounded-xl text-center">
|
||||
<MudText Typo="Typo.h4" Align="Align.Center" Color="Color.Warning">۳ روز</MudText>
|
||||
<MudText Typo="Typo.caption" HtmlTag="div" Align="Align.Center" Color="Color.Info">میانگین زمان استقرار</MudText>
|
||||
</MudPaper>
|
||||
</MudItem>
|
||||
<MudItem xs="6">
|
||||
<MudPaper Elevation="2" Class="pa-4 rounded-xl text-center">
|
||||
<MudText Typo="Typo.h4" Align="Align.Center" Color="Color.Secondary">+۲۰ کشور</MudText>
|
||||
<MudText Typo="Typo.caption" HtmlTag="div" Align="Align.Center" Color="Color.Info">پوشش ارسال کد</MudText>
|
||||
</MudPaper>
|
||||
</MudItem>
|
||||
</MudGrid>
|
||||
</MudStack>
|
||||
</MudItem>
|
||||
|
||||
</MudItem>
|
||||
}
|
||||
</MudGrid>
|
||||
|
||||
</MudContainer>
|
||||
</section>
|
||||
|
||||
<!-- TESTIMONIALS -->
|
||||
<section id="testimonials" class="py-20 testimonials">
|
||||
<MudContainer MaxWidth="MaxWidth.Large">
|
||||
<MudText Typo="Typo.h4" Align="Align.Center" GutterBottom="true">
|
||||
اعتماد مشتریان
|
||||
</MudText>
|
||||
<MudText Typo="Typo.subtitle1" Align="Align.Center" Class="mud-text-secondary mb-8">
|
||||
بخشی از تجربهٔ استفاده از «کارا بازار سلامت».
|
||||
</MudText>
|
||||
<MudGrid Spacing="3" Justify="Justify.Center">
|
||||
<MudItem xs="12" md="6">
|
||||
<MudPaper Elevation="4" Class=" pa-5 ">
|
||||
<MudStack Spacing="2">
|
||||
<MudStack Row="true" Spacing="2" AlignItems="AlignItems.Center">
|
||||
<MudAvatar>
|
||||
<MudImage ObjectFit="ObjectFit.Cover"
|
||||
ObjectPosition="ObjectPosition.Center"
|
||||
Src="images/avatar1.jpg"></MudImage>
|
||||
</MudAvatar>
|
||||
<div>
|
||||
<MudText Typo="Typo.subtitle2">شرکت سینا نت</MudText>
|
||||
<MudText Typo="Typo.overline" Class="mud-text-secondary">مدیر عملیات</MudText>
|
||||
</div>
|
||||
</MudStack>
|
||||
<MudText Typo="Typo.body2">
|
||||
«با کارا بازار سلامت، محاسبهٔ کارمزدها و پایش تیمها بدون اکسل و دردسر انجام میشود.»
|
||||
</MudText>
|
||||
</MudStack>
|
||||
</MudPaper>
|
||||
</MudItem>
|
||||
|
||||
<MudItem xs="12" md="6">
|
||||
<MudPaper Elevation="4" Class=" pa-5 ">
|
||||
<MudStack Spacing="2">
|
||||
<MudStack Row="true" Spacing="2" AlignItems="AlignItems.Center">
|
||||
<MudAvatar>
|
||||
<MudImage ObjectFit="ObjectFit.Cover"
|
||||
ObjectPosition="ObjectPosition.Center"
|
||||
Src="images/avatar2.jpg"></MudImage>
|
||||
</MudAvatar>
|
||||
<div>
|
||||
<MudText Typo="Typo.subtitle2">هولدینگ آریانا</MudText>
|
||||
<MudText Typo="Typo.overline" Class="mud-text-secondary">مدیر فروش</MudText>
|
||||
</div>
|
||||
</MudStack>
|
||||
<MudText Typo="Typo.body2">
|
||||
«شجرهنامهٔ بصری و گزارشهای دقیق باعث شد رشد تیم را لحظهای ببینیم.»
|
||||
</MudText>
|
||||
</MudStack>
|
||||
</MudPaper>
|
||||
</MudItem>
|
||||
|
||||
</MudGrid>
|
||||
</MudContainer>
|
||||
</section>
|
||||
|
||||
<!-- FAQ -->
|
||||
<section id="faq" class="mb-6">
|
||||
<MudContainer MaxWidth="MaxWidth.Large">
|
||||
<MudText Typo="Typo.h4" Align="Align.Center" GutterBottom="true">
|
||||
سوالات متداول
|
||||
</MudText>
|
||||
<MudText Typo="Typo.subtitle1" Align="Align.Center" Class="mud-text-secondary mb-8">
|
||||
پاسخ به سوالات رایج شما.
|
||||
</MudText>
|
||||
<div class="mx-auto max-w-800">
|
||||
<MudExpansionPanels Square="false" Class=" ">
|
||||
@foreach (var q in _faqs)
|
||||
{
|
||||
<MudExpansionPanel Text="@q.Q">
|
||||
<MudText Typo="Typo.body2">@q.A</MudText>
|
||||
</MudExpansionPanel>
|
||||
}
|
||||
</MudExpansionPanels>
|
||||
<div class="text-center mt-6">
|
||||
<MudButton Variant="Variant.Outlined" Color="Color.Primary" Class="rounded-pill"
|
||||
Href="/blog">
|
||||
مشاهده همه مقالات
|
||||
</MudButton>
|
||||
</div>
|
||||
</MudContainer>
|
||||
</section>
|
||||
}
|
||||
|
||||
</MudStack>
|
||||
@* ═══════════════════════════════════════════════
|
||||
6. TESTIMONIALS
|
||||
═══════════════════════════════════════════════ *@
|
||||
<section class="section-landing">
|
||||
<MudContainer MaxWidth="MaxWidth.Large">
|
||||
<div class="text-center mb-8 fade-in-up">
|
||||
<MudText Typo="Typo.h3">اعتماد مشتریان</MudText>
|
||||
<MudText Typo="Typo.body1" Class="mud-text-secondary mt-2">
|
||||
بخشی از تجربه استفاده از «کارا بازار سلامت»
|
||||
</MudText>
|
||||
</div>
|
||||
|
||||
<MudGrid Spacing="4" Justify="Justify.Center">
|
||||
@foreach (var t in _testimonials)
|
||||
{
|
||||
<MudItem xs="12" md="4">
|
||||
<MudPaper Elevation="2" Class="pa-5 rounded-xl testimonial-card fade-in-up" data-delay="@t.Delay">
|
||||
<MudStack Spacing="2">
|
||||
<MudRating ReadOnly="true" SelectedValue="5" Size="Size.Small" Color="Color.Warning" />
|
||||
<MudText Typo="Typo.body2" Class="mud-text-secondary">
|
||||
«@t.Quote»
|
||||
</MudText>
|
||||
<MudDivider Class="my-1" />
|
||||
<MudStack Row="true" Spacing="2" AlignItems="AlignItems.Center">
|
||||
<MudAvatar Size="Size.Small" Color="Color.Primary" Variant="Variant.Filled">
|
||||
<MudIcon Icon="@Icons.Material.Filled.Person" Size="Size.Small" />
|
||||
</MudAvatar>
|
||||
<div>
|
||||
<MudText Typo="Typo.subtitle2">@t.Name</MudText>
|
||||
<MudText Typo="Typo.overline" Class="mud-text-secondary">@t.Role</MudText>
|
||||
</div>
|
||||
</MudStack>
|
||||
</MudStack>
|
||||
</MudPaper>
|
||||
</MudItem>
|
||||
}
|
||||
</MudGrid>
|
||||
</MudContainer>
|
||||
</section>
|
||||
|
||||
@* ═══════════════════════════════════════════════
|
||||
7. FAQ
|
||||
═══════════════════════════════════════════════ *@
|
||||
<section class="section-landing" style="background:var(--mud-palette-background-gray);">
|
||||
<MudContainer MaxWidth="MaxWidth.Medium">
|
||||
<div class="text-center mb-8 fade-in-up">
|
||||
<MudText Typo="Typo.h3">سوالات متداول</MudText>
|
||||
<MudText Typo="Typo.body1" Class="mud-text-secondary mt-2">
|
||||
پاسخ به سوالات رایج شما
|
||||
</MudText>
|
||||
</div>
|
||||
|
||||
<div class="fade-in-up">
|
||||
<MudExpansionPanels Elevation="1" Class="rounded-xl">
|
||||
@foreach (var q in _faqs)
|
||||
{
|
||||
<MudExpansionPanel Text="@q.Q">
|
||||
<MudText Typo="Typo.body2" Class="mud-text-secondary">@q.A</MudText>
|
||||
</MudExpansionPanel>
|
||||
}
|
||||
</MudExpansionPanels>
|
||||
</div>
|
||||
</MudContainer>
|
||||
</section>
|
||||
|
||||
@* ═══════════════════════════════════════════════
|
||||
8. CTA BANNER
|
||||
═══════════════════════════════════════════════ *@
|
||||
<section class="section-landing-lg">
|
||||
<MudContainer MaxWidth="MaxWidth.Medium">
|
||||
<div class="cta-banner pa-8 pa-md-12 fade-in-up">
|
||||
<MudStack AlignItems="AlignItems.Center" Spacing="3">
|
||||
<MudText Typo="Typo.h3" Align="Align.Center" Class="dash-hero-name">
|
||||
آماده شروع هستید؟
|
||||
</MudText>
|
||||
<MudText Typo="Typo.body1" Align="Align.Center" Class="hero-subtitle">
|
||||
همین الان ثبتنام کنید و از مزایای کارا بازار سلامت بهرهمند شوید.
|
||||
</MudText>
|
||||
<MudButton Variant="Variant.Filled"
|
||||
Size="Size.Large"
|
||||
Class="rounded-pill mt-2 hero-cta-primary"
|
||||
OnClick="NavigateToRegistrationWizard">
|
||||
شروع رایگان
|
||||
</MudButton>
|
||||
</MudStack>
|
||||
</div>
|
||||
</MudContainer>
|
||||
</section>
|
||||
|
||||
@@ -1,44 +1,66 @@
|
||||
using CMSMicroservice.Protobuf.Protos.Package;
|
||||
using FrontOffice.Main.Utilities;
|
||||
using FrontOffice.Main.Utilities;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Microsoft.JSInterop;
|
||||
using MudBlazor;
|
||||
using System.Security.Cryptography;
|
||||
|
||||
namespace FrontOffice.Main.Pages;
|
||||
|
||||
public partial class Index:IDisposable
|
||||
public partial class Index : IDisposable
|
||||
{
|
||||
[Inject] private PackageContract.PackageContractClient PackageClient { get; set; } = default!;
|
||||
[Inject] private MobileNumberEncryptor Encryptor { get; set; }
|
||||
private string? _email;
|
||||
private bool _isLoadingPackages;
|
||||
private List<Pack> _packs = new();
|
||||
[Inject] private BlogPostService BlogPostService { get; set; } = default!;
|
||||
[Inject] private AuthService AuthService { get; set; } = default!;
|
||||
|
||||
// ── Latest blog posts (loaded from CMS) ──
|
||||
private List<BlogPostCardDto> _latestPosts = new();
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
MainService.OnChangeHandler +=async () =>
|
||||
MainService.OnChangeHandler += OnStateChanged;
|
||||
|
||||
// Load latest published blog posts
|
||||
// اول پینشدهها، اگر کافی نبود آخرین پستها اضافه شود
|
||||
try
|
||||
{
|
||||
await InvokeAsync(StateHasChanged);
|
||||
};
|
||||
// await LoadPackagesAsync();
|
||||
|
||||
//string mobileNumber = "09387342688";
|
||||
|
||||
//// انکریپت کردن
|
||||
//string encrypted = Encryptor.EncryptMobileNumber(mobileNumber);
|
||||
//Console.WriteLine($"Encrypted: {encrypted}");
|
||||
|
||||
//// دیکریپت کردن برای تست
|
||||
//string decrypted = Encryptor.DecryptMobileNumber(encrypted);
|
||||
//Console.WriteLine($"Decrypted: {decrypted}");
|
||||
_latestPosts = await BlogPostService.GetFeaturedPostsAsync(2);
|
||||
|
||||
// اگر فقط ۱ پینشده داریم، ۱ پست آخر هم اضافه کن
|
||||
if (_latestPosts.Count < 2)
|
||||
{
|
||||
var result = await BlogPostService.GetPublishedPostsAsync(page: 1, pageSize: 2);
|
||||
var existing = _latestPosts.Select(p => p.Id).ToHashSet();
|
||||
foreach (var post in result.Posts)
|
||||
{
|
||||
if (!existing.Contains(post.Id))
|
||||
{
|
||||
_latestPosts.Add(post);
|
||||
if (_latestPosts.Count >= 2) break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
_latestPosts = new();
|
||||
}
|
||||
}
|
||||
|
||||
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||
{
|
||||
if (firstRender)
|
||||
{
|
||||
// Init scroll-triggered fade-in animations
|
||||
await JS.InvokeVoidAsync("initScrollAnimations");
|
||||
|
||||
// Animate stat counters
|
||||
foreach (var stat in _stats)
|
||||
{
|
||||
await JS.InvokeVoidAsync("animateCounter", stat.ElementId, stat.Target, 2200, stat.Suffix);
|
||||
}
|
||||
}
|
||||
|
||||
if (await AuthService.IsAuthenticatedAsync())
|
||||
{
|
||||
if ((await AuthService.IsCompleteRegisterAsync()))
|
||||
if (await AuthService.IsCompleteRegisterAsync())
|
||||
{
|
||||
Navigation.NavigateTo(RouteConstants.Profile.Index);
|
||||
}
|
||||
@@ -47,56 +69,8 @@ public partial class Index:IDisposable
|
||||
Navigation.NavigateTo(RouteConstants.Registration.Wizard);
|
||||
}
|
||||
}
|
||||
await base.OnAfterRenderAsync(firstRender);
|
||||
}
|
||||
|
||||
// private async Task LoadPackagesAsync()
|
||||
// {
|
||||
// _isLoadingPackages = true;
|
||||
// try
|
||||
// {
|
||||
// var response = await PackageClient.GetAllPackageByFilterAsync(request: new());
|
||||
// if (response?.Models?.Any() == true)
|
||||
// {
|
||||
// _packs = response.Models.Select(p => new Pack(
|
||||
// Id: p.Id,
|
||||
// Title: p.Title,
|
||||
// Body: p.Description,
|
||||
// Image: UrlUtility.DownloadUrl + p.ImagePath,
|
||||
// Price: p.Price
|
||||
// )).ToList();
|
||||
// }
|
||||
// else
|
||||
// _packs = new List<Pack>();
|
||||
// }
|
||||
// catch (Exception ex)
|
||||
// {
|
||||
// Snackbar.Add($"خطا در بارگذاری پکیجها: {ex.Message}", Severity.Error);
|
||||
// // Fallback to empty list
|
||||
// _packs = new List<Pack>();
|
||||
// }
|
||||
// finally
|
||||
// {
|
||||
// _isLoadingPackages = false;
|
||||
// await InvokeAsync(StateHasChanged);
|
||||
// }
|
||||
// }
|
||||
|
||||
private void JoinWaitlist()
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(_email))
|
||||
{
|
||||
Snackbar.Add("لطفاً ایمیل معتبر وارد کنید.", Severity.Warning);
|
||||
return;
|
||||
}
|
||||
|
||||
Snackbar.Add("به لیست انتظار «کارا بازار سلامت» اضافه شدید.", Severity.Success);
|
||||
_email = string.Empty;
|
||||
}
|
||||
|
||||
private void NavigateToPackage(long packageId)
|
||||
{
|
||||
Navigation.NavigateTo($"{RouteConstants.Package.Detail}{packageId}");
|
||||
await base.OnAfterRenderAsync(firstRender);
|
||||
}
|
||||
|
||||
private void NavigateToRegistrationWizard()
|
||||
@@ -104,25 +78,77 @@ public partial class Index:IDisposable
|
||||
Navigation.NavigateTo(RouteConstants.Registration.Wizard);
|
||||
}
|
||||
|
||||
private record Pack(long Id, string Title, string Body, string Image, long Price);
|
||||
private void NavigateToPost(string slug)
|
||||
{
|
||||
Navigation.NavigateTo($"/blog/{slug}");
|
||||
}
|
||||
|
||||
private record Plan(string Name, string Price, bool Highlight, IEnumerable<string> Features);
|
||||
private async void OnStateChanged()
|
||||
{
|
||||
await InvokeAsync(StateHasChanged);
|
||||
}
|
||||
|
||||
private record QA(string Q, string A);
|
||||
// ── Trust badges ──
|
||||
private readonly List<(string Icon, string Text)> _trustBadges = new()
|
||||
{
|
||||
(Icons.Material.Outlined.Timer, "ثبتنام زیر ۲ دقیقه"),
|
||||
(Icons.Material.Outlined.SupportAgent, "پشتیبانی ۷×۲۴"),
|
||||
(Icons.Material.Outlined.Lock, "پرداخت ایمن"),
|
||||
(Icons.Material.Outlined.Verified, "تضمین کیفیت"),
|
||||
};
|
||||
|
||||
// ── How it works steps ──
|
||||
private readonly List<(string Title, string Desc)> _steps = new()
|
||||
{
|
||||
("ثبتنام و احراز هویت", "یک حساب بسازید، شماره موبایل را تأیید و اطلاعات هویتی را تکمیل کنید."),
|
||||
("دعوت دوستان", "لینک دعوت اختصاصی خود را با دوستان و آشنایان به اشتراک بگذارید."),
|
||||
("دریافت پاداش", "از خریدهای واقعی اعضای تیمتان پاداش شفاف و لحظهای دریافت کنید."),
|
||||
};
|
||||
|
||||
// ── Feature cards data (6 cards) ──
|
||||
private readonly List<(string Icon, string Title, string Desc, int Delay)> _features = new()
|
||||
{
|
||||
(Icons.Material.Outlined.VerifiedUser, "ثبتنام سریع و ساده", "در چند گام کوتاه حساب بسازید و شروع کنید.", 0),
|
||||
(Icons.Material.Outlined.StarBorder, "پاداشهای شفاف", "قوانین روشن، دسترسی آسان به سوابق و گزارشها.", 100),
|
||||
(Icons.Material.Outlined.Devices, "طراحی واکنشگرا", "تجربهای روان در موبایل و دسکتاپ.", 200),
|
||||
(Icons.Material.Outlined.Groups, "تیمسازی هوشمند", "ساختار درختی شبکه و مدیریت تیمهای فروش.", 300),
|
||||
(Icons.Material.Outlined.Insights, "گزارشهای لحظهای", "داشبورد پویا برای مشاهده عملکرد و کمیسیون.", 400),
|
||||
(Icons.Material.Outlined.Lock, "امنیت بالا", "رمزنگاری اطلاعات و احراز هویت چندمرحلهای.", 500),
|
||||
};
|
||||
|
||||
// ── Stats data (animated counters) ──
|
||||
private readonly List<StatItem> _stats = new()
|
||||
{
|
||||
new("stat-growth", "+۵۰٪", 50, "%+", Color.Success, "رشد میانگین تیم"),
|
||||
new("stat-uptime", "۹۹.۹٪", 99.9, "%", Color.Primary, "آپتایم سرویس"),
|
||||
new("stat-deploy", "۳ روز", 3, " روز", Color.Warning, "میانگین زمان استقرار"),
|
||||
new("stat-coverage", "+۲۰ کشور", 20, "+", Color.Secondary, "پوشش ارسال کد"),
|
||||
};
|
||||
|
||||
// ── Testimonials ──
|
||||
private readonly List<TestimonialItem> _testimonials = new()
|
||||
{
|
||||
new("با کارا بازار سلامت، محاسبه کارمزدها و پایش تیمها بدون اکسل و دردسر انجام میشود.", "شرکت سینا نت", "مدیر عملیات", 0),
|
||||
new("شجرهنامه بصری و گزارشهای دقیق باعث شد رشد تیم را لحظهای ببینیم.", "هولدینگ آریانا", "مدیر فروش", 150),
|
||||
new("سادگی ثبتنام و شفافیت پاداشها مهمترین مزیت این پلتفرم است.", "گروه بهداشتی نوین", "مدیر توسعه", 300),
|
||||
};
|
||||
|
||||
// ── FAQ data ──
|
||||
private readonly List<QA> _faqs = new()
|
||||
{
|
||||
new("دامنهٔ اختصاصی دارم؛ قابل اتصال است؟", "بله، پشت دامنه و گواهی SSL خودتان مستقر میشود."),
|
||||
new("دامنه اختصاصی دارم؛ قابل اتصال است؟", "بله، پشت دامنه و گواهی SSL خودتان مستقر میشود."),
|
||||
new("با دیتابیس خودم کار میکند؟", "کاملاً. SQL Server، PostgreSQL و MySQL پشتیبانی میشود."),
|
||||
new("چه درگاههایی پشتیبانی میشود؟", "Stripe و PayPal یا درگاه اختصاصی از طریق وبهوکها."),
|
||||
new("میتوانم دادهها را خروجی بگیرم؟", "هر زمان از داشبورد ادمین خروجی CSV/Excel بگیرید."),
|
||||
};
|
||||
|
||||
// ── Records ──
|
||||
private record QA(string Q, string A);
|
||||
private record StatItem(string ElementId, string Display, double Target, string Suffix, Color Color, string Label);
|
||||
private record TestimonialItem(string Quote, string Name, string Role, int Delay);
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
MainService.OnChangeHandler -=async () =>
|
||||
{
|
||||
await InvokeAsync(StateHasChanged);
|
||||
};
|
||||
MainService.OnChangeHandler -= OnStateChanged;
|
||||
}
|
||||
}
|
||||
@@ -6,14 +6,11 @@
|
||||
|
||||
<MudContainer MaxWidth="MaxWidth.Large" 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.Index">بازگشت</MudButton>
|
||||
</MudStack>
|
||||
<PageHeader Title="آمار باشگاه توسعه دهندگان" BackHref="@RouteConstants.Profile.Index" />
|
||||
|
||||
@if (_isLoading)
|
||||
{
|
||||
<MudProgressLinear Color="Color.Primary" Indeterminate="true" />
|
||||
<LoadingState Message="در حال دریافت آمار..." />
|
||||
}
|
||||
else if (_statistics is not null)
|
||||
{
|
||||
|
||||
@@ -3,16 +3,7 @@
|
||||
<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>
|
||||
<PageHeader Title="پکیجهای من" BackHref="@RouteConstants.Profile.Index" />
|
||||
|
||||
@if (_isLoading)
|
||||
{
|
||||
|
||||
@@ -3,13 +3,7 @@
|
||||
<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>
|
||||
<PageHeader Title="پکیجهای سرمایهگذاری" BackHref="@RouteConstants.Profile.Index" />
|
||||
|
||||
@if (_isLoading)
|
||||
{
|
||||
|
||||
@@ -4,26 +4,25 @@
|
||||
|
||||
@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>
|
||||
<MudContainer MaxWidth="MaxWidth.Large" Class="py-6">
|
||||
<LoadingState Message="در حال بارگذاری..." />
|
||||
</MudContainer>
|
||||
}
|
||||
else if (_package == null)
|
||||
{
|
||||
<MudStack AlignItems="AlignItems.Center" Class="py-16">
|
||||
<MudIcon Icon="@Icons.Material.Filled.Error" Size="Size.Large" Color="Color.Error" />
|
||||
<MudText Typo="Typo.h5" Class="mt-2">پکیج یافت نشد</MudText>
|
||||
<MudText Typo="Typo.body2" Class="mud-text-secondary">پکیج مورد نظر وجود ندارد یا حذف شده است.</MudText>
|
||||
<MudButton Variant="Variant.Filled" Color="Color.Primary" Class="mt-4" OnClick="() => Navigation.NavigateTo(RouteConstants.Main.MainPage)">
|
||||
بازگشت به صفحه اصلی
|
||||
</MudButton>
|
||||
</MudStack>
|
||||
<MudContainer MaxWidth="MaxWidth.Large" Class="py-6">
|
||||
<EmptyState Icon="@Icons.Material.Filled.Error"
|
||||
Title="پکیج یافت نشد"
|
||||
Description="پکیج مورد نظر وجود ندارد یا حذف شده است."
|
||||
ActionText="بازگشت به صفحه اصلی"
|
||||
ActionHref="@RouteConstants.Main.MainPage" />
|
||||
</MudContainer>
|
||||
}
|
||||
else
|
||||
{
|
||||
<!-- Breadcrumb -->
|
||||
<MudContainer MaxWidth="MaxWidth.Large" Class="py-4">
|
||||
<PageHeader Title="جزئیات پکیج" BackHref="@RouteConstants.Package.List" />
|
||||
<MudBreadcrumbs Items="_breadcrumbItems" />
|
||||
</MudContainer>
|
||||
|
||||
@@ -36,9 +35,9 @@ else
|
||||
<MudStack Class="mb-4">
|
||||
<!-- Package Image -->
|
||||
<MudPaper Class="pa-2 rounded-xl" Style="background: radial-gradient(600px 280px at 120% 0, #daccff 0, transparent 60%), radial-gradient(600px 280px at -10% 100%, #ffe2f2 0, transparent 60%), linear-gradient(180deg, #fff, #fbfaff);">
|
||||
<MudImage Src="@_package.Image"
|
||||
<AppImage Path="@_package.Image"
|
||||
Alt="@_package.Title"
|
||||
Height="250"
|
||||
ImgHeight="250"
|
||||
ObjectFit="ObjectFit.Cover"
|
||||
ObjectPosition="ObjectPosition.Center"
|
||||
Style="width:100%"
|
||||
@@ -228,9 +227,9 @@ else
|
||||
<MudItem xs="12" md="4">
|
||||
<MudPaper Elevation="2" Class="pa-4 d-flex flex-column h-100 cursor-pointer"
|
||||
OnClick="() => NavigateToPackage(relatedPackage.Id)">
|
||||
<MudImage Src="@relatedPackage.Image"
|
||||
<AppImage Path="@relatedPackage.Image"
|
||||
Alt="@relatedPackage.Title"
|
||||
Height="200"
|
||||
ImgHeight="200"
|
||||
ObjectFit="ObjectFit.Cover"
|
||||
Class="rounded-xl mb-3" />
|
||||
<MudText Typo="Typo.h6" Class="mb-2">@relatedPackage.Title</MudText>
|
||||
|
||||
@@ -74,7 +74,7 @@ public partial class PackageDetail : IDisposable
|
||||
Id = packageResponse.Id,
|
||||
Title = packageResponse.Title,
|
||||
Body = packageResponse.Description,
|
||||
Image = UrlUtility.DownloadUrl + packageResponse.ImagePath,
|
||||
Image = packageResponse.ImagePath ?? string.Empty,
|
||||
Specifications = new List<Specification>
|
||||
{
|
||||
new() { Name = "ظرفیت", Value = "تا ۲۰۰ عضو", Icon = Icons.Material.Filled.Group },
|
||||
|
||||
@@ -4,10 +4,7 @@
|
||||
|
||||
<MudContainer MaxWidth="MaxWidth.Large" 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.Index">بازگشت</MudButton>
|
||||
</MudStack>
|
||||
<PageHeader Title="مدیریت آدرسها" BackHref="@RouteConstants.Profile.Index" />
|
||||
|
||||
<MudPaper Elevation="2" Class="pa-4 rounded-lg">
|
||||
<MudStack Spacing="4">
|
||||
|
||||
@@ -4,10 +4,7 @@
|
||||
|
||||
<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>
|
||||
<PageHeader Title="تغییر رمز عبور" BackHref="@RouteConstants.Profile.Settings" />
|
||||
|
||||
<MudPaper Elevation="2" Class="pa-4 rounded-lg">
|
||||
<MudStack Spacing="3">
|
||||
|
||||
@@ -7,12 +7,12 @@
|
||||
|
||||
<MudSelect T="int" @bind-Value="_selectedDepth" Label="عمق" Variant="Variant.Outlined"
|
||||
Dense="true" Margin="Margin.Dense" Style="width: 90px; min-width: 90px;">
|
||||
<MudSelectItem Value="2">2 سطح</MudSelectItem>
|
||||
<MudSelectItem Value="3">3 سطح</MudSelectItem>
|
||||
<MudSelectItem Value="4">4 سطح</MudSelectItem>
|
||||
<MudSelectItem Value="5">5 سطح</MudSelectItem>
|
||||
<MudSelectItem Value="6">6 سطح</MudSelectItem>
|
||||
<MudSelectItem Value="15">همه</MudSelectItem>
|
||||
<MudSelectItem T="int" Value="2">2 سطح</MudSelectItem>
|
||||
<MudSelectItem T="int" Value="3">3 سطح</MudSelectItem>
|
||||
<MudSelectItem T="int" Value="4">4 سطح</MudSelectItem>
|
||||
<MudSelectItem T="int" Value="5">5 سطح</MudSelectItem>
|
||||
<MudSelectItem T="int" Value="6">6 سطح</MudSelectItem>
|
||||
<MudSelectItem T="int" Value="15">همه</MudSelectItem>
|
||||
</MudSelect>
|
||||
|
||||
<MudButtonGroup Variant="Variant.Outlined" Size="Size.Small" OverrideStyles="false">
|
||||
|
||||
@@ -9,9 +9,9 @@
|
||||
@if (!string.IsNullOrWhiteSpace(node.Avatar))
|
||||
{
|
||||
<MudAvatar Size="@GetAvatarSize(Level)">
|
||||
<MudImage ObjectFit="ObjectFit.Cover"
|
||||
ObjectPosition="ObjectPosition.Center"
|
||||
Src="@node.Avatar" />
|
||||
<AppImage Path="@node.Avatar"
|
||||
ObjectFit="ObjectFit.Cover"
|
||||
ObjectPosition="ObjectPosition.Center" />
|
||||
</MudAvatar>
|
||||
}
|
||||
else
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
@attribute [Route(RouteConstants.Profile.Hub)]
|
||||
|
||||
<PageTitle>پروفایل</PageTitle>
|
||||
|
||||
<MudContainer MaxWidth="MaxWidth.Small" Class="py-6">
|
||||
<MudStack AlignItems="AlignItems.Center" Spacing="3" Class="mb-6">
|
||||
<MudAvatar Size="Size.Large" Color="Color.Primary" Variant="Variant.Filled" Class="profile-hub-avatar">
|
||||
<MudIcon Icon="@Icons.Material.Outlined.Person" Size="Size.Large" />
|
||||
</MudAvatar>
|
||||
<MudStack Spacing="0" AlignItems="AlignItems.Center">
|
||||
<MudText Typo="Typo.h6" Class="fw-bold">
|
||||
@($"{_userProfile.FirstName} {_userProfile.LastName}")
|
||||
</MudText>
|
||||
<MudText Typo="Typo.body2" Class="mud-text-secondary">@(_userProfile.Mobile)</MudText>
|
||||
</MudStack>
|
||||
</MudStack>
|
||||
|
||||
<MudStack Spacing="2">
|
||||
<MudLink Href="@RouteConstants.Profile.Personal" Underline="Underline.None">
|
||||
<MudPaper Elevation="0" Class="pa-4 rounded-xl profile-hub-item">
|
||||
<MudStack Row="true" AlignItems="AlignItems.Center" Justify="Justify.SpaceBetween">
|
||||
<MudStack Row="true" AlignItems="AlignItems.Center" Spacing="3">
|
||||
<MudIcon Icon="@Icons.Material.Outlined.Person" Color="Color.Primary" />
|
||||
<MudStack Spacing="0">
|
||||
<MudText Typo="Typo.subtitle2">اطلاعات شخصی</MudText>
|
||||
<MudText Typo="Typo.caption" Class="mud-text-secondary">نام، کد ملی و تاریخ تولد</MudText>
|
||||
</MudStack>
|
||||
</MudStack>
|
||||
<MudIcon Icon="@Icons.Material.Filled.ChevronLeft" Class="mud-text-secondary" />
|
||||
</MudStack>
|
||||
</MudPaper>
|
||||
</MudLink>
|
||||
|
||||
<MudLink Href="@RouteConstants.Profile.Addresses" Underline="Underline.None">
|
||||
<MudPaper Elevation="0" Class="pa-4 rounded-xl profile-hub-item">
|
||||
<MudStack Row="true" AlignItems="AlignItems.Center" Justify="Justify.SpaceBetween">
|
||||
<MudStack Row="true" AlignItems="AlignItems.Center" Spacing="3">
|
||||
<MudIcon Icon="@Icons.Material.Outlined.LocationOn" Color="Color.Success" />
|
||||
<MudStack Spacing="0">
|
||||
<MudText Typo="Typo.subtitle2">آدرسها</MudText>
|
||||
<MudText Typo="Typo.caption" Class="mud-text-secondary">مدیریت آدرسهای تحویل</MudText>
|
||||
</MudStack>
|
||||
</MudStack>
|
||||
<MudIcon Icon="@Icons.Material.Filled.ChevronLeft" Class="mud-text-secondary" />
|
||||
</MudStack>
|
||||
</MudPaper>
|
||||
</MudLink>
|
||||
|
||||
<MudLink Href="@RouteConstants.Profile.Settings" Underline="Underline.None">
|
||||
<MudPaper Elevation="0" Class="pa-4 rounded-xl profile-hub-item">
|
||||
<MudStack Row="true" AlignItems="AlignItems.Center" Justify="Justify.SpaceBetween">
|
||||
<MudStack Row="true" AlignItems="AlignItems.Center" Spacing="3">
|
||||
<MudIcon Icon="@Icons.Material.Outlined.Settings" Color="Color.Warning" />
|
||||
<MudStack Spacing="0">
|
||||
<MudText Typo="Typo.subtitle2">تنظیمات</MudText>
|
||||
<MudText Typo="Typo.caption" Class="mud-text-secondary">تغییر رمز و تنظیمات حساب</MudText>
|
||||
</MudStack>
|
||||
</MudStack>
|
||||
<MudIcon Icon="@Icons.Material.Filled.ChevronLeft" Class="mud-text-secondary" />
|
||||
</MudStack>
|
||||
</MudPaper>
|
||||
</MudLink>
|
||||
</MudStack>
|
||||
</MudContainer>
|
||||
@@ -0,0 +1,34 @@
|
||||
using CMSMicroservice.Protobuf.Protos.User;
|
||||
using FrontOffice.Main.Utilities;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
|
||||
namespace FrontOffice.Main.Pages.Profile;
|
||||
|
||||
public partial class Hub
|
||||
{
|
||||
[Inject] private UserContract.UserContractClient UserContract { get; set; } = default!;
|
||||
|
||||
private GetUserResponse _userProfile = new();
|
||||
|
||||
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||
{
|
||||
await base.OnAfterRenderAsync(firstRender);
|
||||
if (firstRender)
|
||||
{
|
||||
await LoadUserProfile();
|
||||
}
|
||||
}
|
||||
|
||||
private async Task LoadUserProfile()
|
||||
{
|
||||
try
|
||||
{
|
||||
_userProfile = await UserContract.GetUserAsync(request: new());
|
||||
}
|
||||
catch
|
||||
{
|
||||
_userProfile = new GetUserResponse();
|
||||
}
|
||||
StateHasChanged();
|
||||
}
|
||||
}
|
||||
@@ -5,299 +5,237 @@
|
||||
|
||||
<MudContainer MaxWidth="MaxWidth.Large" Class="py-6">
|
||||
<MudGrid Spacing="4">
|
||||
<!-- Profile Header -->
|
||||
|
||||
@* ═══════════════════════════════════════════════
|
||||
1. PROFILE HEADER — Modern gradient card
|
||||
═══════════════════════════════════════════════ *@
|
||||
<MudItem xs="12">
|
||||
<MudPaper Elevation="4" Class="pa-6">
|
||||
<MudStack Spacing="4">
|
||||
<MudStack Row="true" Spacing="3" AlignItems="AlignItems.Center">
|
||||
<MudStack Row="true" Spacing="3" AlignItems="AlignItems.Center">
|
||||
<MudAvatar Size="Size.Large" Color="Color.Primary">
|
||||
<MudIcon Icon="@Icons.Material.Filled.Person" Size="Size.Large" />
|
||||
</MudAvatar>
|
||||
<div>
|
||||
<MudText Typo="Typo.h5">@($"{_userProfile.FirstName} {_userProfile.LastName}")</MudText>
|
||||
<MudText Typo="Typo.body2" Class="mud-text-secondary">@(_userProfile.Mobile)</MudText>
|
||||
<MudText Typo="Typo.caption" Class="mud-text-secondary">عضو از @(_userProfile.MobileVerifiedAt?.ToDateTime().MiladiToJalali())</MudText>
|
||||
</div>
|
||||
</MudStack>
|
||||
<MudSpacer/>
|
||||
|
||||
<MudButton Variant="Variant.Outlined" Href="https://dayadiamond.ir/" >سامانه دایا</MudButton>
|
||||
<MudPaper Elevation="0" Class="dash-header-card pa-5 pa-md-6 rounded-xl">
|
||||
<MudStack Row="true" Spacing="3" AlignItems="AlignItems.Center" Class="flex-wrap">
|
||||
<MudAvatar Size="Size.Large" Class="dash-avatar">
|
||||
<MudIcon Icon="@Icons.Material.Filled.Person" Size="Size.Large" />
|
||||
</MudAvatar>
|
||||
<MudStack Spacing="0" Class="flex-grow-1">
|
||||
<MudText Typo="Typo.h5" Class="dash-hero-name">
|
||||
@($"{_userProfile.FirstName} {_userProfile.LastName}")
|
||||
</MudText>
|
||||
<MudText Typo="Typo.body2" Class="dash-hero-sub">
|
||||
@(_userProfile.Mobile)
|
||||
</MudText>
|
||||
<MudText Typo="Typo.caption" Class="dash-hero-hint">
|
||||
عضو از @(_userProfile.MobileVerifiedAt?.ToDateTime().MiladiToJalali())
|
||||
</MudText>
|
||||
</MudStack>
|
||||
|
||||
|
||||
<!-- Referral Code Section -->
|
||||
<MudDivider />
|
||||
|
||||
@if (CanShowReferralLink)
|
||||
{
|
||||
<MudStack Spacing="3">
|
||||
<MudStack Row="true" AlignItems="AlignItems.Center">
|
||||
<MudText Typo="Typo.subtitle1">کد دعوت شما</MudText>
|
||||
<MudSpacer />
|
||||
<MudButton Variant="Variant.Outlined"
|
||||
Color="Color.Primary"
|
||||
StartIcon="@Icons.Material.Filled.Share"
|
||||
OnClick="ShareReferralCode">
|
||||
اشتراکگذاری
|
||||
</MudButton>
|
||||
</MudStack>
|
||||
<MudText Typo="Typo.body2" Class="mud-text-secondary">
|
||||
این کد را با دوستان خود به اشتراک بگذارید تا از خریدهای آنها پاداش دریافت کنید.
|
||||
</MudText>
|
||||
|
||||
<MudStack Row="true" Spacing="2" AlignItems="AlignItems.Center">
|
||||
<MudTextField @bind-Value="_userProfile.ReferralCode"
|
||||
Label="کد دعوت"
|
||||
Variant="Variant.Outlined"
|
||||
ReadOnly="true"
|
||||
Class="flex-grow-1"
|
||||
Adornment="Adornment.End"
|
||||
AdornmentIcon="@Icons.Material.Filled.ContentCopy"
|
||||
OnAdornmentClick="CopyReferralCode" />
|
||||
</MudStack>
|
||||
|
||||
@if (!string.IsNullOrWhiteSpace(_copyMessage))
|
||||
{
|
||||
<MudText Typo="Typo.caption" Color="Color.Success">@(_copyMessage)</MudText>
|
||||
}
|
||||
</MudStack>
|
||||
}
|
||||
else
|
||||
{
|
||||
<MudPaper Class="my-3 pa-3 border border-secondary">
|
||||
<MudStack Spacing="3" AlignItems="AlignItems.Center">
|
||||
<MudIcon Icon="@Icons.Material.Filled.Lock" Size="Size.Large" Color="Color.Info" />
|
||||
<MudText Typo="Typo.h6" Align="Align.Center" Color="Color.Info">
|
||||
لینک دعوت شما هنوز فعال نشده است
|
||||
</MudText>
|
||||
<MudText Typo="Typo.body1" Align="Align.Center" Class="mud-text-secondary">
|
||||
برای فعالسازی لینک دعوت و دعوت دوستان خود به جمع مشتریان ویژه کارابازار، کافی است ابتدا <strong>پکیج پایه ۵۶ میلیونی</strong> را تهیه کنید و سپس در <strong>باشگاه مشتریان</strong> عضو شوید.
|
||||
</MudText>
|
||||
<MudText Typo="Typo.body2" Align="Align.Center" Class="mud-text-secondary">
|
||||
از مزایای ویژه عضویت در باشگاه مشتریان کارابازار سلامت بهرهمند شده و با فعالیت در زمینه توسعه فروشگاهها پاداش دریافت کنید.
|
||||
</MudText>
|
||||
<MudButton Variant="Variant.Filled"
|
||||
Color="Color.Primary"
|
||||
Size="Size.Large"
|
||||
StartIcon="@Icons.Material.Filled.ShoppingCart"
|
||||
OnClick="OpenPurchaseOptions">
|
||||
شروع فرآیند تامین اعتبار
|
||||
</MudButton>
|
||||
</MudStack>
|
||||
</MudPaper>
|
||||
}
|
||||
<MudButton Variant="Variant.Filled"
|
||||
Class="rounded-pill dash-hero-btn"
|
||||
Href="https://dayadiamond.ir/"
|
||||
StartIcon="@Icons.Material.Filled.Diamond">
|
||||
سامانه دایا
|
||||
</MudButton>
|
||||
</MudStack>
|
||||
</MudPaper>
|
||||
</MudItem>
|
||||
|
||||
<!-- Wallet Highlight Row -->
|
||||
@* ═══════════════════════════════════════════════
|
||||
2. WALLET STRIP — Compact inline stats
|
||||
═══════════════════════════════════════════════ *@
|
||||
<MudItem xs="12">
|
||||
<MudPaper Elevation="3" Class="pa-4 rounded-lg gradient-border">
|
||||
<MudGrid Spacing="2" AlignItems="AlignItems.Center">
|
||||
<MudItem xs="12" sm="6" md="4">
|
||||
<MudStack>
|
||||
<MudText Typo="Typo.subtitle2" Class="mud-text-secondary">موجودی اعتباری</MudText>
|
||||
<MudText Typo="Typo.h5" Color="Color.Primary">@_walletCredit</MudText>
|
||||
</MudStack>
|
||||
</MudItem>
|
||||
<MudItem xs="12" sm="6" md="4">
|
||||
<MudStack>
|
||||
<MudText Typo="Typo.subtitle2" Class="mud-text-secondary">موجودی تخفیف باشگاه</MudText>
|
||||
<MudText Typo="Typo.h5" Color="Color.Primary">@_walletDiscount</MudText>
|
||||
</MudStack>
|
||||
</MudItem>
|
||||
<MudItem xs="12" sm="6" md="4">
|
||||
<MudStack>
|
||||
<MudText Typo="Typo.subtitle2" Class="mud-text-secondary">موجودی پاداش تیمی</MudText>
|
||||
<MudText Typo="Typo.h5" Color="Color.Primary">@_walletNetwork</MudText>
|
||||
</MudStack>
|
||||
</MudItem>
|
||||
<MudItem xs="12" md="4" Class="d-flex justify-end">
|
||||
<MudButton Variant="Variant.Filled" Color="Color.Primary" StartIcon="@Icons.Material.Filled.AccountBalanceWallet" Href="@RouteConstants.Profile.Wallet">جزئیات کیف پول</MudButton>
|
||||
</MudItem>
|
||||
</MudGrid>
|
||||
<MudPaper Elevation="1" Class="pa-2 pa-md-4 rounded-xl">
|
||||
<MudStack Row="true" Justify="Justify.SpaceAround" AlignItems="AlignItems.Center" Class="flex-wrap wallet-strip">
|
||||
<div class="wallet-strip-item">
|
||||
<div class="wallet-strip-label">
|
||||
<MudIcon Icon="@Icons.Material.Outlined.CreditCard" Size="Size.Small" Color="Color.Primary" />
|
||||
<MudText Typo="Typo.caption" Class="mud-text-secondary">اعتباری</MudText>
|
||||
</div>
|
||||
<MudText Typo="Typo.subtitle2" Color="Color.Primary">@_walletCredit</MudText>
|
||||
</div>
|
||||
<MudDivider Vertical="true" FlexItem="true" Class="d-none d-sm-flex" />
|
||||
<div class="wallet-strip-item">
|
||||
<div class="wallet-strip-label">
|
||||
<MudIcon Icon="@Icons.Material.Outlined.Discount" Size="Size.Small" Color="Color.Success" />
|
||||
<MudText Typo="Typo.caption" Class="mud-text-secondary">تخفیف باشگاه</MudText>
|
||||
</div>
|
||||
<MudText Typo="Typo.subtitle2" Color="Color.Success">@_walletDiscount</MudText>
|
||||
</div>
|
||||
<MudDivider Vertical="true" FlexItem="true" Class="d-none d-sm-flex" />
|
||||
<div class="wallet-strip-item">
|
||||
<div class="wallet-strip-label">
|
||||
<MudIcon Icon="@Icons.Material.Outlined.Groups" Size="Size.Small" Color="Color.Warning" />
|
||||
<MudText Typo="Typo.caption" Class="mud-text-secondary">پاداش تیمی</MudText>
|
||||
</div>
|
||||
<MudText Typo="Typo.subtitle2" Color="Color.Warning">@_walletNetwork</MudText>
|
||||
</div>
|
||||
<MudDivider Vertical="true" FlexItem="true" Class="d-none d-sm-flex" />
|
||||
<MudButton Variant="Variant.Text" Color="Color.Primary" Size="Size.Small"
|
||||
Href="@RouteConstants.Profile.Wallet" EndIcon="@Icons.Material.Filled.ArrowBack">
|
||||
کیف پول
|
||||
</MudButton>
|
||||
</MudStack>
|
||||
</MudPaper>
|
||||
</MudItem>
|
||||
|
||||
<!-- Profile Content as tiles -->
|
||||
@* ═══════════════════════════════════════════════
|
||||
3. REFERRAL SECTION
|
||||
═══════════════════════════════════════════════ *@
|
||||
<MudItem xs="12">
|
||||
<MudPaper Elevation="4" Class="pa-4">
|
||||
<MudGrid Spacing="3">
|
||||
<MudItem xs="6" sm="6" md="3">
|
||||
<MudLink Href="@RouteConstants.Profile.Personal" Underline="Underline.None" Class="tile-link">
|
||||
<MudCard Elevation="1" Class="rounded-lg profile-tile">
|
||||
<MudCardContent Class="d-flex flex-column align-center pa-4">
|
||||
<MudIcon Icon="@Icons.Material.Filled.Person" Size="Size.Large" Color="Color.Primary" />
|
||||
<MudText Typo="Typo.subtitle1" Class="mt-2">اطلاعات شخصی</MudText>
|
||||
<MudText Typo="Typo.caption" Class="mud-text-secondary">نمایش و ویرایش اطلاعات</MudText>
|
||||
</MudCardContent>
|
||||
</MudCard>
|
||||
</MudLink>
|
||||
</MudItem>
|
||||
<MudItem xs="6" sm="6" md="3">
|
||||
<MudLink Href="@RouteConstants.Profile.Addresses" Underline="Underline.None" Class="tile-link">
|
||||
<MudCard Elevation="1" Class="rounded-lg profile-tile">
|
||||
<MudCardContent Class="d-flex flex-column align-center pa-4">
|
||||
<MudIcon Icon="@Icons.Material.Filled.LocationOn" Size="Size.Large" Color="Color.Primary" />
|
||||
<MudText Typo="Typo.subtitle1" Class="mt-2">آدرسها</MudText>
|
||||
<MudText Typo="Typo.caption" Class="mud-text-secondary">مدیریت آدرسهای شما</MudText>
|
||||
</MudCardContent>
|
||||
</MudCard>
|
||||
</MudLink>
|
||||
</MudItem>
|
||||
<MudItem xs="6" sm="6" md="3">
|
||||
<MudLink Href="@RouteConstants.Profile.Tree" Underline="Underline.None" Class="tile-link">
|
||||
<MudCard Elevation="1" Class="rounded-lg profile-tile">
|
||||
<MudCardContent Class="d-flex flex-column align-center pa-4">
|
||||
<MudIcon Icon="@Icons.Material.Filled.AccountTree" Size="Size.Large" Color="Color.Primary" />
|
||||
<MudText Typo="Typo.subtitle1" Class="mt-2">شجرهنامه</MudText>
|
||||
<MudText Typo="Typo.caption" Class="mud-text-secondary">ساختار تیم</MudText>
|
||||
</MudCardContent>
|
||||
</MudCard>
|
||||
</MudLink>
|
||||
</MudItem>
|
||||
<MudItem xs="6" sm="6" md="3">
|
||||
<MudLink Href="@RouteConstants.Profile.Settings" Underline="Underline.None" Class="tile-link">
|
||||
<MudCard Elevation="1" Class="rounded-lg profile-tile">
|
||||
<MudCardContent Class="d-flex flex-column align-center pa-4">
|
||||
<MudIcon Icon="@Icons.Material.Filled.Settings" Size="Size.Large" Color="Color.Primary" />
|
||||
<MudText Typo="Typo.subtitle1" Class="mt-2">تنظیمات حساب</MudText>
|
||||
<MudText Typo="Typo.caption" Class="mud-text-secondary">اعلانها و تنظیمات</MudText>
|
||||
</MudCardContent>
|
||||
</MudCard>
|
||||
</MudLink>
|
||||
</MudItem>
|
||||
<MudItem xs="6" sm="6" md="3">
|
||||
<MudLink Href="@RouteConstants.Store.Products" Underline="Underline.None" Class="tile-link">
|
||||
<MudCard Elevation="1" Class="rounded-lg profile-tile">
|
||||
<MudCardContent Class="d-flex flex-column align-center pa-4">
|
||||
<MudIcon Icon="@Icons.Material.Filled.Storefront" Size="Size.Large" Color="Color.Primary" />
|
||||
<MudText Typo="Typo.subtitle1" Class="mt-2">فروشگاه</MudText>
|
||||
<MudText Typo="Typo.caption" Class="mud-text-secondary">مشاهده و خرید محصولات</MudText>
|
||||
</MudCardContent>
|
||||
</MudCard>
|
||||
</MudLink>
|
||||
</MudItem>
|
||||
<MudItem xs="6" sm="6" md="3">
|
||||
<MudLink Href="@RouteConstants.Profile.Wallet" Underline="Underline.None" Class="tile-link">
|
||||
<MudCard Elevation="1" Class="rounded-lg profile-tile">
|
||||
<MudCardContent Class="d-flex flex-column align-center pa-4">
|
||||
<MudIcon Icon="@Icons.Material.Filled.AccountBalanceWallet" Size="Size.Large" Color="Color.Primary" />
|
||||
<MudText Typo="Typo.subtitle1" Class="mt-2">کیف پول</MudText>
|
||||
<MudText Typo="Typo.caption" Class="mud-text-secondary">مدیریت و تاریخچه</MudText>
|
||||
</MudCardContent>
|
||||
</MudCard>
|
||||
</MudLink>
|
||||
</MudItem>
|
||||
<MudItem xs="6" sm="6" md="3">
|
||||
<MudLink Href="@RouteConstants.Profile.WithdrawalRequests" Underline="Underline.None" Class="tile-link">
|
||||
<MudCard Elevation="1" Class="rounded-lg profile-tile">
|
||||
<MudCardContent Class="d-flex flex-column align-center pa-4">
|
||||
<MudIcon Icon="@Icons.Material.Filled.RequestPage" Size="Size.Large" Color="Color.Warning" />
|
||||
<MudText Typo="Typo.subtitle1" Class="mt-2">درخواست برداشت</MudText>
|
||||
<MudText Typo="Typo.caption" Class="mud-text-secondary">ثبت و پیگیری برداشت</MudText>
|
||||
</MudCardContent>
|
||||
</MudCard>
|
||||
</MudLink>
|
||||
</MudItem>
|
||||
<MudItem xs="6" sm="6" md="3">
|
||||
<MudLink Href="@RouteConstants.Club.Membership" Underline="Underline.None" Class="tile-link">
|
||||
<MudCard Elevation="1" Class="rounded-lg profile-tile">
|
||||
<MudCardContent Class="d-flex flex-column align-center pa-4">
|
||||
<MudIcon Icon="@Icons.Material.Filled.CardMembership" Size="Size.Large" Color="Color.Secondary" />
|
||||
<MudText Typo="Typo.subtitle1" Class="mt-2">باشگاه مشتریان</MudText>
|
||||
<MudText Typo="Typo.caption" Class="mud-text-secondary">عضویت و مزایا</MudText>
|
||||
</MudCardContent>
|
||||
</MudCard>
|
||||
</MudLink>
|
||||
</MudItem>
|
||||
<MudItem xs="6" sm="6" md="3">
|
||||
<MudLink Href="@RouteConstants.Network.Statistics" Underline="Underline.None" Class="tile-link">
|
||||
<MudCard Elevation="1" Class="rounded-lg profile-tile">
|
||||
<MudCardContent Class="d-flex flex-column align-center pa-4">
|
||||
<MudIcon Icon="@Icons.Material.Filled.Groups" Size="Size.Large" Color="Color.Info" />
|
||||
<MudText Typo="Typo.subtitle1" Class="mt-2">آمار باشگاه</MudText>
|
||||
<MudText Typo="Typo.caption" Class="mud-text-secondary">آمار جزئیات باشگاه</MudText>
|
||||
</MudCardContent>
|
||||
</MudCard>
|
||||
</MudLink>
|
||||
</MudItem>
|
||||
<MudItem xs="6" sm="6" md="3">
|
||||
<MudLink Href="@RouteConstants.Commission.Dashboard" Underline="Underline.None" Class="tile-link">
|
||||
<MudCard Elevation="1" Class="rounded-lg profile-tile">
|
||||
<MudCardContent Class="d-flex flex-column align-center pa-4">
|
||||
<MudIcon Icon="@Icons.Material.Filled.Payments" Size="Size.Large" Color="Color.Success" />
|
||||
<MudText Typo="Typo.subtitle1" Class="mt-2">پاداش</MudText>
|
||||
<MudText Typo="Typo.caption" Class="mud-text-secondary">درآمد و تاریخچه</MudText>
|
||||
</MudCardContent>
|
||||
</MudCard>
|
||||
</MudLink>
|
||||
</MudItem>
|
||||
</MudGrid>
|
||||
</MudPaper>
|
||||
@if (CanShowReferralLink)
|
||||
{
|
||||
<MudPaper Elevation="1" Class="pa-5 rounded-xl">
|
||||
<MudStack Row="true" AlignItems="AlignItems.Center" Spacing="2" Class="mb-3">
|
||||
<MudIcon Icon="@Icons.Material.Filled.Share" Color="Color.Primary" />
|
||||
<MudText Typo="Typo.h6">کد دعوت شما</MudText>
|
||||
<MudSpacer />
|
||||
<MudButton Variant="Variant.Filled"
|
||||
Color="Color.Primary"
|
||||
Size="Size.Small"
|
||||
Class="rounded-pill"
|
||||
StartIcon="@Icons.Material.Filled.Share"
|
||||
OnClick="ShareReferralCode">
|
||||
اشتراکگذاری
|
||||
</MudButton>
|
||||
</MudStack>
|
||||
<MudText Typo="Typo.body2" Class="mud-text-secondary mb-3">
|
||||
این کد را با دوستان خود به اشتراک بگذارید تا از خریدهای آنها پاداش دریافت کنید.
|
||||
</MudText>
|
||||
<MudTextField @bind-Value="_userProfile.ReferralCode"
|
||||
Label="کد دعوت"
|
||||
Variant="Variant.Outlined"
|
||||
ReadOnly="true"
|
||||
Adornment="Adornment.End"
|
||||
AdornmentIcon="@Icons.Material.Filled.ContentCopy"
|
||||
OnAdornmentClick="CopyReferralCode"
|
||||
Class="rounded-lg" />
|
||||
@if (!string.IsNullOrWhiteSpace(_copyMessage))
|
||||
{
|
||||
<MudText Typo="Typo.caption" Color="Color.Success" Class="mt-2">@(_copyMessage)</MudText>
|
||||
}
|
||||
</MudPaper>
|
||||
}
|
||||
else
|
||||
{
|
||||
<MudPaper Elevation="0" Class="pa-6 rounded-xl text-center" Style="border:2px dashed var(--mud-palette-primary); background:rgba(99,102,241,.04);">
|
||||
<MudIcon Icon="@Icons.Material.Filled.Lock" Size="Size.Large" Color="Color.Primary" Class="mb-2" Style="font-size:2.5rem;" />
|
||||
<MudText Typo="Typo.h6" Color="Color.Primary" Class="mb-2">
|
||||
لینک دعوت شما هنوز فعال نشده است
|
||||
</MudText>
|
||||
<MudText Typo="Typo.body2" Class="mud-text-secondary mb-1" Style="max-width:560px; margin:0 auto;">
|
||||
برای فعالسازی لینک دعوت، ابتدا <strong>پکیج پایه</strong> را تهیه کنید و سپس در <strong>باشگاه مشتریان</strong> عضو شوید.
|
||||
</MudText>
|
||||
<MudText Typo="Typo.body2" Class="mud-text-secondary mb-4" Style="max-width:560px; margin:0 auto;">
|
||||
از مزایای ویژه عضویت بهرهمند شده و با فعالیت در زمینه توسعه فروشگاهها پاداش دریافت کنید.
|
||||
</MudText>
|
||||
<MudButton Variant="Variant.Filled"
|
||||
Color="Color.Primary"
|
||||
Size="Size.Large"
|
||||
Class="rounded-pill"
|
||||
StartIcon="@Icons.Material.Filled.ShoppingCart"
|
||||
OnClick="OpenPurchaseOptions">
|
||||
شروع فرآیند تامین اعتبار
|
||||
</MudButton>
|
||||
</MudPaper>
|
||||
}
|
||||
</MudItem>
|
||||
|
||||
@* ═══════════════════════════════════════════════
|
||||
3.5 LATEST BLOG BANNER
|
||||
═══════════════════════════════════════════════ *@
|
||||
@if (_latestPost is not null)
|
||||
{
|
||||
<MudItem xs="12">
|
||||
<MudLink Href="@($"/blog/{_latestPost.Slug}")" Underline="Underline.None">
|
||||
<MudPaper Elevation="1" Class="rounded-xl dash-blog-banner overflow-hidden">
|
||||
<MudStack Row="true" AlignItems="AlignItems.Center" Class="pa-2" Spacing="2">
|
||||
@if (!string.IsNullOrWhiteSpace(_latestPost.ThumbnailUrl))
|
||||
{
|
||||
<div style="width:72px;height:72px;min-width:72px;border-radius:10px;overflow:hidden;">
|
||||
<AppImage Path="@_latestPost.ThumbnailUrl" Alt="@_latestPost.Title"
|
||||
ObjectFit="ObjectFit.Cover" Style="width:100%;height:100%;" />
|
||||
</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
<MudAvatar Rounded="true" Size="Size.Large" Color="Color.Primary" Variant="Variant.Outlined">
|
||||
<MudIcon Icon="@Icons.Material.Outlined.Article" />
|
||||
</MudAvatar>
|
||||
}
|
||||
<MudStack Spacing="0" Class="flex-grow-1" Style="min-width:0;">
|
||||
<MudText Typo="Typo.caption" Color="Color.Primary" Style="font-size:0.7rem;">جدیدترین مطلب</MudText>
|
||||
<MudText Typo="Typo.body2" Class="dash-blog-title" Style="font-size:0.85rem;">@_latestPost.Title</MudText>
|
||||
</MudStack>
|
||||
<MudIcon Icon="@Icons.Material.Filled.ArrowBack" Color="Color.Primary" Size="Size.Small" />
|
||||
</MudStack>
|
||||
</MudPaper>
|
||||
</MudLink>
|
||||
</MudItem>
|
||||
}
|
||||
|
||||
@* ═══════════════════════════════════════════════
|
||||
4. QUICK ACCESS TILES — Modern grid
|
||||
═══════════════════════════════════════════════ *@
|
||||
<MudItem xs="12">
|
||||
<MudText Typo="Typo.h6" Class="mb-3">دسترسی سریع</MudText>
|
||||
<MudGrid Spacing="3" Justify="Justify.Center">
|
||||
@foreach (var tile in _dashTiles)
|
||||
{
|
||||
<MudItem xs="6" sm="4" md="3">
|
||||
<MudLink Href="@tile.Href" Underline="Underline.None" Class="tile-link">
|
||||
<MudPaper Elevation="0" Class="pa-4 rounded-xl dash-tile text-center">
|
||||
<MudAvatar Size="Size.Medium" Class="mx-auto mb-2" Style="@tile.AvatarStyle">
|
||||
<MudIcon Icon="@tile.Icon" Size="Size.Medium" />
|
||||
</MudAvatar>
|
||||
<MudText Typo="Typo.subtitle2">@tile.Title</MudText>
|
||||
<MudText Typo="Typo.caption" Class="mud-text-secondary">@tile.Subtitle</MudText>
|
||||
</MudPaper>
|
||||
</MudLink>
|
||||
</MudItem>
|
||||
}
|
||||
</MudGrid>
|
||||
</MudItem>
|
||||
|
||||
</MudGrid>
|
||||
</MudContainer>
|
||||
|
||||
<!-- Purchase Options Bottom Sheet -->
|
||||
@* ── Purchase Options Dialog ── *@
|
||||
<MudDialog @bind-Visible="_showPurchaseBottomSheet">
|
||||
<DialogContent>
|
||||
<MudStack Spacing="3" Class="pa-2">
|
||||
<MudText Typo="Typo.h6" Align="Align.Center">
|
||||
خرید پکیج پایه ۵۶ میلیون تومان
|
||||
</MudText>
|
||||
|
||||
<MudDivider />
|
||||
|
||||
<MudText Typo="Typo.body2" Class="mud-text-secondary">
|
||||
برای خرید پکیج پایه، یکی از روشهای زیر را انتخاب کنید:
|
||||
</MudText>
|
||||
|
||||
<!-- Direct Payment Option -->
|
||||
<MudPaper Elevation="0" Class="pa-4 rounded-lg" Style="border: 2px solid var(--mud-palette-primary);">
|
||||
<MudStack Spacing="2">
|
||||
<MudStack Row="true" AlignItems="AlignItems.Center" Spacing="2">
|
||||
<MudIcon Icon="@Icons.Material.Filled.CreditCard" Color="Color.Primary" Size="Size.Medium" />
|
||||
<MudText Typo="Typo.subtitle1" Color="Color.Primary"><b>پرداخت مستقیم</b></MudText>
|
||||
</MudStack>
|
||||
<MudText Typo="Typo.body2" Class="mud-text-secondary">
|
||||
پرداخت آنی از طریق درگاه بانکی
|
||||
</MudText>
|
||||
<MudButton Variant="Variant.Filled" Disabled="true"
|
||||
Color="Color.Primary"
|
||||
FullWidth="true"
|
||||
StartIcon="@Icons.Material.Filled.Payment"
|
||||
OnClick="DirectPayment">
|
||||
<MudText Typo="Typo.body2" Class="mud-text-secondary">پرداخت آنی از طریق درگاه بانکی</MudText>
|
||||
<MudButton Variant="Variant.Filled" Disabled="true" Color="Color.Primary" FullWidth="true"
|
||||
StartIcon="@Icons.Material.Filled.Payment" OnClick="DirectPayment">
|
||||
پرداخت با کارت بانکی(بزودی)
|
||||
</MudButton>
|
||||
</MudStack>
|
||||
</MudPaper>
|
||||
|
||||
<!-- Daya Loan Option -->
|
||||
<MudPaper Elevation="0" Class="pa-4 rounded-lg" Style="border: 2px solid var(--mud-palette-tertiary);">
|
||||
<MudStack Spacing="2">
|
||||
<MudStack Row="true" AlignItems="AlignItems.Center" Spacing="2">
|
||||
<MudIcon Icon="@Icons.Material.Filled.Diamond" Color="Color.Tertiary" Size="Size.Medium" />
|
||||
<MudText Typo="Typo.subtitle1" Color="Color.Tertiary"><b>اعتبار الماسی دایا</b></MudText>
|
||||
</MudStack>
|
||||
<MudText Typo="Typo.body2" Class="mud-text-secondary">
|
||||
تأمین اعتبار از طریق خرید توکن الماس و دریافت وام
|
||||
</MudText>
|
||||
<MudButton Variant="Variant.Filled"
|
||||
Color="Color.Tertiary"
|
||||
FullWidth="true"
|
||||
StartIcon="@Icons.Material.Filled.AccountBalance"
|
||||
OnClick="DayaLoanPayment">
|
||||
<MudText Typo="Typo.body2" Class="mud-text-secondary">تأمین اعتبار از طریق خرید توکن الماس و دریافت وام</MudText>
|
||||
<MudButton Variant="Variant.Filled" Color="Color.Tertiary" FullWidth="true"
|
||||
StartIcon="@Icons.Material.Filled.AccountBalance" OnClick="DayaLoanPayment">
|
||||
تأمین اعتبار الماسی
|
||||
</MudButton>
|
||||
</MudStack>
|
||||
</MudPaper>
|
||||
|
||||
<MudButton Variant="Variant.Text"
|
||||
Color="Color.Default"
|
||||
FullWidth="true"
|
||||
OnClick="ClosePurchaseOptions">
|
||||
<MudButton Variant="Variant.Text" Color="Color.Default" FullWidth="true" OnClick="ClosePurchaseOptions">
|
||||
بستن
|
||||
</MudButton>
|
||||
</MudStack>
|
||||
|
||||
@@ -22,10 +22,11 @@ public partial class Index
|
||||
[Inject] private UserAddressContract.UserAddressContractClient UserAddressContract { get; set; } = default!;
|
||||
[Inject] private PackageContract.PackageContractClient PackageContract { get; set; } = default!;
|
||||
[Inject] private AuthService AuthService { get; set; } = default!;
|
||||
[Inject] private BlogPostService BlogPostService { get; set; } = default!;
|
||||
|
||||
private GetUserResponse _userProfile = new();
|
||||
private UpdateUserRequest _updateUserRequest = new();
|
||||
private readonly UpdateUserRequestValidator _personalValidator = new();
|
||||
private GetUserForCustomerResponse _userProfile = new();
|
||||
private BlogPostCardDto? _latestPost;
|
||||
private UpdateCustomerProfileRequest _updateUserRequest = new();
|
||||
|
||||
private MudForm? _personalForm;
|
||||
|
||||
@@ -45,6 +46,22 @@ public partial class Index
|
||||
private bool _showPurchaseBottomSheet;
|
||||
private bool _isProcessingPayment;
|
||||
|
||||
// Dashboard Tiles
|
||||
private readonly List<DashTile> _dashTiles = new()
|
||||
{
|
||||
new(RouteConstants.Profile.Personal, Icons.Material.Filled.Person, "اطلاعات شخصی", "نمایش و ویرایش", "background:rgba(99,102,241,.12); color:#6366f1;"),
|
||||
new(RouteConstants.Profile.Addresses, Icons.Material.Filled.LocationOn, "آدرسها", "مدیریت آدرسها", "background:rgba(99,102,241,.12); color:#6366f1;"),
|
||||
new(RouteConstants.Profile.Tree, Icons.Material.Filled.AccountTree, "شجرهنامه", "ساختار تیم", "background:rgba(99,102,241,.12); color:#6366f1;"),
|
||||
new(RouteConstants.Gateway.StoreChooser, Icons.Material.Filled.Store, "فروشگاهها", "ورود به فروشگاه", "background:rgba(16,185,129,.12); color:#10b981;"),
|
||||
new(RouteConstants.Profile.Wallet, Icons.Material.Filled.AccountBalanceWallet, "کیف پول", "مدیریت و تاریخچه", "background:rgba(16,185,129,.12); color:#10b981;"),
|
||||
new(RouteConstants.Profile.WithdrawalRequests, Icons.Material.Filled.RequestPage, "درخواست برداشت", "ثبت و پیگیری", "background:rgba(245,158,11,.12); color:#f59e0b;"),
|
||||
new(RouteConstants.Club.Membership, Icons.Material.Filled.CardMembership, "باشگاه مشتریان", "عضویت و مزایا", "background:rgba(168,85,247,.12); color:#a855f7;"),
|
||||
new(RouteConstants.Network.Statistics, Icons.Material.Filled.Groups, "آمار باشگاه", "جزئیات باشگاه", "background:rgba(59,130,246,.12); color:#3b82f6;"),
|
||||
new(RouteConstants.Commission.Dashboard, Icons.Material.Filled.Payments, "پاداش", "درآمد و تاریخچه", "background:rgba(16,185,129,.12); color:#10b981;"),
|
||||
};
|
||||
|
||||
private record DashTile(string Href, string Icon, string Title, string Subtitle, string AvatarStyle);
|
||||
|
||||
// Address management
|
||||
private List<CustomerAddressModel> _addresses = new();
|
||||
private bool _isLoadingAddresses;
|
||||
@@ -64,6 +81,7 @@ public partial class Index
|
||||
await LoadUserProfile();
|
||||
await LoadAddresses();
|
||||
await LoadWallet();
|
||||
await LoadLatestPost();
|
||||
|
||||
// نمایش Modal قرارداد باشگاه اگر پکیج خریده ولی باشگاه فعال نشده
|
||||
await CheckAndShowClubContractModal();
|
||||
@@ -134,19 +152,47 @@ public partial class Index
|
||||
|
||||
private static string FormatPrice(long price) => string.Format("{0:N0} تومان", price);
|
||||
|
||||
private async Task LoadLatestPost()
|
||||
{
|
||||
try
|
||||
{
|
||||
var posts = await BlogPostService.GetFeaturedPostsAsync(1);
|
||||
if (!posts.Any())
|
||||
{
|
||||
var result = await BlogPostService.GetPublishedPostsAsync(page: 1, pageSize: 1);
|
||||
posts = result.Posts;
|
||||
}
|
||||
_latestPost = posts.FirstOrDefault();
|
||||
}
|
||||
catch
|
||||
{
|
||||
_latestPost = null;
|
||||
}
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
private async Task LoadUserProfile()
|
||||
{
|
||||
try
|
||||
{
|
||||
_userProfile = await UserContract.GetUserAsync(request: new());
|
||||
_updateUserRequest = _userProfile.Adapt<UpdateUserRequest>();
|
||||
_userProfile = await UserContract.GetUserForCustomerAsync(new());
|
||||
_updateUserRequest = new UpdateCustomerProfileRequest
|
||||
{
|
||||
FirstName = _userProfile.FirstName,
|
||||
LastName = _userProfile.LastName,
|
||||
Email = _userProfile.Email,
|
||||
NationalCode = _userProfile.NationalCode,
|
||||
};
|
||||
if (_userProfile.BirthDate != null)
|
||||
{
|
||||
_date = _userProfile.BirthDate.ToDateTime();
|
||||
_updateUserRequest.BirthDate = _userProfile.BirthDate;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// Handle the case when user is not authenticated or API fails
|
||||
_userProfile = new GetUserResponse();
|
||||
_userProfile = new GetUserForCustomerResponse();
|
||||
}
|
||||
StateHasChanged();
|
||||
}
|
||||
@@ -168,7 +214,7 @@ public partial class Index
|
||||
if (_date != null)
|
||||
_updateUserRequest.BirthDate = _date.Value.DateTimeToTimestamp();
|
||||
|
||||
await UserContract.UpdateUserAsync(request: _updateUserRequest);
|
||||
await UserContract.UpdateCustomerProfileAsync(request: _updateUserRequest);
|
||||
await LoadUserProfile();
|
||||
Snackbar.Add("اطلاعات شخصی با موفقیت ذخیره شد.", Severity.Success);
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
@using Blazored.LocalStorage
|
||||
@using CMSMicroservice.Protobuf.Protos.Package
|
||||
@using CMSMicroservice.Protobuf.Protos.User
|
||||
@inject IJSRuntime JS
|
||||
|
||||
|
||||
<PageTitle>نتیجه پرداخت | کارا بازار سلامت</PageTitle>
|
||||
@@ -37,7 +38,7 @@
|
||||
</MudText>
|
||||
|
||||
<MudButton Color="Color.Primary" Variant="Variant.Filled" Class="mt-6"
|
||||
Href="/profile">
|
||||
OnClick="GoBack">
|
||||
بازگشت به پروفایل
|
||||
</MudButton>
|
||||
}
|
||||
@@ -48,7 +49,7 @@
|
||||
<MudText Typo="Typo.body1" Class="mt-2">@_message</MudText>
|
||||
|
||||
<MudButton Color="Color.Primary" Variant="Variant.Filled" Class="mt-6"
|
||||
Href="/profile">
|
||||
OnClick="GoBack">
|
||||
بازگشت به پروفایل
|
||||
</MudButton>
|
||||
|
||||
@@ -173,4 +174,6 @@
|
||||
}
|
||||
|
||||
private static string FormatPrice(long price) => string.Format("{0:N0} تومان", price);
|
||||
|
||||
private async Task GoBack() => await JS.InvokeVoidAsync("history.back");
|
||||
}
|
||||
|
||||
@@ -4,13 +4,10 @@
|
||||
|
||||
<MudContainer MaxWidth="MaxWidth.Medium" 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.Index">بازگشت</MudButton>
|
||||
</MudStack>
|
||||
<PageHeader Title="اطلاعات شخصی" BackHref="@RouteConstants.Profile.Index" />
|
||||
|
||||
<MudPaper Elevation="2" Class="pa-4 rounded-lg">
|
||||
<MudForm @ref="_personalForm" Model="_updateUserRequest" Validation="@(_personalValidator.ValidateValue)">
|
||||
<MudForm @ref="_personalForm" Model="_updateUserRequest">
|
||||
<MudGrid Spacing="3">
|
||||
<MudItem xs="12" md="6">
|
||||
<MudTextField @bind-Value="_updateUserRequest.FirstName"
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
using CMSMicroservice.Protobuf.Protos.User;
|
||||
using CMSMicroservice.Protobuf.Validator.User;
|
||||
|
||||
using FrontOffice.Main.Utilities;
|
||||
using Mapster;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using MudBlazor;
|
||||
using Severity = MudBlazor.Severity;
|
||||
@@ -13,9 +11,8 @@ public partial class Personal : ComponentBase
|
||||
{
|
||||
[Inject] private UserContract.UserContractClient UserContract { get; set; } = default!;
|
||||
|
||||
private GetUserResponse _userProfile = new();
|
||||
private UpdateUserRequest _updateUserRequest = new();
|
||||
private readonly UpdateUserRequestValidator _personalValidator = new();
|
||||
private GetUserForCustomerResponse _userProfile = new();
|
||||
private UpdateCustomerProfileRequest _updateUserRequest = new();
|
||||
|
||||
private MudForm? _personalForm;
|
||||
private DateTime? _date;
|
||||
@@ -30,8 +27,14 @@ public partial class Personal : ComponentBase
|
||||
{
|
||||
try
|
||||
{
|
||||
_userProfile = await UserContract.GetUserAsync(new());
|
||||
_updateUserRequest = _userProfile.Adapt<UpdateUserRequest>();
|
||||
_userProfile = await UserContract.GetUserForCustomerAsync(new());
|
||||
_updateUserRequest = new UpdateCustomerProfileRequest
|
||||
{
|
||||
FirstName = _userProfile.FirstName,
|
||||
LastName = _userProfile.LastName,
|
||||
Email = _userProfile.Email,
|
||||
NationalCode = _userProfile.NationalCode,
|
||||
};
|
||||
if (_userProfile.BirthDate != null)
|
||||
_date = _userProfile.BirthDate.ToDateTime();
|
||||
}
|
||||
@@ -56,7 +59,7 @@ public partial class Personal : ComponentBase
|
||||
if (_date != null)
|
||||
_updateUserRequest.BirthDate = _date.Value.DateTimeToTimestamp();
|
||||
|
||||
await UserContract.UpdateUserAsync(_updateUserRequest);
|
||||
await UserContract.UpdateCustomerProfileAsync(_updateUserRequest);
|
||||
Snackbar.Add("اطلاعات شخصی با موفقیت ذخیره شد.", Severity.Success);
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
||||
@@ -4,10 +4,7 @@
|
||||
|
||||
<MudContainer MaxWidth="MaxWidth.Medium" 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.Index">بازگشت</MudButton>
|
||||
</MudStack>
|
||||
<PageHeader Title="تنظیمات حساب" BackHref="@RouteConstants.Profile.Index" />
|
||||
|
||||
<MudPaper Elevation="2" Class="pa-4 rounded-lg">
|
||||
<MudStack Spacing="4">
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using CMSMicroservice.Protobuf.Protos.User;
|
||||
using Mapster;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using MudBlazor;
|
||||
|
||||
@@ -16,8 +15,18 @@ public partial class Settings : ComponentBase
|
||||
{
|
||||
try
|
||||
{
|
||||
var user = await UserContract.GetUserAsync(new());
|
||||
_request = user.Adapt<UpdateUserRequest>();
|
||||
var user = await UserContract.GetUserForCustomerAsync(new());
|
||||
_request = new UpdateUserRequest
|
||||
{
|
||||
Id = user.Id,
|
||||
FirstName = user.FirstName,
|
||||
LastName = user.LastName,
|
||||
Email = user.Email,
|
||||
NationalCode = user.NationalCode,
|
||||
EmailNotifications = user.EmailNotifications,
|
||||
SmsNotifications = user.SmsNotifications,
|
||||
PushNotifications = user.PushNotifications,
|
||||
};
|
||||
}
|
||||
catch
|
||||
{
|
||||
|
||||
@@ -5,10 +5,7 @@
|
||||
|
||||
<MudContainer MaxWidth="MaxWidth.Large" 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.Index">بازگشت</MudButton>
|
||||
</MudStack>
|
||||
<PageHeader Title="شجرهنامه" BackHref="@RouteConstants.Profile.Index" />
|
||||
|
||||
<MudPaper Elevation="2" Class="pa-4 rounded-lg">
|
||||
<OrganizationChart />
|
||||
|
||||
@@ -4,10 +4,7 @@
|
||||
|
||||
<MudContainer MaxWidth="MaxWidth.Large" 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.Index">بازگشت</MudButton>
|
||||
</MudStack>
|
||||
<PageHeader Title="کیف پول" BackHref="@RouteConstants.Profile.Index" />
|
||||
|
||||
<MudGrid Spacing="2">
|
||||
<MudItem xs="12" sm="6" md="4">
|
||||
|
||||
@@ -4,10 +4,7 @@
|
||||
|
||||
<MudContainer MaxWidth="MaxWidth.Large" 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.Wallet">بازگشت به کیف پول</MudButton>
|
||||
</MudStack>
|
||||
<PageHeader Title="درخواستهای برداشت" BackHref="@RouteConstants.Profile.Wallet" />
|
||||
|
||||
<!-- فرم درخواست برداشت جدید -->
|
||||
<MudPaper Elevation="2" Class="pa-4 rounded-lg">
|
||||
@@ -100,7 +97,7 @@
|
||||
|
||||
@if (_isLoading)
|
||||
{
|
||||
<MudProgressLinear Color="Color.Primary" Indeterminate="true" />
|
||||
<LoadingState />
|
||||
}
|
||||
else if (!_withdrawals.Any())
|
||||
{
|
||||
|
||||
@@ -6,10 +6,11 @@
|
||||
<MudContainer MaxWidth="MaxWidth.Large" Class="px-1">
|
||||
<MudGrid Spacing="4" Justify="Justify.Center">
|
||||
<MudItem xs="12" md="5" Class="d-none d-sm-block">
|
||||
<MudStack Spacing="2" Class="mb-6">
|
||||
<MudChip T="string" Color="Color.Secondary" Variant="Variant.Filled" Class="mb-2">ثبتنام سه
|
||||
مرحلهای</MudChip>
|
||||
<MudText Typo="Typo.h3" Class="mb-2">
|
||||
<MudStack Spacing="3" Class="mb-6">
|
||||
<MudChip T="string" Color="Color.Primary" Variant="Variant.Filled" Size="Size.Small" Class="rounded-pill">
|
||||
ثبتنام سه مرحلهای
|
||||
</MudChip>
|
||||
<MudText Typo="Typo.h3" Class="mb-1">
|
||||
فقط در چند دقیقه حساب خود را فعال کنید
|
||||
</MudText>
|
||||
<MudText Typo="Typo.body1" Class="mud-text-secondary">
|
||||
@@ -18,34 +19,47 @@
|
||||
</MudText>
|
||||
</MudStack>
|
||||
|
||||
<MudPaper Elevation="1" Class="pa-4 rounded-xl gradient-border">
|
||||
<MudStack Spacing="2">
|
||||
<MudStack Row="true" AlignItems="AlignItems.Center" Spacing="1">
|
||||
<MudIcon Icon="@Icons.Material.Filled.VerifiedUser" Color="Color.Primary" />
|
||||
<MudPaper Elevation="0" Class="pa-5 rounded-xl" Style="border:1px solid var(--mud-palette-divider);">
|
||||
<MudStack Spacing="3">
|
||||
<MudStack Row="true" AlignItems="AlignItems.Center" Spacing="2">
|
||||
<MudAvatar Size="Size.Small" Color="Color.Primary" Variant="Variant.Filled">
|
||||
<MudIcon Icon="@Icons.Material.Outlined.Verified" Size="Size.Small" />
|
||||
</MudAvatar>
|
||||
<MudText Typo="Typo.subtitle1">مزایای ثبتنام آنلاین</MudText>
|
||||
</MudStack>
|
||||
<MudText Typo="Typo.body2" Class="mud-text-secondary">
|
||||
• تایید سریع و آنلاین شماره موبایل<br />
|
||||
• تکمیل اطلاعات هویتی بدون مراجعه حضوری<br />
|
||||
• دریافت نسخهی دیجیتال قرارداد برای بررسی دقیق
|
||||
</MudText>
|
||||
<MudStack Spacing="2">
|
||||
<MudStack Row="true" Spacing="2" AlignItems="AlignItems.Center">
|
||||
<MudIcon Icon="@Icons.Material.Outlined.PhoneAndroid" Size="Size.Small" Color="Color.Primary" />
|
||||
<MudText Typo="Typo.body2" Class="mud-text-secondary">تایید سریع و آنلاین شماره موبایل</MudText>
|
||||
</MudStack>
|
||||
<MudStack Row="true" Spacing="2" AlignItems="AlignItems.Center">
|
||||
<MudIcon Icon="@Icons.Material.Outlined.Badge" Size="Size.Small" Color="Color.Primary" />
|
||||
<MudText Typo="Typo.body2" Class="mud-text-secondary">تکمیل اطلاعات هویتی بدون مراجعه حضوری</MudText>
|
||||
</MudStack>
|
||||
<MudStack Row="true" Spacing="2" AlignItems="AlignItems.Center">
|
||||
<MudIcon Icon="@Icons.Material.Outlined.Description" Size="Size.Small" Color="Color.Primary" />
|
||||
<MudText Typo="Typo.body2" Class="mud-text-secondary">دریافت نسخهی دیجیتال قرارداد برای بررسی دقیق</MudText>
|
||||
</MudStack>
|
||||
</MudStack>
|
||||
</MudStack>
|
||||
</MudPaper>
|
||||
</MudItem>
|
||||
|
||||
<MudItem xs="12" md="7">
|
||||
<MudPaper Elevation="3" Class="pa-6 wizard-card">
|
||||
<MudPaper Elevation="1" Class="pa-5 pa-md-6 wizard-card">
|
||||
@if (_completed)
|
||||
{
|
||||
<MudStack Spacing="3" AlignItems="AlignItems.Center" Class="text-center">
|
||||
<MudAvatar Icon="@Icons.Material.Filled.CheckCircle" Color="Color.Success" Size="Size.Large" />
|
||||
<MudStack Spacing="3" AlignItems="AlignItems.Center" Class="text-center py-6">
|
||||
<MudAvatar Size="Size.Large" Color="Color.Success" Variant="Variant.Filled">
|
||||
<MudIcon Icon="@Icons.Material.Outlined.CheckCircle" Size="Size.Large" />
|
||||
</MudAvatar>
|
||||
<MudText Typo="Typo.h4">درخواست شما ثبت شد</MudText>
|
||||
<MudText Typo="Typo.body1" Class="mud-text-secondary">
|
||||
<MudText Typo="Typo.body1" Class="mud-text-secondary" Style="max-width:400px;">
|
||||
تیم ما پس از بررسی اطلاعات با شما تماس خواهد گرفت. میتوانید از طریق داشبورد وضعیت ثبتنام
|
||||
را دنبال کنید.
|
||||
</MudText>
|
||||
<MudStack Row="true" Spacing="2" Justify="Justify.Center">
|
||||
<MudButton Variant="Variant.Filled" Color="Color.Primary"
|
||||
<MudButton Variant="Variant.Filled" Color="Color.Primary" Class="rounded-lg"
|
||||
OnClick="@(() => Navigation.NavigateTo(RouteConstants.Main.MainPage))">بازگشت به صفحه
|
||||
اصلی</MudButton>
|
||||
<MudButton Variant="Variant.Outlined" Color="Color.Primary"
|
||||
@@ -56,43 +70,45 @@
|
||||
}
|
||||
else
|
||||
{
|
||||
<MudStack Spacing="3" >
|
||||
<MudStack Spacing="3">
|
||||
<MudStack Row="true" Justify="Justify.SpaceBetween" AlignItems="AlignItems.Center">
|
||||
<MudText Typo="Typo.h4">مراحل ثبتنام</MudText>
|
||||
<MudChip T="string" Color="Color.Info" Variant="Variant.Outlined" Size="Size.Small">۳ مرحله
|
||||
<MudText Typo="Typo.h5">مراحل ثبتنام</MudText>
|
||||
<MudChip T="string" Color="Color.Primary" Variant="Variant.Outlined" Size="Size.Small" Class="rounded-pill">
|
||||
مرحله @(_activeStep + 1) از ۳
|
||||
</MudChip>
|
||||
</MudStack>
|
||||
|
||||
@if (_isSubmitting)
|
||||
{
|
||||
<MudProgressLinear Color="Color.Primary" Indeterminate="true" />
|
||||
<MudProgressLinear Color="Color.Primary" Indeterminate="true" Class="rounded" />
|
||||
}
|
||||
|
||||
<MudStepper @bind-ActiveIndex="_activeStep" @ref="_mudStepper" Elevation="0" DisableClick="true" Class="mb-4 " id="registration-stepper">
|
||||
<MudStepper @bind-ActiveIndex="_activeStep" @ref="_mudStepper" Elevation="0" DisableClick="true" Class="mb-4" id="registration-stepper">
|
||||
<ChildContent>
|
||||
<MudStep Label="تأیید موبایل" Icon="@Icons.Material.Filled.Smartphone">
|
||||
<MudStep Label="تأیید موبایل" Icon="@Icons.Material.Outlined.PhoneAndroid">
|
||||
@* Inline AuthDialog with captcha enabled *@
|
||||
<AuthDialog @ref="_authDialog" InlineMode="true" HideCancelButton="true" OnLoginSuccess="@(async () => { OnPhoneVerified(); })" />
|
||||
</MudStep>
|
||||
|
||||
<MudStep Label="اطلاعات هویتی" Icon="@Icons.Material.Filled.Badge">
|
||||
<MudStep Label="اطلاعات هویتی" Icon="@Icons.Material.Outlined.Badge">
|
||||
<MudForm @ref="_stepTwoForm">
|
||||
<MudTextField Label="نام" Variant="Variant.Outlined" Immediate="true"
|
||||
@bind-Value="_model.FirstName" For="@(() => _model.FirstName)" />
|
||||
<MudTextField Label="نام خانوادگی" Variant="Variant.Outlined" Immediate="true"
|
||||
@bind-Value="_model.LastName" For="@(() => _model.LastName)" />
|
||||
<MudTextField Label="کد ملی" Variant="Variant.Outlined" Immediate="true"
|
||||
MaxLength="10" @bind-Value="_model.NationalCode"
|
||||
For="@(() => _model.NationalCode)" InputType="InputType.Number" />
|
||||
<MudStack Spacing="3">
|
||||
<MudTextField Label="نام" Variant="Variant.Outlined" Immediate="true"
|
||||
@bind-Value="_model.FirstName" For="@(() => _model.FirstName)" />
|
||||
<MudTextField Label="نام خانوادگی" Variant="Variant.Outlined" Immediate="true"
|
||||
@bind-Value="_model.LastName" For="@(() => _model.LastName)" />
|
||||
<MudTextField Label="کد ملی" Variant="Variant.Outlined" Immediate="true"
|
||||
MaxLength="10" @bind-Value="_model.NationalCode"
|
||||
For="@(() => _model.NationalCode)" InputType="InputType.Number" />
|
||||
</MudStack>
|
||||
</MudForm>
|
||||
</MudStep>
|
||||
|
||||
<MudStep Label="قوانین و قرارداد" Icon="@Icons.Material.Filled.Rule">
|
||||
<MudStep Label="قوانین و قرارداد" Icon="@Icons.Material.Outlined.Rule">
|
||||
<MudForm @ref="_stepThreeForm">
|
||||
<MudAlert Variant="Variant.Outlined" Severity="Severity.Info" Class="mb-3">
|
||||
<MudAlert Variant="Variant.Outlined" Severity="Severity.Info" Class="mb-3 rounded-lg">
|
||||
لطفاً قوانین و شرایط همکاری را با دقت مطالعه کنید و در صورت موافقت، تیک
|
||||
تایید را فعال نمایید. همچنین میتوانید نسخهی قرارداد را دانلود و ذخیره
|
||||
کنید.
|
||||
تایید را فعال نمایید.
|
||||
</MudAlert>
|
||||
<MudPaper Elevation="0" Class="terms-box pa-4 mb-3">
|
||||
<MudText Typo="Typo.subtitle2" Class="mb-2">بخشی از قوانین:</MudText>
|
||||
@@ -106,47 +122,44 @@
|
||||
</MudList>
|
||||
</MudPaper>
|
||||
|
||||
<MudStack Row="true" AlignItems="AlignItems.Center" Spacing="2" Class="mb-2">
|
||||
<MudButton Variant="Variant.Outlined" Color="Color.Primary"
|
||||
StartIcon="@Icons.Material.Filled.Download" Disabled="_isSubmitting"
|
||||
OnClick="DownloadContract">
|
||||
دانلود/پرینت قرارداد نمونه
|
||||
</MudButton>
|
||||
<MudText Typo="Typo.caption" Class="mud-text-secondary">فرمت: PDF</MudText>
|
||||
</MudStack>
|
||||
<MudButton Variant="Variant.Outlined" Color="Color.Primary" Class="rounded-lg mb-3"
|
||||
StartIcon="@Icons.Material.Outlined.Download" Disabled="_isSubmitting"
|
||||
OnClick="DownloadContract">
|
||||
دانلود قرارداد نمونه (PDF)
|
||||
</MudButton>
|
||||
|
||||
<MudCheckBox @bind-Checked="_model.AcceptTerms" Color="Color.Success"
|
||||
<MudCheckBox @bind-Checked="_model.AcceptTerms" Color="Color.Primary"
|
||||
For="@(() => _model.AcceptTerms)"
|
||||
Label="قوانین و مقررات را مطالعه کردهام و میپذیرم" />
|
||||
</MudForm>
|
||||
</MudStep>
|
||||
</ChildContent>
|
||||
<ActionContent Context="stepper">
|
||||
<MudStack Row="true" Justify="Justify.SpaceBetween" AlignItems="AlignItems.Center">
|
||||
<MudStack Row="true" Justify="Justify.SpaceBetween" AlignItems="AlignItems.Center" Class="mt-2">
|
||||
@if (_isAuthenticated && _activeStep == 1)
|
||||
{
|
||||
<MudButton Variant="Variant.Text" Color="Color.Secondary"
|
||||
|
||||
<MudButton Variant="Variant.Text" Color="Color.Error" Size="Size.Small"
|
||||
OnClick="@AuthService.LogoutAsync">خروج از حساب</MudButton>
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
<MudButton Variant="Variant.Text" Color="Color.Secondary"
|
||||
Disabled="_activeStep == 0 || _isSubmitting"
|
||||
OnClick="@(async () => { await GoBack(); })">مرحله قبل</MudButton>
|
||||
<MudButton Variant="Variant.Text" Color="Color.Secondary" Size="Size.Small"
|
||||
Disabled="_activeStep == 0 || _isSubmitting"
|
||||
OnClick="@(async () => { await GoBack(); })">مرحله قبل</MudButton>
|
||||
}
|
||||
<MudSpacer/>
|
||||
<MudButton Variant="Variant.Filled" Color="Color.Primary"
|
||||
<MudButton Variant="Variant.Filled" Color="Color.Primary" Class="rounded-lg"
|
||||
Disabled="_isSubmitting"
|
||||
OnClick="@(async () => { await GoNextAsync(); })">
|
||||
@if (_isSubmitting)
|
||||
{
|
||||
<MudProgressCircular Size="Size.Small" Indeterminate="true" Class="me-2" />
|
||||
}
|
||||
@_nextButtonText
|
||||
</MudButton>
|
||||
</MudStack>
|
||||
</ActionContent>
|
||||
</MudStepper>
|
||||
|
||||
|
||||
</MudStack>
|
||||
}
|
||||
</MudPaper>
|
||||
|
||||
@@ -23,13 +23,14 @@ public partial class RegisterWizard
|
||||
private bool _completed;
|
||||
private AuthDialog? _authDialog;
|
||||
private MudStepper? _mudStepper;
|
||||
private UpdateUserRequest _updateUserRequest = new();
|
||||
private UpdateCustomerProfileRequest _updateUserRequest = new();
|
||||
private bool _isAuthenticated;
|
||||
private CancellationTokenSource? _operationCts;
|
||||
private UserAuthInfo _userAuthInfo;
|
||||
private Guid signGuid = Guid.NewGuid();
|
||||
private const string TokenStorageKey = "auth:token";
|
||||
private readonly DialogOptions _normalWidth = new() { MaxWidth = MaxWidth.ExtraSmall, FullWidth = true };
|
||||
private bool _initialDataLoaded;
|
||||
|
||||
[Inject] private AuthService AuthService { get; set; } = default!;
|
||||
[Inject] private IDeviceDetector _deviceDetector { get; set; } = default!;
|
||||
@@ -55,6 +56,7 @@ public partial class RegisterWizard
|
||||
if (_userAuthInfo.IsSignMainContract)
|
||||
{
|
||||
Navigation.NavigateTo(RouteConstants.Profile.Index);
|
||||
return;
|
||||
}
|
||||
|
||||
if (_activeStep == 0)
|
||||
@@ -63,8 +65,9 @@ public partial class RegisterWizard
|
||||
_activeStep = 1;
|
||||
await InvokeAsync(StateHasChanged);
|
||||
}
|
||||
else if (_activeStep == 1)
|
||||
else if (_activeStep == 1 && !_initialDataLoaded)
|
||||
{
|
||||
_initialDataLoaded = true;
|
||||
try
|
||||
{
|
||||
var existUser = await UserContract.GetUserForCustomerAsync(new GetUserForCustomerRequest());
|
||||
@@ -95,7 +98,6 @@ public partial class RegisterWizard
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
await base.OnAfterRenderAsync(firstRender);
|
||||
}
|
||||
|
||||
@@ -355,7 +357,7 @@ public partial class RegisterWizard
|
||||
_updateUserRequest.NationalCode = _model.NationalCode.PersianToEnglish();
|
||||
|
||||
|
||||
await UserContract.UpdateUserAsync(request: _updateUserRequest);
|
||||
await UserContract.UpdateCustomerProfileAsync(request: _updateUserRequest);
|
||||
Snackbar.Add("اطلاعات شخصی با موفقیت ذخیره شد.", Severity.Success);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
<MudContainer MaxWidth="MaxWidth.Large" Class="py-6">
|
||||
<MudStack Spacing="3">
|
||||
<MudText Typo="Typo.h4">سبد خرید</MudText>
|
||||
<PageHeader Title="سبد خرید" BackHref="@RouteConstants.Store.Products" />
|
||||
|
||||
@if (CartData.Items.Count == 0)
|
||||
{
|
||||
@@ -30,8 +30,8 @@
|
||||
<MudTd>
|
||||
<MudStack Spacing="1">
|
||||
<MudStack Row="true" Spacing="2" AlignItems="AlignItems.Center">
|
||||
<MudImage Src="@GetProductImageUrl(context.ImageUrl)" Alt="@context.Title"
|
||||
Width="64" Height="64" Class="product-thumb" />
|
||||
<AppImage Path="@GetProductImageUrl(context.ImageUrl)" Alt="@context.Title"
|
||||
ImgWidth="64" ImgHeight="64" Class="product-thumb" />
|
||||
<MudText>@context.Title</MudText>
|
||||
</MudStack>
|
||||
@if (context.Discount > 0 || !string.IsNullOrWhiteSpace(context.Created) || !string.IsNullOrWhiteSpace(context.Description))
|
||||
@@ -86,8 +86,8 @@
|
||||
<MudStack Spacing="1">
|
||||
<MudStack Row="true" Justify="Justify.SpaceBetween" AlignItems="AlignItems.Center">
|
||||
<MudStack Row="true" Spacing="2" AlignItems="AlignItems.Center">
|
||||
<MudImage Src="@GetProductImageUrl(item.ImageUrl)" Alt="@item.Title"
|
||||
Width="50" Height="50" Class="rounded-circle" />
|
||||
<AppImage Path="@GetProductImageUrl(item.ImageUrl)" Alt="@item.Title"
|
||||
ImgWidth="50" ImgHeight="50" Class="rounded-circle" />
|
||||
<MudText Typo="Typo.subtitle2">@item.Title</MudText>
|
||||
</MudStack>
|
||||
@if (item.Discount > 0)
|
||||
@@ -154,8 +154,8 @@
|
||||
</MudStack>
|
||||
}
|
||||
<MudStack Row="true" Justify="Justify.SpaceBetween" AlignItems="AlignItems.Center">
|
||||
<MudText Typo="Typo.h6" Style="font-weight:bold;">مبلغ قابل پرداخت:</MudText>
|
||||
<MudText Typo="Typo.h6" Color="Color.Primary" Style="font-weight:bold;">@FormatPrice(TotalWithVAT) تومان</MudText>
|
||||
<MudText Typo="Typo.h6" Class="fw-bold">مبلغ قابل پرداخت:</MudText>
|
||||
<MudText Typo="Typo.h6" Color="Color.Primary" Class="fw-bold">@FormatPrice(TotalWithVAT) تومان</MudText>
|
||||
</MudStack>
|
||||
</MudStack>
|
||||
|
||||
@@ -185,8 +185,8 @@
|
||||
}
|
||||
<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>
|
||||
<MudText Typo="Typo.subtitle1" Class="fw-bold">مبلغ قابل پرداخت:</MudText>
|
||||
<MudText Typo="Typo.subtitle1" Color="Color.Primary" Class="fw-bold">@FormatPrice(TotalWithVAT) تومان</MudText>
|
||||
</MudStack>
|
||||
</MudStack>
|
||||
</MudPaper>
|
||||
|
||||
@@ -66,7 +66,7 @@ public partial class Cart : ComponentBase, IDisposable
|
||||
private long VATAmount => VAT.CalculateVAT(CartData.Total);
|
||||
|
||||
private static string GetProductImageUrl(string? imageUrl)
|
||||
=> string.IsNullOrWhiteSpace(imageUrl) ? "/images/product-placeholder.svg" : imageUrl;
|
||||
=> string.IsNullOrWhiteSpace(imageUrl) ? "/images/product-placeholder.svg" : imageUrl.TrimStart('/');
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
|
||||
@@ -5,9 +5,9 @@
|
||||
<PageTitle>دستهبندیها</PageTitle>
|
||||
|
||||
<MudContainer MaxWidth="MaxWidth.Large" Class="py-6">
|
||||
<PageHeader Title="دستهبندی محصولات" BackHref="@RouteConstants.Store.Products" />
|
||||
<MudPaper Elevation="1" Class="pa-4 mb-4 rounded-lg">
|
||||
<MudStack Spacing="1">
|
||||
<MudText Typo="Typo.h5">دستهبندی محصولات</MudText>
|
||||
<MudText Typo="Typo.body2" Class="mud-text-secondary">
|
||||
از بین درخت دستهبندیها انتخاب کنید تا محصولات آن دسته را مشاهده نمایید.
|
||||
</MudText>
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
<PageTitle>خلاصه خرید</PageTitle>
|
||||
|
||||
<MudContainer MaxWidth="MaxWidth.Large" Class="py-6">
|
||||
<PageHeader Title="خلاصه خرید" BackHref="@RouteConstants.Store.Cart" />
|
||||
<MudGrid Spacing="3">
|
||||
<MudItem xs="12" md="8">
|
||||
<MudPaper Elevation="2" Class="pa-4 rounded-lg mb-3">
|
||||
@@ -30,7 +31,7 @@
|
||||
@foreach (var address in _addresses)
|
||||
{
|
||||
<MudPaper Outlined="@(_selectedAddress?.Id != address.Id)"
|
||||
Elevation="@(_selectedAddress?.Id == address.Id ? 4 : 0)"
|
||||
Elevation="@(_selectedAddress?.Id == address.Id ? 2 : 0)"
|
||||
Class="pa-3 rounded-xl cursor-pointer"
|
||||
Style="@(_selectedAddress?.Id == address.Id ? "border: 2px solid var(--mud-palette-primary);" : "")"
|
||||
@onclick="() => _selectedAddress = address">
|
||||
@@ -84,8 +85,8 @@
|
||||
<MudListItemText>
|
||||
<MudStack Spacing="1">
|
||||
<MudStack Row="true" Justify="Justify.SpaceBetween" AlignItems="AlignItems.Center">
|
||||
<MudImage Src="@GetProductImageUrl(item.ImageUrl)" Alt="@item.Title"
|
||||
Width="48" Height="48" Class="rounded-circle" />
|
||||
<AppImage Path="@GetProductImageUrl(item.ImageUrl)" Alt="@item.Title"
|
||||
ImgWidth="48" ImgHeight="48" Class="rounded-circle" />
|
||||
<MudText Typo="Typo.subtitle2">@item.Title</MudText>
|
||||
<MudText Typo="Typo.subtitle2">@FormatPrice(item.LineTotal)</MudText>
|
||||
</MudStack>
|
||||
@@ -118,8 +119,8 @@
|
||||
}
|
||||
<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(VAT.AddVAT(Cart.Total))</MudText>
|
||||
<MudText Typo="Typo.subtitle1" Class="fw-bold">مبلغ قابل پرداخت:</MudText>
|
||||
<MudText Typo="Typo.subtitle1" Color="Color.Primary" Class="fw-bold">@FormatPrice(VAT.AddVAT(Cart.Total))</MudText>
|
||||
</MudStack>
|
||||
</MudStack>
|
||||
|
||||
|
||||
@@ -113,5 +113,5 @@ public partial class CheckoutSummary : ComponentBase
|
||||
private long CalculateVAT() => VAT.CalculateVAT(Cart.Total);
|
||||
|
||||
private static string GetProductImageUrl(string? imageUrl)
|
||||
=> string.IsNullOrWhiteSpace(imageUrl) ? "/images/product-placeholder.svg" : imageUrl;
|
||||
=> string.IsNullOrWhiteSpace(imageUrl) ? "/images/product-placeholder.svg" : imageUrl.TrimStart('/');
|
||||
}
|
||||
@@ -6,24 +6,24 @@
|
||||
@if (_loading)
|
||||
{
|
||||
<MudContainer MaxWidth="MaxWidth.Medium" Class="py-6">
|
||||
<MudStack AlignItems="AlignItems.Center">
|
||||
<MudProgressCircular Indeterminate="true" Color="Color.Primary" />
|
||||
</MudStack>
|
||||
<LoadingState />
|
||||
</MudContainer>
|
||||
}
|
||||
else if (_order is null)
|
||||
{
|
||||
<MudContainer MaxWidth="MaxWidth.Medium" Class="py-6">
|
||||
<MudAlert Severity="Severity.Warning">سفارش یافت نشد.</MudAlert>
|
||||
<MudButton Variant="Variant.Text" StartIcon="@Icons.Material.Filled.ArrowBack" OnClick="() => Navigation.NavigateTo(RouteConstants.Store.Orders)">بازگشت</MudButton>
|
||||
<EmptyState Icon="@Icons.Material.Filled.SearchOff"
|
||||
Title="سفارش یافت نشد."
|
||||
ActionText="بازگشت"
|
||||
ActionHref="@RouteConstants.Store.Orders" />
|
||||
</MudContainer>
|
||||
}
|
||||
else
|
||||
{
|
||||
<MudContainer MaxWidth="MaxWidth.Large" Class="py-6">
|
||||
<PageHeader Title="@($"جزئیات سفارش #{_order.Id}")" BackHref="@RouteConstants.Store.Orders" />
|
||||
<MudPaper Elevation="2" Class="pa-4 rounded-lg">
|
||||
<MudStack Spacing="2">
|
||||
<MudText Typo="Typo.h5">سفارش #@_order.Id</MudText>
|
||||
@if (_order.PaymentDate != null)
|
||||
{
|
||||
<MudText Typo="Typo.body2" Class="mud-text-secondary">تاریخ پرداخت: @_order.PaymentDate.ToDateTime().MiladiToJalaliWithTime()</MudText>
|
||||
@@ -46,8 +46,8 @@ else
|
||||
<RowTemplate>
|
||||
<MudTd>
|
||||
<MudStack Row="true" Spacing="2" AlignItems="AlignItems.Center">
|
||||
<MudImage Src="@GetProductImageUrl(context.ProductThumbnailPath)" Alt="@context.ProductTitle"
|
||||
Width="60" Height="60" Class="rounded-circle" />
|
||||
<AppImage Path="@GetProductImageUrl(context.ProductThumbnailPath)" Alt="@context.ProductTitle"
|
||||
ImgWidth="60" ImgHeight="60" Class="rounded-circle" />
|
||||
<MudText>@context.ProductTitle</MudText>
|
||||
</MudStack>
|
||||
</MudTd>
|
||||
@@ -65,8 +65,8 @@ else
|
||||
<MudPaper Class="pa-3 rounded-lg" Outlined="true">
|
||||
<MudStack Spacing="1">
|
||||
<MudStack Row="true" Spacing="2" AlignItems="AlignItems.Center">
|
||||
<MudImage Src="@GetProductImageUrl(it.ProductThumbnailPath)" Alt="@it.ProductTitle"
|
||||
Width="60" Height="60" Class="rounded-circle" />
|
||||
<AppImage Path="@GetProductImageUrl(it.ProductThumbnailPath)" Alt="@it.ProductTitle"
|
||||
ImgWidth="60" ImgHeight="60" Class="rounded-circle" />
|
||||
<MudText>@it.ProductTitle</MudText>
|
||||
</MudStack>
|
||||
<MudStack Row="true" Justify="Justify.SpaceBetween">
|
||||
@@ -100,15 +100,15 @@ else
|
||||
</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(_order.VatInfo.TotalAmount)</MudText>
|
||||
<MudText Typo="Typo.subtitle1" Class="fw-bold">مبلغ قابل پرداخت:</MudText>
|
||||
<MudText Typo="Typo.subtitle1" Color="Color.Primary" Class="fw-bold">@FormatPrice(_order.VatInfo.TotalAmount)</MudText>
|
||||
</MudStack>
|
||||
}
|
||||
else
|
||||
{
|
||||
<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(subtotal)</MudText>
|
||||
<MudText Typo="Typo.subtitle1" Class="fw-bold">مبلغ قابل پرداخت:</MudText>
|
||||
<MudText Typo="Typo.subtitle1" Color="Color.Primary" Class="fw-bold">@FormatPrice(subtotal)</MudText>
|
||||
</MudStack>
|
||||
}
|
||||
</MudStack>
|
||||
|
||||
@@ -45,6 +45,6 @@ public partial class OrderDetail : ComponentBase
|
||||
}
|
||||
|
||||
private static string GetProductImageUrl(string? imageUrl)
|
||||
=> string.IsNullOrWhiteSpace(imageUrl) ? "/images/product-placeholder.svg" : UrlUtility.DownloadUrl+imageUrl;
|
||||
=> string.IsNullOrWhiteSpace(imageUrl) ? "/images/product-placeholder.svg" : imageUrl.TrimStart('/');
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
<PageTitle>پیگیری سفارش</PageTitle>
|
||||
|
||||
<MudContainer MaxWidth="MaxWidth.Medium" Class="py-6">
|
||||
<PageHeader Title="پیگیری سفارش" BackHref="@RouteConstants.Store.Orders" />
|
||||
@if (_loading)
|
||||
{
|
||||
<MudStack AlignItems="AlignItems.Center">
|
||||
@@ -15,7 +16,7 @@
|
||||
{
|
||||
<MudAlert Severity="Severity.Warning">سفارش یافت نشد.</MudAlert>
|
||||
<MudButton Variant="Variant.Text" StartIcon="@Icons.Material.Filled.ArrowBack"
|
||||
Href="@RouteConstants.Store.Orders">
|
||||
OnClick="GoBack">
|
||||
بازگشت به سفارشها
|
||||
</MudButton>
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using CMSMicroservice.Protobuf.Protos.UserOrder;
|
||||
using FrontOffice.Main.Utilities;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Microsoft.JSInterop;
|
||||
using Messages = CMSMicroservice.Protobuf.Protos;
|
||||
|
||||
namespace FrontOffice.Main.Pages.Store;
|
||||
@@ -8,6 +9,7 @@ namespace FrontOffice.Main.Pages.Store;
|
||||
public partial class OrderTracking : ComponentBase
|
||||
{
|
||||
[Inject] private OrderService OrderService { get; set; } = default!;
|
||||
[Inject] private IJSRuntime JS { get; set; } = default!;
|
||||
|
||||
[Parameter] public long id { get; set; }
|
||||
|
||||
@@ -123,4 +125,6 @@ public partial class OrderTracking : ComponentBase
|
||||
public bool IsCurrent { get; set; }
|
||||
public string Date { get; set; } = "";
|
||||
}
|
||||
|
||||
private async Task GoBack() => await JS.InvokeVoidAsync("history.back");
|
||||
}
|
||||
|
||||
@@ -4,12 +4,10 @@
|
||||
<PageTitle>سفارشات من</PageTitle>
|
||||
|
||||
<MudContainer MaxWidth="MaxWidth.Large" Class="py-6">
|
||||
<MudText Typo="Typo.h4" Class="mb-3">سفارشات من</MudText>
|
||||
<PageHeader Title="سفارشات من" BackHref="@RouteConstants.Store.Products" />
|
||||
@if (_loading)
|
||||
{
|
||||
<MudStack AlignItems="AlignItems.Center" Class="py-4">
|
||||
<MudProgressCircular Indeterminate="true" Color="Color.Primary" />
|
||||
</MudStack>
|
||||
<LoadingState />
|
||||
}
|
||||
else if (_orders.Count == 0)
|
||||
{
|
||||
|
||||
@@ -6,23 +6,22 @@
|
||||
@if (_loading)
|
||||
{
|
||||
<MudContainer MaxWidth="MaxWidth.Medium" Class="py-6">
|
||||
<MudStack AlignItems="AlignItems.Center">
|
||||
<MudProgressCircular Color="Color.Primary" Indeterminate="true"/>
|
||||
</MudStack>
|
||||
<LoadingState />
|
||||
</MudContainer>
|
||||
}
|
||||
else if (_product is null)
|
||||
{
|
||||
<MudContainer MaxWidth="MaxWidth.Medium" Class="py-6">
|
||||
<MudAlert Severity="Severity.Warning">محصول یافت نشد.</MudAlert>
|
||||
<MudButton Class="mt-2" Variant="Variant.Text" StartIcon="@Icons.Material.Filled.ArrowBack"
|
||||
OnClick="() => Navigation.NavigateTo(RouteConstants.Store.Products)">بازگشت
|
||||
</MudButton>
|
||||
<EmptyState Icon="@Icons.Material.Filled.SearchOff"
|
||||
Title="محصول یافت نشد."
|
||||
ActionText="بازگشت"
|
||||
ActionHref="@RouteConstants.Store.Products" />
|
||||
</MudContainer>
|
||||
}
|
||||
else
|
||||
{
|
||||
<MudContainer MaxWidth="MaxWidth.Large" Class="py-6">
|
||||
<PageHeader Title="جزئیات محصول" BackHref="@RouteConstants.Store.Products" />
|
||||
<MudGrid Spacing="3">
|
||||
<MudItem xs="12" md="6">
|
||||
@if (_product is not null)
|
||||
@@ -32,7 +31,9 @@ else
|
||||
<MudPaper Class="rounded-lg pa-2">
|
||||
@if (!string.IsNullOrWhiteSpace(MainImageUrl))
|
||||
{
|
||||
<div class="rounded-lg" style="width:100%;height:360px;background-image: url('@MainImageUrl');background-size: cover; background-position: center;border-radius: 0.5rem;color: transparent;" >@MainImageAlt</div>
|
||||
<AppImage Path="@MainImageUrl" Alt="@MainImageAlt"
|
||||
ObjectFit="ObjectFit.Cover"
|
||||
Style="width:100%; max-height:400px; border-radius:12px;" />
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -45,7 +46,7 @@ else
|
||||
@foreach (var item in _galleryItems)
|
||||
{
|
||||
<MudButton Variant="Variant.Text" Class="p-0" Style="min-width:0;" OnClick="() => SelectGalleryImage(item)">
|
||||
<MudImage Src="@GetThumbnailUrl(item)" Alt="@item.Title" Class="rounded-sm" Style="@GetThumbnailStyle(item)" />
|
||||
<AppImage Path="@GetThumbnailUrl(item)" Alt="@item.Title" Class="rounded-sm" Style="@GetThumbnailStyle(item)" />
|
||||
</MudButton>
|
||||
}
|
||||
</MudStack>
|
||||
|
||||
@@ -3,7 +3,18 @@
|
||||
|
||||
<PageTitle>محصولات</PageTitle>
|
||||
|
||||
<MudContainer MaxWidth="MaxWidth.Large" Class="pa-2 pa-md-6">
|
||||
<MudContainer MaxWidth="MaxWidth.Large" Class="py-6">
|
||||
<!-- Hero Banner -->
|
||||
<MudPaper Class="store-hero pa-6 pa-md-8 mb-4 rounded-xl" Elevation="0">
|
||||
<MudStack AlignItems="AlignItems.Center" Spacing="2">
|
||||
<MudIcon Icon="@Icons.Material.Filled.Storefront" Size="Size.Large" Class="dash-hero-name" />
|
||||
<MudText Typo="Typo.h5" Align="Align.Center" Class="dash-hero-name">فروشگاه کارا بازار سلامت</MudText>
|
||||
<MudText Typo="Typo.body2" Align="Align.Center" Class="dash-hero-sub">
|
||||
محصولات با کیفیت با ضمانت اصالت و ارسال سریع
|
||||
</MudText>
|
||||
</MudStack>
|
||||
</MudPaper>
|
||||
|
||||
<MudPaper Elevation="1" Class="pa-3 pa-md-4 mb-4 rounded-lg">
|
||||
<MudGrid Spacing="2" AlignItems="AlignItems.Center">
|
||||
@* ردیف اول: جستجو و دکمهها *@
|
||||
@@ -44,25 +55,25 @@
|
||||
Margin="Margin.Dense"
|
||||
AnchorOrigin="Origin.BottomCenter"
|
||||
AdornmentIcon="@Icons.Material.Filled.Sort">
|
||||
<MudSelectItem Value="ProductSortOption.PriceDesc">
|
||||
<MudSelectItem T="ProductSortOption" Value="ProductSortOption.PriceDesc">
|
||||
<div class="d-flex align-center gap-2">
|
||||
<MudIcon Icon="@Icons.Material.Filled.ArrowDownward" Size="Size.Small"/>
|
||||
گرانترین
|
||||
</div>
|
||||
</MudSelectItem>
|
||||
<MudSelectItem Value="ProductSortOption.PriceAsc">
|
||||
<MudSelectItem T="ProductSortOption" Value="ProductSortOption.PriceAsc">
|
||||
<div class="d-flex align-center gap-2">
|
||||
<MudIcon Icon="@Icons.Material.Filled.ArrowUpward" Size="Size.Small"/>
|
||||
ارزانترین
|
||||
</div>
|
||||
</MudSelectItem>
|
||||
<MudSelectItem Value="ProductSortOption.Newest">
|
||||
<MudSelectItem T="ProductSortOption" Value="ProductSortOption.Newest">
|
||||
<div class="d-flex align-center gap-2">
|
||||
<MudIcon Icon="@Icons.Material.Filled.NewReleases" Size="Size.Small"/>
|
||||
جدیدترین
|
||||
</div>
|
||||
</MudSelectItem>
|
||||
<MudSelectItem Value="ProductSortOption.Title">
|
||||
<MudSelectItem T="ProductSortOption" Value="ProductSortOption.Title">
|
||||
<div class="d-flex align-center gap-2">
|
||||
<MudIcon Icon="@Icons.Material.Filled.SortByAlpha" Size="Size.Small"/>
|
||||
الفبایی
|
||||
|
||||
@@ -8,15 +8,19 @@
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<meta name="theme-color" content="#7c4dff" />
|
||||
<meta name="apple-mobile-web-app-capable" content="yes" />
|
||||
<meta name="apple-mobile-web-app-status-bar-style" content="default" />
|
||||
<base href="~/" />
|
||||
<link href="css/site.css" rel="stylesheet" />
|
||||
<link href="FrontOffice.Main.styles.css" rel="stylesheet" />
|
||||
<link rel="icon" type="image/png" href="favicon.png"/>
|
||||
<component type="typeof(HeadOutlet)" render-mode="Server" />
|
||||
|
||||
<link href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap" rel="stylesheet" />
|
||||
<!-- Ensure latest MudBlazor CSS is used (cache-busting) -->
|
||||
<!-- MudBlazor CSS (باید قبل از site.css باشه تا override بشه) -->
|
||||
<link href="_content/MudBlazor/MudBlazor.min.css" rel="stylesheet" asp-append-version="true" />
|
||||
<!-- Custom styles (بعد از MudBlazor برای override) -->
|
||||
<link href="css/site.css" rel="stylesheet" asp-append-version="true" />
|
||||
<link href="FrontOffice.Main.styles.css" rel="stylesheet" />
|
||||
<!-- d3-org-chart custom styles -->
|
||||
<link href="css/org-chart.css" rel="stylesheet" asp-append-version="true" />
|
||||
</head>
|
||||
@@ -42,6 +46,7 @@
|
||||
<script src="js/d3-flextree.min.js"></script>
|
||||
<script src="js/d3-org-chart3.js"></script>
|
||||
<script src="js/org-chart.js" asp-append-version="true"></script>
|
||||
<script src="js/landing.js" asp-append-version="true"></script>
|
||||
|
||||
<script src="_framework/blazor.server.js"></script>
|
||||
<script>
|
||||
|
||||
Reference in New Issue
Block a user