pdf-quiz-generator/frontend/src/pages/VerifyEmailPage.jsx
Daniel b2ddee74dc fix: sticky was disabled site-wide, and 100vh is wrong on iOS
`html, body { overflow-x: hidden }` makes both a scroll container, and a
`position: sticky` descendant then sticks to that rather than to the
viewport — which is to say it does not stick at all. Every sticky thing
in the app was affected: the session rail, the settings nav, the article
column, the study-plan rail. `overflow-x: clip` does the same job without
becoming a scroll container. Hidden stays as the fallback, so a browser
without `clip` still cannot be scrolled sideways and only loses
stickiness, which is the lesser fault.

Putting the rail away destroyed the layout. The collapsed grid was
`0 minmax(0, 1fr)` and the rail is `display: none`, so the content
became the *first* grid item and landed in the zero-width column —
wrapping one word per line beside an empty page. One column when there
is one thing in it.

100vh is the largest viewport on iOS — the one with the URL bar hidden —
so anything sized to it is taller than the screen really is and its
bottom sits behind the bar. Eleven files now use 100dvh, which tracks
the viewport as it changes.

The AI Mode composer was the one bottom-sticky bar with no safe-area
inset; its send button sat under the home indicator.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TqXevQJhxFrM7jJg82cgZN
2026-09-12 00:46:06 +02:00

43 lines
1.9 KiB
JavaScript

import { useState, useEffect } from 'react'
import { useSearchParams, Link } from 'react-router-dom'
import api from '../api/client'
export default function VerifyEmailPage() {
const [searchParams] = useSearchParams()
const token = searchParams.get('token')
const [status, setStatus] = useState('verifying') // verifying | success | error
const [message, setMessage] = useState('')
useEffect(() => {
if (!token) { setStatus('error'); setMessage('No verification token provided.'); return }
api.get(`/auth/verify-email?token=${token}`)
.then(res => { setStatus('success'); setMessage(res.data.message) })
.catch(err => { setStatus('error'); setMessage(err.response?.data?.detail || 'Verification failed.') })
}, [token])
return (
<div style={{ minHeight: '100dvh', display: 'flex', alignItems: 'center', justifyContent: 'center', background: '#f1f5f9' }}>
<div className="card" style={{ maxWidth: 420, width: '100%', textAlign: 'center' }}>
{status === 'verifying' && (
<><div className="spinner" style={{ margin: '0 auto 16px' }}></div><p>Verifying your email...</p></>
)}
{status === 'success' && (
<>
<div style={{ fontSize: '3rem', marginBottom: 12 }}></div>
<h2 style={{ color: '#166534', marginBottom: 8 }}>Email Verified!</h2>
<p style={{ color: '#64748b', marginBottom: 24 }}>{message}</p>
<Link to="/login" className="btn btn-primary">Log In</Link>
</>
)}
{status === 'error' && (
<>
<div style={{ fontSize: '3rem', marginBottom: 12 }}></div>
<h2 style={{ color: '#dc2626', marginBottom: 8 }}>Verification Failed</h2>
<p style={{ color: '#64748b', marginBottom: 24 }}>{message}</p>
<Link to="/login" className="btn btn-secondary">Back to Login</Link>
</>
)}
</div>
</div>
)
}