123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546 |
- 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 './styles';
- import {
- Button,
- EditNmModal,
- HorizontalTabView,
- Loading,
- Modal as ReactModal
- } from 'src/components';
- import { useFocusEffect } from '@react-navigation/native';
- import { Colors } from 'src/theme';
- import { styles as ButtonStyles } from 'src/components/RegionPopup/style';
- import { usePostSetToggleItem } from '@api/series';
- import { ScrollView } from 'react-native-gesture-handler';
- import { NAVIGATION_PAGES } from 'src/types';
- import { API_HOST } from 'src/constants';
- import { useGetDareRegionDataQuery, useGetNmRegionDataQuery } from '@api/regions';
- import { StoreType, storage } from 'src/storage';
- import { ButtonVariants } from 'src/types/components';
- import { qualityOptions } from '../../TravelsScreen/utils/constants';
- import moment from 'moment';
- import { useRegion } from 'src/contexts/RegionContext';
- import formatNumber from '../../TravelsScreen/utils/formatNumber';
- import { PhotosData, Props, SeriesData, SeriesGroup, SeriesItem } from './types';
- import ImageCarousel from './ImageCarousel';
- import TravelSeriesList from './TravelSeriesList';
- 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 CalendarSvg from 'assets/icons/travels-screens/calendar.svg';
- import RotateSvg from 'assets/icons/travels-screens/rotate.svg';
- const RegionViewScreen: FC<Props> = ({ navigation, route }) => {
- const regionId = route.params?.regionId;
- const type = route.params?.type;
- 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 } =
- type === 'nm'
- ? useGetNmRegionDataQuery(regionId, type === 'nm', token && token)
- : useGetDareRegionDataQuery(regionId, type === 'dare', token && token);
- const { mutate: updateSeriesItem } = usePostSetToggleItem();
- const [isInfoModalVisible, setIsInfoModalVisible] = useState<boolean>(false);
- const [infoItem, setInfoItem] = useState<SeriesItem | null>(null);
- const [isEditModalVisible, setIsEditModalVisible] = useState(false);
- const [modalState, setModalState] = useState({
- selectedFirstYear: 2021,
- selectedLastYear: 2021,
- selectedQuality: qualityOptions[2],
- selectedNoOfVisits: 1,
- years: [],
- id: regionId
- });
- const {
- handleUpdateNM: updateNM,
- handleUpdateDare: updateDare,
- userData: regionData,
- setUserData: setRegionData,
- handleUpdateNMList,
- handleUpdateDareList
- } = useRegion();
- useEffect(() => {
- navigation.getParent()?.setOptions({
- tabBarStyle: {
- display: 'flex',
- ...Platform.select({
- android: {
- height: 58
- }
- })
- }
- });
- }, [navigation]);
- useFocusEffect(
- useCallback(() => {
- const fetchGroups = async () => {
- let staticGroups = [
- {
- key: 'all',
- title: 'All',
- series_id: 0
- }
- ];
- 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`
- })) ?? []
- );
- const [regionName, ...rest] = data?.data?.region_name?.split(/ – | - /) ?? [];
- const subname = rest?.join(' - ');
- setName([regionName, subname]);
- setSeries(data?.data?.series || []);
- setRoutes(staticGroups);
- 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 handleModalStateChange = (updates: { [key: string]: any }) => {
- setModalState((prevState) => ({ ...prevState, ...updates }));
- };
- useEffect(() => {
- const currentYear = moment().year();
- let yearSelector: { label: string; value: number }[] = [{ label: 'visited', value: 1 }];
- for (let i = currentYear; i >= 1951; i--) {
- yearSelector.push({ label: i.toString(), value: i });
- }
- handleModalStateChange({ years: yearSelector });
- }, []);
- const openModal = (index: number) => {
- setCurrentImageIndex(index);
- setModalVisible(true);
- };
- if (isLoading) return <Loading />;
- const handleOpenEditModal = () => {
- handleModalStateChange({
- selectedFirstYear: regionData?.first_visit_year,
- selectedLastYear: regionData?.last_visit_year,
- selectedQuality:
- qualityOptions.find((quality) => quality.id === regionData?.best_visit_quality) ||
- qualityOptions[2],
- selectedNoOfVisits: regionData?.no_of_visits || 1,
- id: regionId
- });
- setIsEditModalVisible(true);
- };
- const handleUpdateNmModal = (
- region: number = regionId,
- first: number,
- last: number,
- visits: number,
- quality: number
- ) => {
- const updatedNM = {
- ...regionData,
- first_visit_year: first,
- last_visit_year: last,
- best_visit_quality: quality,
- no_of_visits: visits,
- visited: visits > 0 ? true : false
- };
- route.params?.isTravelsScreen
- ? handleUpdateNMList(region, first, last, visits, quality)
- : updateNM(region, first, last, visits, quality);
- updatedNM && setRegionData(updatedNM);
- };
- const handleUpdateNm = () => {
- route.params?.isTravelsScreen
- ? handleUpdateNMList(
- regionId,
- regionData.visited ? 0 : 1,
- regionData.visited ? 0 : 1,
- regionData.visited ? 0 : 1,
- 3
- )
- : updateNM(
- regionId,
- regionData.visited ? 0 : 1,
- regionData.visited ? 0 : 1,
- regionData.visited ? 0 : 1,
- 3
- );
- setRegionData({
- ...regionData,
- first_visit_year: regionData.visited ? 0 : 1,
- last_visit_year: regionData.visited ? 0 : 1,
- best_visit_quality: 3,
- no_of_visits: regionData.visited ? 0 : 1,
- visited: !regionData.visited
- });
- };
- const handleUpdateDare = () => {
- route.params?.isTravelsScreen
- ? handleUpdateDareList(regionId, regionData.visited ? 0 : 1)
- : updateDare(regionId, regionData.visited ? 0 : 1);
- setRegionData({
- ...regionData,
- first_visit_year: regionData.visited ? 0 : 1,
- last_visit_year: regionData.visited ? 0 : 1,
- best_visit_quality: 3,
- no_of_visits: regionData.visited ? 0 : 1,
- visited: !regionData.visited
- });
- };
- 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>
- )}
- <View style={styles.wrapper}>
- <View style={{ flexDirection: 'row', gap: 8, justifyContent: 'flex-end' }}>
- {regionData?.visited && regionData?.first_visit_year > 1 && !disabled && (
- <View style={styles.infoContent}>
- <CalendarSvg height={18} width={18} fill={Colors.DARK_BLUE} />
- <Text style={styles.visitedButtonText}>{regionData?.first_visit_year}</Text>
- </View>
- )}
- {regionData?.visited && type === 'nm' && !disabled && (
- <View style={styles.infoContent}>
- <RotateSvg fill={Colors.DARK_BLUE} />
- <Text style={styles.visitedButtonText}>
- {regionData.no_of_visits >= 10 ? '10+' : regionData.no_of_visits}
- </Text>
- </View>
- )}
- </View>
- <View style={styles.nameContainer}>
- <Text style={styles.title}>{name[0]}</Text>
- <View style={ButtonStyles.btnContainer}>
- {regionData?.visited && type === 'nm' && !disabled ? (
- <TouchableOpacity onPress={handleOpenEditModal} style={ButtonStyles.editBtn}>
- <EditSvg width={14} height={14} />
- </TouchableOpacity>
- ) : null}
- {!disabled ? (
- <TouchableOpacity
- style={[
- ButtonStyles.btn,
- regionData?.visited && !disabled
- ? ButtonStyles.visitedButton
- : ButtonStyles.markVisitedButton
- ]}
- onPress={() => (type === 'nm' ? handleUpdateNm() : handleUpdateDare())}
- >
- {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>
- <Text style={styles.subtitle}>{name[1]}</Text>
- <View style={styles.divider} />
- <View style={styles.stats}>
- {data?.data.users_from_region_count ?? 0 > 0 ? (
- <TouchableOpacity
- style={[styles.statItem, { justifyContent: 'flex-start' }]}
- onPress={() =>
- navigation.navigate(
- ...([
- NAVIGATION_PAGES.USERS_LIST,
- {
- id: regionId,
- isFromHere: true,
- type: 'nm'
- }
- ] 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_region &&
- data?.data.users_from_region.length > 0 &&
- data?.data.users_from_region?.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_region_count ?? 0)}
- </Text>
- </View>
- </View>
- </TouchableOpacity>
- ) : (
- <View style={[styles.statItem, { justifyContent: 'flex-start' }]} />
- )}
- {data?.data.users_who_visited_region_count ?? 0 > 0 ? (
- <TouchableOpacity
- style={[styles.statItem, { justifyContent: 'flex-end' }]}
- onPress={() =>
- navigation.navigate(
- ...([
- NAVIGATION_PAGES.USERS_LIST,
- {
- id: regionId,
- isFromHere: false,
- type
- }
- ] 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_region &&
- data?.data.users_who_visited_region.length > 0 &&
- data?.data.users_who_visited_region?.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_region_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}
- />
- </>
- ) : 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>
- <EditNmModal
- isVisible={isEditModalVisible}
- onClose={() => setIsEditModalVisible(false)}
- modalState={modalState}
- updateModalState={handleModalStateChange}
- updateNM={handleUpdateNmModal}
- />
- </View>
- );
- };
- export default RegionViewScreen;
|