Skip to content

Commit 4ba1255

Browse files
authored
fix: adjust TimeGutter for DST (#2205)
Handle memoization of 'start' and 'end' to prevent infinite useEffect, and add DST fix back to the TimeGutter
1 parent e211bf0 commit 4ba1255

File tree

1 file changed

+41
-17
lines changed

1 file changed

+41
-17
lines changed

src/TimeGutter.js

Lines changed: 41 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,26 @@
1-
import React, { useState, useEffect } from 'react'
1+
import React, { useState, useEffect, useCallback, useMemo } from 'react'
22
import clsx from 'clsx'
33
import PropTypes from 'prop-types'
44

5-
import * as TimeSlotUtils from './utils/TimeSlots'
5+
import { getSlotMetrics } from './utils/TimeSlots'
66
import TimeSlotGroup from './TimeSlotGroup'
77

8+
/**
9+
* Since the TimeGutter only displays the 'times' of slots in a day, and is separate
10+
* from the Day Columns themselves, we check to see if the range contains an offset difference
11+
* and, if so, change the beginning and end 'date' by a day to properly display the slots times
12+
* used.
13+
*/
14+
function adjustForDST({ min, max, localizer }) {
15+
if (localizer.getTimezoneOffset(min) !== localizer.getTimezoneOffset(max)) {
16+
return {
17+
start: localizer.add(min, -1, 'day'),
18+
end: localizer.add(max, -1, 'day'),
19+
}
20+
}
21+
return { start: min, end: max }
22+
}
23+
824
const TimeGutter = ({
925
min,
1026
max,
@@ -17,10 +33,15 @@ const TimeGutter = ({
1733
getters,
1834
gutterRef,
1935
}) => {
36+
const { start, end } = useMemo(
37+
() => adjustForDST({ min, max, localizer }),
38+
// eslint-disable-next-line react-hooks/exhaustive-deps
39+
[min?.toISOString(), max?.toISOString(), localizer]
40+
)
2041
const [slotMetrics, setSlotMetrics] = useState(
21-
TimeSlotUtils.getSlotMetrics({
22-
min,
23-
max,
42+
getSlotMetrics({
43+
min: start,
44+
max: end,
2445
timeslots,
2546
step,
2647
localizer,
@@ -31,8 +52,8 @@ const TimeGutter = ({
3152
if (slotMetrics) {
3253
setSlotMetrics(
3354
slotMetrics.update({
34-
min,
35-
max,
55+
min: start,
56+
max: end,
3657
timeslots,
3758
step,
3859
localizer,
@@ -43,18 +64,21 @@ const TimeGutter = ({
4364
* We don't want this to fire when slotMetrics is updated as it would recursively bomb
4465
*/
4566
// eslint-disable-next-line react-hooks/exhaustive-deps
46-
}, [min, max, timeslots, step])
67+
}, [start?.toISOString(), end?.toISOString(), timeslots, step])
4768

48-
const renderSlot = (value, idx) => {
49-
if (idx) return null // don't return the first (0) idx
69+
const renderSlot = useCallback(
70+
(value, idx) => {
71+
if (idx) return null // don't return the first (0) idx
5072

51-
const isNow = slotMetrics.dateIsInGroup(getNow(), idx)
52-
return (
53-
<span className={clsx('rbc-label', isNow && 'rbc-now')}>
54-
{localizer.format(value, 'timeGutterFormat')}
55-
</span>
56-
)
57-
}
73+
const isNow = slotMetrics.dateIsInGroup(getNow(), idx)
74+
return (
75+
<span className={clsx('rbc-label', isNow && 'rbc-now')}>
76+
{localizer.format(value, 'timeGutterFormat')}
77+
</span>
78+
)
79+
},
80+
[slotMetrics, localizer, getNow]
81+
)
5882

5983
return (
6084
<div className="rbc-time-gutter rbc-time-column" ref={gutterRef}>

0 commit comments

Comments
 (0)