import React, { useState, useCallback, useContext, useEffect, useRef, } from 'react'; import { AlertColor, Alert, AppBar, Box, Button, Dialog, DialogActions, DialogContent, DialogTitle, Link, TextField, Toolbar, } from '@mui/material'; import LoadingContext from './loading-context'; import SnackbarContext from './snackbar-context'; enum UserFormType { Login = 'Login', Register = 'Register', Update = 'Update', } interface UserFormProps { formType: UserFormType | null; close: (message?: string, severity?: AlertColor) => void; username?: string; } function UserForm({ username: propUsername, formType, close }: UserFormProps) { const { setLoading } = useContext(LoadingContext); const [username, setUsername] = useState(propUsername || ''); const [password, setPassword] = useState(''); const [errorOccurred, setError] = useState(false); const submitHandler = useCallback( (del: boolean) => { setLoading(true); setError(false); let method; let endpoint; if (del) { method = 'DELETE'; endpoint = '/users/delete'; } else { switch (formType) { case UserFormType.Login: method = 'POST'; endpoint = '/users/login'; break; case UserFormType.Register: method = 'POST'; endpoint = '/users/register'; break; case UserFormType.Update: method = 'PUT'; endpoint = '/users/update'; break; default: // NOTE: the value is not null when the dialog is open break; } } fetch(`${process.env.NODE_ENV === 'development' ? '//localhost:8080' : ''}${endpoint}`, { method, credentials: process.env.NODE_ENV === 'development' ? 'include' : 'same-origin', headers: { 'Content-Type': 'application/json', }, body: !del ? JSON.stringify({ username, password }) : undefined, }) .then((res) => { switch (res.status) { case 200: close(`Action '${del ? 'Delete' : formType}' successful!`, 'success'); break; default: setError(true); break; } }) .finally(() => setLoading(false)); }, [username, password, formType], ); return (
{ e.preventDefault(); submitHandler(false); }}> {formType} { setUsername(event.target.value); }} />
{ setPassword(event.target.value); }} /> {errorOccurred && Check your inputs!}
{formType === UserFormType.Update // TODO: add another confirm dialog here && ( )}
); } UserForm.defaultProps = { username: undefined }; function Footer() { const { status: snackbarInfo, setStatus: setSnackbarInfo } = useContext(SnackbarContext); const [username, setUsername] = useState(); const [tempUser, setTempUser] = useState(); const [dialogTypeOpen, setDialogTypeOpen] = useState(null); const isFirstRender = useRef(true); const logout = useCallback(() => { fetch(`${process.env.NODE_ENV === 'development' ? '//localhost:8080' : ''}/users/logout`, { method: 'DELETE', credentials: process.env.NODE_ENV === 'development' ? 'include' : 'same-origin', headers: { 'Content-Type': 'application/json', }, }) .then((res) => { switch (res.status) { case 200: setSnackbarInfo({ message: 'Logout successful!', severity: 'success', potentialUserChange: true }); setUsername(undefined); break; default: setSnackbarInfo({ message: 'An error occurred while trying to log out.', severity: 'error', potentialUserChange: false }); break; } }); }, [setSnackbarInfo]); useEffect(() => { // TODO: having the info if the user may have changed on the snackbar info // is a bit lazy and unclean; be better! if (isFirstRender.current || snackbarInfo?.potentialUserChange) { isFirstRender.current = false; fetch(`${process.env.NODE_ENV === 'development' ? '//localhost:8080' : ''}/users/info`, { method: 'GET', credentials: process.env.NODE_ENV === 'development' ? 'include' : 'same-origin', headers: { 'Content-Type': 'application/json', }, }) .then((res) => { switch (res.status) { case 200: res.json().then(({ username: user, temp }) => { setUsername(user); setTempUser(temp); }); break; default: setUsername(undefined); break; } }); } }, [snackbarInfo?.potentialUserChange]); return ( <> {username ? ( <> Logged in as: {' '} {username} {' '} {tempUser ? '(Temporary User. Edit to set a password!)' : undefined} {!tempUser && } ) : ( <> )} Legal Information (Impressum and Data Protection Regulation) setDialogTypeOpen(null)}> { setDialogTypeOpen(null); setSnackbarInfo((!!message && !!severity) ? { message, severity, potentialUserChange: true } : undefined); }} username={dialogTypeOpen === UserFormType.Update ? username : undefined} /> ); } export default Footer;