import React, { useCallback, useEffect, useRef, useState } from 'react'; import { Fade, Placeholder, PlaceholderLine } from 'rn-placeholder'; import { IOScrollView } from 'react-native-intersection-observer' import Geolocation from '@react-native-community/geolocation' import { getTrackingStatus, requestTrackingPermission } from 'react-native-tracking-transparency' import { View, StyleSheet, ScrollView, Platform, TouchableOpacity, RefreshControl, AppState } from 'react-native'; import { BusinessList as BusinessesListingController, useLanguage, useSession, useOrder, useConfig, useUtils, } from 'ordering-components/native'; import { useTheme } from 'styled-components/native'; import Ionicons from 'react-native-vector-icons/Ionicons' import IconAntDesign from 'react-native-vector-icons/AntDesign'; import { Search, OrderControlContainer, AddressInput, WrapMomentOption, HeaderWrapper, ListWrapper, FeaturedWrapper, OrderProgressWrapper, FarAwayMessage, SearchBarWrapper, MomentWrapper, FilterWrapper, ServiceWrapper, PriceWrapper } from './styles'; import { SearchBar } from '../../../SearchBar'; import { OIcon, OText, OButton } from '../../../shared'; import { BusinessesListingParams } from '../../../../types'; import { NotFoundSource } from '../../../NotFoundSource'; import { BusinessTypeFilter } from '../../../BusinessTypeFilter'; import { BusinessController } from '../../../BusinessController'; import { OrderTypeSelector } from '../../../OrderTypeSelector'; import { useSafeAreaInsets } from 'react-native-safe-area-context'; import { BusinessFeaturedController } from '../../../BusinessFeaturedController'; import { HighestRatedBusinesses } from '../../../HighestRatedBusinesses'; import { getTypesText, convertToRadian, priceList } from '../../../../utils'; import { OrderProgress } from '../../../OrderProgress'; import { useFocusEffect, useIsFocused } from '@react-navigation/native'; import { MomentSelector } from '../../../MomentSelector' const PIXELS_TO_SCROLL = 2000; const BusinessesListingUI = (props: BusinessesListingParams) => { const { navigation, businessesList, searchValue, getBusinesses, handleChangeBusinessType, handleBusinessClick, paginationProps, handleChangeSearch, businessId, isGuestUser, handleUpdateBusinessList, priceLevelSelected, handleChangePriceLevel, businessTypeSelected } = props; const theme = useTheme(); const isFocused = useIsFocused(); const appState = useRef(AppState.currentState) const [appStateVisible, setAppStateVisible] = useState(appState.current); const [refreshing] = useState(false); const styles = StyleSheet.create({ container: { marginBottom: 0, }, welcome: { flex: 1, flexDirection: 'row', }, inputStyle: { backgroundColor: theme.colors.inputDisabled, flex: 1, }, wrapperOrderOptions: { width: '100%', flexDirection: 'row', justifyContent: 'space-between', marginBottom: 10, zIndex: 100 }, borderStyle: { borderColor: theme.colors.backgroundGray, borderWidth: 1, borderRadius: 10, }, searchInput: { fontSize: 12, paddingLeft: 0, paddingRight: 17, paddingTop: 7 }, iconStyle: { fontSize: 18, color: theme.colors.warning5, marginRight: 8 }, farAwayMsg: { paddingVertical: 6, paddingHorizontal: 20 }, inputContainerStyles: { backgroundColor: theme.colors.white, borderColor: theme.colors.backgroundGray, borderWidth: 1, }, priceLevel: { marginRight: 10, borderRadius: 50, paddingVertical: 4, paddingLeft: 5, paddingRight: 5, height: 27, borderWidth: 0 } }); const [, t] = useLanguage(); const [{ user, auth }] = useSession(); const [orderState] = useOrder(); const [{ configs }] = useConfig(); const [{ parseDate }] = useUtils(); const { top } = useSafeAreaInsets(); const [featuredBusiness, setFeaturedBusinesses] = useState(Array); const [isFarAway, setIsFarAway] = useState(false) const [businessTypes, setBusinessTypes] = useState(null) const [orderTypeValue, setOrderTypeValue] = useState(orderState?.options.value) const isPreorderEnabled = (configs?.preorder_status_enabled?.value === '1' || configs?.preorder_status_enabled?.value === 'true') && Number(configs?.max_days_preorder?.value) > 0 const isPreOrderSetting = configs?.preorder_status_enabled?.value === '1' const timerId = useRef(false) const [favoriteIds, setFavoriteIds] = useState([]) // const panResponder = useRef( // PanResponder.create({ // onMoveShouldSetPanResponder: (e, gestureState) => { // const { dx, dy } = gestureState; // resetInactivityTimeout() // return (Math.abs(dx) > 20) || (Math.abs(dy) > 20); // }, // }) // ).current const handleMomentClick = () => { if (isPreorderEnabled) { navigation.navigate('MomentOption') } } const configTypes = configs?.order_types_allowed?.value .split('|') .map((value: any) => Number(value)) || []; const handleScroll = ({ nativeEvent }: any) => { const y = nativeEvent.contentOffset.y; const height = nativeEvent.contentSize.height; const hasMore = !( paginationProps.totalPages === paginationProps.currentPage ); if (y + PIXELS_TO_SCROLL > height && !businessesList.loading && hasMore) { getBusinesses(); } }; const getDistance = (lat1: any, lon1: any, lat2: any, lon2: any) => { const R = 6371 // km const dLat = convertToRadian(lat2 - lat1) const dLon = convertToRadian(lon2 - lon1) const curLat1 = convertToRadian(lat1) const curLat2 = convertToRadian(lat2) const a = Math.sin(dLat / 2) * Math.sin(dLat / 2) + Math.sin(dLon / 2) * Math.sin(dLon / 2) * Math.cos(curLat1) * Math.cos(curLat2) const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)) return R * c } const resetInactivityTimeout = () => { clearTimeout(timerId.current) timerId.current = setInterval(() => { getBusinesses(true) }, 120000) } useEffect(() => { if (!businessesList?.loading) { const fb = businessesList.businesses.filter((b) => b.featured === true && b?.open); const ary = []; while (fb.length > 0) { ary.push(fb.splice(0, 2)); } setFeaturedBusinesses(ary); } resetInactivityTimeout() }, [businessesList.loading]) const handleOnRefresh = () => { if (!businessesList.loading) { getBusinesses(true); } } const checkUserLocation = async () => { let trackingStatus = await getTrackingStatus() if (trackingStatus === 'not-determined') { trackingStatus = await requestTrackingPermission() } if (trackingStatus === 'authorized' || trackingStatus === 'unavailable') { Geolocation.getCurrentPosition((pos) => { const crd = pos.coords const distance = getDistance(crd.latitude, crd.longitude, orderState?.options?.address?.location?.lat, orderState?.options?.address?.location?.lng) if (distance > 20) setIsFarAway(true) else setIsFarAway(false) }, (err) => { console.log(`ERROR(${err.code}): ${err.message}`) }, { enableHighAccuracy: true, timeout: 15000, maximumAge: 10000 }) } } useEffect(() => { checkUserLocation() }, [orderState?.options?.address?.location]) useEffect(() => { if (!orderState?.loading) { setOrderTypeValue(orderState?.options?.type) } }, [orderState?.options?.type]) useFocusEffect( useCallback(() => { resetInactivityTimeout() return () => clearTimeout(timerId.current) }, [navigation]) ) useEffect(() => { if (!businessesList?.businesses?.length) return const ids = [...favoriteIds] businessesList.businesses.forEach((business: any) => { if (business?.favorite) { ids.push(business?.id) } }) setFavoriteIds([...new Set(ids)]) }, [businessesList?.businesses?.length]) return ( handleScroll(e)} showsVerticalScrollIndicator={false} refreshControl={ handleOnRefresh()} /> } > {!auth && ( navigation?.canGoBack() && navigation.goBack()} style={{ position: 'absolute', marginStart: 40, paddingVertical: 20 }}> )} auth ? navigation.navigate('AddressList', { isFromBusinesses: true }) : navigation.navigate('AddressForm', { address: orderState.options?.address, isFromBusinesses: true, isGuestUser: isGuestUser }) }> {orderState?.options?.address?.address} {isFarAway && ( {t('YOU_ARE_FAR_FROM_ADDRESS', 'You are far from this address')} )} navigation.navigate('OrderTypes', { configTypes: configTypes, setOrderTypeValue })}> {t(getTypesText(orderTypeValue || orderState?.options?.type || 1), 'Delivery')} {!businessId && ( handleChangeSearch('')} placeholder={t('SEARCH', 'Search')} height={80} isAppointment isDisabled={!businessTypes || configs?.advanced_business_search_enabled?.value === '1'} inputStyle={{ ...styles.searchInput, ...Platform.OS === 'ios' ? {} : { paddingBottom: 4 } }} onPress={() => { configs?.advanced_business_search_enabled?.value === '1' && navigation.navigate('BusinessSearch', { businessTypes }) }} onSubmitEditing={() => { configs?.advanced_business_search_enabled?.value === '1' && navigation.navigate('BusinessSearch', { businessTypes, defaultTerm: searchValue }) }} /> )} {t('POPULAR_SERVICES', 'Popular services')} {t('PRICE', 'Price')} {priceList?.length > 0 && priceList.map((price, i) => ( handleChangePriceLevel(price?.level)} text={`${price.content} ${(priceLevelSelected === price?.level) ? ' X' : ''}`} style={styles.priceLevel} textStyle={{ fontSize: 10, color: (priceLevelSelected === price?.level) ? theme.colors.backgroundLight : theme.colors.black }} /> ))} { !businessId && !props.franchiseId && featuredBusiness && featuredBusiness.length > 0 && ( {t('BUSINESS_FEATURE', 'Featured business')} {featuredBusiness.map((bAry: any, idx) => ( {bAry.length > 1 && ( )} ))} ) } { !businessId && !props.franchiseId && ( ) } {!businessId && ( )} {!businessesList.loading && businessesList.businesses.length === 0 && ( )} {businessesList.businesses?.map( (business: any, i: number) => ( ) )} {businessesList.loading && ( <> {[ ...Array( paginationProps.nextPageItems ? paginationProps.nextPageItems : 8, ).keys(), ].map((item, i) => ( ))} )} ); }; export const BusinessesListing = (props: BusinessesListingParams) => { const BusinessesListingProps = { ...props, isForceSearch: Platform.OS === 'ios', UIComponent: BusinessesListingUI, }; return ; };