@material-ui/pickers#KeyboardDatePicker TypeScript Examples

The following examples show how to use @material-ui/pickers#KeyboardDatePicker. 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: DateSelector.tsx    From backstage with Apache License 2.0 6 votes vote down vote up
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 #2
Source File: SideDrawerField.tsx    From firetable with Apache License 2.0 5 votes vote down vote up
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 #3
Source File: TableCell.tsx    From firetable with Apache License 2.0 5 votes vote down vote up
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 #4
Source File: index.tsx    From aqualink-app with MIT License 5 votes vote down vote up
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 #5
Source File: FilterControls.tsx    From clearflask with Apache License 2.0 5 votes vote down vote up
FilterControlDatePicker = (props: {
  name: string;
  value?: Date;
  onChanged: (val?: Date) => void;
  KeyboardDatePickerProps?: Partial<React.ComponentProps<typeof KeyboardDatePicker>>;
  type: 'past' | 'future';
}) => {
  const classes = useStyles();
  return (
    <KeyboardDatePicker
      shouldDisableDate={(date) => {
        if (!date) return true;
        if (props.type === 'past') {
          if (date.isAfter(moment().endOf('day'))) return true;
        } else if (props.type === 'future') {
          if (date.isBefore(moment().endOf('day'))) return true;
        }
        return false
      }}
      variant='inline'
      inputVariant='standard'
      size='small'
      views={['year', 'date']}
      format='YYYY/MM/DD'
      autoOk
      keyboardIcon={(
        <CalendarIcon className={classes.dateIcon} fontSize='inherit' />)}
      InputProps={{
        disableUnderline: true,
      }}
      InputAdornmentProps={{ position: 'start' }}
      disableToolbar
      initialFocusedDate={new Date()}
      placeholder={props.name}
      value={props.value || null}
      onChange={val => {
        props.onChanged(val?.toDate());
      }}
      {...props.KeyboardDatePickerProps}
    />
  );
}
Example #6
Source File: Calendar.tsx    From glific-frontend with GNU Affero General Public License v3.0 5 votes vote down vote up
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 #7
Source File: date-picker.tsx    From keycaplendar with MIT License 4 votes vote down vote up
DatePicker = ({
  pickerProps,
  modalProps,
  value,
  fallbackValue,
  onChange,
  month,
  allowQuarter,
  showNowButton,
  saveOnClose,
  required,
  helpTextProps = {},
  ...props
}: DatePickerProps) => {
  const device = useAppSelector(selectDevice);
  const useInline = device === "desktop";
  const orientation = useAppSelector(selectOrientation);
  const landscape = orientation === "landscape";

  const [touched, setTouched] = useState(false);
  const invalid = touched
    ? invalidDate(value, {
        allowQuarter,
        disableFuture: pickerProps?.disableFuture,
        month,
        required,
      })
    : false;

  const validFallback = invalidDate(fallbackValue || "") ? "" : fallbackValue;

  const views: KeyboardDatePickerProps["views"] = month
    ? ["year", "month"]
    : undefined;
  const openTo: KeyboardDatePickerProps["openTo"] = month ? "month" : "date";

  const minDate = pickerProps?.minDate || "2000-01-01";
  const maxDate = pickerProps?.disableFuture
    ? DateTime.now().toFormat(month ? "yyyy-MM" : "yyyy-MM-dd")
    : pickerProps?.maxDate
    ? pickerProps.maxDate
    : DateTime.now()
        .plus({ years: 2 })
        .toFormat(month ? "yyyy-MM" : "yyyy-MM-dd");

  const rifm = useRifm({
    accept: allowQuarter ? /\d|\s|Q/g : /\d/g,
    format: formatDateWithAppend(month, allowQuarter),
    onChange,
    value,
  });

  const [open, setOpen] = useState(false);

  const [dialogVal, setDialogVal] = useState(value);
  useEffect(() => {
    if (dialogVal !== value) {
      setDialogVal(value || validFallback || DateTime.now().toISODate());
    }
  }, [value, fallbackValue]);

  const confirmVal = useInline && !saveOnClose ? onChange : setDialogVal;

  const handleDatePickerChange: KeyboardDatePickerProps["onChange"] = (
    date,
    value
  ) => {
    const finalValue =
      (month ? date?.toFormat("yyyy-MM") : date?.toISODate()) || value || "";
    confirmVal(finalValue);
  };
  const setNow = () => {
    confirmVal(DateTime.now().toFormat(month ? "yyyy-MM" : "yyyy-MM-dd"));
  };

  const closeDialog = () => {
    setOpen(false);
  };

  const confirmDialog = () => {
    onChange(
      dialogVal ||
        validFallback ||
        DateTime.now().toFormat(month ? "yyyy-MM" : "yyyy-MM-dd")
    );
    closeDialog();
  };

  const modal = useInline ? (
    <MenuSurface
      {...modalProps}
      anchorCorner="bottomLeft"
      className={bemClasses("modal", { open }, [modalProps?.className || ""])}
      onClose={saveOnClose ? confirmDialog : undefined}
      open={open && (!allowQuarter || value.charAt(0) !== "Q")}
    >
      <KeyboardDatePicker
        maxDate={maxDate}
        minDate={minDate}
        onChange={handleDatePickerChange}
        openTo={openTo}
        orientation="portrait"
        value={
          saveOnClose
            ? dialogVal
            : value || validFallback || DateTime.now().toISODate()
        }
        variant="static"
        views={views}
        {...pickerProps}
      />
      {showNowButton ? (
        <div className={bemClasses("buttons")}>
          <Button
            label={month ? "This month" : "Today"}
            onClick={setNow}
            type="button"
          />
        </div>
      ) : null}
    </MenuSurface>
  ) : (
    <Dialog
      {...modalProps}
      className={bemClasses("modal", { open }, [modalProps?.className || ""])}
      onClose={closeDialog}
      open={open}
      renderToPortal
    >
      <KeyboardDatePicker
        maxDate={maxDate}
        minDate={minDate}
        onChange={handleDatePickerChange}
        openTo={openTo}
        orientation={orientation}
        value={dialogVal || validFallback || DateTime.now().toISODate()}
        variant="static"
        views={views}
        {...pickerProps}
      />
      <ConditionalWrapper
        condition={landscape}
        wrapper={(children) => (
          <div className={bemClasses("bottom-bar")}>{children}</div>
        )}
      >
        <DialogActions>
          {showNowButton ? (
            <Button
              className={bemClasses("show-now-button")}
              label={month ? "This month" : "Today"}
              onClick={setNow}
              type="button"
            />
          ) : null}
          <DialogButton isDefaultAction label="Cancel" onClick={closeDialog} />
          <DialogButton label="Confirm" onClick={confirmDialog} />
        </DialogActions>
      </ConditionalWrapper>
    </Dialog>
  );

  return (
    <ConditionalWrapper
      condition={useInline}
      wrapper={(children) => (
        <MenuSurfaceAnchor className={bemClasses("anchor")}>
          {children}
        </MenuSurfaceAnchor>
      )}
    >
      <TextField
        {...props}
        className={bemClasses("field")}
        helpText={{
          children: invalid
            ? capitalise(invalid)
            : `Format: ${month ? "YYYY-MM" : "YYYY-MM-DD"}${
                allowQuarter ? " or Q1-4 YYYY" : ""
              }`,
          persistent: true,
          validationMsg: true,
          ...helpTextProps,
        }}
        inputMode="numeric"
        invalid={!!invalid}
        onBlur={() => {
          if (!touched) {
            setTouched(true);
          }
          if (useInline) {
            setOpen(false);
          }
        }}
        onChange={rifm.onChange}
        onFocus={() => {
          if (touched) {
            setTouched(false);
          }
          if (useInline) {
            setOpen(true);
          }
        }}
        pattern={`^\\d{4}-\\d{1,2}${!month ? "-\\d{1,2}" : ""}$${
          allowQuarter ? "|^Q[1-4]{1} \\d{4}$" : ""
        }`}
        required={required}
        trailingIcon={
          useInline
            ? undefined
            : withTooltip(
                <IconButton
                  icon={iconObject(<Event />)}
                  onClick={() => setOpen(true)}
                />,
                "Date picker"
              )
        }
        value={rifm.value}
      />
      {modal}
    </ConditionalWrapper>
  );
}
Example #8
Source File: index.tsx    From aqualink-app with MIT License 4 votes vote down vote up
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 #9
Source File: index.tsx    From aqualink-app with MIT License 4 votes vote down vote up
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&apos;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 #10
Source File: index.tsx    From aqualink-app with MIT License 4 votes vote down vote up
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 #11
Source File: chart-filters.tsx    From backstage with Apache License 2.0 4 votes vote down vote up
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>
  );
}