This commit is contained in:
masoodafar-web
2025-11-09 20:24:09 +03:30
parent 0b253074a9
commit 99bfc1e619
9 changed files with 390 additions and 14 deletions

1
src/.vscode/settings.json vendored Normal file
View File

@@ -0,0 +1 @@
{}

View File

@@ -1,9 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<UserSecretsId>6dab807c-c6d8-4711-bf64-11c69e8d39f4</UserSecretsId>
</PropertyGroup>
<ItemGroup>

View File

@@ -17,17 +17,18 @@
ثبت‌نام آسان، تجربهٔ سریع و شفاف. همین امروز حساب بساز و با دعوت دوستانت، امتیاز و پاداش دریافت کن.
</MudText>
<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">شروع کن</MudButton>
</MudStack>
<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"
@@ -350,4 +351,4 @@
</MudContainer>
</section>
</MudStack>
</MudStack>

View File

@@ -76,6 +76,10 @@ public partial class Index
{
Navigation.NavigateTo($"{RouteConstants.Package.Detail}{packageId}");
}
private void NavigateToRegistrationWizard()
{
Navigation.NavigateTo(RouteConstants.Registration.Wizard);
}
private record Pack(long Id, string Title, string Body, string Image, long Price);
private record Plan(string Name, string Price, bool Highlight, IEnumerable<string> Features);

View File

@@ -0,0 +1,185 @@
@attribute [Route(RouteConstants.Registration.Wizard)]
<PageTitle>ثبت‌نام سریع</PageTitle>
<section class="py-12 wizard-section">
<MudContainer MaxWidth="MaxWidth.Large">
<MudGrid Spacing="4" Justify="Justify.Center">
<MudItem xs="12" md="5">
<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">
فقط در چند دقیقه حساب خود را فعال کنید
</MudText>
<MudText Typo="Typo.body1" Class="mud-text-secondary">
اطلاعات اولیه را وارد کنید، مشخصات هویتی را تکمیل کنید و بعد از مطالعه قوانین و دانلود قرارداد، درخواست خود را ارسال کنید.
</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" />
<MudText Typo="Typo.subtitle1">مزایای ثبت‌نام آنلاین</MudText>
</MudStack>
<MudText Typo="Typo.body2" Class="mud-text-secondary">
• تایید سریع و آنلاین شماره موبایل<br />
• تکمیل اطلاعات هویتی بدون مراجعه حضوری<br />
• دریافت نسخه‌ی دیجیتال قرارداد برای بررسی دقیق
</MudText>
</MudStack>
</MudPaper>
</MudItem>
<MudItem xs="12" md="7">
<MudPaper Elevation="3" Class="pa-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" />
<MudText Typo="Typo.h4">درخواست شما ثبت شد</MudText>
<MudText Typo="Typo.body1" Class="mud-text-secondary">
تیم ما پس از بررسی اطلاعات با شما تماس خواهد گرفت. می‌توانید از طریق داشبورد وضعیت ثبت‌نام را دنبال کنید.
</MudText>
<MudStack Row="true" Spacing="2" Justify="Justify.Center">
<MudButton Variant="Variant.Filled"
Color="Color.Primary"
OnClick="@(() => Navigation.NavigateTo(RouteConstants.Main.MainPage))">بازگشت به صفحه اصلی</MudButton>
<MudButton Variant="Variant.Outlined"
Color="Color.Primary"
OnClick="@(() => Navigation.NavigateTo(RouteConstants.Profile.Index))">مشاهده پروفایل</MudButton>
</MudStack>
</MudStack>
}
else
{
<MudStack Spacing="3">
<MudStack Row="true" Justify="Justify.SpaceBetween" AlignItems="AlignItems.Center">
<MudText Typo="Typo.h4">ویزارد ثبت‌نام</MudText>
<MudChip Color="Color.Info" Variant="Variant.Outlined" Size="Size.Small">۳ مرحله</MudChip>
</MudStack>
@if (_isSubmitting)
{
<MudProgressLinear Color="Color.Primary" Indeterminate="true" />
}
<MudStepper @bind-ActiveIndex="_activeStep"
Elevation="0"
DisableClick="true"
Class="mb-4">
<MudStep Label="تایید موبایل" Icon="@Icons.Material.Filled.Smartphone">
<MudForm @ref="_stepOneForm">
<MudTextField Label="شماره موبایل"
Placeholder="مثال: 09121234567"
InputType="InputType.Tel"
Immediate="true"
MaxLength="11"
Variant="Variant.Outlined"
@bind-Value="_model.MobileNumber"
For="@(() => _model.MobileNumber)"
Adornment="Adornment.Start"
AdornmentIcon="@Icons.Material.Outlined.Phone" />
<MudStack Row="true" AlignItems="AlignItems.Center" Spacing="2" Class="mt-4">
<MudPaper Elevation="1" Class="captcha-box d-flex align-center justify-center">
<MudText Typo="Typo.h5">@_captchaCode</MudText>
</MudPaper>
<MudButton Variant="Variant.Text"
Color="Color.Primary"
StartIcon="@Icons.Material.Filled.Refresh"
Disabled="_isSubmitting"
OnClick="GenerateCaptcha">تازه‌سازی کد</MudButton>
</MudStack>
<MudTextField Label="کد کپچا"
Placeholder="کد نمایش داده شده"
Immediate="true"
Variant="Variant.Outlined"
@bind-Value="_model.CaptchaInput"
For="@(() => _model.CaptchaInput)" />
</MudForm>
</MudStep>
<MudStep Label="اطلاعات هویتی" Icon="@Icons.Material.Filled.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" />
</MudForm>
</MudStep>
<MudStep Label="قوانین و قرارداد" Icon="@Icons.Material.Filled.Rule">
<MudForm @ref="_stepThreeForm">
<MudAlert Variant="Variant.Outlined"
Severity="Severity.Info"
Class="mb-3">
لطفاً قوانین و شرایط همکاری را با دقت مطالعه کنید و در صورت موافقت، تیک تایید را فعال نمایید. همچنین می‌توانید نسخه‌ی قرارداد را دانلود و ذخیره کنید.
</MudAlert>
<MudPaper Elevation="0" Class="terms-box pa-4 mb-3">
<MudText Typo="Typo.subtitle2" Class="mb-2">بخشی از قوانین:</MudText>
<MudList Dense="true">
<MudListItem>استفاده از اطلاعات کاربری صرفاً برای ثبت نام و احراز هویت مجاز است.</MudListItem>
<MudListItem>تمامی فعالیت‌ها مطابق قوانین جمهوری اسلامی ایران انجام می‌شود.</MudListItem>
<MudListItem>مسئولیت صحت اطلاعات وارد شده بر عهده متقاضی است.</MudListItem>
</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">فرمت: فایل متنی</MudText>
</MudStack>
<MudCheckBox @bind-Checked="_model.AcceptTerms"
Color="Color.Success"
For="@(() => _model.AcceptTerms)"
Label="قوانین و مقررات را مطالعه کرده‌ام و می‌پذیرم" />
</MudForm>
</MudStep>
</MudStepper>
<MudDivider Class="my-2" />
<MudStack Row="true" Justify="Justify.SpaceBetween" AlignItems="AlignItems.Center">
<MudButton Variant="Variant.Text"
Color="Color.Secondary"
Disabled="_activeStep == 0 || _isSubmitting"
OnClick="GoBack">مرحله قبل</MudButton>
<MudSpacer />
<MudButton Variant="Variant.Filled"
Color="Color.Primary"
Disabled="_isSubmitting"
OnClick="GoNextAsync">
@_nextButtonText
</MudButton>
</MudStack>
</MudStack>
}
</MudPaper>
</MudItem>
</MudGrid>
</MudContainer>
</section>

View File

@@ -0,0 +1,129 @@
using System.ComponentModel.DataAnnotations;
using Microsoft.AspNetCore.Components;
using MudBlazor;
namespace FrontOffice.Main.Pages;
public partial class RegisterWizard
{
private readonly RegistrationModel _model = new();
private MudForm? _stepOneForm;
private MudForm? _stepTwoForm;
private MudForm? _stepThreeForm;
private int _activeStep;
private bool _isSubmitting;
private bool _completed;
private string _captchaCode = string.Empty;
private string _nextButtonText => _activeStep switch
{
0 => "ادامه",
1 => "ادامه",
_ => _isSubmitting ? "در حال ارسال..." : "ثبت نهایی"
};
protected override void OnInitialized()
{
base.OnInitialized();
GenerateCaptcha();
}
private void GenerateCaptcha()
{
var random = Guid.NewGuid().ToString("N")[..6].ToUpperInvariant();
_captchaCode = random;
_model.CaptchaInput = string.Empty;
}
private void GoBack()
{
if (_activeStep == 0 || _isSubmitting)
return;
_activeStep--;
}
private async Task GoNextAsync()
{
if (_isSubmitting)
return;
switch (_activeStep)
{
case 0:
if (!await ValidateStepAsync(_stepOneForm))
return;
if (!string.Equals(_model.CaptchaInput?.Trim(), _captchaCode, StringComparison.OrdinalIgnoreCase))
{
Snackbar.Add("کد کپچا صحیح نیست.", Severity.Warning);
return;
}
_activeStep = 1;
break;
case 1:
if (!await ValidateStepAsync(_stepTwoForm))
return;
_activeStep = 2;
break;
case 2:
if (!await ValidateStepAsync(_stepThreeForm))
return;
await SubmitAsync();
break;
}
}
private async Task<bool> ValidateStepAsync(MudForm? form)
{
if (form is null)
return true;
await form.Validate();
return form.IsValid;
}
private async Task SubmitAsync()
{
_isSubmitting = true;
try
{
await Task.Delay(800);
_completed = true;
Snackbar.Add("ثبت‌نام اولیه با موفقیت انجام شد.", Severity.Success);
}
finally
{
_isSubmitting = false;
}
}
private void DownloadContract()
{
Navigation.NavigateTo("docs/sample-contract.txt", true);
}
private sealed class RegistrationModel
{
[Required(ErrorMessage = "شماره موبایل الزامی است.")]
[RegularExpression(@"^09\d{9}$", ErrorMessage = "شماره موبایل معتبر نیست.")]
public string? MobileNumber { get; set; }
[Required(ErrorMessage = "کد کپچا را وارد کنید.")]
public string? CaptchaInput { get; set; }
[Required(ErrorMessage = "نام الزامی است.")]
[StringLength(50, ErrorMessage = "حداکثر ۵۰ کاراکتر")]
public string? FirstName { get; set; }
[Required(ErrorMessage = "نام خانوادگی الزامی است.")]
[StringLength(70, ErrorMessage = "حداکثر ۷۰ کاراکتر")]
public string? LastName { get; set; }
[Required(ErrorMessage = "کد ملی الزامی است.")]
[RegularExpression(@"^\d{10}$", ErrorMessage = "کدملی باید ۱۰ رقم باشد.")]
public string? NationalCode { get; set; }
[Range(typeof(bool), "true", "true", ErrorMessage = "برای ادامه باید قوانین را تایید کنید.")]
public bool AcceptTerms { get; set; }
}
}

View File

@@ -7,6 +7,11 @@ public static class RouteConstants
public const string MainPage = "/";
}
public static class Registration
{
public const string Wizard = "/register";
}
public static class Profile
{
public const string Index = "/profile";

View File

@@ -195,4 +195,42 @@ html, body {
background: linear-gradient(135deg, var(--mud-palette-dark-surface) 0%, var(--mud-palette-dark-surface-variant) 100%);
}
/*#endregion*/
/*#region Registration Wizard*/
.wizard-section {
background: linear-gradient(180deg, #f9f7ff 0%, #ffffff 40%, #f0f8ff 100%);
}
.wizard-card {
border-radius: 18px;
border: 1px solid var(--mud-palette-divider);
}
.gradient-border {
border-radius: 16px;
border: 1px solid transparent;
background: linear-gradient(var(--mud-palette-surface), var(--mud-palette-surface)) padding-box,
linear-gradient(135deg, rgba(123, 97, 255, 0.4), rgba(255, 140, 189, 0.4)) border-box;
}
.captcha-box {
min-width: 120px;
min-height: 56px;
border-radius: 12px;
letter-spacing: 4px;
font-weight: 600;
background: linear-gradient(135deg, rgba(123, 97, 255, 0.12), rgba(255, 140, 189, 0.12));
}
.terms-box {
border-radius: 12px;
border: 1px dashed var(--mud-palette-divider);
background: rgba(255, 255, 255, 0.7);
}
@media (max-width: 768px) {
.wizard-card {
padding: 1.5rem !important;
}
}
/*#endregion*/
/*#endregion*/

View File

@@ -0,0 +1,12 @@
نمونه قرارداد همکاری
---------------------
این فایل صرفاً نمونه‌ای برای نمایش قابلیت دانلود قرارداد در ویزارد ثبت‌نام است.
بند ۱- اطلاعات شخص حقیقی: شامل نام، نام خانوادگی، کد ملی و شماره تماس متقاضی است.
بند ۲- تعهدات طرفین: متقاضی متعهد می‌شود قوانین حاکم بر پلتفرم را رعایت نموده و اطلاعات صحیح ارائه نماید.
بند ۳- محرمانگی: تبادل هرگونه داده تجاری یا شخصی مشمول اصول محرمانگی خواهد بود.
بند ۴- فسخ همکاری: پلتفرم در صورت نقض قوانین می‌تواند همکاری را یک‌طرفه فسخ نماید.
تاریخ: ..............
امضا متقاضی: ..............