| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239 |
- import React, { useState } from 'react';
- import { View, Text, TouchableOpacity, Image } from 'react-native';
- import { useNavigation } from '@react-navigation/native';
- import moment from 'moment';
- import { TripsData } from '../../utils/types';
- import { API_HOST } from 'src/constants';
- import { Colors } from 'src/theme';
- import { NAVIGATION_PAGES } from 'src/types';
- import { styles } from './styles';
- 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';
- import WarningIcon from 'assets/icons/warning.svg';
- const formatDate = (dateString: string | null) => {
- if (!dateString) return;
- const date = moment(dateString);
- const formattedDate = date.format('MMM DD');
- const year = date.format('YYYY');
- return (
- <Text style={styles.alignCenter}>
- <Text style={styles.tripDateText}>{formattedDate}</Text>
- {'\n'}
- <Text style={styles.tripDateText}>{year}</Text>
- </Text>
- );
- };
- const getValidDate = (value?: string | null) => {
- if (!value) return null;
- const date = moment(value);
- return date.isValid() ? date : null;
- };
- const formatSingleLineDate = (dateString: string | null) => {
- const date = getValidDate(dateString);
- if (!date) return null;
- return `${date.format('MMM DD')} ${date.format('YYYY')}`;
- };
- const renderMissingDatesWarning = (withMarginBottom = true) => (
- <View
- style={{
- flexDirection: 'row',
- gap: 6,
- alignItems: 'center',
- marginBottom: withMarginBottom ? 10 : 0,
- flex: 1
- }}
- >
- <WarningIcon color={Colors.RED} width={16} height={16} />
- <Text
- style={{
- flex: 1,
- fontSize: 14,
- fontWeight: '600',
- color: Colors.RED,
- paddingRight: 4
- }}
- >
- Fill in exact dates to get accurate statistics.
- </Text>
- </View>
- );
- const getTripDateLabel = (item: TripsData) => {
- const validFrom = getValidDate(item.date_from);
- const validTo = getValidDate(item.date_to);
- if (!validFrom && !validTo) {
- if (item.year) {
- return <Text style={[styles.tripDateText, { marginLeft: 8 }]}>{item.year}</Text>;
- }
- return null;
- }
- const fromYear = validFrom ? validFrom.format('YYYY') : null;
- const toYear = validTo ? validTo.format('YYYY') : null;
- if (item.dates_missing === 1) {
- if (!fromYear && !toYear) return null;
- if (fromYear && toYear && fromYear === toYear) {
- return <Text style={[styles.tripDateText, { marginLeft: 8 }]}>{toYear}</Text>;
- }
- return (
- <>
- {fromYear ? <Text style={[styles.tripDateText, { marginLeft: 8 }]}>{fromYear}</Text> : null}
- {fromYear && toYear ? <Text style={styles.tripDateText}>-</Text> : null}
- {toYear ? <Text style={styles.tripDateText}>{toYear}</Text> : null}
- </>
- );
- }
- const hasValidFrom = !!validFrom;
- const hasValidTo = !!validTo;
- if (!hasValidFrom && !hasValidTo) return null;
- if (hasValidFrom && !hasValidTo) {
- return (
- <Text style={[styles.tripDateText, { marginLeft: 8 }]}>
- {formatSingleLineDate(item.date_from)}
- </Text>
- );
- }
- if (!hasValidFrom && hasValidTo) {
- return (
- <Text style={[styles.tripDateText, { marginLeft: 8 }]}>
- {formatSingleLineDate(item.date_to)}
- </Text>
- );
- }
- if (validFrom && validTo && item.date_from === item.date_to) {
- return (
- <Text style={[styles.tripDateText, { marginLeft: 8 }]}>
- {formatSingleLineDate(item.date_from)}
- </Text>
- );
- }
- return (
- <>
- <Text style={{ marginLeft: 8 }}>{formatDate(item.date_from)}</Text>
- <Text style={styles.tripDateText}>-</Text>
- {formatDate(item.date_to)}
- </>
- );
- };
- const TripItem = ({ item }: { item: TripsData }) => {
- const navigation = useNavigation();
- const [showAllRegions, setShowAllRegions] = useState(false);
- const MAX_VISIBLE_REGIONS = 3;
- const totalRegions = item.regions?.length || 0;
- const visibleRegions = showAllRegions
- ? item.regions
- : item.regions?.slice(0, MAX_VISIBLE_REGIONS);
- const validFrom = getValidDate(item.date_from);
- const validTo = getValidDate(item.date_to);
- const hasAnyValidDate = !!validFrom || !!validTo || !!item.year;;
- const shouldRenderWarningAbove = item.dates_missing === 1 && hasAnyValidDate;
- const shouldRenderWarningInsteadOfDate = item.dates_missing === 1 && !hasAnyValidDate;
- const tripDateLabel = getTripDateLabel(item);
- return (
- <View style={styles.tripItemContainer}>
- {shouldRenderWarningAbove ? renderMissingDatesWarning(true) : null}
- <View style={styles.tripHeaderContainer}>
- {shouldRenderWarningInsteadOfDate ? (
- renderMissingDatesWarning(false)
- ) : tripDateLabel ? (
- <View style={styles.tripDateContainer}>
- <CalendarIcon fill={Colors.DARK_BLUE} />
- {tripDateLabel}
- </View>
- ) : null}
- <TouchableOpacity
- style={styles.editButton}
- onPress={() =>
- navigation.navigate(
- ...([NAVIGATION_PAGES.ADD_TRIP_2025, { editTripId: item.id }] as never)
- )
- }
- >
- <EditIcon />
- <Text style={styles.editButtonText}>Edit</Text>
- </TouchableOpacity>
- </View>
- <View style={styles.divider} />
- {item.description && (
- <>
- <Text style={styles.descriptionTitle}>Description</Text>
- <Text style={styles.descriptionText}>{item.description}</Text>
- </>
- )}
- <Text style={styles.visitedRegionsTitle}>Visited regions</Text>
- <View style={styles.regionsContainer}>
- {visibleRegions?.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}-${index}`} style={styles.regionItem}>
- <Image source={{ uri: API_HOST + region.flag1 }} style={styles.flagIcon} />
- {region.flag2 && (
- <Image
- source={{ uri: API_HOST + region.flag2 }}
- style={[styles.flagIcon, { marginLeft: -5 }]}
- />
- )}
- <View style={styles.nameContainer}>
- <Text style={styles.regionName}>{name}</Text>
- <Text style={styles.regionSubname}>{subname}</Text>
- </View>
- </View>
- );
- })}
- </View>
- {totalRegions > MAX_VISIBLE_REGIONS && (
- <TouchableOpacity
- style={styles.showMoreButton}
- hitSlop={{ top: 10, bottom: 10, left: 10, right: 10 }}
- onPress={() => setShowAllRegions(!showAllRegions)}
- >
- <ArrowIcon
- fill={Colors.DARK_BLUE}
- style={[styles.headerIcon, showAllRegions ? styles.rotate : null]}
- />
- <Text style={styles.showMoreText}>
- {showAllRegions ? 'Show less' : `Show more (${totalRegions - MAX_VISIBLE_REGIONS})`}
- </Text>
- </TouchableOpacity>
- )}
- </View>
- );
- };
- export default TripItem;
|