From 4ba1255ac80239e3a35d8adb32cbaa3da526619f Mon Sep 17 00:00:00 2001 From: Steve 'Cutter' Blades Date: Tue, 5 Jul 2022 08:44:50 -0500 Subject: [PATCH] fix: adjust TimeGutter for DST (#2205) Handle memoization of 'start' and 'end' to prevent infinite useEffect, and add DST fix back to the TimeGutter --- src/TimeGutter.js | 58 +++++++++++++++++++++++++++++++++-------------- 1 file changed, 41 insertions(+), 17 deletions(-) diff --git a/src/TimeGutter.js b/src/TimeGutter.js index 469ccbf98..949e7e241 100644 --- a/src/TimeGutter.js +++ b/src/TimeGutter.js @@ -1,10 +1,26 @@ -import React, { useState, useEffect } from 'react' +import React, { useState, useEffect, useCallback, useMemo } from 'react' import clsx from 'clsx' import PropTypes from 'prop-types' -import * as TimeSlotUtils from './utils/TimeSlots' +import { getSlotMetrics } from './utils/TimeSlots' import TimeSlotGroup from './TimeSlotGroup' +/** + * Since the TimeGutter only displays the 'times' of slots in a day, and is separate + * from the Day Columns themselves, we check to see if the range contains an offset difference + * and, if so, change the beginning and end 'date' by a day to properly display the slots times + * used. + */ +function adjustForDST({ min, max, localizer }) { + if (localizer.getTimezoneOffset(min) !== localizer.getTimezoneOffset(max)) { + return { + start: localizer.add(min, -1, 'day'), + end: localizer.add(max, -1, 'day'), + } + } + return { start: min, end: max } +} + const TimeGutter = ({ min, max, @@ -17,10 +33,15 @@ const TimeGutter = ({ getters, gutterRef, }) => { + const { start, end } = useMemo( + () => adjustForDST({ min, max, localizer }), + // eslint-disable-next-line react-hooks/exhaustive-deps + [min?.toISOString(), max?.toISOString(), localizer] + ) const [slotMetrics, setSlotMetrics] = useState( - TimeSlotUtils.getSlotMetrics({ - min, - max, + getSlotMetrics({ + min: start, + max: end, timeslots, step, localizer, @@ -31,8 +52,8 @@ const TimeGutter = ({ if (slotMetrics) { setSlotMetrics( slotMetrics.update({ - min, - max, + min: start, + max: end, timeslots, step, localizer, @@ -43,18 +64,21 @@ const TimeGutter = ({ * We don't want this to fire when slotMetrics is updated as it would recursively bomb */ // eslint-disable-next-line react-hooks/exhaustive-deps - }, [min, max, timeslots, step]) + }, [start?.toISOString(), end?.toISOString(), timeslots, step]) - const renderSlot = (value, idx) => { - if (idx) return null // don't return the first (0) idx + const renderSlot = useCallback( + (value, idx) => { + if (idx) return null // don't return the first (0) idx - const isNow = slotMetrics.dateIsInGroup(getNow(), idx) - return ( - - {localizer.format(value, 'timeGutterFormat')} - - ) - } + const isNow = slotMetrics.dateIsInGroup(getNow(), idx) + return ( + + {localizer.format(value, 'timeGutterFormat')} + + ) + }, + [slotMetrics, localizer, getNow] + ) return (