diff --git a/src/FrontOffice.Main/Pages/Index.razor b/src/FrontOffice.Main/Pages/Index.razor index 2be5568..4ba4291 100644 --- a/src/FrontOffice.Main/Pages/Index.razor +++ b/src/FrontOffice.Main/Pages/Index.razor @@ -15,11 +15,11 @@ - رشد تیم، فروش واقعی، پاداش شفاف + @(_pageData?.HeroTitle ?? "رشد تیم، فروش واقعی، پاداش شفاف") - با دعوت از دوستان، از خریدهای واقعی محصولات سلامت پاداش بگیرید. ثبت‌نام سریع، داشبورد لحظه‌ای. + @(_pageData?.HeroSubtitle ?? "با دعوت از دوستان، از خریدهای واقعی محصولات سلامت پاداش بگیرید. ثبت‌نام سریع، داشبورد لحظه‌ای.") @@ -27,13 +27,13 @@ Class="rounded-pill hero-cta-primary" Size="Size.Large" OnClick="NavigateToRegistrationWizard"> - شروع رایگان + @(_settings?.HeroButtonPrimaryText ?? "شروع رایگان") - آخرین اخبار + @(_settings?.HeroButtonSecondaryText ?? "آخرین اخبار") @@ -99,7 +99,7 @@
- سه گام تا شروع + @(_settings?.StepsTitle ?? "سه گام تا شروع") بدون پیچیدگی، سریع و آسان @@ -128,7 +128,7 @@
- چرا کارا بازار سلامت؟ + @(_settings?.FeaturesTitle ?? "چرا کارا بازار سلامت؟") ابزارهایی ساده و قدرتمند برای رشد کسب‌وکار شما @@ -259,7 +259,7 @@
- اعتماد مشتریان + @(_settings?.TestimonialsTitle ?? "اعتماد مشتریان") بخشی از تجربه استفاده از «کارا بازار سلامت» @@ -299,7 +299,7 @@
- سوالات متداول + @(_settings?.FaqTitle ?? "سوالات متداول") پاسخ به سوالات رایج شما @@ -326,16 +326,16 @@
- آماده شروع هستید؟ + @(_settings?.CtaTitle ?? "آماده شروع هستید؟") - همین الان ثبت‌نام کنید و از مزایای کارا بازار سلامت بهره‌مند شوید. + @(_settings?.CtaDescription ?? "همین الان ثبت‌نام کنید و از مزایای کارا بازار سلامت بهره‌مند شوید.") - شروع رایگان + @(_settings?.CtaButtonText ?? "شروع رایگان")
diff --git a/src/FrontOffice.Main/Pages/Index.razor.cs b/src/FrontOffice.Main/Pages/Index.razor.cs index 595ff44..96875f8 100644 --- a/src/FrontOffice.Main/Pages/Index.razor.cs +++ b/src/FrontOffice.Main/Pages/Index.razor.cs @@ -9,21 +9,48 @@ public partial class Index : IDisposable { [Inject] private BlogPostService BlogPostService { get; set; } = default!; [Inject] private AuthService AuthService { get; set; } = default!; + [Inject] private SitePageSettingsService PageSettingsService { get; set; } = default!; + + // ── CMS page data ── + private PageSettingsDto? _pageData; + private LandingSettings? _settings; // ── Latest blog posts (loaded from CMS) ── private List _latestPosts = new(); + // ── Data lists (populated from DB or fallback) ── + private List<(string Icon, string Text)> _trustBadges = new(); + private List<(string Title, string Desc)> _steps = new(); + private List<(string Icon, string Title, string Desc, int Delay)> _features = new(); + private List _stats = new(); + private List _testimonials = new(); + private List _faqs = new(); + protected override async Task OnInitializedAsync() { MainService.OnChangeHandler += OnStateChanged; + // Load landing page settings from CMS + try + { + _pageData = await PageSettingsService.GetPageAsync("landing"); + if (_pageData != null) + { + _settings = _pageData.GetSettings(); + } + } + catch + { + // Fallback: settings remain null → defaults below + } + + PopulateFromSettings(); + // Load latest published blog posts - // اول پین‌شده‌ها، اگر کافی نبود آخرین پست‌ها اضافه شود try { _latestPosts = await BlogPostService.GetFeaturedPostsAsync(2); - - // اگر فقط ۱ پین‌شده داریم، ۱ پست آخر هم اضافه کن + if (_latestPosts.Count < 2) { var result = await BlogPostService.GetPublishedPostsAsync(page: 1, pageSize: 2); @@ -44,6 +71,155 @@ public partial class Index : IDisposable } } + private void PopulateFromSettings() + { + // ── Trust badges ── + if (_settings?.TrustBadges?.Any() == true) + { + _trustBadges = _settings.TrustBadges + .Select(b => (ResolveIcon(b.IconName), b.Text ?? "")) + .ToList(); + } + else + { + _trustBadges = new() + { + (Icons.Material.Outlined.Timer, "ثبت‌نام زیر ۲ دقیقه"), + (Icons.Material.Outlined.SupportAgent, "پشتیبانی ۷×۲۴"), + (Icons.Material.Outlined.Lock, "پرداخت ایمن"), + (Icons.Material.Outlined.Verified, "تضمین کیفیت"), + }; + } + + // ── Steps ── + if (_settings?.Steps?.Any() == true) + { + _steps = _settings.Steps + .Select(s => (s.Title ?? "", s.Description ?? "")) + .ToList(); + } + else + { + _steps = new() + { + ("ثبت‌نام و احراز هویت", "یک حساب بسازید، شماره موبایل را تأیید و اطلاعات هویتی را تکمیل کنید."), + ("دعوت دوستان", "لینک دعوت اختصاصی خود را با دوستان و آشنایان به اشتراک بگذارید."), + ("دریافت پاداش", "از خریدهای واقعی اعضای تیمتان پاداش شفاف و لحظه‌ای دریافت کنید."), + }; + } + + // ── Features ── + if (_settings?.Features?.Any() == true) + { + _features = _settings.Features + .Select((f, i) => (ResolveIcon(f.IconName), f.Title ?? "", f.Description ?? "", i * 100)) + .ToList(); + } + else + { + _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 ── + if (_settings?.Stats?.Any() == true) + { + _stats = _settings.Stats + .Select((s, i) => new StatItem( + $"stat-{i}", + $"{s.Value}{s.Suffix}", + s.Value, + s.Suffix ?? "", + ResolveColor(s.Color), + s.Label ?? "")) + .ToList(); + } + else + { + _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 ── + if (_settings?.Testimonials?.Any() == true) + { + _testimonials = _settings.Testimonials + .Select((t, i) => new TestimonialItem(t.Quote ?? "", t.Name ?? "", t.Role ?? "", i * 150)) + .ToList(); + } + else + { + _testimonials = new() + { + new("با کارا بازار سلامت، محاسبه کارمزدها و پایش تیم‌ها بدون اکسل و دردسر انجام می‌شود.", "شرکت سینا نت", "مدیر عملیات", 0), + new("شجره‌نامه بصری و گزارش‌های دقیق باعث شد رشد تیم را لحظه‌ای ببینیم.", "هولدینگ آریانا", "مدیر فروش", 150), + new("سادگی ثبت‌نام و شفافیت پاداش‌ها مهم‌ترین مزیت این پلتفرم است.", "گروه بهداشتی نوین", "مدیر توسعه", 300), + }; + } + + // ── FAQs ── + if (_settings?.Faqs?.Any() == true) + { + _faqs = _settings.Faqs + .Select(f => new QA(f.Question ?? "", f.Answer ?? "")) + .ToList(); + } + else + { + _faqs = new() + { + new("دامنه اختصاصی دارم؛ قابل اتصال است؟", "بله، پشت دامنه و گواهی SSL خودتان مستقر می‌شود."), + new("با دیتابیس خودم کار می‌کند؟", "کاملاً. SQL Server، PostgreSQL و MySQL پشتیبانی می‌شود."), + new("چه درگاه‌هایی پشتیبانی می‌شود؟", "Stripe و PayPal یا درگاه اختصاصی از طریق وب‌هوک‌ها."), + new("می‌توانم داده‌ها را خروجی بگیرم؟", "هر زمان از داشبورد ادمین خروجی CSV/Excel بگیرید."), + }; + } + } + + /// + /// Resolve icon name from SettingsJson to MudBlazor icon string. + /// Falls back to a generic icon. + /// + private static string ResolveIcon(string? iconName) + { + if (string.IsNullOrWhiteSpace(iconName)) return Icons.Material.Outlined.Info; + + // Try to get from MudBlazor Icons via reflection + var field = typeof(Icons.Material.Outlined).GetField(iconName, + System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static); + if (field != null) return (string)(field.GetValue(null) ?? Icons.Material.Outlined.Info); + + // Also try Filled + field = typeof(Icons.Material.Filled).GetField(iconName, + System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static); + if (field != null) return (string)(field.GetValue(null) ?? Icons.Material.Outlined.Info); + + return Icons.Material.Outlined.Info; + } + + private static Color ResolveColor(string? colorName) => colorName?.ToLowerInvariant() switch + { + "primary" => Color.Primary, + "secondary" => Color.Secondary, + "success" => Color.Success, + "warning" => Color.Warning, + "error" => Color.Error, + "info" => Color.Info, + _ => Color.Default + }; + protected override async Task OnAfterRenderAsync(bool firstRender) { if (firstRender) @@ -88,65 +264,40 @@ public partial class Index : IDisposable await InvokeAsync(StateHasChanged); } - // ── 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 _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 _testimonials = new() - { - new("با کارا بازار سلامت، محاسبه کارمزدها و پایش تیم‌ها بدون اکسل و دردسر انجام می‌شود.", "شرکت سینا نت", "مدیر عملیات", 0), - new("شجره‌نامه بصری و گزارش‌های دقیق باعث شد رشد تیم را لحظه‌ای ببینیم.", "هولدینگ آریانا", "مدیر فروش", 150), - new("سادگی ثبت‌نام و شفافیت پاداش‌ها مهم‌ترین مزیت این پلتفرم است.", "گروه بهداشتی نوین", "مدیر توسعه", 300), - }; - - // ── FAQ data ── - private readonly List _faqs = new() - { - 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); + // ── SettingsJson DTO ── + private class LandingSettings + { + public string? HeroButtonPrimaryText { get; set; } + public string? HeroButtonSecondaryText { get; set; } + public List? TrustBadges { get; set; } + public string? StepsTitle { get; set; } + public List? Steps { get; set; } + public string? FeaturesTitle { get; set; } + public List? Features { get; set; } + public string? StatsTitle { get; set; } + public List? Stats { get; set; } + public string? TestimonialsTitle { get; set; } + public List? Testimonials { get; set; } + public string? FaqTitle { get; set; } + public List? Faqs { get; set; } + public string? CtaTitle { get; set; } + public string? CtaDescription { get; set; } + public string? CtaButtonText { get; set; } + public bool? FeaturedBlogEnabled { get; set; } + } + + private class TrustBadgeItem { public string? IconName { get; set; } public string? Text { get; set; } } + private class StepItem { public string? Title { get; set; } public string? Description { get; set; } } + private class FeatureItem { public string? IconName { get; set; } public string? Title { get; set; } public string? Description { get; set; } } + private class StatSettingItem { public string? Label { get; set; } public double Value { get; set; } public string? Suffix { get; set; } public string? Color { get; set; } } + private class TestimonialSettingItem { public string? Quote { get; set; } public string? Name { get; set; } public string? Role { get; set; } } + private class FaqItem { public string? Question { get; set; } public string? Answer { get; set; } } + public void Dispose() { MainService.OnChangeHandler -= OnStateChanged;