import { Widgets } from '@mui/icons-material'
import {
Autocomplete,
Box,
Button,
Card,
Chip,
FormControl,
Input,
ListItem,
ListItemContent,
ListItemDecorator,
Option,
Select,
TextField,
Typography,
} from '@mui/joy'
import { useEffect, useState } from 'react'
import { useNavigate } from 'react-router-dom'
const isValidTrigger = (thing, condition, triggerState) => {
const newErrors = {}
if (!thing || !triggerState) {
newErrors.thing = 'Please select a thing and trigger state'
return false
}
if (thing.type === 'boolean') {
if (['true', 'false'].includes(triggerState)) {
return true
} else {
newErrors.type = 'Boolean type does not require a condition'
return false
}
}
if (thing.type === 'number') {
if (isNaN(triggerState)) {
newErrors.triggerState = 'Trigger state must be a number'
return false
}
if (['eq', 'neq', 'gt', 'gte', 'lt', 'lte'].includes(condition)) {
return true
}
}
if (thing.type === 'text') {
if (typeof triggerState === 'string') {
return true
}
}
newErrors.triggerState = 'Trigger state must be a number'
return false
}
const ThingTriggerSection = ({
things,
onTriggerUpdate,
onValidate,
selected,
isAttepmtingToSave,
}) => {
const [selectedThing, setSelectedThing] = useState(null)
const [condition, setCondition] = useState(null)
const [triggerState, setTriggerState] = useState(null)
const navigate = useNavigate()
useEffect(() => {
if (selected) {
setSelectedThing(things?.find(t => t.id === selected.thingId))
setCondition(selected.condition)
setTriggerState(selected.triggerState)
}
}, [things])
useEffect(() => {
if (selectedThing && triggerState) {
onTriggerUpdate({
thing: selectedThing,
condition: condition,
triggerState: triggerState,
})
}
if (isValidTrigger(selectedThing, condition, triggerState)) {
onValidate(true)
} else {
onValidate(false)
}
}, [selectedThing, condition, triggerState])
return (
<Card sx={{ mt: 1 }}>
<Typography level='h5'>
Trigger a task when a thing state changes to a desired state
</Typography>
{things?.length === 0 && (
<Typography level='body-sm'>
it's look like you don't have any things yet, create a thing to
trigger a task when the state changes.
<Button
startDecorator={<Widgets />}
size='sm'
onClick={() => {
navigate('/things')
}}
>
Go to Things
</Button>{' '}
to create a thing
</Typography>
)}
<FormControl error={isAttepmtingToSave && !selectedThing}>
<Autocomplete
options={things}
value={selectedThing}
onChange={(e, newValue) => setSelectedThing(newValue)}
getOptionLabel={option => option.name}
renderOption={(props, option) => (
<ListItem {...props}>
<Box
sx={{
display: 'flex',
flexDirection: 'column',
justifyContent: 'space-between',
alignItems: 'center',
p: 1,
}}
>
<ListItemDecorator sx={{ alignSelf: 'flex-start' }}>
<Typography level='body-lg' textColor='primary'>
{option.name}
</Typography>
</ListItemDecorator>
<ListItemContent>
<Typography level='body2' textColor='text.secondary'>
<Chip>type: {option.type}</Chip>{' '}
<Chip>state: {option.state}</Chip>
</Typography>
</ListItemContent>
</Box>
</ListItem>
)}
renderInput={params => (
<TextField {...params} label='Select a thing' />
)}
/>
</FormControl>
<Typography level='body-sm'>
Create a condition to trigger a task when the thing state changes to
desired state
</Typography>
{selectedThing?.type == 'boolean' && (
<Box>
<Typography level='body-sm'>
When the state of {selectedThing.name} changes as specified below,
the task will become due.
</Typography>
<Select
value={triggerState}
onChange={e => {
if (e?.target.value === 'true' || e?.target.value === 'false')
setTriggerState(e.target.value)
else setTriggerState('false')
}}
>
{['true', 'false'].map(state => (
<Option
key={state}
value={state}
onClick={() => setTriggerState(state)}
>
{state.charAt(0).toUpperCase() + state.slice(1)}
</Option>
))}
</Select>
</Box>
)}
{selectedThing?.type == 'number' && (
<Box>
<Typography level='body-sm'>
When the state of {selectedThing.name} changes as specified below,
the task will become due.
</Typography>
<Box sx={{ display: 'flex', gap: 1, direction: 'row' }}>
<Typography level='body-sm'>State is</Typography>
<Select value={condition} sx={{ width: '50%' }}>
{[
{ name: 'Equal', value: 'eq' },
{ name: 'Not equal', value: 'neq' },
{ name: 'Greater than', value: 'gt' },
{ name: 'Greater than or equal', value: 'gte' },
{ name: 'Less than', value: 'lt' },
{ name: 'Less than or equal', value: 'lte' },
].map(condition => (
<Option
key={condition.value}
value={condition.value}
onClick={() => setCondition(condition.value)}
>
{condition.name}
</Option>
))}
</Select>
<Input
type='number'
value={triggerState}
onChange={e => setTriggerState(e.target.value)}
sx={{ width: '50%' }}
/>
</Box>
</Box>
)}
{selectedThing?.type == 'text' && (
<Box>
<Typography level='body-sm'>
When the state of {selectedThing.name} changes as specified below,
the task will become due.
</Typography>
<Input
value={triggerState}
onChange={e => setTriggerState(e.target.value)}
label='Enter the text to trigger the task'
/>
</Box>
)}
</Card>
)
}
export default ThingTriggerSection