Browse Source

trips2025

Viktoriia 1 week ago
parent
commit
73fc1a00e4

+ 12 - 0
Route.tsx

@@ -112,6 +112,9 @@ import EditCountryDataScreen from 'src/screens/InAppScreens/TravelsScreen/EditCo
 import CreateSharedTripScreen from 'src/screens/InAppScreens/TravelsScreen/CreateSharedTrip';
 import EditNmDataScreen from 'src/screens/InAppScreens/TravelsScreen/EditNmDataScreen';
 import { testConnectionSpeed } from 'src/database/speedService';
+import Trips2025Screen from 'src/screens/InAppScreens/TravelsScreen/Trips2025Screen';
+import AddNewTrip2025Screen from 'src/screens/InAppScreens/TravelsScreen/AddNewTrip2025Screen';
+import AddRegionsNewScreen from 'src/screens/InAppScreens/TravelsScreen/AddRegionsNewScreen';
 
 enableScreens();
 
@@ -360,7 +363,16 @@ const Route = () => {
             <ScreenStack.Screen name={NAVIGATION_PAGES.ADD_PHOTO} component={AddPhotoScreen} />
             <ScreenStack.Screen name={NAVIGATION_PAGES.TRIPS} component={TripsScreen} />
             <ScreenStack.Screen name={NAVIGATION_PAGES.ADD_TRIP} component={AddNewTripScreen} />
+            <ScreenStack.Screen name={NAVIGATION_PAGES.TRIPS_2025} component={Trips2025Screen} />
+            <ScreenStack.Screen
+              name={NAVIGATION_PAGES.ADD_TRIP_2025}
+              component={AddNewTrip2025Screen}
+            />
             <ScreenStack.Screen name={NAVIGATION_PAGES.ADD_REGIONS} component={AddRegionsScreen} />
+            <ScreenStack.Screen
+              name={NAVIGATION_PAGES.ADD_REGIONS_NEW}
+              component={AddRegionsNewScreen}
+            />
             <ScreenStack.Screen name={NAVIGATION_PAGES.COUNTRIES} component={CountriesScreen} />
             <ScreenStack.Screen name={NAVIGATION_PAGES.REGIONS} component={RegionsScreen} />
             <ScreenStack.Screen name={NAVIGATION_PAGES.DARE} component={DareScreen} />

+ 1 - 1
assets/icons/calendar.svg

@@ -1,3 +1,3 @@
 <svg width="18" height="20" viewBox="0 0 18 20" fill="none" xmlns="http://www.w3.org/2000/svg">
-<path fill-rule="evenodd" clip-rule="evenodd" d="M13.5 0.909091C13.5 0.407014 13.0971 0 12.6 0C12.1029 0 11.7 0.407014 11.7 0.909091V1.81818H6.3V0.909091C6.3 0.407014 5.89706 0 5.4 0C4.90294 0 4.5 0.407014 4.5 0.909091V1.81818H2.7C1.20883 1.81818 0 3.03922 0 4.54545V8.18182V17.2727C0 18.779 1.20883 20 2.7 20H15.3C16.7912 20 18 18.779 18 17.2727V8.18182V4.54545C18 3.03922 16.7912 1.81818 15.3 1.81818H13.5V0.909091ZM16.2 7.27273V4.54545C16.2 4.04338 15.7971 3.63636 15.3 3.63636H13.5V4.54545C13.5 5.04753 13.0971 5.45455 12.6 5.45455C12.1029 5.45455 11.7 5.04753 11.7 4.54545V3.63636H6.3V4.54545C6.3 5.04753 5.89706 5.45455 5.4 5.45455C4.90294 5.45455 4.5 5.04753 4.5 4.54545V3.63636H2.7C2.20294 3.63636 1.8 4.04338 1.8 4.54545V7.27273H16.2ZM1.8 9.09091H16.2V17.2727C16.2 17.7748 15.7971 18.1818 15.3 18.1818H2.7C2.20294 18.1818 1.8 17.7748 1.8 17.2727V9.09091Z" fill="#C8C8C8"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M13.5 0.909091C13.5 0.407014 13.0971 0 12.6 0C12.1029 0 11.7 0.407014 11.7 0.909091V1.81818H6.3V0.909091C6.3 0.407014 5.89706 0 5.4 0C4.90294 0 4.5 0.407014 4.5 0.909091V1.81818H2.7C1.20883 1.81818 0 3.03922 0 4.54545V8.18182V17.2727C0 18.779 1.20883 20 2.7 20H15.3C16.7912 20 18 18.779 18 17.2727V8.18182V4.54545C18 3.03922 16.7912 1.81818 15.3 1.81818H13.5V0.909091ZM16.2 7.27273V4.54545C16.2 4.04338 15.7971 3.63636 15.3 3.63636H13.5V4.54545C13.5 5.04753 13.0971 5.45455 12.6 5.45455C12.1029 5.45455 11.7 5.04753 11.7 4.54545V3.63636H6.3V4.54545C6.3 5.04753 5.89706 5.45455 5.4 5.45455C4.90294 5.45455 4.5 5.04753 4.5 4.54545V3.63636H2.7C2.20294 3.63636 1.8 4.04338 1.8 4.54545V7.27273H16.2ZM1.8 9.09091H16.2V17.2727C16.2 17.7748 15.7971 18.1818 15.3 18.1818H2.7C2.20294 18.1818 1.8 17.7748 1.8 17.2727V9.09091Z"/>
 </svg>

+ 2 - 1
src/components/Calendar/InputDatePicker/index.tsx

@@ -7,6 +7,7 @@ import { Button } from '../../Button';
 import SpinnerDatePicker from '../SpinnerDatePicker';
 
 import CalendarIcon from '../../../../assets/icons/calendar.svg';
+import { Colors } from 'src/theme';
 
 type Props = {
   selectedDate?: (date: Date) => void;
@@ -36,7 +37,7 @@ export const InputDatePicker: FC<Props> = ({
   return (
     <View>
       <Input
-        icon={<CalendarIcon />}
+        icon={<CalendarIcon fill={Colors.LIGHT_GRAY} />}
         header={'Date of birth'}
         value={new Date(spinnerSelectedDate).toLocaleDateString()}
         isFocused={(b) => setVisible(b)}

+ 34 - 12
src/components/Calendars/RangeCalendar/index.tsx

@@ -28,7 +28,11 @@ export default function RangeCalendar({
   disableFutureDates = false,
   disablePastDates = false,
   highlightedDates,
-  selectedDate
+  selectedDate,
+  minDate: externalMinDate,
+  maxDate: externalMaxDate,
+  initialStartDate,
+  initialEndDate
 }: {
   isModalVisible: boolean;
   closeModal: (startDate?: string | null, endDate?: string | null) => void;
@@ -37,6 +41,10 @@ export default function RangeCalendar({
   disablePastDates?: boolean;
   highlightedDates?: string[];
   selectedDate?: string;
+  minDate?: string | Date | dayjs.Dayjs;
+  maxDate?: string | Date | dayjs.Dayjs;
+  initialStartDate?: string | null;
+  initialEndDate?: string | null;
 }) {
   const [selectedStartDate, setSelectedStartDate] = useState<string | null>(null);
   const [selectedEndDate, setSelectedEndDate] = useState<string | null>(null);
@@ -44,12 +52,33 @@ export default function RangeCalendar({
   const [startDate, setStartDate] = useState<DateType>(undefined);
   const [endDate, setEndDate] = useState<DateType>(undefined);
 
+  const computedMinDate = externalMinDate
+    ? dayjs(externalMinDate)
+    : highlightedDates && highlightedDates.length > 0
+      ? dayjs(highlightedDates[0])
+      : undefined;
+
+  const computedMaxDate = externalMaxDate
+    ? dayjs(externalMaxDate)
+    : highlightedDates && highlightedDates.length > 0
+      ? dayjs(highlightedDates[highlightedDates.length - 1])
+      : undefined;
+
   useEffect(() => {
-    if (selectedDate) {
+    if (allowRangeSelection) {
+      if (initialStartDate) {
+        setSelectedStartDate(initialStartDate);
+        setStartDate(dayjs(initialStartDate));
+      }
+      if (initialEndDate) {
+        setSelectedEndDate(initialEndDate);
+        setEndDate(dayjs(initialEndDate));
+      }
+    } else if (selectedDate) {
       setSelectedStartDate(selectedDate);
       setSingleDate(dayjs(selectedDate));
     }
-  }, [selectedDate]);
+  }, [initialStartDate, initialEndDate, selectedDate, allowRangeSelection]);
 
   const getDisabledDates = (date: DateType) => {
     const dateString = dayjs(date).format('YYYY-MM-DD');
@@ -110,13 +139,6 @@ export default function RangeCalendar({
     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'}
@@ -131,8 +153,8 @@ export default function RangeCalendar({
           startDate={startDate}
           endDate={endDate}
           onChange={handleDateChange}
-          minDate={minDate}
-          maxDate={maxDate}
+          minDate={computedMinDate}
+          maxDate={computedMaxDate}
           disabledDates={getDisabledDates}
           firstDayOfWeek={1}
           timePicker={false}

+ 627 - 0
src/screens/InAppScreens/TravelsScreen/AddNewTrip2025Screen/index.tsx

@@ -0,0 +1,627 @@
+import React, { useEffect, useState } from 'react';
+import { View, Text, TouchableOpacity, ScrollView, Alert } from 'react-native';
+import { useNavigation } from '@react-navigation/native';
+import moment from 'moment';
+
+import { PageWrapper, Header, Input, WarningModal } from 'src/components';
+import RegionItem from '../Components/RegionItemNew';
+import RangeCalendar from 'src/components/Calendars/RangeCalendar';
+
+import { StoreType, storage } from 'src/storage';
+import { Colors } from 'src/theme';
+import { NAVIGATION_PAGES } from 'src/types';
+import { RegionAddData } from '../utils/types';
+import {
+  useGetTripQuery,
+  usePostDeleteTripMutation,
+  usePostUpdateTripMutation,
+  usePostSetNewTripMutation
+} from '@api/trips';
+import { styles } from './styles';
+
+import { ActivityIndicator } from 'react-native-paper';
+
+interface DateValue {
+  year: number | null;
+  month: number | null;
+  day: number | null;
+}
+
+interface RegionWithDates extends RegionAddData {
+  visitStartDate?: DateValue | null;
+  visitEndDate?: DateValue | null;
+  year_from?: number;
+  year_to?: number;
+  month_from?: number;
+  month_to?: number;
+  day_from?: number | null;
+  day_to?: number | null;
+}
+
+const AddNewTripScreen = ({ route }: { route: any }) => {
+  const editTripId = route.params?.editTripId ?? null;
+  const token = storage.get('token', StoreType.STRING) as string;
+  const { data: editData } = useGetTripQuery(token, editTripId, Boolean(editTripId));
+  const navigation = useNavigation();
+  const [description, setDescription] = useState<string>('');
+  const [regions, setRegions] = useState<RegionWithDates[] | null>(null);
+  const [disabled, setDisabled] = useState(true);
+  const [isLoading, setIsLoading] = useState<string | null>(null);
+  const [isWarningModalVisible, setIsWarningModalVisible] = useState(false);
+
+  const [pendingDelete, setPendingDelete] = useState(false);
+
+  const [calendarVisibleForIndex, setCalendarVisibleForIndex] = useState<number | null>(null);
+  const [calendarMinDate, setCalendarMinDate] = useState<string | undefined>(undefined);
+  const [calendarMaxDate, setCalendarMaxDate] = useState<string | undefined>(undefined);
+
+  const [regionErrors, setRegionErrors] = useState<{ [index: number]: string }>({});
+
+  const { mutate: saveNewTrip } = usePostSetNewTripMutation();
+  const { mutate: updateTrip } = usePostUpdateTripMutation();
+  const { mutate: deleteTrip } = usePostDeleteTripMutation();
+
+  const autoFillAfterAppend = (list: RegionWithDates[]) => {
+    if (!list || list.length === 0) return list;
+
+    const updated = [...list];
+
+    let lastWithDateIndex: number | null = null;
+    for (let i = updated.length - 1; i >= 0; i--) {
+      const r = updated[i];
+      if (
+        r.visitStartDate?.year &&
+        r.visitStartDate?.month &&
+        r.visitStartDate?.day &&
+        r.visitEndDate?.year &&
+        r.visitEndDate?.month &&
+        r.visitEndDate?.day
+      ) {
+        lastWithDateIndex = i;
+        break;
+      }
+    }
+
+    if (lastWithDateIndex === null) return updated;
+
+    const lastDate: DateValue = updated[lastWithDateIndex].visitEndDate as DateValue;
+
+    for (let i = lastWithDateIndex + 1; i < updated.length; i++) {
+      const r = updated[i];
+      const hasStart = !!(
+        r.visitStartDate?.year &&
+        r.visitStartDate?.month &&
+        r.visitStartDate?.day
+      );
+      const hasEnd = !!(r.visitEndDate?.year && r.visitEndDate?.month && r.visitEndDate?.day);
+
+      if (!hasStart || !hasEnd) {
+        updated[i] = {
+          ...r,
+          visitStartDate: lastDate,
+          visitEndDate: lastDate
+        };
+        break;
+      }
+    }
+
+    return updated;
+  };
+
+  useEffect(() => {
+    if (route.params?.regionsToSave) {
+      const filled = autoFillAfterAppend(route.params.regionsToSave);
+
+      setRegions(filled);
+    }
+  }, [route.params?.regionsToSave]);
+
+  function extractNumberAndExtension(path: string | null) {
+    if (!path) return null;
+    const slashIndex = path.lastIndexOf('/');
+    return path.substring(slashIndex + 1);
+  }
+
+  useEffect(() => {
+    if (editData && editData.trip) {
+      setDescription(editData.trip.description);
+      setRegions(
+        editData.trip.regions.map((region: any) => {
+          return {
+            ...region,
+            id: region.region,
+            flag1: extractNumberAndExtension(region.flag1),
+            flag2: extractNumberAndExtension(region.flag2),
+            visitStartDate: {
+              year: region.year_from || null,
+              month: region.month_from || null,
+              day: region.day_from || null
+            },
+            visitEndDate: {
+              year: region.year_to || null,
+              month: region.month_to || null,
+              day: region.day_to || null
+            }
+          };
+        })
+      );
+    }
+  }, [editData]);
+
+  useEffect(() => {
+    setDisabled(!regions?.length);
+  }, [regions]);
+
+  const formatDateForDisplay = (d?: DateValue | null) => {
+    if (!d || !d.year) return 'Select dates';
+    const m = moment(`${d.year}-${d.month}-${d.day}`, 'YYYY-M-D');
+    return m.format('D MMM YYYY');
+  };
+
+  const dateValueToISO = (d?: DateValue | null) => {
+    if (!d || !d.year) return null;
+    const mm = String(d.month).padStart(2, '0');
+    const dd = String(d.day).padStart(2, '0');
+    return `${d.year}-${mm}-${dd}`;
+  };
+
+  const parseISOToDateValue = (iso?: string | null): DateValue | null => {
+    if (!iso) return null;
+    const m = moment(iso, 'YYYY-MM-DD');
+    if (!m.isValid()) return null;
+    return { year: m.year(), month: m.month() + 1, day: m.date() };
+  };
+
+  const validateRegionsDates = (regionsToValidate?: RegionWithDates[] | null) => {
+    const list = regionsToValidate ?? regions;
+    const errors: { [index: number]: string } = {};
+
+    if (!list || list.length === 0) {
+      setRegionErrors(errors);
+      return false;
+    }
+
+    for (let i = 0; i < list.length; i++) {
+      const r = list[i];
+      const s = r.visitStartDate;
+      const e = r.visitEndDate;
+
+      if (!s?.year || !s?.month || !s?.day) {
+        errors[i] = 'Please select visit dates';
+        continue;
+      }
+      if (!e?.year || !e?.month || !e?.day) {
+        errors[i] = 'Please select visit dates';
+        continue;
+      }
+
+      const sM = moment(`${s.year}-${s.month}-${s.day}`, 'YYYY-M-D');
+      const eM = moment(`${e.year}-${e.month}-${e.day}`, 'YYYY-M-D');
+
+      if (sM.isAfter(eM)) {
+        errors[i] = 'Start date cannot be after end date';
+        continue;
+      }
+
+      // if (i > 0) {
+      //   const prevEnd = list[i - 1]?.visitEndDate;
+      //   if (prevEnd?.year) {
+      //     const prevEndM = moment(`${prevEnd.year}-${prevEnd.month}-${prevEnd.day}`, 'YYYY-M-D');
+      //     if (sM.isBefore(prevEndM)) {
+      //       errors[i] = 'This region must start before previous';
+      //       continue;
+      //     }
+      //   }
+      // }
+    }
+
+    setRegionErrors(errors);
+    return Object.keys(errors).length === 0;
+  };
+
+  const openRangeCalendarForRegion = (index: number) => {
+    if (!regions) return;
+
+    const prevEnd = regions[index - 1]?.visitEndDate;
+    const nextStart = regions[index + 1]?.visitStartDate;
+
+    const min = prevEnd ? dateValueToISO(prevEnd) : undefined;
+    const max = nextStart ? dateValueToISO(nextStart) : undefined;
+
+    setCalendarMinDate(min as never);
+    setCalendarMaxDate(max as never);
+    setCalendarVisibleForIndex(index);
+  };
+
+  const closeRangeCalendar = (startDate?: string | null, endDate?: string | null) => {
+    const idx = calendarVisibleForIndex;
+    setCalendarVisibleForIndex(null);
+    setCalendarMinDate(undefined);
+    setCalendarMaxDate(undefined);
+
+    if (idx === null || idx === undefined) return;
+
+    if (!startDate) return;
+
+    const startVal = parseISOToDateValue(startDate);
+    const endVal = parseISOToDateValue(endDate ?? startDate);
+
+    if (!startVal || !endVal) return;
+
+    setRegions((prev) => {
+      if (!prev) return prev;
+      const updated = [...prev];
+
+      updated[idx] = {
+        ...updated[idx],
+        visitStartDate: startVal,
+        visitEndDate: endVal
+      };
+
+      const next = updated[idx + 1];
+      if (next && (!next.visitStartDate?.year || !next.visitEndDate?.year)) {
+        updated[idx + 1] = {
+          ...next,
+          visitStartDate: endVal,
+          visitEndDate: endVal
+        };
+      }
+
+      const prevR = updated[idx - 1];
+      if (prevR && (!prevR.visitStartDate?.year || !prevR.visitEndDate?.year)) {
+        updated[idx - 1] = {
+          ...prevR,
+          visitStartDate: startVal,
+          visitEndDate: startVal
+        };
+      }
+
+      validateRegionsDates(updated);
+
+      return updated;
+    });
+
+    setRegionErrors((prev) => {
+      const clone = { ...prev };
+      delete clone[idx];
+      return clone;
+    });
+  };
+
+  const moveRegionUp = (index: number) => {
+    if (index <= 0 || !regions) return;
+    const newRegions = [...regions];
+    [newRegions[index - 1], newRegions[index]] = [newRegions[index], newRegions[index - 1]];
+    setRegions(newRegions);
+  };
+
+  const moveRegionDown = (index: number) => {
+    if (!regions || index >= regions.length - 1) return;
+    const newRegions = [...regions];
+    [newRegions[index + 1], newRegions[index]] = [newRegions[index], newRegions[index + 1]];
+    setRegions(newRegions);
+  };
+
+  const handleDeleteRegion = (index: number) => {
+    if (!regions) return;
+    const updated = [...regions];
+    updated.splice(index, 1);
+    setRegions(updated);
+  };
+
+  const handleDeleteTrip = async () => {
+    setIsWarningModalVisible(false);
+    setPendingDelete(true);
+  };
+
+  const computePayloadDates = (regionsList: RegionWithDates[]) => {
+    if (!regionsList || regionsList.length === 0) return { date_from: null, date_to: null };
+
+    const starts = regionsList.map((r) => dateValueToISO(r.visitStartDate) as string);
+    const ends = regionsList.map((r) => dateValueToISO(r.visitEndDate) as string);
+
+    const minStart = starts.reduce(
+      (acc, cur) => (!acc || cur < acc ? cur : acc),
+      null as string | null
+    );
+    const maxEnd = ends.reduce(
+      (acc, cur) => (!acc || cur > acc ? cur : acc),
+      null as string | null
+    );
+
+    return { date_from: minStart, date_to: maxEnd };
+  };
+
+  const handleSaveNewTrip = () => {
+    if (regions) {
+      if (!validateRegionsDates(regions)) {
+        return;
+      }
+
+      setIsLoading('save');
+      const regionsData = regions.map((region) => {
+        return {
+          id: region.id,
+          quality: 3,
+          hidden: region.hidden,
+          year_from: region.visitStartDate?.year || null,
+          year_to: region.visitEndDate?.year || null,
+          month_from: region.visitStartDate?.month || null,
+          month_to: region.visitEndDate?.month || null,
+          day_from: region.visitStartDate?.day || null,
+          day_to: region.visitEndDate?.day || null
+        };
+      });
+
+      if (regionsData.length > 30) {
+        Alert.alert('One trip cannot have more than 30 regions.');
+        setIsLoading(null);
+        return;
+      }
+
+      const { date_from, date_to } = computePayloadDates(regions);
+
+      saveNewTrip(
+        {
+          token,
+          date_from,
+          date_to,
+          description,
+          regions: regionsData
+        },
+        {
+          onSuccess: (res) => {
+            if (res && res.result === 'OK') {
+              navigation.popTo(...([NAVIGATION_PAGES.TRIPS_2025, { saved: true }] as never));
+            }
+            setIsLoading(null);
+          },
+          onError: () => {
+            setIsLoading(null);
+          }
+        }
+      );
+    }
+  };
+
+  const handleUpdateTrip = () => {
+    if (regions) {
+      if (!validateRegionsDates(regions)) {
+        return;
+      }
+
+      setIsLoading('update');
+      const regionsData = regions.map((region) => {
+        return {
+          id: region.id,
+          quality: 3,
+          hidden: region.hidden,
+          year_from: region.visitStartDate?.year || null,
+          year_to: region.visitEndDate?.year || null,
+          month_from: region.visitStartDate?.month || null,
+          month_to: region.visitEndDate?.month || null,
+          day_from: region.visitStartDate?.day || null,
+          day_to: region.visitEndDate?.day || null
+        };
+      });
+
+      if (regionsData.length > 30) {
+        Alert.alert('One trip cannot have more than 30 regions.');
+        setIsLoading(null);
+        return;
+      }
+
+      const { date_from, date_to } = computePayloadDates(regions);
+
+      updateTrip(
+        {
+          token,
+          trip_id: editTripId,
+          date_from,
+          date_to,
+          description,
+          regions: regionsData
+        },
+        {
+          onSuccess: (res) => {
+            if (res && res.result === 'OK') {
+              navigation.popTo(...([NAVIGATION_PAGES.TRIPS_2025, { updated: true }] as never));
+            }
+            setIsLoading(null);
+          },
+          onError: () => {
+            setIsLoading(null);
+          }
+        }
+      );
+    }
+  };
+
+  return (
+    <PageWrapper style={{ flex: 1 }}>
+      <Header label={editTripId ? 'Edit Trip' : 'Add New Trip'} />
+      <ScrollView
+        contentContainerStyle={{ flexGrow: 1, gap: 16 }}
+        showsVerticalScrollIndicator={false}
+      >
+        <Input
+          placeholder="Add description and all interesting moments of your trip"
+          inputMode={'text'}
+          onChange={(text) => setDescription(text)}
+          value={description}
+          header="Description"
+          height={54}
+          multiline={true}
+        />
+
+        <View style={{ marginBottom: 8 }}>
+          <Text style={styles.regionsLabel}>Regions</Text>
+          <TouchableOpacity
+            style={styles.addRegionBtn}
+            onPress={() =>
+              navigation.navigate(
+                ...([
+                  NAVIGATION_PAGES.ADD_REGIONS_NEW,
+                  { regionsParams: regions, editId: editTripId }
+                ] as never)
+              )
+            }
+          >
+            <Text style={styles.addRegionBtntext}>Add visit</Text>
+          </TouchableOpacity>
+          {regions && regions.length ? (
+            <View style={styles.regionsContainer}>
+              {regions.map((region, index) => {
+                const startLabel = formatDateForDisplay(region.visitStartDate);
+                const endLabel = formatDateForDisplay(region.visitEndDate);
+                const datesLabel =
+                  region.visitStartDate?.year &&
+                  region.visitEndDate?.year &&
+                  dateValueToISO(region.visitStartDate) === dateValueToISO(region.visitEndDate)
+                    ? startLabel
+                    : region.visitStartDate?.year && region.visitEndDate?.year
+                      ? `${startLabel} – ${endLabel}`
+                      : 'Select visit dates';
+
+                return (
+                  <RegionItem
+                    key={`${region.id}-${index}`}
+                    region={region}
+                    index={index}
+                    total={regions.length}
+                    onDelete={() => handleDeleteRegion(index)}
+                    onSelectDates={() => openRangeCalendarForRegion(index)}
+                    datesLabel={datesLabel}
+                    onMoveUp={() => moveRegionUp(index)}
+                    onMoveDown={() => moveRegionDown(index)}
+                    errorMessage={regionErrors[index]}
+                  />
+                );
+              })}
+              <TouchableOpacity
+                style={[styles.addRegionBtn, { marginTop: 0 }]}
+                onPress={() =>
+                  navigation.navigate(
+                    ...([
+                      NAVIGATION_PAGES.ADD_REGIONS_NEW,
+                      { regionsParams: regions, editId: editTripId }
+                    ] as never)
+                  )
+                }
+              >
+                <Text style={styles.addRegionBtntext}>Add visit</Text>
+              </TouchableOpacity>
+            </View>
+          ) : (
+            <Text style={styles.noRegiosText}>No regions at the moment</Text>
+          )}
+        </View>
+      </ScrollView>
+
+      <View style={styles.tabContainer}>
+        {editTripId ? (
+          <>
+            <TouchableOpacity
+              style={[styles.tabStyle, styles.deleteTab]}
+              onPress={() => setIsWarningModalVisible(true)}
+              disabled={isLoading === 'delete'}
+            >
+              {isLoading === 'delete' ? (
+                <ActivityIndicator size={18} color={Colors.RED} />
+              ) : (
+                <Text style={[styles.tabText, styles.deleteTabText]}>Delete Trip</Text>
+              )}
+            </TouchableOpacity>
+            <TouchableOpacity
+              style={[
+                styles.tabStyle,
+                styles.addNewTab,
+                disabled && { backgroundColor: Colors.LIGHT_GRAY, borderColor: Colors.LIGHT_GRAY }
+              ]}
+              onPress={handleUpdateTrip}
+              disabled={disabled || isLoading === 'update'}
+            >
+              {isLoading === 'update' ? (
+                <ActivityIndicator size={18} color={Colors.WHITE} />
+              ) : (
+                <Text style={[styles.tabText, styles.addNewTabText]}>Save Trip</Text>
+              )}
+            </TouchableOpacity>
+          </>
+        ) : (
+          <TouchableOpacity
+            style={[
+              styles.tabStyle,
+              styles.addNewTab,
+              disabled && { backgroundColor: Colors.LIGHT_GRAY, borderColor: Colors.LIGHT_GRAY },
+              { paddingVertical: 12 }
+            ]}
+            onPress={handleSaveNewTrip}
+            disabled={disabled || isLoading === 'save'}
+          >
+            {isLoading === 'save' ? (
+              <ActivityIndicator size={18} color={Colors.WHITE} />
+            ) : (
+              <Text style={[styles.tabText, styles.addNewTabText]}>Add New Trip</Text>
+            )}
+          </TouchableOpacity>
+        )}
+      </View>
+
+      <RangeCalendar
+        isModalVisible={calendarVisibleForIndex !== null}
+        minDate={calendarMinDate}
+        maxDate={calendarMaxDate}
+        allowRangeSelection={true}
+        closeModal={(startDate?: string | null, endDate?: string | null) =>
+          closeRangeCalendar(startDate, endDate)
+        }
+        initialStartDate={
+          calendarVisibleForIndex !== null && regions?.[calendarVisibleForIndex]?.visitStartDate
+            ? `${regions[calendarVisibleForIndex].visitStartDate.year}-${regions[calendarVisibleForIndex].visitStartDate.month}-${regions[calendarVisibleForIndex].visitStartDate.day}`
+            : undefined
+        }
+        initialEndDate={
+          calendarVisibleForIndex !== null && regions?.[calendarVisibleForIndex]?.visitEndDate
+            ? `${regions[calendarVisibleForIndex].visitEndDate.year}-${regions[calendarVisibleForIndex].visitEndDate.month}-${regions[calendarVisibleForIndex].visitEndDate.day}`
+            : undefined
+        }
+      />
+      <WarningModal
+        type={'delete'}
+        isVisible={isWarningModalVisible}
+        onClose={() => setIsWarningModalVisible(false)}
+        title="Delete Trip"
+        message="Are you sure you want to delete your trip?"
+        action={handleDeleteTrip}
+        onModalHide={() => {
+          if (pendingDelete) {
+            setPendingDelete(false);
+            setIsLoading('delete');
+            deleteTrip(
+              {
+                token,
+                trip_id: editTripId
+              },
+              {
+                onSuccess: (res) => {
+                  if (res && res.result === 'OK') {
+                    navigation.popTo(
+                      ...([NAVIGATION_PAGES.TRIPS_2025, { deleted: true }] as never)
+                    );
+                  }
+                  setIsLoading(null);
+                },
+                onError: () => {
+                  setIsLoading(null);
+                }
+              }
+            );
+          }
+        }}
+      />
+    </PageWrapper>
+  );
+};
+
+export default AddNewTripScreen;

+ 199 - 0
src/screens/InAppScreens/TravelsScreen/AddNewTrip2025Screen/styles.tsx

@@ -0,0 +1,199 @@
+import { StyleSheet } from 'react-native';
+import { Colors } from 'src/theme';
+import { getFontSize } from 'src/utils';
+
+export const styles = StyleSheet.create({
+  tabContainer: { flexDirection: 'row', gap: 16, alignItems: 'center', marginBottom: 8 },
+  tabStyle: {
+    flex: 1,
+    borderRadius: 4,
+    alignItems: 'center',
+    justifyContent: 'center',
+    paddingHorizontal: 16,
+    paddingVertical: 8,
+    gap: 4,
+    borderWidth: 1
+  },
+  deleteTab: {
+    backgroundColor: 'transparent',
+    borderColor: Colors.RED
+  },
+  tabText: {
+    fontSize: getFontSize(14),
+    fontWeight: 'bold',
+    fontFamily: 'redhat-700'
+  },
+  deleteTabText: {
+    color: Colors.RED
+  },
+  addNewTab: {
+    backgroundColor: Colors.ORANGE,
+    borderColor: Colors.ORANGE
+  },
+  addNewTabText: { color: Colors.WHITE },
+  regionSelector: {
+    flexDirection: 'row',
+    alignItems: 'center',
+    paddingHorizontal: 16,
+    borderRadius: 4,
+    height: 36,
+    backgroundColor: Colors.FILL_LIGHT,
+    justifyContent: 'flex-start',
+    gap: 10
+  },
+  regionText: {
+    fontSize: 15,
+    color: Colors.LIGHT_GRAY
+  },
+  regionsLabel: {
+    color: Colors.DARK_BLUE,
+    fontSize: getFontSize(14),
+    fontFamily: 'redhat-700',
+    marginBottom: 5
+  },
+  noRegiosText: {
+    fontSize: 14,
+    fontWeight: '500',
+    color: Colors.LIGHT_GRAY,
+    textAlign: 'center',
+    paddingVertical: 8
+  },
+  addRegionBtn: {
+    display: 'flex',
+    justifyContent: 'center',
+    alignItems: 'center',
+    borderRadius: 4,
+    gap: 10,
+    padding: 10,
+    borderColor: Colors.DARK_BLUE,
+    borderWidth: 1,
+    borderStyle: 'solid',
+    marginTop: 8,
+    marginBottom: 8
+  },
+  addRegionBtntext: {
+    color: Colors.DARK_BLUE,
+    fontSize: getFontSize(14),
+    fontFamily: 'redhat-700'
+  },
+  regionsContainer: {
+    gap: 12
+  },
+  btnOption: {
+    paddingHorizontal: 16,
+    paddingVertical: 9,
+    flexDirection: 'row',
+    alignItems: 'center',
+    gap: 16
+  },
+  btnOptionText: { fontSize: 16, fontWeight: '600', color: Colors.DARK_BLUE },
+  wrapper: {
+    backgroundColor: Colors.WHITE,
+    padding: 16,
+    borderTopLeftRadius: 10,
+    borderTopRightRadius: 10,
+    height: 'auto'
+  },
+  modal: {
+    justifyContent: 'flex-end',
+    margin: 0
+  },
+  regionItemContainer: {
+    backgroundColor: Colors.WHITE,
+    borderRadius: 8,
+    padding: 12,
+    marginBottom: 12,
+    borderWidth: 0.5,
+    borderColor: Colors.LIGHT_GRAY
+  },
+  regionDatesContainer: {
+    marginTop: 12,
+    paddingTop: 12,
+    borderTopWidth: 1,
+    borderTopColor: Colors.LIGHT_GRAY
+  },
+  regionDatesLabel: {
+    fontSize: getFontSize(12),
+    color: Colors.DARK_BLUE,
+    marginBottom: 8,
+    fontWeight: '600'
+  },
+  dateRow: {
+    flexDirection: 'row',
+    alignItems: 'flex-start',
+    gap: 12
+  },
+  dateColumn: {
+    flex: 1
+  },
+  dateFieldLabel: {
+    fontSize: getFontSize(12),
+    color: Colors.DARK_BLUE,
+    marginBottom: 4,
+    fontWeight: '600'
+  },
+  dateInput: {
+    borderRadius: 6,
+    paddingHorizontal: 8,
+    paddingVertical: 6,
+    flexDirection: 'row',
+    alignItems: 'center',
+    justifyContent: 'space-between',
+    backgroundColor: Colors.FILL_LIGHT,
+    height: 36
+  },
+  dateText: {
+    fontSize: getFontSize(12),
+    color: Colors.DARK_BLUE,
+    fontWeight: '500'
+  },
+  placeholderText: {
+    color: Colors.TEXT_GRAY,
+    flexWrap: 'wrap'
+  },
+  datePickerHeader: {
+    flexDirection: 'row',
+    justifyContent: 'space-between',
+    alignItems: 'center',
+    paddingHorizontal: 20,
+    paddingVertical: 16,
+    borderBottomWidth: 1,
+    borderBottomColor: '#eee'
+  },
+
+  datePickerTitle: {
+    fontSize: 18,
+    fontWeight: '600',
+    color: Colors.DARK_BLUE
+  },
+  datePickerCancel: {
+    fontSize: 16,
+    color: '#666'
+  },
+  datePickerConfirm: {
+    fontSize: 16,
+    color: Colors.DARK_BLUE,
+    fontWeight: '600'
+  },
+  wheelContainer: {
+    flexDirection: 'row',
+    paddingHorizontal: 14,
+    paddingTop: 16,
+    paddingBottom: 24
+  },
+  wheelColumn: {
+    flex: 1,
+    alignItems: 'center'
+  },
+  wheelLabel: {
+    fontSize: 14,
+    color: Colors.DARK_BLUE,
+    marginBottom: 8,
+    fontWeight: '600'
+  },
+  wheelPicker: {
+    height: 210,
+    width: '100%',
+    backgroundColor: 'white'
+  }
+});

+ 1 - 3
src/screens/InAppScreens/TravelsScreen/AddNewTripScreen/index.tsx

@@ -395,8 +395,6 @@ const AddNewTripScreen = ({ route }: { route: any }) => {
 
   const handleUpdateTrip = () => {
     if (regions && selectedDates) {
-      const isStartDateInFuture =
-        selectedDates.split(' - ')[0] > new Date().toISOString().split('T')[0];
       setIsLoading('update');
       const regionsData = regions.map((region) => {
         return {
@@ -450,7 +448,7 @@ const AddNewTripScreen = ({ route }: { route: any }) => {
         showsVerticalScrollIndicator={false}
       >
         <TouchableOpacity style={styles.regionSelector} onPress={() => setCalendarVisible(true)}>
-          <CalendarSvg />
+          <CalendarSvg fill={Colors.LIGHT_GRAY} />
           <Text style={styles.regionText}>{selectedDates ?? 'Add dates'}</Text>
         </TouchableOpacity>
 

+ 1 - 1
src/screens/InAppScreens/TravelsScreen/AddPhotoScreen/index.tsx

@@ -271,7 +271,7 @@ const AddPhotoScreen = ({ route }: { route: any }) => {
 
         {!data?.date && (
           <TouchableOpacity style={styles.regionSelector} onPress={() => setCalendarVisible(true)}>
-            <CalendarSvg />
+            <CalendarSvg fill={Colors.LIGHT_GRAY} />
             <Text style={styles.regionText}>{selectedDate ?? 'Add date'}</Text>
           </TouchableOpacity>
         )}

+ 523 - 0
src/screens/InAppScreens/TravelsScreen/AddRegionsNewScreen/index.tsx

@@ -0,0 +1,523 @@
+import React, { useCallback, useEffect, useRef, useState } from 'react';
+import { View, Text, TouchableOpacity, ActivityIndicator, Platform, Linking } from 'react-native';
+import { SafeAreaView } from 'react-native-safe-area-context';
+import { useNavigation } from '@react-navigation/native';
+import * as turf from '@turf/turf';
+import * as MapLibreRN from '@maplibre/maplibre-react-native';
+import * as Location from 'expo-location';
+import { useBottomTabBarHeight } from '@react-navigation/bottom-tabs';
+
+import { Header, Modal, FlatList as List, WarningModal } from 'src/components';
+
+import { VECTOR_MAP_HOST } from 'src/constants';
+import { Colors } from 'src/theme';
+import { NAVIGATION_PAGES } from 'src/types';
+import { RegionAddData } from '../utils/types';
+import { useGetRegionsForTripsQuery } from '@api/trips';
+import { useGetListRegionsQuery } from '@api/regions';
+import { styles } from './styles';
+
+import SearchSvg from '../../../../../assets/icons/search.svg';
+import LocationIcon from 'assets/icons/location.svg';
+
+const generateFilter = (ids: number[]) => {
+  return ids?.length ? ['any', ...ids.map((id) => ['==', 'id', id])] : ['==', 'id', -1];
+};
+
+let nm_regions = {
+  id: 'regions',
+  type: 'fill',
+  source: 'regions',
+  'source-layer': 'regions',
+  style: {
+    fillColor: 'rgba(15, 63, 79, 0)'
+  },
+  filter: ['all'],
+  maxzoom: 16
+};
+
+let selected_region = {
+  id: 'selected_region',
+  type: 'fill',
+  source: 'regions',
+  'source-layer': 'regions',
+  style: {
+    fillColor: 'rgba(237, 147, 52, 0.7)'
+  },
+  maxzoom: 12
+};
+
+const AddRegionsScreen = ({ route }: { route: any }) => {
+  const { regionsParams }: { regionsParams: RegionAddData[] } = route.params;
+  const { data } = useGetRegionsForTripsQuery(true);
+  const { data: regionsList } = useGetListRegionsQuery(true);
+  const navigation = useNavigation();
+
+  const [regions, setRegions] = useState<RegionAddData[] | null>(null);
+  const [isModalVisible, setIsModalVisible] = useState(false);
+  const [selectedRegions, setSelectedRegions] = useState<any[]>([]);
+  const [regionsToSave, setRegionsToSave] = useState<RegionAddData[]>([]);
+  const [regionData, setRegionData] = useState<RegionAddData | null>(null);
+  const [regionPopupVisible, setRegionPopupVisible] = useState(false);
+  const mapRef = useRef<MapLibreRN.MapViewRef>(null);
+  const cameraRef = useRef<MapLibreRN.CameraRef>(null);
+  const [renderCamera, setRenderCamera] = useState(Platform.OS === 'ios');
+  const isAnimatingRef = useRef(false);
+  const animationTimeoutRef = useRef<NodeJS.Timeout | null>(null);
+
+  const [filterSelectedRegions, setFilterSelectedRegions] = useState<any[]>(generateFilter([]));
+  const [isLocationLoading, setIsLocationLoading] = useState(false);
+  const [location, setLocation] = useState<any | null>(null);
+  const [askLocationVisible, setAskLocationVisible] = useState<boolean>(false);
+  const [openSettingsVisible, setOpenSettingsVisible] = useState<boolean>(false);
+
+  const [repeatPopup, setRepeatPopup] = useState<{
+    visible: boolean;
+    text: string;
+  } | null>(null);
+
+  const cameraController = {
+    flyTo: useCallback((coordinates: number[], duration: number = 1000) => {
+      isAnimatingRef.current = true;
+      if (animationTimeoutRef.current) {
+        clearTimeout(animationTimeoutRef.current);
+      }
+
+      if (Platform.OS === 'android') {
+        setRenderCamera(true);
+        requestAnimationFrame(() => {
+          cameraRef.current?.flyTo(coordinates, duration);
+        });
+        animationTimeoutRef.current = setTimeout(() => {
+          isAnimatingRef.current = false;
+          setRenderCamera(false);
+        }, duration + 200);
+      } else {
+        cameraRef.current?.flyTo(coordinates, duration);
+        animationTimeoutRef.current = setTimeout(() => {
+          isAnimatingRef.current = false;
+        }, duration + 100);
+      }
+    }, []),
+
+    setCamera: useCallback((config: any) => {
+      isAnimatingRef.current = true;
+      if (animationTimeoutRef.current) {
+        clearTimeout(animationTimeoutRef.current);
+      }
+
+      if (Platform.OS === 'android') {
+        setRenderCamera(true);
+        requestAnimationFrame(() => {
+          cameraRef.current?.setCamera(config);
+        });
+        animationTimeoutRef.current = setTimeout(
+          () => {
+            isAnimatingRef.current = false;
+            setRenderCamera(false);
+          },
+          (config.animationDuration ?? 1000) + 200
+        );
+      } else {
+        cameraRef.current?.setCamera(config);
+        animationTimeoutRef.current = setTimeout(
+          () => {
+            isAnimatingRef.current = false;
+          },
+          (config.animationDuration ?? 1000) + 100
+        );
+      }
+    }, []),
+
+    fitBounds: useCallback((ne: number[], sw: number[], padding: number[], duration: number) => {
+      isAnimatingRef.current = true;
+
+      if (animationTimeoutRef.current) {
+        clearTimeout(animationTimeoutRef.current);
+      }
+
+      if (Platform.OS === 'android') {
+        setRenderCamera(true);
+
+        requestAnimationFrame(() => {
+          cameraRef.current?.fitBounds(ne, sw, padding, duration);
+        });
+
+        animationTimeoutRef.current = setTimeout(() => {
+          isAnimatingRef.current = false;
+          setRenderCamera(false);
+        }, duration + 200);
+      } else {
+        cameraRef.current?.fitBounds(ne, sw, padding, duration);
+
+        animationTimeoutRef.current = setTimeout(() => {
+          isAnimatingRef.current = false;
+        }, duration + 100);
+      }
+    }, [])
+  };
+
+  useEffect(() => {
+    if (data && data.regions) {
+      setRegions(data.regions);
+    }
+  }, [data]);
+
+  useEffect(() => {
+    const ids = selectedRegions.map((region) => region.id);
+    setFilterSelectedRegions(generateFilter(ids));
+  }, [selectedRegions]);
+
+  useEffect(() => {
+    const addRegionsAsync = async () => {
+      if (regionsParams) {
+        setRegionsToSave((prevRegions) => [...prevRegions, ...regionsParams]);
+
+        setSelectedRegions(
+          (prevSelectedRegions) => [...prevSelectedRegions, ...regionsParams] as any
+        );
+      }
+    };
+
+    addRegionsAsync();
+  }, [regionsParams]);
+
+  useEffect(() => {
+    return () => {
+      if (animationTimeoutRef.current) {
+        clearTimeout(animationTimeoutRef.current);
+      }
+    };
+  }, []);
+
+  const addRegionFromSearch = async (searchRegion: RegionAddData) => {
+    const regionFromApi = regions?.find((r) => r.id === searchRegion.id);
+    if (!regionFromApi) return;
+    const newRegion = {
+      id: searchRegion.id,
+      name: searchRegion.name
+    };
+
+    setSelectedRegions([...selectedRegions, newRegion] as any);
+
+    setRegionsToSave((prev) => [...prev, regionFromApi]);
+
+    setRegionData(regionFromApi);
+    setRegionPopupVisible(true);
+
+    const timesSelected = selectedRegions.filter((r) => r.id === searchRegion.id).length + 1;
+
+    if (timesSelected > 1) {
+      setRepeatPopup({
+        visible: true,
+        text: `selected ${timesSelected} times`
+      });
+    } else {
+      setRepeatPopup(null);
+    }
+
+    if (regionsList) {
+      const region = regionsList.data.find((r) => r.id === searchRegion.id);
+      if (region) {
+        const bounds = turf.bbox(region.bbox);
+        cameraController.fitBounds(
+          [bounds[2], bounds[3]],
+          [bounds[0], bounds[1]],
+          [50, 50, 50, 50],
+          600
+        );
+      }
+    }
+  };
+
+  const handleSavePress = () => {
+    if (route.params?.isSharedTrip) {
+      navigation.popTo(
+        ...([
+          NAVIGATION_PAGES.CREATE_SHARED_TRIP,
+          { regionsToSave: regionsToSave, eventId: route.params?.editId }
+        ] as never)
+      );
+    } else {
+      navigation.popTo(
+        ...([
+          NAVIGATION_PAGES.ADD_TRIP_2025,
+          { regionsToSave: regionsToSave, editTripId: route.params?.editId }
+        ] as never)
+      );
+    }
+  };
+
+  const handleMapPress = useCallback(
+    async (event: any) => {
+      if (!mapRef.current) return;
+
+      try {
+        const { screenPointX, screenPointY } = event.properties;
+
+        const { features } = await mapRef.current.queryRenderedFeaturesAtPoint(
+          [screenPointX, screenPointY],
+          undefined,
+          ['regions']
+        );
+
+        if (features?.length) {
+          const selectedRegion = features[0];
+
+          if (selectedRegion.properties) {
+            const id = selectedRegion.properties.id;
+            if (!id) return;
+
+            const regionFromApi = regions?.find((r) => r.id === id);
+            if (!regionFromApi) return;
+
+            setSelectedRegions((prev) => [...prev, { id }]);
+
+            setRegionsToSave((prev) => [...prev, regionFromApi]);
+
+            setRegionData(regionFromApi);
+            setRegionPopupVisible(true);
+
+            const timesSelected = selectedRegions.filter((r) => r.id === id).length + 1;
+
+            if (timesSelected > 1) {
+              setRepeatPopup({
+                visible: true,
+                text: `selected ${timesSelected} times`
+              });
+            } else {
+              setRepeatPopup(null);
+            }
+
+            if (regionsList) {
+              const region = regionsList.data.find((r) => r.id === id);
+              if (region) {
+                const bounds = turf.bbox(region.bbox);
+                cameraController.fitBounds(
+                  [bounds[2], bounds[3]],
+                  [bounds[0], bounds[1]],
+                  [50, 50, 50, 50],
+                  600
+                );
+              }
+            }
+          }
+        }
+      } catch (error) {
+        console.error('Failed to get coordinates on AddRegionsScreen', error);
+      }
+    },
+    [selectedRegions, regions]
+  );
+
+  const handleGetLocation = async () => {
+    setIsLocationLoading(true);
+    try {
+      let { status, canAskAgain } = await Location.getForegroundPermissionsAsync();
+      const isServicesEnabled = await Location.hasServicesEnabledAsync();
+
+      if (status === 'granted' && isServicesEnabled) {
+        await getLocation();
+      } else if (!canAskAgain || !isServicesEnabled) {
+        setOpenSettingsVisible(true);
+      } else {
+        setAskLocationVisible(true);
+      }
+    } finally {
+      setIsLocationLoading(false);
+    }
+  };
+
+  const getLocation = async () => {
+    try {
+      let currentLocation = await Location.getCurrentPositionAsync({
+        accuracy: Location.Accuracy.Balanced
+      });
+      setLocation(currentLocation.coords);
+
+      if (currentLocation.coords) {
+        cameraController.flyTo(
+          [currentLocation.coords.longitude, currentLocation.coords.latitude],
+          1000
+        );
+      }
+    } catch (error) {
+      console.error('Error fetching user location:', error);
+    }
+  };
+
+  const handleAcceptPermission = async () => {
+    setAskLocationVisible(false);
+    let { status, canAskAgain } = await Location.requestForegroundPermissionsAsync();
+    const isServicesEnabled = await Location.hasServicesEnabledAsync();
+
+    if (status === 'granted' && isServicesEnabled) {
+      getLocation();
+    } else if (!canAskAgain || !isServicesEnabled) {
+      setOpenSettingsVisible(true);
+    }
+  };
+
+  return (
+    <SafeAreaView style={{ height: '100%' }} edges={['top']}>
+      <View style={styles.wrapper}>
+        <Header label={'Add Regions'} />
+        <View style={styles.searchContainer}>
+          <TouchableOpacity style={[styles.regionSelector]} onPress={() => setIsModalVisible(true)}>
+            <SearchSvg fill={Colors.LIGHT_GRAY} />
+            <Text style={styles.regionText}>Search</Text>
+          </TouchableOpacity>
+          <TouchableOpacity
+            style={[
+              styles.saveBtn,
+              selectedRegions.length ? styles.saveBtnActive : styles.saveBtnDisabled
+            ]}
+            onPress={handleSavePress}
+            disabled={!selectedRegions.length}
+          >
+            <Text
+              style={{
+                fontSize: 12,
+                fontWeight: '600',
+                color: !selectedRegions.length ? Colors.LIGHT_GRAY : Colors.WHITE
+              }}
+            >
+              Save
+            </Text>
+          </TouchableOpacity>
+        </View>
+      </View>
+
+      <View style={styles.container}>
+        <MapLibreRN.MapView
+          ref={mapRef}
+          style={styles.map}
+          mapStyle={VECTOR_MAP_HOST + '/nomadmania-maps2025.json'}
+          rotateEnabled={false}
+          attributionEnabled={false}
+          onPress={handleMapPress}
+        >
+          {(Platform.OS === 'ios' || renderCamera) && <MapLibreRN.Camera ref={cameraRef} />}
+
+          <MapLibreRN.LineLayer
+            id="nm-regions-line-layer"
+            sourceID={nm_regions.source}
+            sourceLayerID={nm_regions['source-layer']}
+            filter={nm_regions.filter as any}
+            maxZoomLevel={nm_regions.maxzoom}
+            style={{
+              lineColor: 'rgba(14, 80, 109, 1)',
+              lineWidth: ['interpolate', ['linear'], ['zoom'], 0, 0.2, 4, 1, 5, 1.5, 12, 3],
+              lineWidthTransition: { duration: 300, delay: 0 }
+            }}
+            belowLayerID="waterway-name"
+          />
+          <MapLibreRN.FillLayer
+            id={nm_regions.id}
+            sourceID={nm_regions.source}
+            sourceLayerID={nm_regions['source-layer']}
+            filter={nm_regions.filter as any}
+            style={nm_regions.style}
+            maxZoomLevel={nm_regions.maxzoom}
+            belowLayerID="nm-regions-line-layer"
+          />
+
+          {selectedRegions && selectedRegions.length > 0 ? (
+            <MapLibreRN.FillLayer
+              id={selected_region.id}
+              sourceID={nm_regions.source}
+              sourceLayerID={nm_regions['source-layer']}
+              filter={filterSelectedRegions as any}
+              style={selected_region.style}
+              maxZoomLevel={selected_region.maxzoom}
+              belowLayerID="nm-regions-line-layer"
+            />
+          ) : null}
+
+          {location && (
+            <MapLibreRN.UserLocation
+              animated={true}
+              showsUserHeadingIndicator={true}
+              onPress={async () => {
+                const currentZoom = await mapRef.current?.getZoom();
+                const newZoom = (currentZoom || 0) + 2;
+
+                cameraController.setCamera({
+                  centerCoordinate: [location.longitude, location.latitude],
+                  zoomLevel: newZoom,
+                  animationDuration: 500,
+                  animationMode: 'flyTo'
+                });
+              }}
+            ></MapLibreRN.UserLocation>
+          )}
+        </MapLibreRN.MapView>
+
+        <TouchableOpacity
+          onPress={handleGetLocation}
+          style={[
+            styles.cornerButton,
+            styles.bottomButton,
+            styles.bottomRightButton,
+            { bottom: 20 }
+          ]}
+        >
+          {isLocationLoading ? (
+            <ActivityIndicator size="small" color={Colors.DARK_BLUE} />
+          ) : (
+            <LocationIcon />
+          )}
+        </TouchableOpacity>
+      </View>
+      {regionPopupVisible && regionData && (
+        <View style={styles.popupWrapper}>
+          <View style={styles.popupContainer}>
+            <Text style={styles.popupText}>{regionData.name ?? regionData.region_name}</Text>
+            {repeatPopup && <Text style={styles.popupText}>{repeatPopup.text}</Text>}
+          </View>
+        </View>
+      )}
+      <Modal
+        onRequestClose={() => setIsModalVisible(false)}
+        headerTitle={'Select Regions'}
+        visible={isModalVisible}
+      >
+        <List
+          itemObject={(object) => {
+            setIsModalVisible(false);
+            setRegionData(object);
+            addRegionFromSearch(object);
+          }}
+        />
+      </Modal>
+
+      <WarningModal
+        type={'success'}
+        isVisible={openSettingsVisible}
+        onClose={() => setOpenSettingsVisible(false)}
+        action={async () => {
+          const isServicesEnabled = await Location.hasServicesEnabledAsync();
+
+          if (!isServicesEnabled) {
+            Platform.OS === 'ios'
+              ? Linking.openURL('app-settings:')
+              : Linking.sendIntent('android.settings.LOCATION_SOURCE_SETTINGS');
+          } else {
+            Platform.OS === 'ios' ? Linking.openURL('app-settings:') : Linking.openSettings();
+          }
+        }}
+        message="NomadMania app needs location permissions to function properly. Open settings?"
+      />
+
+      <WarningModal
+        type={'success'}
+        isVisible={askLocationVisible}
+        onClose={() => setAskLocationVisible(false)}
+        action={handleAcceptPermission}
+        message="To use this feature we need your permission to access your location. If you press OK your system will ask you to approve location sharing with NomadMania app."
+      />
+    </SafeAreaView>
+  );
+};
+
+export default AddRegionsScreen;

+ 100 - 0
src/screens/InAppScreens/TravelsScreen/AddRegionsNewScreen/styles.tsx

@@ -0,0 +1,100 @@
+import { StyleSheet } from 'react-native';
+import { Colors } from 'src/theme';
+import { getFontSize } from 'src/utils';
+
+export const styles = StyleSheet.create({
+  container: {
+    flex: 1
+  },
+  wrapper: {
+    marginLeft: '5%',
+    marginRight: '5%',
+    alignItems: 'center'
+  },
+  map: {
+    ...StyleSheet.absoluteFillObject
+  },
+  searchContainer: {
+    gap: 16,
+    flexDirection: 'row',
+    alignItems: 'center',
+    marginBottom: 8
+  },
+  regionSelector: {
+    flexDirection: 'row',
+    alignItems: 'center',
+    paddingHorizontal: 16,
+    borderRadius: 4,
+    height: 36,
+    backgroundColor: Colors.FILL_LIGHT,
+    justifyContent: 'flex-start',
+    gap: 10,
+    flex: 1
+  },
+  regionText: {
+    fontSize: 15,
+    fontWeight: '500',
+    color: Colors.LIGHT_GRAY
+  },
+  saveBtn: {
+    borderRadius: 20,
+    paddingVertical: 10,
+    paddingHorizontal: 16,
+    borderWidth: 1
+  },
+  saveBtnActive: {
+    borderColor: Colors.ORANGE,
+    backgroundColor: Colors.ORANGE
+  },
+  saveBtnDisabled: {
+    borderColor: Colors.LIGHT_GRAY
+  },
+  popupWrapper: {
+    marginHorizontal: 24,
+    position: 'absolute',
+    bottom: 25,
+    left: 0,
+    right: 0
+  },
+  popupContainer: {
+    alignItems: 'center',
+    justifyContent: 'center',
+    alignSelf: 'center',
+    paddingVertical: 8,
+    paddingHorizontal: 16,
+    backgroundColor: 'rgba(33, 37, 41, 0.8)',
+    borderRadius: 100,
+    gap: 6
+  },
+  popupText: {
+    color: Colors.WHITE,
+    fontSize: getFontSize(12),
+    fontWeight: '600'
+  },
+  cornerButton: {
+    position: 'absolute',
+    backgroundColor: Colors.WHITE,
+    padding: 12,
+    width: 48,
+    height: 48,
+    borderRadius: 24,
+    alignItems: 'center',
+    justifyContent: 'center',
+    shadowColor: '#000',
+    shadowOffset: {
+      width: 0,
+      height: 1
+    },
+    shadowOpacity: 0.25,
+    shadowRadius: 1.5,
+    elevation: 2
+  },
+  bottomButton: {
+    width: 42,
+    height: 42,
+    borderRadius: 21
+  },
+  bottomRightButton: {
+    right: 16
+  }
+});

+ 2 - 1
src/screens/InAppScreens/TravelsScreen/Components/PhotoEditModal.tsx

@@ -19,6 +19,7 @@ import { styles } from './styles';
 
 import ChevronIcon from '../../../../../assets/icons/travels-screens/chevron-bottom.svg';
 import CalendarSvg from '../../../../../assets/icons/calendar.svg';
+import { Colors } from 'src/theme';
 
 export const PhotoEditModal = ({
   isVisible,
@@ -108,7 +109,7 @@ export const PhotoEditModal = ({
               style={styles.regionSelector}
               onPress={() => setCalendarVisible(true)}
             >
-              <CalendarSvg />
+              <CalendarSvg fill={Colors.LIGHT_GRAY} />
               <Text style={styles.regionText}>{selectedDate ?? photo?.date}</Text>
             </TouchableOpacity>
 

+ 123 - 0
src/screens/InAppScreens/TravelsScreen/Components/RegionItemNew/index.tsx

@@ -0,0 +1,123 @@
+import React from 'react';
+import { View, Text, Image, TouchableOpacity } from 'react-native';
+import { MaterialCommunityIcons } from '@expo/vector-icons';
+
+import { RegionAddData } from '../../utils/types';
+import { Colors } from 'src/theme';
+import { API_HOST } from 'src/constants';
+import { styles } from './styles';
+
+import TrashSvg from 'assets/icons/travels-screens/trash-solid.svg';
+import CalendarSvg from 'assets/icons/calendar.svg';
+
+interface RegionItemProps {
+  region: RegionAddData;
+  onDelete: () => void;
+  onSelectDates: () => void;
+  datesLabel?: string;
+  onMoveUp: () => void;
+  onMoveDown: () => void;
+  index: number;
+  total: number;
+  errorMessage?: string;
+}
+
+const RegionItem = ({
+  region,
+  onDelete,
+  onSelectDates,
+  datesLabel,
+  onMoveUp,
+  onMoveDown,
+  index,
+  total,
+  errorMessage
+}: RegionItemProps) => {
+  const [name, ...rest] = region.region_name?.split(/ – | - /);
+  const subname = rest?.join(' - ');
+
+  return (
+    <View key={region.id} style={styles.regionItem}>
+      <View style={styles.regionItemTop}>
+        <View style={styles.regionHeader}>
+          <Image
+            source={{ uri: `${API_HOST}/img/flags_new/${region.flag1}` }}
+            style={styles.flagStyle}
+          />
+          {region.flag2 && (
+            <Image
+              source={{ uri: `${API_HOST}/img/flags_new/${region.flag2}` }}
+              style={[styles.flagStyle, { marginLeft: -17 }]}
+            />
+          )}
+          <View style={styles.nameContainer}>
+            <Text style={styles.regionName}>{name}</Text>
+            <Text style={styles.regionSubname}>{subname}</Text>
+          </View>
+        </View>
+        <TouchableOpacity style={styles.trashBtn} onPress={onDelete}>
+          <TrashSvg fill={Colors.WHITE} />
+        </TouchableOpacity>
+      </View>
+
+      <View style={styles.divider}></View>
+
+      <View style={styles.regionDatesContainer}>
+        <View style={styles.dateRow}>
+          <View style={{ flex: 1 }}>
+            <TouchableOpacity style={styles.regionSelector} onPress={onSelectDates}>
+              <CalendarSvg
+                fill={
+                  !region?.visitStartDate?.year || !region?.visitEndDate?.year
+                    ? Colors.TEXT_GRAY
+                    : Colors.DARK_BLUE
+                }
+                height={15}
+                width={15}
+              />
+              <Text
+                style={[
+                  styles.dateText,
+                  (!region?.visitStartDate?.year || !region?.visitEndDate?.year) &&
+                    styles.placeholderText
+                ]}
+              >
+                {datesLabel ?? 'Select visit dates'}
+              </Text>
+            </TouchableOpacity>
+
+            {errorMessage ? (
+              <Text style={{ color: Colors.RED, marginTop: 4, marginLeft: 4, fontSize: 12 }}>
+                {errorMessage}
+              </Text>
+            ) : null}
+          </View>
+
+          <View style={styles.actionsRow}>
+            <TouchableOpacity onPress={onMoveUp} style={styles.iconButton} disabled={index === 0}>
+              <MaterialCommunityIcons
+                name="arrow-up"
+                size={20}
+                color={index === 0 ? Colors.LIGHT_GRAY : Colors.DARK_BLUE}
+              />
+            </TouchableOpacity>
+
+            <TouchableOpacity
+              onPress={onMoveDown}
+              style={styles.iconButton}
+              disabled={index === total - 1}
+            >
+              <MaterialCommunityIcons
+                name="arrow-down"
+                size={20}
+                color={index === total - 1 ? Colors.LIGHT_GRAY : Colors.DARK_BLUE}
+              />
+            </TouchableOpacity>
+          </View>
+        </View>
+      </View>
+    </View>
+  );
+};
+
+export default RegionItem;

+ 168 - 0
src/screens/InAppScreens/TravelsScreen/Components/RegionItemNew/styles.tsx

@@ -0,0 +1,168 @@
+import { StyleSheet } from 'react-native';
+import { Colors } from 'src/theme';
+import { getFontSize } from 'src/utils';
+
+export const styles = StyleSheet.create({
+  regionItem: {
+    paddingVertical: 12,
+    paddingHorizontal: 16,
+    borderRadius: 8,
+    backgroundColor: Colors.FILL_LIGHT
+  },
+  regionItemTop: {
+    flexDirection: 'row',
+    alignItems: 'center',
+    justifyContent: 'space-between'
+  },
+  regionHeader: { flexDirection: 'row', alignItems: 'center', flex: 1 },
+  flagStyle: {
+    width: 32,
+    height: 32,
+    borderRadius: 16,
+    borderWidth: 1,
+    borderColor: Colors.LIGHT_GRAY,
+    marginRight: 12
+  },
+  nameContainer: {
+    flexShrink: 1
+  },
+  regionName: {
+    fontSize: 14,
+    fontWeight: 'bold',
+    color: Colors.DARK_BLUE
+  },
+  regionSubname: {
+    fontSize: 12,
+    fontWeight: '400',
+    color: Colors.DARK_BLUE
+  },
+  regionItemBottom: {
+    flexDirection: 'row',
+    alignItems: 'center',
+    gap: 16
+  },
+  qualityOfVisit: {
+    fontSize: 12,
+    color: Colors.DARK_BLUE,
+    fontWeight: '600',
+    marginBottom: 8
+  },
+  markCompletedButton: {
+    backgroundColor: Colors.ORANGE,
+    paddingVertical: 8,
+    paddingHorizontal: 12,
+    borderRadius: 6,
+    flex: 1,
+    alignItems: 'center',
+    borderWidth: 1,
+    borderColor: Colors.ORANGE
+  },
+  markNotCompletedButton: {
+    backgroundColor: 'transparent',
+    paddingVertical: 8,
+    paddingHorizontal: 12,
+    borderRadius: 6,
+    alignItems: 'center',
+    borderColor: Colors.BORDER_LIGHT,
+    borderWidth: 1,
+    flex: 1
+  },
+  markCompletedButtonText: {
+    color: 'white',
+    fontWeight: 'bold',
+    fontSize: 13
+  },
+  markNotCompletedButtonText: {
+    color: Colors.DARK_BLUE,
+    fontWeight: 'bold',
+    fontSize: 13
+  },
+  trashBtn: {
+    backgroundColor: Colors.RED,
+    padding: 8,
+    borderRadius: 50
+  },
+  qualitySelector: {
+    flexDirection: 'row',
+    alignItems: 'center',
+    paddingHorizontal: 12,
+    paddingVertical: 8,
+    borderRadius: 6,
+    backgroundColor: Colors.DARK_LIGHT,
+    justifyContent: 'space-between',
+    flex: 1
+  },
+  qualityButtonText: {
+    color: Colors.DARK_BLUE,
+    fontWeight: '600',
+    fontSize: 13
+  },
+  divider: { height: 1, backgroundColor: Colors.DARK_LIGHT, marginVertical: 16 },
+  completedContainer: { gap: 8, flexDirection: 'row', alignItems: 'center' },
+  regionDatesContainer: {
+    paddingBottom: 12
+  },
+  regionDatesLabel: {
+    fontSize: getFontSize(12),
+    color: Colors.DARK_BLUE,
+    marginBottom: 8,
+    fontWeight: '600'
+  },
+  dateRow: {
+    flexDirection: 'row',
+    alignItems: 'center',
+    gap: 12
+  },
+  dateColumn: {
+    flex: 1,
+    gap: 8
+  },
+  dateFieldLabel: {
+    fontSize: getFontSize(12),
+    color: Colors.DARK_BLUE,
+    fontWeight: '600'
+  },
+  dateInput: {
+    borderRadius: 6,
+    paddingHorizontal: 8,
+    paddingVertical: 6,
+    flexDirection: 'row',
+    alignItems: 'center',
+    justifyContent: 'space-between',
+    backgroundColor: Colors.DARK_LIGHT,
+    height: 36
+  },
+  regionSelector: {
+    flexDirection: 'row',
+    alignItems: 'center',
+    paddingHorizontal: 8,
+    borderRadius: 6,
+    height: 36,
+    backgroundColor: Colors.DARK_LIGHT,
+    justifyContent: 'flex-start',
+    gap: 6
+  },
+  dateText: {
+    fontSize: getFontSize(13),
+    color: Colors.DARK_BLUE,
+    fontWeight: '600'
+  },
+  placeholderText: {
+    color: Colors.TEXT_GRAY,
+    flexWrap: 'wrap'
+  },
+  regionActionsRow: {
+    flexDirection: 'row',
+    justifyContent: 'flex-end',
+    gap: 16,
+    marginTop: 8
+  },
+  actionsRow: {
+    flexDirection: 'row',
+    justifyContent: 'center',
+    gap: 8
+  },
+  iconButton: {
+    padding: 5
+  }
+});

+ 8 - 2
src/screens/InAppScreens/TravelsScreen/Components/TripItem/index.tsx

@@ -13,7 +13,7 @@ import CalendarIcon from 'assets/icons/travels-screens/calendar.svg';
 import EditIcon from 'assets/icons/travels-screens/pen-to-square.svg';
 import ArrowIcon from 'assets/icons/chevron-left.svg';
 
-const TripItem = ({ item }: { item: TripsData }) => {
+const TripItem = ({ item, isNew }: { item: TripsData; isNew?: boolean }) => {
   const navigation = useNavigation();
   const [showAllRegions, setShowAllRegions] = useState(false);
 
@@ -49,7 +49,13 @@ const TripItem = ({ item }: { item: TripsData }) => {
         <TouchableOpacity
           style={styles.editButton}
           onPress={() =>
-            navigation.navigate(...([NAVIGATION_PAGES.ADD_TRIP, { editTripId: item.id }] as never))
+            isNew
+              ? navigation.navigate(
+                  ...([NAVIGATION_PAGES.ADD_TRIP_2025, { editTripId: item.id }] as never)
+                )
+              : navigation.navigate(
+                  ...([NAVIGATION_PAGES.ADD_TRIP, { editTripId: item.id }] as never)
+                )
           }
         >
           <EditIcon />

+ 193 - 0
src/screens/InAppScreens/TravelsScreen/Trips2025Screen/index.tsx

@@ -0,0 +1,193 @@
+import React, { useCallback, useEffect, useState } from 'react';
+import { View, Text, TouchableOpacity, FlatList } from 'react-native';
+import { useFocusEffect, useNavigation } from '@react-navigation/native';
+
+import { PageWrapper, Header, Modal, FlatList as List, WarningModal } from 'src/components';
+import TripItem from '../Components/TripItem';
+
+import { useGetTripsYearsQuery, useGetTripsForYearQuery } from '@api/trips';
+import { StoreType, storage } from 'src/storage';
+import { TripsData } from '../utils/types';
+import { NAVIGATION_PAGES } from 'src/types';
+import { styles } from './styles';
+
+import ChevronIcon from '../../../../../assets/icons/travels-screens/chevron-bottom.svg';
+import AddIcon from '../../../../../assets/icons/travels-screens/circle-plus.svg';
+import TripSvg from '../../../../../assets/icons/travels-screens/trip.svg';
+import InfoIcon from 'assets/icons/info-solid.svg';
+import { Colors } from 'src/theme';
+
+const TripsScreen = ({ route }: { route: any }) => {
+  const token = storage.get('token', StoreType.STRING) as string;
+  const navigation = useNavigation();
+  const [isDatePickerVisible, setDatePickerVisible] = useState(false);
+  const { data: years, refetch } = useGetTripsYearsQuery(token, true);
+  const [selectedYear, setSelectedYear] = useState<string | null>(null);
+  const { data: tripsData, refetch: refetchTrips } = useGetTripsForYearQuery(
+    token,
+    selectedYear as string,
+    selectedYear ? true : false
+  );
+  const [trips, setTrips] = useState<TripsData[]>([]);
+  const [isWarningModalVisible, setIsWarningModalVisible] = useState(false);
+
+  useFocusEffect(
+    useCallback(() => {
+      const fetchData = async () => {
+        try {
+          await refetch();
+          await refetchTrips();
+        } catch (error) {
+          console.error(error);
+        }
+      };
+
+      if (route.params?.saved || route.params?.updated || route.params?.deleted) {
+        fetchData();
+        setIsWarningModalVisible(true);
+      }
+    }, [route.params])
+  );
+
+  useEffect(() => {
+    if (years && years.data && !selectedYear) {
+      setSelectedYear(years.data[0]);
+    }
+  }, [years]);
+
+  useEffect(() => {
+    if (!isWarningModalVisible) {
+      navigation.setParams({ saved: false, updated: false, deleted: false } as never);
+    }
+  }, [isWarningModalVisible]);
+
+  useEffect(() => {
+    if (tripsData && tripsData.trips) {
+      setTrips(tripsData.trips);
+    }
+  }, [tripsData]);
+
+  const renderItem = useCallback(({ item }: { item: TripsData }) => <TripItem item={item} isNew={true} />, []);
+
+  const onAddNewTripPress = useCallback(() => {
+    navigation.navigate(NAVIGATION_PAGES.ADD_TRIP_2025 as never);
+  }, [navigation]);
+
+  return (
+    <PageWrapper>
+      <Header label="Trips" />
+      <View style={styles.tabContainer}>
+        <TouchableOpacity style={styles.regionSelector} onPress={() => setDatePickerVisible(true)}>
+          <Text style={[styles.regionText]}>{selectedYear}</Text>
+          <ChevronIcon />
+        </TouchableOpacity>
+        <TouchableOpacity style={styles.addNewTab} onPress={onAddNewTripPress}>
+          <AddIcon />
+          <Text style={styles.addNewTabText}>Add New Trip</Text>
+        </TouchableOpacity>
+      </View>
+
+      <View
+        style={{
+          paddingHorizontal: 16,
+          paddingVertical: 16,
+          marginVertical: 8,
+          backgroundColor: Colors.FILL_LIGHT,
+          borderRadius: 8
+        }}
+      >
+        <Text
+          style={{
+            fontSize: 14,
+            fontFamily: 'montserrat-700',
+            color: Colors.DARK_BLUE,
+            paddingBottom: 6
+          }}
+        >
+          Annual statistic:
+        </Text>
+
+        <Text style={{ fontSize: 14, fontWeight: '600', color: Colors.DARK_BLUE }}>
+          X days travelled in total
+        </Text>
+
+        <Text style={{ fontSize: 14, fontWeight: '600', color: Colors.DARK_BLUE }}>
+          X countries visited
+        </Text>
+        <Text style={{ fontSize: 14, fontWeight: '600', color: Colors.DARK_BLUE }}>
+          X regions visited
+        </Text>
+
+        <Text style={{ fontSize: 14, fontWeight: '600', color: Colors.DARK_BLUE }}>
+          X days spent in Y country
+        </Text>
+        <Text style={{ fontSize: 14, fontWeight: '600', color: Colors.DARK_BLUE }}>
+          X days spent in Y region
+        </Text>
+
+        <Text style={{ fontSize: 14, fontWeight: '600', color: Colors.DARK_BLUE }}>
+          Countries by time spent ()
+        </Text>
+        <Text style={{ fontSize: 14, fontWeight: '600', color: Colors.DARK_BLUE }}>
+          Regions by time spent ()
+        </Text>
+      </View>
+
+      {trips.length === 0 ? (
+        <View style={styles.noTripsContainer}>
+          <View style={styles.noTripsIcon}>
+            <TripSvg fill={Colors.WHITE} />
+          </View>
+          <Text style={styles.noTripsText}>No trips at the moment</Text>
+        </View>
+      ) : (
+        <FlatList
+          data={trips}
+          renderItem={renderItem}
+          keyExtractor={(item, index) => `${item.id}-${index}`}
+          style={styles.tripsList}
+          contentContainerStyle={styles.tripsListContentContainer}
+          showsVerticalScrollIndicator={false}
+        />
+      )}
+
+      <Modal
+        onRequestClose={() => setDatePickerVisible(false)}
+        headerTitle={'Select Year'}
+        visible={isDatePickerVisible}
+      >
+        <List
+          itemObject={(object) => {
+            setSelectedYear(object);
+            setDatePickerVisible(false);
+          }}
+          initialData={years?.data}
+          date={true}
+        />
+      </Modal>
+      <WarningModal
+        type={'success'}
+        isVisible={isWarningModalVisible}
+        onClose={() => {
+          setIsWarningModalVisible(false);
+        }}
+        title={
+          route.params?.saved
+            ? 'Trip added'
+            : route.params?.deleted
+              ? 'Trip deleted'
+              : 'Trip updated'
+        }
+        message={
+          route.params?.saved
+            ? 'Trip was successfully added to your list of trips'
+            : route.params?.deleted
+              ? 'This trip was successfully deleted.'
+              : 'Trip was successfully updated'
+        }
+      />
+    </PageWrapper>
+  );
+};
+
+export default TripsScreen;

+ 49 - 0
src/screens/InAppScreens/TravelsScreen/Trips2025Screen/styles.tsx

@@ -0,0 +1,49 @@
+import { StyleSheet } from 'react-native';
+import { Colors } from 'src/theme';
+
+export const styles = StyleSheet.create({
+  tabContainer: { flexDirection: 'row', gap: 16, alignItems: 'center', marginBottom: 8 },
+  noTripsContainer: { flex: 1, alignItems: 'center', justifyContent: 'center', gap: 10 },
+  regionSelector: {
+    flexDirection: 'row',
+    alignItems: 'center',
+    justifyContent: 'space-between',
+    backgroundColor: Colors.FILL_LIGHT,
+    borderRadius: 4,
+    height: 34,
+    flex: 1,
+    paddingHorizontal: 16
+  },
+  regionText: {
+    fontSize: 14,
+    color: Colors.LIGHT_GRAY,
+    fontWeight: '500'
+  },
+  addNewTab: {
+    flex: 1,
+    backgroundColor: Colors.ORANGE,
+    height: 36,
+    borderRadius: 4,
+    flexDirection: 'row',
+    alignItems: 'center',
+    justifyContent: 'center',
+    paddingHorizontal: 16,
+    gap: 4
+  },
+  addNewTabText: { fontSize: 14, color: Colors.WHITE, fontWeight: 'bold' },
+  noTripsIcon: {
+    height: 256,
+    width: 256,
+    borderRadius: 128,
+    backgroundColor: Colors.FILL_LIGHT,
+    alignItems: 'center',
+    justifyContent: 'center'
+  },
+  noTripsText: { color: Colors.DARK_BLUE, fontSize: 11, fontWeight: '600' },
+  tripsList: {
+    flex: 1
+  },
+  tripsListContentContainer: {
+    paddingBottom: 16
+  }
+});

+ 25 - 0
src/screens/InAppScreens/TravelsScreen/index.tsx

@@ -32,6 +32,7 @@ const TravelsScreen = () => {
     { label: 'Series', icon: SeriesIcon, page: NAVIGATION_PAGES.SERIES },
     { label: 'Earth', icon: EarthIcon, page: NAVIGATION_PAGES.EARTH },
     { label: 'Trips', icon: TripIcon, page: NAVIGATION_PAGES.TRIPS },
+    { label: 'Trips 2025', icon: TripIcon, page: NAVIGATION_PAGES.TRIPS_2025 },
     { label: 'Photos', icon: ImagesIcon, page: NAVIGATION_PAGES.PHOTOS },
     { label: 'Fixers', icon: FixersIcon, page: NAVIGATION_PAGES.FIXERS }
   ];
@@ -52,6 +53,30 @@ const TravelsScreen = () => {
   const renderItem = ({ item }: { item: { label: string; icon: any; page: string } }) => (
     <TouchableOpacity style={{ alignItems: 'center' }} onPress={() => handlePress(item.page)}>
       <View style={styles.button}>
+        {item.page === NAVIGATION_PAGES.TRIPS_2025 && (
+          <View
+            style={{
+              backgroundColor: '#0f9113',
+              paddingHorizontal: 6,
+              paddingVertical: 2,
+              position: 'absolute',
+              top: -2,
+              right: -2,
+              borderRadius: 8
+            }}
+          >
+            <Text
+              style={{
+                color: Colors.WHITE,
+                fontSize: 10,
+                fontWeight: '600',
+                fontFamily: 'montserrat-600'
+              }}
+            >
+              Beta
+            </Text>
+          </View>
+        )}
         <item.icon
           fill={Colors.ORANGE}
           width={Dimensions.get('window').width < 380 ? 105 : 110}

+ 4 - 1
src/types/navigation.ts

@@ -42,8 +42,11 @@ export enum NAVIGATION_PAGES {
   MORE_PHOTOS = 'inAppMorePhotos',
   ADD_PHOTO = 'inAppAddPhoto',
   TRIPS = 'inAppTrips',
+  TRIPS_2025 = 'inAppTrips2025',
   ADD_TRIP = 'inAppAddTrip',
+  ADD_TRIP_2025 = 'inAppAddTrip2025',
   ADD_REGIONS = 'inAppAddRegions',
+  ADD_REGIONS_NEW = 'inAppAddRegionsNew',
   COUNTRIES = 'inAppCountries',
   REGIONS = 'inAppRegions',
   DARE = 'inAppDare',
@@ -88,5 +91,5 @@ export enum NAVIGATION_PAGES {
   EDIT_COUNTRY_DATA = 'inAppEditCountryData',
   IN_APP_EVENTS_TAB = 'Events',
   CREATE_SHARED_TRIP = 'inAppCreateSharedTrip',
-  EDIT_NM_DATA = 'inAppEditNmData',
+  EDIT_NM_DATA = 'inAppEditNmData'
 }