Skip to content

Commit 077cd13

Browse files
authored
Timeline calendar num of days issues (#2080)
* fix 3-day issues in timeline * WIP * fix issue with scrolling and selected date * PR fix * disable touch without effect * PR fix * fix issues with week scroll * fix lint * fix PR comments * fix PR comments * fix PR comments * typo fix
1 parent 77a3d9a commit 077cd13

File tree

7 files changed

+108
-42
lines changed

7 files changed

+108
-42
lines changed

src/dateutils.ts

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,30 @@ export function sameDate(a?: XDate, b?: XDate) {
2020
return false;
2121
} else {
2222
return a?.getFullYear() === b?.getFullYear() && a?.getMonth() === b?.getMonth() && a?.getDate() === b?.getDate();
23-
}
23+
}
24+
}
25+
26+
export function onSameDateRange({
27+
firstDay,
28+
secondDay,
29+
numberOfDays,
30+
firstDateInRange,
31+
}: {
32+
firstDay: string;
33+
secondDay: string;
34+
numberOfDays: number;
35+
firstDateInRange: string;
36+
}){
37+
const aDate = new XDate(firstDay);
38+
const bDate = new XDate(secondDay);
39+
const firstDayDate = new XDate(firstDateInRange);
40+
const aDiff = aDate.getTime() - firstDayDate.getTime();
41+
const bDiff = bDate.getTime() - firstDayDate.getTime();
42+
const aTotalDays = Math.ceil(aDiff / (1000 * 3600 * 24));
43+
const bTotalDays = Math.ceil(bDiff / (1000 * 3600 * 24));
44+
const aWeek = Math.floor(aTotalDays / numberOfDays);
45+
const bWeek = Math.floor(bTotalDays / numberOfDays);
46+
return aWeek === bWeek;
2447
}
2548

2649
export function sameWeek(a: string, b: string, firstDayOfWeek: number) {

src/day-state-manager.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@ const {isToday, isDateNotInRange, sameMonth} = require('./dateutils');
22
const {toMarkingFormat} = require('./interface');
33

44

5-
export function getState(day: XDate, current: XDate, props: any) {
5+
export function getState(day: XDate, current: XDate, props: any, disableDaySelection?: boolean) {
66
const {minDate, maxDate, disabledByDefault, context} = props;
77
let state = '';
88

9-
if ((context?.date ?? toMarkingFormat(current)) === toMarkingFormat(day)) {
9+
if (!disableDaySelection && ((context?.date ?? toMarkingFormat(current)) === toMarkingFormat(day))) {
1010
state = 'selected';
1111
} else if (isToday(day)) {
1212
state = 'today';

src/expandableCalendar/WeekCalendar/index.tsx

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import XDate from 'xdate';
33
import React, {useCallback, useContext, useMemo, useRef, useState} from 'react';
44
import {FlatList, View, ViewToken} from 'react-native';
55

6-
import {sameWeek} from '../../dateutils';
6+
import {sameWeek, onSameDateRange} from '../../dateutils';
77
import {toMarkingFormat} from '../../interface';
88
import {DateData} from '../../types';
99
import styleConstructor from '../style';
@@ -36,7 +36,7 @@ const WeekCalendar = (props: WeekCalendarProps) => {
3636
hideDayNames,
3737
current,
3838
theme,
39-
testID
39+
testID,
4040
} = props;
4141
const context = useContext(CalendarContext);
4242
const {allowShadow = true, ...calendarListProps} = props;
@@ -50,9 +50,23 @@ const WeekCalendar = (props: WeekCalendarProps) => {
5050
const list = useRef<FlatList>(null);
5151
const currentIndex = useRef(NUMBER_OF_PAGES);
5252

53+
useDidUpdate(() => {
54+
items.current = getDatesArray(date, firstDay, numberOfDays);
55+
setListData(items.current);
56+
visibleWeek.current = date;
57+
}, [numberOfDays]);
58+
5359
useDidUpdate(() => {
5460
if (updateSource !== UpdateSources.WEEK_SCROLL) {
55-
const pageIndex = items.current.findIndex(item => sameWeek(item, date, firstDay));
61+
const pageIndex = items.current.findIndex(
62+
item => isCustomNumberOfDays(numberOfDays) ?
63+
onSameDateRange({
64+
firstDay: item,
65+
secondDay: date,
66+
numberOfDays: numberOfDays as number,
67+
firstDateInRange: item
68+
}) :
69+
sameWeek(item, date, firstDay));
5670
if (pageIndex !== currentIndex.current) {
5771
if (pageIndex >= 0) {
5872
visibleWeek.current = items.current[pageIndex];
@@ -206,6 +220,14 @@ const WeekCalendar = (props: WeekCalendarProps) => {
206220
);
207221
};
208222

223+
function getDateForDayRange(date: string, weekIndex: number, numberOfDays: number) {
224+
const d = new XDate(date);
225+
if (weekIndex !== 0) {
226+
d.addDays(numberOfDays * weekIndex);
227+
}
228+
return toMarkingFormat(d);
229+
}
230+
209231
function getDate(date: string, firstDay: number, weekIndex: number, numberOfDays?: number) {
210232
const d = new XDate(date);
211233
// get the first day of the week as date (for the on scroll mark)
@@ -225,10 +247,17 @@ function getDate(date: string, firstDay: number, weekIndex: number, numberOfDays
225247

226248
function getDatesArray(date: string, firstDay: number, numberOfDays?: number) {
227249
return [...Array(NUM_OF_ITEMS).keys()].map((index) => {
228-
return getDate(date, firstDay, index - NUMBER_OF_PAGES, numberOfDays);
250+
if(isCustomNumberOfDays(numberOfDays)) {
251+
return getDateForDayRange(date, index - NUMBER_OF_PAGES, numberOfDays as number);
252+
}
253+
return getDate(date, firstDay, index - NUMBER_OF_PAGES);
229254
});
230255
}
231256

257+
function isCustomNumberOfDays(numberOfDays?: number) {
258+
return numberOfDays && numberOfDays > 1;
259+
}
260+
232261
WeekCalendar.displayName = 'WeekCalendar';
233262

234263
export default WeekCalendar;

src/expandableCalendar/index.tsx

Lines changed: 23 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ enum Positions {
3838
}
3939
const SPEED = 20;
4040
const BOUNCINESS = 6;
41-
const CLOSED_HEIGHT = constants.isIOS ? 116 : 120; // header + 1 week
41+
const CLOSED_HEIGHT = 120; // header + 1 week
4242
const WEEK_HEIGHT = 46;
4343
const DAY_NAMES_PADDING = 24;
4444
const PAN_GESTURE_THRESHOLD = 30;
@@ -174,12 +174,17 @@ const ExpandableCalendar = (props: ExpandableCalendarProps) => {
174174
return CLOSED_HEIGHT + (WEEK_HEIGHT * (numberOfWeeks.current - 1)) + (hideKnob ? 12 : KNOB_CONTAINER_HEIGHT) + (constants.isAndroid ? 3 : 0);
175175
};
176176
const openHeight = useRef(getOpenHeight());
177-
const closedHeight = useRef(CLOSED_HEIGHT + (hideKnob || Number(numberOfDays) > 1 ? 0 : KNOB_CONTAINER_HEIGHT));
177+
const closedHeight = useMemo(() => CLOSED_HEIGHT + (hideKnob || Number(numberOfDays) > 1 ? 0 : KNOB_CONTAINER_HEIGHT), [numberOfDays, hideKnob]);
178178

179-
const startHeight = isOpen ? openHeight.current : closedHeight.current;
179+
const startHeight = useMemo(() => isOpen ? openHeight.current : closedHeight, [closedHeight, isOpen]);
180180
const _height = useRef(startHeight);
181+
const deltaY = useMemo(() => new Animated.Value(startHeight), [startHeight]);
182+
183+
useEffect(() => {
184+
_height.current = startHeight;
185+
deltaY.setValue(startHeight);
186+
}, [startHeight]);
181187

182-
const deltaY = useRef(new Animated.Value(startHeight));
183188
const headerDeltaY = useRef(new Animated.Value(isOpen ? -HEADER_HEIGHT : 0));
184189

185190
/** Components' refs */
@@ -221,7 +226,7 @@ const ExpandableCalendar = (props: ExpandableCalendarProps) => {
221226
paddingRight: isNumber(rightPaddings) ? rightPaddings + 6 : DAY_NAMES_PADDING
222227
}
223228
];
224-
}, [calendarStyle, numberOfDays]);
229+
}, [calendarStyle]);
225230

226231
const animatedHeaderStyle = useMemo(() => {
227232
return [style.current.header, {height: HEADER_HEIGHT + 10, top: headerDeltaY.current}];
@@ -236,8 +241,8 @@ const ExpandableCalendar = (props: ExpandableCalendarProps) => {
236241
}, [allowShadow, propsStyle]);
237242

238243
const wrapperStyle = useMemo(() => {
239-
return {height: deltaY.current};
240-
}, [deltaY.current]);
244+
return {height: deltaY};
245+
}, [deltaY]);
241246

242247
/** Effects */
243248

@@ -319,7 +324,7 @@ const ExpandableCalendar = (props: ExpandableCalendarProps) => {
319324

320325
const handlePanResponderMove = (_: GestureResponderEvent, gestureState: PanResponderGestureState) => {
321326
// limit min height to closed height
322-
_wrapperStyles.current.style.height = Math.max(closedHeight.current, _height.current + gestureState.dy);
327+
_wrapperStyles.current.style.height = Math.max(closedHeight, _height.current + gestureState.dy);
323328

324329
if (!horizontal) {
325330
// vertical CalenderList header
@@ -354,15 +359,15 @@ const ExpandableCalendar = (props: ExpandableCalendarProps) => {
354359

355360
const bounceToPosition = (toValue = 0) => {
356361
if (!disablePan) {
357-
const threshold = isOpen ? openHeight.current - closeThreshold : closedHeight.current + openThreshold;
362+
const threshold = isOpen ? openHeight.current - closeThreshold : closedHeight + openThreshold;
358363
let _isOpen = _height.current >= threshold;
359-
const newValue = _isOpen ? openHeight.current : closedHeight.current;
364+
const newValue = _isOpen ? openHeight.current : closedHeight;
360365

361-
deltaY.current.setValue(_height.current); // set the start position for the animated value
366+
deltaY.setValue(_height.current); // set the start position for the animated value
362367
_height.current = toValue || newValue;
363368
_isOpen = _height.current >= threshold; // re-check after _height.current was set
364369

365-
Animated.spring(deltaY.current, {
370+
Animated.spring(deltaY, {
366371
toValue: _height.current,
367372
speed: SPEED,
368373
bounciness: BOUNCINESS,
@@ -371,7 +376,7 @@ const ExpandableCalendar = (props: ExpandableCalendarProps) => {
371376

372377
onCalendarToggled?.(_isOpen);
373378

374-
setPosition(() => _height.current === closedHeight.current ? Positions.CLOSED : Positions.OPEN);
379+
setPosition(() => _height.current === closedHeight ? Positions.CLOSED : Positions.OPEN);
375380
closeHeader(_isOpen);
376381
resetWeekCalendarOpacity(_isOpen);
377382
}
@@ -399,14 +404,14 @@ const ExpandableCalendar = (props: ExpandableCalendarProps) => {
399404
setTimeout(() => {
400405
// to allows setDate to be completed
401406
if (isOpen) {
402-
bounceToPosition(closedHeight.current);
407+
bounceToPosition(closedHeight);
403408
}
404409
}, 0);
405-
}, [isOpen]);
410+
}, [isOpen, closedHeight]);
406411

407412
const toggleCalendarPosition = useCallback(() => {
408-
bounceToPosition(isOpen ? closedHeight.current : openHeight.current);
409-
}, [isOpen, bounceToPosition]);
413+
bounceToPosition(isOpen ? closedHeight : openHeight.current);
414+
}, [isOpen, bounceToPosition, closedHeight]);
410415

411416
/** Events */
412417

@@ -552,7 +557,7 @@ const ExpandableCalendar = (props: ExpandableCalendarProps) => {
552557

553558
const _headerStyle = useMemo(() => {
554559
return [numberOfDaysHeaderStyle, props.headerStyle];
555-
}, [props.headerStyle]);
560+
}, [props.headerStyle, numberOfDaysHeaderStyle]);
556561

557562
const renderCalendarList = () => {
558563
return (

src/expandableCalendar/week.tsx

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,10 @@ const Week = React.memo((props: WeekProps) => {
3939
} = props;
4040
const style = useRef(styleConstructor(theme));
4141

42+
const disableDaySelection = useMemo(() => {
43+
return !!numberOfDays && numberOfDays > 1;
44+
}, [numberOfDays]);
45+
4246
const getWeek = useCallback((date?: string) => {
4347
if (date) {
4448
return getWeekDates(date, firstDay);
@@ -60,15 +64,14 @@ const Week = React.memo((props: WeekProps) => {
6064
}
6165
}
6266
const dayString = toMarkingFormat(day);
63-
6467
return (
6568
<View style={style.current.dayContainer} key={id}>
6669
<Day
6770
{...dayProps}
6871
testID={`${testID}.day_${dayString}`}
6972
date={dayString}
70-
state={getState(day, currXdate, props)}
71-
marking={markedDates?.[dayString]}
73+
state={getState(day, currXdate, props, disableDaySelection)}
74+
marking={disableDaySelection ? {...markedDates?.[dayString], disableTouchEvent: true} : markedDates?.[dayString]}
7275
onPress={onDayPress}
7376
onLongPress={onDayLongPress}
7477
/>

src/timeline-list/index.tsx

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -60,21 +60,24 @@ const TimelineList = (props: TimelineListProps) => {
6060
const {pages, pagesRef, resetPages, resetPagesDebounce, scrollToPageDebounce, shouldResetPages, isOutOfRange} =
6161
useTimelinePages({date, listRef, numberOfDays});
6262

63-
useEffect(() => {
64-
if (date !== prevDate.current) {
65-
const datePageIndex = pagesRef.current.indexOf(date);
66-
67-
if (updateSource !== UpdateSources.LIST_DRAG) {
68-
if (isOutOfRange(datePageIndex)) {
69-
updateSource === UpdateSources.DAY_PRESS ? resetPages(date) : resetPagesDebounce(date);
70-
} else {
71-
scrollToPageDebounce(datePageIndex);
72-
}
63+
const scrollToCurrentDate = useCallback((date: string) => {
64+
const datePageIndex = pagesRef.current.indexOf(date);
65+
66+
if (updateSource !== UpdateSources.LIST_DRAG) {
67+
if (isOutOfRange(datePageIndex)) {
68+
updateSource === UpdateSources.DAY_PRESS ? resetPages(date) : resetPagesDebounce(date);
69+
} else {
70+
scrollToPageDebounce(datePageIndex);
7371
}
72+
}
73+
prevDate.current = date;
74+
}, [updateSource]);
7475

75-
prevDate.current = date;
76+
useEffect(() => {
77+
if (date !== prevDate.current) {
78+
scrollToCurrentDate(date);
7679
}
77-
}, [date, updateSource]);
80+
}, [date]);
7881

7982
const onScroll = useCallback(() => {
8083
if (shouldResetPages.current) {

src/timeline-list/useTimelinePages.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,16 @@ const UseTimelinePages = ({date, listRef, numberOfDays}: UseTimelinePagesProps)
2323
return generateDay(date, numberOfDays * (i - Math.floor(PAGES_COUNT / 2)));
2424
})
2525
);
26+
2627
const [pages, setPages] = useState<string[]>(pagesRef.current);
2728
const shouldResetPages = useRef(false);
2829

2930
useEffect(() => {
30-
setPages(times(PAGES_COUNT, i => {
31+
const updatedDays = times(PAGES_COUNT, i => {
3132
return generateDay(date, numberOfDays * (i - Math.floor(PAGES_COUNT / 2)));
32-
}));
33+
});
34+
pagesRef.current = updatedDays;
35+
setPages(updatedDays);
3336
}, [numberOfDays]);
3437

3538
const isOutOfRange = useCallback((index: number) => {

0 commit comments

Comments
 (0)