using Blazored.LocalStorage; using FrontOffice.BFF.User.Protobuf.Protos.User; using FrontOffice.BFF.User.Protobuf.Validator; using FrontOffice.Main.Utilities; using Grpc.Core; using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.WebUtilities; using MudBlazor; namespace FrontOffice.Main.Pages.Auth; public partial class Phone : IDisposable { private const string PhoneStorageKey = "auth:phone-number"; private const string RedirectStorageKey = "auth:redirect"; private const string TokenStorageKey = "auth:token"; private const string OtpPurpose = "Login"; private CreateNewOtpTokenRequestValidator _requestValidator = new(); private CreateNewOtpTokenRequest _request = new(); private MudForm? _form; private bool _isBusy; private string? _errorMessage; private string? _redirect; private CancellationTokenSource? _sendCts; [Inject] private ILocalStorageService LocalStorage { get; set; } = default!; [Inject] private UserContract.UserContractClient UserClient { get; set; } = default!; protected override async Task OnInitializedAsync() { _request.Purpose = OtpPurpose; var uri = Navigation.ToAbsoluteUri(Navigation.Uri); var query = QueryHelpers.ParseQuery(uri.Query); if (query.TryGetValue("redirect", out var redirectValues)) { _redirect = redirectValues.LastOrDefault(); } var storedPhone = await LocalStorage.GetItemAsync(PhoneStorageKey); if (!string.IsNullOrWhiteSpace(storedPhone)) { _request.Mobile = storedPhone; } if (string.IsNullOrWhiteSpace(_redirect)) { var storedRedirect = await LocalStorage.GetItemAsync(RedirectStorageKey); if (!string.IsNullOrWhiteSpace(storedRedirect)) { _redirect = storedRedirect; } } } private async Task SendOtpAsync() { _errorMessage = null; if (_form is null) return; await _form.Validate(); if (!_form.IsValid) return; _isBusy = true; _sendCts?.Cancel(); _sendCts?.Dispose(); _sendCts = new CancellationTokenSource(); try { var validationResult = _requestValidator.Validate(_request); if (!validationResult.IsValid) { _errorMessage = string.Join(" ", validationResult.Errors.Select(e => e.ErrorMessage).Distinct()); return; } var metadata = await BuildAuthMetadataAsync(); CreateNewOtpTokenResponse response; if (metadata is not null) { response = await UserClient.CreateNewOtpTokenAsync(_request, metadata, cancellationToken: _sendCts.Token); } else { response = await UserClient.CreateNewOtpTokenAsync(_request, cancellationToken: _sendCts.Token); } if (response?.Success != true) { _errorMessage = string.IsNullOrWhiteSpace(response?.Message) ? "ارسال رمز پویا با خطا مواجه شد. لطفاً دوباره تلاش کنید." : response!.Message; return; } await LocalStorage.SetItemAsync(PhoneStorageKey, _request.Mobile); if (!string.IsNullOrWhiteSpace(_redirect)) { await LocalStorage.SetItemAsync(RedirectStorageKey, _redirect); } else { await LocalStorage.RemoveItemAsync(RedirectStorageKey); } var target = $"{RouteConstants.Auth.Verify}?phone={Uri.EscapeDataString(_request.Mobile)}"; if (!string.IsNullOrEmpty(_redirect)) { target += "&redirect=" + Uri.EscapeDataString(_redirect); } Navigation.NavigateTo(target, forceLoad: false); } catch (RpcException rpcEx) { _errorMessage = !string.IsNullOrWhiteSpace(rpcEx.Status.Detail) ? rpcEx.Status.Detail : "ارسال رمز پویا با خطا مواجه شد. لطفاً دوباره تلاش کنید."; } catch (OperationCanceledException) { } catch (Exception ex) { _errorMessage = ex.Message; } finally { _isBusy = false; _sendCts?.Dispose(); _sendCts = null; await InvokeAsync(StateHasChanged); } } private async Task BuildAuthMetadataAsync() { var token = await LocalStorage.GetItemAsync(TokenStorageKey); if (string.IsNullOrWhiteSpace(token)) { return null; } return new Metadata { { "Authorization", $"Bearer {token}" } }; } public void Dispose() { _sendCts?.Cancel(); _sendCts?.Dispose(); _sendCts = null; } }