|
|
@@ -1,11 +1,11 @@
|
|
|
import React, { useEffect, useState } from 'react';
|
|
|
-import { View, Text, TouchableOpacity, ScrollView, Alert } from 'react-native';
|
|
|
+import { View, Text, TouchableOpacity, ScrollView } 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 RangeCalendarWithTabs, { CalendarMode } from 'src/components/Calendars/RangeCalendar/RangeCalendarWithTabs';
|
|
|
|
|
|
import { StoreType, storage } from 'src/storage';
|
|
|
import { Colors } from 'src/theme';
|
|
|
@@ -39,33 +39,39 @@ interface RegionWithDates extends RegionAddData {
|
|
|
month_to?: number;
|
|
|
day_from?: number | null;
|
|
|
day_to?: number | null;
|
|
|
+ dateMode?: CalendarMode;
|
|
|
}
|
|
|
|
|
|
+const CURRENT_YEAR = new Date().getFullYear();
|
|
|
+
|
|
|
+const isFullDate = (d?: DateValue | null): boolean =>
|
|
|
+ !!(d?.year && d?.month && d?.day);
|
|
|
+
|
|
|
+const isValidDate = (d?: DateValue | null): boolean => {
|
|
|
+ if (!d?.year) return false;
|
|
|
+ if (d.year === CURRENT_YEAR) return !!(d.month && d.day);
|
|
|
+ return true;
|
|
|
+};
|
|
|
+
|
|
|
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 [regionErrors, setRegionErrors] = useState<{ [instanceId: string]: string }>({});
|
|
|
const [shouldScrollToEmpty, setShouldScrollToEmpty] = useState(false);
|
|
|
|
|
|
const summarySheetRef = React.useRef<ActionSheetRef>(null);
|
|
|
-
|
|
|
- const [summaryData, setSummaryData] = useState({
|
|
|
- totalDays: 0,
|
|
|
- perRegion: []
|
|
|
- });
|
|
|
-
|
|
|
+ const [summaryData, setSummaryData] = useState({ totalDays: 0, perRegion: [] });
|
|
|
const [pendingAction, setPendingAction] = useState<'save' | 'update' | null>(null);
|
|
|
const isClosingRef = React.useRef<boolean>(null);
|
|
|
|
|
|
@@ -76,31 +82,38 @@ const AddNewTripScreen = ({ route }: { route: any }) => {
|
|
|
const scrollRef = React.useRef<ScrollView>(null);
|
|
|
const instanceCounterRef = React.useRef(1);
|
|
|
|
|
|
+ const getCalendarProps = (
|
|
|
+ index: number | null
|
|
|
+ ): { defaultMode: CalendarMode; initialApproxYear: number | null } => {
|
|
|
+ if (index === null || !regions?.[index]) {
|
|
|
+ return { defaultMode: 'exact', initialApproxYear: null };
|
|
|
+ }
|
|
|
+ const region = regions[index];
|
|
|
+ const start = region.visitStartDate;
|
|
|
+
|
|
|
+ const isYearOnly = start?.year && !start?.month && start.year !== CURRENT_YEAR;
|
|
|
+ if (isYearOnly || region.dateMode === 'approx') {
|
|
|
+ return { defaultMode: 'approx', initialApproxYear: start?.year ?? null };
|
|
|
+ }
|
|
|
+
|
|
|
+ return { defaultMode: 'exact', initialApproxYear: null };
|
|
|
+ };
|
|
|
+
|
|
|
const scrollToError = (errors: { [instanceId: string]: string }) => {
|
|
|
if (!regions || !Object.keys(errors).length) return;
|
|
|
const firstInstanceId = Object.keys(errors)[0];
|
|
|
const idx = regions.findIndex((r) => r._instanceId === firstInstanceId);
|
|
|
if (idx === -1) return;
|
|
|
- const itemHeight = 160;
|
|
|
- scrollRef.current?.scrollTo({ y: idx * itemHeight, animated: true });
|
|
|
+ scrollRef.current?.scrollTo({ y: idx * 160, animated: true });
|
|
|
};
|
|
|
|
|
|
const scrollToEmpty = () => {
|
|
|
if (!regions?.length) return;
|
|
|
-
|
|
|
- const idx = regions.findIndex((r) => {
|
|
|
- const startOK = isFullDate(r.visitStartDate);
|
|
|
- const endOK = isFullDate(r.visitEndDate);
|
|
|
- return !(startOK && endOK);
|
|
|
- });
|
|
|
-
|
|
|
+ const idx = regions.findIndex(
|
|
|
+ (r) => !isValidDate(r.visitStartDate) || !isValidDate(r.visitEndDate)
|
|
|
+ );
|
|
|
if (idx === -1) return;
|
|
|
-
|
|
|
- const itemHeight = 160;
|
|
|
- scrollRef.current?.scrollTo({
|
|
|
- y: idx * itemHeight,
|
|
|
- animated: true
|
|
|
- });
|
|
|
+ scrollRef.current?.scrollTo({ y: idx * 160, animated: true });
|
|
|
};
|
|
|
|
|
|
const computeTripSummary = (list: RegionWithDates[]) => {
|
|
|
@@ -112,7 +125,6 @@ const AddNewTripScreen = ({ route }: { route: any }) => {
|
|
|
|
|
|
if (isTransit) {
|
|
|
const key = `${r.id}_transit`;
|
|
|
-
|
|
|
if (!perRegionMap[key]) {
|
|
|
perRegionMap[key] = {
|
|
|
id: r.id,
|
|
|
@@ -123,7 +135,6 @@ const AddNewTripScreen = ({ route }: { route: any }) => {
|
|
|
flag2: r.flag2 ?? null
|
|
|
};
|
|
|
}
|
|
|
-
|
|
|
perRegionMap[key].days += 1;
|
|
|
continue;
|
|
|
}
|
|
|
@@ -135,7 +146,6 @@ const AddNewTripScreen = ({ route }: { route: any }) => {
|
|
|
|
|
|
let cursor = moment(startISO);
|
|
|
const end = moment(endISO);
|
|
|
-
|
|
|
let regionDays = 0;
|
|
|
|
|
|
while (cursor.isSameOrBefore(end)) {
|
|
|
@@ -145,22 +155,12 @@ const AddNewTripScreen = ({ route }: { route: any }) => {
|
|
|
}
|
|
|
|
|
|
if (!perRegionMap[r.id]) {
|
|
|
- perRegionMap[r.id] = {
|
|
|
- id: r.id,
|
|
|
- name: r.region_name,
|
|
|
- days: 0,
|
|
|
- flag1: r.flag1,
|
|
|
- flag2: r?.flag2
|
|
|
- };
|
|
|
+ perRegionMap[r.id] = { id: r.id, name: r.region_name, days: 0, flag1: r.flag1, flag2: r?.flag2 };
|
|
|
}
|
|
|
-
|
|
|
perRegionMap[r.id].days += regionDays;
|
|
|
}
|
|
|
|
|
|
- return {
|
|
|
- totalDays: daySet.size,
|
|
|
- perRegion: Object.values(perRegionMap)
|
|
|
- };
|
|
|
+ return { totalDays: daySet.size, perRegion: Object.values(perRegionMap) };
|
|
|
};
|
|
|
|
|
|
const normalizeRegion = (r: RegionWithDates): RegionWithDates => ({
|
|
|
@@ -172,21 +172,13 @@ const AddNewTripScreen = ({ route }: { route: any }) => {
|
|
|
|
|
|
const autoFillAfterAppend = (list: RegionWithDates[], oldCount: number) => {
|
|
|
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];
|
|
|
r._instanceId = `r-${instanceCounterRef.current++}`;
|
|
|
- if (
|
|
|
- r.visitStartDate?.year &&
|
|
|
- r.visitStartDate?.month &&
|
|
|
- r.visitStartDate?.day &&
|
|
|
- r.visitEndDate?.year &&
|
|
|
- r.visitEndDate?.month &&
|
|
|
- r.visitEndDate?.day
|
|
|
- ) {
|
|
|
+ if (isFullDate(r.visitStartDate) && isFullDate(r.visitEndDate)) {
|
|
|
lastWithDateIndex = i;
|
|
|
break;
|
|
|
}
|
|
|
@@ -198,11 +190,7 @@ const AddNewTripScreen = ({ route }: { route: any }) => {
|
|
|
|
|
|
for (let i = lastWithDateIndex + 1; i < updated.length; i++) {
|
|
|
const r = updated[i];
|
|
|
-
|
|
|
- const hasStart = isFullDate(r.visitStartDate);
|
|
|
- const hasEnd = isFullDate(r.visitEndDate);
|
|
|
-
|
|
|
- if (!hasStart || !hasEnd) {
|
|
|
+ if (!isFullDate(r.visitStartDate) || !isFullDate(r.visitEndDate)) {
|
|
|
updated[i] = {
|
|
|
...r,
|
|
|
_instanceId: `r-${instanceCounterRef.current++}`,
|
|
|
@@ -218,7 +206,6 @@ const AddNewTripScreen = ({ route }: { route: any }) => {
|
|
|
|
|
|
useEffect(() => {
|
|
|
if (!shouldScrollToEmpty || !regions) return;
|
|
|
-
|
|
|
requestAnimationFrame(() => {
|
|
|
scrollToEmpty();
|
|
|
setShouldScrollToEmpty(false);
|
|
|
@@ -231,7 +218,6 @@ const AddNewTripScreen = ({ route }: { route: any }) => {
|
|
|
const oldCount = oldRegions.length;
|
|
|
const normalized = route.params.regionsToSave.map(normalizeRegion);
|
|
|
const filled = autoFillAfterAppend(normalized, oldCount);
|
|
|
-
|
|
|
setRegions(filled);
|
|
|
setShouldScrollToEmpty(true);
|
|
|
}
|
|
|
@@ -249,6 +235,7 @@ const AddNewTripScreen = ({ route }: { route: any }) => {
|
|
|
setRegions(
|
|
|
editData.trip.regions.map((region: any) => {
|
|
|
const instanceId = `r-${instanceCounterRef.current++}`;
|
|
|
+ const hasYearOnly = region.year_from && !region.day_from;
|
|
|
return {
|
|
|
...region,
|
|
|
_instanceId: instanceId,
|
|
|
@@ -265,7 +252,8 @@ const AddNewTripScreen = ({ route }: { route: any }) => {
|
|
|
month: region.month_to || null,
|
|
|
day: region.day_to || null
|
|
|
},
|
|
|
- quality: region.quality ?? 3
|
|
|
+ quality: region.quality ?? 3,
|
|
|
+ dateMode: hasYearOnly ? 'approx' : 'exact'
|
|
|
};
|
|
|
})
|
|
|
);
|
|
|
@@ -282,8 +270,9 @@ const AddNewTripScreen = ({ route }: { route: any }) => {
|
|
|
return !d.month ? m.format('YYYY') : !d.day ? m.format('MMM YYYY') : m.format('D MMM YYYY');
|
|
|
};
|
|
|
|
|
|
- const dateValueToISO = (d?: DateValue | null) => {
|
|
|
- if (!d || !d.year) return null;
|
|
|
+ const dateValueToISO = (d?: DateValue | null): string | null => {
|
|
|
+ if (!d?.year) return null;
|
|
|
+ if (!d.month || !d.day) return `${d.year}-01-01`;
|
|
|
const mm = String(d.month).padStart(2, '0');
|
|
|
const dd = String(d.day).padStart(2, '0');
|
|
|
return `${d.year}-${mm}-${dd}`;
|
|
|
@@ -311,120 +300,122 @@ const AddNewTripScreen = ({ route }: { route: any }) => {
|
|
|
const e = r.visitEndDate;
|
|
|
const id = r._instanceId ?? `idx-${i}`;
|
|
|
|
|
|
- if (!s?.year || !s?.month || !s?.day) {
|
|
|
- errors[id] = 'Please select visit dates';
|
|
|
+ if (!isValidDate(s)) {
|
|
|
+ errors[id] = s?.year === CURRENT_YEAR
|
|
|
+ ? 'Current year requires a full date'
|
|
|
+ : 'Please select visit dates';
|
|
|
continue;
|
|
|
}
|
|
|
- if (!e?.year || !e?.month || !e?.day) {
|
|
|
- errors[id] = 'Please select visit dates';
|
|
|
+ if (!isValidDate(e)) {
|
|
|
+ errors[id] = e?.year === CURRENT_YEAR
|
|
|
+ ? 'Current year requires a full date'
|
|
|
+ : '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[id] = 'Start date cannot be after end date';
|
|
|
- continue;
|
|
|
+ if (isFullDate(s) && isFullDate(e)) {
|
|
|
+ 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[id] = 'Start date cannot be after end date';
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ if ((s?.year ?? 0) > (e?.year ?? 0)) {
|
|
|
+ errors[id] = 'Start year cannot be after end year';
|
|
|
+ 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 isFullDate = (d?: DateValue | null) => {
|
|
|
- return !!(d?.year && d?.month && d?.day);
|
|
|
- };
|
|
|
-
|
|
|
const openRangeCalendarForRegion = (index: number) => {
|
|
|
if (!regions) return;
|
|
|
setCalendarVisibleForIndex(index);
|
|
|
};
|
|
|
|
|
|
- const closeRangeCalendar = (startDate?: string | null, endDate?: string | null) => {
|
|
|
+ const closeRangeCalendar = (
|
|
|
+ startDate?: string | null,
|
|
|
+ endDate?: string | null,
|
|
|
+ approxYear?: number | null
|
|
|
+ ) => {
|
|
|
const clickedInstanceIndex = calendarVisibleForIndex;
|
|
|
setCalendarVisibleForIndex(null);
|
|
|
|
|
|
- if (clickedInstanceIndex === null || clickedInstanceIndex === undefined || !startDate) return;
|
|
|
-
|
|
|
- const startVal = parseISOToDateValue(startDate);
|
|
|
- const endVal = parseISOToDateValue(endDate ?? startDate);
|
|
|
-
|
|
|
- if (!startVal || !endVal) return;
|
|
|
+ if (clickedInstanceIndex === null || clickedInstanceIndex === undefined) return;
|
|
|
+ if (!startDate && !approxYear) return;
|
|
|
|
|
|
const openedInstanceId = regions?.[clickedInstanceIndex]?._instanceId;
|
|
|
- if (!openedInstanceId) {
|
|
|
- return;
|
|
|
+ if (!openedInstanceId) return;
|
|
|
+
|
|
|
+ let newStartDate: DateValue;
|
|
|
+ let newEndDate: DateValue;
|
|
|
+ let dateMode: CalendarMode;
|
|
|
+
|
|
|
+ if (approxYear) {
|
|
|
+ newStartDate = { year: approxYear, month: null, day: null };
|
|
|
+ newEndDate = { year: approxYear, month: null, day: null };
|
|
|
+ dateMode = 'approx';
|
|
|
+ } else {
|
|
|
+ const startVal = parseISOToDateValue(startDate);
|
|
|
+ const endVal = parseISOToDateValue(endDate ?? startDate);
|
|
|
+ if (!startVal || !endVal) return;
|
|
|
+ newStartDate = startVal;
|
|
|
+ newEndDate = endVal;
|
|
|
+ dateMode = 'exact';
|
|
|
}
|
|
|
|
|
|
const updatedBeforeSort = (regions ?? []).map((r) =>
|
|
|
r._instanceId === openedInstanceId
|
|
|
- ? { ...r, visitStartDate: startVal, visitEndDate: endVal }
|
|
|
+ ? { ...r, visitStartDate: newStartDate, visitEndDate: newEndDate, dateMode }
|
|
|
: r
|
|
|
);
|
|
|
|
|
|
- const sortKey = (r: RegionWithDates) => {
|
|
|
- const iso = dateValueToISO(r.visitStartDate);
|
|
|
- return iso ?? '9999-12-31';
|
|
|
- };
|
|
|
- const sorted = [...updatedBeforeSort].sort((a, b) => sortKey(a).localeCompare(sortKey(b)));
|
|
|
-
|
|
|
- const newIndex = sorted.findIndex((r) => r._instanceId === openedInstanceId);
|
|
|
-
|
|
|
- if (newIndex !== -1) {
|
|
|
- const next = sorted[newIndex + 1];
|
|
|
- if (next && !isFullDate(next.visitStartDate)) {
|
|
|
- sorted[newIndex + 1] = {
|
|
|
- ...next,
|
|
|
- visitStartDate: endVal,
|
|
|
- visitEndDate: endVal
|
|
|
- };
|
|
|
- }
|
|
|
- const prev = sorted[newIndex - 1];
|
|
|
- if (prev && !isFullDate(prev.visitStartDate)) {
|
|
|
- sorted[newIndex - 1] = {
|
|
|
- ...prev,
|
|
|
- visitStartDate: startVal,
|
|
|
- visitEndDate: startVal
|
|
|
- };
|
|
|
+ let sorted: RegionWithDates[];
|
|
|
+
|
|
|
+ if (dateMode === 'exact') {
|
|
|
+ const sortKey = (r: RegionWithDates) => dateValueToISO(r.visitStartDate) ?? '9999-12-31';
|
|
|
+ sorted = [...updatedBeforeSort].sort((a, b) => sortKey(a).localeCompare(sortKey(b)));
|
|
|
+
|
|
|
+ const newIndex = sorted.findIndex((r) => r._instanceId === openedInstanceId);
|
|
|
+ if (newIndex !== -1) {
|
|
|
+ const next = sorted[newIndex + 1];
|
|
|
+ if (next && !isFullDate(next.visitStartDate)) {
|
|
|
+ sorted[newIndex + 1] = { ...next, visitStartDate: newEndDate, visitEndDate: newEndDate };
|
|
|
+ }
|
|
|
+ const prev = sorted[newIndex - 1];
|
|
|
+ if (prev && !isFullDate(prev.visitStartDate)) {
|
|
|
+ sorted[newIndex - 1] = { ...prev, visitStartDate: newStartDate, visitEndDate: newStartDate };
|
|
|
+ }
|
|
|
}
|
|
|
+ } else {
|
|
|
+ sorted = updatedBeforeSort;
|
|
|
}
|
|
|
|
|
|
setRegions(sorted);
|
|
|
-
|
|
|
validateRegionsDates(sorted);
|
|
|
-
|
|
|
setRegionErrors((prev) => {
|
|
|
const clone = { ...prev };
|
|
|
- delete clone[clickedInstanceIndex];
|
|
|
+ delete clone[openedInstanceId];
|
|
|
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 r = [...regions];
|
|
|
+ [r[index - 1], r[index]] = [r[index], r[index - 1]];
|
|
|
+ setRegions(r);
|
|
|
};
|
|
|
|
|
|
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 r = [...regions];
|
|
|
+ [r[index + 1], r[index]] = [r[index], r[index + 1]];
|
|
|
+ setRegions(r);
|
|
|
};
|
|
|
|
|
|
const handleDeleteRegion = (index: number) => {
|
|
|
@@ -442,16 +433,25 @@ const AddNewTripScreen = ({ route }: { route: any }) => {
|
|
|
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 starts = regionsList
|
|
|
+ .map((r) => dateValueToISO(r.visitStartDate))
|
|
|
+ .filter((v): v is string => v !== null);
|
|
|
+ const ends = regionsList
|
|
|
+ .map((r) => dateValueToISO(r.visitEndDate))
|
|
|
+ .filter((v): v is string => v !== null);
|
|
|
+
|
|
|
+ if (!starts.length || !ends.length) return { date_from: null, date_to: null };
|
|
|
+
|
|
|
+ const toComparableStart = (v: string) =>
|
|
|
+ v.length === 4 ? `${v}-01-01` : v;
|
|
|
+ const toComparableEnd = (v: string) =>
|
|
|
+ v.length === 4 ? `${v}-12-31` : v;
|
|
|
|
|
|
- const minStart = starts.reduce(
|
|
|
- (acc, cur) => (!acc || cur < acc ? cur : acc),
|
|
|
- null as string | null
|
|
|
+ const minStart = starts.reduce((acc, cur) =>
|
|
|
+ toComparableStart(cur) < toComparableStart(acc) ? cur : acc
|
|
|
);
|
|
|
- const maxEnd = ends.reduce(
|
|
|
- (acc, cur) => (!acc || cur > acc ? cur : acc),
|
|
|
- null as string | null
|
|
|
+ const maxEnd = ends.reduce((acc, cur) =>
|
|
|
+ toComparableEnd(cur) > toComparableEnd(acc) ? cur : acc
|
|
|
);
|
|
|
|
|
|
return { date_from: minStart, date_to: maxEnd };
|
|
|
@@ -462,45 +462,32 @@ const AddNewTripScreen = ({ route }: { route: any }) => {
|
|
|
|
|
|
try {
|
|
|
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 regionsData = regions.map((region) => ({
|
|
|
+ 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
|
|
|
+ }));
|
|
|
const { date_from, date_to } = computePayloadDates(regions);
|
|
|
|
|
|
saveNewTrip(
|
|
|
- {
|
|
|
- token,
|
|
|
- date_from,
|
|
|
- date_to,
|
|
|
- description,
|
|
|
- regions: regionsData
|
|
|
- },
|
|
|
+ { token, date_from, date_to, description, regions: regionsData },
|
|
|
{
|
|
|
onSuccess: (res) => {
|
|
|
+ console.log('res', res)
|
|
|
if (res && res.result === 'OK') {
|
|
|
navigation.popTo(...([NAVIGATION_PAGES.TRIPS_2025, { saved: true }] as never));
|
|
|
}
|
|
|
setIsLoading(null);
|
|
|
},
|
|
|
- onError: () => {
|
|
|
- setIsLoading(null);
|
|
|
+ onError: (err) => {
|
|
|
+ setIsLoading(null)
|
|
|
+ console.log('err', err)
|
|
|
}
|
|
|
}
|
|
|
);
|
|
|
@@ -511,40 +498,22 @@ const AddNewTripScreen = ({ route }: { route: any }) => {
|
|
|
|
|
|
const performUpdateTrip = async () => {
|
|
|
if (!regions) return;
|
|
|
-
|
|
|
try {
|
|
|
setIsLoading('update');
|
|
|
- const regionsData = regions.map((region) => {
|
|
|
- return {
|
|
|
- id: region.id,
|
|
|
- quality: region.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 regionsData = regions.map((region) => ({
|
|
|
+ id: region.id,
|
|
|
+ quality: region.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
|
|
|
+ }));
|
|
|
const { date_from, date_to } = computePayloadDates(regions);
|
|
|
-
|
|
|
updateTrip(
|
|
|
- {
|
|
|
- token,
|
|
|
- trip_id: editTripId,
|
|
|
- date_from,
|
|
|
- date_to,
|
|
|
- description,
|
|
|
- regions: regionsData
|
|
|
- },
|
|
|
+ { token, trip_id: editTripId, date_from, date_to, description, regions: regionsData },
|
|
|
{
|
|
|
onSuccess: (res) => {
|
|
|
if (res && res.result === 'OK') {
|
|
|
@@ -552,9 +521,7 @@ const AddNewTripScreen = ({ route }: { route: any }) => {
|
|
|
}
|
|
|
setIsLoading(null);
|
|
|
},
|
|
|
- onError: () => {
|
|
|
- setIsLoading(null);
|
|
|
- }
|
|
|
+ onError: () => setIsLoading(null)
|
|
|
}
|
|
|
);
|
|
|
} catch (err) {
|
|
|
@@ -563,49 +530,40 @@ const AddNewTripScreen = ({ route }: { route: any }) => {
|
|
|
};
|
|
|
|
|
|
const handleSaveNewTrip = () => {
|
|
|
- if (regions) {
|
|
|
- if (!validateRegionsDates(regions)) {
|
|
|
- scrollToError(regionErrors);
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- const summary = computeTripSummary(regions);
|
|
|
- if (summary) {
|
|
|
- setSummaryData({
|
|
|
- ...summary,
|
|
|
- perRegion: summary.perRegion?.sort((a: any, b: any) => b.days - a.days) || []
|
|
|
- });
|
|
|
- } else {
|
|
|
- setSummaryData({ totalDays: 0, perRegion: [] });
|
|
|
- }
|
|
|
- setPendingAction('save');
|
|
|
-
|
|
|
- summarySheetRef.current?.show();
|
|
|
+ if (!regions) return;
|
|
|
+ if (!validateRegionsDates(regions)) {
|
|
|
+ scrollToError(regionErrors);
|
|
|
+ return;
|
|
|
}
|
|
|
+ const summary = computeTripSummary(regions);
|
|
|
+ if (summary.totalDays === 0) {
|
|
|
+ performSaveNewTrip();
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ setSummaryData({ ...summary, perRegion: summary.perRegion?.sort((a: any, b: any) => b.days - a.days) || [] });
|
|
|
+ setPendingAction('save');
|
|
|
+ summarySheetRef.current?.show();
|
|
|
};
|
|
|
|
|
|
const handleUpdateTrip = () => {
|
|
|
- if (regions) {
|
|
|
- if (!validateRegionsDates(regions)) {
|
|
|
- scrollToError(regionErrors);
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- const summary = computeTripSummary(regions);
|
|
|
- if (summary) {
|
|
|
- setSummaryData({
|
|
|
- ...summary,
|
|
|
- perRegion: summary.perRegion?.sort((a: any, b: any) => b.days - a.days) || []
|
|
|
- });
|
|
|
- } else {
|
|
|
- setSummaryData({ totalDays: 0, perRegion: [] });
|
|
|
- }
|
|
|
- setPendingAction('update');
|
|
|
-
|
|
|
- summarySheetRef.current?.show();
|
|
|
+ if (!regions) return;
|
|
|
+ if (!validateRegionsDates(regions)) {
|
|
|
+ scrollToError(regionErrors);
|
|
|
+ return;
|
|
|
}
|
|
|
+ const summary = computeTripSummary(regions);
|
|
|
+ if (summary.totalDays === 0) {
|
|
|
+ performUpdateTrip();
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ setSummaryData({ ...summary, perRegion: summary.perRegion?.sort((a: any, b: any) => b.days - a.days) || [] });
|
|
|
+ setPendingAction('update');
|
|
|
+ summarySheetRef.current?.show();
|
|
|
};
|
|
|
|
|
|
+ const calendarProps = getCalendarProps(calendarVisibleForIndex);
|
|
|
+
|
|
|
return (
|
|
|
<PageWrapper style={{ flex: 1 }}>
|
|
|
<Header label={editTripId ? 'Edit Trip' : 'Add New Trip'} />
|
|
|
@@ -632,9 +590,8 @@ const AddNewTripScreen = ({ route }: { route: any }) => {
|
|
|
const startLabel = formatDateForDisplay(region.visitStartDate);
|
|
|
const endLabel = formatDateForDisplay(region.visitEndDate);
|
|
|
const datesLabel =
|
|
|
- region.visitStartDate?.year &&
|
|
|
- region.visitEndDate?.year &&
|
|
|
- dateValueToISO(region.visitStartDate) === dateValueToISO(region.visitEndDate)
|
|
|
+ region.visitStartDate?.year && region.visitEndDate?.year &&
|
|
|
+ dateValueToISO(region.visitStartDate) === dateValueToISO(region.visitEndDate)
|
|
|
? startLabel
|
|
|
: region.visitStartDate?.year && region.visitEndDate?.year
|
|
|
? `${startLabel} - ${endLabel}`
|
|
|
@@ -729,36 +686,32 @@ const AddNewTripScreen = ({ route }: { route: any }) => {
|
|
|
</View>
|
|
|
</View>
|
|
|
|
|
|
- <RangeCalendar
|
|
|
+ <RangeCalendarWithTabs
|
|
|
isModalVisible={calendarVisibleForIndex !== null}
|
|
|
allowRangeSelection={true}
|
|
|
- closeModal={(startDate?: string | null, endDate?: string | null) =>
|
|
|
- closeRangeCalendar(startDate, endDate)
|
|
|
- }
|
|
|
+ closeModal={closeRangeCalendar}
|
|
|
+ defaultMode={calendarProps.defaultMode}
|
|
|
+ initialApproxYear={calendarProps.initialApproxYear}
|
|
|
initialStartDate={
|
|
|
calendarVisibleForIndex !== null &&
|
|
|
- regions?.[calendarVisibleForIndex]?.visitStartDate &&
|
|
|
- regions[calendarVisibleForIndex].visitStartDate?.day
|
|
|
- ? `${regions[calendarVisibleForIndex].visitStartDate.year}-${regions[calendarVisibleForIndex].visitStartDate.month}-${regions[calendarVisibleForIndex].visitStartDate.day}`
|
|
|
+ regions?.[calendarVisibleForIndex]?.visitStartDate?.day
|
|
|
+ ? `${regions[calendarVisibleForIndex].visitStartDate!.year}-${regions[calendarVisibleForIndex].visitStartDate!.month}-${regions[calendarVisibleForIndex].visitStartDate!.day}`
|
|
|
: undefined
|
|
|
}
|
|
|
initialEndDate={
|
|
|
calendarVisibleForIndex !== null &&
|
|
|
- regions?.[calendarVisibleForIndex]?.visitEndDate &&
|
|
|
- regions[calendarVisibleForIndex].visitEndDate?.day
|
|
|
- ? `${regions[calendarVisibleForIndex].visitEndDate.year}-${regions[calendarVisibleForIndex].visitEndDate.month}-${regions[calendarVisibleForIndex].visitEndDate.day}`
|
|
|
+ regions?.[calendarVisibleForIndex]?.visitEndDate?.day
|
|
|
+ ? `${regions[calendarVisibleForIndex].visitEndDate!.year}-${regions[calendarVisibleForIndex].visitEndDate!.month}-${regions[calendarVisibleForIndex].visitEndDate!.day}`
|
|
|
: undefined
|
|
|
}
|
|
|
initialYear={
|
|
|
- calendarVisibleForIndex !== null &&
|
|
|
- regions?.[calendarVisibleForIndex]?.visitStartDate?.year
|
|
|
- ? regions[calendarVisibleForIndex].visitStartDate.year
|
|
|
+ calendarVisibleForIndex !== null
|
|
|
+ ? regions?.[calendarVisibleForIndex]?.visitStartDate?.year ?? undefined
|
|
|
: undefined
|
|
|
}
|
|
|
initialMonth={
|
|
|
- calendarVisibleForIndex !== null &&
|
|
|
- regions?.[calendarVisibleForIndex]?.visitStartDate?.month
|
|
|
- ? regions[calendarVisibleForIndex].visitStartDate.month
|
|
|
+ calendarVisibleForIndex !== null
|
|
|
+ ? regions?.[calendarVisibleForIndex]?.visitStartDate?.month ?? undefined
|
|
|
: undefined
|
|
|
}
|
|
|
withHint={true}
|