@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/MonthList.tsx CHANGED
@@ -1,219 +1,282 @@
1
- import {scaleSize, Spacing} from '@momo-kits/foundation';
2
- import moment, {Moment} from 'moment';
3
- import React, {
4
- forwardRef,
5
- useImperativeHandle,
6
- useCallback,
7
- useContext,
8
- useEffect,
9
- useMemo,
10
- useRef,
11
- useState,
12
- } from 'react';
1
+ import React, {Component} from 'react';
13
2
  import {FlatList, Platform} from 'react-native';
14
- import {ContainerContext} from './index';
15
- import LunarDateConverter from './LunarDateConverter';
3
+ import moment from 'moment';
4
+ import Moment from 'moment';
16
5
  import Month from './Month';
17
- import {MonthListProps, MonthListRef} from './types';
6
+ import LunarDateConverter from './LunarDateConverter';
7
+ import {Holidays, MonthListProps, MonthListState} from './types';
8
+ import {ContainerContext} from './index';
9
+ import {scaleSize, Spacing} from '@momo-kits/foundation';
18
10
 
19
11
  const MAX_RENDER_PER_BATCH = Platform.OS === 'android' ? 1 : 12;
20
12
 
21
13
  // @ts-ignore
22
14
  const converter = new LunarDateConverter();
15
+ export default class MonthList extends Component<
16
+ MonthListProps,
17
+ MonthListState
18
+ > {
19
+ currentDate;
20
+ data;
21
+ currentScrollIndex;
22
+ list;
23
+ heightStyle;
24
+ holidays?: Holidays[] = [];
25
+ currentKey: any;
26
+
27
+ constructor(props: MonthListProps) {
28
+ super(props);
29
+ this.currentDate = moment();
30
+ this.data = this.getMonthList();
31
+ this.currentScrollIndex = this.getIndexOfMonth(
32
+ moment(props.selectedDate),
33
+ this.data,
34
+ );
35
+ this.list = React.createRef<FlatList>();
36
+ this.heightStyle = {};
37
+ this.holidays = props.holidays;
38
+ }
39
+
40
+ renderMonth = (data: {
41
+ item: {dateList: any; date: moment.Moment};
42
+ index: number;
43
+ }) => {
44
+ const {isDoubleDateMode, disabledDays, priceList, isShowLunar} = this.props;
45
+ const {item, index} = data;
46
+
47
+ const keyMonth = moment(item.date)?.format('YYYY-MM');
48
+ const priceListDate = priceList?.[keyMonth];
49
+
50
+ return (
51
+ <Month
52
+ {...this.props}
53
+ key={index}
54
+ month={item.date || {}}
55
+ dateList={item.dateList || []}
56
+ priceListDate={priceListDate}
57
+ isShowLunar={isShowLunar}
58
+ isDoubleDateMode={isDoubleDateMode}
59
+ disabledDays={disabledDays}
60
+ />
61
+ );
62
+ };
63
+
64
+ checkRange = (
65
+ date?: moment.Moment | null,
66
+ start?: moment.Moment | null,
67
+ end?: moment.Moment | null,
68
+ ) => {
69
+ if (!date || !start) return false;
70
+ if (!end) {
71
+ return date.year() === start.year() && date.month() === start.month();
72
+ }
73
+ if (
74
+ date.year() < start.year() ||
75
+ (date.year() === start.year() && date.month() < start.month())
76
+ ) {
77
+ return false;
78
+ }
79
+ return !(
80
+ date.year() > end.year() ||
81
+ (date.year() === end.year() && date.month() > end.month())
82
+ );
83
+ };
84
+
85
+ shouldUpdate = (
86
+ month: {date: any; dateList?: any[]},
87
+ props?: MonthListProps,
88
+ ) => {
89
+ if (!props) return false;
90
+ const {startDate, endDate} = props;
91
+ const {startDate: curStartDate, endDate: curEndDate} = this.props;
92
+ const {date} = month;
93
+ const next = this.checkRange(date, startDate, endDate);
94
+ const prev = this.checkRange(date, curStartDate, curEndDate);
95
+ return prev || next;
96
+ };
97
+
98
+ convertLunarToSolar(date: moment.Moment) {
99
+ return date
100
+ ? converter.SolarToLunar({
101
+ solarDay: date.date(),
102
+ solarMonth: date.month() + 1,
103
+ solarYear: date.year(),
104
+ })
105
+ : {};
106
+ }
107
+
108
+ findHoliday = (date: Moment.Moment) => {
109
+ const {holidays} = this.props;
110
+ if (date && holidays && holidays.length > 0) {
111
+ const day = date.date();
112
+ const month = date.month() + 1;
113
+ return holidays.find(item => item.day === day && item.month === month);
114
+ }
115
+ return null;
116
+ };
117
+
118
+ checkHoliday = (date: moment.Moment) => {
119
+ const holiday = this.findHoliday(date);
120
+ return {
121
+ isSolarHoliday: !!(holiday && !holiday.lunar),
122
+ isLunarHoliday: !!(holiday && holiday.lunar),
123
+ };
124
+ };
23
125
 
24
- const MonthList = forwardRef<MonthListRef, MonthListProps>((props, ref) => {
25
- const {
26
- selectedDate,
27
- minDate,
28
- maxDate,
29
- startDate,
30
- endDate,
31
- holidays = [],
32
- priceList,
33
- isShowLunar,
34
- isDoubleDateMode,
35
- disabledDays,
36
- onScrollCalendar,
37
- ...restProps
38
- } = props;
39
-
40
- const size = useContext(ContainerContext);
41
- const listRef = useRef<FlatList>(null);
42
- const currentKey = useRef<string | null>(null);
43
- const [heightStyle, setHeightStyle] = useState({});
44
-
45
- const data = useMemo(() => {
46
- const months: {date: Moment; dateList: any[]}[] = [];
47
- const mMin = moment(minDate).date(1);
48
- const mMax = moment(maxDate);
126
+ getDayList = (date: moment.Moment) => {
127
+ let dayList;
128
+ const month = date.month();
129
+ let weekday = date.isoWeekday();
130
+ if (weekday === 1) {
131
+ dayList = [];
132
+ } else {
133
+ dayList = new Array(weekday - 1).fill({
134
+ empty: moment(date).subtract(1, 'h'),
135
+ lunarDate: this.convertLunarToSolar(date),
136
+ ...this.checkHoliday(date),
137
+ });
138
+ }
139
+ while (date.month() === month) {
140
+ const cloned = moment(date);
141
+ dayList.push({
142
+ date: cloned,
143
+ lunarDate: this.convertLunarToSolar(cloned),
144
+ ...this.checkHoliday(date),
145
+ });
146
+ date.add(1, 'days');
147
+ }
148
+ date.subtract(1, 'days');
149
+ weekday = date.isoWeekday();
150
+ if (weekday === 1) {
151
+ return dayList.concat(
152
+ new Array(6).fill({
153
+ empty: moment(date).hour(1),
154
+ lunarDate: this.convertLunarToSolar(date),
155
+ }),
156
+ );
157
+ }
158
+ return dayList.concat(
159
+ new Array(Math.abs(7 - weekday)).fill({
160
+ empty: moment(date).hour(1),
161
+ lunarDate: this.convertLunarToSolar(date),
162
+ }),
163
+ );
164
+ };
165
+
166
+ getMonthList = (props?: MonthListProps) => {
167
+ const minDate = moment((props || this.props).minDate).date(1);
168
+ const maxDate = moment((props || this.props).maxDate);
169
+ const monthList: {date: moment.Moment; dateList: any[]}[] = [];
170
+ if (!maxDate || !minDate) return monthList;
49
171
  while (
50
- mMax > mMin ||
51
- (mMax.year() === mMin.year() && mMax.month() === mMin.month())
172
+ maxDate > minDate ||
173
+ (maxDate.year() === minDate.year() && maxDate.month() === minDate.month())
52
174
  ) {
53
- const d = moment(mMin);
54
- const dayList: any[] = [];
55
- const monthIdx = d.month();
56
- let cursor = d.clone();
57
- let weekday = cursor.isoWeekday();
58
- if (weekday !== 1) {
59
- dayList.push(
60
- ...new Array(weekday - 1).fill(0).map(() => ({ isEmpty: true }))
61
- );
62
- }
63
- while (cursor.month() === monthIdx) {
64
- const cloned = cursor.clone();
65
- const hol = holidays.find(
66
- h => h.day === cloned.date() && h.month === cloned.month() + 1
67
- );
68
- dayList.push({
69
- isEmpty: false,
70
- date: cloned,
71
- lunarDate: converter.SolarToLunar({
72
- solarDay: cloned.date(),
73
- solarMonth: cloned.month() + 1,
74
- solarYear: cloned.year(),
75
- }),
76
- isSolarHoliday: !!(hol && !hol.lunar),
77
- isLunarHoliday: !!(hol && hol.lunar),
78
- });
79
- cursor.add(1, 'days');
80
- }
81
- cursor.subtract(1, 'days');
82
- weekday = cursor.isoWeekday();
83
- if (weekday !== 7) {
84
- dayList.push(
85
- ...new Array(7 - weekday).fill(0).map(() => ({ isEmpty: true }))
86
- );
87
- }
88
- months.push({date: d, dateList: dayList});
89
- mMin.add(1, 'month');
175
+ const d = moment(minDate);
176
+ const month = {
177
+ date: d,
178
+ dateList: this.getDayList(d),
179
+ shouldUpdate: false,
180
+ };
181
+ month.shouldUpdate = this.shouldUpdate(month, props);
182
+ monthList.push(month);
183
+ minDate.add(1, 'month');
90
184
  }
91
- return months;
92
- }, [minDate, maxDate, holidays]);
93
-
94
- const getIndexOfMonth = useCallback(
95
- (date: Moment) => data.findIndex(item => item.date.isSame(date, 'month')),
96
- [data]
97
- );
98
-
99
- const currentScrollIndex = useMemo(
100
- () => getIndexOfMonth(moment(selectedDate)),
101
- [selectedDate, getIndexOfMonth]
102
- );
103
-
104
- const scrollToMonth = useCallback(
105
- (month: Moment) => {
106
- const idx = getIndexOfMonth(month);
107
- if (listRef.current && idx !== -1) {
108
- listRef.current.scrollToIndex({index: idx, animated: true});
109
- }
110
- },
111
- [getIndexOfMonth]
112
- );
113
185
 
114
- useImperativeHandle(ref, () => ({scrollToMonth}));
186
+ return monthList;
187
+ };
115
188
 
116
- useEffect(() => {
117
- const timer = setTimeout(() => {
118
- scrollToMonth(selectedDate);
119
- }, 500);
120
- return () => clearTimeout(timer);
121
- }, []);
189
+ getIndexOfMonth = (month: moment.Moment, data: any[]) => {
190
+ return data.findIndex(item => item.date.isSame(month, 'month'));
191
+ };
122
192
 
123
- const onViewableItemsChanged = useRef(({changed}: {changed: any[]}) => {
124
- if (changed.length > 0) {
193
+ getCurrentVisibleMonth = (info: {changed: any}) => {
194
+ const {changed} = info;
195
+ const {onScrollCalendar} = this.props;
196
+ if (changed && changed.length > 0) {
125
197
  const {item, key, index} = changed[0];
126
- if (onScrollCalendar && item && currentKey.current !== key) {
127
- currentKey.current = key;
198
+ if (onScrollCalendar && item && this.currentKey !== key) {
199
+ this.currentKey = key;
128
200
  try {
129
- setHeightStyle({
130
- height:
131
- (scaleSize(48) * item.dateList.length) / 7 +
132
- Spacing.L * 2 +
133
- Spacing.XS,
201
+ this.heightStyle =
202
+ this.data && this.data[index] && this.data[index].dateList
203
+ ? {
204
+ height:
205
+ (scaleSize(48) * this.data[index].dateList.length) / 7 +
206
+ Spacing.L * 2 +
207
+ Spacing.XS,
208
+ }
209
+ : {};
210
+ } catch (e) {
211
+ this.heightStyle = {};
212
+ }
213
+ if (onScrollCalendar) {
214
+ onScrollCalendar({
215
+ date: item.date,
216
+ key,
217
+ currentIndex: index,
134
218
  });
135
- } catch {
136
- setHeightStyle({});
137
219
  }
138
- onScrollCalendar({date: item.date, key, currentIndex: index});
139
220
  }
140
221
  }
141
- }).current;
142
-
143
- const viewabilityConfig = {itemVisiblePercentThreshold: 50};
144
-
145
- const keyExtractor = useCallback(
146
- (item: {date: Moment}) => `${item.date.month() + 1}/${item.date.year()}`,
147
- []
148
- );
149
-
150
- const getItemLayout = useCallback(
151
- (_: any, index: number) => ({
152
- length: size.width,
153
- offset: size.width * index,
154
- index,
155
- }),
156
- [size.width]
157
- );
158
-
159
- const renderItem = useCallback(
160
- ({item, index}: {item: {date: Moment; dateList: any[]}; index: number}) => {
161
- const keyMonth = moment(item.date).format('YYYY-MM');
162
- const priceListDate = priceList?.[keyMonth]?.day;
163
- return (
164
- <Month
165
- {...restProps}
166
- key={index}
167
- month={item.date}
168
- dateList={item.dateList}
169
- priceListDate={priceListDate}
170
- holidays={holidays}
171
- minDate={minDate}
172
- maxDate={maxDate}
173
- startDate={startDate}
174
- endDate={endDate}
175
- isShowLunar={isShowLunar}
176
- isDoubleDateMode={isDoubleDateMode}
177
- disabledDays={disabledDays}
178
- />
179
- );
180
- },
181
- [
182
- restProps,
183
- priceList,
184
- holidays,
185
- minDate,
186
- maxDate,
187
- startDate,
188
- endDate,
189
- isShowLunar,
190
- isDoubleDateMode,
191
- disabledDays,
192
- ]
193
- );
194
-
195
- return (
196
- <FlatList
197
- extraData={priceList}
198
- style={heightStyle}
199
- pagingEnabled
200
- horizontal
201
- ref={listRef}
202
- data={data}
203
- renderItem={renderItem}
204
- showsHorizontalScrollIndicator={false}
205
- keyExtractor={keyExtractor}
206
- onScrollToIndexFailed={() => {}}
207
- scrollEnabled
208
- initialNumToRender={3}
209
- maxToRenderPerBatch={MAX_RENDER_PER_BATCH}
210
- windowSize={1}
211
- onViewableItemsChanged={onViewableItemsChanged}
212
- initialScrollIndex={currentScrollIndex}
213
- getItemLayout={getItemLayout}
214
- viewabilityConfig={viewabilityConfig}
215
- />
216
- );
217
- });
218
-
219
- export default MonthList;
222
+ };
223
+
224
+ keyExtractor = (item: {date: Moment.Moment}) =>
225
+ `${item.date.month() + 1}/${item.date.year()}`;
226
+
227
+ scrollToMonth = (month: moment.Moment) => {
228
+ const index = this.getIndexOfMonth(month, this.data);
229
+ if (this.list.current && index !== -1) {
230
+ this.list.current.scrollToIndex({
231
+ index,
232
+ animated: true,
233
+ });
234
+ }
235
+ };
236
+
237
+ getItemLayout = (data: any, index: number, width: number) => ({
238
+ length: width,
239
+ offset: width * index,
240
+ index,
241
+ });
242
+
243
+ componentDidMount() {
244
+ setTimeout(() => {
245
+ this.scrollToMonth(this.currentDate);
246
+ }, 500);
247
+ }
248
+
249
+ render() {
250
+ const {priceList} = this.props;
251
+ return (
252
+ <ContainerContext.Consumer>
253
+ {size => (
254
+ <FlatList
255
+ extraData={priceList}
256
+ style={this.heightStyle}
257
+ pagingEnabled
258
+ horizontal
259
+ ref={this.list}
260
+ data={this.data}
261
+ renderItem={this.renderMonth}
262
+ showsHorizontalScrollIndicator={false}
263
+ keyExtractor={this.keyExtractor}
264
+ onViewableItemsChanged={this.getCurrentVisibleMonth}
265
+ onScrollToIndexFailed={() => {}}
266
+ scrollEnabled
267
+ initialNumToRender={3}
268
+ maxToRenderPerBatch={MAX_RENDER_PER_BATCH}
269
+ windowSize={1}
270
+ initialScrollIndex={this.currentScrollIndex}
271
+ getItemLayout={(data, index) =>
272
+ this.getItemLayout(data, index, size.width)
273
+ }
274
+ viewabilityConfig={{
275
+ itemVisiblePercentThreshold: 50,
276
+ }}
277
+ />
278
+ )}
279
+ </ContainerContext.Consumer>
280
+ );
281
+ }
282
+ }
package/TabHeader.tsx CHANGED
@@ -17,7 +17,7 @@ export default class TabHeader extends React.Component<
17
17
  > {
18
18
  static contextType = ApplicationContext;
19
19
  label;
20
- defaultDate: Moment.Moment | null;
20
+ defaultDate: Moment.Moment;
21
21
 
22
22
  constructor(props: TabHeaderProps) {
23
23
  super(props);
@@ -25,7 +25,7 @@ export default class TabHeader extends React.Component<
25
25
  active: props.activeTab,
26
26
  };
27
27
  this.label = props.label;
28
- this.defaultDate = props.date ? Moment(props.date) : null;
28
+ this.defaultDate = props.date ? Moment(props.date) : Moment();
29
29
  }
30
30
 
31
31
  onChangeTab = () => {
@@ -35,7 +35,7 @@ export default class TabHeader extends React.Component<
35
35
 
36
36
  updateView = (date?: Moment.Moment | Date | null, activeTab?: boolean) => {
37
37
  this.setState({
38
- date: date ? Moment(date) : undefined,
38
+ date: date ? Moment(date) : Moment(),
39
39
  active: activeTab,
40
40
  });
41
41
  };
package/Util.ts CHANGED
@@ -1,7 +1,6 @@
1
1
  import moment from 'moment';
2
2
  import LunarDateConverter from './LunarDateConverter';
3
3
  import holiday from './holidayData';
4
- import {Holidays} from './types';
5
4
 
6
5
  const I18N_MAP = {
7
6
  en: {
@@ -60,10 +59,8 @@ const formatYYYYMMDD = (dd: number, mm: number, yyyy: any) =>
60
59
  const formatDDMM = (dd: number, mm: number) =>
61
60
  `${dd < 10 ? `0${dd}` : dd}/${mm < 10 ? `0${mm}` : mm}`;
62
61
 
63
- const groupHolidaysByDate = (
64
- holidays: Holidays[]
65
- ): {[key: string]: Holidays} => {
66
- const groupedHolidays: {[key: string]: Holidays} = {};
62
+ const groupHolidaysByDate = (holidays: any[]) => {
63
+ const groupedHolidays: {[key: string]: string[]} = {};
67
64
  if (holidays && holidays.length > 0) {
68
65
  holidays.forEach(item => {
69
66
  const {day, month, lunar, label} = item;
@@ -93,18 +90,17 @@ const groupHolidaysByDate = (
93
90
  return groupedHolidays;
94
91
  };
95
92
 
96
- /**
97
- * Sort and group holidays by date, return sorted array of unique Holidays.
98
- */
99
- const sortByDate = (arr: Holidays[]): Holidays[] => {
93
+ const sortByDate = (arr: any[]) => {
100
94
  if (arr && arr.length > 1) {
101
- arr.sort((a, b) =>
102
- a.month !== b.month ? a.month - b.month : a.day - b.day
103
- );
95
+ arr.sort((a, b) => {
96
+ if (a.month > b.month || (a.month === b.month && a.day > b.day)) {
97
+ return 1;
98
+ }
99
+ return -1;
100
+ });
104
101
  }
105
- // group by date string and return unique values in sorted order
106
- const grouped = groupHolidaysByDate(arr);
107
- return Object.values(grouped);
102
+
103
+ return groupHolidaysByDate(arr);
108
104
  };
109
105
 
110
106
  const Utils = {
@@ -187,11 +183,9 @@ const Utils = {
187
183
  return lastDayOfMonth.getDate();
188
184
  },
189
185
 
190
- /**
191
- * Get sorted list of holidays within the given month.
192
- */
193
- getHolidaysInMonth(headerInfo: moment.Moment): Holidays[] {
186
+ getHolidaysInMonth(headerInfo: moment.Moment) {
194
187
  if (headerInfo) {
188
+ const today = moment();
195
189
  // @ts-ignore
196
190
  const converter = new LunarDateConverter();
197
191
  const startDate = moment(headerInfo).startOf('month');
@@ -215,10 +209,10 @@ const Utils = {
215
209
  month: date.month - 1,
216
210
  date: date.day,
217
211
  });
218
- if (dateAsMoment.isBetween(startDate, endDate, 'day', '[]')) {
212
+ if (dateAsMoment.isSameOrAfter(today, 'date')) {
219
213
  holidays.push(date);
220
214
  }
221
- }
215
+ },
222
216
  );
223
217
  }
224
218
 
@@ -235,13 +229,22 @@ const Utils = {
235
229
  lunarYear: currentYear[1],
236
230
  });
237
231
  const solar1AsMoment = moment(
238
- formatYYYYMMDD(solar1.solarDay, solar1.solarMonth, solar1.solarYear)
232
+ formatYYYYMMDD(
233
+ solar1.solarDay,
234
+ solar1.solarMonth,
235
+ solar1.solarYear,
236
+ ),
239
237
  );
240
238
  const solar2AsMoment = moment(
241
- formatYYYYMMDD(solar2.solarDay, solar2.solarMonth, solar2.solarYear)
239
+ formatYYYYMMDD(
240
+ solar2.solarDay,
241
+ solar2.solarMonth,
242
+ solar2.solarYear,
243
+ ),
242
244
  );
243
245
  if (
244
- solar1AsMoment.isBetween(startDate, endDate, 'day', '[]')
246
+ solar1AsMoment.isBetween(startDate, endDate) &&
247
+ solar1AsMoment.isSameOrAfter(today, 'date')
245
248
  ) {
246
249
  holidays.push({
247
250
  ...item,
@@ -249,7 +252,8 @@ const Utils = {
249
252
  month: solar1.solarMonth,
250
253
  });
251
254
  } else if (
252
- solar2AsMoment.isBetween(startDate, endDate, 'day', '[]')
255
+ solar2AsMoment.isBetween(startDate, endDate) &&
256
+ solar2AsMoment.isSameOrAfter(today, 'date')
253
257
  ) {
254
258
  holidays.push({
255
259
  ...item,
@@ -264,10 +268,11 @@ const Utils = {
264
268
  lunarYear: currentYear,
265
269
  });
266
270
  const solarAsMoment = moment(
267
- formatYYYYMMDD(solar.solarDay, solar.solarMonth, solar.solarYear)
271
+ formatYYYYMMDD(solar.solarDay, solar.solarMonth, solar.solarYear),
268
272
  );
269
273
  if (
270
- solarAsMoment.isBetween(startDate, endDate, 'day', '[]')
274
+ solarAsMoment.isBetween(startDate, endDate) &&
275
+ solarAsMoment.isSameOrAfter(today, 'date')
271
276
  ) {
272
277
  holidays.push({
273
278
  ...item,