All files / core/blong-browser/src/components/Error Error.tsx

82.35% Statements 14/17
73.33% Branches 11/15
71.42% Functions 5/7
84.61% Lines 11/13

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                            8x                               2x       80x 80x 25x 25x   25x   2x   2x         2x                                     2x                                                  
/**
 * Error — global error dialog.
 */
import {Dialog} from '../../primereact/index.js';
 
import {useBlong} from '../../context/BlongContext.js';
import {useAppStore} from '../../state/appStore.js';
import {Button} from '../Button/Button.js';
 
/**
 * Error types that indicate an expired or invalid session.  The primary path
 * for these is the LoginPopup (raised by `wrapHandlerProxy`); this dialog is
 * the fallback when a 401 is surfaced directly via `showError`.
 */
const AUTH_ERROR_TYPES = new Set([
    'identity.unauthenticated',
    'identity.invalidCredentials',
    'identity.sessionExpired',
    'rpc.jwtInvalid',
    'rpc.refreshFailed',
    'gateway.jwtMissingHeader',
    'login.refreshTokenExpired',
    'login.sessionNotFound',
    'login.sessionRevoked',
    'login.sessionInactive',
    'login.sessionExpired',
    'login.invalidCookie',
]);
 
function isAuthError(type?: string) {
    return !!type && AUTH_ERROR_TYPES.has(type);
}
 
export function ErrorDialog() {
    const error = useAppStore(s => s.error);
    const clearError = useAppStore(s => s.clearError);
    const {config: {portal}} = useBlong();
    const loginRoute = portal?.loginRoute;
 
    if (!error) return null;
 
    const unauthorized = isAuthError(error.type);
 
    const handleLogin = () => {
        clearError();
        if (loginRoute) window.location.href = loginRoute;
    };
 
    return (
        <Dialog
            visible
            header={
                <span className="blong-error-dialog__title">
                    <i className="pi pi-exclamation-circle blong-error-dialog__icon" /> Error
                </span>
            }
            onHide={unauthorized ? () => {} : clearError}
            closable={!unauthorized}
            className="blong-error-dialog"
            style={{width: '480px'}}
            modal
        >
            <div className="blong-error-dialog__body">
                <p className="blong-error-dialog__message">{error.print ?? error.message}</p>
                {error.validation && error.validation.length > 0 && (
                    <ul className="blong-error-dialog__validation">
                        {error.validation.map(v => (
                            <li key={v.field}>
                                <strong>{v.field}:</strong> {v.message}
                            </li>
                        ))}
                    </ul>
                )}
            </div>
            <div className="blong-error-dialog__footer">
                {unauthorized ? (
                    <Button
                        label="Login"
                        icon="pi pi-sign-in"
                        onClick={handleLogin}
                    />
                ) : (
                    <Button
                        label="Close"
                        icon="pi pi-times"
                        onClick={clearError}
                    />
                )}
            </div>
        </Dialog>
    );
}