|
@@ -1,11 +1,22 @@
|
|
|
import React, { useEffect, useState } from 'react';
|
|
import React, { useEffect, useState } from 'react';
|
|
|
import { View } from 'react-native';
|
|
import { View } from 'react-native';
|
|
|
-import moment from 'moment';
|
|
|
|
|
import { Modal } from '../../Modal';
|
|
import { Modal } from '../../Modal';
|
|
|
|
|
+import DateTimePicker, { DateType } from 'react-native-ui-datepicker';
|
|
|
|
|
+import dayjs from 'dayjs';
|
|
|
|
|
+import 'dayjs/locale/en';
|
|
|
|
|
+import calendar from 'dayjs/plugin/calendar';
|
|
|
|
|
+import updateLocale from 'dayjs/plugin/updateLocale';
|
|
|
|
|
+import localeData from 'dayjs/plugin/localeData';
|
|
|
|
|
+import customParseFormat from 'dayjs/plugin/customParseFormat';
|
|
|
|
|
+
|
|
|
|
|
+dayjs.locale('en');
|
|
|
|
|
+dayjs.extend(calendar);
|
|
|
|
|
+dayjs.extend(updateLocale);
|
|
|
|
|
+dayjs.extend(localeData);
|
|
|
|
|
+dayjs.extend(customParseFormat);
|
|
|
|
|
|
|
|
import { styles } from './style';
|
|
import { styles } from './style';
|
|
|
import { Colors } from '../../../theme';
|
|
import { Colors } from '../../../theme';
|
|
|
-import { Calendar } from 'react-native-calendars';
|
|
|
|
|
import { Button } from 'src/components/Button';
|
|
import { Button } from 'src/components/Button';
|
|
|
import { ButtonVariants } from 'src/types/components';
|
|
import { ButtonVariants } from 'src/types/components';
|
|
|
|
|
|
|
@@ -28,135 +39,83 @@ export default function RangeCalendar({
|
|
|
}) {
|
|
}) {
|
|
|
const [selectedStartDate, setSelectedStartDate] = useState<string | null>(null);
|
|
const [selectedStartDate, setSelectedStartDate] = useState<string | null>(null);
|
|
|
const [selectedEndDate, setSelectedEndDate] = useState<string | null>(null);
|
|
const [selectedEndDate, setSelectedEndDate] = useState<string | null>(null);
|
|
|
|
|
+ const [singleDate, setSingleDate] = useState<DateType>(undefined);
|
|
|
|
|
+ const [startDate, setStartDate] = useState<DateType>(undefined);
|
|
|
|
|
+ const [endDate, setEndDate] = useState<DateType>(undefined);
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
useEffect(() => {
|
|
|
if (selectedDate) {
|
|
if (selectedDate) {
|
|
|
setSelectedStartDate(selectedDate);
|
|
setSelectedStartDate(selectedDate);
|
|
|
|
|
+ setSingleDate(dayjs(selectedDate));
|
|
|
}
|
|
}
|
|
|
}, [selectedDate]);
|
|
}, [selectedDate]);
|
|
|
|
|
|
|
|
- const customThemeStyles = {
|
|
|
|
|
- textSectionTitleColor: Colors.ORANGE,
|
|
|
|
|
- todayTextColor: Colors.DARK_BLUE,
|
|
|
|
|
- dayTextColor: Colors.DARK_BLUE,
|
|
|
|
|
- textDisabledColor: Colors.LIGHT_GRAY,
|
|
|
|
|
- dotColor: Colors.DARK_BLUE,
|
|
|
|
|
- arrowColor: Colors.DARK_BLUE,
|
|
|
|
|
- monthTextColor: Colors.DARK_BLUE,
|
|
|
|
|
- indicatorColor: Colors.DARK_BLUE,
|
|
|
|
|
- textDayFontWeight: 'normal',
|
|
|
|
|
- textMonthFontWeight: 'bold',
|
|
|
|
|
- textDayHeaderFontWeight: 'bold',
|
|
|
|
|
- textDayFontSize: 14,
|
|
|
|
|
- textMonthFontSize: 14,
|
|
|
|
|
- textDayHeaderFontSize: 12,
|
|
|
|
|
- selectedDayBackgroundColor: Colors.ORANGE,
|
|
|
|
|
- 'stylesheet.calendar.header': {
|
|
|
|
|
- header: styles.calendarHeader
|
|
|
|
|
- }
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
- const onDayPress = (day: any) => {
|
|
|
|
|
- if (!allowRangeSelection) {
|
|
|
|
|
- setSelectedStartDate(day.dateString);
|
|
|
|
|
- return;
|
|
|
|
|
- }
|
|
|
|
|
- if (!selectedStartDate || (selectedStartDate && selectedEndDate)) {
|
|
|
|
|
- setSelectedStartDate(day.dateString);
|
|
|
|
|
- setSelectedEndDate(null);
|
|
|
|
|
- } else if (!selectedEndDate) {
|
|
|
|
|
- if (day.dateString < selectedStartDate) {
|
|
|
|
|
- setSelectedEndDate(selectedStartDate);
|
|
|
|
|
- setSelectedStartDate(day.dateString);
|
|
|
|
|
- } else {
|
|
|
|
|
- setSelectedEndDate(day.dateString);
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- };
|
|
|
|
|
|
|
+ const getDisabledDates = (date: DateType) => {
|
|
|
|
|
+ const dateString = dayjs(date).format('YYYY-MM-DD');
|
|
|
|
|
|
|
|
- const markedDates = (() => {
|
|
|
|
|
- const marked: { [key: string]: any } = {};
|
|
|
|
|
- let start = selectedStartDate as unknown as string;
|
|
|
|
|
- let end = selectedEndDate as unknown as string;
|
|
|
|
|
- if (selectedDate && !selectedStartDate) {
|
|
|
|
|
- marked[selectedDate] = {
|
|
|
|
|
- selected: true,
|
|
|
|
|
- startingDay: true,
|
|
|
|
|
- endingDay: true,
|
|
|
|
|
- color: Colors.ORANGE,
|
|
|
|
|
- textColor: 'white'
|
|
|
|
|
- };
|
|
|
|
|
- }
|
|
|
|
|
if (disableFutureDates) {
|
|
if (disableFutureDates) {
|
|
|
- const today = moment().add(1, 'day');
|
|
|
|
|
- const lastDay = moment().add(2, 'years');
|
|
|
|
|
- while (today.isBefore(lastDay, 'day')) {
|
|
|
|
|
- const dateString = today.format('YYYY-MM-DD');
|
|
|
|
|
- if (!marked[dateString]) {
|
|
|
|
|
- marked[dateString] = { disableTouchEvent: true, disabled: true };
|
|
|
|
|
- }
|
|
|
|
|
- today.add(1, 'day');
|
|
|
|
|
|
|
+ if (dayjs(date).isAfter(dayjs(), 'day')) {
|
|
|
|
|
+ return true;
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
if (disablePastDates) {
|
|
if (disablePastDates) {
|
|
|
- const today = moment().subtract(1, 'day');
|
|
|
|
|
- const firstDay = moment().subtract(2, 'years');
|
|
|
|
|
- while (today.isAfter(firstDay, 'day')) {
|
|
|
|
|
- const dateString = today.format('YYYY-MM-DD');
|
|
|
|
|
- if (!marked[dateString]) {
|
|
|
|
|
- marked[dateString] = { disableTouchEvent: true, disabled: true };
|
|
|
|
|
- }
|
|
|
|
|
- today.subtract(1, 'day');
|
|
|
|
|
|
|
+ if (dayjs(date).isBefore(dayjs(), 'day')) {
|
|
|
|
|
+ return true;
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
- if (highlightedDates) {
|
|
|
|
|
- const datesSet = new Set(highlightedDates);
|
|
|
|
|
|
|
|
|
|
- const startDateMoment = moment(highlightedDates[0]);
|
|
|
|
|
- const endDateMoment = moment(highlightedDates[highlightedDates.length - 1]);
|
|
|
|
|
|
|
+ if (highlightedDates && highlightedDates.length > 0) {
|
|
|
|
|
+ return !highlightedDates.includes(dateString);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return false;
|
|
|
|
|
+ };
|
|
|
|
|
|
|
|
- for (let m = moment(startDateMoment); m.diff(endDateMoment, 'days') <= 0; m.add(1, 'days')) {
|
|
|
|
|
- const dateString = m.format('YYYY-MM-DD');
|
|
|
|
|
- if (!datesSet.has(dateString)) {
|
|
|
|
|
- marked[dateString] = { disableTouchEvent: true, disabled: true };
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ const handleDateChange = (params: any) => {
|
|
|
|
|
+ if (allowRangeSelection) {
|
|
|
|
|
+ setStartDate(params.startDate);
|
|
|
|
|
+ setEndDate(params.endDate);
|
|
|
|
|
+ if (params.startDate) {
|
|
|
|
|
+ setSelectedStartDate(dayjs(params.startDate).format('YYYY-MM-DD'));
|
|
|
}
|
|
}
|
|
|
- }
|
|
|
|
|
- if (start && end) {
|
|
|
|
|
- marked[start] = { startingDay: true, color: Colors.ORANGE, textColor: 'white' };
|
|
|
|
|
- let day = start;
|
|
|
|
|
- while (day < end) {
|
|
|
|
|
- day = moment(day).add(1, 'days').format('YYYY-MM-DD');
|
|
|
|
|
- if (day === end) {
|
|
|
|
|
- marked[day] = { endingDay: true, color: Colors.ORANGE, textColor: 'white' };
|
|
|
|
|
- } else {
|
|
|
|
|
- marked[day] = { color: 'transparent', textColor: Colors.DARK_BLUE };
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ if (params.endDate) {
|
|
|
|
|
+ setSelectedEndDate(dayjs(params.endDate).format('YYYY-MM-DD'));
|
|
|
|
|
+ } else {
|
|
|
|
|
+ setSelectedEndDate(null);
|
|
|
}
|
|
}
|
|
|
- } else if (start) {
|
|
|
|
|
- marked[start] = {
|
|
|
|
|
- selected: true,
|
|
|
|
|
- startingDay: true,
|
|
|
|
|
- endingDay: true,
|
|
|
|
|
- color: Colors.ORANGE,
|
|
|
|
|
- textColor: 'white'
|
|
|
|
|
- };
|
|
|
|
|
|
|
+ } else {
|
|
|
|
|
+ setSingleDate(params.date);
|
|
|
|
|
+ setSelectedStartDate(dayjs(params.date).format('YYYY-MM-DD'));
|
|
|
|
|
+ setSelectedEndDate(null);
|
|
|
}
|
|
}
|
|
|
- return marked;
|
|
|
|
|
- })();
|
|
|
|
|
|
|
+ };
|
|
|
|
|
|
|
|
const resetSelections = () => {
|
|
const resetSelections = () => {
|
|
|
closeModal();
|
|
closeModal();
|
|
|
setSelectedStartDate(null);
|
|
setSelectedStartDate(null);
|
|
|
setSelectedEndDate(null);
|
|
setSelectedEndDate(null);
|
|
|
|
|
+ setStartDate(undefined);
|
|
|
|
|
+ setEndDate(undefined);
|
|
|
|
|
+ setSingleDate(undefined);
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
const handleClose = () => {
|
|
const handleClose = () => {
|
|
|
closeModal(selectedStartDate, selectedEndDate);
|
|
closeModal(selectedStartDate, selectedEndDate);
|
|
|
setSelectedStartDate(null);
|
|
setSelectedStartDate(null);
|
|
|
setSelectedEndDate(null);
|
|
setSelectedEndDate(null);
|
|
|
|
|
+ setStartDate(undefined);
|
|
|
|
|
+ setEndDate(undefined);
|
|
|
|
|
+ setSingleDate(undefined);
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
|
|
+ const minDate =
|
|
|
|
|
+ highlightedDates && highlightedDates.length > 0 ? dayjs(highlightedDates[0]) : undefined;
|
|
|
|
|
+ const maxDate =
|
|
|
|
|
+ highlightedDates && highlightedDates.length > 0
|
|
|
|
|
+ ? dayjs(highlightedDates[highlightedDates.length - 1])
|
|
|
|
|
+ : undefined;
|
|
|
|
|
+
|
|
|
return (
|
|
return (
|
|
|
<Modal
|
|
<Modal
|
|
|
visibleInPercent={'auto'}
|
|
visibleInPercent={'auto'}
|
|
@@ -165,19 +124,114 @@ export default function RangeCalendar({
|
|
|
headerTitle={allowRangeSelection ? 'Select Dates' : 'Select Date'}
|
|
headerTitle={allowRangeSelection ? 'Select Dates' : 'Select Date'}
|
|
|
>
|
|
>
|
|
|
<View style={styles.modalContent}>
|
|
<View style={styles.modalContent}>
|
|
|
- <Calendar
|
|
|
|
|
- monthFormat="MMMM yyyy"
|
|
|
|
|
- onDayPress={onDayPress}
|
|
|
|
|
- markingType={'period'}
|
|
|
|
|
- markedDates={markedDates}
|
|
|
|
|
- enableSwipeMonths={true}
|
|
|
|
|
- firstDay={1}
|
|
|
|
|
- theme={{
|
|
|
|
|
- ...customThemeStyles
|
|
|
|
|
|
|
+ <DateTimePicker
|
|
|
|
|
+ mode={allowRangeSelection ? 'range' : 'single'}
|
|
|
|
|
+ date={singleDate}
|
|
|
|
|
+ startDate={startDate}
|
|
|
|
|
+ endDate={endDate}
|
|
|
|
|
+ onChange={handleDateChange}
|
|
|
|
|
+ minDate={minDate}
|
|
|
|
|
+ maxDate={maxDate}
|
|
|
|
|
+ disabledDates={getDisabledDates}
|
|
|
|
|
+ firstDayOfWeek={1}
|
|
|
|
|
+ timePicker={false}
|
|
|
|
|
+ showOutsideDays={true}
|
|
|
|
|
+ weekdaysFormat={'short'}
|
|
|
|
|
+ styles={{
|
|
|
|
|
+ header: {
|
|
|
|
|
+ paddingBottom: 10
|
|
|
|
|
+ },
|
|
|
|
|
+ month_selector_label: {
|
|
|
|
|
+ color: Colors.DARK_BLUE,
|
|
|
|
|
+ fontWeight: 'bold',
|
|
|
|
|
+ fontSize: 15
|
|
|
|
|
+ },
|
|
|
|
|
+ year_selector_label: {
|
|
|
|
|
+ color: Colors.DARK_BLUE,
|
|
|
|
|
+ fontWeight: 'bold',
|
|
|
|
|
+ fontSize: 15
|
|
|
|
|
+ },
|
|
|
|
|
+ button_prev: {},
|
|
|
|
|
+ button_next: {},
|
|
|
|
|
+ weekday_label: {
|
|
|
|
|
+ color: Colors.DARK_BLUE,
|
|
|
|
|
+ fontWeight: 'bold',
|
|
|
|
|
+ fontSize: 12
|
|
|
|
|
+ },
|
|
|
|
|
+ days: {},
|
|
|
|
|
+ day_cell: {},
|
|
|
|
|
+ day: {},
|
|
|
|
|
+ day_label: {
|
|
|
|
|
+ color: Colors.DARK_BLUE,
|
|
|
|
|
+ fontSize: 14,
|
|
|
|
|
+ fontWeight: 'normal'
|
|
|
|
|
+ },
|
|
|
|
|
+ today: {
|
|
|
|
|
+ borderWidth: 1,
|
|
|
|
|
+ borderRadius: 23,
|
|
|
|
|
+ width: 46,
|
|
|
|
|
+ height: 46,
|
|
|
|
|
+ maxHeight: 46,
|
|
|
|
|
+ borderColor: Colors.ORANGE
|
|
|
|
|
+ },
|
|
|
|
|
+ today_label: {
|
|
|
|
|
+ color: Colors.DARK_BLUE,
|
|
|
|
|
+ fontWeight: '500'
|
|
|
|
|
+ },
|
|
|
|
|
+ selected: {
|
|
|
|
|
+ backgroundColor: Colors.ORANGE,
|
|
|
|
|
+ borderRadius: 23,
|
|
|
|
|
+ width: 46,
|
|
|
|
|
+ height: 46,
|
|
|
|
|
+ maxHeight: 46,
|
|
|
|
|
+ marginVertical: 'auto',
|
|
|
|
|
+ alignItems: 'center',
|
|
|
|
|
+ justifyContent: 'center'
|
|
|
|
|
+ },
|
|
|
|
|
+ selected_label: {
|
|
|
|
|
+ color: 'white',
|
|
|
|
|
+ fontWeight: '500'
|
|
|
|
|
+ },
|
|
|
|
|
+ range_start: {
|
|
|
|
|
+ backgroundColor: Colors.ORANGE,
|
|
|
|
|
+ borderRadius: 23,
|
|
|
|
|
+ width: 46,
|
|
|
|
|
+ height: 46,
|
|
|
|
|
+ alignItems: 'center',
|
|
|
|
|
+ justifyContent: 'center'
|
|
|
|
|
+ },
|
|
|
|
|
+ range_start_label: {
|
|
|
|
|
+ color: 'white'
|
|
|
|
|
+ },
|
|
|
|
|
+ range_end: {
|
|
|
|
|
+ backgroundColor: Colors.ORANGE,
|
|
|
|
|
+ borderRadius: 23,
|
|
|
|
|
+ width: 46,
|
|
|
|
|
+ height: 46,
|
|
|
|
|
+ alignItems: 'center',
|
|
|
|
|
+ justifyContent: 'center'
|
|
|
|
|
+ },
|
|
|
|
|
+ range_end_label: {
|
|
|
|
|
+ color: 'white'
|
|
|
|
|
+ },
|
|
|
|
|
+ range_middle_label: {
|
|
|
|
|
+ color: Colors.DARK_BLUE,
|
|
|
|
|
+ fontWeight: '500'
|
|
|
|
|
+ },
|
|
|
|
|
+ range_fill: {
|
|
|
|
|
+ backgroundColor: Colors.ORANGE,
|
|
|
|
|
+ opacity: 0.2
|
|
|
|
|
+ },
|
|
|
|
|
+ disabled: {
|
|
|
|
|
+ opacity: 0.3
|
|
|
|
|
+ },
|
|
|
|
|
+ disabled_label: {
|
|
|
|
|
+ color: Colors.TEXT_GRAY
|
|
|
|
|
+ },
|
|
|
|
|
+ outside_label: {
|
|
|
|
|
+ color: Colors.LIGHT_GRAY
|
|
|
|
|
+ }
|
|
|
}}
|
|
}}
|
|
|
- minDate={highlightedDates ? highlightedDates[0] : undefined}
|
|
|
|
|
- maxDate={highlightedDates ? highlightedDates[highlightedDates.length - 1] : undefined}
|
|
|
|
|
- current={selectedDate}
|
|
|
|
|
/>
|
|
/>
|
|
|
</View>
|
|
</View>
|
|
|
<View style={styles.modalFooter}>
|
|
<View style={styles.modalFooter}>
|