aboutsummaryrefslogtreecommitdiffstats
path: root/packages/meshbay-hub/src/meshbay_hub/static/auth-page.js
diff options
context:
space:
mode:
Diffstat (limited to 'packages/meshbay-hub/src/meshbay_hub/static/auth-page.js')
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/static/auth-page.js86
1 files changed, 81 insertions, 5 deletions
diff --git a/packages/meshbay-hub/src/meshbay_hub/static/auth-page.js b/packages/meshbay-hub/src/meshbay_hub/static/auth-page.js
index 1cca56f..860f890 100644
--- a/packages/meshbay-hub/src/meshbay_hub/static/auth-page.js
+++ b/packages/meshbay-hub/src/meshbay_hub/static/auth-page.js
@@ -68,16 +68,23 @@ export function LoginPage({ onLogin }) {
const [error, setError] = useState('');
const [loading, setLoading] = useState(false);
+ const [pendingVerif, setPendingVerif] = useState(false);
+
const onSubmit = async (e) => {
e.preventDefault();
if (!username || !password) return;
setError('');
+ setPendingVerif(false);
setLoading(true);
try {
await onLogin(username, password);
navigate('/');
} catch (err) {
- setError(err.message);
+ if (err.message === 'email_verification_required') {
+ setPendingVerif(true);
+ } else {
+ setError(err.message);
+ }
} finally {
setLoading(false);
}
@@ -95,6 +102,11 @@ export function LoginPage({ onLogin }) {
onInput=${e => setPassword(e.target.value)}
autocomplete="current-password" required />
${error && html`<div class="error-msg">${error}</div>`}
+ ${pendingVerif && html`
+ <div class="error-msg" style="background:var(--bg-secondary);border-left:3px solid var(--yellow, #f59e0b)">
+ <p>${t('login.pending_verification')}</p>
+ </div>
+ `}
<button type="submit" disabled=${loading}>
${loading ? t('login.loading') : t('login.submit')}
</button>
@@ -113,8 +125,11 @@ export function RegisterPage() {
const [password, setPassword] = useState('');
const [confirm, setConfirm] = useState('');
const [error, setError] = useState('');
- const [success, setSuccess] = useState(false);
+ const [phase, setPhase] = useState('form'); // form | verify | done
const [loading, setLoading] = useState(false);
+ const [code, setCode] = useState('');
+ const [verifying, setVerifying] = useState(false);
+ const [resent, setResent] = useState(false);
const onSubmit = async (e) => {
e.preventDefault();
@@ -136,7 +151,7 @@ export function RegisterPage() {
body: { username, email, password, pk_user_ed25519: '', pk_user_x25519: '' },
});
}
- setSuccess(true);
+ setPhase('verify');
} catch (err) {
setError(err.message);
} finally {
@@ -144,7 +159,53 @@ export function RegisterPage() {
}
};
- if (success) {
+ const onVerify = async (e) => {
+ e.preventDefault();
+ if (!code.trim()) return;
+ setError('');
+ setVerifying(true);
+ try {
+ await hubFetch('/v1/users/verify-email', {
+ method: 'POST',
+ body: { email, code: code.trim() },
+ });
+ setPhase('done');
+ } catch (err) {
+ setError(err.message);
+ } finally {
+ setVerifying(false);
+ }
+ };
+
+ const onResend = async () => {
+ setError('');
+ setResent(false);
+ try {
+ await hubFetch('/v1/users/register', {
+ method: 'POST',
+ body: { username, email, password, pk_user_ed25519: '', pk_user_x25519: '' },
+ });
+ setResent(true);
+ } catch (err) {
+ setError(err.message);
+ }
+ };
+
+ if (phase === 'done') {
+ return html`
+ <div class="page-center">
+ <div class="card login-card">
+ <h2>${t('register.verified_title')}</h2>
+ <p style="text-align:center; margin-bottom:16px; color:var(--text-secondary)">
+ ${t('register.verified_msg')}
+ </p>
+ <a href="#/login" style="display:block; text-align:center">${t('register.go_login')}</a>
+ </div>
+ </div>
+ `;
+ }
+
+ if (phase === 'verify') {
return html`
<div class="page-center">
<div class="card login-card">
@@ -152,7 +213,22 @@ export function RegisterPage() {
<p style="text-align:center; margin-bottom:16px; color:var(--text-secondary)">
${t('register.success_msg')}
</p>
- <a href="#/login" style="display:block; text-align:center">${t('register.go_login')}</a>
+ <form onSubmit=${onVerify}>
+ <input type="text" placeholder="${t('register.code_placeholder')}"
+ value=${code} onInput=${e => setCode(e.target.value)}
+ autocomplete="one-time-code" inputmode="numeric"
+ maxlength="6" required autofocus
+ style="text-align:center;font-size:1.4em;letter-spacing:0.3em" />
+ ${error && html`<div class="error-msg">${error}</div>`}
+ <button type="submit" disabled=${verifying}>
+ ${verifying ? t('register.verifying') : t('register.verify_btn')}
+ </button>
+ </form>
+ <div class="login-footer">
+ <button class="link-btn" onClick=${onResend}>${t('register.resend')}</button>
+ ${resent && html`<span style="color:var(--success);margin-left:8px">
+ ${t('register.resend_sent')}</span>`}
+ </div>
</div>
</div>
`;