Merge branch 'kub-stage' into production
Build and Deploy to Production / build-and-deploy (push) Successful in 12m51s

This commit is contained in:
masoodafar-web
2026-09-24 21:49:42 +03:30
25 changed files with 458 additions and 34 deletions
+6 -2
View File
@@ -24,7 +24,9 @@
OnChangePhone="ChangePhoneAsync"
OnResendOtp="ResendOtpAsync"
ReferralCode="@_referralCode"
ReferralCodeChanged="OnReferralCodeChanged" />
ReferralCodeChanged="OnReferralCodeChanged"
InviterMobile="@_inviterMobile"
InviterMobileChanged="OnInviterMobileChanged" />
</div>
}
else
@@ -55,7 +57,9 @@ else
OnChangePhone="ChangePhoneAsync"
OnResendOtp="ResendOtpAsync"
ReferralCode="@_referralCode"
ReferralCodeChanged="OnReferralCodeChanged" />
ReferralCodeChanged="OnReferralCodeChanged"
InviterMobile="@_inviterMobile"
InviterMobileChanged="OnInviterMobileChanged" />
<MudStack Class="mt-4" Spacing="2">
@if (_currentStep == AuthStep.Phone)
@@ -44,6 +44,8 @@ public partial class AuthDialog : IDisposable
// Referral code field
private string? _referralCode;
// Inviter mobile (دعوت‌کننده)
private string? _inviterMobile;
[Inject] private ILocalStorageService LocalStorage { get; set; } = default!;
[Inject] private UserContract.UserContractClient UserClient { get; set; } = default!;
@@ -71,6 +73,7 @@ public partial class AuthDialog : IDisposable
}
_referralCode = await LocalStorage.GetItemAsync<string>("referral:code");
_inviterMobile = await LocalStorage.GetItemAsync<string>("inviter:mobile");
// await LocalStorage.RemoveItemAsync(TokenStorageKey);
}
@@ -83,6 +86,15 @@ public partial class AuthDialog : IDisposable
await LocalStorage.RemoveItemAsync("referral:code");
}
private async Task OnInviterMobileChanged(string? value)
{
_inviterMobile = value;
if (!string.IsNullOrWhiteSpace(value))
await LocalStorage.SetItemAsync("inviter:mobile", value);
else
await LocalStorage.RemoveItemAsync("inviter:mobile");
}
private void GenerateCaptcha()
{
_captchaCode = Guid.NewGuid().ToString("N")[..6].ToUpperInvariant();
@@ -204,6 +216,15 @@ public partial class AuthDialog : IDisposable
_verifyRequest.ParentReferralCode = effectiveReferralCode;
}
var storedInviterMobile = await LocalStorage.GetItemAsync<string>("inviter:mobile");
var effectiveInviterMobile = !string.IsNullOrWhiteSpace(_inviterMobile)
? _inviterMobile
: storedInviterMobile;
if (!string.IsNullOrWhiteSpace(effectiveInviterMobile))
{
_verifyRequest.InviterMobile = effectiveInviterMobile;
}
var validationResult = true; // _verifyRequestValidator.Validate(_verifyRequest);
if (!validationResult)
{
@@ -236,6 +257,7 @@ public partial class AuthDialog : IDisposable
await LocalStorage.RemoveItemAsync(PhoneStorageKey);
await LocalStorage.RemoveItemAsync(RedirectStorageKey);
await LocalStorage.RemoveItemAsync("referral:code");
await LocalStorage.RemoveItemAsync("inviter:mobile");
_attemptsLeft = MaxVerificationAttempts;
_verifyRequest.Code = string.Empty;
@@ -52,7 +52,7 @@
روش پرداخت خود را انتخاب کنید:
</MudText>
@* Direct Payment — always available *@
@* Direct Payment (ZarinPal) — always available *@
<MudPaper Elevation="0" Class="pa-4 rounded-lg pkg-payment-option"
Style="border:2px solid var(--mud-palette-primary); cursor:pointer;"
@onclick="() => SelectPaymentMethod(PaymentMethodType.DirectPayment)">
@@ -61,13 +61,29 @@
<MudIcon Icon="@Icons.Material.Filled.CreditCard" Color="Color.Primary" Size="Size.Medium" />
<MudStack Spacing="0" Class="flex-grow-1">
<MudText Typo="Typo.subtitle1" Color="Color.Primary"><b>پرداخت مستقیم</b></MudText>
<MudText Typo="Typo.caption" Class="mud-text-secondary">پرداخت آنی از طریق درگاه بانکی</MudText>
<MudText Typo="Typo.caption" Class="mud-text-secondary">پرداخت آنی از طریق درگاه بانکی (زرین‌پال)</MudText>
</MudStack>
<MudIcon Icon="@Icons.Material.Filled.ArrowBack" Color="Color.Primary" Size="Size.Small" />
</MudStack>
</MudStack>
</MudPaper>
@* TwentyCard IPG *@
<MudPaper Elevation="0" Class="pa-4 rounded-lg pkg-payment-option"
Style="border:2px solid var(--mud-palette-info); cursor:pointer;"
@onclick="() => SelectPaymentMethod(PaymentMethodType.TwentyCard)">
<MudStack Spacing="2">
<MudStack Row="true" AlignItems="AlignItems.Center" Spacing="2">
<MudIcon Icon="@Icons.Material.Filled.AccountBalance" Color="Color.Info" Size="Size.Medium" />
<MudStack Spacing="0" Class="flex-grow-1">
<MudText Typo="Typo.subtitle1" Color="Color.Info"><b>پرداخت با ۲۰کارت</b></MudText>
<MudText Typo="Typo.caption" Class="mud-text-secondary">پرداخت از طریق درگاه ۲۰کارت (نیاز به تأمین اعتبار)</MudText>
</MudStack>
<MudIcon Icon="@Icons.Material.Filled.ArrowBack" Color="Color.Info" Size="Size.Small" />
</MudStack>
</MudStack>
</MudPaper>
@* Daya Loan — only for base package AND first purchase cycle *@
@if (_selectedPackage.SupportsDayaPurchase && PurchaseCycleCount == 0)
{
@@ -229,6 +245,6 @@
: "background:rgba(16,185,129,.12); color:#10b981;";
}
public enum PaymentMethodType { DirectPayment, DayaLoan }
public enum PaymentMethodType { DirectPayment, TwentyCard, DayaLoan }
public record PackagePurchaseResult(PackageDto Package, PaymentMethodType Method);
}
@@ -38,11 +38,21 @@
<MudTextField Value="ReferralCode"
ValueChanged="@((string? v) => ReferralCodeChanged.InvokeAsync(v))"
Label="کد معرف (اختیاری)"
Label="کد معرف سازمان (اختیاری)"
Variant="Variant.Outlined"
Immediate="true"
Placeholder="کد معرف را وارد کنید"
Class="mb-3" />
Placeholder="کد معرف ۱۰ رقمی"
Class="mb-3"
HelperText="جایگاه شما در سازمان — با لینک معرف پر می‌شود" />
<MudTextField Value="InviterMobile"
ValueChanged="@((string? v) => InviterMobileChanged.InvokeAsync(v))"
Label="شماره موبایل دعوت‌کننده (اختیاری)"
Variant="Variant.Outlined"
Immediate="true"
Placeholder="مثلاً 0912xxxxxxx"
Class="mb-3"
HelperText="کسی که شما را به کارابازار معرفی کرده — متفاوت از معرف سازمان" />
@if (!string.IsNullOrWhiteSpace(ErrorMessage))
{
@@ -33,6 +33,10 @@ public partial class PhoneVerifyForm
[Parameter] public string? ReferralCode { get; set; }
[Parameter] public EventCallback<string?> ReferralCodeChanged { get; set; }
// ── Inviter (دعوت‌کننده) ──
[Parameter] public string? InviterMobile { get; set; }
[Parameter] public EventCallback<string?> InviterMobileChanged { get; set; }
// ── Verify actions ──
[Parameter] public EventCallback OnChangePhone { get; set; }
[Parameter] public EventCallback OnResendOtp { get; set; }
@@ -0,0 +1,60 @@
@inject IConfiguration Configuration
@inject IJSRuntime JSRuntime
<MudDialog>
<TitleContent>
<MudStack Row="true" AlignItems="AlignItems.Center" Spacing="2">
<MudIcon Icon="@Icons.Material.Filled.AccountBalance" Color="Color.Primary" />
<MudText Typo="Typo.h6">تأمین اعتبار ۲۰کارت</MudText>
</MudStack>
</TitleContent>
<DialogContent>
<MudStack Spacing="3">
<MudText Typo="Typo.body2" Class="mud-text-secondary">
برای پرداخت از طریق درگاه ۲۰کارت، ابتدا باید اعتبار حساب ۲۰کارت خود را تأمین کنید.
پس از تأمین اعتبار، روی «ادامه پرداخت» بزنید تا به درگاه هدایت شوید.
</MudText>
<MudAlert Severity="Severity.Info" Dense="true" Variant="Variant.Outlined">
اگر قبلاً اعتبار را تأمین کرده‌اید، می‌توانید مستقیم ادامه دهید.
</MudAlert>
</MudStack>
</DialogContent>
<DialogActions>
<MudButton OnClick="Cancel" Variant="Variant.Text">انصراف</MudButton>
<MudButton Variant="Variant.Outlined"
Color="Color.Primary"
StartIcon="@Icons.Material.Filled.OpenInNew"
OnClick="OpenCreditPortal"
Disabled="@string.IsNullOrWhiteSpace(_creditPortalUrl)">
تأمین اعتبار
</MudButton>
<MudButton Variant="Variant.Filled"
Color="Color.Primary"
StartIcon="@Icons.Material.Filled.Payment"
OnClick="ContinuePayment">
ادامه پرداخت
</MudButton>
</DialogActions>
</MudDialog>
@code {
[CascadingParameter] private IMudDialogInstance MudDialog { get; set; } = default!;
private string _creditPortalUrl = string.Empty;
protected override void OnInitialized()
{
_creditPortalUrl = Configuration["TwentyCard:CreditPortalUrl"] ?? string.Empty;
}
private async Task OpenCreditPortal()
{
if (string.IsNullOrWhiteSpace(_creditPortalUrl)) return;
await JSRuntime.InvokeVoidAsync("open", _creditPortalUrl, "_blank");
}
private void ContinuePayment() => MudDialog.Close(DialogResult.Ok(true));
private void Cancel() => MudDialog.Cancel();
}