Files
FrontOffice/src/FrontOffice.Main/Shared/ClubMembershipContractDialog.razor
T
masoodafar-web 6db83ccd90
Build and Deploy to Kubernetes / build-and-deploy (push) Failing after 4m55s
feat: full FrontOffice updates - discount store, blog, payment gateway, UI improvements
- Discount store pages (products, cart, orders, order detail)
- Blog pages and services
- Payment gateway callback page
- AppImage component, EmptyState, LoadingState, PageHeader
- DiscountCartService, DiscountOrderService, DiscountProductService
- BlogCategoryService, BlogPostService, SitePageService, ImageCacheService
- PhoneVerifyForm component
- Profile Hub page
- UI/UX improvements across all pages
- landing.js for homepage
- Config and routing updates
2026-02-16 00:51:39 +03:30

285 lines
12 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
@using CMSMicroservice.Protobuf.Protos.ClubMembership
@using CMSMicroservice.Protobuf.Protos.OtpToken
@using Blazored.LocalStorage
@using FrontOffice.Main.Utilities
@using MudBlazor
@inject ClubMembershipContract.ClubMembershipContractClient ClubMembershipClient
@inject OtpTokenContract.OtpTokenContractClient OtpTokenClient
@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 OtpTokenClient.CreateNewOtpTokenAsync(
new CMSMicroservice.Protobuf.Protos.OtpToken.CreateNewOtpTokenRequest
{
Mobile = await GetUserMobileAsync(),
Purpose = "signClubContract",
SignGuid = _signGuid.ToString()
});
if (response.Success)
{
_step = ContractStep.EnterOtp;
_remainingSeconds = 120; // Default 2 minutes
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 CMSMicroservice.Protobuf.Protos.ClubMembership.AcceptClubMembershipContractRequest
{
OtpCode = _otpCode,
SignGuid = _signGuid.ToString(),
ContractHtml = GetClubContractHtml()
});
if (response.Success)
{
_step = ContractStep.Success;
StopCountdown();
Snackbar.Add("قرارداد باشگاه مشتریان با موفقیت امضا شد.", Severity.Success);
}
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>";
}
private async Task<string> GetUserMobileAsync()
{
// Get user mobile from auth service or localStorage
var userInfo = await AuthService.GetUserAuthInfo();
return userInfo?.MobileNumber ?? "";
}
private async Task<long> GetCurrentUserIdAsync()
{
// Get current user ID from auth service
var userInfo = await AuthService.GetUserAuthInfo();
return userInfo?.UserId ?? 0;
}
}