@material-ui/pickers#DatePicker TypeScript Examples

The following examples show how to use @material-ui/pickers#DatePicker. 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: DatePickerComponent.web.tsx    From react-native-jigsaw with MIT License 5 votes vote down vote up
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 #2
Source File: SQFormDatePicker.tsx    From SQForm with MIT License 4 votes vote down vote up
function SQFormDatePicker({
  name,
  label,
  size = 'auto',
  isDisabled = false,
  placeholder = '',
  onBlur,
  onChange,
  setDisabledDate,
  muiFieldProps,
  muiTextInputProps = {},
  isCalendarOnly = false,
  InputProps,
  InputAdornmentProps,
}: SQFormDatePickerProps): JSX.Element {
  const {
    formikField: {field, helpers},
    fieldState: {isFieldError, isFieldRequired},
    fieldHelpers: {handleBlur, HelperTextComponent},
  } = useForm<Moment | null, Moment | null>({
    name,
    onBlur,
  });

  const handleChange = (date: Moment | null) => {
    helpers.setValue(date);
    onChange && onChange(date);
  };

  const [isCalendarOpen, setIsCalendarOpen] = React.useState(false);
  const handleClose = () => setIsCalendarOpen(false);
  const toggleCalendar = () => setIsCalendarOpen(!isCalendarOpen);
  const handleClickAway = () => {
    if (isCalendarOpen) {
      setIsCalendarOpen(false);
    }
  };

  const classes = useStyles();

  // An empty string will not reset the DatePicker so we have to pass null
  const value = field.value || null;

  return (
    <ClickAwayListener onClickAway={handleClickAway}>
      <Grid item sm={size}>
        <DatePicker
          label={label}
          disabled={isDisabled}
          shouldDisableDate={setDisabledDate}
          value={value}
          onChange={handleChange}
          onClose={handleClose}
          onOpen={toggleCalendar}
          open={isCalendarOpen}
          renderInput={(inputProps) => {
            return (
              <TextField
                {...inputProps}
                name={name}
                color="primary"
                error={isFieldError}
                fullWidth={true}
                inputProps={{...inputProps.inputProps, ...muiTextInputProps}}
                InputLabelProps={{shrink: true}}
                FormHelperTextProps={{error: isFieldError}}
                helperText={!isDisabled && HelperTextComponent}
                placeholder={placeholder}
                onBlur={handleBlur}
                required={isFieldRequired}
                onClick={
                  isCalendarOnly && !isDisabled
                    ? toggleCalendar
                    : handleClickAway
                }
                classes={classes}
              />
            );
          }}
          InputProps={InputProps}
          InputAdornmentProps={InputAdornmentProps}
          {...muiFieldProps}
        />
      </Grid>
    </ClickAwayListener>
  );
}
Example #3
Source File: SQFormDatePickerWithDateFNS.tsx    From SQForm with MIT License 4 votes vote down vote up
function SQFormDatePickerWithDateFNS({
  name,
  label,
  size = 'auto',
  isDisabled = false,
  placeholder = '',
  onBlur,
  onChange,
  setDisabledDate,
  muiFieldProps,
  muiTextInputProps = {},
  isCalendarOnly = false,
  InputProps,
  InputAdornmentProps,
}: SQFormDatePickerDateFNSProps): JSX.Element {
  const {
    formikField: {field, helpers},
    fieldState: {isFieldError, isFieldRequired},
    fieldHelpers: {handleBlur, HelperTextComponent},
  } = useForm<Date | null, Date | null>({
    name,
    onBlur,
  });

  const handleChange = (date: Date | null) => {
    helpers.setValue(date);
    onChange && onChange(date);
  };

  const [isCalendarOpen, setIsCalendarOpen] = React.useState(false);
  const handleClose = () => setIsCalendarOpen(false);
  const toggleCalendar = () => setIsCalendarOpen(!isCalendarOpen);
  const handleClickAway = () => {
    if (isCalendarOpen) {
      setIsCalendarOpen(false);
    }
  };

  const classes = useStyles();

  // An empty string will not reset the DatePicker so we have to pass null
  const value = field.value || null;

  return (
    <ClickAwayListener onClickAway={handleClickAway}>
      <Grid item sm={size}>
        <DatePicker
          label={label}
          disabled={isDisabled}
          shouldDisableDate={setDisabledDate}
          value={value}
          onChange={handleChange}
          onClose={handleClose}
          onOpen={toggleCalendar}
          open={isCalendarOpen}
          renderInput={(inputProps) => {
            return (
              <TextField
                {...inputProps}
                name={name}
                color="primary"
                error={isFieldError}
                fullWidth={true}
                inputProps={{...inputProps.inputProps, ...muiTextInputProps}}
                InputLabelProps={{shrink: true}}
                FormHelperTextProps={{error: isFieldError}}
                helperText={!isDisabled && HelperTextComponent}
                placeholder={placeholder}
                onBlur={handleBlur}
                required={isFieldRequired}
                onClick={
                  isCalendarOnly && !isDisabled
                    ? toggleCalendar
                    : handleClickAway
                }
                classes={classes}
              />
            );
          }}
          InputProps={InputProps}
          InputAdornmentProps={InputAdornmentProps}
          {...muiFieldProps}
        />
      </Grid>
    </ClickAwayListener>
  );
}
Example #4
Source File: DateInput.tsx    From halstack-react with Apache License 2.0 4 votes vote down vote up
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 #5
Source File: Bookings.tsx    From office-booker with MIT License 4 votes vote down vote up
Bookings: React.FC<RouteComponentProps> = () => {
  // Global state
  const { state, dispatch } = useContext(AppContext);
  const { user } = state;

  // Local state
  const [loading, setLoading] = useState(true);
  const [offices, setOffices] = useState<Office[] | undefined>();

  const [selectedOffice, setSelectedOffice] = useState<Office | undefined>();
  const [selectedDate, setSelectedDate] = useState(new Date());

  const [dbBookings, setDbBookings] = useState<Booking[] | undefined>();
  const [sortedBookings, setSortedBookings] = useState<Booking[] | undefined>();

  const [sortBy, setSortBy] = useState<keyof Booking>('user');
  const [sortOrder, setSortOrder] = useState<SortOrder>('asc');

  const [bookingToCancel, setBookingToCancel] = useState<undefined | Booking>();

  // Theme
  const theme = useTheme();
  const fullScreen = useMediaQuery(theme.breakpoints.down('sm'));

  // Helpers
  const getAllBookings = useCallback(() => {
    if (selectedOffice) {
      getBookings({ office: selectedOffice, date: format(selectedDate, 'yyyy-MM-dd') })
        .then((data) => setDbBookings(data))
        .catch((err) => {
          // Handle errors
          setLoading(false);

          dispatch({
            type: 'SET_ALERT',
            payload: {
              message: formatError(err),
              color: 'error',
            },
          });
        });
    }
  }, [selectedOffice, selectedDate, dispatch]);

  const findOffice = useCallback(
    (name: OfficeWithSlots['name']) => offices && offices.find((o) => o.name === name),
    [offices]
  );

  // Effects
  useEffect(() => {
    if (user) {
      // Get all offices admin can manage
      getOffices()
        .then((data) =>
          setOffices(
            data.filter((office) =>
              user.permissions.officesCanManageBookingsFor.find(
                (userOffice) => userOffice.name === office.name
              )
            )
          )
        )
        .catch((err) => {
          // Handle errors
          setLoading(false);

          dispatch({
            type: 'SET_ALERT',
            payload: {
              message: formatError(err),
              color: 'error',
            },
          });
        });
    }
  }, [user, dispatch]);

  useEffect(() => {
    if (user && offices && offices.length > 0 && !selectedOffice) {
      // Retrieve first office user can manage bookings for
      setSelectedOffice(user.permissions.officesCanManageBookingsFor[0]);
    }
  }, [user, offices, selectedOffice, findOffice]);

  useEffect(() => {
    if (selectedOffice) {
      // Retrieve bookings
      getAllBookings();
    }
  }, [dispatch, selectedOffice, selectedDate, getAllBookings]);

  useEffect(() => {
    if (dbBookings) {
      // Sort it!
      setSortedBookings(sortData([...dbBookings], sortBy, sortOrder));
    }
  }, [dbBookings, sortBy, sortOrder]);

  useEffect(() => {
    if (loading && sortedBookings) {
      // Wait for local state to be ready
      setLoading(false);
    }
  }, [loading, sortedBookings]);

  // Handlers
  const handleSort = (key: keyof Booking) => {
    if (key === sortBy) {
      setSortOrder(sortOrder === 'desc' ? 'asc' : 'desc');
    } else {
      setSortBy(key);
    }
  };

  const handleCancelBooking = (booking: Booking) => {
    cancelBooking(booking.id, booking.user)
      .then(() => {
        // Clear selected booking
        setBookingToCancel(undefined);

        // Retrieve updated bookings
        getAllBookings();

        // Show confirmation alert
        dispatch({
          type: 'SET_ALERT',
          payload: {
            message: 'Booking cancelled',
            color: 'success',
          },
        });
      })
      .catch((err) =>
        dispatch({
          type: 'SET_ALERT',
          payload: {
            message: formatError(err),
            color: 'error',
          },
        })
      );
  };

  // Render
  if (!user) {
    return null;
  }

  return (
    <AdminLayout currentRoute="bookings">
      <BookingStyles>
        {loading ? (
          <Loading />
        ) : (
          <>
            <h3>Bookings</h3>

            <OurButton
              startIcon={<AddCircleIcon />}
              type="submit"
              color="secondary"
              onClick={() => navigate('/admin/booking')}
              variant="contained"
              size="small"
            >
              New Booking
            </OurButton>

            {selectedOffice && (
              <Paper square className="table-container">
                <div className="filter">
                  <FormControl className="filter-office">
                    <InputLabel id="office-label">Office</InputLabel>
                    <Select
                      labelId="office-label"
                      id="office"
                      value={selectedOffice.name}
                      onChange={(e) => setSelectedOffice(findOffice(e.target.value as string))}
                    >
                      {user.permissions.officesCanManageBookingsFor.map((office, index) => (
                        <MenuItem value={office.name} key={index}>
                          {office.name}
                        </MenuItem>
                      ))}
                    </Select>
                  </FormControl>

                  <div className="filter-date">
                    <IconButton
                      onClick={() => setSelectedDate(addDays(new Date(selectedDate), -1))}
                      className="date-arrow"
                    >
                      <KeyboardArrowLeftIcon />
                    </IconButton>

                    <DatePicker
                      autoOk
                      disableToolbar
                      variant="inline"
                      label="Date"
                      format="dd/MM/yyyy"
                      value={selectedDate}
                      onChange={(date) => setSelectedDate(date as Date)}
                      className="date-picker"
                    />

                    <IconButton
                      onClick={() => setSelectedDate(addDays(new Date(selectedDate), 1))}
                      className="date-arrow"
                    >
                      <KeyboardArrowRightIcon />
                    </IconButton>
                  </div>
                </div>

                <div className="total-bookings">
                  <InputLabel className="bookings-count-label">Bookings:</InputLabel>
                  <span>{sortedBookings && sortedBookings.length}</span>
                </div>

                <TableContainer className="table">
                  <Table>
                    <TableHead>
                      <TableRow>
                        <TableCell className="table-header">
                          <TableSortLabel
                            active={sortBy === 'user'}
                            direction={sortOrder}
                            onClick={() => handleSort('user')}
                          >
                            User
                          </TableSortLabel>
                        </TableCell>
                        {selectedOffice.parkingQuota > 0 && (
                          <TableCell className="table-header">
                            <TableSortLabel
                              active={sortBy === 'parking'}
                              direction={sortOrder}
                              onClick={() => handleSort('parking')}
                            >
                              Parking
                            </TableSortLabel>
                          </TableCell>
                        )}
                        <TableCell />
                      </TableRow>
                    </TableHead>
                    <TableBody>
                      {sortedBookings && sortedBookings.length > 0 ? (
                        sortedBookings.map((booking, index) => {
                          const parsedDate = parseISO(booking.date);

                          return (
                            <TableRow key={index}>
                              <TableCell>{booking.user}</TableCell>
                              {selectedOffice.parkingQuota > 0 && (
                                <TableCell>{booking.parking ? 'Yes' : 'No'}</TableCell>
                              )}
                              {isToday(parsedDate) || !isPast(parsedDate) ? (
                                <TableCell align="right">
                                  <div className="btn-container">
                                    <OurButton
                                      type="submit"
                                      variant="contained"
                                      color="secondary"
                                      size="small"
                                      onClick={() => setBookingToCancel(booking)}
                                    >
                                      Cancel
                                    </OurButton>
                                  </div>
                                </TableCell>
                              ) : (
                                <TableCell />
                              )}
                            </TableRow>
                          );
                        })
                      ) : (
                        <TableRow>
                          <TableCell>No bookings found</TableCell>
                          {selectedOffice.parkingQuota > 0 && <TableCell />}
                          <TableCell />
                        </TableRow>
                      )}
                    </TableBody>
                  </Table>
                </TableContainer>
              </Paper>
            )}
          </>
        )}

        {bookingToCancel && (
          <Dialog fullScreen={fullScreen} open={true} onClose={() => setBookingToCancel(undefined)}>
            <DialogTitle>{'Are you sure you want to cancel this booking?'}</DialogTitle>
            <DialogContent>
              <DialogContentText>
                Booking for <strong>{bookingToCancel.user}</strong> on{' '}
                <strong>{format(parseISO(bookingToCancel.date), 'do LLLL')}</strong> for{' '}
                <strong>{bookingToCancel.office.name}</strong>
              </DialogContentText>
            </DialogContent>
            <DialogActions>
              <Button onClick={() => setBookingToCancel(undefined)} color="primary" autoFocus>
                No
              </Button>
              <Button
                autoFocus
                onClick={() => handleCancelBooking(bookingToCancel)}
                color="primary"
              >
                Yes
              </Button>
            </DialogActions>
          </Dialog>
        )}
      </BookingStyles>
    </AdminLayout>
  );
}
Example #6
Source File: CreateBooking.tsx    From office-booker with MIT License 4 votes vote down vote up
AdminCreateBooking: React.FC<RouteComponentProps> = () => {
  // Global state
  const { state, dispatch } = useContext(AppContext);
  const { config, user } = state;

  // Local state
  const [loading, setLoading] = useState(false);
  const [offices, setOffices] = useState<Office[] | undefined>();
  const [selectedOffice, setSelectedOffice] = useState<Office | undefined>();
  const [selectedOfficeWithSlots, setSelectedWithSlots] = useState<OfficeWithSlots | undefined>();
  const [officeSlot, setOfficeSlot] = useState<OfficeSlot | undefined>();
  const [bookingDate, setBookingDate] = useState(addDays(new Date(), +1));
  const [email, setEmail] = useState('');
  const [parking, setParking] = useState(false);
  const [showReasonConfirmation, setShowReasonConfirmation] = useState(false);
  const [bookingReason, setBookingReason] = useState<string | undefined>();
  const [isAutoApprovedUser, setIsAutoApprovedUser] = useState<boolean>(false);
  const [searchedUser, setSearchedUser] = useState<User | undefined>();

  // Helpers
  const findOffice = useCallback(
    (name: OfficeWithSlots['name']) => offices && offices.find((o) => o.name === name),
    [offices]
  );

  const handleFetchUser = () => {
    setIsAutoApprovedUser(false);

    if (user && config?.reasonToBookRequired) {
      // Get selected user
      getUser(email)
        .then((searchedUser) => setSearchedUser(searchedUser))
        .catch((err) => {
          // Handle errors
          setLoading(false);

          dispatch({
            type: 'SET_ALERT',
            payload: {
              message: formatError(err),
              color: 'error',
            },
          });
        });
    }
  };

  // Effects
  useEffect(() => {
    if (user) {
      // Get all offices user can manage
      getOffices()
        .then((data) =>
          setOffices(
            data.filter((office) =>
              user.permissions.officesCanManageBookingsFor.find(
                (userOffice) => userOffice.name === office.name
              )
            )
          )
        )
        .catch((err) => {
          // Handle errors
          setLoading(false);

          dispatch({
            type: 'SET_ALERT',
            payload: {
              message: formatError(err),
              color: 'error',
            },
          });
        });
    }
  }, [dispatch, user]);

  useEffect(() => {
    if (user && offices && offices.length > 0 && !selectedOffice) {
      // Retrieve first office user can manage bookings for
      setSelectedOffice(findOffice(user.permissions.officesCanManageBookingsFor[0].name));
    }
  }, [user, offices, selectedOffice, findOffice]);

  useEffect(() => {
    if (selectedOffice === undefined) {
      setSelectedWithSlots(undefined);
    } else {
      setLoading(true);
      getOffice(selectedOffice.id).then((result) => {
        setLoading(false);
        setSelectedWithSlots(result);
      });
    }
  }, [selectedOffice]);

  useEffect(() => {
    if (selectedOfficeWithSlots) {
      setOfficeSlot(
        selectedOfficeWithSlots.slots.find((s) => s.date === format(bookingDate, 'yyyy-MM-dd'))
      );
    }
  }, [selectedOfficeWithSlots, bookingDate]);

  useEffect(() => {
    if (officeSlot) {
      // Wait for everything to be ready
      setLoading(false);
    }
  }, [officeSlot]);

  useEffect(() => {
    if (searchedUser?.autoApproved === true) {
      setIsAutoApprovedUser(true);
    }
  }, [searchedUser?.autoApproved]);

  // Handlers
  const handleSubmit = (e?: React.FormEvent<HTMLFormElement>) => {
    // Validation
    if (email === '') {
      return dispatch({
        type: 'SET_ALERT',
        payload: {
          message: 'Email address required',
          color: 'error',
        },
      });
    }

    if (!config || !validateEmail(config.emailRegex, email)) {
      return dispatch({
        type: 'SET_ALERT',
        payload: {
          message: 'Valid email address required',
          color: 'error',
        },
      });
    }

    if (!selectedOffice || !officeSlot) {
      return dispatch({
        type: 'SET_ALERT',
        payload: {
          message: 'Office required',
          color: 'error',
        },
      });
    }

    if (officeSlot.booked + 1 > selectedOffice.quota) {
      return dispatch({
        type: 'SET_ALERT',
        payload: {
          message: 'No office spaces available',
          color: 'error',
        },
      });
    }

    if (
      selectedOffice.parkingQuota > 0 &&
      parking &&
      officeSlot.bookedParking + 1 > selectedOffice.parkingQuota
    ) {
      return dispatch({
        type: 'SET_ALERT',
        payload: {
          message: 'No office parking spaces available',
          color: 'error',
        },
      });
    }

    // Submit
    const formattedDate = format(bookingDate, 'yyyy-MM-dd');

    createBooking(email, formattedDate, selectedOffice, parking, bookingReason)
      .then(() => {
        // Increase office quota
        // This assumes the date and selected office haven't changed
        setOfficeSlot(
          (slot) =>
            slot && {
              ...slot,
              booked: (slot.booked += 1),
              bookedParking: parking ? (slot.bookedParking += 1) : slot.bookedParking,
            }
        );

        // Clear form
        setEmail('');
        setParking(false);
        setBookingReason(undefined);
        setIsAutoApprovedUser(false);
        setSearchedUser(undefined);

        // Show success alert
        dispatch({
          type: 'SET_ALERT',
          payload: {
            message: `Booking created for ${email}!`,
            color: 'success',
          },
        });
      })
      .catch((err) =>
        // Handle error
        dispatch({
          type: 'SET_ALERT',
          payload: {
            message: formatError(err),
            color: 'error',
          },
        })
      );
  };

  // Render
  if (!user) {
    return null;
  }

  return (
    <AdminLayout currentRoute="bookings">
      <CreateBookingStyles>
        {loading || !offices ? (
          <Loading />
        ) : (
          <>
            <h3>Bookings</h3>

            <Paper square className="form-container">
              <h4>New Booking</h4>

              <form
                onSubmit={(e) => {
                  e.preventDefault();
                  config?.reasonToBookRequired && !isAutoApprovedUser
                    ? setShowReasonConfirmation(true)
                    : handleSubmit(e);
                }}
              >
                <div className="field">
                  <TextField
                    id="outlined-helperText"
                    label="Email address"
                    helperText="Who is the booking for"
                    variant="outlined"
                    type="email"
                    value={email}
                    onChange={(e) => setEmail(e.target.value)}
                    onBlur={() => {
                      handleFetchUser();
                    }}
                    className="input"
                  />
                </div>

                <div className="field">
                  <FormControl variant="outlined" className="input">
                    <InputLabel id="office-label" shrink>
                      Office
                    </InputLabel>
                    <Select
                      labelId="office-label"
                      id="office"
                      value={selectedOffice?.name || ''}
                      onChange={(e) =>
                        setSelectedOffice(offices.find((o) => o.name === e.target.value))
                      }
                      label="Office"
                      required
                    >
                      {offices.map((office, index) => (
                        <MenuItem value={office.name} key={index}>
                          {office.name}
                        </MenuItem>
                      ))}
                    </Select>
                  </FormControl>
                </div>

                {selectedOfficeWithSlots && (
                  <>
                    <div className="field">
                      <DatePicker
                        autoOk
                        disableToolbar
                        minDate={selectedOfficeWithSlots.slots[0].date}
                        maxDate={
                          selectedOfficeWithSlots.slots[selectedOfficeWithSlots.slots.length - 1]
                            .date
                        }
                        inputVariant="outlined"
                        variant="inline"
                        label="Date"
                        format="dd/MM/yyyy"
                        value={bookingDate}
                        onChange={(date) => setBookingDate(date as Date)}
                        className="input"
                      />
                    </div>

                    {officeSlot && (
                      <>
                        <div className="field bump short">
                          <p>
                            <strong>{selectedOfficeWithSlots.quota - officeSlot.booked}</strong>{' '}
                            office spaces available
                          </p>

                          {selectedOfficeWithSlots.parkingQuota > 0 && (
                            <p>
                              <strong>
                                {selectedOfficeWithSlots.parkingQuota - officeSlot.bookedParking}
                              </strong>{' '}
                              parking spaces available
                            </p>
                          )}
                        </div>

                        {selectedOfficeWithSlots.parkingQuota > 0 && (
                          <div className="field bump">
                            <FormControlLabel
                              control={
                                <Checkbox
                                  checked={parking}
                                  onChange={(_, checked) => setParking(checked)}
                                />
                              }
                              label="Include parking"
                              disabled={
                                selectedOfficeWithSlots.parkingQuota - officeSlot.bookedParking <= 0
                              }
                            />
                          </div>
                        )}
                      </>
                    )}
                  </>
                )}

                <OurButton
                  type="submit"
                  variant="contained"
                  color="primary"
                  disabled={
                    !selectedOffice || !officeSlot || selectedOffice.quota - officeSlot.booked <= 0
                  }
                >
                  Create booking
                </OurButton>
              </form>
            </Paper>
            <Dialog
              open={showReasonConfirmation}
              onClose={() => setShowReasonConfirmation(false)}
              disableBackdropClick
            >
              <DialogContent>
                <DialogContentText color="secondary">
                  You can only leave home for work purposes where it is unreasonable for you to do
                  your job from home. Please briefly explain why you cannot work from home.
                </DialogContentText>
                <TextField
                  autoFocus
                  label="Details"
                  type="text"
                  margin="normal"
                  fullWidth
                  multiline
                  required
                  value={bookingReason}
                  onChange={(e) => setBookingReason(e.target.value)}
                />
              </DialogContent>
              <DialogActions>
                <OurButton
                  onClick={() => setShowReasonConfirmation(false)}
                  size="small"
                  color="primary"
                >
                  Cancel
                </OurButton>
                <OurButton
                  onClick={() => {
                    if (bookingDate && bookingReason && bookingReason.trim().length > 0) {
                      setShowReasonConfirmation(false);
                      handleSubmit();
                    }
                  }}
                  variant="contained"
                  size="small"
                  color="secondary"
                >
                  Confirm{parking ? ` + Parking` : null}
                </OurButton>
              </DialogActions>
            </Dialog>
          </>
        )}
      </CreateBookingStyles>
    </AdminLayout>
  );
}
Example #7
Source File: RightSideBar.tsx    From projectboard with MIT License 4 votes vote down vote up
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 #8
Source File: CreateTask.tsx    From projectboard with MIT License 4 votes vote down vote up
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>
        </>
    );
}