react-native-nepali-picker 1.0.8 → 1.1.0-alpha.0
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/lib/commonjs/CalendarPicker.js +89 -80
- package/lib/commonjs/CalendarPicker.js.map +1 -1
- package/lib/commonjs/DayCell.js +57 -0
- package/lib/commonjs/DayCell.js.map +1 -0
- package/lib/commonjs/calendar/config.js +1 -1
- package/lib/commonjs/calendar/functions.js +49 -17
- package/lib/commonjs/calendar/functions.js.map +1 -1
- package/lib/commonjs/calendar/settings.js +3 -1
- package/lib/commonjs/calendar/settings.js.map +1 -1
- package/lib/commonjs/calendar/validate.js +39 -0
- package/lib/commonjs/calendar/validate.js.map +1 -0
- package/lib/commonjs/index.js +13 -0
- package/lib/commonjs/index.js.map +1 -1
- package/lib/module/CalendarPicker.js +91 -82
- package/lib/module/CalendarPicker.js.map +1 -1
- package/lib/module/DayCell.js +52 -0
- package/lib/module/DayCell.js.map +1 -0
- package/lib/module/calendar/config.js +1 -1
- package/lib/module/calendar/functions.js +49 -17
- package/lib/module/calendar/functions.js.map +1 -1
- package/lib/module/calendar/settings.js +2 -0
- package/lib/module/calendar/settings.js.map +1 -1
- package/lib/module/calendar/validate.js +34 -0
- package/lib/module/calendar/validate.js.map +1 -0
- package/lib/module/index.js +1 -0
- package/lib/module/index.js.map +1 -1
- package/lib/typescript/commonjs/src/CalendarPicker.d.ts +1 -1
- package/lib/typescript/commonjs/src/CalendarPicker.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/DayCell.d.ts +14 -0
- package/lib/typescript/commonjs/src/DayCell.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/calendar/functions.d.ts +1 -1
- package/lib/typescript/commonjs/src/calendar/functions.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/calendar/settings.d.ts +2 -0
- package/lib/typescript/commonjs/src/calendar/settings.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/calendar/validate.d.ts +2 -0
- package/lib/typescript/commonjs/src/calendar/validate.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/index.d.ts +1 -0
- package/lib/typescript/commonjs/src/index.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/types.d.ts +3 -1
- package/lib/typescript/commonjs/src/types.d.ts.map +1 -1
- package/lib/typescript/module/src/CalendarPicker.d.ts +1 -1
- package/lib/typescript/module/src/CalendarPicker.d.ts.map +1 -1
- package/lib/typescript/module/src/DayCell.d.ts +14 -0
- package/lib/typescript/module/src/DayCell.d.ts.map +1 -0
- package/lib/typescript/module/src/calendar/functions.d.ts +1 -1
- package/lib/typescript/module/src/calendar/functions.d.ts.map +1 -1
- package/lib/typescript/module/src/calendar/settings.d.ts +2 -0
- package/lib/typescript/module/src/calendar/settings.d.ts.map +1 -1
- package/lib/typescript/module/src/calendar/validate.d.ts +2 -0
- package/lib/typescript/module/src/calendar/validate.d.ts.map +1 -0
- package/lib/typescript/module/src/index.d.ts +1 -0
- package/lib/typescript/module/src/index.d.ts.map +1 -1
- package/lib/typescript/module/src/types.d.ts +3 -1
- package/lib/typescript/module/src/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/CalendarPicker.tsx +111 -119
- package/src/DayCell.tsx +70 -0
- package/src/calendar/config.ts +1 -1
- package/src/calendar/functions.ts +59 -17
- package/src/calendar/settings.ts +2 -0
- package/src/calendar/validate.tsx +37 -0
- package/src/index.tsx +1 -0
- package/src/types.ts +3 -1
package/src/CalendarPicker.tsx
CHANGED
|
@@ -1,13 +1,16 @@
|
|
|
1
|
-
import { useEffect, useState } from 'react';
|
|
1
|
+
import { useCallback, useEffect, useMemo, useState, useRef } from 'react';
|
|
2
2
|
import {
|
|
3
|
-
View,
|
|
4
|
-
Text,
|
|
5
3
|
Modal,
|
|
6
4
|
Pressable,
|
|
5
|
+
ScrollView,
|
|
7
6
|
StyleSheet,
|
|
7
|
+
Text,
|
|
8
8
|
TouchableOpacity,
|
|
9
|
-
|
|
9
|
+
View,
|
|
10
10
|
} from 'react-native';
|
|
11
|
+
import DateSyncLogo from './assets/DateSync';
|
|
12
|
+
import { ChevronIcon } from './assets/Icons';
|
|
13
|
+
import Triangle from './assets/Triangle';
|
|
11
14
|
import {
|
|
12
15
|
bs,
|
|
13
16
|
daysInEnglish,
|
|
@@ -16,12 +19,11 @@ import {
|
|
|
16
19
|
monthsInEnglish,
|
|
17
20
|
monthsInNepali,
|
|
18
21
|
} from './calendar/config';
|
|
19
|
-
import {
|
|
20
|
-
import {
|
|
21
|
-
import
|
|
22
|
-
import DateSyncLogo from './assets/DateSync';
|
|
23
|
-
import Triangle from './assets/Triangle';
|
|
22
|
+
import { NepaliToday } from './calendar/functions';
|
|
23
|
+
import { calcFirstDay, NEPALI_MAX_YEAR, NEPALI_MIN_YEAR } from './calendar/settings';
|
|
24
|
+
import DayCell from './DayCell'
|
|
24
25
|
import type { CalendarPickerProps } from './types';
|
|
26
|
+
import { validateCalendarDates } from './calendar/validate';
|
|
25
27
|
|
|
26
28
|
const CalendarPicker = ({
|
|
27
29
|
visible,
|
|
@@ -29,7 +31,9 @@ const CalendarPicker = ({
|
|
|
29
31
|
theme = 'light',
|
|
30
32
|
onDateSelect,
|
|
31
33
|
language = 'np',
|
|
32
|
-
|
|
34
|
+
date = NepaliToday(),
|
|
35
|
+
minDate = '2000-01-01',
|
|
36
|
+
maxDate = '2099-12-30',
|
|
33
37
|
brandColor = '#2081b9',
|
|
34
38
|
titleTextStyle = {
|
|
35
39
|
fontSize: 20,
|
|
@@ -44,17 +48,17 @@ const CalendarPicker = ({
|
|
|
44
48
|
fontWeight: '600',
|
|
45
49
|
},
|
|
46
50
|
}: CalendarPickerProps) => {
|
|
47
|
-
const
|
|
48
|
-
|
|
49
|
-
const
|
|
50
|
-
|
|
51
|
-
const
|
|
52
|
-
const
|
|
53
|
-
|
|
54
|
-
const
|
|
51
|
+
const yearModelScrollRef = useRef<ScrollView>(null)
|
|
52
|
+
|
|
53
|
+
const value = validateCalendarDates(date, minDate, maxDate);
|
|
54
|
+
|
|
55
|
+
const [userSelectedDate, setUserSelectedDate] = useState(date);
|
|
56
|
+
const cYear = parseInt(userSelectedDate.split('-')[0], 10);
|
|
57
|
+
const cMonth = parseInt(userSelectedDate.split('-')[1], 10);
|
|
58
|
+
const cDay = parseInt(userSelectedDate.split('-')[2], 10);
|
|
59
|
+
|
|
55
60
|
const [month, setMonth] = useState<number>(cMonth);
|
|
56
61
|
const [year, setYear] = useState<number>(cYear);
|
|
57
|
-
const [calendarDate, setCalendarDate] = useState<(number | null)[]>([]);
|
|
58
62
|
|
|
59
63
|
const [yearModal, setYearModal] = useState<boolean>(false);
|
|
60
64
|
|
|
@@ -63,21 +67,42 @@ const CalendarPicker = ({
|
|
|
63
67
|
setYear(cYear);
|
|
64
68
|
};
|
|
65
69
|
|
|
66
|
-
const handleDateClick = (day: number) => {
|
|
70
|
+
const handleDateClick = useCallback((day: number) => {
|
|
67
71
|
const date = `${year}-${month.toString().padStart(2, '0')}-${day.toString().padStart(2, '0')}`;
|
|
68
|
-
|
|
72
|
+
setUserSelectedDate(date);
|
|
69
73
|
onDateSelect(date);
|
|
70
74
|
onClose();
|
|
71
|
-
};
|
|
75
|
+
}, [year, month, onDateSelect, onClose]);
|
|
72
76
|
|
|
77
|
+
//check weather the date is disabled or not?(with maximum and minimum date provided)
|
|
78
|
+
const isDateDisabled = useCallback((day: number) => {
|
|
79
|
+
const date = `${year}-${month
|
|
80
|
+
.toString()
|
|
81
|
+
.padStart(2, '0')}-${day.toString().padStart(2, '0')}`;
|
|
82
|
+
|
|
83
|
+
if (minDate && date < minDate) return true;
|
|
84
|
+
if (maxDate && date > maxDate) return true;
|
|
85
|
+
|
|
86
|
+
return false;
|
|
87
|
+
|
|
88
|
+
}, [year, month, minDate, maxDate])
|
|
89
|
+
|
|
90
|
+
// Set the user selected date is as NepaliDate (initially it will be always
|
|
91
|
+
// current Nepali Date)
|
|
73
92
|
useEffect(() => {
|
|
74
|
-
|
|
75
|
-
}, [
|
|
93
|
+
setUserSelectedDate(date);
|
|
94
|
+
}, [date]);
|
|
95
|
+
|
|
96
|
+
// It will calculate the current date number
|
|
97
|
+
const selectedDay = useMemo(() => {
|
|
98
|
+
const [y, m, d] = userSelectedDate.split('-').map(Number);
|
|
99
|
+
return y === year && m === month ? d : null;
|
|
100
|
+
}, [userSelectedDate, year, month]);
|
|
76
101
|
|
|
77
|
-
//Handle Next Month Click
|
|
102
|
+
//Handle Next Month button Click
|
|
78
103
|
const handleNextClick = () => {
|
|
79
104
|
if (month === 12) {
|
|
80
|
-
if (year <
|
|
105
|
+
if (year < NEPALI_MAX_YEAR) {
|
|
81
106
|
setYear((prev) => prev + 1);
|
|
82
107
|
setMonth(1);
|
|
83
108
|
}
|
|
@@ -86,10 +111,10 @@ const CalendarPicker = ({
|
|
|
86
111
|
}
|
|
87
112
|
};
|
|
88
113
|
|
|
89
|
-
//Handle Previous Month Click
|
|
114
|
+
//Handle Previous Month button Click
|
|
90
115
|
const handlePreviousClick = () => {
|
|
91
116
|
if (month === 1) {
|
|
92
|
-
if (year >
|
|
117
|
+
if (year > NEPALI_MIN_YEAR) {
|
|
93
118
|
setYear((prev) => prev - 1);
|
|
94
119
|
setMonth(12);
|
|
95
120
|
}
|
|
@@ -98,39 +123,54 @@ const CalendarPicker = ({
|
|
|
98
123
|
}
|
|
99
124
|
};
|
|
100
125
|
|
|
101
|
-
|
|
126
|
+
//open the model which shows the list of years(2000-2099)BS
|
|
127
|
+
const openYearView = async () => {
|
|
102
128
|
setYearModal(true);
|
|
129
|
+
|
|
130
|
+
//wait for model to open completely before to scroll down
|
|
131
|
+
await new Promise((resolve) => setTimeout(resolve, 10))
|
|
132
|
+
// After model is opened, need ot scrolldown to that year
|
|
133
|
+
// Here we need to calculate (roughly) how much to scroll to keep the seelcted year in
|
|
134
|
+
// focus
|
|
135
|
+
// - For that we take the height of the year button and one row contain around 3-5(
|
|
136
|
+
// we will take 4) column of buttons so,
|
|
137
|
+
// approx Height = (year number(82 for 2082) * button height)/cloumn number
|
|
138
|
+
// NOTE: This is approx just to make the button visible when model is opened.
|
|
139
|
+
const vHeight = (year - NEPALI_MIN_YEAR) * 36 / 4
|
|
140
|
+
yearModelScrollRef.current?.scrollTo({
|
|
141
|
+
y: vHeight,
|
|
142
|
+
animated: true
|
|
143
|
+
})
|
|
144
|
+
|
|
103
145
|
};
|
|
104
146
|
|
|
147
|
+
//close the year view model
|
|
105
148
|
const closeYearView = () => {
|
|
106
149
|
setYearModal(false);
|
|
107
150
|
};
|
|
108
151
|
|
|
109
|
-
|
|
110
|
-
|
|
152
|
+
|
|
153
|
+
// Calculating the number of cells on that month and year(Max it can have 42 cells)
|
|
154
|
+
// If the cells don't have the date, it will be null otherwise it will contain the actual
|
|
155
|
+
// date number (1,2,3...upto 32)
|
|
156
|
+
const calendarDate = useMemo(() => {
|
|
111
157
|
const FDOM = calcFirstDay(year, month);
|
|
112
158
|
const DIM = bs[year][month];
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
if (dayNumber > 0 && dayNumber <= DIM) {
|
|
119
|
-
return dayNumber;
|
|
120
|
-
} else {
|
|
121
|
-
return null;
|
|
122
|
-
}
|
|
123
|
-
});
|
|
124
|
-
setCalendarDate(calendarCells);
|
|
125
|
-
}, [year, month, initialDate]);
|
|
159
|
+
return Array.from({ length: 42 }, (_, index) => {
|
|
160
|
+
const dayNum = index - FDOM + 1
|
|
161
|
+
return dayNum > 0 && dayNum <= DIM ? dayNum : null
|
|
162
|
+
})
|
|
163
|
+
}, [year, month])
|
|
126
164
|
|
|
127
165
|
const handleYearClick = (y: number) => {
|
|
128
166
|
setYear(y);
|
|
129
167
|
closeYearView();
|
|
130
168
|
};
|
|
169
|
+
|
|
131
170
|
const dark = theme === 'dark';
|
|
132
171
|
const weekDays = language === 'en' ? daysInEnglish : daysInNepali;
|
|
133
172
|
|
|
173
|
+
// If the user prvided (initial value ) is not in correct format i.e (YYYY-MM-DD)
|
|
134
174
|
if (value !== true) {
|
|
135
175
|
return (
|
|
136
176
|
<Modal visible={visible} onRequestClose={onClose} transparent={true}>
|
|
@@ -154,7 +194,7 @@ const CalendarPicker = ({
|
|
|
154
194
|
paddingVertical: 10,
|
|
155
195
|
}}
|
|
156
196
|
>
|
|
157
|
-
Unsupported date range on
|
|
197
|
+
Unsupported date range on Provided Date
|
|
158
198
|
</Text>
|
|
159
199
|
<Text
|
|
160
200
|
style={{
|
|
@@ -187,7 +227,7 @@ const CalendarPicker = ({
|
|
|
187
227
|
paddingHorizontal: 10,
|
|
188
228
|
}}
|
|
189
229
|
>
|
|
190
|
-
{language === 'np' ? '
|
|
230
|
+
{language === 'np' ? 'तपाईंको मिति ' : "Selected Date"}
|
|
191
231
|
</Text>
|
|
192
232
|
{/* Today date in large fonts on click sync the calenar with today date */}
|
|
193
233
|
<View
|
|
@@ -304,67 +344,30 @@ const CalendarPicker = ({
|
|
|
304
344
|
</View>
|
|
305
345
|
|
|
306
346
|
{/* for actual data fo calenadr which has the day in them */}
|
|
347
|
+
|
|
307
348
|
<View style={styles.datesContainer}>
|
|
308
|
-
{calendarDate.map((
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
paddingHorizontal: 6,
|
|
322
|
-
paddingVertical: 3,
|
|
323
|
-
borderRadius: 999,
|
|
324
|
-
//check if the date is today or not and apply conditional styling.
|
|
325
|
-
backgroundColor: isToday(
|
|
326
|
-
TodayNepaliDate,
|
|
327
|
-
index,
|
|
328
|
-
year,
|
|
329
|
-
month,
|
|
330
|
-
firstDayOfMonth
|
|
331
|
-
)
|
|
332
|
-
? brandColor
|
|
333
|
-
: dark
|
|
334
|
-
? '#383838'
|
|
335
|
-
: '#fff',
|
|
336
|
-
}}
|
|
337
|
-
>
|
|
338
|
-
<Text
|
|
339
|
-
style={{
|
|
340
|
-
...dayTextStyle,
|
|
341
|
-
color: isToday(
|
|
342
|
-
TodayNepaliDate,
|
|
343
|
-
index,
|
|
344
|
-
year,
|
|
345
|
-
month,
|
|
346
|
-
firstDayOfMonth
|
|
347
|
-
)
|
|
348
|
-
? '#fff'
|
|
349
|
-
: dark
|
|
350
|
-
? 'white'
|
|
351
|
-
: 'black',
|
|
352
|
-
}}
|
|
353
|
-
>
|
|
354
|
-
{language === 'np'
|
|
355
|
-
? getNepaliNumber(dayItem)
|
|
356
|
-
: dayItem}
|
|
357
|
-
</Text>
|
|
358
|
-
</View>
|
|
359
|
-
) : null}
|
|
360
|
-
</TouchableOpacity>
|
|
361
|
-
);
|
|
362
|
-
})}
|
|
349
|
+
{calendarDate.map((day, index) => (
|
|
350
|
+
<DayCell
|
|
351
|
+
key={index}
|
|
352
|
+
day={day}
|
|
353
|
+
isSelectedDay={day !== null && day === selectedDay}
|
|
354
|
+
disabled={day !== null && isDateDisabled(day)}
|
|
355
|
+
onPress={handleDateClick}
|
|
356
|
+
dark={dark}
|
|
357
|
+
brandColor={brandColor}
|
|
358
|
+
language={language}
|
|
359
|
+
dayTextStyle={dayTextStyle}
|
|
360
|
+
/>
|
|
361
|
+
))}
|
|
363
362
|
</View>
|
|
363
|
+
|
|
364
364
|
</View>
|
|
365
365
|
</View>
|
|
366
366
|
</Pressable>
|
|
367
367
|
</Pressable>
|
|
368
|
+
|
|
369
|
+
{/* the year modal which will show the list of year (in scrollview) */}
|
|
370
|
+
{/* NOTE: Need to change in flatlist for performance but need to fix the responsive */}
|
|
368
371
|
<Modal
|
|
369
372
|
visible={yearModal}
|
|
370
373
|
onRequestClose={closeYearView}
|
|
@@ -383,6 +386,7 @@ const CalendarPicker = ({
|
|
|
383
386
|
>
|
|
384
387
|
<ScrollView
|
|
385
388
|
showsVerticalScrollIndicator={false}
|
|
389
|
+
ref={yearModelScrollRef}
|
|
386
390
|
contentContainerStyle={{
|
|
387
391
|
display: 'flex',
|
|
388
392
|
paddingVertical: 10,
|
|
@@ -397,7 +401,7 @@ const CalendarPicker = ({
|
|
|
397
401
|
return (
|
|
398
402
|
<TouchableOpacity
|
|
399
403
|
key={index}
|
|
400
|
-
onPress={() => handleYearClick(index +
|
|
404
|
+
onPress={() => handleYearClick(index + NEPALI_MIN_YEAR)}
|
|
401
405
|
style={{
|
|
402
406
|
paddingHorizontal: 20,
|
|
403
407
|
paddingVertical: 6,
|
|
@@ -407,7 +411,7 @@ const CalendarPicker = ({
|
|
|
407
411
|
borderRadius: 20,
|
|
408
412
|
|
|
409
413
|
backgroundColor:
|
|
410
|
-
index +
|
|
414
|
+
index + NEPALI_MIN_YEAR === year ? brandColor : '',
|
|
411
415
|
borderWidth: 0.4,
|
|
412
416
|
}}
|
|
413
417
|
>
|
|
@@ -415,7 +419,7 @@ const CalendarPicker = ({
|
|
|
415
419
|
style={{
|
|
416
420
|
fontWeight: '500',
|
|
417
421
|
color:
|
|
418
|
-
index +
|
|
422
|
+
index + NEPALI_MIN_YEAR === year
|
|
419
423
|
? 'white'
|
|
420
424
|
: dark
|
|
421
425
|
? 'white'
|
|
@@ -423,8 +427,8 @@ const CalendarPicker = ({
|
|
|
423
427
|
}}
|
|
424
428
|
>
|
|
425
429
|
{language === 'np'
|
|
426
|
-
? getNepaliNumber(index +
|
|
427
|
-
: index +
|
|
430
|
+
? getNepaliNumber(index + NEPALI_MIN_YEAR)
|
|
431
|
+
: index + NEPALI_MIN_YEAR}
|
|
428
432
|
</Text>
|
|
429
433
|
</TouchableOpacity>
|
|
430
434
|
);
|
|
@@ -466,11 +470,6 @@ const styles = StyleSheet.create({
|
|
|
466
470
|
alignItems: 'center',
|
|
467
471
|
paddingVertical: 18,
|
|
468
472
|
},
|
|
469
|
-
//WeekText: {
|
|
470
|
-
// fontWeight: 'bold',
|
|
471
|
-
// fontSize: 14,
|
|
472
|
-
// color: 'black',
|
|
473
|
-
//},
|
|
474
473
|
datesContainer: {
|
|
475
474
|
flexDirection: 'row',
|
|
476
475
|
flexWrap: 'wrap',
|
|
@@ -482,10 +481,6 @@ const styles = StyleSheet.create({
|
|
|
482
481
|
alignItems: 'center',
|
|
483
482
|
paddingVertical: 10,
|
|
484
483
|
},
|
|
485
|
-
//DayText: {
|
|
486
|
-
// fontSize: 14,
|
|
487
|
-
// fontWeight: '600',
|
|
488
|
-
//},
|
|
489
484
|
CButton: {
|
|
490
485
|
paddingHorizontal: 20,
|
|
491
486
|
paddingVertical: 10,
|
|
@@ -499,10 +494,7 @@ const styles = StyleSheet.create({
|
|
|
499
494
|
outerDateConainer: {
|
|
500
495
|
paddingHorizontal: 3,
|
|
501
496
|
},
|
|
502
|
-
|
|
503
|
-
// fontSize: 20,
|
|
504
|
-
// fontWeight: 'bold',
|
|
505
|
-
//},
|
|
497
|
+
|
|
506
498
|
// for year view modal
|
|
507
499
|
YearInnerPressable: {
|
|
508
500
|
justifyContent: 'center',
|
package/src/DayCell.tsx
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Text, TouchableOpacity, View } from 'react-native';
|
|
3
|
+
import { getNepaliNumber } from './calendar/config';
|
|
4
|
+
|
|
5
|
+
type DayCellProps = {
|
|
6
|
+
day: number | null;
|
|
7
|
+
isSelectedDay: boolean;
|
|
8
|
+
onPress: (day: number) => void;
|
|
9
|
+
dark: boolean;
|
|
10
|
+
brandColor: string;
|
|
11
|
+
language: 'np' | 'en';
|
|
12
|
+
dayTextStyle?: any;
|
|
13
|
+
disabled: boolean;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
const DayCell = React.memo(
|
|
17
|
+
({
|
|
18
|
+
day,
|
|
19
|
+
isSelectedDay,
|
|
20
|
+
onPress,
|
|
21
|
+
dark,
|
|
22
|
+
brandColor,
|
|
23
|
+
language,
|
|
24
|
+
dayTextStyle,
|
|
25
|
+
disabled,
|
|
26
|
+
}: DayCellProps) => {
|
|
27
|
+
if (!day) {
|
|
28
|
+
return <View style={{ width: '14.28%', paddingVertical: 10 }} />;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return (
|
|
32
|
+
<TouchableOpacity
|
|
33
|
+
onPress={() => !disabled && onPress(day)}
|
|
34
|
+
style={[{
|
|
35
|
+
width: '14.28%',
|
|
36
|
+
justifyContent: 'center',
|
|
37
|
+
alignItems: 'center',
|
|
38
|
+
paddingVertical: 10,
|
|
39
|
+
},
|
|
40
|
+
disabled && { opacity: 0.35 }]}
|
|
41
|
+
>
|
|
42
|
+
<View
|
|
43
|
+
style={{
|
|
44
|
+
paddingHorizontal: 6,
|
|
45
|
+
paddingVertical: 3,
|
|
46
|
+
borderRadius: 999,
|
|
47
|
+
backgroundColor: isSelectedDay
|
|
48
|
+
? brandColor
|
|
49
|
+
: dark
|
|
50
|
+
? '#383838'
|
|
51
|
+
: '#fff',
|
|
52
|
+
}}
|
|
53
|
+
>
|
|
54
|
+
<Text
|
|
55
|
+
style={[
|
|
56
|
+
dayTextStyle,
|
|
57
|
+
{
|
|
58
|
+
color: isSelectedDay ? '#fff' : dark ? '#fff' : '#000',
|
|
59
|
+
},
|
|
60
|
+
]}
|
|
61
|
+
>
|
|
62
|
+
{language === 'np' ? getNepaliNumber(day) : day}
|
|
63
|
+
</Text>
|
|
64
|
+
</View>
|
|
65
|
+
</TouchableOpacity>
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
);
|
|
69
|
+
|
|
70
|
+
export default DayCell;
|
package/src/calendar/config.ts
CHANGED
|
@@ -163,7 +163,7 @@ bs[2080] = [2080, 31, 32, 31, 32, 31, 30, 30, 30, 29, 29, 30, 30];
|
|
|
163
163
|
|
|
164
164
|
bs[2081] = [2081, 31, 32, 31, 32, 31, 30, 30, 30, 29, 30, 29, 31];
|
|
165
165
|
|
|
166
|
-
bs[2082] = [2082, 31, 31,
|
|
166
|
+
bs[2082] = [2082, 31, 31, 32, 31, 31, 31, 30, 29, 30, 29, 30, 30];
|
|
167
167
|
|
|
168
168
|
bs[2083] = [2083, 31, 31, 32, 31, 31, 31, 30, 29, 30, 29, 30, 30];
|
|
169
169
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { bs } from './config';
|
|
2
2
|
import type { DateString } from '../types';
|
|
3
|
+
import { NEPALI_MAX_YEAR, NEPALI_MIN_YEAR } from './settings';
|
|
3
4
|
|
|
4
5
|
const formatDate = (date: Date) => {
|
|
5
6
|
const year = date.getFullYear();
|
|
@@ -8,18 +9,59 @@ const formatDate = (date: Date) => {
|
|
|
8
9
|
return `${year}-${month}-${day}`;
|
|
9
10
|
};
|
|
10
11
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
}
|
|
21
|
-
|
|
12
|
+
|
|
13
|
+
// Add padart 0 if the date is day or months are denoted by single number
|
|
14
|
+
const normalizeNepaliDate = (date: string): string | null => {
|
|
15
|
+
const parts = date.split('-');
|
|
16
|
+
if (parts.length !== 3) return null;
|
|
17
|
+
|
|
18
|
+
const [y, m, d] = parts;
|
|
19
|
+
|
|
20
|
+
if (!/^\d{4}$/.test(y)) return null;
|
|
21
|
+
if (!/^\d{1,2}$/.test(m)) return null;
|
|
22
|
+
if (!/^\d{1,2}$/.test(d)) return null;
|
|
23
|
+
|
|
24
|
+
return `${y}-${m.padStart(2, '0')}-${d.padStart(2, '0')}`;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
export const validateDate = (uDate: string): true | string => {
|
|
29
|
+
|
|
30
|
+
const normalized = normalizeNepaliDate(uDate)
|
|
31
|
+
|
|
32
|
+
if (!normalized) {
|
|
33
|
+
return 'Date format must be YYYY-MM-DD';
|
|
22
34
|
}
|
|
35
|
+
|
|
36
|
+
// format check
|
|
37
|
+
if (!/^\d{4}-\d{2}-\d{2}$/.test(normalized)) {
|
|
38
|
+
return 'Date format must be YYYY-MM-DD';
|
|
39
|
+
}
|
|
40
|
+
const [yearStr, monthStr, dayStr] = normalized.split('-');
|
|
41
|
+
const year = Number(yearStr);
|
|
42
|
+
const month = Number(monthStr);
|
|
43
|
+
const day = Number(dayStr);
|
|
44
|
+
|
|
45
|
+
// Year range
|
|
46
|
+
if (year < NEPALI_MIN_YEAR || year > NEPALI_MAX_YEAR) {
|
|
47
|
+
return 'Year range must be between 2000 and 2099 (BS)';
|
|
48
|
+
}
|
|
49
|
+
// Month range
|
|
50
|
+
if (month < 1 || month > 12) {
|
|
51
|
+
return 'Month range must be between 01 and 12';
|
|
52
|
+
}
|
|
53
|
+
//Day range using BS data
|
|
54
|
+
const daysInMonth = bs?.[year]?.[month];
|
|
55
|
+
|
|
56
|
+
if (!daysInMonth) {
|
|
57
|
+
return 'Invalid Nepali calendar data';
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if (day < 1 || day > daysInMonth) {
|
|
61
|
+
return `Day range for ${year}-${monthStr} is 01 to ${daysInMonth}`;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return true;
|
|
23
65
|
};
|
|
24
66
|
|
|
25
67
|
const FindDateDifference = (date1: number, date2: number) => {
|
|
@@ -41,14 +83,14 @@ const AdToBs = (UserDate: DateString): DateString => {
|
|
|
41
83
|
|
|
42
84
|
// number of days from that reference date
|
|
43
85
|
const DateDifference = FindDateDifference(ReferenceDate, UserTimeDate);
|
|
44
|
-
let nepaliYear: number =
|
|
86
|
+
let nepaliYear: number = NEPALI_MIN_YEAR;
|
|
45
87
|
let nepaliMonth: number = 1;
|
|
46
88
|
let nepaliDay: number = 1;
|
|
47
89
|
//difference can calculate upto previous day so add 1 to get current day(Today)
|
|
48
90
|
|
|
49
91
|
let DD = DateDifference + 1;
|
|
50
92
|
|
|
51
|
-
outerLoop: for (let year =
|
|
93
|
+
outerLoop: for (let year = NEPALI_MIN_YEAR; year <= NEPALI_MAX_YEAR; year++) {
|
|
52
94
|
for (let month = 1; month <= 12; month++) {
|
|
53
95
|
if (DD <= bs[year][month]) {
|
|
54
96
|
nepaliYear = year;
|
|
@@ -76,12 +118,12 @@ const NepaliToday = (): DateString => {
|
|
|
76
118
|
new Date(formatDate(date)).getTime()
|
|
77
119
|
);
|
|
78
120
|
|
|
79
|
-
let nepaliYear: number =
|
|
121
|
+
let nepaliYear: number = NEPALI_MIN_YEAR;
|
|
80
122
|
let nepaliMonth: number = 1;
|
|
81
123
|
let nepaliDay: number = 1;
|
|
82
124
|
//difference can calculate upto previous day so add 1 to get current day(Today)
|
|
83
125
|
let DD = DateDifference + 1;
|
|
84
|
-
outerLoop: for (let year =
|
|
126
|
+
outerLoop: for (let year = NEPALI_MIN_YEAR; year <= NEPALI_MAX_YEAR; year++) {
|
|
85
127
|
for (let month = 1; month <= 12; month++) {
|
|
86
128
|
if (DD <= bs[year][month]) {
|
|
87
129
|
nepaliYear = year;
|
|
@@ -108,7 +150,7 @@ const BsToAd = (userDate: DateString): DateString => {
|
|
|
108
150
|
throw new Error('Invalid date format');
|
|
109
151
|
}
|
|
110
152
|
const [userYear, userMonth, userDay] = dateArray.map(Number);
|
|
111
|
-
if (userYear <
|
|
153
|
+
if (userYear < NEPALI_MIN_YEAR || userYear > NEPALI_MAX_YEAR) {
|
|
112
154
|
throw new Error('Year Range is 2000 to 2099');
|
|
113
155
|
}
|
|
114
156
|
if (userMonth < 1 || userMonth > 12) {
|
|
@@ -119,7 +161,7 @@ const BsToAd = (userDate: DateString): DateString => {
|
|
|
119
161
|
// throw new Error('Month out of supported range');
|
|
120
162
|
// }
|
|
121
163
|
|
|
122
|
-
for (let year =
|
|
164
|
+
for (let year = NEPALI_MIN_YEAR; year < userYear; year++) {
|
|
123
165
|
for (let month = 1; month <= 12; month++) {
|
|
124
166
|
dateDifference += bs[year][month];
|
|
125
167
|
}
|
package/src/calendar/settings.ts
CHANGED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { validateDate } from "./functions";
|
|
2
|
+
|
|
3
|
+
export const validateCalendarDates = (
|
|
4
|
+
date: string,
|
|
5
|
+
minDate: string,
|
|
6
|
+
maxDate: string
|
|
7
|
+
): true | string => {
|
|
8
|
+
// 1. Validate minDate
|
|
9
|
+
const minCheck = validateDate(minDate);
|
|
10
|
+
if (minCheck !== true) {
|
|
11
|
+
return `Invalid minDate: ${minCheck}`;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
// 2. Validate maxDate
|
|
15
|
+
const maxCheck = validateDate(maxDate);
|
|
16
|
+
if (maxCheck !== true) {
|
|
17
|
+
return `Invalid maxDate: ${maxCheck}`;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// 3. Validate user provided date
|
|
21
|
+
const initialCheck = validateDate(date);
|
|
22
|
+
if (initialCheck !== true) {
|
|
23
|
+
return `Invalid provided date: ${initialCheck}`;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// 4. Logical range validation
|
|
27
|
+
if (minDate > maxDate) {
|
|
28
|
+
return 'minDate must be less than or equal to maxDate';
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// 5. Initial date within range
|
|
32
|
+
if (date < minDate || date > maxDate) {
|
|
33
|
+
return 'Provided date must be between minDate and maxDate';
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return true;
|
|
37
|
+
};
|
package/src/index.tsx
CHANGED
package/src/types.ts
CHANGED
|
@@ -12,6 +12,8 @@ export interface CalendarPickerProps {
|
|
|
12
12
|
dayTextStyle?: TextStyle;
|
|
13
13
|
weekTextStyle?: TextStyle;
|
|
14
14
|
titleTextStyle?: TextStyle;
|
|
15
|
-
|
|
15
|
+
date?: DateString;
|
|
16
|
+
minDate?: DateString;
|
|
17
|
+
maxDate?: DateString;
|
|
16
18
|
}
|
|
17
19
|
export type DateString = string;
|