Skip to content

Commit 82524a0

Browse files
authored
ExpandableCalendar - disable auto date selection (#2628)
* upgrade rn73 * additional fixes * remove react-navigation * Use modal instead of navigation * removing packageManager * removing react navigation * downgrade eslint-plugin-prettier * updating eslint rules * removing deprecated rule * edit eslintrc * prettier to warn * fix lint errors * fix react hooks ts error * move tests to src * lint and unit tests config fix * some test cleanups * Adding BasicDay test driver * fix drivers * fix text style * skip failing tests (custom renders and events) * remove only testing dependency * fix lint * Day state - move selected from manager to components * UpdateSource - add arrow press and week arrow press (separate from page scroll) * Provider - add selectedDate to separate selected day marking state from the date responsible for functionality * remove consoles * Provider - add disableAutoDaySelection prop to pass navigation types to disable auto day selection * Fix tests for new update sources * move selected to state manager * change context date to selectedDate * state default value * revert change * fix test to count for selectedDate instead of date
1 parent bbe6c44 commit 82524a0

File tree

11 files changed

+56
-29
lines changed

11 files changed

+56
-29
lines changed

example/src/screens/expandableCalendarScreen.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ const ExpandableCalendarScreen = (props: Props) => {
7373
// disabledOpacity={0.6}
7474
theme={todayBtnTheme.current}
7575
// todayBottomMargin={16}
76+
// disableAutoDaySelection={[ExpandableCalendar.navigationTypes.MONTH_SCROLL, ExpandableCalendar.navigationTypes.MONTH_ARROWS]}
7677
>
7778
{weekView ? (
7879
<WeekCalendar testID={testIDs.weekCalendar.CONTAINER} firstDay={1} markedDates={marked.current}/>

src/calendar/__tests__/index.spec.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ describe('Calendar', () => {
165165
const date = '2020-04-01';
166166
const fakeToday = new Date('2020-04-01T12:00:00.002Z');
167167
advanceTo(fakeToday);
168-
const context = {date: '2020-04-02'};
168+
const context = {selectedDate: '2020-04-02'};
169169
const drv = new CalendarDriver(<Calendar {...props} theme={{todayTextColor, todayBackgroundColor}} context={context}/>);
170170
expect(drv.getDay(date).getStyle()).toEqual(partial({backgroundColor: todayBackgroundColor, borderRadius: 16}));
171171
expect(drv.getDay(date).getTextStyle()).toEqual(partial({color: todayTextColor}));

src/calendar/index.tsx

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -188,22 +188,21 @@ const Calendar = (props: CalendarProps & ContextProp) => {
188188
};
189189

190190
const renderDay = (day: XDate, id: number) => {
191-
const dayProps = extractDayProps(props);
192-
193191
if (!sameMonth(day, currentMonth) && hideExtraDays) {
194192
return <View key={id} style={style.current.emptyDayContainer}/>;
195193
}
196194

195+
const dayProps = extractDayProps(props);
197196
const dateString = toMarkingFormat(day);
198-
const isControlled = isEmpty(props.context);
197+
const disableDaySelection = isEmpty(props.context);
199198

200199
return (
201200
<View style={style.current.dayContainer} key={id}>
202201
<Day
203202
{...dayProps}
204203
testID={`${testID}.day_${dateString}`}
205204
date={dateString}
206-
state={getState(day, currentMonth, props, isControlled)}
205+
state={getState(day, currentMonth, props, disableDaySelection)}
207206
marking={markedDates?.[dateString]}
208207
onPress={_onDayPress}
209208
onLongPress={onLongPressDay}

src/day-state-manager.ts

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

4-
5-
export function getState(day: XDate, current: XDate, props: any, disableDaySelection?: boolean) {
4+
export function getState(day: XDate, current: XDate, props: any, disableDaySelection: boolean) {
65
const {minDate, maxDate, disabledByDefault, disabledByWeekDays, context} = props;
7-
let state = '';
6+
let state;
87

9-
if (!disableDaySelection && ((context?.date ?? toMarkingFormat(current)) === toMarkingFormat(day))) {
8+
if (!disableDaySelection && (context?.selectedDate ?? toMarkingFormat(current)) === toMarkingFormat(day)) {
109
state = 'selected';
1110
} else if (isToday(day)) {
1211
state = 'today';

src/expandableCalendar/Context/Provider.tsx

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import {includes} from 'lodash';
12
import XDate from 'xdate';
23

34
import React, {useRef, useState, useCallback, useMemo} from 'react';
@@ -7,7 +8,7 @@ import {sameMonth} from '../../dateutils';
78
import {xdateToData} from '../../interface';
89
import {useDidUpdate} from '../../hooks';
910
import {Theme, DateData} from '../../types';
10-
import {UpdateSources} from '../commons';
11+
import {UpdateSources, CalendarNavigationTypes} from '../commons';
1112
import styleConstructor from '../style';
1213
import CalendarContext from './index';
1314
import TodayButton, {TodayButtonImperativeMethods} from './todayButton';
@@ -23,6 +24,8 @@ export interface CalendarContextProviderProps extends ViewProps {
2324
onDateChanged?: (date: string, updateSource: UpdateSources) => void;
2425
/** Callback for month change event */
2526
onMonthChange?: (date: DateData, updateSource: UpdateSources) => void;
27+
/** The calendar navigation type in which to disable the auto day selection (get options from ExpandableCalendar.navigationTypes) */
28+
disableAutoDaySelection?: CalendarNavigationTypes[];
2629

2730
/** Whether to show the today button */
2831
showTodayButton?: boolean;
@@ -49,6 +52,7 @@ const CalendarProvider = (props: CalendarContextProviderProps) => {
4952
date,
5053
onDateChanged,
5154
onMonthChange,
55+
disableAutoDaySelection,
5256
showTodayButton = false,
5357
disabledOpacity,
5458
todayBottomMargin,
@@ -63,6 +67,7 @@ const CalendarProvider = (props: CalendarContextProviderProps) => {
6367
const prevDate = useRef(date);
6468
const currDate = useRef(date); // for setDate only to keep prevDate up to date
6569
const [currentDate, setCurrentDate] = useState(date);
70+
const [selectedDate, setSelectedDate] = useState(date);
6671
const [updateSource, setUpdateSource] = useState(UpdateSources.CALENDAR_INIT);
6772

6873
const wrapperStyle = useMemo(() => {
@@ -79,6 +84,9 @@ const CalendarProvider = (props: CalendarContextProviderProps) => {
7984
prevDate.current = currDate.current;
8085
currDate.current = date;
8186
setCurrentDate(date);
87+
if (!includes(disableAutoDaySelection, updateSource as string)) {
88+
setSelectedDate(date);
89+
}
8290
setUpdateSource(updateSource);
8391

8492
onDateChanged?.(date, updateSource);
@@ -98,6 +106,7 @@ const CalendarProvider = (props: CalendarContextProviderProps) => {
98106
return {
99107
date: currentDate,
100108
prevDate: prevDate.current,
109+
selectedDate,
101110
updateSource: updateSource,
102111
setDate: _setDate,
103112
setDisabled: _setDisabled,

src/expandableCalendar/Context/calendarProvider.api.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,11 @@
3535
"type": "(date: DateData, updateSource: UpdateSource) => void",
3636
"description": "Handler which gets executed when the month changes"
3737
},
38+
{
39+
"name": "disableAutoDaySelection",
40+
"type": "CalendarNavigationTypes[]",
41+
"description": "The calendar navigation type in which to disable the auto day selection (get options from ExpandableCalendar.navigationTypes)"
42+
},
3843
{
3944
"name": "showTodayButton",
4045
"type": "boolean",

src/expandableCalendar/Context/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import {UpdateSources} from '../commons';
33
export interface CalendarContextProps {
44
date: string;
55
prevDate: string;
6+
selectedDate: string;
67
setDate: (date: string, source: UpdateSources) => void;
78
updateSource: UpdateSources;
89
setDisabled: (disable: boolean) => void;

src/expandableCalendar/__tests__/index.spec.ts

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -185,8 +185,8 @@ describe('ExpandableCalendar', () => {
185185
jest.runAllTimers();
186186
const expectedDate = today.clone().setDate(1).addMonths(direction === Direction.RIGHT ? 1 : -1);
187187
driver.pressOnHeaderArrow({left: direction === Direction.LEFT});
188-
expect(onDateChanged).toHaveBeenCalledWith(toMarkingFormat(expectedDate), UpdateSources.PAGE_SCROLL);
189-
expect(onMonthChange).toHaveBeenCalledWith(xdateToData(expectedDate), UpdateSources.PAGE_SCROLL);
188+
expect(onDateChanged).toHaveBeenCalledWith(toMarkingFormat(expectedDate), UpdateSources.ARROW_PRESS);
189+
expect(onMonthChange).toHaveBeenCalledWith(xdateToData(expectedDate), UpdateSources.ARROW_PRESS);
190190
});
191191

192192
it(`should call onDateChanged and onMonthChanged for first day in initial month when changing to initial month`, () => {
@@ -197,8 +197,8 @@ describe('ExpandableCalendar', () => {
197197
driver.pressOnHeaderArrow({left: true});
198198
jest.runAllTimers();
199199
const expectedDate = today.clone().setDate(1);
200-
expect(onDateChanged).toHaveBeenNthCalledWith(2, toMarkingFormat(expectedDate), UpdateSources.PAGE_SCROLL);
201-
expect(onMonthChange).toHaveBeenNthCalledWith(2, xdateToData(expectedDate), UpdateSources.PAGE_SCROLL);
200+
expect(onDateChanged).toHaveBeenNthCalledWith(2, toMarkingFormat(expectedDate), UpdateSources.ARROW_PRESS);
201+
expect(onMonthChange).toHaveBeenNthCalledWith(2, xdateToData(expectedDate), UpdateSources.ARROW_PRESS);
202202
});
203203

204204
it(`should navigate 6 months ahead and back successfully`, () => {
@@ -209,13 +209,13 @@ describe('ExpandableCalendar', () => {
209209
});
210210
jest.runAllTimers();
211211
const expectedFutureDate = today.clone().setDate(1).addMonths(6);
212-
expect(onDateChanged).toHaveBeenNthCalledWith(6, toMarkingFormat(expectedFutureDate), UpdateSources.PAGE_SCROLL);
213-
expect(onMonthChange).toHaveBeenNthCalledWith(6, xdateToData(expectedFutureDate), UpdateSources.PAGE_SCROLL);
212+
expect(onDateChanged).toHaveBeenNthCalledWith(6, toMarkingFormat(expectedFutureDate), UpdateSources.ARROW_PRESS);
213+
expect(onMonthChange).toHaveBeenNthCalledWith(6, xdateToData(expectedFutureDate), UpdateSources.ARROW_PRESS);
214214
times(6, () => driver.pressOnHeaderArrow({left: true}));
215215
jest.runAllTimers();
216216
const expectedDate = today.clone().setDate(1);
217-
expect(onDateChanged).toHaveBeenNthCalledWith(12, toMarkingFormat(expectedDate), UpdateSources.PAGE_SCROLL);
218-
expect(onMonthChange).toHaveBeenNthCalledWith(12, xdateToData(expectedDate), UpdateSources.PAGE_SCROLL);
217+
expect(onDateChanged).toHaveBeenNthCalledWith(12, toMarkingFormat(expectedDate), UpdateSources.ARROW_PRESS);
218+
expect(onMonthChange).toHaveBeenNthCalledWith(12, xdateToData(expectedDate), UpdateSources.ARROW_PRESS);
219219
});
220220
});
221221
});
@@ -247,14 +247,14 @@ describe('ExpandableCalendar', () => {
247247
const currentDay = today.getDay();
248248
const expectedDate = today.clone().addDays(direction === Direction.LEFT ? -(currentDay + 7) : (7 - currentDay));
249249
driver.pressOnHeaderArrow({left: direction === Direction.LEFT});
250-
expect(onDateChanged).toHaveBeenCalledWith(toMarkingFormat(expectedDate), UpdateSources.PAGE_SCROLL);
250+
expect(onDateChanged).toHaveBeenCalledWith(toMarkingFormat(expectedDate), UpdateSources.WEEK_ARROW_PRESS);
251251
});
252252

253253
it(`should call onDateChanged for first day of initial week when changing to initial week`, () => {
254254
driver.pressOnHeaderArrow({left: false});
255255
driver.pressOnHeaderArrow({left: true});
256256
const expectedDate = today.clone().addDays(-(today.getDay()));
257-
expect(onDateChanged).toHaveBeenNthCalledWith(2, toMarkingFormat(expectedDate), UpdateSources.PAGE_SCROLL);
257+
expect(onDateChanged).toHaveBeenNthCalledWith(2, toMarkingFormat(expectedDate), UpdateSources.WEEK_ARROW_PRESS);
258258
});
259259

260260
it('should fetch next weeks when in last week of the list', () => {
@@ -270,7 +270,7 @@ describe('ExpandableCalendar', () => {
270270
const diff = Math.ceil(((endOfMonth.getUTCDate() + 1) - today.getUTCDate()) / 7) + ((today.getUTCDay() > endOfMonth.getUTCDay()) ? 1 : 0);
271271
const expectedDate = today.clone().setDate(today.getDate() + 7 * diff - today.getDay());
272272
times(diff, () => driver.pressOnHeaderArrow({left: false}));
273-
expect(onMonthChange).toHaveBeenCalledWith(xdateToData(expectedDate), UpdateSources.PAGE_SCROLL);
273+
expect(onMonthChange).toHaveBeenCalledWith(xdateToData(expectedDate), UpdateSources.WEEK_ARROW_PRESS);
274274
});
275275
});
276276
});

src/expandableCalendar/commons.ts

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,21 @@ export const todayString = 'today';
22

33
export enum UpdateSources {
44
CALENDAR_INIT = 'calendarInit',
5+
PROP_UPDATE = 'propUpdate',
56
TODAY_PRESS = 'todayPress',
6-
LIST_DRAG = 'listDrag',
77
DAY_PRESS = 'dayPress',
8+
ARROW_PRESS = 'arrowPress',
9+
WEEK_ARROW_PRESS = 'weekArrowPress',
10+
LIST_DRAG = 'listDrag',
811
PAGE_SCROLL = 'pageScroll',
9-
WEEK_SCROLL = 'weekScroll',
10-
PROP_UPDATE = 'propUpdate'
12+
WEEK_SCROLL = 'weekScroll'
13+
}
14+
15+
export enum CalendarNavigationTypes {
16+
AGENDA_SCROLL = UpdateSources.LIST_DRAG,
17+
MONTH_SCROLL = UpdateSources.PAGE_SCROLL,
18+
WEEK_SCROLL = UpdateSources.WEEK_SCROLL,
19+
MONTH_ARROWS = UpdateSources.ARROW_PRESS,
20+
WEEK_ARROWS = UpdateSources.WEEK_ARROW_PRESS,
21+
TODAY_PRESS = UpdateSources.TODAY_PRESS
1122
}

src/expandableCalendar/index.tsx

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ import Week from './week';
4040
import WeekCalendar from './WeekCalendar';
4141
import Context from './Context';
4242
import constants from '../commons/constants';
43-
import {UpdateSources} from './commons';
43+
import {UpdateSources, CalendarNavigationTypes} from './commons';
4444

4545
export enum Positions {
4646
CLOSED = 'closed',
@@ -316,7 +316,7 @@ const ExpandableCalendar = forwardRef<ExpandableCalendarRef, ExpandableCalendarP
316316
}
317317
};
318318

319-
const scrollPage = useCallback((next: boolean) => {
319+
const scrollPage = useCallback((next: boolean, updateSource = UpdateSources.PAGE_SCROLL) => {
320320
if (horizontal) {
321321
const d = parseDate(date);
322322

@@ -339,7 +339,7 @@ const ExpandableCalendar = forwardRef<ExpandableCalendarRef, ExpandableCalendarP
339339
}
340340
}
341341

342-
setDate?.(toMarkingFormat(d), UpdateSources.PAGE_SCROLL);
342+
setDate?.(toMarkingFormat(d), updateSource);
343343
}
344344
}, [horizontal, isOpen, firstDay, numberOfDays, setDate, date]);
345345

@@ -464,12 +464,12 @@ const ExpandableCalendar = forwardRef<ExpandableCalendarRef, ExpandableCalendarP
464464

465465
const _onPressArrowLeft = useCallback((method: () => void, month?: XDate) => {
466466
onPressArrowLeft?.(method, month);
467-
scrollPage(false);
467+
scrollPage(false, isOpen ? UpdateSources.ARROW_PRESS: UpdateSources.WEEK_ARROW_PRESS);
468468
}, [onPressArrowLeft, scrollPage]);
469469

470470
const _onPressArrowRight = useCallback((method: () => void, month?: XDate) => {
471471
onPressArrowRight?.(method, month);
472-
scrollPage(true);
472+
scrollPage(true, isOpen ? UpdateSources.ARROW_PRESS: UpdateSources.WEEK_ARROW_PRESS);
473473
}, [onPressArrowRight, scrollPage]);
474474

475475
const _onDayPress = useCallback((value: DateData) => {
@@ -652,6 +652,7 @@ const ExpandableCalendar = forwardRef<ExpandableCalendarRef, ExpandableCalendarP
652652
export default Object.assign(ExpandableCalendar, {
653653
displayName: 'ExpandableCalendar',
654654
positions: Positions,
655+
navigationTypes: CalendarNavigationTypes,
655656
defaultProps: {
656657
horizontal: true,
657658
initialPosition: Positions.CLOSED,

0 commit comments

Comments
 (0)