Skip to content

Commit 5a166fc

Browse files
committed
Fix types on Agenda and its subcomponent and demo screen
1 parent 4d8f7b4 commit 5a166fc

File tree

7 files changed

+102
-91
lines changed

7 files changed

+102
-91
lines changed

example/src/screens/agenda.tsx

Lines changed: 37 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,28 @@
11
import React, {Component} from 'react';
22
import {Alert, StyleSheet, Text, View, TouchableOpacity} from 'react-native';
3-
// @ts-expect-error
4-
import {Agenda} from 'react-native-calendars';
3+
import {Agenda, DateData, ReservationItemType, ReservationsType} from 'react-native-calendars';
54
import testIDs from '../testIDs';
65

7-
export default class AgendaScreen extends Component {
8-
state = {
9-
items: {}
6+
interface State {
7+
items?: ReservationsType;
8+
}
9+
10+
export default class AgendaScreen extends Component<State> {
11+
state: State = {
12+
items: undefined
1013
};
1114

1215
render() {
1316
return (
1417
<Agenda
1518
testID={testIDs.agenda.CONTAINER}
1619
items={this.state.items}
17-
loadItemsForMonth={this.loadItems.bind(this)}
20+
loadItemsForMonth={this.loadItems}
1821
selected={'2017-05-16'}
19-
renderItem={this.renderItem.bind(this)}
20-
renderEmptyDate={this.renderEmptyDate.bind(this)}
21-
rowHasChanged={this.rowHasChanged.bind(this)}
22+
//@ts-expect-error
23+
renderItem={this.renderItem}
24+
renderEmptyDate={this.renderEmptyDate}
25+
rowHasChanged={this.rowHasChanged}
2226
showClosingKnob={true}
2327
// markingType={'period'}
2428
// markedDates={{
@@ -38,57 +42,66 @@ export default class AgendaScreen extends Component {
3842
);
3943
}
4044

41-
loadItems(day) {
45+
loadItems = (day: DateData) => {
46+
const items = this.state.items || {};
47+
4248
setTimeout(() => {
4349
for (let i = -15; i < 85; i++) {
4450
const time = day.timestamp + i * 24 * 60 * 60 * 1000;
4551
const strTime = this.timeToString(time);
46-
if (!this.state.items[strTime]) {
47-
this.state.items[strTime] = [];
52+
53+
if (!items[strTime]) {
54+
items[strTime] = [];
55+
4856
const numItems = Math.floor(Math.random() * 3 + 1);
4957
for (let j = 0; j < numItems; j++) {
50-
this.state.items[strTime].push({
58+
items[strTime].push({
5159
name: 'Item for ' + strTime + ' #' + j,
52-
height: Math.max(50, Math.floor(Math.random() * 150))
60+
height: Math.max(50, Math.floor(Math.random() * 150)),
61+
day: strTime
5362
});
5463
}
5564
}
5665
}
57-
const newItems = {};
58-
Object.keys(this.state.items).forEach(key => {
59-
newItems[key] = this.state.items[key];
66+
67+
const newItems: ReservationsType = {};
68+
Object.keys(items).forEach(key => {
69+
newItems[key] = items[key];
6070
});
6171
this.setState({
6272
items: newItems
6373
});
6474
}, 1000);
6575
}
6676

67-
renderItem(item) {
77+
renderItem = (reservation: ReservationItemType, isFirst: boolean) => {
78+
const fontSize = isFirst ? 16 : 14;
79+
const color = isFirst ? 'black' : '#43515c';
80+
6881
return (
6982
<TouchableOpacity
7083
testID={testIDs.agenda.ITEM}
71-
style={[styles.item, {height: item.height}]}
72-
onPress={() => Alert.alert(item.name)}
84+
style={[styles.item, {height: reservation.height}]}
85+
onPress={() => Alert.alert(reservation.name)}
7386
>
74-
<Text>{item.name}</Text>
87+
<Text style={{fontSize, color}}>{reservation.name}</Text>
7588
</TouchableOpacity>
7689
);
7790
}
7891

79-
renderEmptyDate() {
92+
renderEmptyDate = () => {
8093
return (
8194
<View style={styles.emptyDate}>
8295
<Text>This is empty date!</Text>
8396
</View>
8497
);
8598
}
8699

87-
rowHasChanged(r1, r2) {
100+
rowHasChanged = (r1: ReservationItemType, r2: ReservationItemType) => {
88101
return r1.name !== r2.name;
89102
}
90103

91-
timeToString(time) {
104+
timeToString(time: number) {
92105
const date = new Date(time);
93106
return date.toISOString().split('T')[0];
94107
}

src/agenda/index.tsx

Lines changed: 32 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -21,45 +21,35 @@ import {weekDayNames, sameDate, sameMonth} from '../dateutils';
2121
import {AGENDA_CALENDAR_KNOB} from '../testIDs';
2222
import {VelocityTracker} from '../velocityTracker';
2323
import {DateData} from '../types';
24+
import {getCalendarDateString} from '../services';
2425
import styleConstructor from './style';
26+
import {ReservationsType} from '../types';
2527
import CalendarList, {CalendarListProps} from '../calendar-list';
2628
import ReservationList, {ReservationListProps} from './reservation-list';
2729

2830

2931
const HEADER_HEIGHT = 104;
3032
const KNOB_HEIGHT = 24;
3133

32-
export type ReservationItemType = {
33-
name: string;
34-
height: number;
35-
day: XDate;
36-
};
37-
38-
export type ReservationsType = {
39-
[date: string]: ReservationItemType[];
40-
};
41-
4234
export type AgendaProps = CalendarListProps & ReservationListProps & {
4335
/** the list of items that have to be displayed in agenda. If you want to render item as empty date
4436
the value of date key has to be an empty array []. If there exists no value for date key it is
4537
considered that the date in question is not yet loaded */
46-
items: ReservationsType;
38+
items?: ReservationsType;
4739
/** callback that gets called when items for a certain month should be loaded (month became visible) */
48-
loadItemsForMonth?: (data: any) => DateData;
40+
loadItemsForMonth?: (data: DateData) => void;
4941
/** callback that fires when the calendar is opened or closed */
5042
onCalendarToggled?: (enabled: boolean) => void;
51-
/** callback that gets called on day press */
52-
onDayPress?: (data: DateData) => void;
5343
/** callback that gets called when day changes while scrolling agenda list */
54-
onDayChange?: (data: any) => void;
44+
onDayChange?: (data: DateData) => void;
5545
/** specify how agenda knob should look like */
5646
renderKnob?: () => JSX.Element;
5747
/** initially selected day */
58-
selected: boolean; //TODO: Should be renamed 'selectedDay'
48+
selected?: string; //TODO: Should be renamed 'selectedDay'
5949
/** Hide knob button. Default = false */
60-
hideKnob: boolean;
50+
hideKnob?: boolean;
6151
/** When `true` and `hideKnob` prop is `false`, the knob will always be visible and the user will be able to drag the knob up and close the calendar. Default = false */
62-
showClosingKnob: boolean;
52+
showClosingKnob?: boolean;
6353
}
6454

6555
type State = {
@@ -94,8 +84,6 @@ export default class Agenda extends Component<AgendaProps, State> {
9484
loadItemsForMonth: PropTypes.func,
9585
/** callback that fires when the calendar is opened or closed */
9686
onCalendarToggled: PropTypes.func,
97-
/** callback that gets called on day press */
98-
onDayPress: PropTypes.func,
9987
/** callback that gets called when day changes while scrolling agenda list */
10088
onDayChange: PropTypes.func,
10189
/** specify how agenda knob should look like */
@@ -111,14 +99,14 @@ export default class Agenda extends Component<AgendaProps, State> {
11199
private style: {[key: string]: ViewStyle};
112100
private viewHeight: number;
113101
private viewWidth: number;
114-
private scrollTimeout: any;
102+
private scrollTimeout?: ReturnType<typeof setTimeout>;
115103
private headerState: string;
116104
private currentMonth: XDate;
117-
private knobTracker: any;
105+
private knobTracker: VelocityTracker;
118106
private _isMounted: boolean | undefined;
119107
private scrollPad: React.RefObject<any> = React.createRef();
120108
private calendar: React.RefObject<CalendarList> = React.createRef();
121-
private knob: React.RefObject<any> = React.createRef();
109+
private knob: React.RefObject<View> = React.createRef();
122110
public list: React.RefObject<ReservationList> = React.createRef();
123111

124112
constructor(props: AgendaProps) {
@@ -228,11 +216,11 @@ export default class Agenda extends Component<AgendaProps, State> {
228216
}
229217
}
230218

231-
chooseDayFromCalendar = (d: any) => {
219+
onDayPress = (d: DateData) => {
232220
this.chooseDay(d, !this.state.calendarScrollable);
233221
};
234222

235-
chooseDay(d: any, optimisticScroll: boolean) {
223+
chooseDay(d: DateData, optimisticScroll: boolean) {
236224
const day = parseDate(d);
237225

238226
this.setState({
@@ -255,14 +243,16 @@ export default class Agenda extends Component<AgendaProps, State> {
255243
this.props.onDayPress?.(xdateToData(day));
256244
}
257245

258-
generateMarkings = memoize((selectedDay, markedDates, items = {}) => {
246+
generateMarkings = memoize((selectedDay, markedDates, items) => {
259247
if (!markedDates) {
260248
markedDates = {};
261-
Object.keys(items).forEach(key => {
262-
if (items[key] && items[key].length) {
263-
markedDates[key] = {marked: true};
264-
}
265-
});
249+
if (items) {
250+
Object.keys(items).forEach(key => {
251+
if (items[key] && items[key].length) {
252+
markedDates[key] = {marked: true};
253+
}
254+
});
255+
}
266256
}
267257

268258
const key = toMarkingFormat(selectedDay);
@@ -326,7 +316,9 @@ export default class Agenda extends Component<AgendaProps, State> {
326316
this.props.onVisibleMonthsChange?.(months);
327317

328318
if (this.props.items && !this.state.firstReservationLoad) {
329-
clearTimeout(this.scrollTimeout);
319+
if (this.scrollTimeout) {
320+
clearTimeout(this.scrollTimeout);
321+
}
330322

331323
this.scrollTimeout = setTimeout(() => {
332324
if (this._isMounted) {
@@ -336,16 +328,13 @@ export default class Agenda extends Component<AgendaProps, State> {
336328
}
337329
};
338330

339-
onDayChange = (day: any) => {
340-
const newDate = parseDate(day);
341-
const withAnimation = sameMonth(newDate, this.state.selectedDay);
342-
331+
onDayChange = (day: XDate) => {
332+
const withAnimation = sameMonth(day, this.state.selectedDay);
343333
this.calendar?.current?.scrollToDay(day, this.calendarOffset(), withAnimation);
344-
this.setState({
345-
selectedDay: newDate
346-
});
334+
335+
this.setState({selectedDay: day});
347336

348-
this.props.onDayChange?.(xdateToData(newDate));
337+
this.props.onDayChange?.(xdateToData(day));
349338
};
350339

351340
renderReservations() {
@@ -355,7 +344,7 @@ export default class Agenda extends Component<AgendaProps, State> {
355344
<ReservationList
356345
{...reservationListProps}
357346
ref={this.list}
358-
reservations={this.props.items}
347+
items={this.props.items}
359348
selectedDay={this.state.selectedDay}
360349
topDay={this.state.topDay}
361350
onDayChange={this.onDayChange}
@@ -372,13 +361,13 @@ export default class Agenda extends Component<AgendaProps, State> {
372361
<CalendarList
373362
{...calendarListProps}
374363
ref={this.calendar}
375-
current={this.currentMonth}
364+
current={getCalendarDateString(this.currentMonth.toString())}
376365
markedDates={this.generateMarkings(this.state.selectedDay, markedDates, items)}
377366
calendarWidth={this.viewWidth}
378367
scrollEnabled={this.state.calendarScrollable}
379368
hideExtraDays={shouldHideExtraDays}
380369
onLayout={this.onCalendarListLayout}
381-
onDayPress={this.chooseDayFromCalendar}
370+
onDayPress={this.onDayPress}
382371
onVisibleMonthsChange={this.onVisibleMonthsChange}
383372
/>
384373
);

src/agenda/reservation-list/index.tsx

Lines changed: 9 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -10,20 +10,14 @@ import {sameDate} from '../../dateutils';
1010
import {toMarkingFormat} from '../../interface';
1111
import styleConstructor from './style';
1212
import Reservation, {ReservationProps} from './reservation';
13-
import {ReservationItemType, ReservationsType} from '../../agenda';
13+
import {ReservationItemType, ReservationsType, DayReservations} from '../../types';
1414

1515

16-
export interface DayReservations {
17-
reservation?: ReservationItemType;
18-
date?: XDate;
19-
day: XDate;
20-
}
21-
2216
export type ReservationListProps = ReservationProps & {
2317
/** the list of items that have to be displayed in agenda. If you want to render item as empty date
2418
the value of date key kas to be an empty array []. If there exists no value for date key it is
2519
considered that the date in question is not yet loaded */
26-
reservations: ReservationsType;
20+
items?: ReservationsType;
2721
selectedDay: XDate;
2822
topDay: XDate;
2923
/** Show items only for the selected day. Default = false */
@@ -52,19 +46,19 @@ export type ReservationListProps = ReservationProps & {
5246
onRefresh?: () => void;
5347
};
5448

55-
interface ReservationsListState {
49+
interface State {
5650
reservations: DayReservations[];
5751
}
5852

59-
class ReservationList extends Component<ReservationListProps, ReservationsListState> {
53+
class ReservationList extends Component<ReservationListProps, State> {
6054
static displayName = 'ReservationList';
6155

6256
static propTypes = {
6357
...Reservation.propTypes,
6458
/** the list of items that have to be displayed in agenda. If you want to render item as empty date
6559
the value of date key kas to be an empty array []. If there exists no value for date key it is
6660
considered that the date in question is not yet loaded */
67-
reservations: PropTypes.object,
61+
items: PropTypes.object,
6862
selectedDay: PropTypes.instanceOf(XDate),
6963
topDay: PropTypes.instanceOf(XDate),
7064
/** Show items only for the selected day. Default = false */
@@ -159,7 +153,7 @@ class ReservationList extends Component<ReservationListProps, ReservationsListSt
159153

160154
getReservationsForDay(iterator: XDate, props: ReservationListProps) {
161155
const day = iterator.clone();
162-
const res = props.reservations[toMarkingFormat(day)];
156+
const res = props.items?.[toMarkingFormat(day)];
163157
if (res && res.length) {
164158
return res.map((reservation: ReservationItemType, i: number) => {
165159
return {
@@ -182,14 +176,13 @@ class ReservationList extends Component<ReservationListProps, ReservationsListSt
182176

183177
getReservations(props: ReservationListProps) {
184178
const {selectedDay, showOnlySelectedDayItems} = props;
185-
if (!props.reservations || !selectedDay) {
179+
if (!props.items || !selectedDay) {
186180
return {reservations: [], scrollPosition: 0};
187181
}
188182

189183
let reservations: DayReservations[] = [];
190184
if (this.state.reservations && this.state.reservations.length) {
191185
const iterator = this.state.reservations[0].day.clone();
192-
193186
while (iterator.getTime() < selectedDay.getTime()) {
194187
const res = this.getReservationsForDay(iterator, props);
195188
if (!res) {
@@ -275,8 +268,8 @@ class ReservationList extends Component<ReservationListProps, ReservationsListSt
275268
keyExtractor = (_item: DayReservations, index: number) => String(index);
276269

277270
render() {
278-
const {reservations, selectedDay, theme, style} = this.props;
279-
if (!reservations || !reservations[toMarkingFormat(selectedDay)]) {
271+
const {items, selectedDay, theme, style} = this.props;
272+
if (!items || !items[toMarkingFormat(selectedDay)]) {
280273
if (isFunction(this.props.renderEmptyData)) {
281274
return this.props.renderEmptyData?.();
282275
}

0 commit comments

Comments
 (0)