Files
2026-07-21 13:38:38 +07:00

212 lines
5.4 KiB
Plaintext

@page "/account/logout"
@layout AuthenticationLayout
@using Indotalent.Shared.Consts
@using Microsoft.JSInterop
@inject IJSRuntime JSRuntime
@inject NavigationManager Navigation
@inject ISnackbar Snackbar
<PageTitle>Sign Out - @GlobalConsts.AppInitial</PageTitle>
<style>
/* ===== LOGOUT CONTAINER ===== */
.logout-container {
display: flex;
flex-direction: column;
align-items: center;
text-align: center;
}
.logout-icon-wrapper {
display: flex;
justify-content: center;
margin-bottom: 1.5rem;
}
.logout-icon-circle {
width: 4.5rem;
height: 4.5rem;
border-radius: 50%;
background: rgba(139, 92, 246, 0.1);
display: flex;
align-items: center;
justify-content: center;
}
.logout-icon-circle svg {
width: 2.25rem;
height: 2.25rem;
color: #8B5CF6;
}
.logout-title {
font-size: 1.5rem;
font-weight: 700;
color: #1E293B;
margin: 0 0 0.25rem 0;
}
.logout-desc {
font-size: 0.875rem;
color: #64748B;
margin: 0 0 2rem 0;
}
/* ===== BUTTONS ===== */
.btn-signout {
display: inline-flex;
align-items: center;
justify-content: center;
gap: 0.5rem;
padding: 0.75rem 1.75rem;
background: #8B5CF6;
color: #ffffff;
font-size: 0.875rem;
font-weight: 600;
border-radius: 0.5rem;
transition: all 0.2s;
cursor: pointer;
border: none;
width: 100%;
font-family: "Poppins", sans-serif;
height: 48px;
}
.btn-signout:hover:not(:disabled) {
background: #7C3AED;
transform: translateY(-1px);
box-shadow: 0 4px 12px rgba(139, 92, 246, 0.3);
}
.btn-signout:disabled {
opacity: 0.7;
cursor: not-allowed;
transform: none;
box-shadow: none;
}
.btn-cancel {
display: inline-flex;
align-items: center;
justify-content: center;
padding: 0.75rem 1.75rem;
background: transparent;
color: #94A3B8;
font-size: 0.875rem;
font-weight: 600;
border-radius: 0.5rem;
transition: all 0.2s;
cursor: pointer;
border: none;
width: 100%;
font-family: "Poppins", sans-serif;
height: 48px;
margin-top: 0.75rem;
text-decoration: none;
}
.btn-cancel:hover:not(:disabled) {
color: #64748B;
background: rgba(148, 163, 184, 0.08);
}
.btn-cancel:disabled {
opacity: 0.5;
cursor: not-allowed;
}
/* ===== SPINNER ANIMATION ===== */
@@keyframes spin {
to { transform: rotate(360deg); }
}
.spinner {
animation: spin 1s linear infinite;
}
</style>
<div class="logout-container">
<div class="logout-icon-wrapper">
<div class="logout-icon-circle">
<svg fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1.5">
<path stroke-linecap="round" stroke-linejoin="round" d="M15.75 9V5.25A2.25 2.25 0 0013.5 3h-6a2.25 2.25 0 00-2.25 2.25v13.5A2.25 2.25 0 007.5 21h6a2.25 2.25 0 002.25-2.25V15m3 0l3-3m0 0l-3-3m3 3H9"/>
</svg>
</div>
</div>
<h2 class="logout-title">Sign Out</h2>
<p class="logout-desc">Are you sure you want to sign out of your account?</p>
<button class="btn-signout" type="button" disabled="@isLoggingOut" @onclick="Logout">
@if (isLoggingOut)
{
<svg class="spinner" style="width: 1rem; height: 1rem;" fill="none" viewBox="0 0 24 24">
<circle style="opacity: 0.25;" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"/>
<path style="opacity: 0.75;" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z"/>
</svg>
<span>Processing...</span>
}
else
{
<span>Sign Out</span>
}
</button>
<a class="btn-cancel" href="/">
Cancel
</a>
</div>
@code {
private bool isLoggingOut;
private async Task Logout()
{
isLoggingOut = true;
StateHasChanged();
var result = await JSRuntime.InvokeAsync<ApiJSRuntimeResponse>("apiAccountLogout");
if (result.Status == 200)
{
Snackbar.Add("Successfully signed out!", Severity.Success);
await Task.Delay(500);
Navigation.NavigateTo("/", forceLoad: true);
}
else
{
Snackbar.Add(result.Title ?? "Failed to logout.", Severity.Error);
await Task.Delay(500);
}
isLoggingOut = false;
StateHasChanged();
}
private class ApiJSRuntimeResponse
{
public int? Status { get; set; }
public string? Title { get; set; }
}
}
<script>
window.apiAccountLogout = async () => {
try {
const response = await fetch('/api/account/signout', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
credentials: 'include'
});
if (!response.ok) {
throw new Error('Unknown error occurred');
}
return { status: 200, title: 'Success user logout' };
} catch (error) {
return { status: 500, title: 'Server / Network error' };
}
};
</script>