@material-ui/pickers#MuiPickersUtilsProvider TypeScript Examples
The following examples show how to use
@material-ui/pickers#MuiPickersUtilsProvider.
You can vote up the ones you like or vote down the ones you don't like,
and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: TestContext.tsx From office-booker with MIT License | 6 votes |
TestContext: React.FC<{ user?: User; config?: Config }> = ({ children, user, config, }) => ( <StylesProvider injectFirst> <StyledThemeProvider theme={MaterialTheme}> <MaterialThemeProvider theme={MaterialTheme}> <MuiPickersUtilsProvider utils={DateFnsUtils}> <AppProvider initialState={{ user, config }}> <Structure>{children}</Structure> </AppProvider> </MuiPickersUtilsProvider> </MaterialThemeProvider> </StyledThemeProvider> </StylesProvider> )
Example #2
Source File: Root.tsx From office-booker with MIT License | 6 votes |
Root: React.FC = () => (
<StylesProvider injectFirst>
<StyledThemeProvider theme={MaterialTheme}>
<MaterialThemeProvider theme={MaterialTheme}>
<CssBaseline />
<StyledGlobal />
<MuiPickersUtilsProvider utils={DateFnsUtils}>
<ErrorBoundary>
<AppProvider>
<Structure>
<Routes />
</Structure>
</AppProvider>
</ErrorBoundary>
</MuiPickersUtilsProvider>
</MaterialThemeProvider>
</StyledThemeProvider>
</StylesProvider>
)
Example #3
Source File: root.tsx From keycaplendar with MIT License | 6 votes |
Root = () => (
<Provider store={store}>
<MuiPickersUtilsProvider utils={LocalizedUtils}>
<ThemeProvider>
<RMWCProvider tooltip={{ align: "bottom", enterDelay: 500 }}>
<App />
</RMWCProvider>
</ThemeProvider>
</MuiPickersUtilsProvider>
</Provider>
)
Example #4
Source File: DatePickerElement.test.tsx From react-hook-form-mui with MIT License | 6 votes |
it('renders without crashing', () => {
const div = document.createElement('div')
ReactDOM.render(
<MuiPickersUtilsProvider utils={LocalizedUtils}>
<FormContainer
onSuccess={() => console.log('success')}
defaultValues={''}
>
<DatePickerElement
label="The DatePickerElement label"
name={'basic date picker'}
fullWidth
openTo="year"
/>
</FormContainer>
</MuiPickersUtilsProvider>,
div
)
ReactDOM.unmountComponentAtNode(div)
})
Example #5
Source File: DateSelector.tsx From backstage with Apache License 2.0 | 6 votes |
DateSelector = ({ name, control, setValue }: Props) => {
const label = `${
name.charAt(0).toLocaleUpperCase('en-US') + name.slice(1, name.indexOf('D'))
} date`;
return (
<Controller
name={name}
control={control}
render={({ field }) => (
<FormControl>
<MuiPickersUtilsProvider utils={LuxonUtils}>
<KeyboardDatePicker
disableToolbar
format="dd-MM-yyyy"
label={label}
value={field.value}
onChange={date => {
setValue(name, date?.toISO());
}}
InputProps={{
endAdornment: (
<IconButton onClick={() => setValue(name, null)}>
<ClearIcon />
</IconButton>
),
}}
InputAdornmentProps={{
position: 'start',
}}
/>
</MuiPickersUtilsProvider>
</FormControl>
)}
/>
);
}
Example #6
Source File: TableCell.tsx From firetable with Apache License 2.0 | 5 votes |
export default function Date_({
rowIdx,
column,
value,
onSubmit,
disabled,
}: IHeavyCellProps) {
const classes = useStyles();
const { dataGridRef } = useFiretableContext();
const transformedValue = transformValue(value);
const [handleDateChange] = useDebouncedCallback<DatePickerProps["onChange"]>(
(date) => {
const sanitized = sanitizeValue(date);
if (sanitized === undefined) return;
onSubmit(sanitized);
if (dataGridRef?.current?.selectCell)
dataGridRef.current.selectCell({ rowIdx, idx: column.idx });
},
500
);
if (disabled)
return (
<div className={classes.disabledCell}>
<BasicCell
value={value}
type={(column as any).type}
name={column.key}
/>
</div>
);
return (
<MuiPickersUtilsProvider utils={DateFnsUtils}>
<KeyboardDatePicker
value={transformedValue}
onChange={handleDateChange}
onClick={(e) => e.stopPropagation()}
format={column.config?.format ?? DATE_FORMAT}
fullWidth
clearable
keyboardIcon={<DateIcon />}
className={clsx("cell-collapse-padding", classes.root)}
inputVariant="standard"
InputProps={{
disableUnderline: true,
classes: { root: classes.inputBase, input: classes.input },
}}
InputAdornmentProps={{
position: "start",
classes: { root: classes.inputAdornment },
}}
KeyboardButtonProps={{
size: "small",
classes: { root: !disabled ? "row-hover-iconButton" : undefined },
}}
DialogProps={{ onClick: (e) => e.stopPropagation() }}
disabled={disabled}
/>
</MuiPickersUtilsProvider>
);
}
Example #7
Source File: TimePicker.tsx From glific-frontend with GNU Affero General Public License v3.0 | 5 votes |
TimePicker: React.SFC<TimePickerProps> = ({
variant = 'inline',
inputVariant = 'outlined',
field,
form: { setFieldValue, touched, errors },
placeholder,
disabled = false,
helperText,
}) => {
moment.defaultFormat = 'Thh:mm:ss';
const dateValue = field.value ? moment(field.value, moment.defaultFormat).toDate() : null;
const [open, setOpen] = useState(false);
const errorText = getIn(errors, field.name);
const touchedVal = getIn(touched, field.name);
const hasError = touchedVal && errorText !== undefined;
const handleDateChange = (time: Date | null) => {
const value = time ? moment(time).format('THH:mm:ss') : null;
setFieldValue(field.name, value);
};
return (
<MuiPickersUtilsProvider utils={DateFnsUtils}>
<Grid className={styles.TimePicker}>
<KeyboardTimePicker
error={hasError}
autoOk
open={open}
variant={variant}
inputVariant={inputVariant}
label={placeholder}
data-testid="time-picker"
mask="__:__ _M"
value={dateValue}
onClick={() => !disabled && setOpen(true)}
onClose={() => setOpen(false)}
disabled={disabled}
onChange={(date) => handleDateChange(date)}
keyboardIcon={<ScheduleIcon />}
helperText={hasError ? errorText : ''}
className={styles.picker}
/>
{helperText && (
<div id="helper-text" className={styles.HelperText}>
{helperText}
</div>
)}
</Grid>
</MuiPickersUtilsProvider>
);
}
Example #8
Source File: DateTimePicker.tsx From glific-frontend with GNU Affero General Public License v3.0 | 5 votes |
DateTimePicker: React.SFC<DateTimePickerProps> = ({
variant = 'inline',
inputVariant = 'outlined',
format = 'dd/MM/yyyy hh:mm a',
field,
form: { touched, errors, setFieldValue },
placeholder,
minDate,
onChange,
}) => {
const errorText = getIn(errors, field.name);
const touchedVal = getIn(touched, field.name);
const hasError = touchedVal && errorText !== undefined;
const dateValue = field.value ? field.value : null;
const handleDateChange = (date: Date | null | string) => {
const value = date && date.toString() !== 'Invalid Date' ? date : null;
setFieldValue(field.name, value);
if (onChange) onChange(value);
};
const icon = <CalenderIcon />;
return (
<MuiPickersUtilsProvider utils={DateFnsUtils}>
<Grid className={styles.DateTimePicker}>
<KeyboardDateTimePicker
className={styles.Text}
error={hasError}
autoOk
variant={variant}
inputVariant={inputVariant}
format={format}
data-testid="date-picker-inline"
label={placeholder}
value={dateValue}
onChange={handleDateChange}
helperText={hasError ? errorText : ''}
minDate={minDate}
keyboardIcon={icon}
/>
</Grid>
</MuiPickersUtilsProvider>
);
}
Example #9
Source File: Calendar.tsx From glific-frontend with GNU Affero General Public License v3.0 | 5 votes |
Calendar: React.SFC<CalendarProps> = ({
variant = 'inline',
inputVariant = 'outlined',
format = 'MM/dd/yyyy',
field,
disabled = false,
form: { touched, errors, setFieldValue },
placeholder,
minDate,
}) => {
const errorText = getIn(errors, field.name);
const touchedVal = getIn(touched, field.name);
const hasError = touchedVal && errorText !== undefined;
const dateValue = field.value ? field.value : null;
const [open, setOpen] = useState(false);
const handleDateChange = (date: Date | null | string) => {
if (date) {
if (date !== 'Invalid Date') setFieldValue(field.name, date);
} else {
setFieldValue(field.name, null);
}
};
return (
<MuiPickersUtilsProvider utils={DateFnsUtils}>
<Grid className={styles.Calendar}>
<KeyboardDatePicker
error={hasError}
autoOk
open={open}
variant={variant}
inputVariant={inputVariant}
format={format}
className={styles.CalendarInput}
disabled={disabled}
data-testid="date-picker-inline"
label={placeholder}
value={dateValue}
onClick={() => !disabled && setOpen(true)}
onClose={() => setOpen(false)}
onChange={handleDateChange}
helperText={hasError ? errorText : ''}
minDate={minDate}
/>
</Grid>
</MuiPickersUtilsProvider>
);
}
Example #10
Source File: DatePickerComponent.web.tsx From react-native-jigsaw with MIT License | 5 votes |
DatePickerComponent: React.FC<Props & { theme: typeof Theme }> = ({
value,
onChange,
mode,
toggleVisibility,
isVisible,
theme,
}) => {
const internalTheme = createMuiTheme({
palette: {
primary: {
main: theme?.colors?.primary ?? Theme.colors.primary,
},
secondary: {
main: theme?.colors?.secondary ?? Theme.colors.secondary,
},
},
});
const Picker =
mode === "date"
? DatePicker
: mode === "time"
? TimePicker
: DateTimePicker;
return (
<MuiPickersUtilsProvider utils={DateFnsUtils}>
<ThemeProvider theme={internalTheme}>
<Picker
value={value}
open={isVisible}
onChange={(d) => {
toggleVisibility();
onChange(null, d);
}}
onClose={() => toggleVisibility()}
variant="dialog"
TextFieldComponent={() => null}
/>
</ThemeProvider>
</MuiPickersUtilsProvider>
);
}
Example #11
Source File: FilterControls.tsx From clearflask with Apache License 2.0 | 5 votes |
FilterControlDateRange = (props: {
valueFrom?: Date;
onFromChanged: (val?: Date) => void;
valueTo?: Date;
onToChanged: (val?: Date) => void;
}) => {
const classes = useStyles();
// const prefilledDates: Array<{
// label: string,
// start?: Date,
// end?: Date,
// }> = [
// { label: 'Today', start: moment().startOf('day').toDate(), end: moment().endOf('day').toDate() },
// { label: 'This week', start: moment().startOf('week').toDate(), end: moment().endOf('week').toDate() },
// { label: 'This month', start: moment().startOf('month').toDate(), end: moment().endOf('month').toDate() },
// { label: 'All time' },
// { label: 'Past week', start: moment().startOf('week').toDate(), end: moment().endOf('week').toDate() },
// { label: 'Past month', start: moment().startOf('month').toDate(), end: moment().endOf('month').toDate() },
// ];
return (
<MuiPickersUtilsProvider utils={MomentUtils} locale='en'>
<div className={classes.group}>
<FilterControlTitle name='Range' />
<div className={classes.datesVertical}>
<FilterControlDatePicker
name='From'
value={props.valueFrom}
onChanged={props.onFromChanged}
type='past'
/>
<FilterControlDatePicker
name='To'
value={props.valueTo}
onChanged={props.onToChanged}
type='past'
/>
</div>
{/* <div className={this.props.classes.dateButtons}>
{prefilledDates.map((prefilledDate, index) => {
const checked = prefilledDate.start?.getTime() === from?.getTime() && prefilledDate.end?.getTime() === to?.getTime();
return (
<Button
key={`prefilledDate-${prefilledDate.label}`}
className={this.props.classes.dateButton}
variant='text'
color={!!checked ? 'primary' : undefined}
onClick={e => {
const newSearch: Admin.IdeaSearchAdmin = {
...this.props.search,
filterCreatedStart: prefilledDate.start,
filterCreatedEnd: prefilledDate.end,
}
this.props.onSearchChanged(newSearch);
}}
>
{prefilledDate.label}
</Button>
)
})}
</div> */}
</div>
</MuiPickersUtilsProvider>
);
}
Example #12
Source File: index.tsx From aqualink-app with MIT License | 5 votes |
DatePicker = ({
value,
dateName,
dateNameTextVariant,
pickerSize,
autoOk,
timeZone,
onChange,
classes,
}: DatePickerProps) => {
return (
<Grid item>
<Box display="flex" alignItems="flex-end">
<Typography variant={dateNameTextVariant || "h6"} color="textSecondary">
{`${dateName || "Date"}:`}
</Typography>
<div className={classes.datePicker}>
<MuiPickersUtilsProvider utils={DateFnsUtils}>
<KeyboardDatePicker
size={pickerSize}
className={classes.textField}
helperText=""
disableToolbar
format="MM/dd/yyyy"
name="datePicker"
maxDate={moment()
.tz(timeZone || "UTC")
.format("YYYY/MM/DD")}
minDate={moment(0).format("YYYY/MM/DD")}
autoOk={autoOk}
showTodayButton
value={value || null}
onChange={onChange}
InputProps={{
className: classes.textField,
inputProps: { className: classes.smallPadding },
}}
inputVariant="standard"
KeyboardButtonProps={{ className: classes.calendarButton }}
keyboardIcon={<CalendarTodayIcon fontSize="small" />}
/>
</MuiPickersUtilsProvider>
</div>
</Box>
</Grid>
);
}
Example #13
Source File: TableCell.tsx From firetable with Apache License 2.0 | 5 votes |
export default function DateTime({
rowIdx,
column,
value,
onSubmit,
disabled,
}: IHeavyCellProps) {
const classes = useStyles();
const { dataGridRef } = useFiretableContext();
const transformedValue = transformValue(value);
const [handleDateChange] = useDebouncedCallback<DatePickerProps["onChange"]>(
(date) => {
const sanitized = sanitizeValue(date);
if (sanitized === undefined) return;
onSubmit(sanitized);
if (dataGridRef?.current?.selectCell)
dataGridRef.current.selectCell({ rowIdx, idx: column.idx });
},
500
);
if (disabled)
return (
<div className={classes.disabledCell}>
<BasicCell
value={value}
type={(column as any).type}
name={column.key}
/>
</div>
);
return (
<MuiPickersUtilsProvider utils={DateFnsUtils}>
<KeyboardDateTimePicker
value={transformedValue}
onChange={handleDateChange}
onClick={(e) => e.stopPropagation()}
format={DATE_TIME_FORMAT}
fullWidth
clearable
keyboardIcon={<DateTimeIcon />}
className={clsx("cell-collapse-padding", classes.root)}
inputVariant="standard"
InputProps={{
disableUnderline: true,
classes: { root: classes.inputBase, input: classes.input },
}}
InputAdornmentProps={{
position: "start",
classes: { root: classes.inputAdornment },
}}
KeyboardButtonProps={{
size: "small",
classes: { root: "row-hover-iconButton" },
}}
DialogProps={{ onClick: (e) => e.stopPropagation() }}
dateRangeIcon={<DateRangeIcon className={classes.dateTabIcon} />}
timeIcon={<TimeIcon className={classes.dateTabIcon} />}
/>
</MuiPickersUtilsProvider>
);
}
Example #14
Source File: SideDrawerField.tsx From firetable with Apache License 2.0 | 5 votes |
export default function DateTime({
column,
control,
docRef,
disabled,
...props
}: IDateTimeProps) {
const theme = useTheme();
return (
<Controller
control={control}
name={column.key}
render={({ onChange, onBlur, value }) => {
const transformedValue = transformValue(value);
const handleChange = (date: Date | null) => {
const sanitized = sanitizeValue(date);
if (sanitized === undefined) return;
onChange(sanitized);
};
return (
<MuiPickersUtilsProvider utils={DateFnsUtils}>
<KeyboardDateTimePicker
variant="inline"
inputVariant="filled"
fullWidth
margin="none"
format={DATE_TIME_FORMAT}
placeholder={DATE_TIME_FORMAT}
InputAdornmentProps={{
style: { marginRight: theme.spacing(-1) },
}}
keyboardIcon={<TimeIcon />}
{...props}
value={transformedValue}
onChange={handleChange}
onBlur={onBlur}
label=""
hiddenLabel
id={`sidedrawer-field-${column.key}`}
dateRangeIcon={
<DateRangeIcon
style={{ color: theme.palette.primary.contrastText }}
/>
}
timeIcon={
<TimeIcon
style={{ color: theme.palette.primary.contrastText }}
/>
}
disabled={disabled}
/>
</MuiPickersUtilsProvider>
);
}}
/>
);
}
Example #15
Source File: SideDrawerField.tsx From firetable with Apache License 2.0 | 5 votes |
export default function Date_({
column,
control,
docRef,
disabled,
...props
}: IDateProps) {
const theme = useTheme();
return (
<MuiPickersUtilsProvider utils={DateFnsUtils}>
<Controller
control={control}
name={column.key}
render={({ onChange, onBlur, value }) => {
const transformedValue = transformValue(value);
const handleChange = (date: Date | null) => {
const sanitized = sanitizeValue(date);
if (sanitized === undefined) return;
onChange(sanitized);
};
return (
<KeyboardDatePicker
variant="inline"
inputVariant="filled"
fullWidth
margin="none"
format={column.config?.format ?? DATE_FORMAT}
placeholder={column.config?.format ?? DATE_FORMAT}
InputAdornmentProps={{
style: { marginRight: theme.spacing(-1) },
}}
{...props}
value={transformedValue}
onChange={handleChange}
onBlur={onBlur}
label=""
hiddenLabel
// TODO: move this out to side drawer
id={`sidedrawer-field-${column.key}`}
disabled={disabled}
/>
);
}}
/>
</MuiPickersUtilsProvider>
);
}
Example #16
Source File: ShiftOverrideModal.tsx From backstage with Apache License 2.0 | 4 votes |
ShiftOverrideModal = ({
scheduleId,
shift,
refetchOnCallSchedules,
isModalOpened,
setIsModalOpened,
}: {
scheduleId: number;
shift: Shift;
refetchOnCallSchedules: () => void;
isModalOpened: boolean;
setIsModalOpened: (isModalOpened: boolean) => void;
}) => {
const [
{ isLoading, users, user, start, end },
{ setUser, setStart, setEnd, setIsLoading },
] = useShiftOverride(shift, isModalOpened);
const ilertApi = useApi(ilertApiRef);
const alertApi = useApi(alertApiRef);
const classes = useStyles();
const handleClose = () => {
setIsModalOpened(false);
};
const handleOverride = () => {
if (!shift || !shift.user) {
return;
}
setIsLoading(true);
setTimeout(async () => {
try {
const success = await ilertApi.overrideShift(
scheduleId,
user.id,
start,
end,
);
if (success) {
alertApi.post({ message: 'Shift overridden.' });
refetchOnCallSchedules();
}
} catch (err) {
alertApi.post({ message: err, severity: 'error' });
}
setIsModalOpened(false);
}, 250);
};
if (!shift) {
return null;
}
return (
<Dialog
open={isModalOpened}
onClose={handleClose}
aria-labelledby="override-shift-form-title"
>
<DialogTitle id="override-shift-form-title">Shift override</DialogTitle>
<DialogContent>
<MuiPickersUtilsProvider utils={LuxonUtils}>
<Autocomplete
disabled={isLoading}
options={users}
value={user}
classes={{
root: classes.formControl,
option: classes.option,
}}
onChange={(_event: any, newValue: any) => {
setUser(newValue);
}}
autoHighlight
getOptionLabel={a => ilertApi.getUserInitials(a)}
renderOption={a => (
<div className={classes.optionWrapper}>
<Typography noWrap>{ilertApi.getUserInitials(a)}</Typography>
</div>
)}
renderInput={params => (
<TextField
{...params}
label="User"
variant="outlined"
fullWidth
inputProps={{
...params.inputProps,
autoComplete: 'new-password', // disable autocomplete and autofill
}}
/>
)}
/>
<DateTimePicker
label="Start"
inputVariant="outlined"
fullWidth
margin="normal"
ampm={false}
value={start}
className={classes.formControl}
onChange={date => {
setStart(date ? date.toISO() : '');
}}
/>
<DateTimePicker
label="End"
inputVariant="outlined"
fullWidth
margin="normal"
ampm={false}
value={end}
className={classes.formControl}
onChange={date => {
setEnd(date ? date.toISO() : '');
}}
/>
</MuiPickersUtilsProvider>
</DialogContent>
<DialogActions>
<Button
disabled={isLoading}
onClick={handleOverride}
color="primary"
variant="contained"
>
Override
</Button>
<Button disabled={isLoading} onClick={handleClose} color="primary">
Cancel
</Button>
</DialogActions>
</Dialog>
);
}
Example #17
Source File: chart-filters.tsx From backstage with Apache License 2.0 | 4 votes |
export function ChartFilters(props: ChartFiltersProps) {
const {
analysis,
cicdConfiguration,
initialFetchFilter,
currentFetchFilter,
onChangeFetchFilter,
updateFetchFilter,
initialViewOptions,
onChangeViewOptions,
} = props;
const classes = useStyles();
const [internalRef] = useState<InternalRef>({ first: true });
const [useNowAsToDate, setUseNowAsToDate] = useState(true);
const [toDate, setToDate] = useState(initialFetchFilter.toDate);
const [fromDate, setFromDate] = useState(initialFetchFilter.fromDate);
const [branch, setBranch] = useState(initialFetchFilter.branch);
const statusValues: ReadonlyArray<StatusSelection> =
cicdConfiguration.availableStatuses;
const [selectedStatus, setSelectedStatus] = useState(
initialFetchFilter.status,
);
const [viewOptions, setViewOptions] = useState(initialViewOptions);
const setLowercaseNames = useCallback(
(lowercaseNames: boolean) => {
setViewOptions(old => ({ ...old, lowercaseNames }));
},
[setViewOptions],
);
const setNormalizeTimeRange = useCallback(
(normalizeTimeRange: boolean) => {
setViewOptions(old => ({ ...old, normalizeTimeRange }));
},
[setViewOptions],
);
const setHideLimit = useCallback(
(value: number) => {
setViewOptions(old => ({ ...old, hideLimit: value }));
},
[setViewOptions],
);
const setCollapseLimit = useCallback(
(value: number) => {
setViewOptions(old => ({ ...old, collapsedLimit: value }));
},
[setViewOptions],
);
const setChartType = useCallback(
(statusType: FilterStatusType, chartTypes: ChartTypes) => {
setViewOptions(old => ({
...old,
chartTypes: { ...old.chartTypes, [statusType]: chartTypes },
}));
},
[setViewOptions],
);
const setChartTypeSpecific = useMemo(
() =>
Object.fromEntries(
statusTypes.map(
status =>
[
status,
(chartTypes: ChartTypes) => setChartType(status, chartTypes),
] as const,
),
),
[setChartType],
);
useEffect(() => {
onChangeViewOptions(viewOptions);
}, [onChangeViewOptions, viewOptions]);
useEffect(() => {
if (internalRef.first) {
// Skip calling onChangeFetchFilter first time
internalRef.first = false;
return;
}
onChangeFetchFilter({
toDate,
fromDate,
branch,
status: selectedStatus,
});
}, [
internalRef,
toDate,
fromDate,
branch,
selectedStatus,
onChangeFetchFilter,
]);
const toggleUseNowAsDate = useCallback(() => {
setUseNowAsToDate(!useNowAsToDate);
if (!DateTime.fromJSDate(toDate).hasSame(DateTime.now(), 'day')) {
setToDate(new Date());
}
}, [useNowAsToDate, toDate]);
const hasFetchFilterChanges = useMemo(
() =>
!currentFetchFilter ||
!isSameChartFilter(
{
toDate,
fromDate,
branch,
status: selectedStatus,
},
currentFetchFilter,
),
[toDate, fromDate, branch, selectedStatus, currentFetchFilter],
);
const updateFilter = useCallback(() => {
updateFetchFilter({
toDate,
fromDate,
branch,
status: selectedStatus,
});
}, [toDate, fromDate, branch, selectedStatus, updateFetchFilter]);
const inrefferedStatuses = analysis?.statuses ?? selectedStatus;
return (
<MuiPickersUtilsProvider utils={LuxonUtils}>
<Card className={classes.rootCard}>
<CardHeader
action={
<Button
size="small"
color="secondary"
variant="contained"
onClick={updateFilter}
disabled={!hasFetchFilterChanges}
>
Update
</Button>
}
title={
<Typography variant="subtitle2" className={classes.header}>
Fetching options
</Typography>
}
/>
<CardContent>
<Typography
variant="subtitle2"
className={`${classes.title} ${classes.title}`}
>
Date range
</Typography>
<KeyboardDatePicker
autoOk
variant="inline"
inputVariant="outlined"
label="From date"
format="yyyy-MM-dd"
value={fromDate}
InputAdornmentProps={{ position: 'start' }}
onChange={date => setFromDate(date?.toJSDate() ?? new Date())}
/>
<br />
<FormControl component="fieldset">
<FormGroup>
<FormControlLabel
control={
<Switch
checked={useNowAsToDate}
onChange={toggleUseNowAsDate}
/>
}
label={<Label>To today</Label>}
/>
{useNowAsToDate ? null : (
<KeyboardDatePicker
autoOk
variant="inline"
inputVariant="outlined"
label="To date"
format="yyyy-MM-dd"
value={toDate}
InputAdornmentProps={{ position: 'start' }}
onChange={date => setToDate(date?.toJSDate() ?? new Date())}
/>
)}
</FormGroup>
</FormControl>
<Typography
variant="subtitle2"
className={`${classes.title} ${classes.title}`}
>
Branch
</Typography>
<ButtonSwitch<string>
values={branchValues}
selection={branch}
onChange={setBranch}
/>
<Typography
variant="subtitle2"
className={`${classes.title} ${classes.title}`}
>
Status
</Typography>
<ButtonSwitch<string>
values={statusValues}
multi
vertical
selection={selectedStatus}
onChange={setSelectedStatus}
/>
</CardContent>
</Card>
<Card className={classes.rootCard}>
<CardHeader
title={
<Typography variant="subtitle2" className={classes.header}>
View options
</Typography>
}
/>
<CardContent>
<Toggle
checked={viewOptions.lowercaseNames}
setChecked={setLowercaseNames}
>
<Tooltip
arrow
title={
'Lowercasing names can reduce duplications ' +
'when stage names have changed casing'
}
>
<Label>Lowercase names</Label>
</Tooltip>
</Toggle>
<Toggle
checked={viewOptions.normalizeTimeRange}
setChecked={setNormalizeTimeRange}
>
<Tooltip
arrow
title={
'All charts will use the same x-axis. ' +
'This reduces confusion when stages have been altered over time ' +
'and only appear in a part of the time range.'
}
>
<Label>Normalize time range</Label>
</Tooltip>
</Toggle>
<DurationSlider
header="Hide under peak"
value={viewOptions.hideLimit}
setValue={setHideLimit}
/>
<DurationSlider
header="Collapse under peak"
value={viewOptions.collapsedLimit}
setValue={setCollapseLimit}
/>
<Typography
variant="subtitle2"
className={`${classes.title} ${classes.title}`}
>
Chart styles
</Typography>
{inrefferedStatuses.map(status => (
<Grid key={status} container spacing={0}>
<Grid item>
<ButtonSwitch<ChartType>
values={chartTypeValues}
selection={viewOptions.chartTypes[status as FilterStatusType]}
onChange={setChartTypeSpecific[status]}
multi
/>
</Grid>
<Grid item className={classes.buttonDescription}>
<div>{status}</div>
</Grid>
</Grid>
))}
</CardContent>
</Card>
</MuiPickersUtilsProvider>
);
}
Example #18
Source File: index.tsx From aqualink-app with MIT License | 4 votes |
Form = ({
siteName,
application,
agreed,
handleFormSubmit,
classes,
}: FormProps) => {
const [installationSchedule, setInstallationSchedule] = useState<Date | null>(
null
);
useEffect(() => {
if (application?.installationSchedule) {
setInstallationSchedule(new Date(application.installationSchedule));
}
}, [application]);
const { register, errors, handleSubmit } = useForm({
reValidateMode: "onSubmit",
});
const handleInstalationChange = (date: Date | null) => {
if (date) {
setInstallationSchedule(date);
}
};
const formSubmit = useCallback(
(data: any) => {
const params: SiteApplyParams = {
fundingSource: data.fundingSource,
permitRequirements: data.permitRequirements,
installationResources: data.installationResources,
installationSchedule: new Date(data.installationSchedule).toISOString(),
};
handleFormSubmit(data.siteName, params);
},
[handleFormSubmit]
);
return (
<form className={classes.form} onSubmit={handleSubmit(formSubmit)}>
<Typography className={classes.formTitle} variant="h3">
Your Site
</Typography>
<TextField
className={`${classes.formField} ${classes.textField}`}
variant="outlined"
inputProps={{ className: classes.textField }}
fullWidth
placeholder="Site Name e.g. 'Sombrero Site'"
disabled
defaultValue={siteName}
name="siteName"
inputRef={register({
required: "This is a required field",
})}
error={!!errors.siteName}
helperText={errors?.siteName?.message || ""}
/>
<Typography className={classes.additionalInfo}>
Please provide some additional information for each site:
</Typography>
<Typography>Permitting</Typography>
<TextField
className={`${classes.formField} ${classes.textField}`}
variant="outlined"
inputProps={{ className: classes.textField }}
fullWidth
multiline
rows={2}
defaultValue={application?.permitRequirements || null}
placeholder="Please describe the permitting requirements. Please be sure to mention the authority having jurisdiction"
name="permitRequirements"
inputRef={register({
required: "This is a required field",
})}
error={!!errors.permitRequirements}
helperText={errors?.permitRequirements?.message || ""}
/>
<Typography>Funding Source</Typography>
<TextField
className={`${classes.formField} ${classes.textField}`}
variant="outlined"
inputProps={{ className: classes.textField }}
fullWidth
multiline
rows={2}
defaultValue={application?.fundingSource || null}
placeholder="Funding source for import duties and shipping. Please describe the funding source for the import duties and shipping costs"
name="fundingSource"
inputRef={register({
required: "This is a required field",
})}
error={!!errors.fundingSource}
helperText={errors?.fundingSource?.message || ""}
/>
<Typography>Schedule for installation</Typography>
<Typography className={classes.scheduleDescription}>
What is the soonest date you could install the Smart Buoy and conduct a
survey?
</Typography>
<MuiPickersUtilsProvider utils={DateFnsUtils}>
<KeyboardDatePicker
className={classes.formField}
disableToolbar
format="MM/dd/yyyy"
id="installationSchedule"
name="installationSchedule"
autoOk
showTodayButton
helperText={errors?.installationSchedule?.message || ""}
inputRef={register({
required: "This is a required field",
validate: {
validDate: (value) =>
moment(value, "MM/DD/YYYY", true).isValid() || "Invalid date",
},
})}
error={!!errors.installationSchedule}
value={installationSchedule}
onChange={handleInstalationChange}
KeyboardButtonProps={{
"aria-label": "change date",
}}
inputProps={{
className: classes.textField,
}}
inputVariant="outlined"
/>
</MuiPickersUtilsProvider>
<Typography>
Installation, survey and maintenance personnel and equipment
</Typography>
<TextField
className={`${classes.formField} ${classes.textField}`}
variant="outlined"
inputProps={{ className: classes.textField }}
fullWidth
multiline
rows={4}
defaultValue={application?.installationResources || null}
placeholder="Please provide a description of the people that will be able to conduct periodic surveys and maintenance of the buoy. Please also include a description of the equipment (e.g. a boat, cameras) that are available."
name="installationResources"
inputRef={register({
required: "This is a required field",
})}
error={!!errors.installationResources}
helperText={errors?.installationResources?.message || ""}
/>
<Button
disabled={!agreed}
type="submit"
color="primary"
variant="contained"
>
Submit
</Button>
</form>
);
}
Example #19
Source File: index.tsx From aqualink-app with MIT License | 4 votes |
ExclusionDatesDialog = ({
dialogType,
open,
token,
timeZone,
siteId,
onClose,
classes,
}: ExclusionDatesDialogProps) => {
const dispatch = useDispatch();
// State variables for deploy dialog
const [deployDateTime, setDeployDateTime] = useState<Date | null>(null);
const [deployLoading, setDeployLoading] = useState(false);
const [deployError, setDeployError] = useState<string>();
const [pickerError, setPickerError] = useState("");
// State variables for maintain dialog
const [maintainStartDateTime, setMaintainStartDateTime] =
useState<Date | null>(null);
const [maintainEndDateTime, setMaintainEndDateTime] = useState<Date | null>(
null
);
const [maintainLoading, setMaintainLoading] = useState(false);
const [maintainError, setMaintainError] = useState<string>();
const [startPickerError, setStartPickerError] = useState("");
const [endPickerError, setEndPickerError] = useState("");
const [isConfirmationDialogOpen, setIsConfirmationDialogOpen] =
useState(false);
const isMaintainDisabled =
!maintainStartDateTime || !maintainEndDateTime || maintainLoading;
useEffect(() => {
switch (dialogType) {
case "deploy":
if (deployDateTime) {
setPickerError("");
}
break;
case "maintain":
if (maintainStartDateTime) {
setStartPickerError("");
}
if (maintainEndDateTime) {
setEndPickerError("");
}
break;
default:
break;
}
}, [deployDateTime, dialogType, maintainEndDateTime, maintainStartDateTime]);
const onDeployDialogClose = () => {
setDeployLoading(false);
setDeployDateTime(null);
setDeployError(undefined);
setPickerError("");
onClose();
};
const onMaintainDialogClose = () => {
setMaintainLoading(false);
setMaintainStartDateTime(null);
setMaintainEndDateTime(null);
setMaintainError(undefined);
setStartPickerError("");
setEndPickerError("");
onClose();
};
const onDeploy = () => {
const localDate = setTimeZone(deployDateTime, timeZone);
if (localDate) {
setDeployLoading(true);
siteServices
.deploySpotter(siteId, { endDate: localDate.toString() }, token)
.then(() => {
setPickerError("");
onDeployDialogClose();
dispatch(siteRequest(`${siteId}`));
dispatch(liveDataRequest(`${siteId}`));
})
.catch((err) =>
setDeployError(err?.response?.data?.message || "Something went wrong")
)
.finally(() => setDeployLoading(false));
} else {
setPickerError("Cannot be empty");
}
};
const onMaintainAdd = () => {
const localStartDate = setTimeZone(maintainStartDateTime, timeZone);
const localEndDate = setTimeZone(maintainEndDateTime, timeZone);
if (!localStartDate) {
setStartPickerError("Cannot be empty");
}
if (!localEndDate) {
setEndPickerError("Cannot be empty");
}
if (localStartDate && localEndDate) {
setMaintainLoading(true);
siteServices
.maintainSpotter(
siteId,
{
endDate: localEndDate,
startDate: localStartDate,
},
token
)
.then(() => {
setStartPickerError("");
setEndPickerError("");
onMaintainDialogClose();
dispatch(clearTimeSeriesData());
dispatch(clearTimeSeriesDataRange());
dispatch(setSelectedSite(undefined));
dispatch(siteRequest(`${siteId}`));
dispatch(liveDataRequest(`${siteId}`));
})
.catch((err) =>
setMaintainError(
err?.response?.data?.message || "Something went wrong"
)
)
.finally(() => {
setMaintainLoading(false);
onConfirmationDialogClose();
});
}
};
const confirmActionButtonText = () => {
switch (dialogType) {
case "deploy":
return deployLoading ? "Deploying..." : "Deploy";
case "maintain":
return "Add Period";
default:
return "";
}
};
const onConfirmationDialogOpen = () => setIsConfirmationDialogOpen(true);
const onConfirmationDialogClose = () => setIsConfirmationDialogOpen(false);
const actions: Action[] = [
{
action:
dialogType === "deploy" ? onDeployDialogClose : onMaintainDialogClose,
color: "secondary",
size: "small",
text: "Cancel",
variant: "outlined",
},
{
action: dialogType === "deploy" ? onDeploy : onConfirmationDialogOpen,
color: "primary",
size: "small",
text: confirmActionButtonText(),
variant: "outlined",
disabled: dialogType === "deploy" ? deployLoading : isMaintainDisabled,
},
];
return (
<>
<ConfirmationDialog
open={isConfirmationDialogOpen}
isConfirmLoading={maintainLoading}
onClose={onConfirmationDialogClose}
handleMaintainPeriodAddition={onMaintainAdd}
start={maintainStartDateTime || undefined}
end={maintainEndDateTime || undefined}
timeZone={timeZone || "UTC"}
/>
<Dialog
open={open}
actions={actions}
header={
dialogType === "deploy" ? "Mark as deployed" : "Data Exclusion Dates"
}
onClose={
dialogType === "deploy" ? onDeployDialogClose : onMaintainDialogClose
}
content={
<div className={classes.dialogContent}>
<Box mb="20px">
<Alert severity="info">
{dialogType === "deploy"
? "Spotter data before this date will be deleted."
: "Spotter data between these dates will be deleted."}{" "}
Note: The dates below are in the site's local timezone (
{timeZone || "UTC"}).
</Alert>
</Box>
<Box mb="5px">
{(deployError || maintainError) && (
<Alert severity="error">{deployError || maintainError}</Alert>
)}
</Box>
<Typography
className={classes.dateTitle}
color="textSecondary"
variant="h5"
>
{dialogType === "deploy" ? "Activation Date" : "Start"}
</Typography>
<Grid
className={
dialogType === "maintain"
? classes.startDateContainer
: undefined
}
container
item
spacing={1}
>
<Grid item xs={12} sm={6}>
<MuiPickersUtilsProvider utils={DateFnsUtils}>
<KeyboardDatePicker
className={classes.textField}
disableToolbar
format="MM/dd/yyyy"
autoOk
size="small"
fullWidth
showTodayButton
value={
dialogType === "deploy"
? deployDateTime
: maintainStartDateTime
}
onChange={
dialogType === "deploy"
? setDeployDateTime
: setMaintainStartDateTime
}
KeyboardButtonProps={{
"aria-label": "change date",
}}
inputProps={{
className: classes.textField,
}}
inputVariant="outlined"
error={
dialogType === "deploy"
? pickerError !== ""
: startPickerError !== ""
}
helperText={
dialogType === "deploy" ? pickerError : startPickerError
}
/>
</MuiPickersUtilsProvider>
</Grid>
<Grid item xs={12} sm={6}>
<MuiPickersUtilsProvider utils={DateFnsUtils}>
<KeyboardTimePicker
className={classes.textField}
id="time-picker"
name="diveTime"
size="small"
autoOk
fullWidth
format="HH:mm"
value={
dialogType === "deploy"
? deployDateTime
: maintainStartDateTime
}
onChange={
dialogType === "deploy"
? setDeployDateTime
: setMaintainStartDateTime
}
KeyboardButtonProps={{
"aria-label": "change time",
}}
InputProps={{
className: classes.textField,
}}
keyboardIcon={<AccessTimeIcon />}
inputVariant="outlined"
error={
dialogType === "deploy"
? pickerError !== ""
: startPickerError !== ""
}
helperText={
dialogType === "deploy" ? pickerError : startPickerError
}
/>
</MuiPickersUtilsProvider>
</Grid>
</Grid>
{dialogType === "maintain" && (
<>
<Typography
className={classes.dateTitle}
color="textSecondary"
variant="h5"
>
End
</Typography>
<Grid container item spacing={1}>
<Grid item xs={12} sm={6}>
<MuiPickersUtilsProvider utils={DateFnsUtils}>
<KeyboardDatePicker
className={classes.textField}
disableToolbar
format="MM/dd/yyyy"
size="small"
autoOk
fullWidth
showTodayButton
value={maintainEndDateTime}
onChange={setMaintainEndDateTime}
KeyboardButtonProps={{
"aria-label": "change date",
}}
inputProps={{
className: classes.textField,
}}
inputVariant="outlined"
error={endPickerError !== ""}
helperText={endPickerError}
/>
</MuiPickersUtilsProvider>
</Grid>
<Grid item xs={12} sm={6}>
<MuiPickersUtilsProvider utils={DateFnsUtils}>
<KeyboardTimePicker
className={classes.textField}
id="time-picker"
name="diveTime"
size="small"
autoOk
fullWidth
format="HH:mm"
value={maintainEndDateTime}
onChange={setMaintainEndDateTime}
KeyboardButtonProps={{
"aria-label": "change time",
}}
InputProps={{
className: classes.textField,
}}
keyboardIcon={<AccessTimeIcon />}
inputVariant="outlined"
error={endPickerError !== ""}
helperText={endPickerError}
/>
</MuiPickersUtilsProvider>
</Grid>
</Grid>
</>
)}
</div>
}
/>
</>
);
}
Example #20
Source File: DateInput.tsx From halstack-react with Apache License 2.0 | 4 votes |
DxcDateInput = React.forwardRef<RefType, DateInputPropsType>(
(
{
label,
name,
defaultValue = "",
value,
format = "dd-MM-yyyy",
helperText,
placeholder = false,
clearable,
disabled,
optional,
onChange,
onBlur,
error,
autocomplete,
margin,
size,
tabIndex,
},
ref
) => {
const [innerValue, setInnerValue] = useState(defaultValue);
const [isOpen, setIsOpen] = useState(false);
const [anchorEl, setAnchorEl] = useState(null);
const colorsTheme = useTheme();
const translatedLabels = useTranslatedLabels();
const refDate = ref || useRef(null);
const handleCalendarOnKeyDown = (event) => {
switch (event.keyCode) {
case 27: // Esc
event.preventDefault();
setIsOpen(false);
break;
}
};
const handleCalendarOnClick = (newDate) => {
const newValue = dayjs(newDate).format(format.toUpperCase());
value ?? setInnerValue(newValue);
newDate?.toJSON()
? onChange?.({
value: newValue,
date: newDate,
})
: onChange?.({
value: newValue,
});
};
const handleIOnChange = ({ value: newValue, error: inputError }) => {
value ?? setInnerValue(newValue);
const dayjsDate = dayjs(newValue, format.toUpperCase(), true);
const invalidDateMessage =
newValue !== "" && !dayjsDate.isValid() && translatedLabels.dateInput.invalidDateErrorMessage;
const callbackParams =
inputError || invalidDateMessage
? { value: newValue, error: inputError || invalidDateMessage }
: { value: newValue };
dayjsDate.isValid()
? onChange?.({
...callbackParams,
date: dayjsDate.toDate(),
})
: onChange?.(callbackParams);
};
const handleIOnBlur = ({ value, error: inputError }) => {
const dayjsDate = dayjs(value, format.toUpperCase(), true);
const invalidDateMessage =
value !== "" && !dayjsDate.isValid() && translatedLabels.dateInput.invalidDateErrorMessage;
const callbackParams =
inputError || invalidDateMessage ? { value, error: inputError || invalidDateMessage } : { value };
dayjsDate.isValid()
? onBlur?.({
...callbackParams,
date: dayjsDate.toDate(),
})
: onBlur?.(callbackParams);
};
const openCalendar = () => {
const dateBtn = refDate.current.getElementsByTagName("button")[0];
setIsOpen(!isOpen);
setAnchorEl(dateBtn);
};
const closeCalendar = () => {
setIsOpen(false);
};
const calendarAction = {
onClick: openCalendar,
icon: (
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24" width="24" fill="currentColor">
<path d="M0 0h24v24H0z" fill="none" />
<path d="M20 3h-1V1h-2v2H7V1H5v2H4c-1.1 0-2 .9-2 2v16c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm0 18H4V8h16v13z" />
</svg>
),
};
const dateTheme = createMuiTheme({
overrides: {
MuiTypography: {
root: {
fontFamily: `${colorsTheme.dateInput.pickerFontFamily} !important`,
},
},
MuiPickersYearSelection: {
container: {
color: colorsTheme.dateInput.pickerYearFontColor,
"&::-webkit-scrollbar": {
width: "3px",
},
"&::-webkit-scrollbar-track": {
backgroundColor: "#D9D9D9",
borderRadius: "3px",
},
"&::-webkit-scrollbar-thumb": {
backgroundColor: "#666666",
borderRadius: "3px",
},
},
},
MuiPickersToolbar: {
toolbar: {
backgroundColor: colorsTheme.dateInput.pickerBackgroundColor,
color: colorsTheme.dateInput.pickerDayFontColor,
},
},
MuiIconButton: {
root: {
height: "36px",
width: "36px",
padding: "0px",
},
},
MuiTouchRipple: {
child: {
opacity: "0",
},
},
MuiButtonBase: {
root: {
"&:focus": {
outline: colorsTheme.dateInput.pickerFocusColor + " solid 2px",
},
},
},
MuiPickersBasePicker: {
pickerView: {
minWidth: "unset",
maxWidth: "unset",
minHeight: "unset",
padding: "0px 10px",
height: colorsTheme.dateInput.pickerHeight,
width: colorsTheme.dateInput.pickerWidth,
backgroundColor: colorsTheme.dateInput.pickerBackgroundColor,
fontFamily: colorsTheme.dateInput.pickerFontFamily,
},
},
MuiPickersToolbarText: {
toolbarTxt: {
color: colorsTheme.dateInput.pickerActualDateFontColor,
fontFamily: colorsTheme.dateInput.pickerFontFamily,
fontSize: "2rem",
},
toolbarBtnSelected: {
color: colorsTheme.dateInput.pickerActualDateFontColor,
},
},
MuiPickersCalendarHeader: {
transitionContainer: {
color: colorsTheme.dateInput.pickerMonthFontColor,
},
dayLabel: {
color: colorsTheme.dateInput.pickerWeekFontColor,
fontFamily: colorsTheme.dateInput.pickerFontFamily,
},
switchHeader: {
backgroundColor: "#ffffff",
color: colorsTheme.dateInput.pickerDayFontColor,
},
iconButton: {
backgroundColor: colorsTheme.dateInput.pickerMonthArrowsBackgroundColor,
"&:hover": {
backgroundColor: colorsTheme.dateInput.pickerMonthArrowsBackgroundColor,
},
},
},
MuiPickersCalendar: {
week: {
marginBottom: "2px",
},
},
MuiPickersDay: {
current: {
color: colorsTheme.dateInput.pickerDayFontColor,
},
day: {
fontFamily: colorsTheme.dateInput.pickerFontFamily,
color: colorsTheme.dateInput.pickerDayFontColor,
"&:hover": {
backgroundColor: colorsTheme.dateInput.pickerHoverDateBackgroundColor,
color: colorsTheme.dateInput.pickerHoverDateFontColor,
},
},
daySelected: {
backgroundColor: colorsTheme.dateInput.pickerSelectedDateBackgroundColor,
color: colorsTheme.dateInput.pickerSelectedDateColor,
"&:hover": {
backgroundColor: colorsTheme.dateInput.pickerSelectedDateBackgroundColor,
color: colorsTheme.dateInput.pickerSelectedDateColor,
opacity: "1",
},
},
},
MuiPickersYear: {
yearSelected: {
color: colorsTheme.dateInput.pickerSelectedDateColor,
backgroundColor: colorsTheme.dateInput.pickerSelectedDateBackgroundColor,
margin: "0px 100px",
borderRadius: "20px",
},
root: {
"&:focus": {
color: colorsTheme.dateInput.pickerHoverDateFontColor,
backgroundColor: colorsTheme.dateInput.pickerHoverDateBackgroundColor,
},
},
},
MuiPickersModal: {
dialogAction: {
color: "pink",
},
},
},
});
return (
<ThemeProvider theme={colorsTheme}>
<MuiThemeProvider theme={dateTheme}>
<MuiPickersUtilsProvider utils={DayjsUtils}>
<StyledDPicker>
<DxcTextInput
label={label}
name={name}
defaultValue={defaultValue}
value={value ?? innerValue}
helperText={helperText}
placeholder={placeholder ? format.toUpperCase() : null}
action={calendarAction}
clearable={clearable}
disabled={disabled}
optional={optional}
onChange={handleIOnChange}
onBlur={handleIOnBlur}
error={error}
autocomplete={autocomplete}
margin={margin}
size={size}
tabIndex={tabIndex}
ref={refDate}
/>
<Popover
onKeyDown={handleCalendarOnKeyDown}
open={isOpen}
anchorEl={anchorEl}
anchorOrigin={{
vertical: "bottom",
horizontal: "left",
}}
transformOrigin={{
vertical: "top",
horizontal: "center",
}}
PaperProps={{
style: {
marginTop: "10px",
},
}}
>
<ClickAwayListener onClickAway={closeCalendar}>
<Paper role="dialog" aria-modal="true">
<DatePicker
variant="static"
value={getValueForPicker(value ?? innerValue, format)}
onChange={(date) => handleCalendarOnClick(date)}
format={format}
disabled={disabled}
/>
</Paper>
</ClickAwayListener>
</Popover>
</StyledDPicker>
</MuiPickersUtilsProvider>
</MuiThemeProvider>
</ThemeProvider>
);
}
)
Example #21
Source File: index.tsx From aqualink-app with MIT License | 4 votes |
SurveyForm = ({
siteId,
timeZone,
onSubmit,
classes,
}: SurveyFormProps) => {
const theme = useTheme();
const isMobile = useMediaQuery(theme.breakpoints.down("xs"));
const diveLocation = useSelector(diveLocationSelector);
const [diveDateTime, setDiveDateTime] = useState<Date | null>(null);
const [weather, setWeather] =
useState<SurveyData["weatherConditions"]>("calm");
const itemsSize = isMobile ? "small" : "medium";
const iconSize = isMobile ? "small" : "default";
const { register, errors, handleSubmit, reset } = useForm({
reValidateMode: "onSubmit",
});
const handleDiveDateTimeChange = (date: Date | null) => {
if (date) {
setDiveDateTime(date);
}
};
const handleWeatherChange = (event: ChangeEvent<{ value: unknown }>) => {
setWeather(event.target.value as SurveyData["weatherConditions"]);
};
const nativeSubmit = useCallback(
(data: { comments: string }) => {
if (diveDateTime) {
const dateTime = new Date(
setTimeZone(diveDateTime, timeZone) || diveDateTime
).toISOString();
const weatherConditions = weather;
const { comments } = data;
onSubmit(dateTime, diveLocation, weatherConditions, comments);
}
},
[onSubmit, diveDateTime, timeZone, weather, diveLocation]
);
const resetForm = () => {
reset({
diveTime: null,
diveDate: null,
comments: null,
});
setDiveDateTime(null);
setWeather("calm");
};
return (
<form onSubmit={handleSubmit(nativeSubmit)}>
{/* Dive Date and Time */}
<Grid
className={classes.section}
container
justify="space-between"
spacing={2}
>
<Grid item xs={12} sm={6}>
<Typography variant="h6" gutterBottom>
Dive Date
</Typography>
<MuiPickersUtilsProvider utils={DateFnsUtils}>
<KeyboardDatePicker
className={classes.textField}
disableToolbar
format="MM/dd/yyyy"
fullWidth
id="dive-date"
name="diveDate"
autoOk
showTodayButton
size={itemsSize}
helperText={errors?.diveDate?.message || ""}
inputRef={register({
required: "This is a required field",
validate: {
validDate: (value) =>
moment(value, "MM/DD/YYYY", true).isValid() ||
"Invalid date",
},
})}
error={!!errors.diveDate}
value={diveDateTime}
onChange={handleDiveDateTimeChange}
KeyboardButtonProps={{
"aria-label": "change date",
}}
inputProps={{
className: classes.textField,
}}
inputVariant="outlined"
keyboardIcon={<EventIcon fontSize={iconSize} />}
/>
</MuiPickersUtilsProvider>
</Grid>
<Grid item xs={12} sm={6}>
<Typography variant="h6" gutterBottom>
Dive Local Time
</Typography>
<MuiPickersUtilsProvider utils={DateFnsUtils}>
<KeyboardTimePicker
className={classes.textField}
id="time-picker"
name="diveTime"
fullWidth
autoOk
size={itemsSize}
helperText={errors?.diveTime?.message || ""}
inputRef={register({
required: "This is a required field",
pattern: {
value: /^([0-9]|0[0-9]|1[0-9]|2[0-3]):[0-5][0-9]$/,
message: "Invalid time format",
},
})}
error={!!errors.diveTime}
format="HH:mm"
value={diveDateTime}
onChange={handleDiveDateTimeChange}
KeyboardButtonProps={{
"aria-label": "change time",
}}
InputProps={{
className: classes.textField,
}}
keyboardIcon={<AccessTimeIcon fontSize={iconSize} />}
inputVariant="outlined"
/>
</MuiPickersUtilsProvider>
</Grid>
</Grid>
<Typography variant="h6" gutterBottom>
Dive Location
</Typography>
<Grid className={classes.section} container spacing={2}>
<Grid item xs={12} sm={6}>
<TextField
variant="outlined"
inputProps={{ className: classes.textField }}
fullWidth
placeholder="LAT"
label="Latitude"
value={diveLocation?.lat || ""}
disabled
size={itemsSize}
/>
</Grid>
<Grid item xs={12} sm={6}>
<TextField
variant="outlined"
inputProps={{ className: classes.textField }}
fullWidth
placeholder="LONG"
label="Longitude"
value={diveLocation?.lng || ""}
disabled
size={itemsSize}
/>
</Grid>
</Grid>
{/* Weather Conditions */}
<Grid item xs={12}>
<Typography variant="h6" gutterBottom>
Weather Conditions
</Typography>
</Grid>
<Grid className={classes.extraMargin} item xs={12}>
<TextField
className={classes.textField}
select
id="weather"
name="weather"
value={weather}
onChange={handleWeatherChange}
placeholder="Select One"
fullWidth
variant="outlined"
size={itemsSize}
inputProps={{
className: classes.textField,
}}
>
<MenuItem className={classes.textField} value="calm">
Calm
</MenuItem>
<MenuItem className={classes.textField} value="waves">
Waves
</MenuItem>
<MenuItem className={classes.textField} value="storm">
Stormy
</MenuItem>
</TextField>
</Grid>
<Grid item xs={12}>
<Typography variant="h6" gutterBottom>
Comments
</Typography>
</Grid>
<Grid className={classes.extraMargin} item xs={12}>
<TextField
className={classes.textField}
variant="outlined"
multiline
name="comments"
placeholder="Did anything stand out during this survey"
inputRef={register()}
fullWidth
size={itemsSize}
inputProps={{
className: classes.textField,
}}
/>
</Grid>
{/* SUBMIT */}
<Grid
className={classes.section}
container
justify="flex-end"
item
spacing={2}
>
<Grid item>
<Button
component={Link}
to={`/sites/${siteId}`}
onClick={resetForm}
color="primary"
variant="outlined"
size={itemsSize}
>
Cancel
</Button>
</Grid>
<Grid item>
<Button
size={itemsSize}
onClick={resetForm}
color="primary"
variant="outlined"
>
Clear
</Button>
</Grid>
<Grid item>
<Button
size={itemsSize}
type="submit"
color="primary"
variant="contained"
>
Next
</Button>
</Grid>
</Grid>
</form>
);
}
Example #22
Source File: DatePicker.tsx From UsTaxes with GNU Affero General Public License v3.0 | 4 votes |
export function DatePicker<TFormValues>(
props: DatePickerProps<TFormValues>
): ReactElement {
const {
label,
required = false,
name,
minDate = new Date(1900, 0, 1),
maxDate,
useGrid = true,
sizes = { xs: 12 }
} = props
const classes = useStyles()
const {
control,
formState: { isSubmitted }
} = useFormContext<TFormValues>()
return (
<ConditionallyWrap
condition={useGrid}
wrapper={(children) => (
<Grid item {...sizes}>
{children}
</Grid>
)}
>
<Controller
name={name}
control={control}
rules={{
required
}}
render={({ field: { value, onChange } }) => {
const forceError: boolean | undefined =
(isSubmitted &&
required &&
((value as string | undefined | null) ?? undefined) ===
undefined) ||
value === ''
const forceErrorProps = forceError
? {
helperText: 'Input is required',
error: true
}
: {}
return (
<div className={classes.root}>
<FormControl component="fieldset">
<MuiPickersUtilsProvider utils={DateFnsUtils}>
<MuiDatePicker
{...forceErrorProps}
data-testid={name}
label={label}
InputLabelProps={{
shrink: true
}}
inputVariant="filled"
minDate={minDate}
maxDate={maxDate}
maxDateMessage={`Date cannot be after ${maxDate.toLocaleDateString()}`}
minDateMessage={`Date cannot be before ${minDate.toLocaleDateString()}`}
// invalid date message can be shown once user has attempted to submit
invalidDateMessage={
isSubmitted ? 'Invalid date format' : undefined
}
value={(value as string | undefined) ?? null}
placeholder="mm/dd/yyyy"
onChange={onChange}
format="MM/dd/yyyy"
/>
</MuiPickersUtilsProvider>
</FormControl>
</div>
)
}}
/>
</ConditionallyWrap>
)
}
Example #23
Source File: RightSideBar.tsx From projectboard with MIT License | 4 votes |
RightSideBar: React.FC<Props> = ({ showMenu, onCloseMenu }) => {
const ref = useRef<HTMLDivElement>() as RefObject<HTMLDivElement>;
const { task } = useSelector((state: RootState) => state.taskDetail);
const { error, loading, success } = useSelector((state: RootState) => state.updateTask);
const dispatch = useDispatch();
const params = useParams<URLParams>();
const { getAccessTokenSilently } = useAuth0();
const classes = classNames(
`absolute lg:static inset-0 transform duration-300 lg:relative lg:translate-x-0 bg-white flex flex-col flex-shrink-0 w-80 font-sans text-sm text-gray-700 border-l border-gray-100 lg:shadow-none justify-items-start h-screen`,
{
'-translate-x-full ease-out shadow-none': !showMenu,
'translate-x-0 ease-in shadow-xl': showMenu
}
);
const [startDate, setStartDate] = useState<MaterialUiPickersDate>(task.startDate);
const [dueDate, setDueDate] = useState<MaterialUiPickersDate>(task.dueDate);
const [priority, setPriority] = useState(task.priority);
const [label, setLabel] = useState(task.label);
const [status, setStatus] = useState(task.status);
const [assignee, setAssignee] = useState<Member>(task.assignee);
const [edited, setEdited] = useState(false);
// Date Pickers
const [isOpenStartDate, setIsOpenStartDate] = useState(false);
const [isOpenDueDate, setIsOpenDueDate] = useState(false);
const onStartDatePick = () => {
setIsOpenStartDate(true);
};
const onDueDatePick = () => {
setIsOpenDueDate(true);
};
let ready = false;
useClickOutside(ref, () => {
if (ready && showMenu && onCloseMenu)
onCloseMenu();
});
const onCancel = useCallback(() => {
setPriority(task.priority);
setLabel(task.label);
setDueDate(task.dueDate);
setStartDate(task.startDate);
setAssignee(task.assignee);
setStatus(task.status);
setEdited(false);
}, [task]);
const onSave = async () => {
const fieldsToUpdate = {
status: task.status !== status,
priority: task.priority !== priority,
startDate: task.startDate !== startDate,
dueDate: task.dueDate !== dueDate,
label: task.label !== label,
assignee: task?.assignee?.user?._id !== assignee?.user?._id
};
const body: any = {};
if (fieldsToUpdate.dueDate) body.dueDate = dueDate;
if (fieldsToUpdate.startDate) body.startDate = startDate;
if (fieldsToUpdate.assignee) body.assignee = assignee._id;
if (fieldsToUpdate.priority) body.priority = priority;
if (fieldsToUpdate.status) body.status = status;
if (fieldsToUpdate.label) body.label = label;
const token = await getAccessTokenSilently();
dispatch(updateTaskMicroProperties(params.taskId, params.projectId, token, body));
};
useEffect(() => {
// eslint-disable-next-line react-hooks/exhaustive-deps
setTimeout(() => ready = true, 300);
});
useEffect(() => {
if (priority !== task.priority) setEdited(true);
if (label !== task.label) setEdited(true);
if (status !== task.status) setEdited(true);
if (startDate !== task.startDate) setEdited(true);
if (dueDate !== task.dueDate) setEdited(true);
if (assignee?.user?._id !== task?.assignee?.user?._id) setEdited(true);
}, [priority, label, status, assignee, edited, task.priority, task.label, task.status, task.startDate, task.dueDate, startDate, dueDate, task?.assignee?.user?._id]);
useEffect(() => {
if (error) {
showError('Please try again later.', 'Unable to Update Task.');
onCancel();
dispatch({ type: UPDATE_TASK_MICRO_PROPS_CLEAR });
}
if (success) {
showInfo('', 'Task Updated Successfully');
setEdited(false);
getAccessTokenSilently().then(token => {
dispatch(getTaskDetail(token, params.projectId, params.taskId));
dispatch({ type: UPDATE_TASK_MICRO_PROPS_CLEAR });
});
}
}, [success, error, onCancel, dispatch, getAccessTokenSilently, params]);
return (
<>
<div className={classes} style={{ zIndex: 3 }} ref={ref}>
<button
className='flex-shrink-0 px-5 ml-2 lg:hidden h-14 focus:outline-none'
onClick={onCloseMenu}
>
<CloseIcon className='w-4' />
</button>
{/* Top menu*/}
{loading ? <div className='flex items-center justify-center flex-1'><CircularProgress color="primary" /></div> : <div className='flex flex-col flex-grow-0 flex-shrink-0 px-5 py-3 pt-10'>
<div className='flex justify-between items-center mb-6'>
<p className='text-gray-400 font-medium w-28'>Status</p>
<div className='flex items-center mr-auto'>
<StatusMenu
id='status-menu'
button={<button className='flex items-center justify-center w-6 h-6 border-none rounded focus:outline-none hover:bg-gray-100'><StatusIcon status={status} /></button>}
onSelect={(st) => {
setStatus(st);
}}
/>
<p className='text-gray-500 ml-2'>{getStatusText(status)}</p>
</div>
</div>
<div className='flex justify-between items-center mb-6'>
<p className='text-gray-400 font-medium w-28'>Priority</p>
<div className='flex items-center mr-auto'>
<PriorityMenu
// id='priority-menu'
button={<button
className='inline-flex items-center h-6 px-2 text-gray-500 border-none rounded focus:outline-none hover:bg-gray-100 hover:text-gray-700'
>
{priority && <PriorityIcon priority={priority} />}
</button>}
onSelect={(val) => setPriority(val)}
/>
<p className='text-gray-500 ml-2'>{getPriorityString(priority)}</p>
</div>
</div>
<div className='flex justify-between items-center mb-6'>
<p className='text-gray-400 font-medium w-28'>Assignee</p>
<div className='flex items-center mr-auto'>
<AssigneeMenu
button={<button className='inline-flex items-center h-6 px-2 mr-2 text-gray-500 border-none rounded focus:outline-none hover:bg-gray-100 hover:text-gray-700'>
{!assignee ? <><OwnerIcon className='w-3.5 h-3.5 mr-2' />
<span>Unassigned</span></> : <><OwnerIcon className='w-3.5 h-3.5 mr-2' />
<span>{`${assignee?.user?.firstName} ${assignee?.user?.lastName}`}</span></>}
</button>}
onSelect={(assignee: Member) => setAssignee(assignee)}
/>
</div>
</div>
<div className='flex justify-between items-center mb-6'>
<p className='text-gray-400 font-medium w-28'>Label</p>
<div className='flex items-center mr-auto'>
<LabelMenu
id='label-menu'
onSelect={(label: Label) => setLabel(label.name)}
button={<button className='inline-flex items-center h-6 px-2 mr-2 text-gray-500 border-none rounded focus:outline-none hover:bg-gray-100 hover:text-gray-700'>
{label === 'No Label' ? <><LabelIcon className='w-3.5 h-3.5 mr-2' /> <span>No Label</span> </> : <><div className="w-2.5 h-2.5 rounded-full mr-2" style={{ background: getLabelObj(label)?.color }}></div> <span>{getLabelObj(label)?.name}</span> </>}
</button>} />
</div>
</div>
<MuiPickersUtilsProvider utils={DateFnsUtils}>
<div className='flex justify-between items-center mb-6'>
<p className='text-gray-400 font-medium w-28'>Start Date</p>
<div className='flex items-center mr-auto'>
<DatePicker
disablePast
open={isOpenStartDate}
onOpen={() => setIsOpenStartDate(true)}
onClose={() => setIsOpenStartDate(false)}
TextFieldComponent={() => null}
variant='dialog'
onChange={(date: MaterialUiPickersDate) => setStartDate(date)}
value={startDate}
/>
<button onClick={onStartDatePick} className='inline-flex items-center h-6 px-2 mr-2 text-gray-500 border-none rounded focus:outline-none hover:bg-gray-100 hover:text-gray-700'>
{startDate ? `${formatDate(startDate)}` : "Start Date"}
</button>
</div>
</div>
<div className='flex justify-between items-center mb-6'>
<p className='text-gray-400 font-medium w-28'>Due Date</p>
<div className='flex items-center mr-auto'>
<DatePicker
disablePast
open={isOpenDueDate}
onOpen={() => setIsOpenDueDate(true)}
onClose={() => setIsOpenDueDate(false)}
TextFieldComponent={() => null}
variant='dialog'
onChange={(date: MaterialUiPickersDate) => setDueDate(date)}
value={dueDate}
/>
<button onClick={onDueDatePick} className='inline-flex items-center h-6 px-2 mr-2 text-gray-500 border-none rounded focus:outline-none hover:bg-gray-100 hover:text-gray-700'>
{dueDate ? `${formatDate(dueDate)}` : "Due Date"}
</button>
</div>
</div>
<div className='flex justify-around mt-4'>
{edited && <><button onClick={onCancel} className='inline-flex items-center justify-center px-4 py-2 transition-all rounded-md border border-gray-200 text-gray-500 hover:bg-gray-100 rouned hover:text-gray-700 w-28'>Cancel</button>
<button onClick={onSave} className='ml-3 inline-flex items-center justify-center px-4 py-2 transition-all duration-400 bg-indigo-700 rounded-md hover:bg-indigo-800 rouned w-5/12 text-white'>Save</button></>}
</div>
</MuiPickersUtilsProvider>
</div>}
</div>
</>
);
}
Example #24
Source File: CreateTask.tsx From projectboard with MIT License | 4 votes |
CreateTask: React.FC<Props> = ({ match, history, location }) => {
const [showMenu, setShowMenu] = useState(false);
const [title, setTitle] = useState('');
const [description, setDescription] = useState('');
const [priority, setPriority] = useState(Priority.NO_PRIORITY);
const [status, setStatus] = useState(location?.state?.status || Status.BACKLOG);
const [label, setLabel] = useState(DEFAULT_LABLES[3]);
const [assignee, setAssignee] = useState<Member>();
const [dueDate, setDueDate] = useState<MaterialUiPickersDate>(() => {
const date = new Date();
const newDate = new Date(Number(date));
newDate.setDate(date.getDate() + 10);
return newDate;
});
const [startDate, setStartDate] = useState<MaterialUiPickersDate>(new Date());
// Date Pickers
const [isOpenStartDate, setIsOpenStartDate] = useState(false);
const [isOpenDueDate, setIsOpenDueDate] = useState(false);
const { projectData } = useSelector((state: RootState) => state.currentProject);
const { memberList } = useSelector((state: RootState) => state);
const memberIds = memberList.members.map((member: Member) => member._id);
const { getAccessTokenSilently } = useAuth0();
const onAssigneeSelect = (member: Member) => {
setAssignee(member);
};
const onStartDatePick = () => {
setIsOpenStartDate(true);
};
const onDueDatePick = () => {
setIsOpenDueDate(true);
};
const handleSubmit = async () => {
if (title === '') {
showWarning('Please enter a title before submiting', 'Title required');
return;
}
const body = {
title,
priority,
status,
label: label.name,
assignee: assignee?._id,
description,
startDate,
dueDate
};
try {
showWarning('Please wait!', 'Creating Task...');
const token = await getAccessTokenSilently();
const { data } = await axios({
url: `${baseURL}${endpoints.projects}/${match.params.projectId}${endpoints.tasks}`,
method: 'POST',
data: body,
headers: {
Authorization: `Bearer ${token}`
}
});
socket.emit('create_task_update', { newTask: data, member: projectData._id, memberIds });
} catch (e) {
showError('', 'Error Creating Task.');
}
setTitle('');
setDescription('');
setPriority(Priority.NO_PRIORITY);
setStatus(Status.BACKLOG);
showInfo('You created new task.', 'Task created');
history.push(`/projects/${projectData.project._id}/tasks`);
};
useEffect(() => {
const buyCoffee = document.getElementById('bmc-wbtn');
if (buyCoffee) {
buyCoffee.style.opacity = '0';
buyCoffee.style.visibility = 'hidden';
}
return () => {
const buyCoffee = document.getElementById('bmc-wbtn');
if (buyCoffee) {
buyCoffee.style.opacity = '1';
buyCoffee.style.visibility = 'visible';
}
};
}, []);
return (
<>
<LeftSideBar showMenu={showMenu} onCloseMenu={() => setShowMenu(false)} />
<div className="flex flex-col flex-grow">
<div className="flex flex-col w-full py-4 flex-1">
{/* header */}
<div className="flex items-center justify-between flex-shrink-0 px-4">
<div className="flex items-center">
<span className="inline-flex items-center p-1 text-gray-400 bg-gray-100 rounded">
<GitIssueIcon className="w-3 mr-1" />
<span>{projectData.project.title}</span>
</span>
<span className="ml-2 font-normal text-gray-700">› New Task</span>
</div>
<div className="flex items-center">
<Link
to={`/projects/${projectData.project._id}/tasks`}
className="inline-flex items-center justify-center ml-2 text-gray-500 h-7 w-7 hover:bg-gray-100 rouned hover:text-gray-700"
>
<CloseIcon className="w-4" />
</Link>
</div>
</div>
<div className="flex flex-col flex-1 pb-3.5 overflow-y-auto">
{/* Task title */}
<div className="flex items-center w-full mt-1.5 px-4">
<StatusMenu
id="status-menu"
button={
<button className="flex items-center justify-center w-6 h-6 border-none rounded focus:outline-none hover:bg-gray-100">
<StatusIcon status={status} />
</button>
}
onSelect={st => {
setStatus(st);
}}
/>
<input
className="w-full ml-1.5 text-lg font-semibold placeholder-gray-400 border-none h-7 focus:outline-none"
placeholder="Task title"
value={title}
onChange={e => setTitle(e.target.value)}
/>
</div>
{/* Task description editor */}
<div className="flex px-4">
<MarkdownStyles>
<Editor
autoFocus
id="editor"
defaultValue={description}
onChange={value => setDescription(value())}
className="mt-4 ml-5 font-normal border-none appearance-none min-h-12 text-md focus:outline-none"
placeholder="Add description..."
/>
</MarkdownStyles>
</div>
</div>
{/* Task labels & priority */}
<div className="flex items-center px-4 pb-3 mt-1 border-b border-gray-200 flex-wrap">
<PriorityMenu
// id='priority-menu'
button={
<button className="mt-2 inline-flex items-center h-6 px-2 text-gray-500 bg-gray-200 border-none rounded focus:outline-none hover:bg-gray-100 hover:text-gray-700 mr-2">
<PriorityIcon priority={priority} className="mr-2" />
<span>{getPriorityString(priority)}</span>
</button>
}
onSelect={val => setPriority(val)}
/>
<AssigneeMenu
button={
<button className="mt-2 inline-flex items-center h-6 px-2 mr-2 text-gray-500 bg-gray-200 border-none rounded focus:outline-none hover:bg-gray-100 hover:text-gray-700">
{!assignee ? (
<>
<OwnerIcon className="w-3.5 h-3.5 mr-2" />
<span>Assignee</span>
</>
) : (
<>
<OwnerIcon className="w-3.5 h-3.5 mr-2" />
<span>{`${assignee.user.firstName} ${assignee.user.lastName}`}</span>
</>
)}
</button>
}
onSelect={onAssigneeSelect}
/>
<LabelMenu
id="label-menu"
onSelect={(label: Label) => setLabel(label)}
button={
<button className="mt-2 inline-flex items-center h-6 px-2 mr-2 text-gray-500 bg-gray-200 border-none rounded focus:outline-none hover:bg-gray-100 hover:text-gray-700">
{label.name === 'No Label' ? (
<>
<LabelIcon className="w-3.5 h-3.5 mr-2" /> <span>No Label</span>{' '}
</>
) : (
<>
<div
className="w-2.5 h-2.5 rounded-full mr-2"
style={{ background: label.color }}
></div>{' '}
<span>{label.name}</span>{' '}
</>
)}
</button>
}
/>
<MuiPickersUtilsProvider utils={DateFnsUtils}>
<DatePicker
disablePast
open={isOpenStartDate}
onOpen={() => setIsOpenStartDate(true)}
onClose={() => setIsOpenStartDate(false)}
TextFieldComponent={() => null}
variant="dialog"
onChange={(date: MaterialUiPickersDate) => setStartDate(date)}
value={startDate}
/>
<button
onClick={onStartDatePick}
className="mt-2 inline-flex items-center h-6 px-2 mr-2 text-gray-500 bg-gray-200 border-none rounded focus:outline-none hover:bg-gray-100 hover:text-gray-700"
>
{startDate ? `Start Date: ${formatDate(startDate)}` : 'Start Date'}
</button>
<DatePicker
disablePast
open={isOpenDueDate}
onOpen={() => setIsOpenDueDate(true)}
onClose={() => setIsOpenDueDate(false)}
TextFieldComponent={() => null}
variant="dialog"
onChange={(date: MaterialUiPickersDate) => setDueDate(date)}
value={dueDate}
/>
<button
onClick={onDueDatePick}
className="mt-2 inline-flex items-center h-6 px-2 mr-2 text-gray-500 bg-gray-200 border-none rounded focus:outline-none hover:bg-gray-100 hover:text-gray-700"
>
{dueDate ? `Due Date: ${formatDate(dueDate)}` : 'Due Date'}
</button>
</MuiPickersUtilsProvider>
</div>
{/* Footer */}
<div className="flex items-center justify-between flex-shrink-0 px-4 pt-3 w-full">
<div className="flex items-center w-full">
<button
className="px-3 ml-2 text-white bg-indigo-600 rounded hover:bg-indigo-700 h-7 focus:outline-none ml-auto"
onClick={handleSubmit}
>
Save Task
</button>
</div>
</div>
</div>
</div>
</>
);
}