123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520 |
- import React, { FC, useCallback, useEffect, useState } from 'react';
- import { View, Text, Image, TouchableOpacity, Platform } from 'react-native';
- import ImageView from 'better-react-native-image-viewing';
- import { styles } from '../RegionViewScreen/styles';
- import { Button, HorizontalTabView, Loading, Modal as ReactModal } from 'src/components';
- import { CommonActions, useFocusEffect } from '@react-navigation/native';
- import { Colors } from 'src/theme';
- import { ScrollView } from 'react-native-gesture-handler';
- import { styles as ButtonStyles } from 'src/components/RegionPopup/style';
- import { usePostSetToggleItem } from '@api/series';
- import { NAVIGATION_PAGES } from 'src/types';
- import { API_HOST } from 'src/constants';
- import { StoreType, storage } from 'src/storage';
- import { ButtonVariants } from 'src/types/components';
- import { useRegion } from 'src/contexts/RegionContext';
- import formatNumber from '../../TravelsScreen/utils/formatNumber';
- import { PhotosData, Props, SeriesData, SeriesGroup, SeriesItem } from '../RegionViewScreen/types';
- import ImageCarousel from '../RegionViewScreen/ImageCarousel';
- import TravelSeriesList from '../RegionViewScreen/TravelSeriesList';
- import { useGetCountryDataQuery } from '@api/countries';
- import EditModal from '../../TravelsScreen/Components/EditSlowModal';
- import MarkIcon from 'assets/icons/mark.svg';
- import ChevronLeft from 'assets/icons/chevron-left.svg';
- import CaseSvg from 'assets/icons/briefcase.svg';
- import HouseSvg from 'assets/icons/house.svg';
- import EditSvg from 'assets/icons/travels-screens/pen-to-square.svg';
- import CheckSvg from 'assets/icons/travels-screens/circle-check.svg';
- import CheckRegularSvg from 'assets/icons/travels-screens/circle-check-regular.svg';
- import MapSvg from 'assets/icons/travels-screens/map-location.svg';
- const CountryViewScreen: FC<Props> = ({ navigation, route }) => {
- const countryId = route.params?.regionId;
- const disabled = route.params?.disabled;
- const token = storage.get('token', StoreType.STRING) as string;
- const [isLoading, setIsLoading] = useState(true);
- const [isModalVisible, setModalVisible] = useState(false);
- const [currentImageIndex, setCurrentImageIndex] = useState(0);
- const [activeIndex, setActiveIndex] = useState(0);
- const [indexSeries, setIndexSeries] = useState(0);
- const [routes, setRoutes] = useState<SeriesGroup[]>([]);
- const [series, setSeries] = useState<SeriesData[]>([]);
- const [photos, setPhotos] = useState<PhotosData[]>([]);
- const [name, setName] = useState('');
- const { data } = useGetCountryDataQuery(countryId, true, token && token);
- const { mutate: updateSeriesItem } = usePostSetToggleItem();
- const [isInfoModalVisible, setIsInfoModalVisible] = useState<boolean>(false);
- const [infoItem, setInfoItem] = useState<SeriesItem | null>(null);
- const [isEditSlowModalVisible, setIsEditSlowModalVisible] = useState<boolean>(false);
- const {
- handleUpdateSlow: updateSlow,
- userData: regionData,
- setUserData: setRegionData,
- handleUpdateSlowList
- } = useRegion();
- useEffect(() => {
- navigation.getParent()?.setOptions({
- tabBarStyle: {
- display: 'flex',
- ...Platform.select({
- android: {
- height: 58
- }
- })
- }
- });
- }, [navigation]);
- useFocusEffect(
- useCallback(() => {
- const fetchGroups = async () => {
- let staticGroups = [];
- const routesData = data?.data?.series?.map((item) => ({
- key: item.series_id?.toString(),
- title: item.series_name,
- series_id: item.series_id,
- icon: item.icon,
- items: item.items
- }));
- routesData && staticGroups.push(...routesData);
- setPhotos(
- data?.data?.photos?.map((item) => ({
- ...item,
- uriSmall: `${API_HOST}/ajax/pic/${item.id}/small`,
- uri: `${API_HOST}/ajax/pic/${item.id}/full`
- })) ?? []
- );
- setName(data?.data.name ?? '');
- setSeries(data?.data?.series || []);
- setRoutes(staticGroups);
- if (regionData?.id !== countryId) {
- setRegionData(data?.data || {});
- }
- setIsLoading(false);
- };
- if (data && data.result === 'OK') {
- fetchGroups();
- }
- }, [data])
- );
- const handleCheckboxChange = useCallback(
- async (item: SeriesItem, double: boolean, seriesId: number) => {
- setSeries((currentData) => {
- const groupIndex = currentData.findIndex((group) => group?.series_id === seriesId);
- if (groupIndex === -1) return currentData;
- const newData = [...currentData];
- const newGroup = { ...newData[groupIndex] };
- newGroup.items = newGroup.items.map((subItem) =>
- subItem.id === item.id
- ? {
- ...subItem,
- ...(double
- ? { visited_double: subItem.visited_double === 0 ? 1 : 0 }
- : { visited: subItem.visited === 0 ? 1 : 0 })
- }
- : subItem
- );
- newData[groupIndex] = newGroup;
- return newData;
- });
- const itemData = {
- token: token,
- series_id: seriesId,
- item_id: item.id,
- checked: (item.visited === 1 ? 0 : 1) as 0 | 1,
- double: (double && !item.visited_double ? 1 : 0) as 0 | 1
- };
- try {
- updateSeriesItem(itemData);
- } catch (error) {
- console.error('Failed to update checkbox state', error);
- }
- },
- [token, updateSeriesItem]
- );
- const openModal = (index: number) => {
- setCurrentImageIndex(index);
- setModalVisible(true);
- };
- if (isLoading) return <Loading />;
- const handleUpdateSlowModal = (
- id: number,
- v: boolean,
- s11: boolean,
- s31: boolean,
- s101: boolean
- ) => {
- const updatedSlow = {
- ...regionData,
- visited: v,
- slow11: Number(s11) as 0 | 1,
- slow31: Number(s31) as 0 | 1,
- slow101: Number(s101) as 0 | 1
- };
- const updatedSlowData = {
- token,
- id,
- v,
- s11,
- s31,
- s101
- };
- route.params?.isTravelsScreen
- ? handleUpdateSlowList(id, v, s11, s31, s101)
- : updateSlow(id, v, s11, s31, s101);
- updatedSlow && setRegionData(updatedSlow);
- };
- const handleUpdateSlow = () => {
- route.params?.isTravelsScreen
- ? handleUpdateSlowList(
- countryId,
- !regionData.visited,
- Boolean(regionData.slow11),
- Boolean(regionData.slow31),
- Boolean(regionData.slow101)
- )
- : updateSlow(
- countryId,
- !regionData.visited,
- Boolean(regionData.slow11),
- Boolean(regionData.slow31),
- Boolean(regionData.slow101)
- );
- setRegionData({
- ...regionData,
- visited: !regionData.visited
- });
- };
- const renderDurationIcon = (condition: 0 | 1) =>
- condition ? <CheckSvg fill={Colors.DARK_BLUE} /> : <CheckRegularSvg />;
- return (
- <View style={styles.container}>
- <TouchableOpacity
- onPress={() => {
- navigation.goBack();
- }}
- style={styles.backButton}
- >
- <View style={styles.chevronWrapper}>
- <ChevronLeft fill={Colors.WHITE} />
- </View>
- </TouchableOpacity>
- <ScrollView
- contentContainerStyle={{ flexGrow: 1 }}
- nestedScrollEnabled={true}
- showsVerticalScrollIndicator={false}
- >
- {photos.length > 0 ? (
- <ImageCarousel
- photos={photos}
- activeIndex={activeIndex}
- setActiveIndex={setActiveIndex}
- openModal={openModal}
- />
- ) : (
- <View style={styles.emptyImage}>
- <Image
- source={require('../../../../../assets/images/logo-opacity.png')}
- style={{ width: 100, height: 100 }}
- />
- <Text style={styles.emptyImageText}>No image available at this location</Text>
- </View>
- )}
- <TouchableOpacity
- onPress={() => {
- route.params?.isTravelsScreen || route.params?.isProfileScreen
- ? navigation.dispatch(
- CommonActions.reset({
- index: 1,
- routes: [
- {
- name: NAVIGATION_PAGES.IN_APP_MAP_TAB,
- state: {
- routes: [
- {
- name: NAVIGATION_PAGES.MAP_TAB,
- params: { id: countryId, type: 'countries' }
- }
- ]
- }
- }
- ]
- })
- )
- : navigation.goBack();
- }}
- style={styles.goToMapBtn}
- >
- <View style={styles.chevronWrapper}>
- <MapSvg fill={Colors.WHITE} />
- </View>
- </TouchableOpacity>
- <View style={styles.wrapper}>
- {regionData?.visited && !disabled && (
- <View style={styles.durationContainer}>
- <View style={styles.durationItem}>
- {renderDurationIcon(regionData.slow11)}
- <Text style={styles.visitDuration}>11+ days</Text>
- </View>
- <View style={styles.durationItem}>
- {renderDurationIcon(regionData.slow31)}
- <Text style={styles.visitDuration}>31+ days</Text>
- </View>
- <View style={styles.durationItem}>
- {renderDurationIcon(regionData.slow101)}
- <Text style={styles.visitDuration}>101+ days</Text>
- </View>
- </View>
- )}
- <View style={styles.nameContainer}>
- <Text style={styles.title}>{name}</Text>
- <View style={ButtonStyles.btnContainer}>
- {regionData?.visited && !disabled ? (
- <TouchableOpacity
- onPress={() => setIsEditSlowModalVisible(true)}
- style={ButtonStyles.editBtn}
- >
- <EditSvg width={14} height={14} />
- </TouchableOpacity>
- ) : null}
- {!disabled ? (
- <TouchableOpacity
- style={[
- ButtonStyles.btn,
- regionData?.visited && !disabled
- ? ButtonStyles.visitedButton
- : ButtonStyles.markVisitedButton
- ]}
- onPress={handleUpdateSlow}
- >
- {regionData?.visited ? (
- <View style={ButtonStyles.visitedContainer}>
- <MarkIcon width={16} height={16} />
- <Text style={ButtonStyles.visitedButtonText}>Visited</Text>
- </View>
- ) : (
- <Text style={[ButtonStyles.markVisitedButtonText]}>Mark Visited</Text>
- )}
- </TouchableOpacity>
- ) : null}
- </View>
- </View>
- <View style={styles.divider} />
- <View style={styles.stats}>
- {data?.data.users_from_country_count ?? 0 > 0 ? (
- <TouchableOpacity
- style={[styles.statItem, { justifyContent: 'flex-start' }]}
- onPress={() =>
- navigation.navigate(
- ...([
- NAVIGATION_PAGES.USERS_LIST,
- {
- id: countryId,
- isFromHere: true,
- type: 'country'
- }
- ] as never)
- )
- }
- >
- <View style={styles.icon}>
- <HouseSvg />
- </View>
- <View
- style={{
- height: 12,
- width: 1,
- backgroundColor: Colors.DARK_BLUE,
- marginRight: 6
- }}
- />
- <View style={styles.userImageContainer}>
- {data?.data.users_from_country &&
- data?.data.users_from_country.length > 0 &&
- data?.data.users_from_country?.map((user, index: number) => (
- <Image
- key={index}
- source={{ uri: API_HOST + user }}
- style={styles.userImage}
- />
- ))}
- <View style={styles.userCountContainer}>
- <Text style={styles.userCount}>
- {formatNumber(data?.data?.users_from_country_count ?? 0)}
- </Text>
- </View>
- </View>
- </TouchableOpacity>
- ) : (
- <View style={[styles.statItem, { justifyContent: 'flex-start' }]} />
- )}
- {data?.data.users_who_visited_country_count ?? 0 > 0 ? (
- <TouchableOpacity
- style={[styles.statItem, { justifyContent: 'flex-end' }]}
- onPress={() =>
- navigation.navigate(
- ...([
- NAVIGATION_PAGES.USERS_LIST,
- {
- id: countryId,
- isFromHere: false,
- type: 'country'
- }
- ] as never)
- )
- }
- >
- <View style={styles.icon}>
- <CaseSvg />
- </View>
- <View
- style={{
- height: 12,
- width: 1,
- backgroundColor: Colors.DARK_BLUE,
- marginRight: 6
- }}
- />
- <View style={styles.userImageContainer}>
- {data?.data.users_who_visited_country &&
- data?.data.users_who_visited_country.length > 0 &&
- data?.data.users_who_visited_country?.map((user, index) => (
- <Image
- key={index}
- source={{ uri: API_HOST + user }}
- style={[styles.userImage]}
- />
- ))}
- <View style={styles.userCountContainer}>
- <Text style={styles.userCount}>
- {formatNumber(data?.data.users_who_visited_country_count ?? 0)}
- </Text>
- </View>
- </View>
- </TouchableOpacity>
- ) : (
- <View style={[styles.statItem, { justifyContent: 'flex-end' }]} />
- )}
- </View>
- <View style={[styles.divider, { marginBottom: 8 }]} />
- {series.length > 0 ? (
- <>
- <Text style={styles.travelSeriesTitle}>TRAVEL SERIES</Text>
- <HorizontalTabView
- index={indexSeries}
- setIndex={setIndexSeries}
- routes={routes}
- renderScene={({ route }: { route: SeriesGroup }) => <View style={{ height: 0 }} />}
- />
- <TravelSeriesList
- series={series}
- indexSeries={indexSeries}
- routes={routes}
- handleCheckboxChange={handleCheckboxChange}
- setIsInfoModalVisible={setIsInfoModalVisible}
- setInfoItem={setInfoItem}
- disabled={disabled}
- includeAll={false}
- />
- </>
- ) : null}
- </View>
- <ImageView
- images={photos}
- imageIndex={currentImageIndex}
- visible={isModalVisible}
- onRequestClose={() => setModalVisible(false)}
- backgroundColor={Colors.DARK_BLUE}
- onImageIndexChange={setActiveIndex}
- FooterComponent={({ imageIndex }) => (
- <View style={styles.imageFooter}>
- <Text style={styles.imageDescription}>{photos[imageIndex].title}</Text>
- <TouchableOpacity
- onPress={() => {
- setModalVisible(false);
- navigation.navigate(
- ...([
- NAVIGATION_PAGES.PUBLIC_PROFILE_VIEW,
- { userId: photos[imageIndex].user_id, hideTabBar: true }
- ] as never)
- );
- }}
- disabled={disabled}
- style={styles.imageOwner}
- >
- <Text style={styles.imageOwnerText}>{photos[imageIndex].first_name}</Text>
- <Text style={styles.imageOwnerText}>{photos[imageIndex].last_name}</Text>
- </TouchableOpacity>
- </View>
- )}
- />
- <ReactModal
- visible={isInfoModalVisible}
- children={
- <View style={styles.modalView}>
- <Text style={styles.infoTitle}>{infoItem?.name}</Text>
- <Text style={styles.infoText}>{infoItem?.description}</Text>
- <Button
- variant={ButtonVariants.OPACITY}
- containerStyles={styles.btnContainer}
- textStyles={{
- color: Colors.DARK_BLUE
- }}
- onPress={() => setIsInfoModalVisible(false)}
- children={'Got it'}
- />
- </View>
- }
- onRequestClose={() => setIsInfoModalVisible(false)}
- headerTitle={'Info'}
- visibleInPercent={'auto'}
- />
- </ScrollView>
- <EditModal
- isVisible={isEditSlowModalVisible}
- onClose={() => setIsEditSlowModalVisible(false)}
- item={{ ...regionData, country_id: countryId }}
- updateSlow={(id, v, s11, s31, s101) => {
- handleUpdateSlowModal(id, v, s11, s31, s101);
- }}
- />
- </View>
- );
- };
- export default CountryViewScreen;
|