feat: add club membership contract dialog and city autocomplete
This commit is contained in:
@@ -18,6 +18,7 @@ using FrontOffice.BFF.ClubMembership.Protobuf.Protos.ClubMembership;
|
|||||||
using FrontOffice.BFF.Commission.Protobuf.Protos.Commission;
|
using FrontOffice.BFF.Commission.Protobuf.Protos.Commission;
|
||||||
using FrontOffice.BFF.NetworkMembership.Protobuf.Protos.NetworkMembership;
|
using FrontOffice.BFF.NetworkMembership.Protobuf.Protos.NetworkMembership;
|
||||||
using FrontOffice.BFF.DiscountShop.Protobuf.Protos.DiscountShop;
|
using FrontOffice.BFF.DiscountShop.Protobuf.Protos.DiscountShop;
|
||||||
|
using FrontOffice.BFF.City.Protobuf;
|
||||||
using FrontOffice.Main.Utilities;
|
using FrontOffice.Main.Utilities;
|
||||||
|
|
||||||
namespace Microsoft.Extensions.DependencyInjection;
|
namespace Microsoft.Extensions.DependencyInjection;
|
||||||
@@ -101,6 +102,7 @@ public static class ConfigureServices
|
|||||||
services.AddScoped(CreateAuthenticatedClient<CommissionContract.CommissionContractClient>);
|
services.AddScoped(CreateAuthenticatedClient<CommissionContract.CommissionContractClient>);
|
||||||
services.AddScoped(CreateAuthenticatedClient<NetworkMembershipContract.NetworkMembershipContractClient>);
|
services.AddScoped(CreateAuthenticatedClient<NetworkMembershipContract.NetworkMembershipContractClient>);
|
||||||
services.AddScoped(CreateAuthenticatedClient<DiscountShopContract.DiscountShopContractClient>);
|
services.AddScoped(CreateAuthenticatedClient<DiscountShopContract.DiscountShopContractClient>);
|
||||||
|
services.AddScoped(CreateAuthenticatedClient<CityContract.CityContractClient>);
|
||||||
|
|
||||||
return services;
|
return services;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="DateTimeConverterCL" Version="1.0.0" />
|
<PackageReference Include="DateTimeConverterCL" Version="1.0.0" />
|
||||||
<PackageReference Include="Foursat.FrontOffice.BFF.ClubMembership.Protobuf" Version="0.0.3" />
|
<!-- <PackageReference Include="Foursat.FrontOffice.BFF.ClubMembership.Protobuf" Version="0.0.3" /> -->
|
||||||
<PackageReference Include="Foursat.FrontOffice.BFF.Commission.Protobuf" Version="0.0.2" />
|
<PackageReference Include="Foursat.FrontOffice.BFF.Commission.Protobuf" Version="0.0.2" />
|
||||||
<PackageReference Include="Foursat.FrontOffice.BFF.DiscountShop.Protobuf" Version="0.0.2" />
|
<PackageReference Include="Foursat.FrontOffice.BFF.DiscountShop.Protobuf" Version="0.0.2" />
|
||||||
<PackageReference Include="Foursat.FrontOffice.BFF.NetworkMembership.Protobuf" Version="0.0.2" />
|
<PackageReference Include="Foursat.FrontOffice.BFF.NetworkMembership.Protobuf" Version="0.0.2" />
|
||||||
@@ -37,6 +37,8 @@
|
|||||||
<!-- Local Proto Project Reference for development -->
|
<!-- Local Proto Project Reference for development -->
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\..\..\FrontOffice.BFF\src\Protobufs\FrontOffice.BFF.Package.Protobuf\FrontOffice.BFF.Package.Protobuf.csproj" />
|
<ProjectReference Include="..\..\..\FrontOffice.BFF\src\Protobufs\FrontOffice.BFF.Package.Protobuf\FrontOffice.BFF.Package.Protobuf.csproj" />
|
||||||
|
<ProjectReference Include="..\..\..\FrontOffice.BFF\src\Protobufs\FrontOffice.BFF.ClubMembership.Protobuf\FrontOffice.BFF.ClubMembership.Protobuf.csproj" />
|
||||||
|
<ProjectReference Include="..\..\..\FrontOffice.BFF\src\Protobufs\FrontOffice.BFF.City.Protobuf\FrontOffice.BFF.City.Protobuf.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<!-- New Proto Projects (local references until NuGet publish) -->
|
<!-- New Proto Projects (local references until NuGet publish) -->
|
||||||
|
|||||||
@@ -29,13 +29,34 @@
|
|||||||
Required="true"
|
Required="true"
|
||||||
RequiredError="کد پستی الزامی است." />
|
RequiredError="کد پستی الزامی است." />
|
||||||
|
|
||||||
<MudTextField @bind-Value="_request.CityId"
|
<MudAutocomplete T="CityProto.GetAllCitiesByFilterResponseModel"
|
||||||
For="@(() => _request.CityId)"
|
@bind-Value="_selectedCity"
|
||||||
Label="شناسه شهر"
|
Label="شهر"
|
||||||
Variant="Variant.Outlined"
|
Variant="Variant.Outlined"
|
||||||
InputType="InputType.Number"
|
SearchFunc="SearchCities"
|
||||||
Required="true"
|
ToStringFunc="@(city => city != null ? $"{city.Native} ({city.StateName})" : string.Empty)"
|
||||||
RequiredError="شهر الزامی است." />
|
Required="true"
|
||||||
|
RequiredError="شهر الزامی است."
|
||||||
|
Clearable="true"
|
||||||
|
ResetValueOnEmptyText="true"
|
||||||
|
CoerceText="false"
|
||||||
|
CoerceValue="false"
|
||||||
|
Dense="true"
|
||||||
|
DebounceInterval="300"
|
||||||
|
MaxItems="20"
|
||||||
|
MinCharacters="2"
|
||||||
|
ProgressIndicatorColor="Color.Primary">
|
||||||
|
<ItemTemplate Context="city">
|
||||||
|
<MudStack Row="true" Spacing="2" AlignItems="AlignItems.Center">
|
||||||
|
<MudIcon Icon="@Icons.Material.Filled.LocationCity" Size="Size.Small" />
|
||||||
|
<MudText>@city.Native</MudText>
|
||||||
|
<MudText Typo="Typo.caption" Class="mud-text-secondary">(@city.StateName)</MudText>
|
||||||
|
</MudStack>
|
||||||
|
</ItemTemplate>
|
||||||
|
<NoItemsTemplate>
|
||||||
|
<MudText Typo="Typo.body2" Class="mud-text-secondary pa-2">شهری یافت نشد</MudText>
|
||||||
|
</NoItemsTemplate>
|
||||||
|
</MudAutocomplete>
|
||||||
</MudStack>
|
</MudStack>
|
||||||
</MudForm>
|
</MudForm>
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ using FrontOffice.BFF.UserAddress.Protobuf.Validator;
|
|||||||
using Microsoft.AspNetCore.Components;
|
using Microsoft.AspNetCore.Components;
|
||||||
using MudBlazor;
|
using MudBlazor;
|
||||||
using Severity = MudBlazor.Severity;
|
using Severity = MudBlazor.Severity;
|
||||||
|
using CityProto = FrontOffice.BFF.City.Protobuf;
|
||||||
|
|
||||||
namespace FrontOffice.Main.Pages.Profile.Components;
|
namespace FrontOffice.Main.Pages.Profile.Components;
|
||||||
|
|
||||||
@@ -10,19 +11,48 @@ public partial class AddAddressDialog : ComponentBase
|
|||||||
{
|
{
|
||||||
[CascadingParameter] private IDialogReference MudDialog { get; set; } = default!;
|
[CascadingParameter] private IDialogReference MudDialog { get; set; } = default!;
|
||||||
[Inject] private UserAddressContract.UserAddressContractClient UserAddressContract { get; set; } = default!;
|
[Inject] private UserAddressContract.UserAddressContractClient UserAddressContract { get; set; } = default!;
|
||||||
|
[Inject] private CityProto.CityContract.CityContractClient CityContract { get; set; } = default!;
|
||||||
|
|
||||||
private MudForm? _form;
|
private MudForm? _form;
|
||||||
private readonly CreateNewUserAddressRequestValidator _validator = new();
|
private readonly CreateNewUserAddressRequestValidator _validator = new();
|
||||||
private bool _isSaving;
|
private bool _isSaving;
|
||||||
private CreateNewUserAddressRequest _request = new();
|
private CreateNewUserAddressRequest _request = new();
|
||||||
|
private CityProto.GetAllCitiesByFilterResponseModel? _selectedCity;
|
||||||
|
|
||||||
|
private async Task<IEnumerable<CityProto.GetAllCitiesByFilterResponseModel>> SearchCities(string value, CancellationToken ct)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(value) || value.Length < 2)
|
||||||
|
return Enumerable.Empty<CityProto.GetAllCitiesByFilterResponseModel>();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var response = await CityContract.GetAllCitiesByFilterAsync(new CityProto.GetAllCitiesByFilterRequest
|
||||||
|
{
|
||||||
|
PaginationState = new CityProto.PaginationState { PageNumber = 1, PageSize = 20 },
|
||||||
|
Filter = new CityProto.GetAllCitiesByFilterFilter { Native = value }
|
||||||
|
}, cancellationToken: ct);
|
||||||
|
|
||||||
|
return response?.Models?.ToList() ?? new List<CityProto.GetAllCitiesByFilterResponseModel>();
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return Enumerable.Empty<CityProto.GetAllCitiesByFilterResponseModel>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private async Task SaveAddress()
|
private async Task SaveAddress()
|
||||||
{
|
{
|
||||||
if (_form == null) return;
|
if (_form == null) return;
|
||||||
|
|
||||||
await _form.Validate();
|
await _form.Validate();
|
||||||
if (!_form.IsValid) return;
|
if (!_form.IsValid || _selectedCity == null)
|
||||||
|
{
|
||||||
|
if (_selectedCity == null)
|
||||||
|
Snackbar.Add("لطفاً شهر را انتخاب کنید.", Severity.Warning);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_request.CityId = _selectedCity.Id;
|
||||||
_isSaving = true;
|
_isSaving = true;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -28,13 +28,34 @@
|
|||||||
Required="true"
|
Required="true"
|
||||||
RequiredError="کد پستی الزامی است." />
|
RequiredError="کد پستی الزامی است." />
|
||||||
|
|
||||||
<MudTextField @bind-Value="_request.CityId"
|
<MudAutocomplete T="CityProto.GetAllCitiesByFilterResponseModel"
|
||||||
For="@(() => _request.CityId)"
|
@bind-Value="_selectedCity"
|
||||||
Label="شناسه شهر"
|
Label="شهر"
|
||||||
Variant="Variant.Outlined"
|
Variant="Variant.Outlined"
|
||||||
InputType="InputType.Number"
|
SearchFunc="SearchCities"
|
||||||
Required="true"
|
ToStringFunc="@(city => city != null ? $"{city.Native} ({city.StateName})" : string.Empty)"
|
||||||
RequiredError="شهر الزامی است." />
|
Required="true"
|
||||||
|
RequiredError="شهر الزامی است."
|
||||||
|
Clearable="true"
|
||||||
|
ResetValueOnEmptyText="true"
|
||||||
|
CoerceText="false"
|
||||||
|
CoerceValue="false"
|
||||||
|
Dense="true"
|
||||||
|
DebounceInterval="300"
|
||||||
|
MaxItems="20"
|
||||||
|
MinCharacters="2"
|
||||||
|
ProgressIndicatorColor="Color.Primary">
|
||||||
|
<ItemTemplate Context="city">
|
||||||
|
<MudStack Row="true" Spacing="2" AlignItems="AlignItems.Center">
|
||||||
|
<MudIcon Icon="@Icons.Material.Filled.LocationCity" Size="Size.Small" />
|
||||||
|
<MudText>@city.Native</MudText>
|
||||||
|
<MudText Typo="Typo.caption" Class="mud-text-secondary">(@city.StateName)</MudText>
|
||||||
|
</MudStack>
|
||||||
|
</ItemTemplate>
|
||||||
|
<NoItemsTemplate>
|
||||||
|
<MudText Typo="Typo.body2" Class="mud-text-secondary pa-2">شهری یافت نشد</MudText>
|
||||||
|
</NoItemsTemplate>
|
||||||
|
</MudAutocomplete>
|
||||||
</MudStack>
|
</MudStack>
|
||||||
</MudForm>
|
</MudForm>
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
|
|||||||
@@ -4,14 +4,15 @@ using Mapster;
|
|||||||
using Microsoft.AspNetCore.Components;
|
using Microsoft.AspNetCore.Components;
|
||||||
using MudBlazor;
|
using MudBlazor;
|
||||||
using Severity = MudBlazor.Severity;
|
using Severity = MudBlazor.Severity;
|
||||||
|
using CityProto = FrontOffice.BFF.City.Protobuf;
|
||||||
|
|
||||||
namespace FrontOffice.Main.Pages.Profile.Components;
|
namespace FrontOffice.Main.Pages.Profile.Components;
|
||||||
|
|
||||||
public partial class EditAddressDialog : ComponentBase
|
public partial class EditAddressDialog : ComponentBase
|
||||||
{
|
{
|
||||||
[CascadingParameter] private IDialogReference MudDialog { get; set; } = default!; // updated type
|
[CascadingParameter] private IDialogReference MudDialog { get; set; } = default!;
|
||||||
[Inject] private UserAddressContract.UserAddressContractClient UserAddressContract { get; set; } = default!;
|
[Inject] private UserAddressContract.UserAddressContractClient UserAddressContract { get; set; } = default!;
|
||||||
// removed duplicate Snackbar injection; provided by Razor partial via _Imports
|
[Inject] private CityProto.CityContract.CityContractClient CityContract { get; set; } = default!;
|
||||||
|
|
||||||
[Parameter] public GetAllUserAddressByFilterResponseModel? Model { get; set; }
|
[Parameter] public GetAllUserAddressByFilterResponseModel? Model { get; set; }
|
||||||
|
|
||||||
@@ -19,12 +20,60 @@ public partial class EditAddressDialog : ComponentBase
|
|||||||
private readonly UpdateUserAddressRequestValidator _validator = new();
|
private readonly UpdateUserAddressRequestValidator _validator = new();
|
||||||
private bool _isSaving;
|
private bool _isSaving;
|
||||||
private UpdateUserAddressRequest _request = new();
|
private UpdateUserAddressRequest _request = new();
|
||||||
|
private CityProto.GetAllCitiesByFilterResponseModel? _selectedCity;
|
||||||
|
|
||||||
protected override void OnInitialized()
|
protected override async Task OnInitializedAsync()
|
||||||
{
|
{
|
||||||
base.OnInitialized();
|
await base.OnInitializedAsync();
|
||||||
if (Model != null)
|
if (Model != null)
|
||||||
|
{
|
||||||
_request = Model.Adapt<UpdateUserAddressRequest>();
|
_request = Model.Adapt<UpdateUserAddressRequest>();
|
||||||
|
|
||||||
|
// Load selected city if CityId exists
|
||||||
|
if (Model.CityId > 0)
|
||||||
|
{
|
||||||
|
await LoadCurrentCity(Model.CityId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task LoadCurrentCity(long cityId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var response = await CityContract.GetAllCitiesByFilterAsync(new CityProto.GetAllCitiesByFilterRequest
|
||||||
|
{
|
||||||
|
PaginationState = new CityProto.PaginationState { PageNumber = 1, PageSize = 1 },
|
||||||
|
Filter = new CityProto.GetAllCitiesByFilterFilter { Id = cityId }
|
||||||
|
});
|
||||||
|
|
||||||
|
_selectedCity = response?.Models?.FirstOrDefault();
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
// Ignore error loading city
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<IEnumerable<CityProto.GetAllCitiesByFilterResponseModel>> SearchCities(string value, CancellationToken ct)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(value) || value.Length < 2)
|
||||||
|
return Enumerable.Empty<CityProto.GetAllCitiesByFilterResponseModel>();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var response = await CityContract.GetAllCitiesByFilterAsync(new CityProto.GetAllCitiesByFilterRequest
|
||||||
|
{
|
||||||
|
PaginationState = new CityProto.PaginationState { PageNumber = 1, PageSize = 20 },
|
||||||
|
Filter = new CityProto.GetAllCitiesByFilterFilter { Native = value }
|
||||||
|
}, cancellationToken: ct);
|
||||||
|
|
||||||
|
return response?.Models?.ToList() ?? new List<CityProto.GetAllCitiesByFilterResponseModel>();
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return Enumerable.Empty<CityProto.GetAllCitiesByFilterResponseModel>();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task SaveAddress()
|
private async Task SaveAddress()
|
||||||
@@ -32,8 +81,14 @@ public partial class EditAddressDialog : ComponentBase
|
|||||||
if (_form == null) return;
|
if (_form == null) return;
|
||||||
|
|
||||||
await _form.Validate();
|
await _form.Validate();
|
||||||
if (!_form.IsValid) return;
|
if (!_form.IsValid || _selectedCity == null)
|
||||||
|
{
|
||||||
|
if (_selectedCity == null)
|
||||||
|
Snackbar.Add("لطفاً شهر را انتخاب کنید.", Severity.Warning);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_request.CityId = _selectedCity.Id;
|
||||||
_isSaving = true;
|
_isSaving = true;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -60,6 +60,9 @@ public partial class Index
|
|||||||
await LoadUserProfile();
|
await LoadUserProfile();
|
||||||
await LoadAddresses();
|
await LoadAddresses();
|
||||||
await LoadWallet();
|
await LoadWallet();
|
||||||
|
|
||||||
|
// نمایش Modal قرارداد باشگاه اگر پکیج خریده ولی باشگاه فعال نشده
|
||||||
|
await CheckAndShowClubContractModal();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -79,6 +82,39 @@ public partial class Index
|
|||||||
StateHasChanged();
|
StateHasChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// بررسی و نمایش Modal قرارداد باشگاه مشتریان
|
||||||
|
/// اگر کاربر پکیج خریده ولی هنوز قرارداد باشگاه را امضا نکرده
|
||||||
|
/// </summary>
|
||||||
|
private async Task CheckAndShowClubContractModal()
|
||||||
|
{
|
||||||
|
// اگر پکیج خریده ولی باشگاه فعال نیست = باید قرارداد امضا کند
|
||||||
|
if (_hasPurchasedPackage && !_isClubMemberActive)
|
||||||
|
{
|
||||||
|
var options = new DialogOptions
|
||||||
|
{
|
||||||
|
BackdropClick = false, // غیرقابل بسته شدن با کلیک بیرون
|
||||||
|
CloseOnEscapeKey = false, // غیرقابل بسته شدن با Escape
|
||||||
|
CloseButton = false, // بدون دکمه بستن
|
||||||
|
MaxWidth = MaxWidth.Medium,
|
||||||
|
FullWidth = true
|
||||||
|
};
|
||||||
|
|
||||||
|
var dialog = await DialogService.ShowAsync<Shared.ClubMembershipContractDialog>(
|
||||||
|
"قرارداد باشگاه مشتریان",
|
||||||
|
options);
|
||||||
|
|
||||||
|
var result = await dialog.Result;
|
||||||
|
|
||||||
|
// اگر موفق بود، صفحه را refresh کنیم
|
||||||
|
if (!result.Canceled)
|
||||||
|
{
|
||||||
|
await LoadUserAuthInfo();
|
||||||
|
StateHasChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private string _walletCredit = "-";
|
private string _walletCredit = "-";
|
||||||
private string _walletDiscount = "-";
|
private string _walletDiscount = "-";
|
||||||
private string _walletNetwork = "-";
|
private string _walletNetwork = "-";
|
||||||
|
|||||||
@@ -0,0 +1,271 @@
|
|||||||
|
@using FrontOffice.BFF.ClubMembership.Protobuf.Protos.ClubMembership
|
||||||
|
@using Blazored.LocalStorage
|
||||||
|
@using FrontOffice.Main.Utilities
|
||||||
|
@using MudBlazor
|
||||||
|
@inject ClubMembershipContract.ClubMembershipContractClient ClubMembershipClient
|
||||||
|
@inject ILocalStorageService LocalStorage
|
||||||
|
@inject AuthService AuthService
|
||||||
|
@inject ISnackbar Snackbar
|
||||||
|
@inject NavigationManager Navigation
|
||||||
|
|
||||||
|
<MudDialog DisableSidePadding="true">
|
||||||
|
<DialogContent>
|
||||||
|
<MudContainer Style="max-height: 80vh; overflow-y: auto;" Class="pa-4">
|
||||||
|
@if (_step == ContractStep.ReadContract)
|
||||||
|
{
|
||||||
|
<MudText Typo="Typo.h5" Class="mb-4" Align="Align.Center">
|
||||||
|
<MudIcon Icon="@Icons.Material.Filled.Article" Class="ml-2" />
|
||||||
|
قرارداد باشگاه مشتریان
|
||||||
|
</MudText>
|
||||||
|
|
||||||
|
<MudAlert Severity="Severity.Info" Class="mb-4">
|
||||||
|
لطفاً قرارداد باشگاه مشتریان را به دقت مطالعه کنید و در صورت موافقت تایید نمایید.
|
||||||
|
</MudAlert>
|
||||||
|
|
||||||
|
<MudPaper Class="pa-4 mb-4" Style="max-height: 400px; overflow-y: auto;">
|
||||||
|
@((MarkupString)GetClubContractHtml())
|
||||||
|
</MudPaper>
|
||||||
|
|
||||||
|
<MudCheckBox @bind-Value="_acceptedTerms" Label="قوانین و مقررات باشگاه مشتریان را مطالعه کردم و میپذیرم" Color="Color.Primary" />
|
||||||
|
|
||||||
|
<MudButton Variant="Variant.Filled"
|
||||||
|
Color="Color.Primary"
|
||||||
|
FullWidth="true"
|
||||||
|
Class="mt-4"
|
||||||
|
Disabled="@(!_acceptedTerms || _isLoading)"
|
||||||
|
OnClick="RequestOtp">
|
||||||
|
@if (_isLoading)
|
||||||
|
{
|
||||||
|
<MudProgressCircular Size="Size.Small" Indeterminate="true" Class="ml-2" />
|
||||||
|
}
|
||||||
|
ادامه و دریافت کد تایید
|
||||||
|
</MudButton>
|
||||||
|
}
|
||||||
|
else if (_step == ContractStep.EnterOtp)
|
||||||
|
{
|
||||||
|
<MudText Typo="Typo.h5" Class="mb-4" Align="Align.Center">
|
||||||
|
<MudIcon Icon="@Icons.Material.Filled.Sms" Class="ml-2" />
|
||||||
|
تایید قرارداد
|
||||||
|
</MudText>
|
||||||
|
|
||||||
|
<MudAlert Severity="Severity.Success" Class="mb-4">
|
||||||
|
کد تایید به شماره موبایل شما ارسال شد. لطفاً کد را وارد کنید.
|
||||||
|
</MudAlert>
|
||||||
|
|
||||||
|
<MudTextField @bind-Value="_otpCode"
|
||||||
|
Label="کد تایید ۶ رقمی"
|
||||||
|
Variant="Variant.Outlined"
|
||||||
|
MaxLength="6"
|
||||||
|
InputType="InputType.Number"
|
||||||
|
Class="mb-4"
|
||||||
|
Immediate="true" />
|
||||||
|
|
||||||
|
@if (_remainingSeconds > 0)
|
||||||
|
{
|
||||||
|
<MudText Typo="Typo.body2" Color="Color.Secondary" Class="mb-2">
|
||||||
|
زمان باقیمانده: @_remainingSeconds ثانیه
|
||||||
|
</MudText>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<MudButton Variant="Variant.Text" Color="Color.Primary" OnClick="RequestOtp" Disabled="_isLoading">
|
||||||
|
ارسال مجدد کد
|
||||||
|
</MudButton>
|
||||||
|
}
|
||||||
|
|
||||||
|
<MudButton Variant="Variant.Filled"
|
||||||
|
Color="Color.Primary"
|
||||||
|
FullWidth="true"
|
||||||
|
Class="mt-4"
|
||||||
|
Disabled="@(string.IsNullOrEmpty(_otpCode) || _otpCode.Length != 6 || _isLoading)"
|
||||||
|
OnClick="AcceptContract">
|
||||||
|
@if (_isLoading)
|
||||||
|
{
|
||||||
|
<MudProgressCircular Size="Size.Small" Indeterminate="true" Class="ml-2" />
|
||||||
|
}
|
||||||
|
تایید و فعالسازی عضویت
|
||||||
|
</MudButton>
|
||||||
|
}
|
||||||
|
else if (_step == ContractStep.Success)
|
||||||
|
{
|
||||||
|
<div class="text-center">
|
||||||
|
<MudIcon Icon="@Icons.Material.Filled.CheckCircle" Color="Color.Success" Style="font-size: 80px" />
|
||||||
|
<MudText Typo="Typo.h5" Color="Color.Success" Class="mt-4">
|
||||||
|
عضویت شما در باشگاه مشتریان فعال شد!
|
||||||
|
</MudText>
|
||||||
|
<MudText Typo="Typo.body1" Class="mt-2">
|
||||||
|
اکنون میتوانید از لینک دعوت خود استفاده کنید و دوستانتان را دعوت کنید.
|
||||||
|
</MudText>
|
||||||
|
<MudButton Variant="Variant.Filled"
|
||||||
|
Color="Color.Primary"
|
||||||
|
Class="mt-6"
|
||||||
|
OnClick="CloseAndRefresh">
|
||||||
|
متوجه شدم
|
||||||
|
</MudButton>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</MudContainer>
|
||||||
|
</DialogContent>
|
||||||
|
</MudDialog>
|
||||||
|
|
||||||
|
@code {
|
||||||
|
[CascadingParameter] IMudDialogInstance MudDialog { get; set; }
|
||||||
|
|
||||||
|
private enum ContractStep { ReadContract, EnterOtp, Success }
|
||||||
|
private ContractStep _step = ContractStep.ReadContract;
|
||||||
|
|
||||||
|
private bool _acceptedTerms;
|
||||||
|
private string _otpCode = "";
|
||||||
|
private bool _isLoading;
|
||||||
|
private int _remainingSeconds;
|
||||||
|
private readonly Guid _signGuid = Guid.NewGuid();
|
||||||
|
private System.Timers.Timer? _timer;
|
||||||
|
private const string TokenStorageKey = "auth:token";
|
||||||
|
|
||||||
|
// این Modal غیرقابل بسته شدن است - Options در ShowAsync تنظیم میشوند
|
||||||
|
|
||||||
|
private async Task RequestOtp()
|
||||||
|
{
|
||||||
|
_isLoading = true;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var response = await ClubMembershipClient.RequestClubContractOtpAsync(
|
||||||
|
new RequestClubContractOtpRequest
|
||||||
|
{
|
||||||
|
SignGuid = _signGuid.ToString()
|
||||||
|
});
|
||||||
|
|
||||||
|
if (response.Success)
|
||||||
|
{
|
||||||
|
_step = ContractStep.EnterOtp;
|
||||||
|
_remainingSeconds = response.RemainingSeconds > 0 ? response.RemainingSeconds : 120;
|
||||||
|
StartCountdown();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Snackbar.Add(response.Message, Severity.Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Snackbar.Add($"خطا در ارسال کد: {ex.Message}", Severity.Error);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
_isLoading = false;
|
||||||
|
StateHasChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task AcceptContract()
|
||||||
|
{
|
||||||
|
_isLoading = true;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var response = await ClubMembershipClient.AcceptClubMembershipContractAsync(
|
||||||
|
new AcceptClubMembershipContractRequest
|
||||||
|
{
|
||||||
|
OtpCode = _otpCode,
|
||||||
|
SignGuid = _signGuid.ToString(),
|
||||||
|
ContractHtml = GetClubContractHtml()
|
||||||
|
});
|
||||||
|
|
||||||
|
if (response.Success)
|
||||||
|
{
|
||||||
|
// ذخیره توکن جدید
|
||||||
|
if (!string.IsNullOrEmpty(response.Token))
|
||||||
|
{
|
||||||
|
await LocalStorage.SetItemAsync(TokenStorageKey, response.Token);
|
||||||
|
await AuthService.InitUserAuthInfo();
|
||||||
|
}
|
||||||
|
|
||||||
|
_step = ContractStep.Success;
|
||||||
|
StopCountdown();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Snackbar.Add(response.Message, Severity.Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Snackbar.Add($"خطا در ثبت قرارداد: {ex.Message}", Severity.Error);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
_isLoading = false;
|
||||||
|
StateHasChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CloseAndRefresh()
|
||||||
|
{
|
||||||
|
MudDialog.Close(DialogResult.Ok(true));
|
||||||
|
Navigation.NavigateTo(Navigation.Uri, forceLoad: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void StartCountdown()
|
||||||
|
{
|
||||||
|
_timer = new System.Timers.Timer(1000);
|
||||||
|
_timer.Elapsed += (s, e) =>
|
||||||
|
{
|
||||||
|
_remainingSeconds--;
|
||||||
|
if (_remainingSeconds <= 0)
|
||||||
|
{
|
||||||
|
StopCountdown();
|
||||||
|
}
|
||||||
|
InvokeAsync(StateHasChanged);
|
||||||
|
};
|
||||||
|
_timer.Start();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void StopCountdown()
|
||||||
|
{
|
||||||
|
_timer?.Stop();
|
||||||
|
_timer?.Dispose();
|
||||||
|
_timer = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
StopCountdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetClubContractHtml()
|
||||||
|
{
|
||||||
|
return @"
|
||||||
|
<div style='direction: rtl; font-family: Tahoma, sans-serif; line-height: 2; text-align: justify;'>
|
||||||
|
<h2 style='text-align: center; margin-bottom: 20px;'>قرارداد عضویت در باشگاه مشتریان کارابازار</h2>
|
||||||
|
|
||||||
|
<p><strong>ماده ۱ - تعاریف</strong></p>
|
||||||
|
<p>۱-۱. باشگاه مشتریان: سامانهای که امکان معرفی دوستان و دریافت پاداش را فراهم میکند.</p>
|
||||||
|
<p>۱-۲. لینک دعوت: لینک اختصاصی هر کاربر برای معرفی دیگران.</p>
|
||||||
|
<p>۱-۳. پاداش معرفی: مبلغی که به ازای هر معرفی موفق به کاربر تعلق میگیرد.</p>
|
||||||
|
|
||||||
|
<p><strong>ماده ۲ - شرایط عضویت</strong></p>
|
||||||
|
<p>۲-۱. کاربر با پرداخت مبلغ ۵۶ میلیون تومان (پکیج پایه)، امکان عضویت در باشگاه مشتریان را خواهد داشت.</p>
|
||||||
|
<p>۲-۲. پس از امضای این قرارداد، لینک دعوت کاربر فعال خواهد شد.</p>
|
||||||
|
<p>۲-۳. کاربر میتواند حداکثر ۲ نفر را مستقیماً دعوت کند (یک نفر در شاخه چپ و یک نفر در شاخه راست).</p>
|
||||||
|
|
||||||
|
<p><strong>ماده ۳ - تعهدات کاربر</strong></p>
|
||||||
|
<p>۳-۱. کاربر متعهد است از لینک دعوت فقط برای معرفی افراد واقعی استفاده کند.</p>
|
||||||
|
<p>۳-۲. هرگونه سوءاستفاده از سیستم منجر به لغو عضویت خواهد شد.</p>
|
||||||
|
<p>۳-۳. کاربر حق انتقال یا فروش عضویت خود را ندارد.</p>
|
||||||
|
|
||||||
|
<p><strong>ماده ۴ - حقوق کاربر</strong></p>
|
||||||
|
<p>۴-۱. دریافت پاداش معرفی به ازای هر عضو جدید که از طریق شبکه کاربر عضو شود.</p>
|
||||||
|
<p>۴-۲. دسترسی به داشبورد مدیریت شبکه و مشاهده وضعیت زیرمجموعهها.</p>
|
||||||
|
<p>۴-۳. امکان برداشت موجودی کیف پول طبق قوانین سایت.</p>
|
||||||
|
|
||||||
|
<p><strong>ماده ۵ - شرایط فسخ</strong></p>
|
||||||
|
<p>۵-۱. در صورت نقض هر یک از مفاد این قرارداد، کارابازار حق لغو عضویت کاربر را دارد.</p>
|
||||||
|
<p>۵-۲. در صورت فسخ قرارداد، موجودی کیف پول طبق قوانین سایت تسویه خواهد شد.</p>
|
||||||
|
|
||||||
|
<p><strong>ماده ۶ - حل اختلاف</strong></p>
|
||||||
|
<p>۶-۱. در صورت بروز اختلاف، طرفین ابتدا از طریق مذاکره اقدام به حل و فصل خواهند کرد.</p>
|
||||||
|
<p>۶-۲. در صورت عدم توافق، مراجع قضایی صلاحیتدار رسیدگی خواهند کرد.</p>
|
||||||
|
|
||||||
|
<p style='text-align: center; margin-top: 30px;'><strong>شناسه قرارداد: " + _signGuid + @"</strong></p>
|
||||||
|
</div>";
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -12,6 +12,7 @@
|
|||||||
@using MudBlazor
|
@using MudBlazor
|
||||||
@using FrontOffice.Main.Utilities
|
@using FrontOffice.Main.Utilities
|
||||||
@using DateTimeConverterCL
|
@using DateTimeConverterCL
|
||||||
|
@using CityProto = FrontOffice.BFF.City.Protobuf
|
||||||
|
|
||||||
@inject NavigationManager Navigation
|
@inject NavigationManager Navigation
|
||||||
@inject IDialogService DialogService
|
@inject IDialogService DialogService
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"GwUrl": "https://frontoffice-bff.foursat.afrino.co",
|
// "GwUrl": "https://frontoffice-bff.foursat.afrino.co",
|
||||||
// "GwUrl": "https://localhost:34781",
|
"GwUrl": "https://localhost:34781",
|
||||||
"DownloadUrl": "https://dl.afrino.co",
|
"DownloadUrl": "https://dl.afrino.co",
|
||||||
"EncryptionSettings": {
|
"EncryptionSettings": {
|
||||||
"Key": "kmcQ3XTmH4mrdh8VHziuscyf8LLYjG//Kyni81nH/0E=",
|
"Key": "kmcQ3XTmH4mrdh8VHziuscyf8LLYjG//Kyni81nH/0E=",
|
||||||
|
|||||||
Reference in New Issue
Block a user