refactor(auth): migrate login, account, user and error screens to v3

- Login/forgot/reset, create/edit user, profile: Field/Dialog/Toaster
  shims, colorPalette/button renames, typed hookstate handlers
- DeleteDialogue, NotFound, SomethingWentWrong: dialog + centered
  layout on v3 tokens with legacy copy intact
This commit is contained in:
2026-09-06 10:31:23 -04:00
parent 0919295843
commit 54debe4b0a
10 changed files with 180 additions and 236 deletions
+26 -33
View File
@@ -3,13 +3,9 @@ import agent from '../api/agent'
import { useNavigate } from 'react-router-dom' import { useNavigate } from 'react-router-dom'
import { Data } from '../models/game' import { Data } from '../models/game'
import { import {
AlertDialog, Button, Text
AlertDialogBody,
AlertDialogContent, AlertDialogFooter,
AlertDialogHeader,
AlertDialogOverlay,
Button, Icon, Text
} from '@chakra-ui/react' } from '@chakra-ui/react'
import {DialogBody, DialogContent, DialogFooter, DialogHeader, DialogRoot} from './ui/dialog'
type Props = { type Props = {
id: string id: string
@@ -44,34 +40,31 @@ export default function DeleteDialogue({
} }
} }
const cancelRef = useRef(null) const cancelRef = useRef<HTMLButtonElement | null>(null)
return ( return (
<AlertDialog isOpen={open} leastDestructiveRef={cancelRef} onClose={handleClose}> <DialogRoot open={open} onOpenChange={(e) => { if (!e.open) handleClose() }} role="alertdialog" initialFocusEl={() => cancelRef.current}>
<AlertDialogOverlay> <DialogContent>
<AlertDialogContent> <DialogHeader fontSize='lg' fontWeight='bold'>Delete?</DialogHeader>
<DialogBody>
<AlertDialogHeader fontSize='lg' fontWeight='bold'>Delete?</AlertDialogHeader> Are you sure you would like to delete <strong>{game.title}</strong>?
<AlertDialogBody> </DialogBody>
Are you sure you would like to delete <strong>{game.title}</strong>? <DialogFooter>
</AlertDialogBody> <Button ref={cancelRef} onMouseDown={handleClose}>
<AlertDialogFooter> <Text mt='1'>No</Text>
<Button ref={cancelRef} onMouseDown={handleClose}> </Button>
<Icon name='remove' mr='1' /> <Text mt='1'>No</Text> <Button
</Button> colorPalette='red'
<Button onMouseDown={() => {
colorScheme='red' deleteGame(id)
onMouseDown={() => { }}
deleteGame(id) ml={3}
}} autoFocus
ml={3} >
autoFocus <Text mt='1'>Yes</Text>
> </Button>
<Icon name='checkmark' mr='1' /> <Text mt='1'>Yes</Text> </DialogFooter>
</Button> </DialogContent>
</AlertDialogFooter> </DialogRoot>
</AlertDialogContent>
</AlertDialogOverlay>
</AlertDialog>
) )
} }
+3 -2
View File
@@ -1,5 +1,6 @@
import React from 'react' import React from 'react'
import { Checkbox, Text } from '@chakra-ui/react' import { Text } from '@chakra-ui/react'
import {Checkbox} from '../ui/checkbox'
import { adminModeToggle, loggedInUser, adminMode } from '../../stateManagement/userState' import { adminModeToggle, loggedInUser, adminMode } from '../../stateManagement/userState'
import { useHookstate } from '@hookstate/core' import { useHookstate } from '@hookstate/core'
@@ -8,7 +9,7 @@ export default function AdminMode() {
const admin = useHookstate(adminMode).get() const admin = useHookstate(adminMode).get()
return ( return (
<Checkbox size={'lg'} onChange={() => adminModeToggle()} isChecked={admin} isDisabled={!(user.role === 'admin')}> <Checkbox colorPalette="blue" size={'lg'} onCheckedChange={() => adminModeToggle()} checked={admin} disabled={!(user.role === 'admin')}>
<Text mt={'1'}>Administrator Mode</Text> <Text mt={'1'}>Administrator Mode</Text>
</Checkbox> </Checkbox>
) )
@@ -3,11 +3,11 @@ import { useForm } from 'react-hook-form'
import { import {
Container, Container,
Button, Button,
FormControl,
FormLabel,
Input, Input,
useColorModeValue, FormErrorMessage, useToast,
} from '@chakra-ui/react' } from '@chakra-ui/react'
import {Field} from '../ui/field'
import {useColorModeValue} from '../ui/color-mode'
import {toaster} from '../ui/toaster'
import agent from '../../api/agent' import agent from '../../api/agent'
import { IForgotPassword } from '../../models/user' import { IForgotPassword } from '../../models/user'
@@ -18,7 +18,6 @@ export default function ForgotPassword() {
handleSubmit, handleSubmit,
formState: { errors, isSubmitting, isDirty }, formState: { errors, isSubmitting, isDirty },
} = useForm() } = useForm()
const toast = useToast()
interface Message { interface Message {
success: boolean success: boolean
@@ -27,27 +26,25 @@ export default function ForgotPassword() {
const onSubmit = handleSubmit(async (values) => { const onSubmit = handleSubmit(async (values) => {
const message = await agent.Account.forgot(values as IForgotPassword) as Message const message = await agent.Account.forgot(values as IForgotPassword) as Message
toast({ toaster.create({
title: 'Email Sent', title: 'Email Sent',
status: 'success', type: 'success',
description: message.data, description: message.data,
isClosable: true, closable: true,
duration: 10000, duration: 10000,
position: 'top'
}) })
}) })
return ( return (
<Container style={{ marginTop: '7rem', paddingBottom: '5rem' }}> <Container style={{ marginTop: '7rem', paddingBottom: '5rem' }}>
<form onSubmit={onSubmit}> <form onSubmit={onSubmit}>
<FormControl isInvalid={Boolean(errors.email)} mb={'3'}> <Field label="Email" invalid={Boolean(errors.email)} errorText={errors.email?.type === 'required' ? errors.email.message?.toString() : errors.email?.type === 'pattern' ? 'Invalid Email Address' : undefined} mb={'3'}>
<FormLabel htmlFor="email">Email</FormLabel>
<Input <Input
id="email" id="email"
bg={bg} bg={bg}
_placeholder={{ color: 'gray.500' }} _placeholder={{ color: 'gray.500' }}
border="1px" borderWidth="1px" borderStyle="solid"
borderColor="gray.500" borderColor={{ base: "gray.500", _invalid: "red.500" }}
rounded="md" rounded="md"
placeholder="Email" placeholder="Email"
{...register('email', { {...register('email', {
@@ -55,16 +52,13 @@ export default function ForgotPassword() {
pattern: /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i, pattern: /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i,
})} })}
/> />
<FormErrorMessage> </Field>
{errors.email?.type === 'required' && errors.email.message?.toString()}
{errors.email?.type === 'pattern' && 'Invalid Email Address'}
</FormErrorMessage>
</FormControl>
<br/> <br/>
<Button <Button
type="submit" type="submit"
colorPalette="blue"
disabled={!isDirty} disabled={!isDirty}
isLoading={isSubmitting} loading={isSubmitting}
> >
Submit Submit
</Button> </Button>
+14 -23
View File
@@ -5,11 +5,10 @@ import { login } from '../../stateManagement/userState'
import { import {
Container, Container,
Button, Button,
FormControl, Input, HStack, Center,
FormLabel,
Input,
useColorModeValue, HStack, Center, FormErrorMessage,
} from '@chakra-ui/react' } from '@chakra-ui/react'
import {Field} from '../ui/field'
import {useColorModeValue} from '../ui/color-mode'
import { Link } from 'react-router-dom' import { Link } from 'react-router-dom'
export default function LoginForm() { export default function LoginForm() {
@@ -38,14 +37,13 @@ export default function LoginForm() {
return ( return (
<Container style={{ marginTop: '7rem', paddingBottom: '5rem' }}> <Container style={{ marginTop: '7rem', paddingBottom: '5rem' }}>
<form onSubmit={onSubmit}> <form onSubmit={onSubmit}>
<FormControl isInvalid={Boolean(errors.email)} mb={'3'}> <Field label="Email" invalid={Boolean(errors.email)} errorText={errors.email?.type === 'required' ? errors.email.message?.toString() : errors.email?.type === 'pattern' ? 'Invalid Email Address' : undefined} mb={'3'}>
<FormLabel htmlFor="email">Email</FormLabel>
<Input <Input
id="email" id="email"
bg={bg} bg={bg}
_placeholder={{ color: 'gray.500' }} _placeholder={{ color: 'gray.500' }}
border="1px" borderWidth="1px" borderStyle="solid"
borderColor="gray.500" borderColor={{ base: "gray.500", _invalid: "red.500" }}
rounded="md" rounded="md"
placeholder="Email" placeholder="Email"
{...register('email', { {...register('email', {
@@ -53,40 +51,33 @@ export default function LoginForm() {
pattern: /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i, pattern: /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i,
})} })}
/> />
<FormErrorMessage> </Field>
{errors.email?.type === 'required' && errors.email.message?.toString()} <Field label="Password" invalid={Boolean(errors.password)} errorText={errors.password?.message?.toString()} mb={'3'}>
{errors.email?.type === 'pattern' && 'Invalid Email Address'}
</FormErrorMessage>
</FormControl>
<FormControl isInvalid={Boolean(errors.password)} mb={'3'}>
<FormLabel htmlFor="password">Password</FormLabel>
<Input <Input
id="password" id="password"
bg={bg} bg={bg}
_placeholder={{ color: 'gray.500' }} _placeholder={{ color: 'gray.500' }}
border="1px" borderWidth="1px" borderStyle="solid"
borderColor="gray.500" borderColor={{ base: "gray.500", _invalid: "red.500" }}
rounded="md" rounded="md"
placeholder="Password" placeholder="Password"
type="password" type="password"
{...register('password', { required: 'You must specify a password' })} {...register('password', { required: 'You must specify a password' })}
/> />
<FormErrorMessage> </Field>
{errors.password && errors.password.message?.toString()}
</FormErrorMessage>
</FormControl>
<br/> <br/>
<HStack> <HStack>
<Button <Button
type="submit" type="submit"
colorPalette="blue"
disabled={!isDirty} disabled={!isDirty}
isLoading={isSubmitting} loading={isSubmitting}
> >
Submit Submit
</Button> </Button>
</HStack> </HStack>
<Center mt={'5rem'}> <Center mt={'5rem'}>
<Button as={Link} to={'/forgotpassword'}>Forgot Password</Button> <Button asChild variant="outline"><Link to={'/forgotpassword'}>Forgot Password</Link></Button>
</Center> </Center>
</form> </form>
</Container> </Container>
+23 -32
View File
@@ -4,10 +4,11 @@ import { IResetPassword } from '../../models/user'
import { import {
Button, Button,
Container, Container,
FormControl, Input,
FormLabel,
Input, useToast, useColorModeValue, FormErrorMessage,
} from '@chakra-ui/react' } from '@chakra-ui/react'
import {Field} from '../ui/field'
import {useColorModeValue} from '../ui/color-mode'
import {toaster} from '../ui/toaster'
import agent from '../../api/agent' import agent from '../../api/agent'
import { useNavigate, useParams } from 'react-router-dom' import { useNavigate, useParams } from 'react-router-dom'
@@ -17,7 +18,7 @@ interface Message {
} }
interface URL { interface URL {
token: string token?: string
} }
export default function ResetPassword() { export default function ResetPassword() {
@@ -27,32 +28,29 @@ export default function ResetPassword() {
watch, watch,
formState: { errors, isSubmitting, isDirty }, formState: { errors, isSubmitting, isDirty },
} = useForm() } = useForm()
const { token } = useParams<URL>() const { token } = useParams()
const history = useNavigate() const history = useNavigate()
const toast = useToast()
const password = useRef({}) const password = useRef({})
password.current = watch('password', '') password.current = watch('password', '')
const onSubmit = handleSubmit(async (data) => { const onSubmit = handleSubmit(async (data) => {
const message = await agent.Account.reset(token, data as IResetPassword) as Message const message = await agent.Account.reset(token!, data as IResetPassword) as Message
if (message.success) { if (message.success) {
setTimeout(() => history('/login'), 3000) setTimeout(() => history('/login'), 3000)
toast({ toaster.create({
title: 'Password Reset', title: 'Password Reset',
status: 'success', type: 'success',
description: 'Your password has been reset. You will be redirected to login automatically', description: 'Your password has been reset. You will be redirected to login automatically',
isClosable: true, closable: true,
duration: 5000, duration: 5000,
position: 'top',
}) })
} else { } else {
toast({ toaster.create({
title: 'Password Not Reset', title: 'Password Not Reset',
status: 'error', type: 'error',
description: 'Something went wrong, please contact the website administrator', description: 'Something went wrong, please contact the website administrator',
isClosable: true, closable: true,
duration: 10000, duration: 10000,
position: 'top',
}) })
} }
}) })
@@ -62,15 +60,14 @@ export default function ResetPassword() {
return ( return (
<Container style={{ marginTop: '7rem', paddingBottom: '5rem' }}> <Container style={{ marginTop: '7rem', paddingBottom: '5rem' }}>
<form onSubmit={onSubmit}> <form onSubmit={onSubmit}>
<FormControl isInvalid={Boolean(errors.password)} mb={'3'}> <Field label="Password" invalid={Boolean(errors.password)} errorText={errors.password?.message?.toString()} mb={'3'}>
<FormLabel htmlFor="password">Password</FormLabel>
<Input <Input
id="password" id="password"
bg={bg} bg={bg}
_placeholder={{ color: 'gray.500' }} _placeholder={{ color: 'gray.500' }}
border="1px" borderWidth="1px" borderStyle="solid"
borderColor="gray.500" borderColor={{ base: "gray.500", _invalid: "red.500" }}
rounded="md" rounded="md"
placeholder="Password" placeholder="Password"
type="password" type="password"
@@ -82,18 +79,14 @@ export default function ResetPassword() {
}, },
})} })}
/> />
<FormErrorMessage> </Field>
{errors.password && errors.password.message?.toString()} <Field label="Repeat Password" invalid={Boolean(errors.repeat_password)} errorText={errors.repeat_password?.message?.toString()} mb={'3'}>
</FormErrorMessage>
</FormControl>
<FormControl isInvalid={Boolean(errors.repeat_password)} mb={'3'}>
<FormLabel htmlFor="repeat_password">Repeat Password</FormLabel>
<Input <Input
id="repeat_password" id="repeat_password"
bg={bg} bg={bg}
_placeholder={{ color: 'gray.500' }} _placeholder={{ color: 'gray.500' }}
border="1px" borderWidth="1px" borderStyle="solid"
borderColor="gray.500" borderColor={{ base: "gray.500", _invalid: "red.500" }}
rounded="md" rounded="md"
placeholder="Repeat Password" placeholder="Repeat Password"
type="password" type="password"
@@ -102,15 +95,13 @@ export default function ResetPassword() {
value === password.current || 'The passwords do not match', value === password.current || 'The passwords do not match',
})} })}
/> />
<FormErrorMessage> </Field>
{errors.repeat_password && errors.repeat_password.message?.toString()}
</FormErrorMessage>
</FormControl>
<br/> <br/>
<Button <Button
type="submit" type="submit"
colorPalette="blue"
disabled={!isDirty} disabled={!isDirty}
isLoading={isSubmitting} loading={isSubmitting}
> >
Submit Submit
</Button> </Button>
+30 -45
View File
@@ -3,15 +3,13 @@ import { useForm } from 'react-hook-form'
import { UserFormValues } from '../../models/user' import { UserFormValues } from '../../models/user'
import { createUser } from '../../stateManagement/userState' import { createUser } from '../../stateManagement/userState'
import { import {
Alert,
AlertDescription,
AlertIcon,
Button, Button,
Container, Container,
FormControl, FormErrorMessage, Input,
FormLabel,
Input, useColorModeValue,
} from '@chakra-ui/react' } from '@chakra-ui/react'
import {Field} from '../ui/field'
import {Alert} from '../ui/alert'
import {useColorModeValue} from '../ui/color-mode'
export default function CreateUser() { export default function CreateUser() {
const { const {
@@ -44,59 +42,52 @@ export default function CreateUser() {
return ( return (
<Container style={{ marginTop: '7rem', paddingBottom: '5rem' }}> <Container style={{ marginTop: '7rem', paddingBottom: '5rem' }}>
<form onSubmit={onSubmit}> <form onSubmit={onSubmit}>
<FormControl isInvalid={Boolean(errors.name)} mb={'3'}> <Field label="Full Name" invalid={Boolean(errors.name)} errorText={errors.name?.message?.toString()} mb={'3'}>
<FormLabel htmlFor='name'>Full Name</FormLabel>
<Input <Input
id='name' id='name'
bg={bg} bg={bg}
_placeholder={{ color: 'gray.500' }} _placeholder={{ color: 'gray.500' }}
border="1px" borderWidth="1px" borderStyle="solid"
borderColor="gray.500" borderColor={{ base: "gray.500", _invalid: "red.500" }}
rounded="md" rounded="md"
placeholder='Full Name' placeholder='Full Name'
{...register('name', { required: 'Name is required' })} {...register('name', { required: 'Name is required' })}
/> />
{errors.name && <FormErrorMessage>{ errors.name.message?.toString()}</FormErrorMessage>} </Field>
</FormControl> <Field label="Display Name" invalid={Boolean(errors.displayName)} errorText={errors.displayName?.message?.toString()} mb={'3'}>
<FormControl isInvalid={Boolean(errors.displayName)} mb={'3'}>
<FormLabel htmlFor='displayName'>Display Name</FormLabel>
<Input <Input
id='displayName' id='displayName'
bg={bg} bg={bg}
_placeholder={{ color: 'gray.500' }} _placeholder={{ color: 'gray.500' }}
border="1px" borderWidth="1px" borderStyle="solid"
borderColor="gray.500" borderColor={{ base: "gray.500", _invalid: "red.500" }}
rounded="md" rounded="md"
placeholder='Display Name' placeholder='Display Name'
{...register('displayName', { required: 'Display Name is required' })} {...register('displayName', { required: 'Display Name is required' })}
/> />
{errors.displayName && <FormErrorMessage>{ errors.displayName.message?.toString()}</FormErrorMessage>} </Field>
</FormControl> <Field label="Email" invalid={Boolean(errors.email)} errorText={errors.email?.message?.toString()} mb={'3'}>
<FormControl isInvalid={Boolean(errors.email)} mb={'3'}>
<FormLabel htmlFor='email'>Email</FormLabel>
<Input <Input
id='email' id='email'
bg={bg} bg={bg}
_placeholder={{ color: 'gray.500' }} _placeholder={{ color: 'gray.500' }}
border="1px" borderWidth="1px" borderStyle="solid"
borderColor="gray.500" borderColor={{ base: "gray.500", _invalid: "red.500" }}
rounded="md" rounded="md"
placeholder='Email' placeholder='Email'
{...register('email', { required: 'Email is required' })} {...register('email', { required: 'Email is required' })}
/> />
{errors.email && <FormErrorMessage>{ errors.email.message?.toString()}</FormErrorMessage>} </Field>
</FormControl> <Field label="Password" invalid={Boolean(errors.password)} errorText={errors.password?.message?.toString()} mb={'3'}>
<FormControl isInvalid={Boolean(errors.password)} mb={'3'}>
<FormLabel htmlFor='password'>Password</FormLabel>
<Input <Input
id='password' id='password'
bg={bg} bg={bg}
_placeholder={{ color: 'gray.500' }} _placeholder={{ color: 'gray.500' }}
border="1px" borderWidth="1px" borderStyle="solid"
borderColor="gray.500" borderColor={{ base: "gray.500", _invalid: "red.500" }}
rounded="md" rounded="md"
placeholder='Password' placeholder='Password'
type='password' type='password'
@@ -108,26 +99,22 @@ export default function CreateUser() {
}, },
})} })}
/> />
{errors.password && <FormErrorMessage>{ errors.password.message?.toString()}</FormErrorMessage>} </Field>
</FormControl>
{errors.password && ( {errors.password && (
<> <>
<Alert status='error' style={{ marginBottom: 10 }}> <Alert status='error' title={errors.password.message?.toString()} style={{ marginBottom: 10 }}>
<AlertIcon /> {errors.password.message?.toString()}
<AlertDescription>{errors.password.message?.toString()}</AlertDescription>
{/*<CloseButton position='absolute' right='8px' top='8px' />*/}
</Alert> </Alert>
<br /> <br />
</> </>
)} )}
<FormControl isInvalid={Boolean(errors.repeat_password)} mb={'3'}> <Field label="Repeat Password" invalid={Boolean(errors.repeat_password)} errorText={errors.repeat_password?.message?.toString()} mb={'3'}>
<FormLabel htmlFor='repeat_password'>Repeat Password</FormLabel>
<Input <Input
id='repeat_password' id='repeat_password'
bg={bg} bg={bg}
_placeholder={{ color: 'gray.500' }} _placeholder={{ color: 'gray.500' }}
border="1px" borderWidth="1px" borderStyle="solid"
borderColor="gray.500" borderColor={{ base: "gray.500", _invalid: "red.500" }}
rounded="md" rounded="md"
placeholder='Repeat Password' placeholder='Repeat Password'
type='password' type='password'
@@ -136,22 +123,20 @@ export default function CreateUser() {
value === password.current || 'The passwords do not match', value === password.current || 'The passwords do not match',
})} })}
/> />
{errors.repeat_password && <FormErrorMessage>{ errors.repeat_password.message?.toString()}</FormErrorMessage>} </Field>
</FormControl>
{errors.repeat_password && ( {errors.repeat_password && (
<> <>
<Alert status='error' style={{ marginBottom: 10 }}> <Alert status='error' title={errors.repeat_password.message?.toString()} style={{ marginBottom: 10 }}>
<AlertIcon /> {errors.repeat_password.message?.toString()}
<AlertDescription>{errors.repeat_password.message?.toString()}</AlertDescription>
{/*<CloseButton position='absolute' right='8px' top='8px' />*/}
</Alert> </Alert>
</> </>
)} )}
<br /> <br />
<Button <Button
type='submit' type='submit'
colorPalette="blue"
disabled={!isDirty} disabled={!isDirty}
isLoading={isSubmitting} loading={isSubmitting}
> >
Submit Submit
</Button> </Button>
+33 -44
View File
@@ -5,14 +5,14 @@ import { loadedPreferences, loggedInUser, updateUserPreferences } from '../../st
import { import {
Button, Button,
Container, Flex, Container, Flex,
FormControl,
FormLabel,
Heading, Heading,
Input, Input,
Stack, Switch, Stack,
useColorModeValue,
useToast,
} from '@chakra-ui/react' } from '@chakra-ui/react'
import {Field} from '../ui/field'
import {Switch} from '../ui/switch'
import {useColorModeValue} from '../ui/color-mode'
import {toaster} from '../ui/toaster'
import { useHookstate } from '@hookstate/core' import { useHookstate } from '@hookstate/core'
import agent from '../../api/agent' import agent from '../../api/agent'
import { useNavigate } from 'react-router-dom' import { useNavigate } from 'react-router-dom'
@@ -43,12 +43,10 @@ export default function EditUser() {
const history = useNavigate() const history = useNavigate()
useEffect(() => { useEffect(() => {
reset(user) reset(user as any)
return return
}, [user.name !== '']) }, [user.name !== ''])
const toast = useToast()
interface Message { interface Message {
success: boolean success: boolean
data: string data: string
@@ -66,13 +64,12 @@ export default function EditUser() {
const engageChangePassword = async (values: IForgotPassword) => { const engageChangePassword = async (values: IForgotPassword) => {
const message = await agent.Account.forgot(values as IForgotPassword) as Message const message = await agent.Account.forgot(values as IForgotPassword) as Message
toast({ toaster.create({
title: 'Email Sent', title: 'Email Sent',
status: 'success', type: 'success',
description: message.data, description: message.data,
isClosable: true, closable: true,
duration: 10000, duration: 10000,
position: 'top'
}) })
} }
@@ -90,78 +87,70 @@ export default function EditUser() {
<Container style={{ marginTop: '7rem', paddingBottom: '5rem' }}> <Container style={{ marginTop: '7rem', paddingBottom: '5rem' }}>
<Heading as="h1" marginBottom={'3rem'}>Edit {user.displayName}</Heading> <Heading as="h1" marginBottom={'3rem'}>Edit {user.displayName}</Heading>
<form onSubmit={onSubmit}> <form onSubmit={onSubmit}>
<FormControl> <Field label="Full Name">
<FormLabel htmlFor="name">Full Name</FormLabel>
<Input <Input
id="name" id="name"
bg={bg} bg={bg}
border="1px" borderWidth="1px" borderStyle="solid"
borderColor="gray.500" borderColor={{ base: "gray.500", _invalid: "red.500" }}
rounded="md" rounded="md"
{...register('name', { required: 'Name is required' })} {...register('name', { required: 'Name is required' })}
/> />
</FormControl> </Field>
<FormControl mt={'3'}> <Field label="Display Name" mt={'3'}>
<FormLabel htmlFor="displayName">Display Name</FormLabel>
<Input <Input
id="displayName" id="displayName"
bg={bg} bg={bg}
border="1px" borderWidth="1px" borderStyle="solid"
borderColor="gray.500" borderColor={{ base: "gray.500", _invalid: "red.500" }}
rounded="md" rounded="md"
{...register('displayName', { required: 'Display Name is required' })} {...register('displayName', { required: 'Display Name is required' })}
/> />
</FormControl> </Field>
<FormControl mt={'3'}> <Field label="Email" mt={'3'}>
<FormLabel htmlFor="email">Email</FormLabel>
<Input <Input
id="email" id="email"
bg={bg} bg={bg}
_placeholder={{ color: 'gray.500' }} _placeholder={{ color: 'gray.500' }}
isDisabled disabled
border="1px" borderWidth="1px" borderStyle="solid"
borderColor="gray.500" borderColor={{ base: "gray.500", _invalid: "red.500" }}
rounded="md" rounded="md"
placeholder="Email" placeholder="Email"
{...register('email', { required: 'Email is required' })} {...register('email', { required: 'Email is required' })}
/> />
</FormControl> </Field>
<FormControl> <Field label="Dark Mode:" orientation="horizontal" mt={'6'}>
<Flex mt={'6'}>
<FormLabel htmlFor={"theme"}>Dark Mode:</FormLabel>
<Controller <Controller
control={control} control={control}
name="theme" name="theme"
render={({ field: { onChange, value, ref } }) => ( render={({ field: { onChange, value, ref } }) => (
<Switch isChecked={value} onChange={onChange} ref={ref} /> <Switch colorPalette="blue" checked={value} onCheckedChange={({ checked }: any) => onChange(checked)} ref={ref} />
)} )}
/> />
</Flex> </Field>
</FormControl> <Field label="Sticky Navbar:" orientation="horizontal" mt={'6'}>
<FormControl>
<Flex mt={'6'}>
<FormLabel htmlFor={"stickyNav"}>Sticky Navbar:</FormLabel>
<Controller <Controller
control={control} control={control}
name="stickyNav" name="stickyNav"
render={({ field: { onChange, value, ref } }) => ( render={({ field: { onChange, value, ref } }) => (
<Switch isChecked={value} onChange={onChange} ref={ref} /> <Switch colorPalette="blue" checked={value} onCheckedChange={({ checked }: any) => onChange(checked)} ref={ref} />
)} )}
/> />
</Flex> </Field>
</FormControl>
<br /> <br />
<Stack spacing={[1, 5]} direction={'row'} align="self-end" pb="3"> <Stack gap={[1, 5]} direction={'row'} alignSelf="flex-end" pb="3">
<Button <Button
type="submit" type="submit"
colorPalette="blue"
disabled={!isDirty} disabled={!isDirty}
isLoading={isSubmitting} loading={isSubmitting}
> >
Submit Submit
</Button> </Button>
<Button <Button
isLoading={passwordLoading.get()} loading={passwordLoading.get()}
isDisabled={passwordDisabled.get()} disabled={passwordDisabled.get()}
onMouseDown={async () => { onMouseDown={async () => {
passwordLoading.set(true) passwordLoading.set(true)
passwordDisabled.set(true) passwordDisabled.set(true)
+30 -32
View File
@@ -7,14 +7,10 @@ import {
GridItem, GridItem,
Heading, Heading,
Image, Image,
Table,
TableContainer,
Tbody,
Td,
Text, Text,
Tr, Table,
useColorModeValue
} from '@chakra-ui/react' } from '@chakra-ui/react'
import {useColorModeValue} from '../ui/color-mode'
import {useHookstate} from '@hookstate/core' import {useHookstate} from '@hookstate/core'
import {loggedInUser} from '../../stateManagement/userState' import {loggedInUser} from '../../stateManagement/userState'
import {Link} from 'react-router-dom' import {Link} from 'react-router-dom'
@@ -28,10 +24,12 @@ const UserProfile = () => {
<Heading mb={'1rem'} as="h1">User Profile</Heading> <Heading mb={'1rem'} as="h1">User Profile</Heading>
<Grid templateColumns={`repeat(7, 1fr)`} templateRows={'2'} gap={6}> <Grid templateColumns={`repeat(7, 1fr)`} templateRows={'2'} gap={6}>
<GridItem rowStart={1} rowEnd={1} colStart={7} alignSelf={'end'} justifySelf={'end'}> <GridItem rowStart={1} rowEnd={1} colStart={7} alignSelf={'end'} justifySelf={'end'}>
<Button as={Link} to={`/edit-user`} colorScheme="blue" style={{textAlign: 'right'}}> <Button asChild colorPalette="blue" style={{textAlign: 'right'}}>
<Text mt={'1'}> <Link to={`/edit-user`}>
Edit <Text mt={'1'}>
</Text> Edit
</Text>
</Link>
</Button> </Button>
</GridItem> </GridItem>
<GridItem rowStart={2} rowEnd={2} colSpan={2} colStart={2}> <GridItem rowStart={2} rowEnd={2} colSpan={2} colStart={2}>
@@ -42,28 +40,28 @@ const UserProfile = () => {
</GridItem> </GridItem>
<GridItem rowStart={2} rowEnd={2} colStart={4} colEnd={8}> <GridItem rowStart={2} rowEnd={2} colStart={4} colEnd={8}>
<Box bg={bg} p="5" rounded="md"> <Box bg={bg} p="5" rounded="md">
<TableContainer> <Table.ScrollArea>
<Table variant="simple"> <Table.Root variant="outline">
<Tbody> <Table.Body>
<Tr> <Table.Row>
<Td><Text fontSize={'1.5rem'}>Display Name: </Text></Td> <Table.Cell><Text fontSize={'1.5rem'}>Display Name: </Text></Table.Cell>
<Td><Text fontSize={'1.5rem'}>{user.displayName}</Text></Td> <Table.Cell><Text fontSize={'1.5rem'}>{user.displayName}</Text></Table.Cell>
</Tr> </Table.Row>
<Tr> <Table.Row>
<Td><Text fontSize={'1.5rem'}>Full Name: </Text></Td> <Table.Cell><Text fontSize={'1.5rem'}>Full Name: </Text></Table.Cell>
<Td><Text fontSize={'1.5rem'}>{user.name}</Text></Td> <Table.Cell><Text fontSize={'1.5rem'}>{user.name}</Text></Table.Cell>
</Tr> </Table.Row>
<Tr> <Table.Row>
<Td><Text fontSize={'1.5rem'}>Email: </Text></Td> <Table.Cell><Text fontSize={'1.5rem'}>Email: </Text></Table.Cell>
<Td><Text fontSize={'1.5rem'}>{user.email}</Text></Td> <Table.Cell><Text fontSize={'1.5rem'}>{user.email}</Text></Table.Cell>
</Tr> </Table.Row>
<Tr> <Table.Row>
<Td><Text fontSize={'1.5rem'}>Role: </Text></Td> <Table.Cell><Text fontSize={'1.5rem'}>Role: </Text></Table.Cell>
<Td><Text fontSize={'1.5rem'}>{user.role}</Text></Td> <Table.Cell><Text fontSize={'1.5rem'}>{user.role}</Text></Table.Cell>
</Tr> </Table.Row>
</Tbody> </Table.Body>
</Table> </Table.Root>
</TableContainer> </Table.ScrollArea>
</Box> </Box>
</GridItem> </GridItem>
</Grid> </Grid>
+2 -2
View File
@@ -29,8 +29,8 @@ export default function NotFound() {
It looks like you hit a{' '} It looks like you hit a{' '}
{<span style={styles.retroFontBody}>DEAD</span>} end! {<span style={styles.retroFontBody}>DEAD</span>} end!
</Heading> </Heading>
<Button colorScheme='blue' as={Link} to={'/games'} style={{fontSize: '1.2rem', marginLeft: '5rem'}}> <Button colorPalette='blue' asChild style={{fontSize: '1.2rem', marginLeft: '5rem'}}>
Back to Games List <Link to={'/games'}>Back to Games List</Link>
</Button> </Button>
<Suspense fallback={<LoadingModal />}> <Suspense fallback={<LoadingModal />}>
<Video/> <Video/>
+3 -1
View File
@@ -29,10 +29,12 @@ export default function SomethingWentWrong() {
{<span style={styles.retroFontBody}>WE APOLOGIZE!</span>}<br/> {<span style={styles.retroFontBody}>WE APOLOGIZE!</span>}<br/>
Please contact the website administrator! Please contact the website administrator!
</Heading> </Heading>
<Button colorScheme='blue' as={Link} to={'/games'} style={{fontSize: '1.2rem', marginLeft: '5rem'}}> <Button colorPalette='blue' asChild style={{fontSize: '1.2rem', marginLeft: '5rem'}}>
<Link to={'/games'}>
<div style={{marginTop: '.25rem'}}> <div style={{marginTop: '.25rem'}}>
Back to Games List Back to Games List
</div> </div>
</Link>
</Button> </Button>
<Suspense fallback={<LoadingModal/>}> <Suspense fallback={<LoadingModal/>}>
<Video/> <Video/>