Add NFC tag writing functionality to ChoreCard component, Add Email to sign up
This commit is contained in:
parent
71bad5a19f
commit
c34da50c8c
4 changed files with 93 additions and 10 deletions
18
src/service/NFCWriter.jsx
Normal file
18
src/service/NFCWriter.jsx
Normal file
|
@ -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
|
|
@ -60,10 +60,10 @@ const SignupView = () => {
|
||||||
setUsernameError('Username must be at least 4 characters')
|
setUsernameError('Username must be at least 4 characters')
|
||||||
isValid = false
|
isValid = false
|
||||||
}
|
}
|
||||||
// if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) {
|
if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) {
|
||||||
// setEmailError('Invalid email address')
|
setEmailError('Invalid email address')
|
||||||
// isValid = false
|
isValid = false
|
||||||
// }
|
}
|
||||||
|
|
||||||
if (password.length < 8) {
|
if (password.length < 8) {
|
||||||
setPasswordError('Password must be at least 8 characters')
|
setPasswordError('Password must be at least 8 characters')
|
||||||
|
@ -158,10 +158,10 @@ const SignupView = () => {
|
||||||
margin='normal'
|
margin='normal'
|
||||||
required
|
required
|
||||||
fullWidth
|
fullWidth
|
||||||
id='email'
|
id='username'
|
||||||
label='Email Address'
|
label='Username'
|
||||||
name='email'
|
name='username'
|
||||||
autoComplete='email'
|
autoComplete='username'
|
||||||
autoFocus
|
autoFocus
|
||||||
value={username}
|
value={username}
|
||||||
onChange={e => {
|
onChange={e => {
|
||||||
|
@ -173,6 +173,26 @@ const SignupView = () => {
|
||||||
<FormHelperText c>{usernameError}</FormHelperText>
|
<FormHelperText c>{usernameError}</FormHelperText>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
{/* Error message display */}
|
{/* 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'}>
|
<Typography level='body2' alignSelf={'start'}>
|
||||||
Password:
|
Password:
|
||||||
</Typography>
|
</Typography>
|
||||||
|
|
|
@ -16,6 +16,8 @@ import {
|
||||||
RadioGroup,
|
RadioGroup,
|
||||||
Select,
|
Select,
|
||||||
Sheet,
|
Sheet,
|
||||||
|
Snackbar,
|
||||||
|
Stack,
|
||||||
Typography,
|
Typography,
|
||||||
} from '@mui/joy'
|
} from '@mui/joy'
|
||||||
import moment from 'moment'
|
import moment from 'moment'
|
||||||
|
@ -77,7 +79,9 @@ const ChoreEdit = () => {
|
||||||
const [createdBy, setCreatedBy] = useState(0)
|
const [createdBy, setCreatedBy] = useState(0)
|
||||||
const [errors, setErrors] = useState({})
|
const [errors, setErrors] = useState({})
|
||||||
const [attemptToSave, setAttemptToSave] = useState(false)
|
const [attemptToSave, setAttemptToSave] = useState(false)
|
||||||
|
const [isSnackbarOpen, setIsSnackbarOpen] = useState(false)
|
||||||
|
const [snackbarMessage, setSnackbarMessage] = useState('')
|
||||||
|
const [snackbarColor, setSnackbarColor] = useState('warning')
|
||||||
const Navigate = useNavigate()
|
const Navigate = useNavigate()
|
||||||
|
|
||||||
const HandleValidateChore = () => {
|
const HandleValidateChore = () => {
|
||||||
|
@ -127,8 +131,24 @@ const ChoreEdit = () => {
|
||||||
// if there is any error then return false:
|
// if there is any error then return false:
|
||||||
setErrors(errors)
|
setErrors(errors)
|
||||||
if (Object.keys(errors).length > 0) {
|
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 false
|
||||||
}
|
}
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -506,7 +526,7 @@ const ChoreEdit = () => {
|
||||||
</FormControl>
|
</FormControl>
|
||||||
)}
|
)}
|
||||||
</Box>
|
</Box>
|
||||||
{!['once', 'no_repeat', 'trigger'].includes(frequencyType) && (
|
{!['once', 'no_repeat'].includes(frequencyType) && (
|
||||||
<Box mt={2}>
|
<Box mt={2}>
|
||||||
<Typography level='h4'>Scheduling Preferences: </Typography>
|
<Typography level='h4'>Scheduling Preferences: </Typography>
|
||||||
<Typography level='h5'>
|
<Typography level='h5'>
|
||||||
|
@ -737,6 +757,20 @@ const ChoreEdit = () => {
|
||||||
</Sheet>
|
</Sheet>
|
||||||
<ConfirmationModal config={confirmModelConfig} />
|
<ConfirmationModal config={confirmModelConfig} />
|
||||||
{/* <ChoreHistory ChoreHistory={choresHistory} UsersData={performers} /> */}
|
{/* <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>
|
</Container>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ import {
|
||||||
ManageSearch,
|
ManageSearch,
|
||||||
MoreTime,
|
MoreTime,
|
||||||
MoreVert,
|
MoreVert,
|
||||||
|
Nfc,
|
||||||
NoteAdd,
|
NoteAdd,
|
||||||
RecordVoiceOver,
|
RecordVoiceOver,
|
||||||
Repeat,
|
Repeat,
|
||||||
|
@ -34,6 +35,7 @@ import moment from 'moment'
|
||||||
import React, { useEffect } from 'react'
|
import React, { useEffect } from 'react'
|
||||||
import { useNavigate } from 'react-router-dom'
|
import { useNavigate } from 'react-router-dom'
|
||||||
import { API_URL } from '../../Config'
|
import { API_URL } from '../../Config'
|
||||||
|
import writeToNFC from '../../service/NFCWriter'
|
||||||
import { Fetch } from '../../utils/TokenManager'
|
import { Fetch } from '../../utils/TokenManager'
|
||||||
import ConfirmationModal from '../Modals/Inputs/ConfirmationModal'
|
import ConfirmationModal from '../Modals/Inputs/ConfirmationModal'
|
||||||
import DateModal from '../Modals/Inputs/DateModal'
|
import DateModal from '../Modals/Inputs/DateModal'
|
||||||
|
@ -518,6 +520,15 @@ const ChoreCard = ({ chore, performers, onChoreUpdate, onChoreRemove, sx }) => {
|
||||||
<MoreTime />
|
<MoreTime />
|
||||||
Change due date
|
Change due date
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
|
<MenuItem
|
||||||
|
onClick={() => {
|
||||||
|
// write current chore URL to NFC
|
||||||
|
writeToNFC(`${window.location.origin}/chores/${chore.id}`)
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Nfc />
|
||||||
|
Write to NFC
|
||||||
|
</MenuItem>
|
||||||
<MenuItem onClick={handleEdit}>
|
<MenuItem onClick={handleEdit}>
|
||||||
<Edit />
|
<Edit />
|
||||||
Edit
|
Edit
|
||||||
|
|
Loading…
Add table
Reference in a new issue