Loading packages/shop-mobile-expo/src/router/drawer.routes.ts +4 −0 Original line number Diff line number Diff line Loading @@ -44,6 +44,10 @@ const DRAWER_ROUTES: DrawerScreenType[] = [ name: 'DRAWER/TRANSLATION', component: SCREENS.APP.Translation, }, { name: 'DRAWER/SEARCH', component: SCREENS.APP.Search, }, { name: 'DRAWER/MERCHANTS_SEARCH', component: SCREENS.APP.MerchantsSearch, Loading packages/shop-mobile-expo/src/screens/app/InStore.screen.tsx +122 −7 Original line number Diff line number Diff line import React from 'react'; import { StyleSheet, Text, View } from 'react-native'; import { View, ActivityIndicator, FlatList, StyleSheet } from 'react-native'; import { Title } from 'react-native-paper'; import { useQuery } from '@apollo/client'; import PagerView from 'react-native-pager-view'; interface Props {} // CONFIGS const InStoreScreen: React.FC<Props> = ({}) => { // TYPES/INTERFACES import type { ProductInfoInterface, ProductsQueryArgsInterface, } from '../../client/products/argumentInterfaces'; // SELECTORS import { useAppSelector } from '../../store/hooks'; import { getUserData, getProductViewType } from '../../store/features/user'; import { getLanguage } from '../../store/features/translation'; // ACTIONS // QUERIES import { GEO_LOCATION_PRODUCTS_BY_PAGING } from '../../client/products/queries'; // COMPONENTS import { FocusAwareStatusBar, CustomScreenHeader, ProductItem, } from '../../components/Common'; // STYLES import { GLOBAL_STYLE as GS } from '../../assets/ts/styles'; function InStoreScreen({}) { // SELECTORS const LANGUAGE = useAppSelector(getLanguage); const USER_DATA = useAppSelector(getUserData); const VIEW_TYPE = useAppSelector(getProductViewType); // DATA const PRODUCTS_QUERY_ARGS_INTERFACE: ProductsQueryArgsInterface = { geoLocation: { loc: { type: 'Point', coordinates: [ USER_DATA?.geoLocation ? USER_DATA?.geoLocation?.coordinates?.lng : 0, USER_DATA?.geoLocation ? USER_DATA?.geoLocation?.coordinates?.lat : 0, ], }, }, }; // QUERIES const PRODUCTS_QUERY_RESPONSE = useQuery(GEO_LOCATION_PRODUCTS_BY_PAGING, { variables: { ...PRODUCTS_QUERY_ARGS_INTERFACE, }, }); // STYLES const STYLES = StyleSheet.create({ main: {}, loaderContainer: { ...GS.centered, ...GS.w100, flex: 1 }, productItemContainer: { ...GS.mx1, ...GS.mt2, ...GS.mb1, }, }); return ( <View style={STYLES.main}> <Text>InStore.screen</Text> <View style={{ ...GS.screen }}> <FocusAwareStatusBar translucent={true} backgroundColor='transparent' barStyle='light-content' /> <CustomScreenHeader title={LANGUAGE.IN_STORE} showBackBtn /> {PRODUCTS_QUERY_RESPONSE.loading ? ( <View style={STYLES.loaderContainer}> <ActivityIndicator color={'#FFF'} size={25} /> </View> ) : PRODUCTS_QUERY_RESPONSE.data?.geoLocationProductsByPaging && PRODUCTS_QUERY_RESPONSE.data?.geoLocationProductsByPaging .length ? ( VIEW_TYPE === 'list' ? ( <FlatList data={ PRODUCTS_QUERY_RESPONSE.data ?.geoLocationProductsByPaging } renderItem={({ item, index }) => ( <View style={STYLES.productItemContainer}> <ProductItem type={VIEW_TYPE} data={{ ...item, id: index }} /> </View> )} keyExtractor={(_item, _index) => _index.toString()} style={{ ...GS.h100 }} /> ) : ( <PagerView style={{ ...GS.screen }}> {PRODUCTS_QUERY_RESPONSE.data?.geoLocationProductsByPaging?.map( (item: ProductInfoInterface, index: number) => ( <View key={index}> <ProductItem key={index} type={VIEW_TYPE} data={{ ...item }} /> </View> ), )} </PagerView> ) ) : ( <View style={{ ...GS.screen, ...GS.centered }}> <Title>Nothing to buy for now.</Title> </View> )} </View> ); }; } export default InStoreScreen; packages/shop-mobile-expo/src/screens/app/Search.screen.tsx 0 → 100644 +229 −0 Original line number Diff line number Diff line import React from 'react'; import { View, ActivityIndicator, StyleSheet, ScrollView } from 'react-native'; import { Button, TextInput, Title, Text } from 'react-native-paper'; import { useLazyQuery } from '@apollo/client'; // tslint:disable-next-line: no-implicit-dependencies no-submodule-imports import MaterialIcon from '@expo/vector-icons/MaterialCommunityIcons'; import { debounce } from 'lodash'; // TYPES/INTERFACES import { QueryGetMerchantsByNameArgsInterface, MerchantsSearchedInterface, } from '../../client/merchants/argumentInterfaces'; // HELPERS import { isEmpty } from '../../helpers/utils'; // STORE import { useAppSelector } from '../../store/hooks'; import { getUserData } from '../../store/features/user'; import { getLanguage } from '../../store/features/translation'; // QUERIES import { GET_MERCHANTS_QUERY } from '../../client/merchants/queries'; // COMPONENTS import { FocusAwareStatusBar, CustomScreenHeader, TouchableCard, } from '../../components/Common'; // STYLES import { GLOBAL_STYLE as GS, CONSTANT_COLOR as CC, CONSTANT_SIZE as CS, } from '../../assets/ts/styles'; function SearchScreen({}) { // SELECTORS const LANGUAGE = useAppSelector(getLanguage); const USER_DATA = useAppSelector(getUserData); // STATES const [searchedValue, setSearchedValue] = React.useState<string>(''); const [dataLoading, setDataLoading] = React.useState<boolean>(false); // QUERIES const SEARCH_QUERY = useLazyQuery(GET_MERCHANTS_QUERY); const STYLES = StyleSheet.create({ loaderContainer: { ...GS.centered, ...GS.w100, flex: 1 }, searchContainer: { ...GS.px2, ...GS.row, ...GS.centered, ...GS.pt2, height: 90, backgroundColor: CC.dark, }, containerSearchInput: { ...GS.flex1, ...GS.mr2, height: 57 }, searchInput: { ...GS.bgLight, ...GS.flex1, marginTop: -6, color: CC.dark, fontSize: CS.FONT_SIZE - 1, }, scanBtn: { ...GS.p0, ...GS.my0, ...GS.justifyCenter, height: 57 }, searchedText: { ...GS.FF_NunitoBold, ...GS.txtUpper }, }); // FUNCTIONS const debouncedFetchData = React.useMemo( () => debounce((text: string) => { const MERCHANT_SEARCH_QUERY_ARGS: QueryGetMerchantsByNameArgsInterface = { searchName: text, ...(isEmpty(text) ? { geoLocation: { city: USER_DATA?.geoLocation.city, countryId: USER_DATA?.geoLocation?.countryId, countryName: USER_DATA?.geoLocation?.countryName, streetAddress: USER_DATA?.geoLocation ?.streetAddress, postcode: USER_DATA?.geoLocation?.postcode, house: USER_DATA?.geoLocation?.house, loc: { type: USER_DATA?.geoLocation ?.coordinates?.__typename || '', coordinates: [ USER_DATA?.geoLocation ?.coordinates?.lng || 0, USER_DATA?.geoLocation ?.coordinates?.lat || 0, ], }, }, } : {}), }; setDataLoading(false); SEARCH_QUERY[0]({ variables: MERCHANT_SEARCH_QUERY_ARGS, }); }, 500), // eslint-disable-next-line react-hooks/exhaustive-deps [], ); // EFFECTS React.useEffect(() => { debouncedFetchData(searchedValue); return () => debouncedFetchData.cancel(); // eslint-disable-next-line react-hooks/exhaustive-deps }, [searchedValue]); return ( <View style={{ ...GS.screen }}> <FocusAwareStatusBar translucent={true} backgroundColor='transparent' barStyle='light-content' /> <CustomScreenHeader title={LANGUAGE.PRODUCTS_VIEW.TITLE} showBackBtn /> <View style={STYLES.searchContainer}> <View style={STYLES.containerSearchInput}> <TextInput value={searchedValue} placeholder={LANGUAGE.MERCHANTS_VIEW.NAME} style={STYLES.searchInput} theme={{ colors: { text: CC.dark }, roundness: CS.SPACE, }} placeholderTextColor={CC.gray} left={ <TextInput.Icon name='search' color={CC.dark} size={18} style={GS.mt1} /> } onChangeText={(text) => { setDataLoading(true); setSearchedValue(text); }} mode='outlined' /> </View> <Button style={STYLES.scanBtn} theme={{ roundness: CS.SPACE }} uppercase={false} mode='contained'> <MaterialIcon name='qrcode-scan' color={CC.light} size={16} />{' '} {LANGUAGE.SCAN} </Button> </View> <View style={{ ...GS.centered, ...GS.pt3, ...GS.pb4 }}> <Text style={STYLES.searchedText}> {!isEmpty(searchedValue) ? LANGUAGE.MERCHANTS_VIEW.WITH_NAME + ' "' + searchedValue + '"' : LANGUAGE.MERCHANTS_VIEW.CLOSE_TO_YOU} </Text> </View> {SEARCH_QUERY[1].loading || dataLoading ? ( <View style={STYLES.loaderContainer}> <ActivityIndicator color={CC.white} size={25} /> </View> ) : SEARCH_QUERY[1]?.data?.getMerchantsBuyName?.length ? ( <ScrollView style={{ ...GS.screen }} contentContainerStyle={{ ...GS.px2 }}> {(SEARCH_QUERY[1]?.data ? (SEARCH_QUERY[1]?.data ?.getMerchantsBuyName as MerchantsSearchedInterface[]) : [] ).map((_item, _index) => ( <TouchableCard key={_index} img={_item.logo} title={_item.name} titleStyle={{ color: CC.primary }} indicatorIconProps={{ name: 'chevron-right' }} height={65} style={GS.mb2} onPress={() => {}} /> ))} </ScrollView> ) : ( <ScrollView style={{ ...GS.screen }} contentContainerStyle={{ ...GS.screen, ...GS.centered }}> <Title>{LANGUAGE.NOT_FOUND}</Title> </ScrollView> )} </View> ); } export default SearchScreen; packages/shop-mobile-expo/src/screens/index.ts +2 −0 Original line number Diff line number Diff line Loading @@ -11,6 +11,7 @@ import HomeScreen from './app/Home.screen'; import OrderHistoryScreen from './app/OrderHistory.screen'; import AccountScreen from './app/Account.screen'; import TranslationScreen from './app/Translation.screen'; import SearchScreen from './app/Search.screen'; import MerchantsSearchScreen from './app/MerchantsSearch.screen'; import InStoreScreen from './app/InStore.screen'; Loading @@ -25,6 +26,7 @@ const SCREENS = { OrderHistory: OrderHistoryScreen, Account: AccountScreen, Translation: TranslationScreen, Search: SearchScreen, MerchantsSearch: MerchantsSearchScreen, InStore: InStoreScreen, }, Loading Loading
packages/shop-mobile-expo/src/router/drawer.routes.ts +4 −0 Original line number Diff line number Diff line Loading @@ -44,6 +44,10 @@ const DRAWER_ROUTES: DrawerScreenType[] = [ name: 'DRAWER/TRANSLATION', component: SCREENS.APP.Translation, }, { name: 'DRAWER/SEARCH', component: SCREENS.APP.Search, }, { name: 'DRAWER/MERCHANTS_SEARCH', component: SCREENS.APP.MerchantsSearch, Loading
packages/shop-mobile-expo/src/screens/app/InStore.screen.tsx +122 −7 Original line number Diff line number Diff line import React from 'react'; import { StyleSheet, Text, View } from 'react-native'; import { View, ActivityIndicator, FlatList, StyleSheet } from 'react-native'; import { Title } from 'react-native-paper'; import { useQuery } from '@apollo/client'; import PagerView from 'react-native-pager-view'; interface Props {} // CONFIGS const InStoreScreen: React.FC<Props> = ({}) => { // TYPES/INTERFACES import type { ProductInfoInterface, ProductsQueryArgsInterface, } from '../../client/products/argumentInterfaces'; // SELECTORS import { useAppSelector } from '../../store/hooks'; import { getUserData, getProductViewType } from '../../store/features/user'; import { getLanguage } from '../../store/features/translation'; // ACTIONS // QUERIES import { GEO_LOCATION_PRODUCTS_BY_PAGING } from '../../client/products/queries'; // COMPONENTS import { FocusAwareStatusBar, CustomScreenHeader, ProductItem, } from '../../components/Common'; // STYLES import { GLOBAL_STYLE as GS } from '../../assets/ts/styles'; function InStoreScreen({}) { // SELECTORS const LANGUAGE = useAppSelector(getLanguage); const USER_DATA = useAppSelector(getUserData); const VIEW_TYPE = useAppSelector(getProductViewType); // DATA const PRODUCTS_QUERY_ARGS_INTERFACE: ProductsQueryArgsInterface = { geoLocation: { loc: { type: 'Point', coordinates: [ USER_DATA?.geoLocation ? USER_DATA?.geoLocation?.coordinates?.lng : 0, USER_DATA?.geoLocation ? USER_DATA?.geoLocation?.coordinates?.lat : 0, ], }, }, }; // QUERIES const PRODUCTS_QUERY_RESPONSE = useQuery(GEO_LOCATION_PRODUCTS_BY_PAGING, { variables: { ...PRODUCTS_QUERY_ARGS_INTERFACE, }, }); // STYLES const STYLES = StyleSheet.create({ main: {}, loaderContainer: { ...GS.centered, ...GS.w100, flex: 1 }, productItemContainer: { ...GS.mx1, ...GS.mt2, ...GS.mb1, }, }); return ( <View style={STYLES.main}> <Text>InStore.screen</Text> <View style={{ ...GS.screen }}> <FocusAwareStatusBar translucent={true} backgroundColor='transparent' barStyle='light-content' /> <CustomScreenHeader title={LANGUAGE.IN_STORE} showBackBtn /> {PRODUCTS_QUERY_RESPONSE.loading ? ( <View style={STYLES.loaderContainer}> <ActivityIndicator color={'#FFF'} size={25} /> </View> ) : PRODUCTS_QUERY_RESPONSE.data?.geoLocationProductsByPaging && PRODUCTS_QUERY_RESPONSE.data?.geoLocationProductsByPaging .length ? ( VIEW_TYPE === 'list' ? ( <FlatList data={ PRODUCTS_QUERY_RESPONSE.data ?.geoLocationProductsByPaging } renderItem={({ item, index }) => ( <View style={STYLES.productItemContainer}> <ProductItem type={VIEW_TYPE} data={{ ...item, id: index }} /> </View> )} keyExtractor={(_item, _index) => _index.toString()} style={{ ...GS.h100 }} /> ) : ( <PagerView style={{ ...GS.screen }}> {PRODUCTS_QUERY_RESPONSE.data?.geoLocationProductsByPaging?.map( (item: ProductInfoInterface, index: number) => ( <View key={index}> <ProductItem key={index} type={VIEW_TYPE} data={{ ...item }} /> </View> ), )} </PagerView> ) ) : ( <View style={{ ...GS.screen, ...GS.centered }}> <Title>Nothing to buy for now.</Title> </View> )} </View> ); }; } export default InStoreScreen;
packages/shop-mobile-expo/src/screens/app/Search.screen.tsx 0 → 100644 +229 −0 Original line number Diff line number Diff line import React from 'react'; import { View, ActivityIndicator, StyleSheet, ScrollView } from 'react-native'; import { Button, TextInput, Title, Text } from 'react-native-paper'; import { useLazyQuery } from '@apollo/client'; // tslint:disable-next-line: no-implicit-dependencies no-submodule-imports import MaterialIcon from '@expo/vector-icons/MaterialCommunityIcons'; import { debounce } from 'lodash'; // TYPES/INTERFACES import { QueryGetMerchantsByNameArgsInterface, MerchantsSearchedInterface, } from '../../client/merchants/argumentInterfaces'; // HELPERS import { isEmpty } from '../../helpers/utils'; // STORE import { useAppSelector } from '../../store/hooks'; import { getUserData } from '../../store/features/user'; import { getLanguage } from '../../store/features/translation'; // QUERIES import { GET_MERCHANTS_QUERY } from '../../client/merchants/queries'; // COMPONENTS import { FocusAwareStatusBar, CustomScreenHeader, TouchableCard, } from '../../components/Common'; // STYLES import { GLOBAL_STYLE as GS, CONSTANT_COLOR as CC, CONSTANT_SIZE as CS, } from '../../assets/ts/styles'; function SearchScreen({}) { // SELECTORS const LANGUAGE = useAppSelector(getLanguage); const USER_DATA = useAppSelector(getUserData); // STATES const [searchedValue, setSearchedValue] = React.useState<string>(''); const [dataLoading, setDataLoading] = React.useState<boolean>(false); // QUERIES const SEARCH_QUERY = useLazyQuery(GET_MERCHANTS_QUERY); const STYLES = StyleSheet.create({ loaderContainer: { ...GS.centered, ...GS.w100, flex: 1 }, searchContainer: { ...GS.px2, ...GS.row, ...GS.centered, ...GS.pt2, height: 90, backgroundColor: CC.dark, }, containerSearchInput: { ...GS.flex1, ...GS.mr2, height: 57 }, searchInput: { ...GS.bgLight, ...GS.flex1, marginTop: -6, color: CC.dark, fontSize: CS.FONT_SIZE - 1, }, scanBtn: { ...GS.p0, ...GS.my0, ...GS.justifyCenter, height: 57 }, searchedText: { ...GS.FF_NunitoBold, ...GS.txtUpper }, }); // FUNCTIONS const debouncedFetchData = React.useMemo( () => debounce((text: string) => { const MERCHANT_SEARCH_QUERY_ARGS: QueryGetMerchantsByNameArgsInterface = { searchName: text, ...(isEmpty(text) ? { geoLocation: { city: USER_DATA?.geoLocation.city, countryId: USER_DATA?.geoLocation?.countryId, countryName: USER_DATA?.geoLocation?.countryName, streetAddress: USER_DATA?.geoLocation ?.streetAddress, postcode: USER_DATA?.geoLocation?.postcode, house: USER_DATA?.geoLocation?.house, loc: { type: USER_DATA?.geoLocation ?.coordinates?.__typename || '', coordinates: [ USER_DATA?.geoLocation ?.coordinates?.lng || 0, USER_DATA?.geoLocation ?.coordinates?.lat || 0, ], }, }, } : {}), }; setDataLoading(false); SEARCH_QUERY[0]({ variables: MERCHANT_SEARCH_QUERY_ARGS, }); }, 500), // eslint-disable-next-line react-hooks/exhaustive-deps [], ); // EFFECTS React.useEffect(() => { debouncedFetchData(searchedValue); return () => debouncedFetchData.cancel(); // eslint-disable-next-line react-hooks/exhaustive-deps }, [searchedValue]); return ( <View style={{ ...GS.screen }}> <FocusAwareStatusBar translucent={true} backgroundColor='transparent' barStyle='light-content' /> <CustomScreenHeader title={LANGUAGE.PRODUCTS_VIEW.TITLE} showBackBtn /> <View style={STYLES.searchContainer}> <View style={STYLES.containerSearchInput}> <TextInput value={searchedValue} placeholder={LANGUAGE.MERCHANTS_VIEW.NAME} style={STYLES.searchInput} theme={{ colors: { text: CC.dark }, roundness: CS.SPACE, }} placeholderTextColor={CC.gray} left={ <TextInput.Icon name='search' color={CC.dark} size={18} style={GS.mt1} /> } onChangeText={(text) => { setDataLoading(true); setSearchedValue(text); }} mode='outlined' /> </View> <Button style={STYLES.scanBtn} theme={{ roundness: CS.SPACE }} uppercase={false} mode='contained'> <MaterialIcon name='qrcode-scan' color={CC.light} size={16} />{' '} {LANGUAGE.SCAN} </Button> </View> <View style={{ ...GS.centered, ...GS.pt3, ...GS.pb4 }}> <Text style={STYLES.searchedText}> {!isEmpty(searchedValue) ? LANGUAGE.MERCHANTS_VIEW.WITH_NAME + ' "' + searchedValue + '"' : LANGUAGE.MERCHANTS_VIEW.CLOSE_TO_YOU} </Text> </View> {SEARCH_QUERY[1].loading || dataLoading ? ( <View style={STYLES.loaderContainer}> <ActivityIndicator color={CC.white} size={25} /> </View> ) : SEARCH_QUERY[1]?.data?.getMerchantsBuyName?.length ? ( <ScrollView style={{ ...GS.screen }} contentContainerStyle={{ ...GS.px2 }}> {(SEARCH_QUERY[1]?.data ? (SEARCH_QUERY[1]?.data ?.getMerchantsBuyName as MerchantsSearchedInterface[]) : [] ).map((_item, _index) => ( <TouchableCard key={_index} img={_item.logo} title={_item.name} titleStyle={{ color: CC.primary }} indicatorIconProps={{ name: 'chevron-right' }} height={65} style={GS.mb2} onPress={() => {}} /> ))} </ScrollView> ) : ( <ScrollView style={{ ...GS.screen }} contentContainerStyle={{ ...GS.screen, ...GS.centered }}> <Title>{LANGUAGE.NOT_FOUND}</Title> </ScrollView> )} </View> ); } export default SearchScreen;
packages/shop-mobile-expo/src/screens/index.ts +2 −0 Original line number Diff line number Diff line Loading @@ -11,6 +11,7 @@ import HomeScreen from './app/Home.screen'; import OrderHistoryScreen from './app/OrderHistory.screen'; import AccountScreen from './app/Account.screen'; import TranslationScreen from './app/Translation.screen'; import SearchScreen from './app/Search.screen'; import MerchantsSearchScreen from './app/MerchantsSearch.screen'; import InStoreScreen from './app/InStore.screen'; Loading @@ -25,6 +26,7 @@ const SCREENS = { OrderHistory: OrderHistoryScreen, Account: AccountScreen, Translation: TranslationScreen, Search: SearchScreen, MerchantsSearch: MerchantsSearchScreen, InStore: InStoreScreen, }, Loading