|
@@ -0,0 +1,359 @@
|
|
|
+import React, { useEffect, useState } from 'react';
|
|
|
+import { View, Text, TouchableOpacity, ScrollView } from 'react-native';
|
|
|
+import ReactModal from 'react-native-modal';
|
|
|
+import { useNavigation } from '@react-navigation/native';
|
|
|
+
|
|
|
+import { PageWrapper, Header, Input, WarningModal } from 'src/components';
|
|
|
+import RegionItem from '../Components/RegionItem';
|
|
|
+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 { qualityOptions } from '../utils/constants';
|
|
|
+import { styles } from './styles';
|
|
|
+
|
|
|
+import CalendarSvg from '../../../../../assets/icons/calendar.svg';
|
|
|
+
|
|
|
+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 [calendarVisible, setCalendarVisible] = useState(false);
|
|
|
+ const [selectedDates, setSelectedDates] = useState<string | null>(null);
|
|
|
+ const [description, setDescription] = useState<string>('');
|
|
|
+ const [regions, setRegions] = useState<RegionAddData[] | null>(null);
|
|
|
+ const [disabled, setDisabled] = useState(true);
|
|
|
+ const [qualitySelectorVisible, setQualitySelectorVisible] = useState(false);
|
|
|
+ const [selectedRegionId, setSelectedRegionId] = useState<number | null>(null);
|
|
|
+ const [isWarningModalVisible, setIsWarningModalVisible] = useState(false);
|
|
|
+
|
|
|
+ const { mutate: saveNewTrip } = usePostSetNewTripMutation();
|
|
|
+ const { mutate: updateTrip } = usePostUpdateTripMutation();
|
|
|
+ const { mutate: deleteTrip } = usePostDeleteTripMutation();
|
|
|
+
|
|
|
+ useEffect(() => {
|
|
|
+ if (route.params?.regionsToSave) {
|
|
|
+ setRegions((currentRegions) => {
|
|
|
+ const newRegionsIds = route.params.regionsToSave.map((region: RegionAddData) => region.id);
|
|
|
+ const existingRegions = currentRegions?.filter((region) =>
|
|
|
+ newRegionsIds.includes(region.id)
|
|
|
+ );
|
|
|
+
|
|
|
+ const updatedRegions = route.params.regionsToSave.map((newRegion: RegionAddData) => {
|
|
|
+ const existingRegion = existingRegions?.find((region) => region.id === newRegion.id);
|
|
|
+
|
|
|
+ return {
|
|
|
+ ...newRegion,
|
|
|
+ quality: existingRegion ? existingRegion.quality : 3,
|
|
|
+ status: existingRegion ? existingRegion.status : 0,
|
|
|
+ can_be_hidden: existingRegion ? existingRegion.can_be_hidden : newRegion.hidden,
|
|
|
+ hidden: existingRegion ? existingRegion.hidden : false
|
|
|
+ };
|
|
|
+ });
|
|
|
+
|
|
|
+ return updatedRegions;
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }, [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) {
|
|
|
+ setSelectedDates(editData.trip.date_from + ' - ' + editData.trip.date_to);
|
|
|
+ setDescription(editData.trip.description);
|
|
|
+ setRegions(
|
|
|
+ editData.trip.regions.map((region: any) => {
|
|
|
+ return {
|
|
|
+ ...region,
|
|
|
+ flag1: extractNumberAndExtension(region.flag1),
|
|
|
+ flag2: extractNumberAndExtension(region.flag2)
|
|
|
+ };
|
|
|
+ })
|
|
|
+ );
|
|
|
+ }
|
|
|
+ }, [editData]);
|
|
|
+
|
|
|
+ useEffect(() => {
|
|
|
+ if (regions?.length && selectedDates) {
|
|
|
+ setDisabled(false);
|
|
|
+ } else {
|
|
|
+ setDisabled(true);
|
|
|
+ }
|
|
|
+ }, [regions, selectedDates]);
|
|
|
+
|
|
|
+ const changeQualityForRegion = (regionId: number | null, newQuality: number) => {
|
|
|
+ regions &&
|
|
|
+ setRegions(
|
|
|
+ regions.map((region) => {
|
|
|
+ if (region.id === regionId) {
|
|
|
+ return { ...region, quality: newQuality };
|
|
|
+ }
|
|
|
+ return region;
|
|
|
+ })
|
|
|
+ );
|
|
|
+ };
|
|
|
+
|
|
|
+ const changeStatusForRegion = (regionId: number | null) => {
|
|
|
+ regions &&
|
|
|
+ setRegions(
|
|
|
+ regions.map((region) => {
|
|
|
+ if (region.id === regionId) {
|
|
|
+ return { ...region, status: region.status === 1 ? 0 : 1 };
|
|
|
+ }
|
|
|
+ return region;
|
|
|
+ })
|
|
|
+ );
|
|
|
+ };
|
|
|
+
|
|
|
+ const changeHiddenForRegion = (regionId: number | null) => {
|
|
|
+ regions &&
|
|
|
+ setRegions(
|
|
|
+ regions.map((region) => {
|
|
|
+ if (region.id === regionId) {
|
|
|
+ return { ...region, hidden: !region.hidden };
|
|
|
+ }
|
|
|
+ return region;
|
|
|
+ })
|
|
|
+ );
|
|
|
+ };
|
|
|
+
|
|
|
+ const handleDeleteRegion = (regionId: number) => {
|
|
|
+ regions && setRegions(regions.filter((region) => region.id !== regionId));
|
|
|
+ };
|
|
|
+
|
|
|
+ const handleDeleteTrip = () => {
|
|
|
+ deleteTrip(
|
|
|
+ {
|
|
|
+ token,
|
|
|
+ trip_id: editTripId
|
|
|
+ },
|
|
|
+ {
|
|
|
+ onSuccess: () => {
|
|
|
+ setIsWarningModalVisible(false);
|
|
|
+ navigation.navigate(...([NAVIGATION_PAGES.TRIPS, { deleted: true }] as never));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ );
|
|
|
+ };
|
|
|
+
|
|
|
+ const handleSaveNewTrip = () => {
|
|
|
+ if (regions && selectedDates) {
|
|
|
+ const isStartDateInFuture =
|
|
|
+ selectedDates.split(' - ')[0] > new Date().toISOString().split('T')[0];
|
|
|
+ const regionsData = regions.map((region) => {
|
|
|
+ return {
|
|
|
+ id: region.id,
|
|
|
+ quality: region.quality ?? 3,
|
|
|
+ status: isStartDateInFuture ? 0 : (Number(region.status) as 0 | 1),
|
|
|
+ hidden: region.hidden
|
|
|
+ };
|
|
|
+ });
|
|
|
+
|
|
|
+ saveNewTrip(
|
|
|
+ {
|
|
|
+ token,
|
|
|
+ date_from: selectedDates.split(' - ')[0],
|
|
|
+ date_to: selectedDates.split(' - ')[1],
|
|
|
+ description,
|
|
|
+ regions: regionsData
|
|
|
+ },
|
|
|
+ {
|
|
|
+ onSuccess: () => {
|
|
|
+ navigation.navigate(...([NAVIGATION_PAGES.TRIPS, { saved: true }] as never));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ );
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ const handleUpdateTrip = () => {
|
|
|
+ if (regions && selectedDates) {
|
|
|
+ const isStartDateInFuture =
|
|
|
+ selectedDates.split(' - ')[0] > new Date().toISOString().split('T')[0];
|
|
|
+ const regionsData = regions.map((region) => {
|
|
|
+ return {
|
|
|
+ id: region.id,
|
|
|
+ quality: region.quality ?? 3,
|
|
|
+ status: isStartDateInFuture ? 0 : (Number(region.status) as 0 | 1),
|
|
|
+ hidden: region.hidden
|
|
|
+ };
|
|
|
+ });
|
|
|
+
|
|
|
+ updateTrip(
|
|
|
+ {
|
|
|
+ token,
|
|
|
+ trip_id: editTripId,
|
|
|
+ date_from: selectedDates.split(' - ')[0],
|
|
|
+ date_to: selectedDates.split(' - ')[1],
|
|
|
+ description,
|
|
|
+ regions: regionsData
|
|
|
+ },
|
|
|
+ {
|
|
|
+ onSuccess: (res) => {
|
|
|
+ navigation.navigate(...([NAVIGATION_PAGES.TRIPS, { updated: true }] as never));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ );
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ return (
|
|
|
+ <PageWrapper style={{ flex: 1 }}>
|
|
|
+ <Header label={editTripId ? 'Edit Trip' : 'Add New Trip'} />
|
|
|
+ <ScrollView
|
|
|
+ contentContainerStyle={{ flexGrow: 1, gap: 16 }}
|
|
|
+ showsVerticalScrollIndicator={false}
|
|
|
+ >
|
|
|
+ <TouchableOpacity style={styles.regionSelector} onPress={() => setCalendarVisible(true)}>
|
|
|
+ <CalendarSvg />
|
|
|
+ <Text style={styles.regionText}>{selectedDates ?? 'Add dates'}</Text>
|
|
|
+ </TouchableOpacity>
|
|
|
+
|
|
|
+ <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,
|
|
|
+ { regionsParams: regions, editId: editTripId }
|
|
|
+ ] as never)
|
|
|
+ )
|
|
|
+ }
|
|
|
+ >
|
|
|
+ <Text style={styles.addRegionBtntext}>Add Region</Text>
|
|
|
+ </TouchableOpacity>
|
|
|
+ {regions && regions.length ? (
|
|
|
+ <View style={styles.regionsContainer}>
|
|
|
+ {regions.map((region) => {
|
|
|
+ return (
|
|
|
+ <RegionItem
|
|
|
+ key={region.id}
|
|
|
+ region={region}
|
|
|
+ onDelete={() => handleDeleteRegion(region.id)}
|
|
|
+ onToggleStatus={() => changeStatusForRegion(region.id)}
|
|
|
+ onQualityChange={() => {
|
|
|
+ setSelectedRegionId(region.id);
|
|
|
+ setQualitySelectorVisible(true);
|
|
|
+ }}
|
|
|
+ onHiddenChange={() => changeHiddenForRegion(region.id)}
|
|
|
+ startDate={selectedDates ? selectedDates.split(' - ')[0] : null}
|
|
|
+ />
|
|
|
+ );
|
|
|
+ })}
|
|
|
+ </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)}
|
|
|
+ >
|
|
|
+ <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}
|
|
|
+ >
|
|
|
+ <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}
|
|
|
+ >
|
|
|
+ <Text style={[styles.tabText, styles.addNewTabText]}>Add New Trip</Text>
|
|
|
+ </TouchableOpacity>
|
|
|
+ )}
|
|
|
+ </View>
|
|
|
+
|
|
|
+ <RangeCalendar
|
|
|
+ isModalVisible={calendarVisible}
|
|
|
+ closeModal={(startDate?: Date | null, endDate?: Date | null) => {
|
|
|
+ startDate &&
|
|
|
+ setSelectedDates(
|
|
|
+ startDate.toString() + ' - ' + (endDate ? endDate?.toString() : startDate?.toString())
|
|
|
+ );
|
|
|
+ setCalendarVisible(false);
|
|
|
+ }}
|
|
|
+ />
|
|
|
+ <ReactModal
|
|
|
+ isVisible={qualitySelectorVisible}
|
|
|
+ onBackdropPress={() => setQualitySelectorVisible(false)}
|
|
|
+ style={styles.modal}
|
|
|
+ statusBarTranslucent={true}
|
|
|
+ presentationStyle="overFullScreen"
|
|
|
+ >
|
|
|
+ <View style={styles.wrapper}>
|
|
|
+ <View style={{ paddingBottom: 16 }}>
|
|
|
+ {qualityOptions.map((option) => (
|
|
|
+ <TouchableOpacity
|
|
|
+ key={option.id}
|
|
|
+ style={styles.btnOption}
|
|
|
+ onPress={() => {
|
|
|
+ setQualitySelectorVisible(false);
|
|
|
+ changeQualityForRegion(selectedRegionId, option.id);
|
|
|
+ }}
|
|
|
+ >
|
|
|
+ <Text style={styles.btnOptionText}>{option.name}</Text>
|
|
|
+ </TouchableOpacity>
|
|
|
+ ))}
|
|
|
+ </View>
|
|
|
+ </View>
|
|
|
+ </ReactModal>
|
|
|
+ <WarningModal
|
|
|
+ type={'delete'}
|
|
|
+ isVisible={isWarningModalVisible}
|
|
|
+ onClose={() => setIsWarningModalVisible(false)}
|
|
|
+ title="Delete Trip"
|
|
|
+ message="Are you sure you want to delete your trip?"
|
|
|
+ action={handleDeleteTrip}
|
|
|
+ />
|
|
|
+ </PageWrapper>
|
|
|
+ );
|
|
|
+};
|
|
|
+
|
|
|
+export default AddNewTripScreen;
|