123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471 |
- import { FC, useCallback, useEffect, useState } from 'react';
- import { TouchableOpacity, View, Text, Image, Dimensions } from 'react-native';
- import { Series, usePostGetProfileRegions } from '@api/user';
- import { NavigationProp } from '@react-navigation/native';
- import Modal from 'react-native-modal';
- import Tooltip from 'react-native-walkthrough-tooltip';
- import RegionsRenderer from '../RegionsRenderer';
- import CompassIcon from 'assets/icons/travels-section/compass.svg';
- import FriendsIcon from 'assets/icons/user-group.svg';
- import FlagsIcon from 'assets/icons/travels-section/flags.svg';
- import PhotosIcon from 'assets/icons/travels-section/images.svg';
- import RegionsIcon from 'assets/icons/travels-section/regions.svg';
- import SeriesIcon from 'assets/icons/travels-section/series.svg';
- import WHSIcon from 'assets/icons/travels-section/whs.svg';
- import ArrowIcon from 'assets/icons/next.svg';
- import { styles } from './styles';
- import { InfoItem } from './InfoItem';
- import { Colors } from 'src/theme';
- import { API_HOST } from 'src/constants';
- import { NAVIGATION_PAGES } from 'src/types';
- import { AvatarWithInitials, WarningModal } from 'src/components';
- import { usePostFriendRequestMutation, usePostUpdateFriendStatusMutation } from '@api/friends';
- import FriendStatus from './FriendStatus';
- type PersonalInfoProps = {
- data: {
- bio: string;
- scores: { [key: string]: number | string };
- homebase: string;
- series: Series[];
- friends: {
- avatar: string | null;
- user_id: number;
- first_name: string;
- last_name: string;
- flag: string;
- }[];
- firstName: string;
- lastName: string;
- friendRequestSent: 0 | 1;
- friendRequestReceived: 0 | 1;
- isFriend: 0 | 1;
- friendDbId: number;
- ownProfile: 0 | 1;
- };
- updates: {
- countries: number;
- dare: number;
- friends: number;
- new_nm: number;
- photos: number;
- series: number;
- visited_regions: number;
- whs: number;
- };
- userId: number;
- navigation: NavigationProp<any>;
- isPublicView: boolean;
- token: string | null;
- };
- const AVATAR_SIZE = 28;
- const AVATAR_MARGIN = 8;
- const SCREEN_PADDING_PERCENT = 0.05;
- export const PersonalInfo: FC<PersonalInfoProps> = ({
- data,
- userId,
- updates,
- navigation,
- isPublicView,
- token
- }) => {
- const [showMoreSeries, setShowMoreSeries] = useState(false);
- const [type, setType] = useState<string>('nm');
- const [isModalVisible, setIsModalVisible] = useState(false);
- const [toolTipVisible, setToolTipVisible] = useState<number | null>(null);
- const [tooltipUser, setTooltipUser] = useState<number | null>(null);
- const { mutateAsync: sendFriendRequest } = usePostFriendRequestMutation();
- const { mutateAsync: updateFriendStatus } = usePostUpdateFriendStatusMutation();
- const [friendStatus, setFriendStatus] = useState<number | null>(null);
- const [modalInfo, setModalInfo] = useState({
- type: 'friend',
- message: '',
- isVisible: false,
- action: () => {},
- title: ''
- });
- const { data: regions } = usePostGetProfileRegions(userId, type);
- useEffect(() => {
- if (data.isFriend === 1) {
- setFriendStatus(1);
- } else if (data.friendRequestReceived === 1) {
- setFriendStatus(2);
- } else if (data.friendRequestSent === 1) {
- setFriendStatus(3);
- } else {
- setFriendStatus(4);
- }
- }, [data]);
- const scores = [
- { name: 'score_nm', score: 'NM' },
- { name: 'score_mqp', score: 'DARE' },
- { name: 'score_un', score: 'UN' },
- { name: 'score_unp', score: 'UN+' },
- { name: 'score_tcc', score: 'TCC' },
- { name: 'score_deep', score: 'DEEP' },
- { name: 'score_yes', score: 'YES' },
- { name: 'score_slow', score: 'SLOW' },
- { name: 'score_whs', score: 'WHS' },
- { name: 'score_kye', score: 'KYE' }
- ];
- const handleOpenModal = (type: string) => {
- switch (type) {
- case 'NM':
- setType('nm');
- break;
- case 'DARE':
- setType('mqp');
- break;
- case 'UN':
- setType('un');
- break;
- case 'UN+':
- setType('unp');
- break;
- case 'TCC':
- setType('tcc');
- break;
- case 'SLOW':
- setType('slow');
- break;
- case 'YES':
- setType('yes');
- break;
- case 'WHS':
- setType('whs');
- break;
- case 'KYE':
- setType('kye');
- case 'DEEP':
- setType('deep');
- }
- setIsModalVisible(true);
- };
- const hasUpdates = () => {
- return (
- (updates.countries && updates.countries > 0) ||
- (updates.visited_regions && updates.visited_regions > 0) ||
- (updates.dare && updates.dare > 0) ||
- (updates.series && updates.series > 0) ||
- (updates.whs && updates.whs > 0) ||
- (updates.new_nm && updates.new_nm > 0) ||
- (updates.photos && updates.photos > 0) ||
- (updates.friends && updates.friends > 0)
- );
- };
- const handleSendFriendRequest = useCallback(async () => {
- await sendFriendRequest(
- { token: token as string, uid: userId },
- {
- onSuccess: () => {
- setFriendStatus(3);
- }
- }
- );
- }, [sendFriendRequest, token, userId]);
- const handleUpdateFriendStatus = useCallback(
- async (status: number) => {
- await updateFriendStatus(
- { token: token as string, id: data.friendDbId, status },
- {
- onSuccess: () => {
- status === -1 || status === 2 ? setFriendStatus(4) : setFriendStatus(status);
- }
- }
- );
- },
- [updateFriendStatus, token, data.friendDbId]
- );
- const screenWidth = Dimensions.get('window').width;
- const availableWidth = screenWidth * (1 - 2 * SCREEN_PADDING_PERCENT);
- const maxAvatars = Math.floor(availableWidth / (AVATAR_SIZE - AVATAR_MARGIN)) - 2;
- return (
- <>
- <View style={styles.wrapper}>
- <View style={styles.scoreContainer}>
- {scores.map((score, index) => {
- let scoreRank = +data.scores[score.name] > 0 ? data.scores[score.name] : '-';
- if (score.score === 'YES' && +scoreRank >= 4500) {
- scoreRank = '-';
- }
- return (
- <TouchableOpacity
- key={index}
- style={styles.rankingItem}
- disabled={score.score === 'DEEP' || score.score === 'KYE'}
- onPress={() => handleOpenModal(score.score)}
- >
- <Text style={styles.rankingScore}>{scoreRank}</Text>
- <Text style={[styles.titleText, { flex: 0 }]}>{score.score}</Text>
- </TouchableOpacity>
- );
- })}
- </View>
- {isPublicView && token ? (
- <FriendStatus
- status={friendStatus}
- data={data}
- setModalInfo={setModalInfo}
- handleSendFriendRequest={handleSendFriendRequest}
- handleUpdateFriendStatus={handleUpdateFriendStatus}
- />
- ) : null}
- {data.friends.length > 0 ? (
- <InfoItem inline={true} title={'FRIENDS'}>
- <View style={{ flexDirection: 'row', flex: 1 }}>
- {data.friends.slice(0, maxAvatars).map((friend, index) => (
- <Tooltip
- isVisible={tooltipUser === index}
- content={
- <TouchableOpacity
- onPress={() =>
- navigation.navigate(
- ...([
- NAVIGATION_PAGES.PUBLIC_PROFILE_VIEW,
- { userId: friend.user_id }
- ] as never)
- )
- }
- >
- <Text style={{}}>
- {friend.first_name} {friend.last_name}
- </Text>
- </TouchableOpacity>
- }
- contentStyle={{ backgroundColor: Colors.FILL_LIGHT }}
- placement="top"
- onClose={() => setTooltipUser(null)}
- key={index}
- backgroundColor="transparent"
- >
- <TouchableOpacity
- onPress={() => setTooltipUser(index)}
- style={{ marginLeft: index === 0 ? 0 : -AVATAR_MARGIN }}
- >
- {friend.avatar ? (
- <Image
- style={styles.avatar}
- source={{ uri: API_HOST + '/img/avatars/' + friend.avatar }}
- />
- ) : (
- <AvatarWithInitials
- text={`${friend.first_name[0] ?? ''}${friend.last_name[0] ?? ''}`}
- flag={API_HOST + '/img/flags_new/' + friend.flag}
- size={28}
- borderColor={Colors.DARK_LIGHT}
- fontSize={11}
- borderWidth={1}
- />
- )}
- </TouchableOpacity>
- </Tooltip>
- ))}
- </View>
- <Tooltip
- isVisible={tooltipUser === -1}
- content={<Text style={{}}>Only friends can see details.</Text>}
- contentStyle={{ backgroundColor: Colors.FILL_LIGHT, justifyContent: 'flex-end' }}
- placement="top"
- onClose={() => setTooltipUser(null)}
- backgroundColor="transparent"
- allowChildInteraction={false}
- >
- <TouchableOpacity
- style={[styles.avatar, styles.userShowMore]}
- onPress={() => {
- if (friendStatus !== 1 && isPublicView) {
- setTooltipUser(-1);
- } else {
- data.ownProfile === 0
- ? navigation.navigate(
- ...([
- NAVIGATION_PAGES.FRIENDS_LIST,
- {
- id: userId,
- type: 'friends'
- }
- ] as never)
- )
- : navigation.navigate(NAVIGATION_PAGES.MY_FRIENDS);
- }
- }}
- >
- <View style={styles.dots}></View>
- <View style={styles.dots}></View>
- <View style={styles.dots}></View>
- </TouchableOpacity>
- </Tooltip>
- </InfoItem>
- ) : null}
- {hasUpdates() ? (
- <InfoItem title={'UPDATES (last 90 days)'}>
- <View style={{ flexDirection: 'row', flexWrap: 'wrap' }}>
- {updates.countries && updates.countries > 0 ? (
- <View style={styles.updates}>
- <FlagsIcon fill={Colors.DARK_BLUE} height={20} width={20} />
- <View>
- <Text style={styles.updatesTextCount}>+{updates.countries}</Text>
- <Text style={styles.updatesText}>visited countries</Text>
- </View>
- </View>
- ) : null}
- {updates.visited_regions && updates.visited_regions > 0 ? (
- <View style={styles.updates}>
- <RegionsIcon fill={Colors.DARK_BLUE} height={20} width={20} />
- <View>
- <Text style={styles.updatesTextCount}>+{updates.visited_regions}</Text>
- <Text style={styles.updatesText}>visited regions</Text>
- </View>
- </View>
- ) : null}
- {updates.dare && updates.dare > 0 ? (
- <View style={styles.updates}>
- <CompassIcon fill={Colors.DARK_BLUE} height={20} width={20} />
- <View>
- <Text style={styles.updatesTextCount}>+{updates.dare}</Text>
- <Text style={styles.updatesText}>new DARE places</Text>
- </View>
- </View>
- ) : null}
- {updates.series && updates.series > 0 ? (
- <View style={styles.updates}>
- <SeriesIcon fill={Colors.DARK_BLUE} height={20} width={20} />
- <View>
- <Text style={styles.updatesTextCount}>+{updates.series}</Text>
- <Text style={styles.updatesText}>new series</Text>
- </View>
- </View>
- ) : null}
- {updates.whs && updates.whs > 0 ? (
- <View style={styles.updates}>
- <WHSIcon fill={Colors.DARK_BLUE} height={20} width={20} />
- <View>
- <Text style={styles.updatesTextCount}>+{updates.whs}</Text>
- <Text style={styles.updatesText}>new WHS sites</Text>
- </View>
- </View>
- ) : null}
- {updates.new_nm && updates.new_nm > 0 ? (
- <View style={styles.updates}>
- <RegionsIcon fill={Colors.DARK_BLUE} height={20} width={20} />
- <View>
- <Text style={styles.updatesTextCount}>+{updates.new_nm}</Text>
- <Text style={styles.updatesText}>new NM regions</Text>
- </View>
- </View>
- ) : null}
- {updates.photos && updates.photos > 0 ? (
- <View style={styles.updates}>
- <PhotosIcon fill={Colors.DARK_BLUE} height={20} width={20} />
- <View>
- <Text style={styles.updatesTextCount}>+{updates.photos}</Text>
- <Text style={styles.updatesText}>new photos</Text>
- </View>
- </View>
- ) : null}
- {updates.friends && updates.friends > 0 ? (
- <View style={styles.updates}>
- <FriendsIcon fill={Colors.DARK_BLUE} height={20} width={20} />
- <View>
- <Text style={styles.updatesTextCount}>+{updates.friends}</Text>
- <Text style={styles.updatesText}>new friends</Text>
- </View>
- </View>
- ) : null}
- </View>
- </InfoItem>
- ) : null}
- {data.series?.length > 0 && (
- <InfoItem showMore={showMoreSeries} inline={true} title={'SERIES'}>
- {data.series?.slice(0, showMoreSeries ? data.series.length : 8).map((data, index) => (
- <Tooltip
- isVisible={toolTipVisible === index}
- content={<Text style={{}}>{data.name}</Text>}
- contentStyle={{ backgroundColor: Colors.FILL_LIGHT }}
- placement="top"
- onClose={() => setToolTipVisible(null)}
- key={index}
- backgroundColor="transparent"
- allowChildInteraction={false}
- >
- <TouchableOpacity style={styles.series} onPress={() => setToolTipVisible(index)}>
- <Image
- source={{ uri: API_HOST + data.app_icon }}
- style={{ width: 28, height: 28 }}
- />
- <Text style={[styles.headerText, { flex: 0 }]}>{data.score}</Text>
- </TouchableOpacity>
- </Tooltip>
- ))}
- </InfoItem>
- )}
- {data.series?.length > 8 ? (
- <TouchableOpacity onPress={() => setShowMoreSeries(!showMoreSeries)}>
- <View
- style={[
- { alignItems: 'center' },
- showMoreSeries
- ? { transform: 'rotate(180deg)', paddingTop: 8 }
- : { paddingBottom: 8 }
- ]}
- >
- <ArrowIcon stroke={'#B7C6CB'} />
- </View>
- </TouchableOpacity>
- ) : null}
- <View style={{ display: 'flex', flexDirection: 'row' }}>
- <Text style={styles.headerText}>REGION OF ORIGIN</Text>
- <Text style={styles.titleText}>{data.homebase}</Text>
- </View>
- {data.bio && data.bio.length > 0 && (
- <InfoItem title={'BIO'}>
- <Text style={[styles.titleText, { flex: 0 }]}>{data.bio}</Text>
- </InfoItem>
- )}
- </View>
- <Modal
- isVisible={isModalVisible}
- onBackdropPress={() => setIsModalVisible(false)}
- onBackButtonPress={() => setIsModalVisible(false)}
- style={styles.modal}
- statusBarTranslucent={true}
- presentationStyle="overFullScreen"
- >
- <RegionsRenderer type={type} regions={regions} setIsModalVisible={setIsModalVisible} />
- </Modal>
- <WarningModal
- type={modalInfo.type}
- isVisible={modalInfo.isVisible}
- message={modalInfo.message}
- action={modalInfo.action}
- onClose={() => setModalInfo({ ...modalInfo, isVisible: false })}
- title=""
- />
- </>
- );
- };
|