feat: داشبورد — لیست کاشی پکیجها + مدال انتخاب روش پرداخت
- حذف متن hardcoded 'پکیج پایه ۵۶ میلیون تومان' و دیالوگ inline - ایجاد PackagePurchaseDialog — کامپوننت مستقل 2 مرحلهای: مرحله ۱: نمایش کاشیهای پکیج (ریسپانسیو ۲-۳ تایی) مرحله ۲: انتخاب روش پرداخت (درگاه بانکی / دایا الماس) - دایا الماس فقط برای پکیج پایه + دور اول نمایش داده میشه - پکیجها داینامیک از API بارگذاری میشن - تغییر متن CTA از 'شروع فرآیند تامین اعتبار' به 'تهیه پکیج' - تغییر متن راهنما از 'پکیج پایه را تهیه کنید' به 'یکی از پکیجها را تهیه کنید' - CSS: hover effects + badge + responsive tiles
This commit is contained in:
@@ -42,8 +42,7 @@ public partial class Index
|
||||
private bool _isClubMemberActive;
|
||||
private bool CanShowReferralLink => _hasPurchasedPackage && _isClubMemberActive;
|
||||
|
||||
// Purchase Options Bottom Sheet
|
||||
private bool _showPurchaseBottomSheet;
|
||||
// Purchase flow
|
||||
private bool _isProcessingPayment;
|
||||
private int _purchaseCycleCount; // تعداد دورهای خرید — اگر > 0 فقط IPG مجاز
|
||||
|
||||
@@ -394,53 +393,65 @@ public partial class Index
|
||||
}
|
||||
}
|
||||
|
||||
private void OpenPurchaseOptions()
|
||||
private async Task OpenPurchaseOptions()
|
||||
{
|
||||
_showPurchaseBottomSheet = true;
|
||||
var options = new DialogOptions
|
||||
{
|
||||
MaxWidth = MaxWidth.Small,
|
||||
FullWidth = true,
|
||||
CloseOnEscapeKey = true,
|
||||
BackdropClick = true
|
||||
};
|
||||
|
||||
var parameters = new DialogParameters<Shared.PackagePurchaseDialog>
|
||||
{
|
||||
{ x => x.PurchaseCycleCount, _purchaseCycleCount }
|
||||
};
|
||||
|
||||
var dialog = await DialogService.ShowAsync<Shared.PackagePurchaseDialog>(
|
||||
string.Empty, parameters, options);
|
||||
var result = await dialog.Result;
|
||||
|
||||
if (result.Canceled) return;
|
||||
|
||||
if (result.Data is Shared.PackagePurchaseDialog.PackagePurchaseResult purchase)
|
||||
{
|
||||
switch (purchase.Method)
|
||||
{
|
||||
case Shared.PackagePurchaseDialog.PaymentMethodType.DirectPayment:
|
||||
await ProcessDirectPayment(purchase.Package.Id);
|
||||
break;
|
||||
case Shared.PackagePurchaseDialog.PaymentMethodType.DayaLoan:
|
||||
await ProcessDayaLoanPayment();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ClosePurchaseOptions()
|
||||
{
|
||||
_showPurchaseBottomSheet = false;
|
||||
}
|
||||
|
||||
private async Task DirectPayment()
|
||||
private async Task ProcessDirectPayment(long packageId)
|
||||
{
|
||||
if (_isProcessingPayment) return;
|
||||
|
||||
|
||||
_isProcessingPayment = true;
|
||||
_showPurchaseBottomSheet = false;
|
||||
|
||||
StateHasChanged();
|
||||
|
||||
try
|
||||
{
|
||||
// Get available packages and pick the first one
|
||||
var packages = await PackageContract.GetCustomerPackagesAsync(new GetCustomerPackagesRequest());
|
||||
var selectedPackage = packages?.Models?.FirstOrDefault();
|
||||
if (selectedPackage == null)
|
||||
{
|
||||
Snackbar.Add("پکیجی برای خرید یافت نشد", Severity.Error);
|
||||
return;
|
||||
}
|
||||
|
||||
// Call CMS to initiate purchase (UserId from JWT, PackageId explicit)
|
||||
var callbackUrl = $"{Navigation.BaseUri}profile/payment-callback";
|
||||
|
||||
|
||||
var response = await PackageContract.CustomerPurchasePackageAsync(new CustomerPurchasePackageRequest
|
||||
{
|
||||
PackageId = selectedPackage.Id,
|
||||
PackageId = packageId,
|
||||
CallbackUrl = callbackUrl,
|
||||
PurchaseMethod = PurchaseMethodEnum.PurchaseMethodGateway
|
||||
});
|
||||
|
||||
|
||||
if (!response.Success)
|
||||
{
|
||||
Snackbar.Add(response.Message ?? "خطا در آغاز فرآیند پرداخت", Severity.Error);
|
||||
return;
|
||||
}
|
||||
|
||||
// Redirect to payment gateway
|
||||
// ZarinPal appends ?Authority=...&Status=... to callback URL
|
||||
// PaymentCallback uses Authority+Status to verify via CustomerVerifyPackagePurchase
|
||||
|
||||
if (!string.IsNullOrEmpty(response.PaymentGatewayUrl))
|
||||
{
|
||||
Navigation.NavigateTo(response.PaymentGatewayUrl, forceLoad: true);
|
||||
@@ -461,41 +472,34 @@ public partial class Index
|
||||
}
|
||||
}
|
||||
|
||||
private async Task DayaLoanPayment()
|
||||
private async Task ProcessDayaLoanPayment()
|
||||
{
|
||||
// Validate user info before redirecting
|
||||
if (string.IsNullOrWhiteSpace(_updateUserRequest.FirstName))
|
||||
{
|
||||
_showPurchaseBottomSheet = false;
|
||||
Snackbar.Add($"لطفا اطلاعات شخصی خود را تکمیل کنید. (نام وارد نشده)", Severity.Error);
|
||||
Snackbar.Add("لطفا اطلاعات شخصی خود را تکمیل کنید. (نام وارد نشده)", Severity.Error);
|
||||
return;
|
||||
}
|
||||
if (string.IsNullOrWhiteSpace(_updateUserRequest.LastName))
|
||||
{
|
||||
_showPurchaseBottomSheet = false;
|
||||
Snackbar.Add($"لطفا اطلاعات شخصی خود را تکمیل کنید. (نام خانوادگی وارد نشده)", Severity.Error);
|
||||
Snackbar.Add("لطفا اطلاعات شخصی خود را تکمیل کنید. (نام خانوادگی وارد نشده)", Severity.Error);
|
||||
return;
|
||||
}
|
||||
if (string.IsNullOrWhiteSpace(_updateUserRequest.NationalCode))
|
||||
{
|
||||
_showPurchaseBottomSheet = false;
|
||||
Snackbar.Add($"لطفا اطلاعات شخصی خود را تکمیل کنید. (کدملی وارد نشده)", Severity.Error);
|
||||
Snackbar.Add("لطفا اطلاعات شخصی خود را تکمیل کنید. (کدملی وارد نشده)", Severity.Error);
|
||||
return;
|
||||
}
|
||||
if (_updateUserRequest.BirthDate == null)
|
||||
{
|
||||
_showPurchaseBottomSheet = false;
|
||||
Snackbar.Add($"لطفا اطلاعات شخصی خود را تکمیل کنید. (تاریخ تولد وارد نشده)", Severity.Error);
|
||||
Snackbar.Add("لطفا اطلاعات شخصی خود را تکمیل کنید. (تاریخ تولد وارد نشده)", Severity.Error);
|
||||
return;
|
||||
}
|
||||
if (!_addresses.Any())
|
||||
{
|
||||
_showPurchaseBottomSheet = false;
|
||||
Snackbar.Add($"آدرس محل سکونت شما الزامی است!", Severity.Error);
|
||||
Snackbar.Add("آدرس محل سکونت شما الزامی است!", Severity.Error);
|
||||
return;
|
||||
}
|
||||
|
||||
_showPurchaseBottomSheet = false;
|
||||
|
||||
var url = "https://dayadiamond.ir/profile/creditpurchase/?merchantcode=56146364";
|
||||
await JSRuntime.InvokeVoidAsync("open", url, "_blank");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user