diff options
-rw-r--r-- | src/service/NFCWriter.jsx | 18 | ||||
-rw-r--r-- | src/views/Authorization/Signup.jsx | 36 | ||||
-rw-r--r-- | src/views/ChoreEdit/ChoreEdit.jsx | 38 | ||||
-rw-r--r-- | src/views/Chores/ChoreCard.jsx | 11 |
4 files changed, 93 insertions, 10 deletions
diff --git a/src/service/NFCWriter.jsx b/src/service/NFCWriter.jsx new file mode 100644 index 0000000..91ac978 --- /dev/null +++ b/src/service/NFCWriter.jsx @@ -0,0 +1,18 @@ +const writeToNFC = async url => { + if ('NDEFReader' in window) { + try { + const ndef = new window.NDEFReader() + await ndef.write({ + records: [{ recordType: 'url', data: url }], + }) + alert('URL written to NFC tag successfully!') + } catch (error) { + console.error('Error writing to NFC tag:', error) + alert('Error writing to NFC tag. Please try again.') + } + } else { + alert('NFC is not supported by this browser.') + } +} + +export default writeToNFC diff --git a/src/views/Authorization/Signup.jsx b/src/views/Authorization/Signup.jsx index d83411f..a1e312c 100644 --- a/src/views/Authorization/Signup.jsx +++ b/src/views/Authorization/Signup.jsx @@ -60,10 +60,10 @@ const SignupView = () => { setUsernameError('Username must be at least 4 characters') isValid = false } - // if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) { - // setEmailError('Invalid email address') - // isValid = false - // } + if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) { + setEmailError('Invalid email address') + isValid = false + } if (password.length < 8) { setPasswordError('Password must be at least 8 characters') @@ -158,10 +158,10 @@ const SignupView = () => { margin='normal' required fullWidth - id='email' - label='Email Address' - name='email' - autoComplete='email' + id='username' + label='Username' + name='username' + autoComplete='username' autoFocus value={username} onChange={e => { @@ -174,6 +174,26 @@ const SignupView = () => { </FormControl> {/* Error message display */} <Typography level='body2' alignSelf={'start'}> + Email + </Typography> + <Input + margin='normal' + required + fullWidth + id='email' + label='email' + name='email' + autoComplete='email' + value={email} + onChange={e => { + setEmailError(null) + setEmail(e.target.value.trim()) + }} + /> + <FormControl error={emailError}> + <FormHelperText c>{emailError}</FormHelperText> + </FormControl> + <Typography level='body2' alignSelf={'start'}> Password: </Typography> <Input diff --git a/src/views/ChoreEdit/ChoreEdit.jsx b/src/views/ChoreEdit/ChoreEdit.jsx index 568b20a..645a15d 100644 --- a/src/views/ChoreEdit/ChoreEdit.jsx +++ b/src/views/ChoreEdit/ChoreEdit.jsx @@ -16,6 +16,8 @@ import { RadioGroup, Select, Sheet, + Snackbar, + Stack, Typography, } from '@mui/joy' import moment from 'moment' @@ -77,7 +79,9 @@ const ChoreEdit = () => { const [createdBy, setCreatedBy] = useState(0) const [errors, setErrors] = useState({}) const [attemptToSave, setAttemptToSave] = useState(false) - + const [isSnackbarOpen, setIsSnackbarOpen] = useState(false) + const [snackbarMessage, setSnackbarMessage] = useState('') + const [snackbarColor, setSnackbarColor] = useState('warning') const Navigate = useNavigate() const HandleValidateChore = () => { @@ -127,8 +131,24 @@ const ChoreEdit = () => { // if there is any error then return false: setErrors(errors) if (Object.keys(errors).length > 0) { + // generate a list with error and set it in snackbar: + + const errorList = Object.keys(errors).map(key => ( + <ListItem key={key}>{errors[key]}</ListItem> + )) + setSnackbarMessage( + <Stack spacing={0.5}> + <Typography level='title-md'> + Please resolve the following errors: + </Typography> + <List>{errorList}</List> + </Stack>, + ) + setSnackbarColor('danger') + setIsSnackbarOpen(true) return false } + return true } @@ -506,7 +526,7 @@ const ChoreEdit = () => { </FormControl> )} </Box> - {!['once', 'no_repeat', 'trigger'].includes(frequencyType) && ( + {!['once', 'no_repeat'].includes(frequencyType) && ( <Box mt={2}> <Typography level='h4'>Scheduling Preferences: </Typography> <Typography level='h5'> @@ -737,6 +757,20 @@ const ChoreEdit = () => { </Sheet> <ConfirmationModal config={confirmModelConfig} /> {/* <ChoreHistory ChoreHistory={choresHistory} UsersData={performers} /> */} + <Snackbar + open={isSnackbarOpen} + onClose={() => { + setIsSnackbarOpen(false) + setSnackbarMessage(null) + }} + color={snackbarColor} + autoHideDuration={4000} + sx={{ bottom: 70 }} + invertedColors={true} + variant='soft' + > + {snackbarMessage} + </Snackbar> </Container> ) } diff --git a/src/views/Chores/ChoreCard.jsx b/src/views/Chores/ChoreCard.jsx index 8efaf04..ee25458 100644 --- a/src/views/Chores/ChoreCard.jsx +++ b/src/views/Chores/ChoreCard.jsx @@ -8,6 +8,7 @@ import { ManageSearch, MoreTime, MoreVert, + Nfc, NoteAdd, RecordVoiceOver, Repeat, @@ -34,6 +35,7 @@ import moment from 'moment' import React, { useEffect } from 'react' import { useNavigate } from 'react-router-dom' import { API_URL } from '../../Config' +import writeToNFC from '../../service/NFCWriter' import { Fetch } from '../../utils/TokenManager' import ConfirmationModal from '../Modals/Inputs/ConfirmationModal' import DateModal from '../Modals/Inputs/DateModal' @@ -518,6 +520,15 @@ const ChoreCard = ({ chore, performers, onChoreUpdate, onChoreRemove, sx }) => { <MoreTime /> Change due date </MenuItem> + <MenuItem + onClick={() => { + // write current chore URL to NFC + writeToNFC(`${window.location.origin}/chores/${chore.id}`) + }} + > + <Nfc /> + Write to NFC + </MenuItem> <MenuItem onClick={handleEdit}> <Edit /> Edit |