123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399 |
- import React, { useCallback } from 'react';
- import { View, Text, Image, TouchableOpacity, ScrollView } from 'react-native';
- import { Colors } from 'src/theme';
- import { styles } from './styles';
- import { Loading } from 'src/components';
- import CheckSvg from 'assets/icons/mark.svg';
- import CloseSVG from 'assets/icons/close.svg';
- import { API_HOST } from 'src/constants';
- import { FlashList } from '@shopify/flash-list';
- interface Mega {
- id: number;
- name: string;
- regions: {
- id: number;
- name: string;
- flag1: string;
- flag2: string | null;
- }[];
- transits: number[];
- visits: number[];
- }
- interface Region {
- id: number;
- name: string;
- flag1: string;
- flag2: string | null;
- country_id: number;
- }
- const RegionsRenderer = ({
- type,
- regions,
- setIsModalVisible
- }: {
- type: string;
- regions: any;
- setIsModalVisible: (value: boolean) => void;
- }) => {
- const flashlistConfig = {
- waitForInteraction: true,
- itemVisiblePercentThreshold: 50,
- minimumViewTime: 1000
- };
- const getOpacity = useCallback(
- (item: any, mega?: Mega) => {
- switch (type) {
- case 'nm':
- case 'mqp':
- return mega?.visits.includes(item.id) ? 1 : 0.4;
- case 'un':
- case 'unp':
- case 'tcc':
- return regions.data[1].includes(item.name) ? 1 : 0.4;
- case 'slow':
- return item.visited === 1 ? 1 : 0.4;
- case 'whs':
- return item.visited ? 1 : 0.4;
- default:
- return 1;
- }
- },
- [type, regions?.data]
- );
- const renderRegion = useCallback(
- (item: any, mega?: Mega) => {
- return (
- <View style={[styles.regionRow, { opacity: getOpacity(item, mega) }]}>
- <View
- style={[
- styles.flags,
- type === 'yes' ? { flex: 2 } : type === 'slow' ? { flex: 1 } : {}
- ]}
- >
- <Image
- source={{
- uri:
- API_HOST +
- (type === 'whs'
- ? item.flag
- : type === 'slow'
- ? '/img/flags_new/' + item?.flag
- : '/img/flags_new/' + item?.flag1)
- }}
- style={styles.regionsFlag}
- />
- {item?.flag2 ? (
- <Image
- source={{ uri: API_HOST + '/img/flags_new/' + item.flag2 }}
- style={[styles.regionsFlag, { marginLeft: -18 }]}
- />
- ) : null}
- <View style={styles.regionInfo}>
- <Text style={styles.regionName}>{type === 'slow' ? item.country : item?.name}</Text>
- </View>
- </View>
- {type === 'nm' && (
- <View style={{ flexDirection: 'row', flex: 2 }}>
- <View style={{ width: '56%', alignItems: 'center', marginRight: '2%' }}>
- {regions.data.firsts[item?.id] && regions.data.firsts[item?.id] !== 1 ? (
- <Text style={[styles.regionName, { fontSize: 12, fontWeight: '700' }]}>
- {regions.data.firsts[item?.id]}
- </Text>
- ) : null}
- </View>
- <View style={{ width: '42%', alignItems: 'center' }}>
- {regions.data.last[item?.id] && regions.data.last[item?.id] !== 1 ? (
- <Text style={[styles.regionName, { fontSize: 12, fontWeight: '700' }]}>
- {regions.data.last[item?.id]}
- </Text>
- ) : null}
- </View>
- </View>
- )}
- {type === 'yes' && (
- <View style={{ flexDirection: 'row', flex: 1 }}>
- <View style={{ width: '60%', alignItems: 'center' }}>
- {regions.data[1][item?.id] && regions.data[1][item?.id].year !== 1 ? (
- <Text style={[styles.regionName, { fontSize: 12, fontWeight: '700' }]}>
- {regions.data[1][item?.id].year}
- </Text>
- ) : null}
- </View>
- <View style={{ width: '40%', alignItems: 'center' }}>
- {regions.data[1][item?.id] ? (
- <Text style={[styles.regionName, { fontSize: 12, fontWeight: '700' }]}>
- {regions.data[1][item?.id].score}
- </Text>
- ) : null}
- </View>
- </View>
- )}
- {type === 'slow' && (
- <View style={{ flexDirection: 'row', flex: 1 }}>
- <View style={{ width: '33%', alignItems: 'center' }}>
- {item.slow11 === 1 ? (
- <CheckSvg fill={Colors.DARK_BLUE} width={14} height={14} />
- ) : null}
- </View>
- <View style={{ width: '33%', alignItems: 'center' }}>
- {item.slow31 === 1 ? (
- <CheckSvg fill={Colors.DARK_BLUE} width={14} height={14} />
- ) : null}
- </View>
- <View style={{ width: '33%', alignItems: 'center' }}>
- {item.slow101 === 1 ? (
- <CheckSvg fill={Colors.DARK_BLUE} width={14} height={14} />
- ) : null}
- </View>
- </View>
- )}
- </View>
- );
- },
- [getOpacity, regions?.data, type]
- );
- const renderMegaregion = useCallback(
- ({ item }: { item: Mega }) => {
- return (
- <View style={styles.megaregion}>
- <View style={styles.blockTitle}>
- <Text style={[styles.megaregionTitle, type === 'mqp' ? { textAlign: 'center' } : {}]}>
- {type === 'nm' ? '- ' : ''}
- {item.name}
- <Text style={{ fontWeight: '600' }}>
- {' '}
- - {item.visits.length}/{item.regions.length} (
- {((item.visits.length * 100) / item.regions.length).toFixed(2)}%)
- </Text>
- </Text>
- {type === 'nm' && (
- <View style={{ flexDirection: 'row', flex: 2 }}>
- <View style={{ width: '56%', alignItems: 'center', marginRight: '2%' }}>
- <Text style={styles.alignCenter}>
- <Text style={[styles.megaregionTitle, { fontSize: 12 }]}>First</Text>
- {'\n'}
- <Text style={[styles.megaregionTitle, { fontSize: 12 }]}>visited</Text>
- </Text>
- </View>
- <View style={{ width: '42%', alignItems: 'center' }}>
- <Text style={styles.alignCenter}>
- <Text style={[styles.megaregionTitle, { fontSize: 12 }]}>Last</Text>
- {'\n'}
- <Text style={[styles.megaregionTitle, { fontSize: 12 }]}>visit</Text>
- </Text>
- </View>
- </View>
- )}
- </View>
- <View style={styles.megaSubList}>
- <ScrollView
- style={{ flex: 1 }}
- nestedScrollEnabled={true}
- showsVerticalScrollIndicator={false}
- horizontal={false}
- >
- {item.regions?.map((region: any) => (
- <View key={region.id}>{renderRegion(region, item)}</View>
- ))}
- </ScrollView>
- </View>
- </View>
- );
- },
- [flashlistConfig, renderRegion, type]
- );
- const renderContent = () => {
- const renderHeader = (headerText: string) => (
- <RegionsModalHeader textHeader={headerText} onRequestClose={() => setIsModalVisible(false)} />
- );
- switch (type) {
- case 'nm':
- case 'mqp':
- return (
- <>
- {renderHeader(type === 'nm' ? 'NM' : 'DARE')}
- <FlashList
- viewabilityConfig={flashlistConfig}
- estimatedItemSize={4000}
- data={regions.data.megaregions}
- renderItem={renderMegaregion}
- keyExtractor={(megaregion) => megaregion?.id?.toString()}
- showsVerticalScrollIndicator={false}
- nestedScrollEnabled={true}
- contentContainerStyle={{ paddingTop: 8 }}
- />
- </>
- );
- case 'un':
- case 'unp':
- case 'tcc':
- return (
- <>
- {renderHeader(type === 'un' ? 'UN' : type === 'unp' ? 'UN+' : 'TCC')}
- <FlashList
- viewabilityConfig={flashlistConfig}
- estimatedItemSize={50}
- data={regions.data[0]}
- renderItem={(region) => renderRegion(region.item)}
- keyExtractor={(region: Region) => region.name}
- showsVerticalScrollIndicator={false}
- contentContainerStyle={{ paddingTop: 8 }}
- ListHeaderComponent={() => (
- <View style={styles.blockTitle}>
- <Text style={[styles.megaregionTitle, { textAlign: 'center' }]}>
- {type === 'un' ? 'Countries' : 'Territories'}
- <Text style={{ fontWeight: '600' }}>
- {' '}
- - {regions.data[3]}/{regions.data[2]} (
- {((regions.data[3] * 100) / regions.data[2]).toFixed(2)}%)
- </Text>
- </Text>
- </View>
- )}
- />
- </>
- );
- case 'slow':
- return (
- <>
- {renderHeader('SLOW')}
- <FlashList
- viewabilityConfig={flashlistConfig}
- estimatedItemSize={50}
- data={regions.data[0]}
- renderItem={(region) => renderRegion(region.item)}
- keyExtractor={(region: Region) => region.country_id.toString()}
- showsVerticalScrollIndicator={false}
- contentContainerStyle={{ paddingTop: 8 }}
- ListHeaderComponent={() => {
- return (
- <View style={styles.blockTitle}>
- <Text style={[styles.megaregionTitle, { flex: 1 }]}>Countries</Text>
- <View style={{ flexDirection: 'row', flex: 1 }}>
- <View style={styles.slow}>
- <Text style={styles.alignCenter}>
- <Text style={[styles.megaregionTitle, { fontSize: 12 }]}>Slow11</Text>
- </Text>
- </View>
- <View style={styles.slow}>
- <Text style={styles.alignCenter}>
- <Text style={[styles.megaregionTitle, { fontSize: 12 }]}>Slow31</Text>
- </Text>
- </View>
- <View style={styles.slow}>
- <Text style={styles.alignCenter}>
- <Text style={[styles.megaregionTitle, { fontSize: 12 }]}>Slow101</Text>
- </Text>
- </View>
- </View>
- </View>
- );
- }}
- />
- </>
- );
- case 'yes':
- const calcTotalScore = (
- values: {
- year: number;
- score: number;
- country: string;
- }[]
- ) => {
- const totalScore = values.reduce((accumulator, item) => {
- return accumulator + item.score;
- }, 0);
- return totalScore;
- };
- return (
- <>
- {renderHeader('YES')}
- <FlashList
- viewabilityConfig={flashlistConfig}
- estimatedItemSize={50}
- data={regions.data[0]}
- renderItem={(region) => renderRegion(region.item)}
- keyExtractor={(region: Region) => region.id.toString()}
- showsVerticalScrollIndicator={false}
- contentContainerStyle={{ paddingTop: 8 }}
- ListHeaderComponent={() => {
- return (
- <View style={styles.blockTitle}>
- <Text style={[styles.megaregionTitle, { flex: 2 }]}>
- Countries
- <Text style={{ fontWeight: '600' }}>
- {' total score '}
- {calcTotalScore(Object.values(regions.data[1]))}
- </Text>
- </Text>
- <View style={{ flexDirection: 'row', flex: 1 }}>
- <View style={{ width: '60%', alignItems: 'center' }}>
- <Text style={styles.alignCenter}>
- <Text style={[styles.megaregionTitle, { fontSize: 12 }]}>Last visit</Text>
- </Text>
- </View>
- <View
- style={{ width: '40%', alignItems: 'center', justifyContent: 'center' }}
- >
- <Text style={styles.alignCenter}>
- <Text style={[styles.megaregionTitle, { fontSize: 12 }]}>Score</Text>
- </Text>
- </View>
- </View>
- </View>
- );
- }}
- />
- </>
- );
- case 'whs':
- return (
- <>
- {renderHeader('WHS')}
- <FlashList
- viewabilityConfig={flashlistConfig}
- estimatedItemSize={50}
- data={regions.data}
- renderItem={(region) => renderRegion(region.item)}
- keyExtractor={(region: Region) => region.name}
- showsVerticalScrollIndicator={false}
- contentContainerStyle={{ paddingTop: 8 }}
- />
- </>
- );
- }
- };
- return <View style={styles.modalContent}>{regions?.data ? renderContent() : <Loading />}</View>;
- };
- const RegionsModalHeader = ({
- textHeader,
- onRequestClose,
- rightElement
- }: {
- textHeader: string;
- onRequestClose: () => void;
- rightElement?: any;
- }) => {
- return (
- <View style={styles.header}>
- <TouchableOpacity onPress={onRequestClose} style={{ padding: 6 }}>
- <CloseSVG />
- </TouchableOpacity>
- <Text style={styles.headerText}>{textHeader}</Text>
- {rightElement ? rightElement : <View style={{ height: 30, width: 30 }} />}
- </View>
- );
- };
- export default RegionsRenderer;
|