astro_avtourist/frontend/src/pages/auth/verify.astro

208 lines
No EOL
6.2 KiB
Text
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.

---
import Layout from '@layouts/Layout.astro';
import { SITE_URL } from '@constants';
const success = Astro.url.searchParams.get('success');
const error = Astro.url.searchParams.get('error');
const token = Astro.url.searchParams.get('token');
const userId = Astro.url.searchParams.get('userId');
---
<Layout
title="Подтверждение email"
description="Подтверждение email адреса"
canonicalLink={`${SITE_URL}/auth/verify`}
>
<div class="verify-page">
<div class="verify-container">
<div class="verify-card" id="verify-card">
<!-- Loading state -->
<div id="loading">
<div class="verify-icon">
<div class="spinner"></div>
</div>
<h1>Подтверждение email...</h1>
</div>
<!-- Success state -->
<div id="success" class="hidden">
<div class="verify-icon success">
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"></path>
<polyline points="22 4 12 14.01 9 11.01"></polyline>
</svg>
</div>
<h1>Email подтверждён!</h1>
<p>Ваш аккаунт успешно активирован. Теперь вы можете войти в личный кабинет.</p>
<a href="/auth/sign-in" class="btn-primary">Войти в аккаунт</a>
</div>
<!-- Error state -->
<div id="error" class="hidden">
<div class="verify-icon error">
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<circle cx="12" cy="12" r="10"></circle>
<line x1="15" y1="9" x2="9" y2="15"></line>
<line x1="9" y1="9" x2="15" y2="15"></line>
</svg>
</div>
<h1>Ошибка подтверждения</h1>
<p id="error-message">Ссылка недействительна или истёк срок действия.</p>
<a href="/auth/sign-up" class="btn-primary">На страницу регистрации</a>
</div>
</div>
</div>
</div>
<script define:vars={{ token, userId, success, error }}>
const urlParams = new URLSearchParams(window.location.search);
function showSection(id) {
document.getElementById('loading')?.classList.add('hidden');
document.getElementById('success')?.classList.add('hidden');
document.getElementById('error')?.classList.add('hidden');
document.getElementById(id)?.classList.remove('hidden');
}
async function verifyEmail() {
const token = urlParams.get('token');
const userId = urlParams.get('userId');
if (!token || !userId) {
document.getElementById('error-message').textContent = 'Отсутствуют параметры подтверждения';
showSection('error');
return;
}
try {
const response = await fetch('/api/auth/confirm', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ token, userId }),
});
const data = await response.json();
if (response.ok && data.success) {
showSection('success');
} else {
document.getElementById('error-message').textContent = data.error || 'Ошибка подтверждения';
showSection('error');
}
} catch (e) {
console.error('Verification error:', e);
document.getElementById('error-message').textContent = 'Ошибка подтверждения';
showSection('error');
}
}
if (success === 'true') {
showSection('success');
} else if (error) {
document.getElementById('error-message').textContent = error;
showSection('error');
} else if (token && userId) {
verifyEmail();
} else {
document.getElementById('error-message').textContent = 'Отсутствует токен подтверждения';
showSection('error');
}
</script>
</Layout>
<style>
.verify-page {
min-height: calc(100vh - 160px);
background: linear-gradient(135deg, #f5f7fa 0%, #e8ecf1 100%);
display: flex;
align-items: center;
justify-content: center;
padding: 6rem 2rem 2rem;
}
.verify-container {
width: 100%;
max-width: 440px;
}
.verify-card {
background: #ffffff;
border-radius: 16px;
padding: 1rem 1.25rem;
box-shadow: 0 10px 40px rgba(0, 0, 0, 0.1);
text-align: center;
}
.verify-icon {
width: 60px;
height: 60px;
background: linear-gradient(135deg, #10b981 0%, #059669 100%);
border-radius: 50%;
display: inline-flex;
align-items: center;
justify-content: center;
margin-bottom: 1rem;
}
.verify-icon.success {
background: linear-gradient(135deg, #10b981 0%, #059669 100%);
}
.verify-icon.error {
background: linear-gradient(135deg, #ef4444 0%, #dc2626 100%);
}
.verify-icon svg {
color: white;
}
.spinner {
width: 40px;
height: 40px;
border: 3px solid rgba(255,255,255,0.3);
border-top-color: white;
border-radius: 50%;
animation: spin 1s linear infinite;
}
@keyframes spin {
to { transform: rotate(360deg); }
}
.verify-card h1 {
color: #1e3050;
font-size: 1.5rem;
font-weight: 700;
margin: 0 0 1rem;
}
.verify-card p {
color: #64748b;
font-size: 0.95rem;
line-height: 1.6;
margin: 0 0 1.5rem;
}
.btn-primary {
display: inline-block;
background: linear-gradient(135deg, #eac26e 0%, #ce9f40 100%);
color: #ffffff;
border: none;
border-radius: 8px;
padding: 0.75rem 1.5rem;
font-size: 0.95rem;
font-weight: 700;
text-decoration: none;
cursor: pointer;
transition: all 0.3s ease;
}
.btn-primary:hover {
transform: translateY(-2px);
box-shadow: 0 8px 20px rgba(206, 159, 64, 0.4);
}
.hidden {
display: none !important;
}
</style>