@material-ui/pickers#KeyboardTimePicker TypeScript Examples

The following examples show how to use @material-ui/pickers#KeyboardTimePicker. 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: TimePicker.tsx    From glific-frontend with GNU Affero General Public License v3.0 5 votes vote down vote up
TimePicker: React.SFC<TimePickerProps> = ({
  variant = 'inline',
  inputVariant = 'outlined',
  field,
  form: { setFieldValue, touched, errors },
  placeholder,
  disabled = false,
  helperText,
}) => {
  moment.defaultFormat = 'Thh:mm:ss';
  const dateValue = field.value ? moment(field.value, moment.defaultFormat).toDate() : null;
  const [open, setOpen] = useState(false);

  const errorText = getIn(errors, field.name);
  const touchedVal = getIn(touched, field.name);
  const hasError = touchedVal && errorText !== undefined;

  const handleDateChange = (time: Date | null) => {
    const value = time ? moment(time).format('THH:mm:ss') : null;
    setFieldValue(field.name, value);
  };

  return (
    <MuiPickersUtilsProvider utils={DateFnsUtils}>
      <Grid className={styles.TimePicker}>
        <KeyboardTimePicker
          error={hasError}
          autoOk
          open={open}
          variant={variant}
          inputVariant={inputVariant}
          label={placeholder}
          data-testid="time-picker"
          mask="__:__ _M"
          value={dateValue}
          onClick={() => !disabled && setOpen(true)}
          onClose={() => setOpen(false)}
          disabled={disabled}
          onChange={(date) => handleDateChange(date)}
          keyboardIcon={<ScheduleIcon />}
          helperText={hasError ? errorText : ''}
          className={styles.picker}
        />
        {helperText && (
          <div id="helper-text" className={styles.HelperText}>
            {helperText}
          </div>
        )}
      </Grid>
    </MuiPickersUtilsProvider>
  );
}
Example #2
Source File: time-picker.tsx    From keycaplendar with MIT License 4 votes vote down vote up
TimePicker = ({
  pickerProps,
  modalProps,
  value,
  fallbackValue,
  onChange,
  showNowButton,
  saveOnClose,
  required,
  helpTextProps = {},
  ...props
}: TimePickerProps) => {
  const device = useAppSelector(selectDevice);
  const useInline = device === "desktop";
  const orientation = useAppSelector(selectOrientation);
  const landscape = orientation === "landscape";

  const [touched, setTouched] = useState(false);
  const invalid = touched ? invalidTime(value, { required }) : false;

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

  const rifm = useRifm({
    accept: /\d:/g,
    format: formatTime,
    onChange,
    value,
  });

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

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

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

  const handleTimePickerChange: KeyboardTimePickerProps["onChange"] = (
    date,
    value
  ) => {
    const finalValue =
      date?.toLocaleString(DateTime.TIME_24_SIMPLE) || value || "";
    confirmVal(finalValue);
  };
  const setNow = () => {
    confirmVal(DateTime.now().toLocaleString(DateTime.TIME_24_SIMPLE));
  };

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

  const confirmDialog = () => {
    onChange(
      dialogVal ||
        validFallback ||
        DateTime.now().toLocaleString(DateTime.TIME_24_SIMPLE)
    );
    closeDialog();
  };

  const modal = useInline ? (
    <MenuSurface
      {...modalProps}
      anchorCorner="bottomLeft"
      className={bemClasses("modal", { open }, [modalProps?.className || ""])}
      onClose={saveOnClose ? confirmDialog : undefined}
      open={open}
    >
      <KeyboardTimePicker
        ampm={false}
        onChange={handleTimePickerChange}
        openTo="hours"
        orientation="portrait"
        value={`2020-12-20T${
          saveOnClose
            ? dialogVal
            : value || validFallback || DateTime.now().toISODate()
        }`}
        variant="static"
        {...pickerProps}
      />
      {showNowButton ? (
        <div className={bemClasses("buttons")}>
          <Button label="Now" onClick={setNow} type="button" />
        </div>
      ) : null}
    </MenuSurface>
  ) : (
    <Dialog
      {...modalProps}
      className={bemClasses("modal", { open }, [modalProps?.className || ""])}
      onClose={closeDialog}
      open={open}
      renderToPortal
    >
      <KeyboardTimePicker
        ampm={false}
        onChange={handleTimePickerChange}
        openTo="hours"
        orientation={orientation}
        value={`2020-12-20T${
          dialogVal ||
          validFallback ||
          DateTime.now().toLocaleString(DateTime.TIME_24_SIMPLE)
        }`}
        variant="static"
        {...pickerProps}
      />
      <ConditionalWrapper
        condition={landscape}
        wrapper={(children) => (
          <div className={bemClasses("bottom-bar")}>{children}</div>
        )}
      >
        <DialogActions>
          {showNowButton ? (
            <Button
              className={bemClasses("show-now-button")}
              label="Now"
              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", { inline: useInline })}
        helpText={{
          children: invalid ? capitalise(invalid) : "Format: HH:YY (24hr)",
          persistent: true,
          validationMsg: true,
          ...helpTextProps,
        }}
        inputMode="numeric"
        invalid={!!invalid}
        onBlur={() => {
          if (!touched) {
            setTouched(true);
          }
          if (useInline && !saveOnClose) {
            setOpen(false);
          }
        }}
        onChange={rifm.onChange}
        onFocus={() => {
          if (touched) {
            setTouched(false);
          }
          if (useInline) {
            setOpen(true);
          }
        }}
        pattern="^\d{2}:\d{2}"
        required={required}
        trailingIcon={
          useInline
            ? undefined
            : withTooltip(
                <IconButton
                  icon={iconObject(<Event />)}
                  onClick={() => setOpen(true)}
                />,
                "Time picker"
              )
        }
        value={rifm.value}
      />
      {modal}
    </ConditionalWrapper>
  );
}
Example #3
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 #4
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>
        }
      />
    </>
  );
}