From 8bba7752a53c754f0d452fc8cc5c06839baa9788 Mon Sep 17 00:00:00 2001 From: dzonidoo Date: Tue, 5 Nov 2024 13:06:59 +0100 Subject: [PATCH 1/4] implement dateTime component with 'all day' lable --- client/components/Events/EventDateTime.tsx | 17 +++++++++++++++-- .../Events/EventScheduleInput/index.tsx | 4 ++-- .../forms/rescheduleEventForm.tsx | 4 ++-- .../components/fields/editor/EventSchedule.tsx | 4 ++-- client/utils/events.ts | 6 +++--- client/validators/events.ts | 2 +- 6 files changed, 25 insertions(+), 12 deletions(-) diff --git a/client/components/Events/EventDateTime.tsx b/client/components/Events/EventDateTime.tsx index 6ed80b8a4..e08138f18 100644 --- a/client/components/Events/EventDateTime.tsx +++ b/client/components/Events/EventDateTime.tsx @@ -8,6 +8,7 @@ import {eventUtils, timeUtils} from '../../utils'; import {DateTime} from '../UI'; import './style.scss'; +import {Spacer} from 'superdesk-ui-framework/react'; interface IProps { item: IEventItem; @@ -23,7 +24,8 @@ export class EventDateTime extends React.PureComponent { const start = eventUtils.getStartDate(item); const end = eventUtils.getEndDate(item); const isAllDay = eventUtils.isEventAllDay(start, end); - const multiDay = !eventUtils.isEventSameDay(start, end); + const multiDay = !eventUtils.isSameDay(start, end); + const isEventAndPlanningSameDate = eventUtils.isSameDay(start, this.props.planningProps?.date); const showEventStartDate = eventUtils.showEventStartDate(start, multiDay, this.props.planningProps?.date); const isRemoteTimeZone = timeUtils.isEventInDifferentTimeZone(item); const withYear = multiDay && start.year() !== end.year(); @@ -71,7 +73,18 @@ export class EventDateTime extends React.PureComponent { return isAllDay && !ignoreAllDay ? ( - {gettext('All day')} + + {(!isEventAndPlanningSameDate || multiDay) && ( + + )} + {gettext('All day')} + ) : ( diff --git a/client/components/Events/EventScheduleInput/index.tsx b/client/components/Events/EventScheduleInput/index.tsx index 86a473fe6..c372199d9 100644 --- a/client/components/Events/EventScheduleInput/index.tsx +++ b/client/components/Events/EventScheduleInput/index.tsx @@ -42,7 +42,7 @@ export class EventScheduleInput extends React.Component { this.state = { isAllDay: eventUtils.isEventAllDay(dates.start, dates.end, true), - isMultiDay: !eventUtils.isEventSameDay(dates.start, dates.end), + isMultiDay: !eventUtils.isSameDay(dates.start, dates.end), }; this.onChange = this.onChange.bind(this); @@ -197,7 +197,7 @@ export class EventScheduleInput extends React.Component { componentWillReceiveProps(nextProps: Readonly) { const nextDates = nextProps.diff?.dates ?? {}; const isAllDay = eventUtils.isEventAllDay(nextDates.start, nextDates.end, true); - const isMultiDay = !eventUtils.isEventSameDay(nextDates.start, nextDates.end); + const isMultiDay = !eventUtils.isSameDay(nextDates.start, nextDates.end); const newState: Partial = {}; diff --git a/client/components/ItemActionConfirmation/forms/rescheduleEventForm.tsx b/client/components/ItemActionConfirmation/forms/rescheduleEventForm.tsx index de8adf08d..8cb179a04 100644 --- a/client/components/ItemActionConfirmation/forms/rescheduleEventForm.tsx +++ b/client/components/ItemActionConfirmation/forms/rescheduleEventForm.tsx @@ -134,8 +134,8 @@ export class RescheduleEventComponent extends React.Component { fieldsToValidate // Validate only those fields which can change while rescheduling. ); - const multiDayChanged = eventUtils.isEventSameDay(original.dates.start, original.dates.end) && - !eventUtils.isEventSameDay(diff.dates.start, diff.dates.end); + const multiDayChanged = eventUtils.isSameDay(original.dates.start, original.dates.end) && + !eventUtils.isSameDay(diff.dates.start, diff.dates.end); if ((!diff[TO_BE_CONFIRMED_FIELD] && eventUtils.eventsDatesSame(diff, original, TIME_COMPARISON_GRANULARITY.MINUTE)) || diff --git a/client/components/fields/editor/EventSchedule.tsx b/client/components/fields/editor/EventSchedule.tsx index 93738236d..8d8ef0cc8 100644 --- a/client/components/fields/editor/EventSchedule.tsx +++ b/client/components/fields/editor/EventSchedule.tsx @@ -80,7 +80,7 @@ export class EditorFieldEventSchedule extends React.PureComponent { const _startTime = this.props.item?._startTime; const defaultDurationOnChange = this.props.profile?.editor?.dates?.default_duration_on_change ?? 1; const isAllDay = eventUtils.isEventAllDay(startDate, endDate, true); - const isMultiDay = !eventUtils.isEventSameDay(startDate, endDate); + const isMultiDay = !eventUtils.isSameDay(startDate, endDate); const newStartDate = !startDate ? value : moment(startDate) @@ -130,7 +130,7 @@ export class EditorFieldEventSchedule extends React.PureComponent { endDate.hour(value.hour()).minute(value.minute()) : value; const isAllDay = eventUtils.isEventAllDay(startDate, endDate, true); - const isMultiDay = !eventUtils.isEventSameDay(startDate, endDate); + const isMultiDay = !eventUtils.isSameDay(startDate, endDate); const changes = {'dates.end': newEndDate}; if (((_endTime && isAllDay) || !_endTime) && diff --git a/client/utils/events.ts b/client/utils/events.ts index d136fea94..90cbcf130 100644 --- a/client/utils/events.ts +++ b/client/utils/events.ts @@ -76,7 +76,7 @@ function isEventAllDay(startingDate: IDateTime, endingDate: IDateTime, checkMult end.isSame(end.clone().endOf('day'), 'minute'); } -function isEventSameDay(startingDate: IDateTime, endingDate: IDateTime): boolean { +function isSameDay(startingDate: IDateTime, endingDate: IDateTime): boolean { return moment(startingDate).format('DD/MM/YYYY') === moment(endingDate).format('DD/MM/YYYY'); } @@ -843,7 +843,7 @@ function getEventActions( const CREATE_PLANNING = callBacks[EVENTS.ITEM_ACTIONS.CREATE_PLANNING.actionName]; const CREATE_AND_OPEN_PLANNING = callBacks[EVENTS.ITEM_ACTIONS.CREATE_AND_OPEN_PLANNING.actionName]; - (!withMultiPlanningDate || self.isEventSameDay(item)) ? + (!withMultiPlanningDate || self.isSameDay(item)) ? self.getSingleDayPlanningActions(item, actions, CREATE_PLANNING, CREATE_AND_OPEN_PLANNING) : self.getMultiDayPlanningActions(item, actions, CREATE_PLANNING, CREATE_AND_OPEN_PLANNING); } @@ -1361,7 +1361,7 @@ const self = { canUpdateEventTime, canConvertToRecurringEvent, canUpdateEventRepetitions, - isEventSameDay, + isSameDay, showEventStartDate, isEventRecurring, getDateStringForEvent, diff --git a/client/validators/events.ts b/client/validators/events.ts index 608ca691e..9e1de0a11 100644 --- a/client/validators/events.ts +++ b/client/validators/events.ts @@ -46,7 +46,7 @@ const validateDateRange = ({value, errors, messages}) => { } if (endDate.isSameOrBefore(startDate, 'minutes')) { - if (eventUtils.isEventSameDay(value.start, value.end)) { + if (eventUtils.isSameDay(value.start, value.end)) { set(errors, '_endTime', gettext('End time should be after start time')); messages.push(gettext('END TIME should be after START TIME')); } else { From 59b0cfffcabcacd02e0a5ffcaa3a4d5087b3f433 Mon Sep 17 00:00:00 2001 From: dzonidoo Date: Wed, 6 Nov 2024 14:17:38 +0100 Subject: [PATCH 2/4] create Iprop interface instead of using propTypes --- client/components/UI/DateTime.tsx | 37 +++++++++++++------------------ 1 file changed, 15 insertions(+), 22 deletions(-) diff --git a/client/components/UI/DateTime.tsx b/client/components/UI/DateTime.tsx index 837b3de7e..9c279a45c 100644 --- a/client/components/UI/DateTime.tsx +++ b/client/components/UI/DateTime.tsx @@ -1,5 +1,4 @@ import React from 'react'; -import PropTypes from 'prop-types'; import moment from 'moment'; import {appConfig} from 'appConfig'; @@ -7,6 +6,20 @@ import {superdeskApi} from '../../superdeskApi'; import {timeUtils} from '../../utils'; import './style.scss'; +import {IDateTime} from 'interfaces'; + +interface IPropsDateTime { + date: IDateTime, + withTime?: boolean, + withYear?: boolean, + withDate?: boolean, + padLeft?: boolean, + toBeConfirmed?: boolean, + isFullDay?: boolean, + isEndEventDateTime?: boolean, + noEndTime?: boolean, + multiDay?: boolean, +} /** * @ngdoc react @@ -24,7 +37,7 @@ function DateTime({ isEndEventDateTime, noEndTime, multiDay, -}) { +}: IPropsDateTime) { const {gettext} = superdeskApi.localization; const dateFormat = appConfig.planning.dateformat; const timeFormat = appConfig.planning.timeformat; @@ -71,24 +84,4 @@ function DateTime({ ); } -DateTime.propTypes = { - date: PropTypes.oneOfType([PropTypes.object, PropTypes.string]).isRequired, - withTime: PropTypes.bool, - withYear: PropTypes.bool, - withDate: PropTypes.bool, - padLeft: PropTypes.bool, - toBeConfirmed: PropTypes.bool, - isFullDay: PropTypes.bool, - isEndEventDateTime: PropTypes.bool, - noEndTime: PropTypes.bool, - multiDay: PropTypes.bool, -}; - -DateTime.defaultProps = { - withTime: true, - withDate: true, - withYear: true, - padLeft: false, -}; - export default DateTime; From 4f4c2a38804dcc7f0a8dd7549647b5e4c544bbc8 Mon Sep 17 00:00:00 2001 From: dzonidoo Date: Thu, 7 Nov 2024 13:57:35 +0100 Subject: [PATCH 3/4] move out isSameDay function from utilis --- client/components/Events/EventDateTime.tsx | 5 +++-- client/components/Events/EventScheduleInput/index.tsx | 5 +++-- .../ItemActionConfirmation/forms/rescheduleEventForm.tsx | 5 +++-- client/components/fields/editor/EventSchedule.tsx | 5 +++-- client/helpers.ts | 9 +++++++-- client/utils/events.ts | 8 ++------ client/validators/events.ts | 3 ++- 7 files changed, 23 insertions(+), 17 deletions(-) diff --git a/client/components/Events/EventDateTime.tsx b/client/components/Events/EventDateTime.tsx index e08138f18..c37bda088 100644 --- a/client/components/Events/EventDateTime.tsx +++ b/client/components/Events/EventDateTime.tsx @@ -9,6 +9,7 @@ import {DateTime} from '../UI'; import './style.scss'; import {Spacer} from 'superdesk-ui-framework/react'; +import {isSameDay} from 'helpers'; interface IProps { item: IEventItem; @@ -24,8 +25,8 @@ export class EventDateTime extends React.PureComponent { const start = eventUtils.getStartDate(item); const end = eventUtils.getEndDate(item); const isAllDay = eventUtils.isEventAllDay(start, end); - const multiDay = !eventUtils.isSameDay(start, end); - const isEventAndPlanningSameDate = eventUtils.isSameDay(start, this.props.planningProps?.date); + const multiDay = !isSameDay(start, end); + const isEventAndPlanningSameDate = isSameDay(start, this.props.planningProps?.date); const showEventStartDate = eventUtils.showEventStartDate(start, multiDay, this.props.planningProps?.date); const isRemoteTimeZone = timeUtils.isEventInDifferentTimeZone(item); const withYear = multiDay && start.year() !== end.year(); diff --git a/client/components/Events/EventScheduleInput/index.tsx b/client/components/Events/EventScheduleInput/index.tsx index c372199d9..7c09556b7 100644 --- a/client/components/Events/EventScheduleInput/index.tsx +++ b/client/components/Events/EventScheduleInput/index.tsx @@ -9,6 +9,7 @@ import {TO_BE_CONFIRMED_FIELD} from '../../../constants'; import {Row, DateTimeInput, LineInput, ToggleInput, Field, TimeZoneInput} from '../../UI/Form'; import {RecurringRulesInput} from '../RecurringRulesInput'; +import {isSameDay} from 'helpers'; interface IProps { item: IEventItem; @@ -42,7 +43,7 @@ export class EventScheduleInput extends React.Component { this.state = { isAllDay: eventUtils.isEventAllDay(dates.start, dates.end, true), - isMultiDay: !eventUtils.isSameDay(dates.start, dates.end), + isMultiDay: !isSameDay(dates.start, dates.end), }; this.onChange = this.onChange.bind(this); @@ -197,7 +198,7 @@ export class EventScheduleInput extends React.Component { componentWillReceiveProps(nextProps: Readonly) { const nextDates = nextProps.diff?.dates ?? {}; const isAllDay = eventUtils.isEventAllDay(nextDates.start, nextDates.end, true); - const isMultiDay = !eventUtils.isSameDay(nextDates.start, nextDates.end); + const isMultiDay = !isSameDay(nextDates.start, nextDates.end); const newState: Partial = {}; diff --git a/client/components/ItemActionConfirmation/forms/rescheduleEventForm.tsx b/client/components/ItemActionConfirmation/forms/rescheduleEventForm.tsx index 8cb179a04..d24ec3a6c 100644 --- a/client/components/ItemActionConfirmation/forms/rescheduleEventForm.tsx +++ b/client/components/ItemActionConfirmation/forms/rescheduleEventForm.tsx @@ -20,6 +20,7 @@ import {Row} from '../../UI/Preview'; import {TextAreaInput, Field} from '../../UI/Form'; import '../style.scss'; +import {isSameDay} from 'helpers'; export class RescheduleEventComponent extends React.Component { constructor(props) { @@ -134,8 +135,8 @@ export class RescheduleEventComponent extends React.Component { fieldsToValidate // Validate only those fields which can change while rescheduling. ); - const multiDayChanged = eventUtils.isSameDay(original.dates.start, original.dates.end) && - !eventUtils.isSameDay(diff.dates.start, diff.dates.end); + const multiDayChanged = isSameDay(original.dates.start, original.dates.end) && + !isSameDay(diff.dates.start, diff.dates.end); if ((!diff[TO_BE_CONFIRMED_FIELD] && eventUtils.eventsDatesSame(diff, original, TIME_COMPARISON_GRANULARITY.MINUTE)) || diff --git a/client/components/fields/editor/EventSchedule.tsx b/client/components/fields/editor/EventSchedule.tsx index 8d8ef0cc8..2439616ee 100644 --- a/client/components/fields/editor/EventSchedule.tsx +++ b/client/components/fields/editor/EventSchedule.tsx @@ -11,6 +11,7 @@ import {EditorFieldStartDateTime} from './StartDateTime'; import {Row, TimeZoneInput} from '../../UI/Form'; import {eventUtils, timeUtils} from '../../../utils'; import {TO_BE_CONFIRMED_FIELD} from '../../../constants'; +import {isSameDay} from 'helpers'; interface IProps extends IEditorFieldProps { item: IEventItem; @@ -80,7 +81,7 @@ export class EditorFieldEventSchedule extends React.PureComponent { const _startTime = this.props.item?._startTime; const defaultDurationOnChange = this.props.profile?.editor?.dates?.default_duration_on_change ?? 1; const isAllDay = eventUtils.isEventAllDay(startDate, endDate, true); - const isMultiDay = !eventUtils.isSameDay(startDate, endDate); + const isMultiDay = !isSameDay(startDate, endDate); const newStartDate = !startDate ? value : moment(startDate) @@ -130,7 +131,7 @@ export class EditorFieldEventSchedule extends React.PureComponent { endDate.hour(value.hour()).minute(value.minute()) : value; const isAllDay = eventUtils.isEventAllDay(startDate, endDate, true); - const isMultiDay = !eventUtils.isSameDay(startDate, endDate); + const isMultiDay = !isSameDay(startDate, endDate); const changes = {'dates.end': newEndDate}; if (((_endTime && isAllDay) || !_endTime) && diff --git a/client/helpers.ts b/client/helpers.ts index 8d0cfc3c2..bec84a609 100644 --- a/client/helpers.ts +++ b/client/helpers.ts @@ -1,5 +1,6 @@ +import moment from 'moment'; import {GENERIC_ITEM_ACTIONS} from './constants'; -import {IItemAction} from './interfaces'; +import {IDateTime, IItemAction} from './interfaces'; export function isItemAction( x: IItemAction | typeof GENERIC_ITEM_ACTIONS.DIVIDER | typeof GENERIC_ITEM_ACTIONS.LABEL, @@ -11,4 +12,8 @@ export function isMenuDivider( x: IItemAction | typeof GENERIC_ITEM_ACTIONS.DIVIDER | typeof GENERIC_ITEM_ACTIONS.LABEL, ): x is typeof GENERIC_ITEM_ACTIONS.DIVIDER { return x['label'] != null && x['label'] === GENERIC_ITEM_ACTIONS.DIVIDER.label; -} \ No newline at end of file +} + +export function isSameDay(startingDate: IDateTime, endingDate: IDateTime): boolean { + return moment(startingDate).format('DD/MM/YYYY') === moment(endingDate).format('DD/MM/YYYY'); +} diff --git a/client/utils/events.ts b/client/utils/events.ts index 90cbcf130..a47efb089 100644 --- a/client/utils/events.ts +++ b/client/utils/events.ts @@ -57,6 +57,7 @@ import { sanitizeItemFields, } from './index'; import {toUIFrameworkInterface, getRelatedEventIdsForPlanning} from './planning'; +import {isSameDay} from 'helpers'; /** @@ -76,10 +77,6 @@ function isEventAllDay(startingDate: IDateTime, endingDate: IDateTime, checkMult end.isSame(end.clone().endOf('day'), 'minute'); } -function isSameDay(startingDate: IDateTime, endingDate: IDateTime): boolean { - return moment(startingDate).format('DD/MM/YYYY') === moment(endingDate).format('DD/MM/YYYY'); -} - function showEventStartDate(eventDate: IDateTime, multiDay: boolean, planningDate?: IDateTime): boolean { if (planningDate == null) { return true; @@ -843,7 +840,7 @@ function getEventActions( const CREATE_PLANNING = callBacks[EVENTS.ITEM_ACTIONS.CREATE_PLANNING.actionName]; const CREATE_AND_OPEN_PLANNING = callBacks[EVENTS.ITEM_ACTIONS.CREATE_AND_OPEN_PLANNING.actionName]; - (!withMultiPlanningDate || self.isSameDay(item)) ? + (!withMultiPlanningDate || isSameDay(item)) ? self.getSingleDayPlanningActions(item, actions, CREATE_PLANNING, CREATE_AND_OPEN_PLANNING) : self.getMultiDayPlanningActions(item, actions, CREATE_PLANNING, CREATE_AND_OPEN_PLANNING); } @@ -1361,7 +1358,6 @@ const self = { canUpdateEventTime, canConvertToRecurringEvent, canUpdateEventRepetitions, - isSameDay, showEventStartDate, isEventRecurring, getDateStringForEvent, diff --git a/client/validators/events.ts b/client/validators/events.ts index 9e1de0a11..19b75e8e1 100644 --- a/client/validators/events.ts +++ b/client/validators/events.ts @@ -7,6 +7,7 @@ import {gettext, eventUtils} from '../utils'; import * as selectors from '../selectors'; import {formProfile} from './profile'; import {PRIVILEGES, EVENTS, TO_BE_CONFIRMED_FIELD} from '../constants'; +import {isSameDay} from 'helpers'; const validateRequiredDates = ({value, errors, messages, diff}) => { if (!get(value, 'start')) { @@ -46,7 +47,7 @@ const validateDateRange = ({value, errors, messages}) => { } if (endDate.isSameOrBefore(startDate, 'minutes')) { - if (eventUtils.isSameDay(value.start, value.end)) { + if (isSameDay(value.start, value.end)) { set(errors, '_endTime', gettext('End time should be after start time')); messages.push(gettext('END TIME should be after START TIME')); } else { From 44eb622849fa26277a7855ba25a079da6aa29d71 Mon Sep 17 00:00:00 2001 From: dzonidoo Date: Thu, 7 Nov 2024 14:47:40 +0100 Subject: [PATCH 4/4] changed imports --- client/components/Events/EventDateTime.tsx | 2 +- client/components/Events/EventScheduleInput/index.tsx | 2 +- .../ItemActionConfirmation/forms/rescheduleEventForm.tsx | 2 +- client/components/fields/editor/EventSchedule.tsx | 2 +- client/utils/events.ts | 2 +- client/validators/events.ts | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/client/components/Events/EventDateTime.tsx b/client/components/Events/EventDateTime.tsx index c37bda088..0ae46d122 100644 --- a/client/components/Events/EventDateTime.tsx +++ b/client/components/Events/EventDateTime.tsx @@ -9,7 +9,7 @@ import {DateTime} from '../UI'; import './style.scss'; import {Spacer} from 'superdesk-ui-framework/react'; -import {isSameDay} from 'helpers'; +import {isSameDay} from './../../helpers'; interface IProps { item: IEventItem; diff --git a/client/components/Events/EventScheduleInput/index.tsx b/client/components/Events/EventScheduleInput/index.tsx index 7c09556b7..c1293121f 100644 --- a/client/components/Events/EventScheduleInput/index.tsx +++ b/client/components/Events/EventScheduleInput/index.tsx @@ -9,7 +9,7 @@ import {TO_BE_CONFIRMED_FIELD} from '../../../constants'; import {Row, DateTimeInput, LineInput, ToggleInput, Field, TimeZoneInput} from '../../UI/Form'; import {RecurringRulesInput} from '../RecurringRulesInput'; -import {isSameDay} from 'helpers'; +import {isSameDay} from './../../../helpers'; interface IProps { item: IEventItem; diff --git a/client/components/ItemActionConfirmation/forms/rescheduleEventForm.tsx b/client/components/ItemActionConfirmation/forms/rescheduleEventForm.tsx index d24ec3a6c..f167fb118 100644 --- a/client/components/ItemActionConfirmation/forms/rescheduleEventForm.tsx +++ b/client/components/ItemActionConfirmation/forms/rescheduleEventForm.tsx @@ -20,7 +20,7 @@ import {Row} from '../../UI/Preview'; import {TextAreaInput, Field} from '../../UI/Form'; import '../style.scss'; -import {isSameDay} from 'helpers'; +import {isSameDay} from './../../../helpers'; export class RescheduleEventComponent extends React.Component { constructor(props) { diff --git a/client/components/fields/editor/EventSchedule.tsx b/client/components/fields/editor/EventSchedule.tsx index 2439616ee..371d5d543 100644 --- a/client/components/fields/editor/EventSchedule.tsx +++ b/client/components/fields/editor/EventSchedule.tsx @@ -11,7 +11,7 @@ import {EditorFieldStartDateTime} from './StartDateTime'; import {Row, TimeZoneInput} from '../../UI/Form'; import {eventUtils, timeUtils} from '../../../utils'; import {TO_BE_CONFIRMED_FIELD} from '../../../constants'; -import {isSameDay} from 'helpers'; +import {isSameDay} from './../../../helpers'; interface IProps extends IEditorFieldProps { item: IEventItem; diff --git a/client/utils/events.ts b/client/utils/events.ts index a47efb089..db0c114e1 100644 --- a/client/utils/events.ts +++ b/client/utils/events.ts @@ -57,7 +57,7 @@ import { sanitizeItemFields, } from './index'; import {toUIFrameworkInterface, getRelatedEventIdsForPlanning} from './planning'; -import {isSameDay} from 'helpers'; +import {isSameDay} from './../helpers'; /** diff --git a/client/validators/events.ts b/client/validators/events.ts index 19b75e8e1..2d8caf0c4 100644 --- a/client/validators/events.ts +++ b/client/validators/events.ts @@ -7,7 +7,7 @@ import {gettext, eventUtils} from '../utils'; import * as selectors from '../selectors'; import {formProfile} from './profile'; import {PRIVILEGES, EVENTS, TO_BE_CONFIRMED_FIELD} from '../constants'; -import {isSameDay} from 'helpers'; +import {isSameDay} from './../helpers'; const validateRequiredDates = ({value, errors, messages, diff}) => { if (!get(value, 'start')) {