Material UI Pickers - Jalali Calendar Issue - pick jalali date by Keyboard (KeyboardDatePicker)

Viewed 100

I'm using Material-UI pickers v3.3.10 in my react app. I have difficulty to change the Jalali calendar value by keyboard and dialog box together. it returns NaN/NaN/NaN value and returns this message error: "Date should not be before minimal date". Does anyone have a tips?

Code:

import moment from "moment";
    import jMoment from "moment-jalaali";
    import React, { useState } from "react";
    import JalaliUtils from "@date-io/jalaali";

    import { MuiPickersUtilsProvider, KeyboardDatePicker } from "@material-ui/pickers";

    jMoment.loadPersian({ dialect: "persian-modern", usePersianDigits: true });

    function App() {
      const [selectedDate, handleDateChange] = useState(moment());

      return (
        <MuiPickersUtilsProvider utils={JalaliUtils} locale="fa">
          <KeyboardDatePicker
            clearable
            okLabel="تأیید"
            cancelLabel="لغو"
            clearLabel="پاک کردن"
            labelFunc={date => (date ? date.format("jYYYY/jMM/jDD") : "")}
            value={selectedDate}
            onChange={handleDateChange}
          />
        </MuiPickersUtilsProvider>
      );
    }
    export default App;
1 Answers

After a while, I found a solution for this problem.

define states:

const [blured, setBlured] = React.useState(false);

jalaliToGregorian:

 const JalaliDate = {
        g_days_in_month: [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31],
        j_days_in_month: [31, 31, 31, 31, 31, 31, 30, 30, 30, 30, 30, 29],
      };

  JalaliDate.jalaliToGregorian = function (j_y, j_m, j_d) {
    j_y = parseInt(j_y);
    j_m = parseInt(j_m);
    j_d = parseInt(j_d);
    var jy = j_y - 979;
    var jm = j_m - 1;
    var jd = j_d - 1;

    var j_day_no =
      365 * jy + parseInt(jy / 33) * 8 + parseInt(((jy % 33) + 3) / 4);
    for (var i = 0; i < jm; ++i) j_day_no += JalaliDate.j_days_in_month[i];

    j_day_no += jd;

    var g_day_no = j_day_no + 79;

    var gy =
      1600 +
      400 *
        parseInt(
          g_day_no / 146097
        ); /* 146097 = 365*400 + 400/4 - 400/100 + 400/400 */
    g_day_no = g_day_no % 146097;

    var leap = true;
    if (g_day_no >= 36525) {
      /* 36525 = 365*100 + 100/4 */
      g_day_no--;
      gy +=
        100 *
        parseInt(g_day_no / 36524); /* 36524 = 365*100 + 100/4 - 100/100 */
      g_day_no = g_day_no % 36524;

      if (g_day_no >= 365) g_day_no++;
      else leap = false;
    }

    gy += 4 * parseInt(g_day_no / 1461); /* 1461 = 365*4 + 4/4 */
    g_day_no %= 1461;

    if (g_day_no >= 366) {
      leap = false;

      g_day_no--;
      gy += parseInt(g_day_no / 365);
      g_day_no = g_day_no % 365;
    }

    for (
      var i = 0;
      g_day_no >= JalaliDate.g_days_in_month[i] + (i == 1 && leap);
      i++
    )
      g_day_no -= JalaliDate.g_days_in_month[i] + (i == 1 && leap);
    var gm = i + 1;
    var gd = g_day_no + 1;

    gm = gm < 10 ? "0" + gm : gm;
    gd = gd < 10 ? "0" + gd : gd;

    return [parseInt(gy), parseInt(gm), parseInt(gd)];
  };

defaultProps:

const defaultProps = {
    label: props.label,
    variant: "inline",
    inputVariant: "outlined",
    // autoOk: true,
    ampm: false,
    // clearable: true,
    showTodayButton: true,
    format: "YYYY/MM/DD HH:mm",
    labelFunc: (date) =>
      date? date.format("jYYYY/jMM/jDD HH:mm"): "",
    value: props.value,
    onChange: (date) => {
      if (!blured) {
        var d = new Date();
        let newDate = new Date(date);
        if (!props.timePicker)
          newDate.setHours(d.getHours(), d.getMinutes(), d.getSeconds());
        props.onChange(moment(newDate).format("YYYY-MM-DDTHH:mm:ss"));
      }
    },
    onBlur: (event) => {
      setBlured(false);
      let date = event.target.value;
      let gregorian = JalaliDate.jalaliToGregorian(
        date.split("/")[0],
        date.split("/")[1],
        date.split("/")[2]
      );
      var d = new Date();
      let newDate = new Date(
        gregorian[0] + "-" + gregorian[1] + "-" + gregorian[2]
      );
      if (props.timePicker)
        newDate.setHours(
          new Date(date).getHours(),
          new Date(date).getMinutes(),
          new Date(date).getSeconds()
        );
      else newDate.setHours(d.getHours(), d.getMinutes(), d.getSeconds());
      props.onChange(moment(newDate).format("YYYY-MM-DDTHH:mm:ss"));
    },
    onFocus: () => {
      setBlured(true);
    },
    keyboardIcon: (
      <CalendarIcon
        className={clsx(
          classes.calendarIcon,
          classes.calendarIconKeyboardPicker
        )}
      />
    ),
    KeyboardButtonProps: {
      classes: {
        root: clsx(classes.iconButtonRoot),
      },
      disableRipple: true,
    },
    inputProps: {
      ...props.inputProps,
      className: clsx(props.inputClassName, classes.inputMui),
      outlined: classes.outlined,
    },
    InputProps: {
      classes: {
        root: clsx(classes.outlinedRoot),
        notchedOutline: classes.notchedOutline,
        focused: classes.focused,
      },
    },
    InputLabelProps: {
      classes: {
        root: clsx(
          device.isNotMobile ? classes.rootLabel : classes.rootLabelMobile
        ),
        focused: device.isNotMobile
          ? classes.formLabelFocused
          : classes.formLabelFocusedMobile,
        marginDense: classes.marginDense,
        shrink: classes.shrink,
        outlined: classes.outlined,
      },
    },
  };

return:

<MuiPickersUtilsProvider utils={JalaliUtils} locale="fa">
   <KeyboardDateTimePicker {...defaultProps} />
</MuiPickersUtilsProvider>
Related