aboutsummaryrefslogtreecommitdiffstats
path: root/src/views/Things
diff options
context:
space:
mode:
authorLibravatar Mo Tarbin <mhed.t91@gmail.com>2024-06-30 18:55:39 -0400
committerLibravatar Mo Tarbin <mhed.t91@gmail.com>2024-06-30 18:55:39 -0400
commit2657469964e24ffbeb905024532120395f6e797c (patch)
tree2fe9db8a4ecfa92d854ca94f7586d81163c8bd25 /src/views/Things
downloaddonetick-frontend-2657469964e24ffbeb905024532120395f6e797c.tar.gz
donetick-frontend-2657469964e24ffbeb905024532120395f6e797c.tar.bz2
donetick-frontend-2657469964e24ffbeb905024532120395f6e797c.zip
move to Donetick Org, First commit frontend
Diffstat (limited to '')
-rw-r--r--src/views/Things/ThingsHistory.jsx13
-rw-r--r--src/views/Things/ThingsView.jsx324
2 files changed, 337 insertions, 0 deletions
diff --git a/src/views/Things/ThingsHistory.jsx b/src/views/Things/ThingsHistory.jsx
new file mode 100644
index 0000000..39f0e30
--- /dev/null
+++ b/src/views/Things/ThingsHistory.jsx
@@ -0,0 +1,13 @@
+import { Container, Typography } from '@mui/joy'
+
+const ThingsHistory = () => {
+ return (
+ <Container maxWidth='md'>
+ <Typography level='h3' mb={1.5}>
+ Summary:
+ </Typography>
+ </Container>
+ )
+}
+
+export default ThingsHistory
diff --git a/src/views/Things/ThingsView.jsx b/src/views/Things/ThingsView.jsx
new file mode 100644
index 0000000..deb2df5
--- /dev/null
+++ b/src/views/Things/ThingsView.jsx
@@ -0,0 +1,324 @@
+import {
+ Add,
+ Delete,
+ Edit,
+ Flip,
+ PlusOne,
+ ToggleOff,
+ ToggleOn,
+ Widgets,
+} from '@mui/icons-material'
+import {
+ Box,
+ Card,
+ Chip,
+ Container,
+ Grid,
+ IconButton,
+ Typography,
+} from '@mui/joy'
+import { useEffect, useState } from 'react'
+import {
+ CreateThing,
+ DeleteThing,
+ GetThings,
+ SaveThing,
+ UpdateThingState,
+} from '../../utils/Fetcher'
+import ConfirmationModal from '../Modals/Inputs/ConfirmationModal'
+import CreateThingModal from '../Modals/Inputs/CreateThingModal'
+
+const ThingCard = ({
+ thing,
+ onEditClick,
+ onStateChangeRequest,
+ onDeleteClick,
+}) => {
+ const getThingIcon = type => {
+ if (type === 'text') {
+ return <Flip />
+ } else if (type === 'number') {
+ return <PlusOne />
+ } else if (type === 'boolean') {
+ if (thing.state === 'true') {
+ return <ToggleOn />
+ } else {
+ return <ToggleOff />
+ }
+ } else {
+ return <ToggleOff />
+ }
+ }
+ return (
+ <Card
+ variant='outlined'
+ sx={{
+ // display: 'flex',
+ // flexDirection: 'row', // Change to 'row'
+ justifyContent: 'space-between',
+ p: 2,
+ backgroundColor: 'white',
+ boxShadow: 'sm',
+ borderRadius: 8,
+ mb: 1,
+ }}
+ >
+ <Grid container>
+ <Grid item xs={9}>
+ <Box
+ sx={{
+ display: 'flex',
+ flexDirection: 'row',
+ gap: 1,
+ }}
+ >
+ <Typography level='title-lg' component='h2'>
+ {thing?.name}
+ </Typography>
+ <Chip level='body-md' component='p'>
+ {thing?.type}
+ </Chip>
+ </Box>
+ <Box>
+ <Typography level='body-sm' component='p'>
+ Current state:
+ <Chip level='title-md' component='span' size='sm'>
+ {thing?.state}
+ </Chip>
+ </Typography>
+ </Box>
+ </Grid>
+ <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>
+ <IconButton
+ // sx={{ width: 15 }}
+ variant='soft'
+ color='success'
+ onClick={() => {
+ onEditClick(thing)
+ }}
+ sx={{
+ borderRadius: '50%',
+ width: 25,
+ height: 25,
+ position: 'relative',
+ left: -10,
+ }}
+ >
+ <Edit />
+ </IconButton>
+ {/* add delete icon: */}
+ <IconButton
+ // sx={{ width: 15 }}
+
+ color='danger'
+ variant='soft'
+ onClick={() => {
+ onDeleteClick(thing)
+ }}
+ sx={{
+ borderRadius: '50%',
+ width: 25,
+ height: 25,
+ position: 'relative',
+ left: -10,
+ }}
+ >
+ <Delete />
+ </IconButton>
+ </Box>
+ </Grid>
+ </Grid>
+ </Card>
+ )
+}
+
+const ThingsView = () => {
+ const [things, setThings] = useState([])
+ const [isShowCreateThingModal, setIsShowCreateThingModal] = useState(false)
+ const [createModalThing, setCreateModalThing] = useState(null)
+ const [confirmModelConfig, setConfirmModelConfig] = useState({})
+ useEffect(() => {
+ // fetch things
+ GetThings().then(result => {
+ result.json().then(data => {
+ setThings(data.res)
+ })
+ })
+ }, [])
+
+ const handleSaveThing = thing => {
+ let saveFunc = CreateThing
+ if (thing?.id) {
+ saveFunc = SaveThing
+ }
+ saveFunc(thing).then(result => {
+ result.json().then(data => {
+ if (thing?.id) {
+ const currentThings = [...things]
+ const thingIndex = currentThings.findIndex(
+ currentThing => currentThing.id === thing.id,
+ )
+ currentThings[thingIndex] = data.res
+ setThings(currentThings)
+ } else {
+ const currentThings = [...things]
+ currentThings.push(data.res)
+ setThings(currentThings)
+ }
+ })
+ })
+ }
+ const handleEditClick = thing => {
+ setCreateModalThing(thing)
+ setIsShowCreateThingModal(true)
+ }
+ const handleDeleteClick = thing => {
+ setConfirmModelConfig({
+ isOpen: true,
+ title: 'Delete Things',
+ confirmText: 'Delete',
+ cancelText: 'Cancel',
+ message: 'Are you sure you want to delete this Thing?',
+ onClose: isConfirmed => {
+ if (isConfirmed === true) {
+ DeleteThing(thing.id).then(response => {
+ if (response.ok) {
+ const currentThings = [...things]
+ const thingIndex = currentThings.findIndex(
+ currentThing => currentThing.id === thing.id,
+ )
+ currentThings.splice(thingIndex, 1)
+ setThings(currentThings)
+ }
+ })
+ }
+ setConfirmModelConfig({})
+ },
+ })
+ }
+
+ const handleStateChangeRequest = thing => {
+ if (thing?.type === 'text') {
+ setCreateModalThing(thing)
+ setIsShowCreateThingModal(true)
+ } else {
+ if (thing?.type === 'number') {
+ thing.state = Number(thing.state) + 1
+ } else if (thing?.type === 'boolean') {
+ if (thing.state === 'true') {
+ thing.state = 'false'
+ } else {
+ thing.state = 'true'
+ }
+ }
+
+ UpdateThingState(thing).then(result => {
+ result.json().then(data => {
+ const currentThings = [...things]
+ const thingIndex = currentThings.findIndex(
+ currentThing => currentThing.id === thing.id,
+ )
+ currentThings[thingIndex] = data.res
+ setThings(currentThings)
+ })
+ })
+ }
+ }
+
+ return (
+ <Container maxWidth='md'>
+ {things.length === 0 && (
+ <Box
+ sx={{
+ display: 'flex',
+ justifyContent: 'center',
+ alignItems: 'center',
+ flexDirection: 'column',
+ height: '50vh',
+ }}
+ >
+ <Widgets
+ sx={{
+ fontSize: '4rem',
+ // color: 'text.disabled',
+ mb: 1,
+ }}
+ />
+ <Typography level='title-md' gutterBottom>
+ No things has been created/found
+ </Typography>
+ </Box>
+ )}
+ {things.map(thing => (
+ <ThingCard
+ key={thing?.id}
+ thing={thing}
+ onEditClick={handleEditClick}
+ onDeleteClick={handleDeleteClick}
+ onStateChangeRequest={handleStateChangeRequest}
+ />
+ ))}
+ <Box
+ // variant='outlined'
+ sx={{
+ position: 'fixed',
+ bottom: 0,
+ left: 10,
+ p: 2, // padding
+ display: 'flex',
+ justifyContent: 'flex-end',
+ gap: 2,
+
+ 'z-index': 1000,
+ }}
+ >
+ <IconButton
+ color='primary'
+ variant='solid'
+ sx={{
+ borderRadius: '50%',
+ width: 50,
+ height: 50,
+ }}
+ // startDecorator={<Add />}
+ onClick={() => {
+ setIsShowCreateThingModal(true)
+ }}
+ >
+ <Add />
+ </IconButton>
+ {isShowCreateThingModal && (
+ <CreateThingModal
+ isOpen={isShowCreateThingModal}
+ onClose={() => {
+ setIsShowCreateThingModal(false)
+ setCreateModalThing(null)
+ }}
+ onSave={handleSaveThing}
+ currentThing={createModalThing}
+ />
+ )}
+ <ConfirmationModal config={confirmModelConfig} />
+ </Box>
+ </Container>
+ )
+}
+
+export default ThingsView