Feature: E-Mail-Verifikation + Forum öffentlich lesbar + Launch-Vorbereitung
- Forum ohne requiresAuth: öffentlich lesbar, Schreiben weiter via API-Guard
- E-Mail-Verifikation: Token bei Registrierung, support@-Mail, /verify-email/{token}
- Verifikations-Banner (orange, dismissible) wenn email_verified=0
- Grüner Haken / "Nicht bestätigt"-Chip in Settings
- POST /auth/resend-verification für Chip und Banner
- DB-Migration: users.verification_token TEXT
- SW by-v575, APP_VER 552
This commit is contained in:
parent
e79290edb7
commit
b9ee67b8dd
7 changed files with 137 additions and 11 deletions
|
|
@ -3,7 +3,7 @@
|
|||
Router, State-Management, Navigation, Initialisierung.
|
||||
============================================================ */
|
||||
|
||||
const APP_VER = '551'; // ← bei jedem Deploy mit Frontend-Änderungen erhöhen
|
||||
const APP_VER = '552'; // ← bei jedem Deploy mit Frontend-Änderungen erhöhen
|
||||
const APP_VERSION = '1.1.4'; // ← semantische Version, wird bei make release gesetzt
|
||||
const IS_STAGING = location.hostname === 'staging.banyaro.app';
|
||||
|
||||
|
|
@ -45,7 +45,7 @@ const App = (() => {
|
|||
poison: { title: 'Giftköder-Alarm', module: null },
|
||||
walks: { title: 'Gassi-Treffen', module: null, requiresAuth: true },
|
||||
sitting: { title: 'Sitting', module: null, requiresAuth: true },
|
||||
forum: { title: 'Forum', module: null, requiresAuth: true },
|
||||
forum: { title: 'Forum', module: null },
|
||||
wiki: { title: 'Wiki', module: null },
|
||||
knigge: { title: 'Knigge', module: null },
|
||||
movies: { title: 'Filme', module: null },
|
||||
|
|
@ -473,6 +473,7 @@ const App = (() => {
|
|||
navigate('onboarding');
|
||||
}
|
||||
|
||||
_showVerifyBanner();
|
||||
_updateNotifBadge();
|
||||
_updateChatBadge();
|
||||
_checkNearbyAlerts();
|
||||
|
|
@ -551,6 +552,28 @@ const App = (() => {
|
|||
navigate('welcome', false);
|
||||
}
|
||||
|
||||
function _showVerifyBanner() {
|
||||
const banner = document.getElementById('verify-banner');
|
||||
if (!banner) return;
|
||||
if (!state.user || state.user.email_verified) {
|
||||
banner.style.display = 'none';
|
||||
return;
|
||||
}
|
||||
const dismissed = sessionStorage.getItem('by_verify_dismissed');
|
||||
if (dismissed) return;
|
||||
banner.style.display = 'flex';
|
||||
|
||||
document.getElementById('verify-resend-btn')?.addEventListener('click', async () => {
|
||||
await API.post('/auth/resend-verification', {});
|
||||
UI.toast.success('Bestätigungs-Mail erneut gesendet.');
|
||||
}, { once: true });
|
||||
|
||||
document.getElementById('verify-banner-close')?.addEventListener('click', () => {
|
||||
banner.style.display = 'none';
|
||||
sessionStorage.setItem('by_verify_dismissed', '1');
|
||||
}, { once: true });
|
||||
}
|
||||
|
||||
function _updateHeaderUserBtn(loggedIn) {
|
||||
const btn = document.getElementById('header-user-btn');
|
||||
const icon = document.getElementById('header-user-icon');
|
||||
|
|
@ -800,6 +823,18 @@ const App = (() => {
|
|||
hashParams[k] = isNaN(v) ? v : Number(v);
|
||||
});
|
||||
}
|
||||
|
||||
// E-Mail-Verifikation: Redirect von /api/auth/verify-email/{token}
|
||||
if (hashParams.verified === '1' || hashParams.verified === 1) {
|
||||
if (state.user) state.user.email_verified = 1;
|
||||
document.getElementById('verify-banner')?.style?.setProperty('display', 'none');
|
||||
UI.toast.success('E-Mail-Adresse erfolgreich bestätigt!');
|
||||
history.replaceState(null, '', '/');
|
||||
} else if (hashParams.verified === 'error') {
|
||||
UI.toast.error('Ungültiger oder abgelaufener Bestätigungs-Link.');
|
||||
history.replaceState(null, '', '/');
|
||||
}
|
||||
|
||||
const startPage = (hashPage && pages[hashPage]) ? hashPage : 'welcome';
|
||||
// Nicht eingeloggte User immer zur Welcome-Seite — auch bei direktem Link auf Forum, Map etc.
|
||||
navigate(state.user ? startPage : 'welcome', false, hashParams);
|
||||
|
|
|
|||
|
|
@ -138,7 +138,15 @@ window.Page_settings = (() => {
|
|||
style="display:none">
|
||||
<div>
|
||||
<div style="font-weight:700;font-size:var(--text-lg)">${_esc(u.name)}</div>
|
||||
<div style="color:var(--c-text-secondary);font-size:var(--text-sm)">${_esc(u.email)}</div>
|
||||
<div style="display:flex;align-items:center;gap:var(--space-2);color:var(--c-text-secondary);font-size:var(--text-sm)">
|
||||
${_esc(u.email)}
|
||||
${u.email_verified
|
||||
? `<svg class="ph-icon" aria-hidden="true" style="width:14px;height:14px;color:#22c55e" title="Bestätigt"><use href="/icons/phosphor.svg#check-circle"></use></svg>`
|
||||
: `<span id="settings-verify-chip"
|
||||
style="font-size:10px;background:#fef3c7;color:#d97706;padding:1px 7px;
|
||||
border-radius:999px;cursor:pointer;white-space:nowrap"
|
||||
title="E-Mail noch nicht bestätigt">Nicht bestätigt</span>`}
|
||||
</div>
|
||||
<div style="display:flex;flex-wrap:wrap;gap:var(--space-1);margin-top:var(--space-1)">
|
||||
${u.is_premium
|
||||
? `<span class="badge badge-primary">
|
||||
|
|
@ -480,6 +488,12 @@ window.Page_settings = (() => {
|
|||
});
|
||||
|
||||
// Avatar-Hover-Overlay
|
||||
// E-Mail-Verifikation: Chip → erneut senden
|
||||
document.getElementById('settings-verify-chip')?.addEventListener('click', async () => {
|
||||
await API.post('/auth/resend-verification', {});
|
||||
UI.toast.success('Bestätigungs-Mail gesendet — bitte prüfe dein Postfach.');
|
||||
});
|
||||
|
||||
const avatarBtn = document.getElementById('settings-avatar-btn');
|
||||
const avatarOverlay = avatarBtn?.querySelector('.avatar-overlay');
|
||||
if (avatarBtn && avatarOverlay) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue