1
0

DateSelector.tsx 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. /*
  2. * Copyright 2023 Avaiga Private Limited
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
  5. * the License. You may obtain a copy of the License at
  6. *
  7. * http://www.apache.org/licenses/LICENSE-2.0
  8. *
  9. * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
  10. * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
  11. * specific language governing permissions and limitations under the License.
  12. */
  13. import React, { useState, useEffect, useCallback } from "react";
  14. import Box from "@mui/material/Box";
  15. import Tooltip from "@mui/material/Tooltip";
  16. import { DatePicker } from "@mui/x-date-pickers/DatePicker";
  17. import { BaseDateTimePickerSlotsComponentsProps } from "@mui/x-date-pickers/DateTimePicker/shared";
  18. import { DateTimePicker } from "@mui/x-date-pickers/DateTimePicker";
  19. import { isValid } from "date-fns";
  20. import { ErrorBoundary } from "react-error-boundary";
  21. import { createSendUpdateAction } from "../../context/taipyReducers";
  22. import { getSuffixedClassNames, TaipyActiveProps, TaipyChangeProps } from "./utils";
  23. import { dateToString, getDateTime, getTimeZonedDate } from "../../utils";
  24. import { useClassNames, useDispatch, useDynamicProperty, useFormatConfig, useModule } from "../../utils/hooks";
  25. import Field from "./Field";
  26. import ErrorFallback from "../../utils/ErrorBoundary";
  27. interface DateSelectorProps extends TaipyActiveProps, TaipyChangeProps {
  28. withTime?: boolean;
  29. format?: string;
  30. date: string;
  31. defaultDate?: string;
  32. defaultEditable?: boolean;
  33. editable?: boolean;
  34. label?: string;
  35. }
  36. const boxSx = { display: "inline-block" };
  37. const textFieldProps = { textField: { margin: "dense" } } as BaseDateTimePickerSlotsComponentsProps<Date>;
  38. const DateSelector = (props: DateSelectorProps) => {
  39. const { updateVarName, withTime = false, id, propagate = true } = props;
  40. const dispatch = useDispatch();
  41. const formatConfig = useFormatConfig();
  42. const tz = formatConfig.timeZone;
  43. const [value, setValue] = useState(() => getDateTime(props.defaultDate, tz, withTime));
  44. const module = useModule();
  45. const className = useClassNames(props.libClassName, props.dynamicClassName, props.className);
  46. const active = useDynamicProperty(props.active, props.defaultActive, true);
  47. const editable = useDynamicProperty(props.editable, props.defaultEditable, true);
  48. const hover = useDynamicProperty(props.hoverText, props.defaultHoverText, undefined);
  49. const handleChange = useCallback(
  50. (v: Date | null) => {
  51. setValue(v);
  52. if (v !== null && isValid(v)) {
  53. const newDate = getTimeZonedDate(v, tz, withTime);
  54. dispatch(
  55. createSendUpdateAction(
  56. updateVarName,
  57. dateToString(newDate, withTime),
  58. module,
  59. props.onChange,
  60. propagate
  61. )
  62. );
  63. }
  64. },
  65. [updateVarName, dispatch, withTime, propagate, tz, props.onChange, module]
  66. );
  67. // Run every time props.value get updated
  68. useEffect(() => {
  69. if (props.date !== undefined) {
  70. setValue(getDateTime(props.date, tz, withTime));
  71. }
  72. }, [props.date, tz, withTime]);
  73. return (
  74. <ErrorBoundary FallbackComponent={ErrorFallback}>
  75. <Tooltip title={hover || ""}>
  76. <Box id={id} className={className} sx={boxSx}>
  77. {editable ? (
  78. withTime ? (
  79. <DateTimePicker
  80. value={value}
  81. onChange={handleChange}
  82. className={getSuffixedClassNames(className, "-picker")}
  83. disabled={!active}
  84. slotProps={textFieldProps}
  85. label={props.label}
  86. />
  87. ) : (
  88. <DatePicker
  89. value={value}
  90. onChange={handleChange}
  91. className={getSuffixedClassNames(className, "-picker")}
  92. disabled={!active}
  93. slotProps={textFieldProps}
  94. label={props.label}
  95. />
  96. )
  97. ) : (
  98. <Field
  99. dataType="datetime"
  100. defaultValue={props.defaultDate}
  101. value={props.date}
  102. format={props.format}
  103. id={id && id + "-field"}
  104. className={getSuffixedClassNames(className, "-text")}
  105. />
  106. )}
  107. </Box>
  108. </Tooltip>
  109. </ErrorBoundary>
  110. );
  111. };
  112. export default DateSelector;