From 230ba41113d25ef196fc60faef49d4062c4549a5 Mon Sep 17 00:00:00 2001 From: masoodafar-web Date: Fri, 14 Nov 2025 13:12:31 +0330 Subject: [PATCH] Add device detection and PDF generation features; refactor AuthDialog and update print utilities --- src/FrontOffice.Main/ConfigureServices.cs | 7 ++ src/FrontOffice.Main/FrontOffice.Main.csproj | 6 +- .../Pages/RegisterWizard.razor | 29 +++-- .../Pages/RegisterWizard.razor.cs | 78 ++++++++++-- src/FrontOffice.Main/Pages/_Host.cshtml | 1 + src/FrontOffice.Main/Program.cs | 16 +++ src/FrontOffice.Main/Shared/AuthDialog.razor | 71 +++++++---- .../Shared/AuthDialog.razor.cs | 2 +- .../Utilities/AuthDialogService.cs | 19 ++- .../Utilities/DeviceDetector.cs | 117 ++++++++++++++++++ .../Utilities/Pdf/HtmlToPdfService.cs | 36 ++++++ .../wwwroot/js/print-utils.js | 69 +++++++++++ 12 files changed, 397 insertions(+), 54 deletions(-) create mode 100644 src/FrontOffice.Main/Utilities/DeviceDetector.cs create mode 100644 src/FrontOffice.Main/Utilities/Pdf/HtmlToPdfService.cs create mode 100644 src/FrontOffice.Main/wwwroot/js/print-utils.js diff --git a/src/FrontOffice.Main/ConfigureServices.cs b/src/FrontOffice.Main/ConfigureServices.cs index 7a67069..13cfe5b 100644 --- a/src/FrontOffice.Main/ConfigureServices.cs +++ b/src/FrontOffice.Main/ConfigureServices.cs @@ -30,9 +30,16 @@ public static class ConfigureServices config.JsonSerializerOptions.WriteIndented = false; }); + // Access HttpContext for User-Agent + services.AddHttpContextAccessor(); + // Register custom services services.AddScoped(); services.AddScoped(); + // Device detection: very light, dependency-free + services.AddScoped(); + // PDF generation + services.AddSingleton(); return services; } diff --git a/src/FrontOffice.Main/FrontOffice.Main.csproj b/src/FrontOffice.Main/FrontOffice.Main.csproj index 0fdef73..4655804 100644 --- a/src/FrontOffice.Main/FrontOffice.Main.csproj +++ b/src/FrontOffice.Main/FrontOffice.Main.csproj @@ -19,10 +19,14 @@ + + + - + + diff --git a/src/FrontOffice.Main/Pages/RegisterWizard.razor b/src/FrontOffice.Main/Pages/RegisterWizard.razor index fdf5cb3..5dfb0bd 100644 --- a/src/FrontOffice.Main/Pages/RegisterWizard.razor +++ b/src/FrontOffice.Main/Pages/RegisterWizard.razor @@ -3,7 +3,7 @@ ثبت‌نام سریع
- + @@ -68,7 +68,7 @@ } - + @* Inline AuthDialog with captcha enabled *@ @@ -110,10 +110,9 @@ - دانلود قرارداد نمونه + دانلود/پرینت قرارداد نمونه - فرمت: فایل متنی - + فرمت: PDF از طریق Print + @if (_isAuthenticated && _activeStep == 1) + { + خروج از حساب + } + else + { + مرحله قبل - + Disabled="_activeStep == 0 || _isSubmitting" + OnClick="@(async () => { await GoBack(); })">مرحله قبل + } + + Disabled="_isSubmitting" + OnClick="@(async () => { await GoNextAsync(); })"> @_nextButtonText diff --git a/src/FrontOffice.Main/Pages/RegisterWizard.razor.cs b/src/FrontOffice.Main/Pages/RegisterWizard.razor.cs index d343f0d..711a9d8 100644 --- a/src/FrontOffice.Main/Pages/RegisterWizard.razor.cs +++ b/src/FrontOffice.Main/Pages/RegisterWizard.razor.cs @@ -4,6 +4,7 @@ using FrontOffice.Main.Shared; using FrontOffice.Main.Utilities; using Google.Protobuf.WellKnownTypes; using Microsoft.AspNetCore.Components; +using Microsoft.JSInterop; using MudBlazor; namespace FrontOffice.Main.Pages; @@ -19,7 +20,12 @@ public partial class RegisterWizard private bool _isSubmitting; private bool _completed; private AuthDialog _authDialog; + private MudStepper _mudStepper; private UpdateUserRequest _updateUserRequest = new(); + private bool _isAuthenticated; + + [Inject] private AuthService AuthService { get; set; } = default!; + [Inject] private IJSRuntime Js { get; set; } = default!; private string _nextButtonText => _activeStep switch { @@ -28,21 +34,56 @@ public partial class RegisterWizard _ => _isSubmitting ? "در حال ارسال..." : "ثبت نهایی" }; - protected override void OnInitialized() + + protected override async Task OnAfterRenderAsync(bool firstRender) { - base.OnInitialized(); + _isAuthenticated = await AuthService.IsAuthenticatedAsync(); + if (_isAuthenticated && _activeStep == 0) + { + await _mudStepper.NextStepAsync(); + _activeStep = 1; + await InvokeAsync(StateHasChanged); + } + else if (_isAuthenticated && _activeStep == 1) + { + try + { + var existUser = await UserContract.GetUserAsync(new Empty()); + if (existUser != null && !string.IsNullOrEmpty(existUser.FirstName) && string.IsNullOrWhiteSpace(_model.FirstName)) + { + _model.FirstName = existUser.FirstName; + } + + if (existUser != null && !string.IsNullOrEmpty(existUser.LastName) && string.IsNullOrWhiteSpace(_model.LastName)) + { + _model.LastName = existUser.LastName; + } + + if (existUser != null && !string.IsNullOrEmpty(existUser.NationalCode) && string.IsNullOrWhiteSpace(_model.NationalCode)) + { + _model.NationalCode = existUser.NationalCode; + } + } + catch (Exception e) + { + Console.WriteLine(e); + } + await InvokeAsync(StateHasChanged); + } + + await base.OnAfterRenderAsync(firstRender); } - private async Task GoBack(MudStepper mudStepper) + private async Task GoBack() { - if (_activeStep == 0 || _isSubmitting) + if (_activeStep == 0 || _isSubmitting || (_isAuthenticated && _activeStep == 1)) return; _activeStep--; - await mudStepper.PreviousStepAsync(); + await _mudStepper.PreviousStepAsync(); } - private async Task GoNextAsync(MudStepper mudStepper) + private async Task GoNextAsync() { if (_isSubmitting) return; @@ -61,7 +102,6 @@ public partial class RegisterWizard if (!verifyOtp) return; - _activeStep = 1; } @@ -76,6 +116,7 @@ public partial class RegisterWizard return; _activeStep = 2; + await _mudStepper.NextStepAsync(); break; case 2: if (!await ValidateStepAsync(_stepThreeForm)) @@ -83,8 +124,6 @@ public partial class RegisterWizard await SubmitAsync(); break; } - - await mudStepper.NextStepAsync(); } private async Task ValidateStepAsync(MudForm? form) @@ -111,16 +150,29 @@ public partial class RegisterWizard } } - private void DownloadContract() + private async void DownloadContract() { - Navigation.NavigateTo("docs/sample-contract.txt", true); + // Example dynamic HTML (could be constructed based on user data) + var html = $"

قرارداد اولیه کاربر

نام: {_model.FirstName ?? "-"} {_model.LastName ?? "-"}

کد ملی: {_model.NationalCode ?? "-"}

این یک نسخه نمونه است.

"; + + // Option A: trigger browser print dialog for PDF (client-side) + try + { + await Js.InvokeVoidAsync("printUtils.printHtml", html, new { title = "قرارداد نمونه" }); + } + catch + { + // Fallback to server-side generation endpoint if JS fails + var encoded = Uri.EscapeDataString(html); + Navigation.NavigateTo($"contract/generate?html={encoded}&fileName=sample-contract", true); + } } private void OnPhoneVerified() { // Move to next step after phone verification success // _activeStep = 1; - // StateHasChanged(); + //StateHasChanged(); } private async Task SavePersonalInfo() @@ -145,7 +197,7 @@ public partial class RegisterWizard Console.WriteLine(_updateUserRequest.FirstName); Console.WriteLine(_updateUserRequest.LastName); Console.WriteLine(_updateUserRequest.NationalCode); - + await UserContract.UpdateUserAsync(request: _updateUserRequest); Snackbar.Add("اطلاعات شخصی با موفقیت ذخیره شد.", Severity.Success); return true; diff --git a/src/FrontOffice.Main/Pages/_Host.cshtml b/src/FrontOffice.Main/Pages/_Host.cshtml index 561a418..eb3599d 100644 --- a/src/FrontOffice.Main/Pages/_Host.cshtml +++ b/src/FrontOffice.Main/Pages/_Host.cshtml @@ -35,6 +35,7 @@ +