aboutsummaryrefslogtreecommitdiffstats
path: root/src/views/Things
diff options
context:
space:
mode:
authorLibravatar Mo Tarbin <mhed.t91@gmail.com>2024-07-01 22:12:19 -0400
committerLibravatar Mo Tarbin <mhed.t91@gmail.com>2024-07-01 22:12:19 -0400
commit5e54da8271c7fac5062f0aca9b10e7370fd4bae2 (patch)
tree376e53b60c9639d9db80cbcd809212253f29f0d0 /src/views/Things
parent6bc28be9e351662025a3eb0662f32902e64eb143 (diff)
downloaddonetick-frontend-5e54da8271c7fac5062f0aca9b10e7370fd4bae2.tar.gz
donetick-frontend-5e54da8271c7fac5062f0aca9b10e7370fd4bae2.tar.bz2
donetick-frontend-5e54da8271c7fac5062f0aca9b10e7370fd4bae2.zip
Update button re-enable timeout to 3 seconds, update thing history
Diffstat (limited to '')
-rw-r--r--src/views/Things/ThingsHistory.jsx164
-rw-r--r--src/views/Things/ThingsView.jsx87
2 files changed, 233 insertions, 18 deletions
diff --git a/src/views/Things/ThingsHistory.jsx b/src/views/Things/ThingsHistory.jsx
index 39f0e30..4b32b0e 100644
--- a/src/views/Things/ThingsHistory.jsx
+++ b/src/views/Things/ThingsHistory.jsx
@@ -1,11 +1,171 @@
-import { Container, Typography } from '@mui/joy'
+import { EventBusy } from '@mui/icons-material'
+import {
+ Box,
+ Button,
+ Chip,
+ Container,
+ List,
+ ListDivider,
+ ListItem,
+ ListItemContent,
+ Typography,
+} from '@mui/joy'
+import moment from 'moment'
+import { useEffect, useState } from 'react'
+import { Link, useParams } from 'react-router-dom'
+import { GetThingHistory } from '../../utils/Fetcher'
const ThingsHistory = () => {
+ const { id } = useParams()
+ const [thingsHistory, setThingsHistory] = useState([])
+ const [noMoreHistory, setNoMoreHistory] = useState(false)
+ const [errLoading, setErrLoading] = useState(false)
+ useEffect(() => {
+ GetThingHistory(id, 0, 10).then(resp => {
+ if (resp.ok) {
+ resp.json().then(data => {
+ setThingsHistory(data.res)
+ if (data.res.length < 10) {
+ setNoMoreHistory(true)
+ }
+ })
+ } else {
+ setErrLoading(true)
+ }
+ })
+ }, [])
+
+ const handleLoadMore = () => {
+ GetThingHistory(id, thingsHistory.length).then(resp => {
+ if (resp.ok) {
+ resp.json().then(data => {
+ setThingsHistory([...thingsHistory, ...data.res])
+ if (data.res.length < 10) {
+ setNoMoreHistory(true)
+ }
+ })
+ }
+ })
+ }
+
+ const formatTimeDifference = (startDate, endDate) => {
+ const diffInMinutes = moment(startDate).diff(endDate, 'minutes')
+ let timeValue = diffInMinutes
+ let unit = 'minute'
+
+ if (diffInMinutes >= 60) {
+ const diffInHours = moment(startDate).diff(endDate, 'hours')
+ timeValue = diffInHours
+ unit = 'hour'
+
+ if (diffInHours >= 24) {
+ const diffInDays = moment(startDate).diff(endDate, 'days')
+ timeValue = diffInDays
+ unit = 'day'
+ }
+ }
+
+ return `${timeValue} ${unit}${timeValue !== 1 ? 's' : ''}`
+ }
+ if (errLoading || !thingsHistory) {
+ return (
+ <Container
+ maxWidth='md'
+ sx={{
+ textAlign: 'center',
+ display: 'flex',
+ // make sure the content is centered vertically:
+ alignItems: 'center',
+ justifyContent: 'center',
+ flexDirection: 'column',
+ height: '50vh',
+ }}
+ >
+ <EventBusy
+ sx={{
+ fontSize: '6rem',
+ // color: 'text.disabled',
+ mb: 1,
+ }}
+ />
+
+ <Typography level='h3' gutterBottom>
+ No history found
+ </Typography>
+ <Typography level='body1'>
+ It's look like there is no history for this thing yet.
+ </Typography>
+ <Button variant='soft' sx={{ mt: 2 }}>
+ <Link to='/things'>Go back to things</Link>
+ </Button>
+ </Container>
+ )
+ }
+
return (
<Container maxWidth='md'>
<Typography level='h3' mb={1.5}>
- Summary:
+ History:
</Typography>
+ <List sx={{ p: 0 }}>
+ {thingsHistory.map((history, index) => (
+ <>
+ <ListItem sx={{ gap: 1.5, alignItems: 'flex-start' }}>
+ <ListItemContent sx={{ my: 0 }}>
+ <Box
+ sx={{
+ display: 'flex',
+ justifyContent: 'space-between',
+ alignItems: 'center',
+ }}
+ >
+ <Typography level='body1' sx={{ fontWeight: 'md' }}>
+ {moment(history.updatedAt).format(
+ 'ddd MM/DD/yyyy HH:mm:ss',
+ )}
+ </Typography>
+ <Chip>{history.state === '1' ? 'Active' : 'Inactive'}</Chip>
+ </Box>
+ </ListItemContent>
+ </ListItem>
+ {index < thingsHistory.length - 1 && (
+ <>
+ <ListDivider component='li'>
+ {/* time between two completion: */}
+ {index < thingsHistory.length - 1 &&
+ thingsHistory[index + 1].createdAt && (
+ <Typography level='body3' color='text.tertiary'>
+ {formatTimeDifference(
+ history.createdAt,
+ thingsHistory[index + 1].createdAt,
+ )}{' '}
+ before
+ </Typography>
+ )}
+ </ListDivider>
+ </>
+ )}
+ </>
+ ))}
+ </List>
+ {/* Load more Button */}
+ <Box
+ sx={{
+ display: 'flex',
+ justifyContent: 'center',
+ mt: 2,
+ }}
+ >
+ <Button
+ variant='plain'
+ fullWidth
+ color='primary'
+ onClick={handleLoadMore}
+ disabled={noMoreHistory}
+ >
+ {noMoreHistory ? 'No more history' : 'Load more'}
+ </Button>
+ </Box>
</Container>
)
}
diff --git a/src/views/Things/ThingsView.jsx b/src/views/Things/ThingsView.jsx
index deb2df5..8b2beb6 100644
--- a/src/views/Things/ThingsView.jsx
+++ b/src/views/Things/ThingsView.jsx
@@ -12,12 +12,15 @@ import {
Box,
Card,
Chip,
+ CircularProgress,
Container,
Grid,
IconButton,
+ Snackbar,
Typography,
} from '@mui/joy'
import { useEffect, useState } from 'react'
+import { useNavigate } from 'react-router-dom'
import {
CreateThing,
DeleteThing,
@@ -27,13 +30,14 @@ import {
} from '../../utils/Fetcher'
import ConfirmationModal from '../Modals/Inputs/ConfirmationModal'
import CreateThingModal from '../Modals/Inputs/CreateThingModal'
-
const ThingCard = ({
thing,
onEditClick,
onStateChangeRequest,
onDeleteClick,
}) => {
+ const [isDisabled, setIsDisabled] = useState(false)
+ const Navigate = useNavigate()
const getThingIcon = type => {
if (type === 'text') {
return <Flip />
@@ -49,6 +53,15 @@ const ThingCard = ({
return <ToggleOff />
}
}
+
+ const handleRequestChange = thing => {
+ setIsDisabled(true)
+ onStateChangeRequest(thing)
+ setTimeout(() => {
+ setIsDisabled(false)
+ }, 2000)
+ }
+
return (
<Card
variant='outlined'
@@ -71,6 +84,9 @@ const ThingCard = ({
flexDirection: 'row',
gap: 1,
}}
+ onClick={() => {
+ Navigate(`/things/${thing?.id}`)
+ }}
>
<Typography level='title-lg' component='h2'>
{thing?.name}
@@ -91,21 +107,39 @@ const ThingCard = ({
<Grid item xs={3}>
<Box display='flex' justifyContent='flex-end' alignItems='flex-end'>
{/* <ButtonGroup> */}
- <IconButton
- variant='solid'
- color='success'
- onClick={() => {
- onStateChangeRequest(thing)
- }}
- sx={{
- borderRadius: '50%',
- width: 50,
- height: 50,
- zIndex: 1,
- }}
- >
- {getThingIcon(thing?.type)}
- </IconButton>
+ <div className='relative grid place-items-center'>
+ <IconButton
+ variant='solid'
+ color='success'
+ onClick={() => {
+ handleRequestChange(thing)
+ }}
+ sx={{
+ borderRadius: '50%',
+ width: 50,
+ minWidth: 50,
+ height: 50,
+ zIndex: 1,
+ }}
+ disabled={isDisabled}
+ >
+ {getThingIcon(thing?.type)}
+ </IconButton>
+ {isDisabled && (
+ <CircularProgress
+ variant='solid'
+ color='success'
+ size='md'
+ sx={{
+ color: 'success.main',
+ position: 'absolute',
+ '--CircularProgress-size': '55px',
+
+ zIndex: 0,
+ }}
+ />
+ )}
+ </div>
<IconButton
// sx={{ width: 15 }}
variant='soft'
@@ -154,6 +188,10 @@ const ThingsView = () => {
const [isShowCreateThingModal, setIsShowCreateThingModal] = useState(false)
const [createModalThing, setCreateModalThing] = useState(null)
const [confirmModelConfig, setConfirmModelConfig] = useState({})
+
+ const [isSnackbarOpen, setIsSnackbarOpen] = useState(false)
+ const [snackBarMessage, setSnackBarMessage] = useState('')
+
useEffect(() => {
// fetch things
GetThings().then(result => {
@@ -184,6 +222,8 @@ const ThingsView = () => {
}
})
})
+ setSnackBarMessage('Thing saved successfully')
+ setIsSnackbarOpen(true)
}
const handleEditClick = thing => {
setCreateModalThing(thing)
@@ -240,6 +280,8 @@ const ThingsView = () => {
})
})
}
+ setSnackBarMessage('Thing state updated successfully')
+ setIsSnackbarOpen(true)
}
return (
@@ -317,6 +359,19 @@ const ThingsView = () => {
)}
<ConfirmationModal config={confirmModelConfig} />
</Box>
+ <Snackbar
+ open={isSnackbarOpen}
+ onClose={() => {
+ setIsSnackbarOpen(false)
+ }}
+ autoHideDuration={3000}
+ variant='soft'
+ color='success'
+ size='lg'
+ invertedColors
+ >
+ <Typography level='title-md'>{snackBarMessage}</Typography>
+ </Snackbar>
</Container>
)
}