2024-07-06 02:33:06 -04:00
|
|
|
import {
|
|
|
|
CalendarMonth,
|
|
|
|
CancelScheduleSend,
|
|
|
|
Check,
|
|
|
|
Checklist,
|
2024-07-13 01:54:23 -04:00
|
|
|
History,
|
2024-07-06 02:33:06 -04:00
|
|
|
PeopleAlt,
|
|
|
|
Person,
|
2024-07-15 21:58:23 -04:00
|
|
|
SwitchAccessShortcut,
|
2024-07-13 01:54:23 -04:00
|
|
|
Timelapse,
|
2024-07-06 02:33:06 -04:00
|
|
|
} from '@mui/icons-material'
|
|
|
|
import {
|
|
|
|
Box,
|
|
|
|
Button,
|
2024-07-07 19:48:34 -04:00
|
|
|
Card,
|
2024-07-07 00:25:11 -04:00
|
|
|
Checkbox,
|
2024-07-13 01:54:23 -04:00
|
|
|
Chip,
|
2024-07-06 02:33:06 -04:00
|
|
|
Container,
|
2024-07-07 00:25:11 -04:00
|
|
|
FormControl,
|
2024-07-06 02:33:06 -04:00
|
|
|
Grid,
|
2024-07-07 00:25:11 -04:00
|
|
|
Input,
|
2024-07-06 02:33:06 -04:00
|
|
|
ListItem,
|
|
|
|
ListItemContent,
|
|
|
|
Sheet,
|
|
|
|
Snackbar,
|
|
|
|
styled,
|
|
|
|
Typography,
|
|
|
|
} from '@mui/joy'
|
|
|
|
import moment from 'moment'
|
|
|
|
import { useEffect, useState } from 'react'
|
2024-07-14 17:56:18 -04:00
|
|
|
import { useNavigate, useParams, useSearchParams } from 'react-router-dom'
|
2024-07-06 02:33:06 -04:00
|
|
|
import {
|
|
|
|
GetAllUsers,
|
|
|
|
GetChoreDetailById,
|
|
|
|
MarkChoreComplete,
|
2024-07-15 21:58:23 -04:00
|
|
|
SkipChore,
|
2024-07-06 02:33:06 -04:00
|
|
|
} from '../../utils/Fetcher'
|
2024-07-15 21:58:23 -04:00
|
|
|
import ConfirmationModal from '../Modals/Inputs/ConfirmationModal'
|
2024-07-06 02:33:06 -04:00
|
|
|
const IconCard = styled('div')({
|
|
|
|
display: 'flex',
|
|
|
|
alignItems: 'center',
|
|
|
|
justifyContent: 'center',
|
|
|
|
backgroundColor: '#f0f0f0', // Adjust the background color as needed
|
|
|
|
borderRadius: '50%',
|
2024-07-15 21:58:23 -04:00
|
|
|
minWidth: '40px',
|
|
|
|
height: '40px',
|
2024-07-06 02:33:06 -04:00
|
|
|
marginRight: '16px',
|
|
|
|
})
|
|
|
|
const ChoreView = () => {
|
|
|
|
const [chore, setChore] = useState({})
|
2024-07-14 17:56:18 -04:00
|
|
|
const navigate = useNavigate()
|
2024-07-06 02:33:06 -04:00
|
|
|
const [performers, setPerformers] = useState([])
|
|
|
|
const [infoCards, setInfoCards] = useState([])
|
|
|
|
const { choreId } = useParams()
|
2024-07-07 00:25:11 -04:00
|
|
|
const [note, setNote] = useState(null)
|
2024-07-06 02:33:06 -04:00
|
|
|
|
|
|
|
const [searchParams] = useSearchParams()
|
|
|
|
|
|
|
|
const [isPendingCompletion, setIsPendingCompletion] = useState(false)
|
|
|
|
const [timeoutId, setTimeoutId] = useState(null)
|
|
|
|
const [secondsLeftToCancel, setSecondsLeftToCancel] = useState(null)
|
2024-07-07 00:25:11 -04:00
|
|
|
const [completedDate, setCompletedDate] = useState(null)
|
2024-07-15 21:58:23 -04:00
|
|
|
const [confirmModelConfig, setConfirmModelConfig] = useState({})
|
|
|
|
|
2024-07-06 02:33:06 -04:00
|
|
|
useEffect(() => {
|
|
|
|
Promise.all([
|
|
|
|
GetChoreDetailById(choreId).then(resp => {
|
|
|
|
if (resp.ok) {
|
|
|
|
return resp.json().then(data => {
|
|
|
|
setChore(data.res)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}),
|
|
|
|
GetAllUsers()
|
|
|
|
.then(response => response.json())
|
|
|
|
.then(data => {
|
|
|
|
setPerformers(data.res)
|
|
|
|
}),
|
|
|
|
])
|
|
|
|
const auto_complete = searchParams.get('auto_complete')
|
|
|
|
if (auto_complete === 'true') {
|
|
|
|
handleTaskCompletion()
|
|
|
|
}
|
|
|
|
}, [])
|
|
|
|
useEffect(() => {
|
|
|
|
if (chore && performers.length > 0) {
|
|
|
|
generateInfoCards(chore)
|
|
|
|
}
|
|
|
|
}, [chore, performers])
|
|
|
|
|
|
|
|
const generateInfoCards = chore => {
|
|
|
|
const cards = [
|
|
|
|
{
|
2024-07-13 01:54:23 -04:00
|
|
|
size: 6,
|
2024-07-06 02:33:06 -04:00
|
|
|
icon: <PeopleAlt />,
|
|
|
|
text: 'Assigned To',
|
|
|
|
subtext: performers.find(p => p.id === chore.assignedTo)?.displayName,
|
|
|
|
},
|
2024-07-15 21:58:23 -04:00
|
|
|
{
|
|
|
|
size: 6,
|
|
|
|
icon: <CalendarMonth />,
|
|
|
|
text: 'Due Date',
|
|
|
|
subtext: chore.nextDueDate
|
|
|
|
? moment(chore.nextDueDate).fromNow()
|
|
|
|
: 'N/A',
|
|
|
|
},
|
|
|
|
|
2024-07-06 02:33:06 -04:00
|
|
|
// {
|
|
|
|
// icon: <TextFields />,
|
|
|
|
// text: 'Frequency',
|
|
|
|
// subtext:
|
|
|
|
// chore.frequencyType.charAt(0).toUpperCase() +
|
|
|
|
// chore.frequencyType.slice(1),
|
|
|
|
// },
|
|
|
|
{
|
2024-07-13 01:54:23 -04:00
|
|
|
size: 6,
|
2024-07-06 02:33:06 -04:00
|
|
|
icon: <Checklist />,
|
2024-07-15 21:58:23 -04:00
|
|
|
text: 'Total Completed',
|
2024-07-13 01:54:23 -04:00
|
|
|
subtext: `${chore.totalCompletedCount} times`,
|
2024-07-06 02:33:06 -04:00
|
|
|
},
|
|
|
|
{
|
2024-07-13 01:54:23 -04:00
|
|
|
size: 6,
|
|
|
|
icon: <Timelapse />,
|
2024-07-15 21:58:23 -04:00
|
|
|
text: 'Last Completed',
|
2024-07-13 01:54:23 -04:00
|
|
|
subtext:
|
2024-07-15 21:58:23 -04:00
|
|
|
// chore.lastCompletedDate &&
|
|
|
|
// moment(chore.lastCompletedDate).format('MM/DD/YYYY hh:mm A'),
|
|
|
|
chore.lastCompletedDate && moment(chore.lastCompletedDate).fromNow(),
|
2024-07-13 01:54:23 -04:00
|
|
|
},
|
|
|
|
{
|
|
|
|
size: 6,
|
2024-07-06 02:33:06 -04:00
|
|
|
icon: <Person />,
|
2024-07-15 21:58:23 -04:00
|
|
|
text: 'Last Performer',
|
2024-07-06 02:33:06 -04:00
|
|
|
subtext: chore.lastCompletedDate
|
|
|
|
? `${
|
2024-07-07 19:48:34 -04:00
|
|
|
performers.find(p => p.id === chore.lastCompletedBy)?.displayName
|
2024-07-15 21:58:23 -04:00
|
|
|
}`
|
2024-07-06 02:33:06 -04:00
|
|
|
: 'Never',
|
|
|
|
},
|
2024-07-07 00:25:11 -04:00
|
|
|
{
|
2024-07-15 21:58:23 -04:00
|
|
|
size: 6,
|
|
|
|
icon: <Person />,
|
|
|
|
text: 'Created By',
|
|
|
|
subtext: performers.find(p => p.id === chore.createdBy)?.displayName,
|
2024-07-07 00:25:11 -04:00
|
|
|
},
|
2024-07-15 21:58:23 -04:00
|
|
|
// {
|
|
|
|
// size: 12,
|
|
|
|
// icon: <Note />,
|
|
|
|
// text: 'Recent Note',
|
|
|
|
// subtext: chore.notes || '--',
|
|
|
|
// },
|
2024-07-06 02:33:06 -04:00
|
|
|
]
|
|
|
|
setInfoCards(cards)
|
|
|
|
}
|
|
|
|
const handleTaskCompletion = () => {
|
|
|
|
setIsPendingCompletion(true)
|
|
|
|
let seconds = 3 // Starting countdown from 3 seconds
|
|
|
|
setSecondsLeftToCancel(seconds)
|
|
|
|
|
|
|
|
const countdownInterval = setInterval(() => {
|
|
|
|
seconds -= 1
|
|
|
|
setSecondsLeftToCancel(seconds)
|
|
|
|
|
|
|
|
if (seconds <= 0) {
|
|
|
|
clearInterval(countdownInterval) // Stop the countdown when it reaches 0
|
|
|
|
}
|
|
|
|
}, 1000)
|
|
|
|
|
|
|
|
const id = setTimeout(() => {
|
2024-07-07 00:25:11 -04:00
|
|
|
MarkChoreComplete(choreId, note, completedDate)
|
2024-07-06 02:33:06 -04:00
|
|
|
.then(resp => {
|
|
|
|
if (resp.ok) {
|
|
|
|
return resp.json().then(data => {
|
2024-07-07 00:25:11 -04:00
|
|
|
setNote(null)
|
2024-07-06 02:33:06 -04:00
|
|
|
setChore(data.res)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.then(() => {
|
|
|
|
setIsPendingCompletion(false)
|
|
|
|
clearTimeout(id)
|
|
|
|
clearInterval(countdownInterval) // Ensure to clear this interval as well
|
|
|
|
setTimeoutId(null)
|
|
|
|
setSecondsLeftToCancel(null)
|
|
|
|
})
|
|
|
|
.then(() => {
|
|
|
|
// refetch the chore details
|
|
|
|
GetChoreDetailById(choreId).then(resp => {
|
|
|
|
if (resp.ok) {
|
|
|
|
return resp.json().then(data => {
|
|
|
|
setChore(data.res)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
})
|
|
|
|
})
|
|
|
|
}, 3000)
|
|
|
|
|
|
|
|
setTimeoutId(id)
|
|
|
|
}
|
2024-07-15 21:58:23 -04:00
|
|
|
const handleSkippingTask = () => {
|
|
|
|
SkipChore(choreId).then(response => {
|
|
|
|
if (response.ok) {
|
|
|
|
response.json().then(data => {
|
|
|
|
const newChore = data.res
|
|
|
|
setChore(newChore)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
2024-07-06 02:33:06 -04:00
|
|
|
return (
|
2024-07-07 00:25:11 -04:00
|
|
|
<Container
|
|
|
|
maxWidth='sm'
|
|
|
|
sx={{
|
|
|
|
display: 'flex',
|
|
|
|
flexDirection: 'column',
|
|
|
|
// space between :
|
|
|
|
justifyContent: 'space-between',
|
|
|
|
}}
|
|
|
|
>
|
2024-07-13 01:54:23 -04:00
|
|
|
<Box
|
|
|
|
sx={{
|
|
|
|
display: 'flex',
|
|
|
|
flexDirection: 'column',
|
|
|
|
justifyContent: 'center',
|
|
|
|
alignItems: 'center',
|
|
|
|
textAlign: 'center',
|
|
|
|
}}
|
|
|
|
>
|
2024-07-07 00:25:11 -04:00
|
|
|
<Typography
|
|
|
|
level='h3'
|
2024-07-13 01:54:23 -04:00
|
|
|
// textAlign={'center'}
|
2024-07-07 00:25:11 -04:00
|
|
|
sx={{
|
|
|
|
mt: 2,
|
2024-07-13 01:54:23 -04:00
|
|
|
mb: 1,
|
2024-07-07 00:25:11 -04:00
|
|
|
}}
|
|
|
|
>
|
|
|
|
{chore.name}
|
|
|
|
</Typography>
|
2024-07-13 01:54:23 -04:00
|
|
|
<Chip startDecorator={<CalendarMonth />} size='lg' sx={{ mb: 4 }}>
|
|
|
|
{chore.nextDueDate
|
|
|
|
? `Due at ${moment(chore.nextDueDate).format('MM/DD/YYYY hh:mm A')}`
|
|
|
|
: 'N/A'}
|
|
|
|
</Chip>
|
|
|
|
</Box>
|
|
|
|
<Box>
|
2024-07-15 21:58:23 -04:00
|
|
|
<Typography level='title-md' sx={{ mb: 1 }}>
|
|
|
|
Details
|
|
|
|
</Typography>
|
|
|
|
|
|
|
|
<Sheet
|
|
|
|
sx={{
|
|
|
|
mb: 1,
|
|
|
|
borderRadius: 'lg',
|
|
|
|
p: 2,
|
|
|
|
}}
|
|
|
|
variant='outlined'
|
|
|
|
>
|
|
|
|
<Grid container spacing={1}>
|
|
|
|
{infoCards.map((detail, index) => (
|
|
|
|
<Grid item xs={4} key={index}>
|
|
|
|
{/* divider between the list items: */}
|
|
|
|
|
|
|
|
<ListItem key={index}>
|
2024-07-07 00:25:11 -04:00
|
|
|
<ListItemContent>
|
2024-07-15 21:58:23 -04:00
|
|
|
<Typography level='body-xs' sx={{ fontWeight: 'md' }}>
|
|
|
|
{detail.text}
|
2024-07-07 00:25:11 -04:00
|
|
|
</Typography>
|
2024-07-15 21:58:23 -04:00
|
|
|
<Typography level='body-sm' color='text.tertiary'>
|
|
|
|
{detail.subtext ? detail.subtext : '--'}
|
2024-07-07 00:25:11 -04:00
|
|
|
</Typography>
|
|
|
|
</ListItemContent>
|
|
|
|
</ListItem>
|
2024-07-15 21:58:23 -04:00
|
|
|
</Grid>
|
|
|
|
))}
|
2024-07-13 01:54:23 -04:00
|
|
|
</Grid>
|
2024-07-15 21:58:23 -04:00
|
|
|
</Sheet>
|
|
|
|
{chore.notes && (
|
|
|
|
<>
|
|
|
|
<Typography level='title-md' sx={{ mb: 1 }}>
|
|
|
|
Previous note:
|
|
|
|
</Typography>
|
|
|
|
<Sheet variant='outlined' sx={{ p: 2, borderRadius: 'lg' }}>
|
|
|
|
<Typography level='body-md' sx={{ mb: 1 }}>
|
|
|
|
{chore.notes || '--'}
|
|
|
|
</Typography>
|
|
|
|
</Sheet>
|
|
|
|
</>
|
|
|
|
)}
|
|
|
|
|
|
|
|
<Box
|
|
|
|
sx={{
|
|
|
|
display: 'flex',
|
|
|
|
flexDirection: 'row',
|
|
|
|
gap: 1,
|
|
|
|
alignContent: 'center',
|
|
|
|
justifyContent: 'center',
|
|
|
|
}}
|
|
|
|
>
|
|
|
|
<Button
|
|
|
|
startDecorator={<History />}
|
|
|
|
size='lg'
|
|
|
|
color='success'
|
|
|
|
variant='plain'
|
|
|
|
onClick={() => {
|
|
|
|
navigate(`/chores/${choreId}/history`)
|
|
|
|
}}
|
|
|
|
>
|
|
|
|
View History
|
|
|
|
</Button>
|
|
|
|
</Box>
|
2024-07-07 00:25:11 -04:00
|
|
|
</Box>
|
2024-07-07 19:48:34 -04:00
|
|
|
{/* <Divider
|
2024-07-06 02:33:06 -04:00
|
|
|
sx={{
|
2024-07-07 00:25:11 -04:00
|
|
|
my: 2,
|
2024-07-06 02:33:06 -04:00
|
|
|
}}
|
2024-07-07 19:48:34 -04:00
|
|
|
/> */}
|
2024-07-15 21:58:23 -04:00
|
|
|
<Typography level='title-md' sx={{ mt: 1 }}>
|
|
|
|
Actions
|
|
|
|
</Typography>
|
2024-07-07 19:48:34 -04:00
|
|
|
<Card
|
|
|
|
sx={{
|
|
|
|
p: 2,
|
|
|
|
borderRadius: 'md',
|
|
|
|
boxShadow: 'sm',
|
|
|
|
mt: 2,
|
|
|
|
}}
|
|
|
|
>
|
2024-07-07 00:25:11 -04:00
|
|
|
<Typography level='title-md'>Additional Notes</Typography>
|
|
|
|
<Input
|
|
|
|
fullWidth
|
|
|
|
multiline
|
|
|
|
label='Additional Notes'
|
|
|
|
placeholder='note or information about the task'
|
|
|
|
value={note || ''}
|
|
|
|
onChange={e => {
|
|
|
|
if (e.target.value.trim() === '') {
|
|
|
|
setNote(null)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
setNote(e.target.value)
|
|
|
|
}}
|
|
|
|
size='md'
|
|
|
|
sx={{
|
2024-07-15 21:58:23 -04:00
|
|
|
mb: 1,
|
2024-07-07 00:25:11 -04:00
|
|
|
}}
|
|
|
|
/>
|
2024-07-07 19:48:34 -04:00
|
|
|
|
2024-07-15 21:58:23 -04:00
|
|
|
<FormControl size='sm'>
|
2024-07-07 00:25:11 -04:00
|
|
|
<Checkbox
|
|
|
|
defaultChecked={completedDate !== null}
|
|
|
|
checked={completedDate !== null}
|
|
|
|
value={completedDate !== null}
|
2024-07-07 19:48:34 -04:00
|
|
|
size='lg'
|
2024-07-07 00:25:11 -04:00
|
|
|
onChange={e => {
|
|
|
|
if (e.target.checked) {
|
|
|
|
setCompletedDate(
|
|
|
|
moment(new Date()).format('YYYY-MM-DDTHH:00:00'),
|
|
|
|
)
|
|
|
|
} else {
|
|
|
|
setCompletedDate(null)
|
|
|
|
}
|
|
|
|
}}
|
|
|
|
overlay
|
2024-07-14 17:56:18 -04:00
|
|
|
sx={
|
|
|
|
{
|
|
|
|
// my: 1,
|
|
|
|
}
|
|
|
|
}
|
2024-07-07 00:25:11 -04:00
|
|
|
label={<Typography level='body2'>Set completion date</Typography>}
|
|
|
|
/>
|
|
|
|
</FormControl>
|
|
|
|
{completedDate !== null && (
|
|
|
|
<Input
|
|
|
|
sx={{ mt: 1, mb: 1.5, width: 300 }}
|
|
|
|
type='datetime-local'
|
|
|
|
value={completedDate}
|
|
|
|
onChange={e => {
|
|
|
|
setCompletedDate(e.target.value)
|
|
|
|
}}
|
|
|
|
/>
|
|
|
|
)}
|
2024-07-14 17:56:18 -04:00
|
|
|
|
2024-07-07 00:25:11 -04:00
|
|
|
<Button
|
|
|
|
fullWidth
|
|
|
|
size='lg'
|
|
|
|
onClick={handleTaskCompletion}
|
|
|
|
disabled={isPendingCompletion}
|
|
|
|
color={isPendingCompletion ? 'danger' : 'success'}
|
|
|
|
startDecorator={<Check />}
|
2024-07-06 02:33:06 -04:00
|
|
|
>
|
2024-07-07 00:25:11 -04:00
|
|
|
<Box>Mark as done</Box>
|
|
|
|
</Button>
|
2024-07-15 21:58:23 -04:00
|
|
|
<Button
|
|
|
|
fullWidth
|
|
|
|
size='lg'
|
|
|
|
onClick={() => {
|
|
|
|
setConfirmModelConfig({
|
|
|
|
isOpen: true,
|
|
|
|
title: 'Skip Task',
|
2024-07-07 00:25:11 -04:00
|
|
|
|
2024-07-15 21:58:23 -04:00
|
|
|
message: 'Are you sure you want to skip this task?',
|
|
|
|
|
|
|
|
confirmText: 'Skip',
|
|
|
|
cancelText: 'Cancel',
|
|
|
|
onClose: confirmed => {
|
|
|
|
if (confirmed) {
|
|
|
|
handleSkippingTask()
|
|
|
|
}
|
|
|
|
setConfirmModelConfig({})
|
|
|
|
},
|
|
|
|
})
|
|
|
|
}}
|
|
|
|
startDecorator={<SwitchAccessShortcut />}
|
|
|
|
>
|
|
|
|
<Box>Skip</Box>
|
|
|
|
</Button>
|
|
|
|
<Snackbar
|
|
|
|
open={isPendingCompletion}
|
|
|
|
endDecorator={
|
|
|
|
<Button
|
|
|
|
onClick={() => {
|
|
|
|
if (timeoutId) {
|
|
|
|
clearTimeout(timeoutId)
|
|
|
|
setIsPendingCompletion(false)
|
|
|
|
setTimeoutId(null)
|
|
|
|
setSecondsLeftToCancel(null) // Reset or adjust as needed
|
|
|
|
}
|
|
|
|
}}
|
|
|
|
size='lg'
|
|
|
|
variant='outlined'
|
|
|
|
color='danger'
|
|
|
|
startDecorator={<CancelScheduleSend />}
|
|
|
|
>
|
|
|
|
Cancel
|
|
|
|
</Button>
|
|
|
|
}
|
|
|
|
>
|
|
|
|
<Typography level='body-md' textAlign={'center'}>
|
|
|
|
Task will be marked as completed in {secondsLeftToCancel} seconds
|
|
|
|
</Typography>
|
|
|
|
</Snackbar>
|
|
|
|
<ConfirmationModal config={confirmModelConfig} />
|
|
|
|
</Card>
|
2024-07-06 02:33:06 -04:00
|
|
|
</Container>
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
export default ChoreView
|