initial commit
This commit is contained in:
@@ -0,0 +1,119 @@
|
||||
@page "/account/forgot-password"
|
||||
@layout AuthenticationLayout
|
||||
@using System.ComponentModel.DataAnnotations
|
||||
@using Indotalent.Shared.Consts
|
||||
@using Microsoft.JSInterop
|
||||
@inject IJSRuntime JSRuntime
|
||||
@inject ISnackbar Snackbar
|
||||
@inject NavigationManager Navigation
|
||||
|
||||
<PageTitle>Forgot Password - @GlobalConsts.AppInitial</PageTitle>
|
||||
|
||||
<div class="page-header">
|
||||
<h2>Forgot Password?</h2>
|
||||
<p>Enter your email address below and we'll send you a link to reset your password.</p>
|
||||
</div>
|
||||
|
||||
<MudForm @ref="form" @bind-IsValid="@success">
|
||||
<div style="display:flex;flex-direction:column;gap:1rem;">
|
||||
<div>
|
||||
<label class="form-label">Email Address</label>
|
||||
<MudTextField T="string"
|
||||
@bind-Value="model.Email"
|
||||
Variant="Variant.Outlined"
|
||||
Placeholder="name@example.com"
|
||||
Margin="Margin.Dense"
|
||||
Adornment="Adornment.Start"
|
||||
AdornmentIcon="@Icons.Material.Filled.Email"
|
||||
Required="true"
|
||||
Validation="@(new EmailAddressAttribute() { ErrorMessage = "Invalid email address format" })"
|
||||
For="@(() => model.Email)" />
|
||||
</div>
|
||||
|
||||
<button type="button"
|
||||
class="btn-primary-custom"
|
||||
disabled="@(!success || isProcessing)"
|
||||
@onclick="HandleForgotPassword">
|
||||
@if (isProcessing)
|
||||
{
|
||||
<MudProgressCircular Size="Size.Small" Indeterminate="true" Color="Color.Inherit" />
|
||||
<span>Sending link...</span>
|
||||
}
|
||||
else
|
||||
{
|
||||
<span>Send Reset Link</span>
|
||||
}
|
||||
</button>
|
||||
</div>
|
||||
</MudForm>
|
||||
|
||||
<div style="text-align:center;margin-top:1.5rem;">
|
||||
<span style="font-size:0.875rem;color:#64748B;">Remember your password? </span>
|
||||
<a class="auth-link" href="/account/login">Back to Sign In</a>
|
||||
</div>
|
||||
|
||||
@code {
|
||||
private MudForm form = default!;
|
||||
private bool success;
|
||||
private bool isProcessing;
|
||||
private ForgotPasswordModel model = new();
|
||||
|
||||
private class ForgotPasswordModel
|
||||
{
|
||||
public string Email { get; set; } = "";
|
||||
}
|
||||
|
||||
private async Task HandleForgotPassword()
|
||||
{
|
||||
await form.Validate();
|
||||
if (!success) return;
|
||||
|
||||
isProcessing = true;
|
||||
StateHasChanged();
|
||||
|
||||
var result = await JSRuntime.InvokeAsync<ApiResponse>("apiForgotPassword", model.Email);
|
||||
|
||||
if (result.Status == 200)
|
||||
{
|
||||
Snackbar.Add("If your email is registered, a reset link has been sent.", Severity.Success);
|
||||
await Task.Delay(500);
|
||||
Navigation.NavigateTo("/account/login");
|
||||
}
|
||||
else
|
||||
{
|
||||
Snackbar.Add(result.Title ?? "Failed to send reset link", Severity.Error);
|
||||
}
|
||||
|
||||
isProcessing = false;
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
private class ApiResponse
|
||||
{
|
||||
public int Status { get; set; }
|
||||
public string? Title { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
<script>
|
||||
window.apiForgotPassword = async (email) => {
|
||||
try {
|
||||
const response = await fetch('/api/account/forgot-password', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ email })
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
return { status: 200, title: 'Success' };
|
||||
} else {
|
||||
const data = await response.json();
|
||||
let msg = 'Error processing request';
|
||||
if (data.errors && data.errors.length > 0) msg = data.errors[0];
|
||||
return { status: response.status, title: msg };
|
||||
}
|
||||
} catch (error) {
|
||||
return { status: 500, title: 'Network error' };
|
||||
}
|
||||
};
|
||||
</script>
|
||||
Reference in New Issue
Block a user