Add SkipChore function to Fetcher utility module, Update Loading Comp
This commit is contained in:
parent
93512eb666
commit
7f4e592849
7 changed files with 296 additions and 171 deletions
|
@ -26,6 +26,7 @@ import {
|
||||||
styled,
|
styled,
|
||||||
Typography,
|
Typography,
|
||||||
} from '@mui/joy'
|
} from '@mui/joy'
|
||||||
|
import { Divider } from '@mui/material'
|
||||||
import moment from 'moment'
|
import moment from 'moment'
|
||||||
import { useEffect, useState } from 'react'
|
import { useEffect, useState } from 'react'
|
||||||
import { useNavigate, useParams, useSearchParams } from 'react-router-dom'
|
import { useNavigate, useParams, useSearchParams } from 'react-router-dom'
|
||||||
|
@ -135,7 +136,7 @@ const ChoreView = () => {
|
||||||
? `${
|
? `${
|
||||||
performers.find(p => p.id === chore.lastCompletedBy)?.displayName
|
performers.find(p => p.id === chore.lastCompletedBy)?.displayName
|
||||||
}`
|
}`
|
||||||
: 'Never',
|
: '--',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
size: 6,
|
size: 6,
|
||||||
|
@ -230,8 +231,8 @@ const ChoreView = () => {
|
||||||
level='h3'
|
level='h3'
|
||||||
// textAlign={'center'}
|
// textAlign={'center'}
|
||||||
sx={{
|
sx={{
|
||||||
mt: 2,
|
mt: 1,
|
||||||
mb: 1,
|
mb: 0.5,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{chore.name}
|
{chore.name}
|
||||||
|
@ -243,7 +244,7 @@ const ChoreView = () => {
|
||||||
</Chip>
|
</Chip>
|
||||||
</Box>
|
</Box>
|
||||||
<Box>
|
<Box>
|
||||||
<Typography level='title-md' sx={{ mb: 1 }}>
|
<Typography level='title-md' sx={{ mb: 0.5 }}>
|
||||||
Details
|
Details
|
||||||
</Typography>
|
</Typography>
|
||||||
|
|
||||||
|
@ -265,9 +266,13 @@ const ChoreView = () => {
|
||||||
<Typography level='body-xs' sx={{ fontWeight: 'md' }}>
|
<Typography level='body-xs' sx={{ fontWeight: 'md' }}>
|
||||||
{detail.text}
|
{detail.text}
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography level='body-sm' color='text.tertiary'>
|
<Chip
|
||||||
|
color='primary'
|
||||||
|
size='md'
|
||||||
|
startDecorator={detail.icon}
|
||||||
|
>
|
||||||
{detail.subtext ? detail.subtext : '--'}
|
{detail.subtext ? detail.subtext : '--'}
|
||||||
</Typography>
|
</Chip>
|
||||||
</ListItemContent>
|
</ListItemContent>
|
||||||
</ListItem>
|
</ListItem>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
@ -286,28 +291,6 @@ const ChoreView = () => {
|
||||||
</Sheet>
|
</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>
|
|
||||||
</Box>
|
</Box>
|
||||||
{/* <Divider
|
{/* <Divider
|
||||||
sx={{
|
sx={{
|
||||||
|
@ -325,25 +308,63 @@ const ChoreView = () => {
|
||||||
mt: 2,
|
mt: 2,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Typography level='title-md'>Additional Notes</Typography>
|
<Typography level='body-md' sx={{ mb: 1 }}>
|
||||||
<Input
|
Complete the task
|
||||||
fullWidth
|
</Typography>
|
||||||
multiline
|
|
||||||
label='Additional Notes'
|
<FormControl size='sm'>
|
||||||
placeholder='note or information about the task'
|
<Checkbox
|
||||||
value={note || ''}
|
defaultChecked={note !== null}
|
||||||
onChange={e => {
|
checked={note !== null}
|
||||||
if (e.target.value.trim() === '') {
|
value={note !== null}
|
||||||
setNote(null)
|
size='lg'
|
||||||
return
|
onChange={e => {
|
||||||
|
if (e.target.checked) {
|
||||||
|
setNote('')
|
||||||
|
} else {
|
||||||
|
setNote(null)
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
overlay
|
||||||
|
sx={
|
||||||
|
{
|
||||||
|
// my: 1,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
setNote(e.target.value)
|
label={
|
||||||
}}
|
<Typography
|
||||||
size='md'
|
level='body-sm'
|
||||||
sx={{
|
sx={{
|
||||||
mb: 1,
|
// center vertically
|
||||||
}}
|
display: 'flex',
|
||||||
/>
|
alignItems: 'center',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Add Additional Notes
|
||||||
|
</Typography>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</FormControl>
|
||||||
|
{note !== null && (
|
||||||
|
<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={{
|
||||||
|
mb: 1,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
<FormControl size='sm'>
|
<FormControl size='sm'>
|
||||||
<Checkbox
|
<Checkbox
|
||||||
|
@ -366,7 +387,18 @@ const ChoreView = () => {
|
||||||
// my: 1,
|
// my: 1,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
label={<Typography level='body2'>Set completion date</Typography>}
|
label={
|
||||||
|
<Typography
|
||||||
|
level='body-sm'
|
||||||
|
sx={{
|
||||||
|
// center vertically
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Specify completion date
|
||||||
|
</Typography>
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
{completedDate !== null && (
|
{completedDate !== null && (
|
||||||
|
@ -390,30 +422,55 @@ const ChoreView = () => {
|
||||||
>
|
>
|
||||||
<Box>Mark as done</Box>
|
<Box>Mark as done</Box>
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Divider sx={{ my: 0.5 }}>or</Divider>
|
||||||
fullWidth
|
|
||||||
size='lg'
|
|
||||||
onClick={() => {
|
|
||||||
setConfirmModelConfig({
|
|
||||||
isOpen: true,
|
|
||||||
title: 'Skip Task',
|
|
||||||
|
|
||||||
message: 'Are you sure you want to skip this task?',
|
<Box
|
||||||
|
sx={{
|
||||||
confirmText: 'Skip',
|
display: 'flex',
|
||||||
cancelText: 'Cancel',
|
flexDirection: 'row',
|
||||||
onClose: confirmed => {
|
gap: 1,
|
||||||
if (confirmed) {
|
alignContent: 'center',
|
||||||
handleSkippingTask()
|
justifyContent: 'center',
|
||||||
}
|
|
||||||
setConfirmModelConfig({})
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}}
|
}}
|
||||||
startDecorator={<SwitchAccessShortcut />}
|
|
||||||
>
|
>
|
||||||
<Box>Skip</Box>
|
<Button
|
||||||
</Button>
|
fullWidth
|
||||||
|
size='lg'
|
||||||
|
onClick={() => {
|
||||||
|
setConfirmModelConfig({
|
||||||
|
isOpen: true,
|
||||||
|
title: 'Skip Task',
|
||||||
|
|
||||||
|
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>
|
||||||
|
<Button
|
||||||
|
startDecorator={<History />}
|
||||||
|
size='lg'
|
||||||
|
color='primary'
|
||||||
|
variant='outlined'
|
||||||
|
fullWidth
|
||||||
|
onClick={() => {
|
||||||
|
navigate(`/chores/${choreId}/history`)
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
History
|
||||||
|
</Button>
|
||||||
|
</Box>
|
||||||
|
|
||||||
<Snackbar
|
<Snackbar
|
||||||
open={isPendingCompletion}
|
open={isPendingCompletion}
|
||||||
endDecorator={
|
endDecorator={
|
||||||
|
|
|
@ -17,6 +17,7 @@ import {
|
||||||
SwitchAccessShortcut,
|
SwitchAccessShortcut,
|
||||||
TimesOneMobiledata,
|
TimesOneMobiledata,
|
||||||
Update,
|
Update,
|
||||||
|
ViewCarousel,
|
||||||
Webhook,
|
Webhook,
|
||||||
} from '@mui/icons-material'
|
} from '@mui/icons-material'
|
||||||
import {
|
import {
|
||||||
|
@ -107,6 +108,9 @@ const ChoreCard = ({
|
||||||
const handleEdit = () => {
|
const handleEdit = () => {
|
||||||
navigate(`/chores/${chore.id}/edit`)
|
navigate(`/chores/${chore.id}/edit`)
|
||||||
}
|
}
|
||||||
|
const handleView = () => {
|
||||||
|
navigate(`/chores/${chore.id}`)
|
||||||
|
}
|
||||||
const handleDelete = () => {
|
const handleDelete = () => {
|
||||||
setConfirmModelConfig({
|
setConfirmModelConfig({
|
||||||
isOpen: true,
|
isOpen: true,
|
||||||
|
@ -579,6 +583,10 @@ const ChoreCard = ({
|
||||||
<Edit />
|
<Edit />
|
||||||
Edit
|
Edit
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
|
<MenuItem onClick={handleView}>
|
||||||
|
<ViewCarousel />
|
||||||
|
View
|
||||||
|
</MenuItem>
|
||||||
<MenuItem onClick={handleDelete} color='danger'>
|
<MenuItem onClick={handleDelete} color='danger'>
|
||||||
<Delete />
|
<Delete />
|
||||||
Delete
|
Delete
|
||||||
|
|
|
@ -3,7 +3,6 @@ import {
|
||||||
Badge,
|
Badge,
|
||||||
Box,
|
Box,
|
||||||
Checkbox,
|
Checkbox,
|
||||||
CircularProgress,
|
|
||||||
Container,
|
Container,
|
||||||
IconButton,
|
IconButton,
|
||||||
Input,
|
Input,
|
||||||
|
@ -18,8 +17,8 @@ import Fuse from 'fuse.js'
|
||||||
import { useContext, useEffect, useRef, useState } from 'react'
|
import { useContext, useEffect, useRef, useState } from 'react'
|
||||||
import { useNavigate } from 'react-router-dom'
|
import { useNavigate } from 'react-router-dom'
|
||||||
import { UserContext } from '../../contexts/UserContext'
|
import { UserContext } from '../../contexts/UserContext'
|
||||||
import Logo from '../../Logo'
|
|
||||||
import { GetAllUsers, GetChores, GetUserProfile } from '../../utils/Fetcher'
|
import { GetAllUsers, GetChores, GetUserProfile } from '../../utils/Fetcher'
|
||||||
|
import LoadingComponent from '../components/Loading'
|
||||||
import ChoreCard from './ChoreCard'
|
import ChoreCard from './ChoreCard'
|
||||||
|
|
||||||
const MyChores = () => {
|
const MyChores = () => {
|
||||||
|
@ -184,18 +183,7 @@ const MyChores = () => {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (userProfile === null) {
|
if (userProfile === null) {
|
||||||
return (
|
return <LoadingComponent />
|
||||||
<Container className='flex h-full items-center justify-center'>
|
|
||||||
<Box className='flex flex-col items-center justify-center'>
|
|
||||||
<CircularProgress
|
|
||||||
color='success'
|
|
||||||
sx={{ '--CircularProgress-size': '200px' }}
|
|
||||||
>
|
|
||||||
<Logo />
|
|
||||||
</CircularProgress>
|
|
||||||
</Box>
|
|
||||||
</Container>
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -1,15 +1,13 @@
|
||||||
import { Checklist, EventBusy, Timelapse } from '@mui/icons-material'
|
import { Checklist, EventBusy, Group, Timelapse } from '@mui/icons-material'
|
||||||
import {
|
import {
|
||||||
Avatar,
|
Avatar,
|
||||||
Box,
|
|
||||||
Button,
|
Button,
|
||||||
CircularProgress,
|
Chip,
|
||||||
Container,
|
Container,
|
||||||
Grid,
|
Grid,
|
||||||
List,
|
List,
|
||||||
ListItem,
|
ListItem,
|
||||||
ListItemContent,
|
ListItemContent,
|
||||||
ListItemDecorator,
|
|
||||||
Sheet,
|
Sheet,
|
||||||
Typography,
|
Typography,
|
||||||
} from '@mui/joy'
|
} from '@mui/joy'
|
||||||
|
@ -19,6 +17,7 @@ import { Link, useParams } from 'react-router-dom'
|
||||||
import { API_URL } from '../../Config'
|
import { API_URL } from '../../Config'
|
||||||
import { GetAllCircleMembers } from '../../utils/Fetcher'
|
import { GetAllCircleMembers } from '../../utils/Fetcher'
|
||||||
import { Fetch } from '../../utils/TokenManager'
|
import { Fetch } from '../../utils/TokenManager'
|
||||||
|
import LoadingComponent from '../components/Loading'
|
||||||
import HistoryCard from './HistoryCard'
|
import HistoryCard from './HistoryCard'
|
||||||
|
|
||||||
const ChoreHistory = () => {
|
const ChoreHistory = () => {
|
||||||
|
@ -92,59 +91,49 @@ const ChoreHistory = () => {
|
||||||
|
|
||||||
const historyInfo = [
|
const historyInfo = [
|
||||||
{
|
{
|
||||||
icon: (
|
icon: <Checklist />,
|
||||||
<Avatar>
|
text: 'Total Completed',
|
||||||
<Checklist />
|
subtext: `${histories.length} times`,
|
||||||
</Avatar>
|
|
||||||
),
|
|
||||||
text: `${histories.length} completed`,
|
|
||||||
subtext: `${Object.keys(userHistories).length} users contributed`,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: (
|
icon: <Timelapse />,
|
||||||
<Avatar>
|
text: 'Usually Within',
|
||||||
<Timelapse />
|
subtext: moment.duration(averageDelayMoment).humanize(),
|
||||||
</Avatar>
|
|
||||||
),
|
|
||||||
text: `Completed within ${moment
|
|
||||||
.duration(averageDelayMoment)
|
|
||||||
.humanize()}`,
|
|
||||||
subtext: `Maximum delay was ${moment
|
|
||||||
.duration(maxDelayMoment)
|
|
||||||
.humanize()}`,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: <Avatar></Avatar>,
|
icon: <Timelapse />,
|
||||||
text: `${
|
text: 'Maximum Delay',
|
||||||
|
subtext: moment.duration(maxDelayMoment).humanize(),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: <Avatar />,
|
||||||
|
text: ' Completed Most',
|
||||||
|
subtext: `${
|
||||||
performers.find(p => p.userId === Number(userCompletedByMost))
|
performers.find(p => p.userId === Number(userCompletedByMost))
|
||||||
?.displayName
|
?.displayName
|
||||||
} completed most`,
|
} `,
|
||||||
subtext: `${userHistories[userCompletedByMost]} time/s`,
|
},
|
||||||
|
// contributes:
|
||||||
|
{
|
||||||
|
icon: <Group />,
|
||||||
|
text: 'Total Performers',
|
||||||
|
subtext: `${Object.keys(userHistories).length} users`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: <Avatar />,
|
||||||
|
text: 'Last Completed',
|
||||||
|
subtext: `${
|
||||||
|
performers.find(p => p.userId === Number(histories[0].completedBy))
|
||||||
|
?.displayName
|
||||||
|
}`,
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
if (userCompletedByLeast !== userCompletedByMost) {
|
|
||||||
historyInfo.push({
|
|
||||||
icon: (
|
|
||||||
<Avatar>
|
|
||||||
{
|
|
||||||
performers.find(p => p.userId === userCompletedByLeast)
|
|
||||||
?.displayName
|
|
||||||
}
|
|
||||||
</Avatar>
|
|
||||||
),
|
|
||||||
text: `${
|
|
||||||
performers.find(p => p.userId === Number(userCompletedByLeast))
|
|
||||||
.displayName
|
|
||||||
} completed least`,
|
|
||||||
subtext: `${userHistories[userCompletedByLeast]} time/s`,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
setHistoryInfo(historyInfo)
|
setHistoryInfo(historyInfo)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isLoading) {
|
if (isLoading) {
|
||||||
return <CircularProgress /> // Show loading indicator
|
return <LoadingComponent />
|
||||||
}
|
}
|
||||||
if (!choreHistory.length) {
|
if (!choreHistory.length) {
|
||||||
return (
|
return (
|
||||||
|
@ -184,50 +173,43 @@ const ChoreHistory = () => {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Container maxWidth='md'>
|
<Container maxWidth='md'>
|
||||||
<Typography level='h3' mb={1.5}>
|
<Typography level='title-md' mb={1.5}>
|
||||||
Summary:
|
Summary:
|
||||||
</Typography>
|
</Typography>
|
||||||
{/* <Sheet sx={{ mb: 1, borderRadius: 'sm', p: 2, boxShadow: 'md' }}>
|
<Sheet
|
||||||
<ListItem sx={{ gap: 1.5 }}>
|
// sx={{
|
||||||
<ListItemDecorator>
|
// mb: 1,
|
||||||
<Avatar>
|
// borderRadius: 'lg',
|
||||||
<AccountCircle />
|
// p: 2,
|
||||||
</Avatar>
|
// }}
|
||||||
</ListItemDecorator>
|
sx={{ borderRadius: 'sm', p: 2 }}
|
||||||
<ListItemContent>
|
variant='outlined'
|
||||||
<Typography level='body1' sx={{ fontWeight: 'md' }}>
|
>
|
||||||
{choreHistory.length} completed
|
<Grid container spacing={1}>
|
||||||
</Typography>
|
{historyInfo.map((info, index) => (
|
||||||
<Typography level='body2' color='text.tertiary'>
|
<Grid item xs={4} key={index}>
|
||||||
{Object.keys(userHistory).length} users contributed
|
{/* divider between the list items: */}
|
||||||
</Typography>
|
|
||||||
</ListItemContent>
|
<ListItem key={index}>
|
||||||
</ListItem>
|
|
||||||
</Sheet> */}
|
|
||||||
<Grid container>
|
|
||||||
{historyInfo.map((info, index) => (
|
|
||||||
<Grid key={index} item xs={12} sm={6}>
|
|
||||||
<Sheet sx={{ mb: 1, borderRadius: 'sm', p: 2, boxShadow: 'md' }}>
|
|
||||||
<ListItem sx={{ gap: 1.5 }}>
|
|
||||||
<ListItemDecorator>{info.icon}</ListItemDecorator>
|
|
||||||
<ListItemContent>
|
<ListItemContent>
|
||||||
<Typography level='body1' sx={{ fontWeight: 'md' }}>
|
<Typography level='body-xs' sx={{ fontWeight: 'md' }}>
|
||||||
{info.text}
|
{info.text}
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography level='body1' color='text.tertiary'>
|
<Chip color='primary' size='md' startDecorator={info.icon}>
|
||||||
{info.subtext}
|
{info.subtext ? info.subtext : '--'}
|
||||||
</Typography>
|
</Chip>
|
||||||
</ListItemContent>
|
</ListItemContent>
|
||||||
</ListItem>
|
</ListItem>
|
||||||
</Sheet>
|
</Grid>
|
||||||
</Grid>
|
))}
|
||||||
))}
|
</Grid>
|
||||||
</Grid>
|
</Sheet>
|
||||||
|
|
||||||
{/* User History Cards */}
|
{/* User History Cards */}
|
||||||
<Typography level='h3' my={1.5}>
|
<Typography level='title-md' my={1.5}>
|
||||||
History:
|
History:
|
||||||
</Typography>
|
</Typography>
|
||||||
<Box sx={{ borderRadius: 'sm', p: 2, boxShadow: 'md' }}>
|
<Sheet sx={{ borderRadius: 'sm', p: 2, boxShadow: 'md' }}>
|
||||||
{/* Chore History List (Updated Style) */}
|
{/* Chore History List (Updated Style) */}
|
||||||
|
|
||||||
<List sx={{ p: 0 }}>
|
<List sx={{ p: 0 }}>
|
||||||
|
@ -241,7 +223,7 @@ const ChoreHistory = () => {
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</List>
|
</List>
|
||||||
</Box>
|
</Sheet>
|
||||||
</Container>
|
</Container>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import { CalendarViewDay, Check, Timelapse } from '@mui/icons-material'
|
||||||
import {
|
import {
|
||||||
Avatar,
|
Avatar,
|
||||||
Box,
|
Box,
|
||||||
|
@ -30,6 +31,50 @@ const HistoryCard = ({ allHistory, performers, historyEntry, index }) => {
|
||||||
|
|
||||||
return `${timeValue} ${unit}${timeValue !== 1 ? 's' : ''}`
|
return `${timeValue} ${unit}${timeValue !== 1 ? 's' : ''}`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const getCompletedChip = historyEntry => {
|
||||||
|
var text = 'No Due Date'
|
||||||
|
var color = 'info'
|
||||||
|
var icon = <CalendarViewDay />
|
||||||
|
// if completed few hours +-6 hours
|
||||||
|
if (
|
||||||
|
historyEntry.dueDate &&
|
||||||
|
historyEntry.completedAt > historyEntry.dueDate - 1000 * 60 * 60 * 6 &&
|
||||||
|
historyEntry.completedAt < historyEntry.dueDate + 1000 * 60 * 60 * 6
|
||||||
|
) {
|
||||||
|
text = 'On Time'
|
||||||
|
color = 'success'
|
||||||
|
icon = <Check />
|
||||||
|
} else if (
|
||||||
|
historyEntry.dueDate &&
|
||||||
|
historyEntry.completedAt < historyEntry.dueDate
|
||||||
|
) {
|
||||||
|
text = 'On Time'
|
||||||
|
color = 'success'
|
||||||
|
icon = <Check />
|
||||||
|
}
|
||||||
|
|
||||||
|
// if completed after due date then it's late
|
||||||
|
else if (
|
||||||
|
historyEntry.dueDate &&
|
||||||
|
historyEntry.completedAt > historyEntry.dueDate
|
||||||
|
) {
|
||||||
|
text = 'Late'
|
||||||
|
color = 'warning'
|
||||||
|
icon = <Timelapse />
|
||||||
|
} else {
|
||||||
|
text = 'No Due Date'
|
||||||
|
color = 'info'
|
||||||
|
icon = <CalendarViewDay />
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Chip startDecorator={icon} color={color}>
|
||||||
|
{text}
|
||||||
|
</Chip>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<ListItem sx={{ gap: 1.5, alignItems: 'flex-start' }}>
|
<ListItem sx={{ gap: 1.5, alignItems: 'flex-start' }}>
|
||||||
|
@ -55,13 +100,7 @@ const HistoryCard = ({ allHistory, performers, historyEntry, index }) => {
|
||||||
<Typography level='body1' sx={{ fontWeight: 'md' }}>
|
<Typography level='body1' sx={{ fontWeight: 'md' }}>
|
||||||
{moment(historyEntry.completedAt).format('ddd MM/DD/yyyy HH:mm')}
|
{moment(historyEntry.completedAt).format('ddd MM/DD/yyyy HH:mm')}
|
||||||
</Typography>
|
</Typography>
|
||||||
|
{getCompletedChip(historyEntry)}
|
||||||
<Chip>
|
|
||||||
{historyEntry.dueDate &&
|
|
||||||
historyEntry.completedAt > historyEntry.dueDate
|
|
||||||
? 'Late'
|
|
||||||
: 'On Time'}
|
|
||||||
</Chip>
|
|
||||||
</Box>
|
</Box>
|
||||||
<Typography level='body2' color='text.tertiary'>
|
<Typography level='body2' color='text.tertiary'>
|
||||||
<Chip>
|
<Chip>
|
||||||
|
|
|
@ -7,7 +7,7 @@ const DemoHistory = () => {
|
||||||
{
|
{
|
||||||
id: 32,
|
id: 32,
|
||||||
choreId: 12,
|
choreId: 12,
|
||||||
completedAt: moment().format(),
|
completedAt: moment().hour(4).format(),
|
||||||
completedBy: 1,
|
completedBy: 1,
|
||||||
assignedTo: 1,
|
assignedTo: 1,
|
||||||
notes: null,
|
notes: null,
|
||||||
|
@ -25,8 +25,8 @@ const DemoHistory = () => {
|
||||||
{
|
{
|
||||||
id: 31,
|
id: 31,
|
||||||
choreId: 12,
|
choreId: 12,
|
||||||
completedAt: moment().day(-10).format(),
|
completedAt: moment().day(-10).hour(1).format(),
|
||||||
completedBy: 1,
|
completedBy: 2,
|
||||||
assignedTo: 1,
|
assignedTo: 1,
|
||||||
notes: null,
|
notes: null,
|
||||||
dueDate: moment().day(-10).format(),
|
dueDate: moment().day(-10).format(),
|
||||||
|
|
51
src/views/components/Loading.jsx
Normal file
51
src/views/components/Loading.jsx
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
import { Box, CircularProgress, Container } from '@mui/joy'
|
||||||
|
import { Typography } from '@mui/material'
|
||||||
|
import { useEffect, useState } from 'react'
|
||||||
|
import Logo from '../../Logo'
|
||||||
|
|
||||||
|
const LoadingComponent = () => {
|
||||||
|
const [message, setMessage] = useState('Loading...')
|
||||||
|
const [subMessage, setSubMessage] = useState('')
|
||||||
|
useEffect(() => {
|
||||||
|
// if loading took more than 5 seconds update submessage to mention there might be an error:
|
||||||
|
const timeout = setTimeout(() => {
|
||||||
|
setSubMessage(
|
||||||
|
'This is taking longer than usual. There might be an issue.',
|
||||||
|
)
|
||||||
|
}, 5000)
|
||||||
|
return () => clearTimeout(timeout)
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Container className='flex h-full items-center justify-center'>
|
||||||
|
<Box
|
||||||
|
className='flex flex-col items-center justify-center'
|
||||||
|
sx={{
|
||||||
|
minHeight: '80vh',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<CircularProgress
|
||||||
|
color='success'
|
||||||
|
sx={{ '--CircularProgress-size': '200px' }}
|
||||||
|
>
|
||||||
|
<Logo />
|
||||||
|
</CircularProgress>
|
||||||
|
<Box
|
||||||
|
className='flex items-center gap-2'
|
||||||
|
sx={{
|
||||||
|
fontWeight: 700,
|
||||||
|
fontSize: 24,
|
||||||
|
mt: 2,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{message}
|
||||||
|
</Box>
|
||||||
|
<Typography level='h2' fontWeight={500} textAlign={'center'}>
|
||||||
|
{subMessage}
|
||||||
|
</Typography>
|
||||||
|
</Box>
|
||||||
|
</Container>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default LoadingComponent
|
Loading…
Add table
Reference in a new issue