|
|
@@ -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;
|