Explorar o código

duplicate region for trip

Viktoriia hai 2 meses
pai
achega
de7261323f

+ 6 - 0
assets/icons/travels-screens/copy.svg

@@ -0,0 +1,6 @@
+<!-- Generated by IcoMoon.io -->
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="1024" height="1024" viewBox="0 0 1024 1024">
+<g id="icomoon-ignore">
+</g>
+<path d="M575.999 927.991h-447.99c-17.6 0-31.999-14.4-31.999-31.999v-447.99c0-17.6 14.4-31.999 31.999-31.999h95.998v-95.998h-95.998c-70.598 0-127.997 57.399-127.997 127.997v447.99c0 70.598 57.399 127.997 127.997 127.997h447.99c70.598 0 127.997-57.399 127.997-127.997v-95.998h-95.998v95.998c0 17.6-14.4 31.999-31.999 31.999zM448.001 607.998c-17.6 0-31.999-14.4-31.999-31.999v-447.99c0-17.6 14.4-31.999 31.999-31.999h447.99c17.6 0 31.999 14.4 31.999 31.999v447.99c0 17.6-14.4 31.999-31.999 31.999h-447.99zM320.004 575.999c0 70.598 57.399 127.997 127.997 127.997h447.99c70.598 0 127.997-57.399 127.997-127.997v-447.99c0-70.598-57.399-127.997-127.997-127.997h-447.99c-70.598 0-127.997 57.399-127.997 127.997v447.99z"></path>
+</svg>

+ 66 - 36
src/screens/InAppScreens/TravelsScreen/AddNewTripScreen/index.tsx

@@ -43,7 +43,7 @@ interface RegionWithDates extends RegionAddData {
 }
 
 interface DatePickerState {
-  regionId: number;
+  regionIndex: number;
   field: 'visitStartDate' | 'visitEndDate';
 }
 
@@ -241,11 +241,11 @@ const AddNewTripScreen = ({ route }: { route: any }) => {
   const days = getDaysInMonth(selectedYear, selectedMonth);
 
   const openDatePicker = (
-    regionId: number,
+    index: number,
     field: 'visitStartDate' | 'visitEndDate',
     initialDate?: DateValue | null
   ) => {
-    setShowDatePicker({ regionId, field });
+    setShowDatePicker({ regionIndex: index, field });
 
     if (initialDate && initialDate.year) {
       setSelectedYear(initialDate.year || null);
@@ -262,20 +262,19 @@ const AddNewTripScreen = ({ route }: { route: any }) => {
 
   const handleDateConfirm = () => {
     if (showDatePicker) {
+      const { regionIndex, field } = showDatePicker;
       const dateValue: DateValue = {
         year: selectedYear || null,
         month: selectedMonth || null,
         day: selectedDay || null
       };
 
-      setRegions(
-        (prevRegions) =>
-          prevRegions?.map((region) =>
-            region.id === showDatePicker.regionId
-              ? { ...region, [showDatePicker.field]: dateValue }
-              : region
-          ) || null
-      );
+      setRegions((prev) => {
+        if (!prev) return null;
+        const newRegions = [...prev];
+        newRegions[regionIndex] = { ...newRegions[regionIndex], [field]: dateValue };
+        return newRegions;
+      });
 
       setShowDatePicker(null);
       actionSheetRef.current?.hide();
@@ -287,32 +286,58 @@ const AddNewTripScreen = ({ route }: { route: any }) => {
     actionSheetRef.current?.hide();
   };
 
-  const changeQualityForRegion = (regionId: number | null, newQuality: number) => {
+  const changeQualityForRegion = (index: number | null, newQuality: number) => {
+    if (index === null || index === undefined) return;
+
     regions &&
-      setRegions(
-        regions.map((region) => {
-          if (region.id === regionId) {
-            return { ...region, quality: newQuality };
-          }
-          return region;
-        })
-      );
+      setRegions((prev) => {
+        if (!prev) return null;
+        const newRegions = [...prev];
+        newRegions[index] = { ...newRegions[index], quality: newQuality };
+        return newRegions;
+      });
   };
 
-  const changeHiddenForRegion = (regionId: number | null) => {
+  const changeHiddenForRegion = (index: number | null) => {
+    if (index === null || index === undefined) return;
+
     regions &&
-      setRegions(
-        regions.map((region) => {
-          if (region.id === regionId) {
-            return { ...region, hidden: !region.hidden };
-          }
-          return region;
-        })
-      );
+      setRegions((prev) => {
+        if (!prev) return null;
+        const newRegions = [...prev];
+        newRegions[index] = { ...newRegions[index], hidden: !newRegions[index].hidden };
+        return newRegions;
+      });
+  };
+
+  const duplicateRegion = (index: number) => {
+    if (!regions) return;
+    const regionToCopy = regions[index];
+    const copy = { ...regionToCopy };
+    const newRegions = [...regions];
+    newRegions.splice(index + 1, 0, copy);
+    setRegions(newRegions);
+  };
+
+  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 = (regionId: number) => {
-    regions && setRegions(regions.filter((region) => region.id !== regionId));
+  const handleDeleteRegion = (index: number) => {
+    if (!regions) return;
+    const updated = [...regions];
+    updated.splice(index, 1);
+    setRegions(updated);
   };
 
   const handleDeleteTrip = async () => {
@@ -428,20 +453,25 @@ const AddNewTripScreen = ({ route }: { route: any }) => {
           </TouchableOpacity>
           {regions && regions.length ? (
             <View style={styles.regionsContainer}>
-              {regions.map((region) => {
+              {regions.map((region, index) => {
                 return (
                   <RegionItem
-                    key={region.id}
+                    key={`${region.id}-${index}`}
                     region={region}
-                    onDelete={() => handleDeleteRegion(region.id)}
+                    index={index}
+                    total={regions.length}
+                    onDelete={() => handleDeleteRegion(index)}
                     onQualityChange={() => {
-                      setSelectedRegionId(region.id);
+                      setSelectedRegionId(index);
                       setQualitySelectorVisible(true);
                     }}
-                    onHiddenChange={() => changeHiddenForRegion(region.id)}
+                    onHiddenChange={() => changeHiddenForRegion(index)}
                     openDatePicker={openDatePicker}
                     visitStartDate={region.visitStartDate}
                     visitEndDate={region.visitEndDate}
+                    onDuplicate={() => duplicateRegion(index)}
+                    onMoveUp={() => moveRegionUp(index)}
+                    onMoveDown={() => moveRegionDown(index)}
                   />
                 );
               })}

+ 2 - 2
src/screens/InAppScreens/TravelsScreen/AddRegionsScreen/index.tsx

@@ -173,8 +173,8 @@ const AddRegionsScreen = ({ route }: { route: any }) => {
             const regionIndex = selectedRegions.findIndex((region) => region.id === id);
 
             if (regionIndex >= 0) {
-              const newSelectedRegions = [...selectedRegions];
-              newSelectedRegions.splice(regionIndex, 1);
+              let newSelectedRegions = [...selectedRegions];
+              newSelectedRegions = newSelectedRegions.filter((region) => region.id !== id);
               setSelectedRegions(newSelectedRegions);
               setRegionsToSave(regionsToSave.filter((region) => region.id !== id));
               setRegionPopupVisible(false);

+ 41 - 3
src/screens/InAppScreens/TravelsScreen/Components/RegionItem/index.tsx

@@ -12,6 +12,7 @@ import TrashSvg from 'assets/icons/travels-screens/trash-solid.svg';
 import ChevronIcon from 'assets/icons/travels-screens/down-arrow.svg';
 import CheckSvg from 'assets/icons/travels-screens/check.svg';
 import SquareSvg from 'assets/icons/travels-screens/square.svg';
+import CopySvg from 'assets/icons/travels-screens/copy.svg';
 
 interface DateValue {
   year: number | null;
@@ -28,10 +29,15 @@ interface RegionItemProps {
   visitEndDate?: DateValue | null;
   onDateChange?: (field: 'visitStartDate' | 'visitEndDate', dateValue: DateValue) => void;
   openDatePicker?: (
-    regionId: number,
+    index: number,
     field: 'visitStartDate' | 'visitEndDate',
     initialDate?: DateValue | null
   ) => void;
+  onDuplicate: () => void;
+  onMoveUp: () => void;
+  onMoveDown: () => void;
+  index: number;
+  total: number;
 }
 
 const RegionItem = ({
@@ -42,7 +48,12 @@ const RegionItem = ({
   visitStartDate,
   visitEndDate,
   onDateChange,
-  openDatePicker
+  openDatePicker,
+  onDuplicate,
+  onMoveUp,
+  onMoveDown,
+  index,
+  total
 }: RegionItemProps) => {
   const [name, ...rest] = region.region_name?.split(/ – | - /);
   const subname = rest?.join(' - ');
@@ -74,7 +85,7 @@ const RegionItem = ({
     (field: 'visitStartDate' | 'visitEndDate', currentDate: DateValue | null): JSX.Element => (
       <TouchableOpacity
         style={styles.dateInput}
-        onPress={() => openDatePicker?.(region.id, field, currentDate)}
+        onPress={() => openDatePicker?.(index, field, currentDate)}
       >
         <Text style={[styles.dateText, !isDateValid(currentDate) && styles.placeholderText]}>
           {formatDateForDisplay(currentDate)}
@@ -149,6 +160,33 @@ const RegionItem = ({
           </TouchableOpacity>
         </View>
       )}
+      <View style={styles.regionActionsRow}>
+        <TouchableOpacity onPress={onDuplicate} style={styles.iconButton}>
+          <CopySvg width={20} height={20} fill={Colors.DARK_BLUE} />
+        </TouchableOpacity>
+
+        <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>
   );
 };

+ 14 - 0
src/screens/InAppScreens/TravelsScreen/Components/RegionItem/styles.tsx

@@ -140,5 +140,19 @@ export const styles = StyleSheet.create({
   placeholderText: {
     color: Colors.TEXT_GRAY,
     flexWrap: 'wrap'
+  },
+  regionActionsRow: {
+    flexDirection: 'row',
+    justifyContent: 'space-between',
+    gap: 16,
+    marginTop: 8
+  },
+  actionsRow: {
+    flexDirection: 'row',
+    justifyContent: 'center',
+    gap: 16
+  },
+  iconButton: {
+    padding: 5
   }
 });

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

@@ -65,13 +65,13 @@ const TripItem = ({ item }: { item: TripsData }) => {
         horizontal={false}
         nestedScrollEnabled={true}
       >
-        {item.regions?.map((region) => {
+        {item.regions?.map((region, index) => {
           if (!region.id || !region.region_name) return null;
           const [name, ...rest] = region.region_name?.split(/ – | - /);
           const subname = rest?.join(' - ');
 
           return (
-            <View key={region.id} style={styles.regionItem}>
+            <View key={`${region.id}-${index}`} style={styles.regionItem}>
               <Image source={{ uri: API_HOST + region.flag1 }} style={styles.flagIcon} />
               {region.flag2 && (
                 <Image

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

@@ -108,7 +108,7 @@ const TripsScreen = ({ route }: { route: any }) => {
         <FlatList
           data={trips}
           renderItem={renderItem}
-          keyExtractor={(item) => item.id.toString()}
+          keyExtractor={(item, index) => `${item.id}-${index}`}
           style={styles.tripsList}
           contentContainerStyle={styles.tripsListContentContainer}
           showsVerticalScrollIndicator={false}