Files
static-cms/core/src/backends/git-gateway/AuthenticationPage.tsx
2022-10-26 07:19:03 -04:00

227 lines
6.2 KiB
TypeScript

import Button from '@mui/material/Button';
import { styled } from '@mui/material/styles';
import TextField from '@mui/material/TextField';
import React, { useCallback, useEffect, useState } from 'react';
import AuthenticationPage from '../../components/UI/AuthenticationPage';
import { colors } from '../../components/UI/styles';
import type { ChangeEvent, FormEvent } from 'react';
import type { AuthenticationPageProps, TranslatedProps, User } from '../../interface';
const StyledAuthForm = styled('form')`
width: 350px;
display: flex;
flex-direction: column;
gap: 16px;
`;
const ErrorMessage = styled('div')`
color: ${colors.errorText};
`;
function useNetlifyIdentifyEvent(eventName: 'login', callback: (login: User) => void): void;
function useNetlifyIdentifyEvent(eventName: 'logout', callback: () => void): void;
function useNetlifyIdentifyEvent(eventName: 'error', callback: (err: Error) => void): void;
function useNetlifyIdentifyEvent(
eventName: 'login' | 'logout' | 'error',
// eslint-disable-next-line @typescript-eslint/no-explicit-any
callback: (input?: any) => void,
): void {
useEffect(() => {
window.netlifyIdentity?.on(eventName, callback);
}, [callback, eventName]);
}
export interface GitGatewayAuthenticationPageProps
extends TranslatedProps<AuthenticationPageProps> {
handleAuth: (email: string, password: string) => Promise<User | string>;
}
const GitGatewayAuthenticationPage = ({
inProgress = false,
config,
onLogin,
handleAuth,
t,
}: GitGatewayAuthenticationPageProps) => {
const [loggedIn, setLoggedIn] = useState(false);
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const [errors, setErrors] = useState<{
identity?: string;
server?: string;
email?: string;
password?: string;
}>({});
useEffect(() => {
if (!loggedIn && window.netlifyIdentity && window.netlifyIdentity.currentUser()) {
onLogin(window.netlifyIdentity.currentUser());
window.netlifyIdentity.close();
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
const handleIdentityLogin = useCallback(
(user: User) => {
onLogin(user);
window.netlifyIdentity?.close();
},
[onLogin],
);
useNetlifyIdentifyEvent('login', handleIdentityLogin);
const handleIdentityLogout = useCallback(() => {
window.netlifyIdentity?.open();
}, []);
useNetlifyIdentifyEvent('logout', handleIdentityLogout);
const handleIdentityError = useCallback(
(err: Error) => {
if (err?.message?.match(/^Failed to load settings from.+\.netlify\/identity$/)) {
window.netlifyIdentity?.close();
setErrors({ identity: t('auth.errors.identitySettings') });
}
},
[t],
);
useNetlifyIdentifyEvent('error', handleIdentityError);
const handleIdentity = useCallback(() => {
const user = window.netlifyIdentity?.currentUser();
if (user) {
onLogin(user);
} else {
window.netlifyIdentity?.open();
}
}, [onLogin]);
const handleEmailChange = useCallback((event: ChangeEvent<HTMLInputElement>) => {
setEmail(event.target.value);
}, []);
const handlePasswordChange = useCallback((event: ChangeEvent<HTMLInputElement>) => {
setPassword(event.target.value);
}, []);
const handleLogin = useCallback(
async (e: FormEvent<HTMLFormElement>) => {
e.preventDefault();
const validationErrors: typeof errors = {};
if (!email) {
validationErrors.email = t('auth.errors.email');
}
if (!password) {
validationErrors.password = t('auth.errors.password');
}
if (Object.keys(validationErrors).length > 0) {
setErrors(validationErrors);
return;
}
let response: User | string;
try {
response = await handleAuth(email, password);
} catch (e: unknown) {
if (e instanceof Error) {
response = e.message;
} else {
response = 'Unknown authentication error';
}
}
if (typeof response === 'string') {
setErrors({ server: response });
setLoggedIn(false);
return;
}
onLogin(response);
},
[email, handleAuth, onLogin, password, t],
);
if (window.netlifyIdentity) {
if (errors.identity) {
return (
<AuthenticationPage
logoUrl={config.logo_url}
siteUrl={config.site_url}
onLogin={handleIdentity}
pageContent={
<a
href="https://docs.netlify.com/visitor-access/git-gateway/#setup-and-settings"
target="_blank"
rel="noopener noreferrer"
>
{errors.identity}
</a>
}
t={t}
/>
);
} else {
return (
<AuthenticationPage
logoUrl={config.logo_url}
siteUrl={config.site_url}
onLogin={handleIdentity}
buttonContent={t('auth.loginWithNetlifyIdentity')}
t={t}
/>
);
}
}
return (
<AuthenticationPage
logoUrl={config.logo_url}
siteUrl={config.site_url}
pageContent={
<StyledAuthForm onSubmit={handleLogin}>
{!errors.server ? null : <ErrorMessage>{String(errors.server)}</ErrorMessage>}
<TextField
type="text"
name="email"
label="Email"
value={email}
onChange={handleEmailChange}
fullWidth
variant="outlined"
error={Boolean(errors.email)}
helperText={errors.email ?? undefined}
/>
<TextField
type="password"
name="password"
label="Password"
value={password}
onChange={handlePasswordChange}
fullWidth
variant="outlined"
error={Boolean(errors.password)}
helperText={errors.password ?? undefined}
/>
<Button
variant="contained"
type="submit"
disabled={inProgress}
sx={{ width: 120, alignSelf: 'center' }}
>
{inProgress ? t('auth.loggingIn') : t('auth.login')}
</Button>
</StyledAuthForm>
}
t={t}
/>
);
};
export default GitGatewayAuthenticationPage;