File size: 4,618 Bytes
1337ed3
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
import { useEffect, useState } from 'react';
import { API_URL } from '../config';
import { saveSession } from '../lib/session';
import { ROUTES } from '../lib/routes';
import MarketingHeader from './layout/MarketingHeader';
import { useLanguage } from '../i18n';

export default function VerifyEmailPage() {
  const { t } = useLanguage();
  const [status, setStatus] = useState('verifying');

  useEffect(() => {
    const params = new URLSearchParams(window.location.search);
    const token = params.get('token');
    if (!token) {
      setStatus('no-token');
      return;
    }
    fetch(`${API_URL}/owners/verify`, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ token }),
      })
      .then(async (res) => {
        if (!res.ok) {
          const err = await res.json().catch(() => ({}));
          throw new Error(err.detail || 'Verification failed');
        }
        const data = await res.json();
        const session = { owner: data.owner, token: data.token, expires_at: data.expires_at };
        saveSession(session);
        setStatus('success');
      })
      .catch((err) => {
        console.error('Verify email error:', err);
        setStatus('error');
      });
  }, []);

  return (
    <div className="bg-surface-container-low min-h-screen flex flex-col">
      <MarketingHeader />
      <div className="flex-1 flex flex-col items-center justify-center p-sm">
        <div className="w-full max-w-[400px] bg-surface-container-lowest border border-hairline-border rounded-xl p-lg flex flex-col items-center shadow-sm text-center animate-fade-in">

          {status === 'verifying' && (
            <>
              <div className="w-16 h-16 bg-primary/10 rounded-full flex items-center justify-center mb-lg">
                <span className="material-symbols-outlined text-primary text-[36px] animate-spin">progress_activity</span>
              </div>
              <h1 className="font-headline-sm text-headline-sm text-on-surface mb-sm">{t('verifyEmail.verifying')}</h1>
            </>
          )}

          {status === 'success' && (
            <>
              <div className="w-16 h-16 bg-green-100 rounded-full flex items-center justify-center mb-lg">
                <span className="material-symbols-outlined text-green-600 text-[36px]" style={{ fontVariationSettings: "'FILL' 1" }}>check_circle</span>
              </div>
              <h1 className="font-headline-sm text-headline-sm text-on-surface mb-sm">{t('verifyEmail.success')}</h1>
              <p className="font-body-md text-body-md text-on-surface-variant mb-lg">{t('verifyEmail.successDesc')}</p>
              <a href={ROUTES.onboarding} className="bg-primary text-on-primary px-lg py-sm rounded-lg font-label-md text-label-md hover:opacity-90 transition-all no-underline">
                {t('verifyEmail.continueOnboarding')}
              </a>
            </>
          )}

          {status === 'error' && (
            <>
              <div className="w-16 h-16 bg-red-100 rounded-full flex items-center justify-center mb-lg">
                <span className="material-symbols-outlined text-red-600 text-[36px]" style={{ fontVariationSettings: "'FILL' 1" }}>error</span>
              </div>
              <h1 className="font-headline-sm text-headline-sm text-on-surface mb-sm">{t('verifyEmail.failed')}</h1>
              <p className="font-body-md text-body-md text-on-surface-variant mb-lg">{t('verifyEmail.failedDesc')}</p>
              <a href={ROUTES.login} className="bg-primary text-on-primary px-lg py-sm rounded-lg font-label-md text-label-md hover:opacity-90 transition-all no-underline">
                {t('verifyEmail.goToLogin')}
              </a>
            </>
          )}

          {status === 'no-token' && (
            <>
              <div className="w-16 h-16 bg-orange-100 rounded-full flex items-center justify-center mb-lg">
                <span className="material-symbols-outlined text-orange-600 text-[36px]">link_off</span>
              </div>
              <h1 className="font-headline-sm text-headline-sm text-on-surface mb-sm">{t('verifyEmail.missingToken')}</h1>
              <p className="font-body-md text-body-md text-on-surface-variant mb-lg">{t('verifyEmail.missingTokenDesc')}</p>
              <a href={ROUTES.login} className="bg-primary text-on-primary px-lg py-sm rounded-lg font-label-md text-label-md hover:opacity-90 transition-all no-underline">
                {t('verifyEmail.goToLogin')}
              </a>
            </>
          )}
        </div>
      </div>
    </div>
  );
}