react-garden
Version:
React + TypeScript + ThreeJS app using Material UI on NextJS, Apollo Client, GraphQL + WordPress REST APIs, for ThreeD web development.. a part of the threed.ai code family.
328 lines (307 loc) • 11.3 kB
JavaScript
// ** React Imports
import { useState, useEffect, forwardRef, useCallback, Fragment } from 'react'
// ** MUI Imports
import Box from '@mui/material/Box'
import Drawer from '@mui/material/Drawer'
import Select from '@mui/material/Select'
import Switch from '@mui/material/Switch'
import Button from '@mui/material/Button'
import MenuItem from '@mui/material/MenuItem'
import TextField from '@mui/material/TextField'
import InputLabel from '@mui/material/InputLabel'
import Typography from '@mui/material/Typography'
import FormControl from '@mui/material/FormControl'
import FormHelperText from '@mui/material/FormHelperText'
import FormControlLabel from '@mui/material/FormControlLabel'
// ** Third Party Imports
import DatePicker from 'react-datepicker'
import { useForm, Controller } from 'react-hook-form'
// ** Icons Imports
import Close from 'mdi-material-ui/Close'
import DeleteOutline from 'mdi-material-ui/DeleteOutline'
// ** Styled Components
import DatePickerWrapper from '~/@core/styles/libs/react-datepicker'
const capitalize = string => string && string[0].toUpperCase() + string.slice(1)
const defaultState = {
url: '',
title: '',
guests: [],
allDay: true,
description: '',
endDate: new Date(),
calendar: 'Business',
startDate: new Date()
}
const AddEventSidebar = props => {
// ** Props
const {
store,
dispatch,
addEvent,
updateEvent,
drawerWidth,
calendarApi,
deleteEvent,
handleSelectEvent,
addEventSidebarOpen,
handleAddEventSidebarToggle
} = props
// ** States
const [values, setValues] = useState(defaultState)
const {
control,
setValue,
clearErrors,
handleSubmit,
formState: { errors }
} = useForm({ defaultValues: { title: '' } })
const handleSidebarClose = async () => {
setValues(defaultState)
clearErrors()
dispatch(handleSelectEvent(null))
handleAddEventSidebarToggle()
}
const onSubmit = data => {
const modifiedEvent = {
url: values.url,
display: 'block',
title: data.title,
end: values.endDate,
allDay: values.allDay,
start: values.startDate,
extendedProps: {
calendar: capitalize(values.calendar),
guests: values.guests && values.guests.length ? values.guests : undefined,
description: values.description.length ? values.description : undefined
}
}
if (store.selectedEvent === null || (store.selectedEvent !== null && !store.selectedEvent.title.length)) {
dispatch(addEvent(modifiedEvent))
} else {
dispatch(updateEvent({ id: store.selectedEvent.id, ...modifiedEvent }))
}
calendarApi.refetchEvents()
handleSidebarClose()
}
const handleDeleteEvent = () => {
if (store.selectedEvent) {
dispatch(deleteEvent(store.selectedEvent.id))
}
// calendarApi.getEventById(store.selectedEvent.id).remove()
handleSidebarClose()
}
const handleStartDate = date => {
if (date > values.endDate) {
setValues({ ...values, startDate: new Date(date), endDate: new Date(date) })
}
}
const resetToStoredValues = useCallback(() => {
if (store.selectedEvent !== null) {
const event = store.selectedEvent
setValue('title', event.title || '')
setValues({
url: event.url || '',
title: event.title || '',
allDay: event.allDay,
guests: event.extendedProps.guests || [],
description: event.extendedProps.description || '',
calendar: event.extendedProps.calendar || 'Business',
endDate: event.end !== null ? event.end : event.start,
startDate: event.start !== null ? event.start : new Date()
})
}
}, [setValue, store.selectedEvent])
const resetToEmptyValues = useCallback(() => {
setValue('title', '')
setValues(defaultState)
}, [setValue])
useEffect(() => {
if (store.selectedEvent !== null) {
resetToStoredValues()
} else {
resetToEmptyValues()
}
}, [addEventSidebarOpen, resetToStoredValues, resetToEmptyValues, store.selectedEvent])
const PickersComponent = forwardRef(({ ...props }, ref) => {
return (
<TextField
inputRef={ref}
fullWidth
{...props}
label={props.label || ''}
sx={{ width: '100%' }}
error={props.error}
/>
)
})
const RenderSidebarFooter = () => {
if (store.selectedEvent === null || (store.selectedEvent !== null && !store.selectedEvent.title.length)) {
return (
<>
<Button size='large' type='submit' variant='contained' sx={{ mr: 4 }}>
Add
</Button>
<Button size='large' variant='outlined' color='secondary' onClick={resetToEmptyValues}>
Reset
</Button>
</>
)
} else {
return (
<>
<Button size='large' type='submit' variant='contained' sx={{ mr: 4 }}>
Update
</Button>
<Button size='large' variant='outlined' color='secondary' onClick={resetToStoredValues}>
Reset
</Button>
</>
)
}
}
return (
<Drawer
anchor='right'
open={addEventSidebarOpen}
onClose={handleSidebarClose}
ModalProps={{ keepMounted: true }}
sx={{ '& .MuiDrawer-paper': { width: ['100%', drawerWidth] } }}
>
<Box
className='sidebar-header'
sx={{
display: 'flex',
justifyContent: 'space-between',
backgroundColor: 'background.default',
p: theme => theme.spacing(3, 3.255, 3, 5.255)
}}
>
<Typography variant='h6'>
{store.selectedEvent !== null && store.selectedEvent.title.length ? 'Update Event' : 'Add Event'}
</Typography>
<Box sx={{ display: 'flex', alignItems: 'center' }}>
{store.selectedEvent !== null && store.selectedEvent.title.length ? (
<DeleteOutline
fontSize='small'
sx={{ cursor: 'pointer', mr: store.selectedEvent !== null ? 2 : 0 }}
onClick={handleDeleteEvent}
/>
) : null}
<Close fontSize='small' onClick={handleSidebarClose} sx={{ cursor: 'pointer' }} />
</Box>
</Box>
<Box className='sidebar-body' sx={{ p: theme => theme.spacing(5, 6) }}>
<DatePickerWrapper>
<form onSubmit={handleSubmit(onSubmit)} autoComplete='off'>
<FormControl fullWidth sx={{ mb: 6 }}>
<Controller
name='title'
control={control}
rules={{ required: true }}
render={({ field: { value, onChange } }) => (
<TextField label='Title' value={value} onChange={onChange} error={Boolean(errors.title)} />
)}
/>
{errors.title && (
<FormHelperText sx={{ color: 'error.main' }} id='event-title-error'>
This field is required
</FormHelperText>
)}
</FormControl>
<FormControl fullWidth sx={{ mb: 6 }}>
<InputLabel id='event-calendar'>Calendar</InputLabel>
<Select
label='Calendar'
value={values.calendar}
labelId='event-calendar'
onChange={e => setValues({ ...values, calendar: e.target.value })}
>
<MenuItem value='Personal'>Personal</MenuItem>
<MenuItem value='Business'>Business</MenuItem>
<MenuItem value='Family'>Family</MenuItem>
<MenuItem value='Holiday'>Holiday</MenuItem>
<MenuItem value='ETC'>ETC</MenuItem>
</Select>
</FormControl>
<Box sx={{ mb: 6 }}>
<DatePicker
selectsStart
id='event-start-date'
endDate={values.endDate}
selected={values.startDate}
startDate={values.startDate}
showTimeSelect={!values.allDay}
dateFormat={!values.allDay ? 'yyyy-MM-dd hh:mm' : 'yyyy-MM-dd'}
customInput={<PickersComponent label='Start Date' registername='startDate' />}
onChange={date => setValues({ ...values, startDate: new Date(date) })}
onSelect={handleStartDate}
/>
</Box>
<Box sx={{ mb: 6 }}>
<DatePicker
selectsEnd
id='event-end-date'
endDate={values.endDate}
selected={values.endDate}
minDate={values.startDate}
startDate={values.startDate}
showTimeSelect={!values.allDay}
dateFormat={!values.allDay ? 'yyyy-MM-dd hh:mm' : 'yyyy-MM-dd'}
customInput={<PickersComponent label='End Date' registername='endDate' />}
onChange={date => setValues({ ...values, endDate: new Date(date) })}
/>
</Box>
<FormControl sx={{ mb: 6 }}>
<FormControlLabel
label='All Day'
control={
<Switch checked={values.allDay} onChange={e => setValues({ ...values, allDay: e.target.checked })} />
}
/>
</FormControl>
<TextField
fullWidth
type='url'
id='event-url'
sx={{ mb: 6 }}
label='Event URL'
value={values.url}
onChange={e => setValues({ ...values, url: e.target.value })}
/>
<FormControl fullWidth sx={{ mb: 6 }}>
<InputLabel id='event-guests'>Guests</InputLabel>
<Select
multiple
label='Guests'
value={values.guests}
labelId='event-guests'
id='event-guests-select'
onChange={e => setValues({ ...values, guests: e.target.value })}
>
<MenuItem value='bruce'>Bruce</MenuItem>
<MenuItem value='clark'>Clark</MenuItem>
<MenuItem value='diana'>Diana</MenuItem>
<MenuItem value='john'>John</MenuItem>
<MenuItem value='barry'>Barry</MenuItem>
</Select>
</FormControl>
<TextField
rows={4}
multiline
fullWidth
sx={{ mb: 6 }}
label='Description'
id='event-description'
value={values.description}
onChange={e => setValues({ ...values, description: e.target.value })}
/>
<Box sx={{ display: 'flex', alignItems: 'center' }}>
<RenderSidebarFooter />
</Box>
</form>
</DatePickerWrapper>
</Box>
</Drawer>
)
}
export default AddEventSidebar