Forráskód Böngészése

new calendar component

Viktoriia 1 hónapja
szülő
commit
cbcaf7dc81

+ 2 - 1
package.json

@@ -41,6 +41,7 @@
     "@turf/turf": "^7.2.0",
     "axios": "^1.12.2",
     "better-react-native-image-viewing": "^0.2.7",
+    "dayjs": "^1.11.18",
     "dotenv": "^16.6.1",
     "expo": "^54.0.12",
     "expo-asset": "~12.0.9",
@@ -71,7 +72,6 @@
     "react-native": "0.81.4",
     "react-native-actions-sheet": "^0.9.7",
     "react-native-animated-pagination-dot": "^0.4.0",
-    "react-native-calendars": "1.1304.1",
     "react-native-collapsible-tab-view": "^8.0.1",
     "react-native-device-detection": "^0.2.1",
     "react-native-emoji-selector": "^0.2.0",
@@ -101,6 +101,7 @@
     "react-native-searchable-dropdown-kj": "^1.9.3",
     "react-native-share": "^12.2.0",
     "react-native-svg": "15.12.1",
+    "react-native-ui-datepicker": "3.0.7",
     "react-native-url-polyfill": "^2.0.0",
     "react-native-view-shot": "4.0.3",
     "react-native-walkthrough-tooltip": "^1.6.0",

+ 0 - 93
patches/react-native-calendars+1.1304.1.patch

@@ -1,93 +0,0 @@
-diff --git a/node_modules/react-native-calendars/src/calendar/day/period/index.js b/node_modules/react-native-calendars/src/calendar/day/period/index.js
-index f27db0e..434f414 100644
---- a/node_modules/react-native-calendars/src/calendar/day/period/index.js
-+++ b/node_modules/react-native-calendars/src/calendar/day/period/index.js
-@@ -87,21 +87,19 @@ const PeriodDay = (props) => {
-         return textStyle;
-     }, [marking, state]);
-     const fillerStyles = useMemo(() => {
--        const leftFillerStyle = { backgroundColor: undefined };
--        const rightFillerStyle = { backgroundColor: undefined };
-+        const leftFillerStyle = { backgroundColor: marking?.disabled ? 'transparent' : 'rgb(250, 223, 194)' };
-+        const rightFillerStyle = { backgroundColor: marking?.disabled ? 'transparent' : 'rgb(250, 223, 194)' };
-         let fillerStyle = {};
-         const start = markingStyle.startingDay;
-         const end = markingStyle.endingDay;
--        if (start && !end) {
--            rightFillerStyle.backgroundColor = markingStyle.startingDay?.backgroundColor;
-+        if (start) {
-+          leftFillerStyle.backgroundColor = markingStyle.day?.backgroundColor;
-         }
--        else if (end && !start) {
--            leftFillerStyle.backgroundColor = markingStyle.endingDay?.backgroundColor;
-+        if (end) {
-+          rightFillerStyle.backgroundColor = markingStyle.day?.backgroundColor;
-         }
--        else if (markingStyle.day) {
--            leftFillerStyle.backgroundColor = markingStyle.day?.backgroundColor;
--            rightFillerStyle.backgroundColor = markingStyle.day?.backgroundColor;
--            fillerStyle = { backgroundColor: markingStyle.day?.backgroundColor };
-+        if (!start && !end && markingStyle.day) {
-+          fillerStyle = { backgroundColor: markingStyle.day?.backgroundColor };
-         }
-         return { leftFillerStyle, rightFillerStyle, fillerStyle };
-     }, [marking]);
-diff --git a/node_modules/react-native-calendars/src/calendar/day/period/style.js b/node_modules/react-native-calendars/src/calendar/day/period/style.js
-index 51e2082..d82f5eb 100644
---- a/node_modules/react-native-calendars/src/calendar/day/period/style.js
-+++ b/node_modules/react-native-calendars/src/calendar/day/period/style.js
-@@ -10,7 +10,7 @@ export default function styleConstructor(theme = {}) {
-             marginLeft: -1
-         },
-         base: {
--            width: 38,
-+            width: FILLER_HEIGHT,
-             height: FILLER_HEIGHT,
-             alignItems: 'center',
-             justifyContent: 'center'
-@@ -44,7 +44,10 @@ export default function styleConstructor(theme = {}) {
-             bottom: 3
-         },
-         today: {
--            backgroundColor: appStyle.todayBackgroundColor
-+            backgroundColor: appStyle.todayBackgroundColor,
-+            borderColor: '#ED9334',
-+            borderWidth: 1,
-+            borderRadius: 17
-         },
-         todayText: {
-             fontWeight: '500',
-diff --git a/node_modules/react-native-calendars/src/calendar/index.js b/node_modules/react-native-calendars/src/calendar/index.js
-index 6f46e8a..de8ce86 100644
---- a/node_modules/react-native-calendars/src/calendar/index.js
-+++ b/node_modules/react-native-calendars/src/calendar/index.js
-@@ -2,7 +2,7 @@ import PropTypes from 'prop-types';
- import XDate from 'xdate';
- import isEmpty from 'lodash/isEmpty';
- import React, { useRef, useState, useEffect, useCallback, useMemo } from 'react';
--import { View } from 'react-native';
-+import { View, PanResponder } from 'react-native';
- // @ts-expect-error
- import GestureRecognizer, { swipeDirections } from 'react-native-swipe-gestures';
- import constants from '../commons/constants';
-@@ -137,6 +137,11 @@ const Calendar = (props) => {
-         }
-         return false;
-     }, [currentMonth, displayLoadingIndicator, markedDates]);
-+    const panResponder = useRef(
-+      PanResponder.create({
-+        onStartShouldSetPanResponder: () => true,
-+      })
-+    ).current;
-     const renderHeader = () => {
-         const headerProps = extractHeaderProps(props);
-         const ref = customHeader ? undefined : header;
-@@ -150,7 +155,7 @@ const Calendar = (props) => {
-     };
-     const gestureProps = enableSwipeMonths ? swipeProps : undefined;
-     return (<GestureComponent {...gestureProps}>
--      <View style={[style.current.container, propsStyle]} testID={testID} accessibilityElementsHidden={accessibilityElementsHidden} // iOS
-+      <View {...panResponder.panHandlers} style={[style.current.container, propsStyle]} testID={testID} accessibilityElementsHidden={accessibilityElementsHidden} // iOS
-      importantForAccessibility={importantForAccessibility} // Android
-     >
-         {renderHeader()}

+ 165 - 111
src/components/Calendars/RangeCalendar/index.tsx

@@ -1,11 +1,22 @@
 import React, { useEffect, useState } from 'react';
 import { View } from 'react-native';
-import moment from 'moment';
 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 { Colors } from '../../../theme';
-import { Calendar } from 'react-native-calendars';
 import { Button } from 'src/components/Button';
 import { ButtonVariants } from 'src/types/components';
 
@@ -28,135 +39,83 @@ export default function RangeCalendar({
 }) {
   const [selectedStartDate, setSelectedStartDate] = 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(() => {
     if (selectedDate) {
       setSelectedStartDate(selectedDate);
+      setSingleDate(dayjs(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) {
-      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) {
-      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 = () => {
     closeModal();
     setSelectedStartDate(null);
     setSelectedEndDate(null);
+    setStartDate(undefined);
+    setEndDate(undefined);
+    setSingleDate(undefined);
   };
 
   const handleClose = () => {
     closeModal(selectedStartDate, selectedEndDate);
     setSelectedStartDate(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 (
     <Modal
       visibleInPercent={'auto'}
@@ -165,19 +124,114 @@ export default function RangeCalendar({
       headerTitle={allowRangeSelection ? 'Select Dates' : 'Select Date'}
     >
       <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 style={styles.modalFooter}>