diff --git a/packages/volto/news/6213.feature b/packages/volto/news/6213.feature
new file mode 100644
index 0000000000..76fbceecdc
--- /dev/null
+++ b/packages/volto/news/6213.feature
@@ -0,0 +1,2 @@
+
+Refactor the `DatetimeWidget` component from a class component to a functional component. @Raman-Luhach
diff --git a/packages/volto/src/components/manage/Widgets/DatetimeWidget.jsx b/packages/volto/src/components/manage/Widgets/DatetimeWidget.jsx
index 546f57e22a..bfa4cfe6fb 100644
--- a/packages/volto/src/components/manage/Widgets/DatetimeWidget.jsx
+++ b/packages/volto/src/components/manage/Widgets/DatetimeWidget.jsx
@@ -1,12 +1,6 @@
-/**
- * DatetimeWidget component.
- * @module components/manage/Widgets/DatetimeWidget
- */
-import React, { Component } from 'react';
-import { compose } from 'redux';
+import React, { useState, useEffect } from 'react';
import PropTypes from 'prop-types';
-import { defineMessages, injectIntl } from 'react-intl';
-import { connect } from 'react-redux';
+import { defineMessages, useIntl } from 'react-intl';
import loadable from '@loadable/component';
import cx from 'classnames';
import { Icon } from '@plone/volto/components';
@@ -50,6 +44,7 @@ const PrevIcon = () => (
);
+
const NextIcon = () => (
{
+ const {
+ id,
+ resettable,
+ reactDates,
+ widgetOptions,
+ moment,
+ value,
+ onChange,
+ dateOnly,
+ widget,
+ noPastDates: propNoPastDates,
+ isDisabled,
+ } = props;
+
+ const intl = useIntl();
+ const lang = intl.locale;
+
+ const [focused, setFocused] = useState(false);
+ const [isDefault, setIsDefault] = useState(false);
+
+ const { SingleDatePicker } = reactDates;
+
+ useEffect(() => {
+ const parsedDateTime = parseDateTime(
+ toBackendLang(lang),
+ value,
undefined,
- this.moment,
+ moment.default,
+ );
+ setIsDefault(
+ parsedDateTime?.toISOString() === moment.default().utc().toISOString(),
);
- }
+ }, [value, lang, moment]);
- getDateOnly() {
- return this.props.dateOnly || this.props.widget === 'date';
- }
+ const getInternalValue = () => {
+ return parseDateTime(toBackendLang(lang), value, undefined, moment.default);
+ };
+
+ const getDateOnly = () => {
+ return dateOnly || widget === 'date';
+ };
- /**
- * Update date storage
- * @method onDateChange
- * @param {Object} date updated momentjs Object for date
- * @returns {undefined}
- */
- onDateChange = (date) => {
+ const onDateChange = (date) => {
if (date) {
- const moment = this.props.moment.default;
- const isDateOnly = this.getDateOnly();
- const base = (this.getInternalValue() || moment()).set({
+ const isDateOnly = getDateOnly();
+ const base = (getInternalValue() || moment.default()).set({
year: date.year(),
month: date.month(),
date: date.date(),
@@ -142,125 +122,100 @@ export class DatetimeWidgetComponent extends Component {
const dateValue = isDateOnly
? base.format('YYYY-MM-DD')
: base.toISOString();
- this.props.onChange(this.props.id, dateValue);
+ onChange(id, dateValue);
}
- this.setState({ isDefault: false });
+ setIsDefault(false);
};
- /**
- * Update date storage
- * @method onTimeChange
- * @param {Object} time updated momentjs Object for time
- * @returns {undefined}
- */
- onTimeChange = (time) => {
- const moment = this.props.moment.default;
+ const onTimeChange = (time) => {
if (time) {
- const base = (this.getInternalValue() || moment()).set({
+ const base = (getInternalValue() || moment.default()).set({
hours: time?.hours() ?? 0,
minutes: time?.minutes() ?? 0,
seconds: 0,
});
const dateValue = base.toISOString();
- this.props.onChange(this.props.id, dateValue);
+ onChange(id, dateValue);
}
};
- onResetDates = () => {
- this.setState({ isDefault: false });
- this.props.onChange(this.props.id, null);
+ const onResetDates = () => {
+ setIsDefault(false);
+ onChange(id, null);
};
- /**
- * Handle SingleDatePicker focus
- * @method onFocusChange
- * @param {boolean} focused component focus state.
- * @returns {undefined}
- */
- onFocusChange = ({ focused }) => this.setState({ focused });
-
- render() {
- const { id, resettable, intl, reactDates, widgetOptions, lang } =
- this.props;
- const noPastDates =
- this.props.noPastDates || widgetOptions?.pattern_options?.noPastDates;
- const moment = this.props.moment.default;
- const datetime = this.getInternalValue();
- const dateOnly = this.getDateOnly();
- const { SingleDatePicker } = reactDates;
-
- return (
-
-
+ const onFocusChange = ({ focused }) => setFocused(focused);
+
+ const noPastDates =
+ propNoPastDates || widgetOptions?.pattern_options?.noPastDates;
+ const datetime = getInternalValue();
+ const isDateOnly = getDateOnly();
+
+ return (
+
+
+
+
false })}
+ onFocusChange={onFocusChange}
+ noBorder
+ displayFormat={moment.default
+ .localeData(toBackendLang(lang))
+ .longDateFormat('L')}
+ navPrev={}
+ navNext={}
+ id={`${id}-date`}
+ placeholder={intl.formatMessage(messages.date)}
+ />
+
+ {!isDateOnly && (
- false })}
- onFocusChange={this.onFocusChange}
- noBorder
- displayFormat={moment
+ }
- navNext={}
- id={`${id}-date`}
- placeholder={intl.formatMessage(messages.date)}
+ .longDateFormat('LT')}
+ placeholder={intl.formatMessage(messages.time)}
+ focusOnOpen
+ placement="bottomRight"
/>
- {!dateOnly && (
-
-
-
- )}
- {resettable && (
-
- )}
-
-
- );
- }
-}
+ )}
+ {resettable && (
+
+ )}
+
+
+ );
+};
-/**
- * Property types.
- * @property {Object} propTypes Property types.
- * @static
- */
DatetimeWidgetComponent.propTypes = {
id: PropTypes.string.isRequired,
title: PropTypes.string.isRequired,
@@ -275,11 +230,6 @@ DatetimeWidgetComponent.propTypes = {
resettable: PropTypes.bool,
};
-/**
- * Default properties.
- * @property {Object} defaultProps Default properties.
- * @static
- */
DatetimeWidgetComponent.defaultProps = {
description: null,
required: false,
@@ -290,10 +240,6 @@ DatetimeWidgetComponent.defaultProps = {
resettable: true,
};
-export default compose(
- injectLazyLibs(['reactDates', 'moment']),
- connect((state) => ({
- lang: state.intl.locale,
- })),
- injectIntl,
-)(DatetimeWidgetComponent);
+export default injectLazyLibs(['reactDates', 'moment'])(
+ DatetimeWidgetComponent,
+);