feat: add club membership contract dialog and city autocomplete
This commit is contained in:
@@ -29,13 +29,34 @@
|
||||
Required="true"
|
||||
RequiredError="کد پستی الزامی است." />
|
||||
|
||||
<MudTextField @bind-Value="_request.CityId"
|
||||
For="@(() => _request.CityId)"
|
||||
Label="شناسه شهر"
|
||||
Variant="Variant.Outlined"
|
||||
InputType="InputType.Number"
|
||||
Required="true"
|
||||
RequiredError="شهر الزامی است." />
|
||||
<MudAutocomplete T="CityProto.GetAllCitiesByFilterResponseModel"
|
||||
@bind-Value="_selectedCity"
|
||||
Label="شهر"
|
||||
Variant="Variant.Outlined"
|
||||
SearchFunc="SearchCities"
|
||||
ToStringFunc="@(city => city != null ? $"{city.Native} ({city.StateName})" : string.Empty)"
|
||||
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>
|
||||
</MudForm>
|
||||
</DialogContent>
|
||||
|
||||
@@ -3,6 +3,7 @@ using FrontOffice.BFF.UserAddress.Protobuf.Validator;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using MudBlazor;
|
||||
using Severity = MudBlazor.Severity;
|
||||
using CityProto = FrontOffice.BFF.City.Protobuf;
|
||||
|
||||
namespace FrontOffice.Main.Pages.Profile.Components;
|
||||
|
||||
@@ -10,19 +11,48 @@ public partial class AddAddressDialog : ComponentBase
|
||||
{
|
||||
[CascadingParameter] private IDialogReference MudDialog { get; set; } = default!;
|
||||
[Inject] private UserAddressContract.UserAddressContractClient UserAddressContract { get; set; } = default!;
|
||||
[Inject] private CityProto.CityContract.CityContractClient CityContract { get; set; } = default!;
|
||||
|
||||
private MudForm? _form;
|
||||
private readonly CreateNewUserAddressRequestValidator _validator = new();
|
||||
private bool _isSaving;
|
||||
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()
|
||||
{
|
||||
if (_form == null) return;
|
||||
|
||||
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;
|
||||
try
|
||||
{
|
||||
|
||||
@@ -28,13 +28,34 @@
|
||||
Required="true"
|
||||
RequiredError="کد پستی الزامی است." />
|
||||
|
||||
<MudTextField @bind-Value="_request.CityId"
|
||||
For="@(() => _request.CityId)"
|
||||
Label="شناسه شهر"
|
||||
Variant="Variant.Outlined"
|
||||
InputType="InputType.Number"
|
||||
Required="true"
|
||||
RequiredError="شهر الزامی است." />
|
||||
<MudAutocomplete T="CityProto.GetAllCitiesByFilterResponseModel"
|
||||
@bind-Value="_selectedCity"
|
||||
Label="شهر"
|
||||
Variant="Variant.Outlined"
|
||||
SearchFunc="SearchCities"
|
||||
ToStringFunc="@(city => city != null ? $"{city.Native} ({city.StateName})" : string.Empty)"
|
||||
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>
|
||||
</MudForm>
|
||||
</DialogContent>
|
||||
|
||||
@@ -4,14 +4,15 @@ using Mapster;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using MudBlazor;
|
||||
using Severity = MudBlazor.Severity;
|
||||
using CityProto = FrontOffice.BFF.City.Protobuf;
|
||||
|
||||
namespace FrontOffice.Main.Pages.Profile.Components;
|
||||
|
||||
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!;
|
||||
// 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; }
|
||||
|
||||
@@ -19,12 +20,60 @@ public partial class EditAddressDialog : ComponentBase
|
||||
private readonly UpdateUserAddressRequestValidator _validator = new();
|
||||
private bool _isSaving;
|
||||
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)
|
||||
{
|
||||
_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()
|
||||
@@ -32,8 +81,14 @@ public partial class EditAddressDialog : ComponentBase
|
||||
if (_form == null) return;
|
||||
|
||||
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;
|
||||
try
|
||||
{
|
||||
|
||||
@@ -60,6 +60,9 @@ public partial class Index
|
||||
await LoadUserProfile();
|
||||
await LoadAddresses();
|
||||
await LoadWallet();
|
||||
|
||||
// نمایش Modal قرارداد باشگاه اگر پکیج خریده ولی باشگاه فعال نشده
|
||||
await CheckAndShowClubContractModal();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,6 +81,39 @@ public partial class Index
|
||||
}
|
||||
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 _walletDiscount = "-";
|
||||
|
||||
Reference in New Issue
Block a user