@momo-kits/calendar 0.121.0-rc.10 → 0.121.0-rc.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CalendarPro.tsx CHANGED
@@ -1,14 +1,7 @@
1
- import React, {
2
- useContext,
3
- useRef,
4
- useState,
5
- useEffect,
6
- useMemo,
7
- forwardRef,
8
- useImperativeHandle,
9
- } from 'react';
1
+ import React, {Component, createRef} from 'react';
2
+
10
3
  import {ScrollView, View} from 'react-native';
11
- import moment, {Moment} from 'moment';
4
+ import Moment from 'moment';
12
5
  import {
13
6
  ApplicationContext,
14
7
  CheckBox,
@@ -22,281 +15,377 @@ import LunarDateConverter from './LunarDateConverter';
22
15
  import Util from './Util';
23
16
  import {
24
17
  CalendarProProps,
25
- CalendarProRef,
18
+ CalendarProState,
26
19
  HeaderControlRef,
27
- MonthListRef,
28
20
  Holidays,
29
21
  } from './types';
30
22
  import {ContainerContext} from './index';
31
23
  import styles from './styles';
32
24
 
33
- const CalendarPro = forwardRef<CalendarProRef, CalendarProProps>(
34
- (
35
- {
36
- startDate: propStartDate,
37
- endDate: propEndDate,
38
- minDate: propMinDate,
39
- maxDate: propMaxDate,
40
- isShowLunar: propIsShowLunar,
41
- selectedDate: propSelectedDate,
42
- isDoubleDateMode,
43
- onDateChange,
44
- priceList,
45
- isHideHoliday,
46
- isOffLunar,
47
- onCallbackCalendar,
48
- disabledDays,
49
- },
50
- ref
51
- ) => {
52
- const {theme, translate} = useContext(ApplicationContext);
53
- const size = useContext(ContainerContext);
54
-
55
- const today = useMemo(() => moment(), []);
56
- const headerRef = useRef<Moment>(today.clone());
57
- const headerControlRef = useRef<HeaderControlRef>(null);
58
- const monthListRef = useRef<MonthListRef>(null);
25
+ export default class CalendarPro extends Component<
26
+ CalendarProProps,
27
+ CalendarProState
28
+ > {
29
+ static contextType = ApplicationContext;
30
+ today: Moment.Moment;
31
+ year: number;
32
+ header: Moment.Moment;
33
+ selectedDate: Moment.Moment;
34
+ converter: typeof LunarDateConverter;
35
+ minDate: Moment.Moment = Moment();
36
+ maxDate: Moment.Moment = Moment();
37
+ monthListRef?: MonthList | null;
38
+ headerControlRef;
59
39
 
60
- // Compute min/max date range
61
- const [minDate, maxDate] = useMemo(() => {
62
- let max = moment(propMaxDate);
63
- let min = moment(propMinDate);
64
- const maxValid = max.isValid();
65
- const minValid = min.isValid();
66
- if (!maxValid && !minValid) {
67
- max = moment().add(12, 'months');
68
- min = moment();
69
- } else if (!maxValid && minValid) {
70
- max = min.clone().add(12, 'months');
71
- } else if (maxValid && !minValid) {
72
- min = max.clone().subtract(12, 'months');
73
- }
74
- return [min, max];
75
- }, [propMinDate, propMaxDate, isDoubleDateMode]);
40
+ constructor(props: CalendarProProps) {
41
+ super(props);
42
+ this.today = Moment();
43
+ this.year = this.today.year();
44
+ this.getDateRange();
45
+ this.header = this.today.clone();
46
+ this.selectedDate = props.selectedDate;
47
+ this.headerControlRef = createRef<HeaderControlRef>();
48
+ this.state = {
49
+ startDate: props.startDate,
50
+ endDate: props.endDate,
51
+ showLunar: props.isShowLunar,
52
+ tabSelected: 0,
53
+ holidays: [],
54
+ ownUpdate: false,
55
+ };
56
+ // @ts-ignore
57
+ this.converter = new LunarDateConverter();
58
+ }
76
59
 
77
- // State
78
- const [startDate, setStartDate] = useState<Moment>(propStartDate);
79
- const [endDate, setEndDate] = useState<Moment | null>(propEndDate || null);
80
- const [showLunar, setShowLunar] = useState<boolean>(!!propIsShowLunar);
81
- const [tabSelected, setTabSelected] = useState<number>(0);
82
- const [holidays, setHolidays] = useState<Holidays[]>([]);
83
- const [temp, setTemp] = useState<any[]>([]);
84
- const [headerKey, setHeaderKey] = useState<string>('');
85
- const [ownUpdate, setOwnUpdate] = useState<boolean>(false);
60
+ static getDerivedStateFromProps(
61
+ nextProps: {isShowLunar: any},
62
+ prevState: {ownUpdate: any; showLunar: any}
63
+ ) {
64
+ if (prevState.ownUpdate) {
65
+ return {
66
+ ownUpdate: false,
67
+ };
68
+ }
69
+ if (nextProps.isShowLunar !== prevState.showLunar) {
70
+ return {showLunar: nextProps.isShowLunar};
71
+ }
72
+ return null;
73
+ }
86
74
 
87
- const converter: any = useMemo(() => LunarDateConverter(), []);
75
+ setDateRange = (
76
+ dateRange: {startDate: any; endDate: any},
77
+ isScrollToStartDate: any
78
+ ) => {
79
+ if (dateRange && dateRange.startDate && dateRange.endDate) {
80
+ this.setState(
81
+ {
82
+ startDate: dateRange.startDate,
83
+ endDate: dateRange.endDate,
84
+ },
85
+ () => {
86
+ const dateScroll = isScrollToStartDate
87
+ ? dateRange.startDate
88
+ : dateRange.endDate;
88
89
 
89
- useImperativeHandle(ref, () => ({
90
- setDoubleDateAndTabIndex: (
91
- firstDate?: Moment | null,
92
- secondDate?: Moment | null,
93
- tabIdx?: number
94
- ) => {
95
- if (typeof tabIdx === 'number') setTabSelected(tabIdx);
96
- if (firstDate) setStartDate(firstDate);
97
- if (secondDate !== undefined) setEndDate(secondDate);
98
- },
99
- setDateRange: (
100
- dateRange: {startDate: any; endDate: any},
101
- ) => {
102
- if (monthListRef.current && dateRange.startDate) {
103
- monthListRef.current.scrollToMonth(moment(dateRange.startDate));
90
+ this.monthListRef?.scrollToMonth(dateScroll);
104
91
  }
105
- },
106
- }));
92
+ );
93
+ }
94
+ };
107
95
 
108
- // Sync showLunar prop
109
- useEffect(() => {
110
- if (ownUpdate) {
111
- setOwnUpdate(false);
112
- } else if (propIsShowLunar !== showLunar) {
113
- setShowLunar(!!propIsShowLunar);
114
- }
115
- }, [propIsShowLunar]);
96
+ ownSetState(state: any) {
97
+ this.setState({
98
+ ...state,
99
+ ownUpdate: true,
100
+ });
101
+ }
116
102
 
117
- // Scroll to initial selected date on mount or when it changes
118
- useEffect(() => {
119
- const timer = setTimeout(() => {
120
- monthListRef.current?.scrollToMonth(propSelectedDate);
121
- }, 500);
122
- return () => clearTimeout(timer);
123
- }, [propSelectedDate]);
103
+ getDateRange = () => {
104
+ const {maxDate, minDate} = this.props;
105
+ let max = Moment(maxDate);
106
+ let min = Moment(minDate);
107
+ const maxValid = max.isValid();
108
+ const minValid = min.isValid();
109
+ if (!maxValid && !minValid) {
110
+ max = Moment().add(12, 'months');
111
+ min = Moment();
112
+ }
113
+ if (!maxValid && minValid) {
114
+ max = min.add(12, 'months');
115
+ }
116
+ if (maxValid && !minValid) {
117
+ min = max.subtract(12, 'months');
118
+ }
119
+ if (min.isSame(max) && this.props.isDoubleDateMode) return {};
120
+ if (min.isAfter(max)) return {};
121
+ this.minDate = min;
122
+ this.maxDate = max;
123
+ };
124
124
 
125
- // Handlers
126
- const onChooseDay = (day: Moment) => {
127
- if (isDoubleDateMode) {
128
- if (tabSelected === 1) {
129
- if (startDate && day >= startDate) {
130
- setEndDate(day);
131
- } else if (startDate && day < startDate) {
132
- setStartDate(day);
133
- setEndDate(null);
134
- }
135
- } else {
136
- setStartDate(day);
125
+ onChoose = (day: Moment.Moment) => {
126
+ const {startDate, tabSelected} = this.state;
127
+ const {isDoubleDateMode, onDateChange} = this.props;
128
+ if (isDoubleDateMode) {
129
+ if (tabSelected === 1) {
130
+ if (startDate && day >= Moment(startDate)) {
131
+ this.ownSetState({
132
+ endDate: day,
133
+ });
134
+ } else if (startDate && day < Moment(startDate)) {
135
+ this.ownSetState({
136
+ startDate: day,
137
+ endDate: null,
138
+ });
137
139
  }
138
140
  } else {
139
- setStartDate(day);
140
- setEndDate(null);
141
+ this.ownSetState({
142
+ startDate: day,
143
+ });
141
144
  }
142
- onDateChange?.(day);
143
- };
145
+ } else {
146
+ this.ownSetState({
147
+ startDate: day,
148
+ endDate: null,
149
+ });
150
+ }
151
+ if (onDateChange) {
152
+ onDateChange(day);
153
+ }
154
+ };
144
155
 
145
- const executeProcessAfterScrollCalendar = (date: Moment, key: string) => {
146
- // get sorted array of holidays directly
147
- const allHolidays = Util.getHolidaysInMonth(moment(date));
148
- const filtered = showLunar
149
- ? allHolidays
150
- : allHolidays.filter(item => !item.lunar || item.mixedLabel);
151
- headerControlRef.current?.onUpdateInfo({date});
152
- headerRef.current = date.clone().startOf('month');
153
- setHolidays(allHolidays);
154
- setTemp(filtered);
155
- setHeaderKey(key);
156
- };
156
+ executeProcessAfterScrollCalendar = (date: Moment.Moment, key: any) => {
157
+ const holidays: any[] = Object.values(
158
+ Util.getHolidaysInMonth(Moment(date))
159
+ );
160
+ const {showLunar} = this.state;
161
+ if (this.headerControlRef) {
162
+ this.headerControlRef.current?.onUpdateInfo({date});
163
+ this.header = date.clone().startOf('month');
164
+ }
165
+ let data = [];
166
+ if (!showLunar) {
167
+ data = holidays.filter(item => !item.lunar || item.mixedLabel);
168
+ } else {
169
+ data = holidays;
170
+ }
171
+ this.ownSetState({
172
+ holidays,
173
+ temp: data,
174
+ headerKey: key,
175
+ });
176
+ };
157
177
 
158
- const onScrollCalendar = (info: {
159
- date: Moment;
160
- key: string;
161
- currentIndex: number;
162
- }) => {
163
- if (info.key !== headerKey) {
164
- executeProcessAfterScrollCalendar(info.date, info.key);
178
+ onScrollCalendar = (data: {key: string; date: Moment.Moment}) => {
179
+ const {headerKey} = this.state;
180
+ if (data) {
181
+ if (data.key !== headerKey) {
182
+ this.executeProcessAfterScrollCalendar(data.date, data.key);
165
183
  }
166
- };
184
+ }
185
+ };
167
186
 
168
- const onToggleLunar = () => {
169
- setOwnUpdate(true);
170
- const next = !showLunar;
171
- const filtered = next
172
- ? holidays
173
- : holidays.filter(item => !item.lunar || item.mixedLabel);
174
- onCallbackCalendar?.('lunar', next);
175
- setShowLunar(next);
176
- setTemp(filtered);
177
- };
187
+ setDoubleDateAndTabIndex = (
188
+ firstDate: Moment.Moment | Date | undefined,
189
+ secondDate?: Moment.Moment | Date | undefined | null,
190
+ tabSelected?: any
191
+ ) => {
192
+ this.ownSetState({
193
+ startDate: firstDate ? Moment(firstDate) : null,
194
+ endDate: secondDate ? Moment(secondDate) : null,
195
+ tabSelected,
196
+ });
197
+ };
178
198
 
179
- const onPressBackArrow = () => {
180
- const prev = headerRef.current
181
- .clone()
182
- .startOf('month')
183
- .subtract(1, 'months');
184
- if (prev.isSameOrAfter(minDate, 'month')) {
185
- headerRef.current = prev;
186
- headerControlRef.current?.onUpdateInfo({date: prev});
187
- monthListRef.current?.scrollToMonth(prev);
188
- }
189
- };
199
+ toggleLunarDate = () => {
200
+ const {showLunar, holidays} = this.state;
201
+ const {onCallbackCalendar} = this.props;
202
+ let data: Holidays[] = [];
203
+ const nextStateShowLunar = !showLunar;
204
+ if (!nextStateShowLunar) {
205
+ data = holidays?.filter(item => !item.lunar || item.mixedLabel);
206
+ } else {
207
+ data = holidays;
208
+ }
209
+ if (onCallbackCalendar) {
210
+ onCallbackCalendar('lunar', nextStateShowLunar);
211
+ }
190
212
 
191
- const onPressNextArrow = () => {
192
- const next = headerRef.current.clone().startOf('month').add(1, 'months');
193
- if (next.isSameOrBefore(maxDate, 'month')) {
194
- headerRef.current = next;
195
- headerControlRef.current?.onUpdateInfo({date: next});
196
- monthListRef.current?.scrollToMonth(next);
197
- }
198
- };
213
+ this.ownSetState({
214
+ showLunar: !showLunar,
215
+ temp: data,
216
+ ownUpdate: true,
217
+ });
218
+ };
219
+
220
+ onPressBackArrow = () => {
221
+ const previousDate = Moment(this.header)
222
+ .startOf('month')
223
+ .subtract(1, 'months');
224
+ if (
225
+ this.headerControlRef &&
226
+ previousDate.isSameOrAfter(this.minDate, 'month')
227
+ ) {
228
+ this.header = previousDate;
229
+ this.headerControlRef.current?.onUpdateInfo({date: previousDate});
230
+ this.monthListRef?.scrollToMonth(previousDate);
231
+ }
232
+ };
199
233
 
200
- // Determine price list format
234
+ onPressNextArrow = () => {
235
+ const nextDate = Moment(this.header).startOf('month').add(1, 'months');
236
+ if (
237
+ this.headerControlRef &&
238
+ nextDate.isSameOrBefore(this.maxDate, 'month')
239
+ ) {
240
+ this.header = nextDate;
241
+ this.headerControlRef.current?.onUpdateInfo({date: nextDate});
242
+ this.monthListRef?.scrollToMonth(nextDate);
243
+ }
244
+ };
245
+
246
+ render() {
247
+ const {
248
+ startDate,
249
+ endDate,
250
+ showLunar = false,
251
+ tabSelected,
252
+ holidays,
253
+ temp,
254
+ } = this.state;
255
+ const {
256
+ isDoubleDateMode,
257
+ priceList,
258
+ disabledDays,
259
+ isHideHoliday,
260
+ isOffLunar,
261
+ } = this.props;
201
262
  let priceListFormat = priceList?.outbound;
202
263
  if (isDoubleDateMode) {
203
264
  priceListFormat =
204
265
  tabSelected === 0 ? priceList?.outbound : priceList?.inbound;
205
266
  }
206
267
 
268
+ const {theme, translate} = this.context;
269
+
207
270
  return (
208
- <View style={styles.container}>
209
- <HeaderControl
210
- ref={headerControlRef}
211
- selectedDate={propSelectedDate}
212
- onPressBackArrow={onPressBackArrow}
213
- onPressNextArrow={onPressNextArrow}
214
- />
215
- <View style={styles.blueSeperator} />
216
- <View>
217
- <View style={styles.viewDay}>
218
- {[1, 2, 3, 4, 5, 6, 7].map(dayIdx => (
219
- <Text
220
- key={dayIdx}
221
- color={dayIdx >= 6 ? Colors.red_03 : Colors.black_17}
222
- typography="label_s_medium"
271
+ <ContainerContext.Consumer>
272
+ {size => (
273
+ <View style={styles.container}>
274
+ <View>
275
+ <HeaderControl
276
+ ref={this.headerControlRef}
277
+ selectedDate={this.selectedDate}
278
+ onPressBackArrow={this.onPressBackArrow}
279
+ onPressNextArrow={this.onPressNextArrow}
280
+ />
281
+ <View style={styles.blueSeperator} />
282
+ <View>
283
+ <View style={styles.viewDay}>
284
+ {[1, 2, 3, 4, 5, 6, 7].map(item => (
285
+ <Text
286
+ color={
287
+ item === 6 || item === 7
288
+ ? Colors.red_03
289
+ : Colors.black_17
290
+ }
291
+ typography={'label_s_medium'}
292
+ style={[
293
+ styles.textDay,
294
+ {
295
+ width: (size.width - Spacing.M * 2) / 7,
296
+ },
297
+ ]}
298
+ key={item}>
299
+ {translate(Util.mapWeeKDate(item))}
300
+ </Text>
301
+ ))}
302
+ </View>
303
+ <MonthList
304
+ ref={ref => (this.monthListRef = ref)}
305
+ today={this.today}
306
+ minDate={this.minDate}
307
+ maxDate={this.maxDate}
308
+ startDate={startDate}
309
+ endDate={endDate}
310
+ onChoose={this.onChoose}
311
+ onScrollCalendar={this.onScrollCalendar}
312
+ isShowLunar={!isOffLunar && showLunar}
313
+ isDoubleDateMode={isDoubleDateMode}
314
+ tabSelected={tabSelected}
315
+ lunarConverter={this.converter}
316
+ holidays={holidays}
317
+ selectedDate={this.selectedDate}
318
+ priceList={priceListFormat}
319
+ disabledDays={disabledDays}
320
+ />
321
+ </View>
322
+ </View>
323
+ {!isOffLunar && (
324
+ <View
223
325
  style={[
224
- styles.textDay,
225
- {width: (size.width - Spacing.M * 2) / 7},
326
+ styles.viewLunar,
327
+ {borderColor: theme.colors.border.default},
226
328
  ]}>
227
- {translate?.(Util.mapWeeKDate(dayIdx))}
228
- </Text>
229
- ))}
230
- </View>
231
- <MonthList
232
- ref={monthListRef}
233
- today={today}
234
- minDate={minDate}
235
- maxDate={maxDate}
236
- startDate={startDate!}
237
- endDate={endDate!}
238
- onChoose={onChooseDay}
239
- onScrollCalendar={onScrollCalendar}
240
- isShowLunar={!isOffLunar && showLunar}
241
- isDoubleDateMode={isDoubleDateMode}
242
- tabSelected={tabSelected}
243
- lunarConverter={converter}
244
- holidays={holidays}
245
- selectedDate={propSelectedDate}
246
- priceList={priceListFormat}
247
- disabledDays={disabledDays}
248
- />
249
- </View>
250
- {!isOffLunar && (
251
- <View
252
- style={[
253
- styles.viewLunar,
254
- {borderColor: theme.colors.border.default},
255
- ]}>
256
- <CheckBox
257
- onChange={onToggleLunar}
258
- value={showLunar}
259
- label={translate?.('showLunar')}
260
- />
329
+ <CheckBox
330
+ onChange={this.toggleLunarDate}
331
+ value={showLunar}
332
+ label={translate('showLunar')}
333
+ />
334
+ </View>
335
+ )}
336
+
337
+ {!isHideHoliday && (
338
+ <ScrollView
339
+ contentContainerStyle={styles.contentScroll}
340
+ showsVerticalScrollIndicator={false}
341
+ nestedScrollEnabled>
342
+ {temp &&
343
+ temp.length > 0 &&
344
+ temp.map(
345
+ (
346
+ item: {
347
+ mixedLabel: any;
348
+ label: any;
349
+ day: number;
350
+ month: number;
351
+ highlight: string;
352
+ },
353
+ idx: {toString: () => React.Key | null | undefined}
354
+ ) => {
355
+ const labelHoliday = showLunar
356
+ ? item.mixedLabel || item.label || ''
357
+ : item.label || '';
358
+ const labelDate = `${
359
+ item.day > 9 ? item.day : `0${item.day}`
360
+ }/${item.month > 9 ? item.month : `0${item.month}`}`;
361
+ const labelHighlight = showLunar
362
+ ? item.highlight || ''
363
+ : '';
364
+ return (
365
+ <View style={styles.row} key={idx.toString()}>
366
+ <Text
367
+ color={theme.colors.error.primary}
368
+ typography={'description_default_regular'}
369
+ style={styles.txtMonthLunar}>
370
+ {labelDate}
371
+ </Text>
372
+ <Text
373
+ typography={'description_default_regular'}
374
+ style={styles.subTextLunar}>
375
+ {`${translate(labelHoliday)}`}
376
+ </Text>
377
+ <Text typography={'description_default_regular'}>
378
+ {labelHighlight}
379
+ </Text>
380
+ </View>
381
+ );
382
+ }
383
+ )}
384
+ </ScrollView>
385
+ )}
261
386
  </View>
262
387
  )}
263
- {!isHideHoliday && (
264
- <ScrollView
265
- contentContainerStyle={styles.contentScroll}
266
- showsVerticalScrollIndicator={false}
267
- nestedScrollEnabled>
268
- {temp.map((item, idx) => {
269
- const labelDate = `${item.day > 9 ? item.day : `0${item.day}`}/${
270
- item.month > 9 ? item.month : `0${item.month}`
271
- }`;
272
- const labelHoliday = showLunar
273
- ? item.mixedLabel || item.label
274
- : item.label;
275
- const labelHighlight = showLunar ? item.highlight || '' : '';
276
- return (
277
- <View style={styles.row} key={idx.toString()}>
278
- <Text
279
- color={theme.colors.error.primary}
280
- typography="description_default_regular"
281
- style={styles.txtMonthLunar}>
282
- {labelDate}
283
- </Text>
284
- <Text
285
- typography="description_default_regular"
286
- style={styles.subTextLunar}>
287
- {translate?.(labelHoliday)}
288
- </Text>
289
- <Text typography="description_default_regular">
290
- {labelHighlight}
291
- </Text>
292
- </View>
293
- );
294
- })}
295
- </ScrollView>
296
- )}
297
- </View>
388
+ </ContainerContext.Consumer>
298
389
  );
299
390
  }
300
- );
301
-
302
- export default CalendarPro;
391
+ }