Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 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 99 100 101 102 103 104 105 106 107 | 16x 16x 4x 4x 4x 4x 4x 4x | /**
* LoginPopup — modal re-authentication prompt.
*
* Shown when an operation fails with an expired/invalid session (401) and the
* client-side token renewal could not refresh it (e.g. the session was closed
* server-side). The user logs in here and then re-invokes the failed
* operation — there is deliberately NO automatic retry of the original call.
*
* Wired through the store's `loginPrompt` flag, which `wrapHandlerProxy`
* raises on auth-classified errors.
*/
import './LoginPopup.css';
import {Dialog, InputText, Message, Password} from '../../primereact/index.js';
import {useState} from 'react';
import {useBlong} from '../../context/BlongContext.js';
import {useAppStore} from '../../state/appStore.js';
import {Button} from '../Button/Button.js';
export function LoginPopup() {
const prompt = useAppStore(s => s.loginPrompt);
const setLoginPrompt = useAppStore(s => s.setLoginPrompt);
const {handler} = useBlong();
const [username, setUsername] = useState('');
const [password, setPassword] = useState('');
const [error, setError] = useState<string | undefined>(undefined);
const [loading, setLoading] = useState(false);
Eif (!prompt) return null;
const close = () => {
setLoginPrompt(false);
setError(undefined);
setPassword('');
};
const onSubmit = async () => {
setLoading(true);
setError(undefined);
try {
const result = (await handler.authLogin(
{username, password},
{},
)) as {step?: string; error?: string};
if (result.step === 'success') {
close();
} else {
setError(result.error ?? 'Login failed');
}
} catch (err) {
setError((err as {message?: string}).message ?? 'Login failed');
} finally {
setLoading(false);
}
};
return (
<Dialog
visible
header="Session expired — please log in"
onHide={close}
closable
modal
className="blong-login-popup"
style={{width: '380px'}}
>
<div className="blong-login-popup__body">
{error && (
<Message
severity="error"
text={error}
className="blong-login-popup__error"
/>
)}
<div className="blong-login-popup__field">
<label htmlFor="blong-login-popup-username">Username</label>
<InputText
id="blong-login-popup-username"
name="username"
value={username}
onChange={e => setUsername(e.target.value)}
onKeyDown={e => e.key === 'Enter' && onSubmit()}
autoFocus
/>
</div>
<div className="blong-login-popup__field">
<label htmlFor="blong-login-popup-password">Password</label>
<Password
id="blong-login-popup-password"
name="password"
value={password}
onChange={e => setPassword(e.target.value)}
onKeyDown={e => e.key === 'Enter' && onSubmit()}
feedback={false}
toggleMask
/>
</div>
</div>
<div className="blong-login-popup__footer">
<Button label="Cancel" icon="pi pi-times" onClick={close} outlined />
<Button label="Login" icon="pi pi-sign-in" onClick={onSubmit} loading={loading} />
</div>
</Dialog>
);
}
|