Final Feature 9c #10
|
|
@ -86,6 +86,18 @@ export function AuthProvider({ children }) {
|
||||||
return data
|
return data
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const setAuthFromToken = (token, profile) => {
|
||||||
|
// Direct token/profile set (for email verification auto-login)
|
||||||
|
localStorage.setItem(TOKEN_KEY, token)
|
||||||
|
localStorage.setItem(PROFILE_KEY, profile.id)
|
||||||
|
setSession({
|
||||||
|
token,
|
||||||
|
profile_id: profile.id,
|
||||||
|
role: profile.role || 'user',
|
||||||
|
profile
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
const logout = async () => {
|
const logout = async () => {
|
||||||
const token = localStorage.getItem(TOKEN_KEY)
|
const token = localStorage.getItem(TOKEN_KEY)
|
||||||
if (token) {
|
if (token) {
|
||||||
|
|
@ -102,7 +114,7 @@ export function AuthProvider({ children }) {
|
||||||
return (
|
return (
|
||||||
<AuthContext.Provider value={{
|
<AuthContext.Provider value={{
|
||||||
session, loading, needsSetup,
|
session, loading, needsSetup,
|
||||||
login, setup, logout,
|
login, setup, logout, setAuthFromToken,
|
||||||
isAdmin, canUseAI, canExport,
|
isAdmin, canUseAI, canExport,
|
||||||
token: session?.token,
|
token: session?.token,
|
||||||
profileId: session?.profile_id,
|
profileId: session?.profile_id,
|
||||||
|
|
|
||||||
|
|
@ -7,9 +7,9 @@ export default function Verify() {
|
||||||
const [searchParams] = useSearchParams()
|
const [searchParams] = useSearchParams()
|
||||||
const token = searchParams.get('token')
|
const token = searchParams.get('token')
|
||||||
const navigate = useNavigate()
|
const navigate = useNavigate()
|
||||||
const { login } = useAuth()
|
const { setAuthFromToken } = useAuth()
|
||||||
|
|
||||||
const [status, setStatus] = useState('loading') // loading | success | error | expired
|
const [status, setStatus] = useState('loading') // loading | success | error | expired | already_verified
|
||||||
const [error, setError] = useState(null)
|
const [error, setError] = useState(null)
|
||||||
const [email, setEmail] = useState('')
|
const [email, setEmail] = useState('')
|
||||||
const [resending, setResending] = useState(false)
|
const [resending, setResending] = useState(false)
|
||||||
|
|
@ -27,8 +27,8 @@ export default function Verify() {
|
||||||
const result = await api.verifyEmail(token)
|
const result = await api.verifyEmail(token)
|
||||||
|
|
||||||
// Auto-login with returned token
|
// Auto-login with returned token
|
||||||
if (result.token) {
|
if (result.token && result.profile) {
|
||||||
login(result.token, result.profile)
|
setAuthFromToken(result.token, result.profile)
|
||||||
setStatus('success')
|
setStatus('success')
|
||||||
|
|
||||||
// Redirect to dashboard after 2 seconds
|
// Redirect to dashboard after 2 seconds
|
||||||
|
|
@ -42,8 +42,14 @@ export default function Verify() {
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
const errorMsg = err.message || 'Verifizierung fehlgeschlagen'
|
const errorMsg = err.message || 'Verifizierung fehlgeschlagen'
|
||||||
|
|
||||||
|
// Check if already verified
|
||||||
|
if (errorMsg.includes('bereits bestätigt') || errorMsg.includes('already verified')) {
|
||||||
|
setStatus('already_verified')
|
||||||
|
// Auto-redirect to login after 3 seconds
|
||||||
|
setTimeout(() => navigate('/login'), 3000)
|
||||||
|
}
|
||||||
// Check if token expired
|
// Check if token expired
|
||||||
if (errorMsg.includes('abgelaufen') || errorMsg.includes('expired')) {
|
else if (errorMsg.includes('abgelaufen') || errorMsg.includes('expired')) {
|
||||||
setStatus('expired')
|
setStatus('expired')
|
||||||
setError(errorMsg)
|
setError(errorMsg)
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -54,7 +60,7 @@ export default function Verify() {
|
||||||
}
|
}
|
||||||
|
|
||||||
verify()
|
verify()
|
||||||
}, [token, login, navigate])
|
}, [token, setAuthFromToken, navigate])
|
||||||
|
|
||||||
const handleResend = async () => {
|
const handleResend = async () => {
|
||||||
if (!email.trim()) {
|
if (!email.trim()) {
|
||||||
|
|
@ -177,6 +183,40 @@ export default function Verify() {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (status === 'already_verified') {
|
||||||
|
return (
|
||||||
|
<div style={{
|
||||||
|
maxWidth:420, margin:'0 auto', padding:'60px 20px',
|
||||||
|
textAlign:'center'
|
||||||
|
}}>
|
||||||
|
<div style={{
|
||||||
|
background:'var(--accent-light)',
|
||||||
|
border:'2px solid var(--accent)',
|
||||||
|
borderRadius:16, padding:'40px 24px', marginBottom:24
|
||||||
|
}}>
|
||||||
|
<div style={{fontSize:48, marginBottom:16}}>✓</div>
|
||||||
|
<h2 style={{marginBottom:12, color:'var(--accent-dark)'}}>
|
||||||
|
E-Mail bereits bestätigt
|
||||||
|
</h2>
|
||||||
|
<p style={{color:'var(--text2)', lineHeight:1.6, marginBottom:24}}>
|
||||||
|
Deine E-Mail-Adresse wurde bereits verifiziert.
|
||||||
|
Du kannst dich jetzt anmelden.
|
||||||
|
</p>
|
||||||
|
<p style={{fontSize:13, color:'var(--text3)'}}>
|
||||||
|
Du wirst gleich zum Login weitergeleitet...
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button
|
||||||
|
onClick={() => navigate('/login')}
|
||||||
|
className="btn btn-primary btn-full"
|
||||||
|
>
|
||||||
|
Jetzt anmelden
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
if (status === 'error') {
|
if (status === 'error') {
|
||||||
return (
|
return (
|
||||||
<div style={{
|
<div style={{
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user