├── .expo-shared └── assets.json ├── .gitignore ├── App.tsx ├── README.md ├── app.json ├── app ├── hooks.ts ├── slices │ └── navigationSlice.ts └── store.ts ├── assets ├── adaptive-icon.png ├── favicon.png ├── icon.png ├── screenshots │ ├── Screenshot_1634302767.jpg │ ├── Screenshot_1634302842.jpg │ ├── Screenshot_1634302884.jpg │ ├── ezgif-7-2d01dc3b82b1.gif │ └── logo.png └── splash.png ├── babel.config.js ├── components ├── HomeNavigation.tsx ├── Map.tsx ├── MapScreenNavigation.tsx ├── NavFavorites.tsx ├── NavOptions.tsx ├── NavigateCard.tsx └── RideOptionsCard.tsx ├── env.d.ts ├── package-lock.json ├── package.json ├── screens ├── EatsScreen.tsx ├── HomeScreen.tsx └── MapScreen.tsx └── tsconfig.json /.expo-shared/assets.json: -------------------------------------------------------------------------------- 1 | { 2 | "12bb71342c6255bbf50437ec8f4441c083f47cdb74bd89160c15e4f43e52a1cb": true, 3 | "40b842e832070c58deac6aa9e08fa459302ee3f9da492c7e77d93d2fbf4a56fd": true 4 | } 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | .expo/ 3 | npm-debug.* 4 | *.jks 5 | *.p8 6 | *.p12 7 | *.key 8 | *.mobileprovision 9 | *.orig.* 10 | web-build/ 11 | 12 | # macOS 13 | .DS_Store 14 | 15 | .env 16 | -------------------------------------------------------------------------------- /App.tsx: -------------------------------------------------------------------------------- 1 | import "intl"; 2 | import "intl/locale-data/jsonp/en"; 3 | 4 | import { KeyboardAvoidingView, Platform } from "react-native"; 5 | 6 | import HomeNavigation from "./components/HomeNavigation"; 7 | import { NavigationContainer } from "@react-navigation/native"; 8 | import { Provider } from "react-redux"; 9 | import React from "react"; 10 | import { SafeAreaProvider } from "react-native-safe-area-context"; 11 | import { store } from "./app/store"; 12 | 13 | export default function App() { 14 | return ( 15 | 16 | 17 | 18 | 23 | 24 | 25 | 26 | 27 | 28 | ); 29 | } 30 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # React Native Uber Clone 2 | 3 | A cross-platform Uber clone app built with React Native, Expo 4 | 5 | ## Demo 6 | 7 | React native uber clone 8 | 9 | ## Features 10 | 11 | - Cross platform (Web, iOS, Android) 12 | - Pick origin and destination 13 | - Pick ride type (UberX, Uber XL, Uber LUX) 14 | - Show fare and travel distance 15 | - Show travel time 16 | 17 | ## Run Locally 18 | 19 | Clone the project 20 | 21 | ```bash 22 | git clone https://github.com/emmanuelchucks/react-native-uber-clone.git 23 | ``` 24 | 25 | Go to the project directory 26 | 27 | ```bash 28 | cd react-native-uber-clone 29 | ``` 30 | 31 | Install dependencies 32 | 33 | ```bash 34 | npm install 35 | ``` 36 | 37 | Start the server 38 | 39 | ```bash 40 | npm start 41 | ``` 42 | 43 | ## Screenshots 44 | 45 | Screen to pick an origin Screen to pick a destination Screen to pick a ride 46 | -------------------------------------------------------------------------------- /app.json: -------------------------------------------------------------------------------- 1 | { 2 | "expo": { 3 | "name": "UberClone", 4 | "slug": "UberClone", 5 | "version": "1.0.0", 6 | "orientation": "portrait", 7 | "icon": "./assets/icon.png", 8 | "splash": { 9 | "image": "./assets/splash.png", 10 | "resizeMode": "contain", 11 | "backgroundColor": "#ffffff" 12 | }, 13 | "updates": { 14 | "fallbackToCacheTimeout": 0 15 | }, 16 | "assetBundlePatterns": [ 17 | "**/*" 18 | ], 19 | "ios": { 20 | "supportsTablet": true 21 | }, 22 | "android": { 23 | "adaptiveIcon": { 24 | "foregroundImage": "./assets/adaptive-icon.png", 25 | "backgroundColor": "#FFFFFF" 26 | } 27 | }, 28 | "web": { 29 | "favicon": "./assets/favicon.png" 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /app/hooks.ts: -------------------------------------------------------------------------------- 1 | import type { AppDispatch, RootState } from "./store"; 2 | import { TypedUseSelectorHook, useDispatch, useSelector } from "react-redux"; 3 | 4 | export const useAppDispatch = () => useDispatch(); 5 | export const useAppSelector: TypedUseSelectorHook = useSelector; 6 | -------------------------------------------------------------------------------- /app/slices/navigationSlice.ts: -------------------------------------------------------------------------------- 1 | import { PayloadAction, createSlice } from "@reduxjs/toolkit"; 2 | 3 | import { Point } from "react-native-google-places-autocomplete"; 4 | import { RootState } from "../../app/store"; 5 | 6 | type DistanceMatrix = { 7 | distance: { 8 | text: string; 9 | value: number; 10 | }; 11 | duration: { 12 | text: string; 13 | value: number; 14 | }; 15 | status: string; 16 | }; 17 | 18 | type NavigationState = { 19 | origin: { location: Point | undefined; description: string } | null; 20 | destination: { location: Point | undefined; description: string } | null; 21 | travelTimeInfo: DistanceMatrix | null; 22 | }; 23 | 24 | const initialState: NavigationState = { 25 | origin: null, 26 | destination: null, 27 | travelTimeInfo: null, 28 | }; 29 | 30 | export const navigationSlice = createSlice({ 31 | name: "navigation", 32 | initialState, 33 | reducers: { 34 | setOrigin: (state, action: PayloadAction) => { 35 | state.origin = action.payload; 36 | }, 37 | setDestination: ( 38 | state, 39 | action: PayloadAction 40 | ) => { 41 | state.destination = action.payload; 42 | }, 43 | setTravelTimeInfo: (state, action: PayloadAction) => { 44 | state.travelTimeInfo = action.payload; 45 | }, 46 | }, 47 | }); 48 | 49 | export const { setOrigin, setDestination, setTravelTimeInfo } = 50 | navigationSlice.actions; 51 | 52 | export const selectOrigin = (state: RootState) => state.navigation.origin; 53 | export const selectDestination = (state: RootState) => 54 | state.navigation.destination; 55 | export const selectTravelTimeInfo = (state: RootState) => 56 | state.navigation.travelTimeInfo; 57 | 58 | export default navigationSlice.reducer; 59 | -------------------------------------------------------------------------------- /app/store.ts: -------------------------------------------------------------------------------- 1 | import { configureStore } from "@reduxjs/toolkit"; 2 | import navigationReducer from "./slices/navigationSlice"; 3 | 4 | export const store = configureStore({ 5 | reducer: { navigation: navigationReducer }, 6 | }); 7 | 8 | export type RootState = ReturnType; 9 | export type AppDispatch = typeof store.dispatch; 10 | -------------------------------------------------------------------------------- /assets/adaptive-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emmanuelchucks/react-native-uber-clone/af032325f5536a9351900b7393b26de0c5d9b186/assets/adaptive-icon.png -------------------------------------------------------------------------------- /assets/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emmanuelchucks/react-native-uber-clone/af032325f5536a9351900b7393b26de0c5d9b186/assets/favicon.png -------------------------------------------------------------------------------- /assets/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emmanuelchucks/react-native-uber-clone/af032325f5536a9351900b7393b26de0c5d9b186/assets/icon.png -------------------------------------------------------------------------------- /assets/screenshots/Screenshot_1634302767.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emmanuelchucks/react-native-uber-clone/af032325f5536a9351900b7393b26de0c5d9b186/assets/screenshots/Screenshot_1634302767.jpg -------------------------------------------------------------------------------- /assets/screenshots/Screenshot_1634302842.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emmanuelchucks/react-native-uber-clone/af032325f5536a9351900b7393b26de0c5d9b186/assets/screenshots/Screenshot_1634302842.jpg -------------------------------------------------------------------------------- /assets/screenshots/Screenshot_1634302884.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emmanuelchucks/react-native-uber-clone/af032325f5536a9351900b7393b26de0c5d9b186/assets/screenshots/Screenshot_1634302884.jpg -------------------------------------------------------------------------------- /assets/screenshots/ezgif-7-2d01dc3b82b1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emmanuelchucks/react-native-uber-clone/af032325f5536a9351900b7393b26de0c5d9b186/assets/screenshots/ezgif-7-2d01dc3b82b1.gif -------------------------------------------------------------------------------- /assets/screenshots/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emmanuelchucks/react-native-uber-clone/af032325f5536a9351900b7393b26de0c5d9b186/assets/screenshots/logo.png -------------------------------------------------------------------------------- /assets/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emmanuelchucks/react-native-uber-clone/af032325f5536a9351900b7393b26de0c5d9b186/assets/splash.png -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = function (api) { 2 | api.cache(true); 3 | return { 4 | presets: ["babel-preset-expo"], 5 | plugins: [ 6 | [ 7 | "module:react-native-dotenv", 8 | { 9 | moduleName: "@env", 10 | path: ".env", 11 | }, 12 | ], 13 | ], 14 | }; 15 | }; 16 | -------------------------------------------------------------------------------- /components/HomeNavigation.tsx: -------------------------------------------------------------------------------- 1 | import EatsScreen from "../screens/EatsScreen"; 2 | import HomeScreen from "../screens/HomeScreen"; 3 | import MapScreen from "../screens/MapScreen"; 4 | import React from "react"; 5 | import { createNativeStackNavigator } from "@react-navigation/native-stack"; 6 | 7 | export type StackList = { 8 | HomeScreen: undefined; 9 | MapScreen: undefined; 10 | EatsScreen: undefined; 11 | }; 12 | 13 | const Stack = createNativeStackNavigator(); 14 | 15 | const HomeNavigation = () => { 16 | return ( 17 | 18 | 25 | 32 | 39 | 40 | ); 41 | }; 42 | 43 | export default HomeNavigation; 44 | -------------------------------------------------------------------------------- /components/Map.tsx: -------------------------------------------------------------------------------- 1 | import MapView, { Marker } from "react-native-maps"; 2 | import React, { useEffect, useRef } from "react"; 3 | import { 4 | selectDestination, 5 | selectOrigin, 6 | setTravelTimeInfo, 7 | } from "../app/slices/navigationSlice"; 8 | import { useDispatch, useSelector } from "react-redux"; 9 | 10 | import { GOOGLE_MAPS_API_KEY } from "@env"; 11 | import MapViewDirections from "react-native-maps-directions"; 12 | import tailwind from "tailwind-react-native-classnames"; 13 | 14 | const Map = () => { 15 | const dispatch = useDispatch(); 16 | const origin = useSelector(selectOrigin); 17 | const destination = useSelector(selectDestination); 18 | const mapRef = useRef(null); 19 | 20 | useEffect(() => { 21 | if (!origin || !destination) return; 22 | 23 | mapRef.current?.fitToSuppliedMarkers(["origin", "destination"], { 24 | edgePadding: { top: 50, right: 50, bottom: 50, left: 50 }, 25 | }); 26 | }, [origin, destination]); 27 | 28 | useEffect(() => { 29 | if (!origin || !destination) return; 30 | 31 | const getTravelTime = async () => { 32 | const url = `https://maps.googleapis.com/maps/api/distancematrix/json?units=imperial&origins=${origin.description}&destinations=${destination.description}&key=${GOOGLE_MAPS_API_KEY}`; 33 | const response = await fetch(url); 34 | const data = await response.json(); 35 | dispatch(setTravelTimeInfo(data.rows[0].elements[0])); 36 | }; 37 | 38 | getTravelTime(); 39 | }, [origin, destination, GOOGLE_MAPS_API_KEY]); 40 | 41 | return ( 42 | 53 | {origin && destination && ( 54 | 62 | )} 63 | 64 | {origin?.location && ( 65 | 74 | )} 75 | 76 | {destination?.location && ( 77 | 86 | )} 87 | 88 | ); 89 | }; 90 | 91 | export default Map; 92 | -------------------------------------------------------------------------------- /components/MapScreenNavigation.tsx: -------------------------------------------------------------------------------- 1 | import NavigateCard from "./NavigateCard"; 2 | import React from "react"; 3 | import RideOptionsCard from "./RideOptionsCard"; 4 | import { createNativeStackNavigator } from "@react-navigation/native-stack"; 5 | 6 | export type StackList = { 7 | NavigateCard: undefined; 8 | RideOptionsCard: undefined; 9 | }; 10 | 11 | const Stack = createNativeStackNavigator(); 12 | 13 | const MapScreenNavigation = () => { 14 | return ( 15 | 16 | {/* */} 23 | 30 | 37 | 38 | ); 39 | }; 40 | 41 | export default MapScreenNavigation; 42 | -------------------------------------------------------------------------------- /components/NavFavorites.tsx: -------------------------------------------------------------------------------- 1 | import { FlatList, Text, TouchableOpacity, View } from "react-native"; 2 | import { 3 | selectOrigin, 4 | setDestination, 5 | setOrigin, 6 | } from "../app/slices/navigationSlice"; 7 | import { useDispatch, useSelector } from "react-redux"; 8 | 9 | import { HomeScreenProp } from "./NavOptions"; 10 | import { Icon } from "react-native-elements"; 11 | import { Point } from "react-native-google-places-autocomplete"; 12 | import React from "react"; 13 | import tailwind from "tailwind-react-native-classnames"; 14 | import { useNavigation } from "@react-navigation/native"; 15 | 16 | const NavFavorites = ({ shouldSetOrigin }: { shouldSetOrigin?: boolean }) => { 17 | const dispatch = useDispatch(); 18 | const origin = useSelector(selectOrigin); 19 | const navigation = useNavigation(); 20 | 21 | return ( 22 | shouldSetOrigin || origin?.location !== item.location 26 | )} 27 | keyExtractor={(item) => item.id} 28 | ItemSeparatorComponent={() => ( 29 | 37 | )} 38 | renderItem={({ item: { name, icon, location, description } }) => ( 39 | { 42 | if (shouldSetOrigin) { 43 | dispatch( 44 | setOrigin({ 45 | location, 46 | description, 47 | }) 48 | ); 49 | navigation.navigate("MapScreen"); 50 | } else { 51 | dispatch( 52 | setDestination({ 53 | location, 54 | description, 55 | }) 56 | ); 57 | } 58 | }} 59 | > 60 | 67 | 68 | {name} 69 | {description} 70 | 71 | 72 | )} 73 | /> 74 | ); 75 | }; 76 | 77 | type FavoritesData = { 78 | id: string; 79 | name: string; 80 | icon: string; 81 | location: Point; 82 | description: string; 83 | }[]; 84 | 85 | const favoritesData: FavoritesData = [ 86 | { 87 | id: "234", 88 | icon: "home", 89 | name: "Home", 90 | location: { lat: 5.4945, lng: -0.4118 }, 91 | description: "Jordan Gospel Centre, Land of Grace", 92 | }, 93 | { 94 | id: "567", 95 | icon: "briefcase", 96 | name: "Work", 97 | location: { lat: 5.5497, lng: -0.3522 }, 98 | description: "Finger Bites Kitchen, Mile 11", 99 | }, 100 | ]; 101 | 102 | export default NavFavorites; 103 | -------------------------------------------------------------------------------- /components/NavOptions.tsx: -------------------------------------------------------------------------------- 1 | import { FlatList, Image, Text, TouchableOpacity, View } from "react-native"; 2 | 3 | import { Icon } from "react-native-elements"; 4 | import { NativeStackNavigationProp } from "@react-navigation/native-stack"; 5 | import React from "react"; 6 | import { StackList } from "./HomeNavigation"; 7 | import { selectOrigin } from "../app/slices/navigationSlice"; 8 | import tailwind from "tailwind-react-native-classnames"; 9 | import { useNavigation } from "@react-navigation/native"; 10 | import { useSelector } from "react-redux"; 11 | 12 | const NavOptions = () => { 13 | const navigation = useNavigation(); 14 | const origin = useSelector(selectOrigin); 15 | 16 | return ( 17 | item.id} 21 | renderItem={({ item }) => ( 22 | navigation.navigate(item.screen)} 25 | style={tailwind`pr-2 pl-6 pt-4 pb-8 bg-gray-200 mr-2 mb-5 w-40 rounded-md`} 26 | > 27 | 28 | 32 | {item.title} 33 | 39 | 40 | 41 | )} 42 | /> 43 | ); 44 | }; 45 | 46 | type NavData = { 47 | id: string; 48 | title: string; 49 | image: string; 50 | screen: keyof StackList; 51 | }[]; 52 | 53 | export const navData: NavData = [ 54 | { 55 | id: "123", 56 | title: "Get a ride", 57 | image: "https://links.papareact.com/3pn", 58 | screen: "MapScreen", 59 | }, 60 | { 61 | id: "456", 62 | title: "Order Food", 63 | image: "https://links.papareact.com/28w", 64 | screen: "EatsScreen", 65 | }, 66 | ]; 67 | 68 | export type HomeScreenProp = NativeStackNavigationProp; 69 | 70 | export default NavOptions; 71 | -------------------------------------------------------------------------------- /components/NavigateCard.tsx: -------------------------------------------------------------------------------- 1 | import { StyleSheet, Text, TouchableOpacity, View } from "react-native"; 2 | 3 | import { GOOGLE_MAPS_API_KEY } from "@env"; 4 | import { GooglePlacesAutocomplete } from "react-native-google-places-autocomplete"; 5 | import { Icon } from "react-native-elements"; 6 | import { NativeStackNavigationProp } from "@react-navigation/native-stack"; 7 | import NavFavorites from "./NavFavorites"; 8 | import React from "react"; 9 | import { SafeAreaView } from "react-native-safe-area-context"; 10 | import { StackList } from "./MapScreenNavigation"; 11 | import { setDestination } from "../app/slices/navigationSlice"; 12 | import tailwind from "tailwind-react-native-classnames"; 13 | import { useDispatch } from "react-redux"; 14 | import { useNavigation } from "@react-navigation/native"; 15 | 16 | const NavigateCard = () => { 17 | const dispatch = useDispatch(); 18 | const navigation = useNavigation(); 19 | 20 | return ( 21 | 22 | 23 | 24 | Good morning, Papi 25 | 26 | 27 | { 39 | dispatch( 40 | setDestination({ 41 | location: details?.geometry.location, 42 | description: data.description, 43 | }) 44 | ); 45 | navigation.navigate("RideOptionsCard"); 46 | }} 47 | /> 48 | 49 | 50 | 51 | 52 | 53 | 56 | navigation.navigate("RideOptionsCard")} 59 | > 60 | 61 | Rides 62 | 63 | 66 | 72 | Eats 73 | 74 | 75 | 76 | ); 77 | }; 78 | 79 | const toInputBoxStyles = StyleSheet.create({ 80 | container: { 81 | backgroundColor: "white", 82 | paddingTop: 20, 83 | flex: 0, 84 | }, 85 | textInput: { 86 | backgroundColor: "#DDDDDF", 87 | borderRadius: 0, 88 | fontSize: 18, 89 | }, 90 | textInputContainer: { 91 | paddingHorizontal: 20, 92 | paddingBottom: 0, 93 | }, 94 | }); 95 | 96 | type NavigateCardProp = NativeStackNavigationProp; 97 | 98 | export default NavigateCard; 99 | -------------------------------------------------------------------------------- /components/RideOptionsCard.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | FlatList, 3 | Image, 4 | Platform, 5 | Text, 6 | TouchableOpacity, 7 | View, 8 | } from "react-native"; 9 | import React, { useState } from "react"; 10 | 11 | import { Icon } from "react-native-elements"; 12 | import { SafeAreaView } from "react-native-safe-area-context"; 13 | import { selectTravelTimeInfo } from "../app/slices/navigationSlice"; 14 | import tailwind from "tailwind-react-native-classnames"; 15 | import { useNavigation } from "@react-navigation/native"; 16 | import { useSelector } from "react-redux"; 17 | 18 | const RideOptionsCard = () => { 19 | const navigation = useNavigation(); 20 | const [selected, setSelected] = useState(null); 21 | const travelTimeInformation = useSelector(selectTravelTimeInfo); 22 | 23 | return ( 24 | 25 | 26 | navigation.goBack()} 28 | style={tailwind`absolute top-1 left-0 px-5 rounded-full`} 29 | > 30 | 34 | 35 | 36 | Select a Ride - {travelTimeInformation?.distance.text} 37 | 38 | 39 | item.id} 42 | renderItem={({ item: { id, title, multiplier, image }, item }) => ( 43 | setSelected(item)} 45 | style={tailwind.style( 46 | `flex-row justify-between items-center px-6`, 47 | id === selected?.id && "bg-gray-200" 48 | )} 49 | > 50 | 60 | 61 | {title} 62 | {travelTimeInformation?.duration.text} 63 | 64 | 65 | {new Intl.NumberFormat("ee-gh", { 66 | currency: "GHS", 67 | style: "currency", 68 | }).format( 69 | ((travelTimeInformation?.duration.value || 0) * 70 | SURGE_CHARGE_RATE * 71 | multiplier) / 72 | 100 73 | )} 74 | 75 | 76 | )} 77 | /> 78 | 79 | 86 | 87 | Choose {selected?.title} 88 | 89 | 90 | 91 | 92 | ); 93 | }; 94 | 95 | type RidesData = { 96 | id: string; 97 | title: string; 98 | multiplier: number; 99 | image: string; 100 | }[]; 101 | 102 | const ridesData: RidesData = [ 103 | { 104 | id: "Uber-X-123", 105 | title: "UberX", 106 | multiplier: 1, 107 | image: "https://links.papareact.com/3pn", 108 | }, 109 | { 110 | id: "Uber-XL-456", 111 | title: "Uber XL", 112 | multiplier: 1.2, 113 | image: "https://links.papareact.com/5w8", 114 | }, 115 | { 116 | id: "Uber-LUX-789", 117 | title: "Uber LUX", 118 | multiplier: 1.75, 119 | image: "https://links.papareact.com/7pf", 120 | }, 121 | ]; 122 | 123 | const SURGE_CHARGE_RATE = 1.5; 124 | 125 | export default RideOptionsCard; 126 | -------------------------------------------------------------------------------- /env.d.ts: -------------------------------------------------------------------------------- 1 | declare module "@env" { 2 | export const GOOGLE_MAPS_API_KEY: string; 3 | } 4 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "main": "node_modules/expo/AppEntry.js", 3 | "scripts": { 4 | "start": "expo start", 5 | "android": "expo start --android", 6 | "ios": "expo start --ios", 7 | "web": "expo start --web", 8 | "eject": "expo eject" 9 | }, 10 | "dependencies": { 11 | "@react-navigation/native": "^6.0.4", 12 | "@react-navigation/native-stack": "^6.2.2", 13 | "@reduxjs/toolkit": "^1.6.1", 14 | "expo": "~42.0.1", 15 | "expo-status-bar": "~1.0.4", 16 | "intl": "^1.2.5", 17 | "react": "16.13.1", 18 | "react-dom": "16.13.1", 19 | "react-native": "0.63.4", 20 | "react-native-dotenv": "^3.2.0", 21 | "react-native-elements": "^3.4.2", 22 | "react-native-google-places-autocomplete": "^2.4.1", 23 | "react-native-maps": "0.28.0", 24 | "react-native-maps-directions": "^1.8.0", 25 | "react-native-safe-area-context": "3.2.0", 26 | "react-native-screens": "~3.4.0", 27 | "react-native-vector-icons": "^8.1.0", 28 | "react-native-web": "~0.13.12", 29 | "react-redux": "^7.2.5", 30 | "tailwind-react-native-classnames": "^1.5.1" 31 | }, 32 | "devDependencies": { 33 | "@babel/core": "~7.9.0", 34 | "@types/react": "~16.9.35", 35 | "@types/react-native": "~0.63.2", 36 | "typescript": "~4.0.0" 37 | }, 38 | "private": true 39 | } 40 | -------------------------------------------------------------------------------- /screens/EatsScreen.tsx: -------------------------------------------------------------------------------- 1 | import { Image, Text, View } from "react-native"; 2 | 3 | import React from "react"; 4 | import { SafeAreaView } from "react-native-safe-area-context"; 5 | import { navData } from "../components/NavOptions"; 6 | 7 | const EatsScreen = () => { 8 | return ( 9 | 12 | 13 | 17 | 18 | 19 | Not yet implemented... 20 | 21 | 22 | ); 23 | }; 24 | 25 | export default EatsScreen; 26 | -------------------------------------------------------------------------------- /screens/HomeScreen.tsx: -------------------------------------------------------------------------------- 1 | import { Image, View } from "react-native"; 2 | import { setDestination, setOrigin } from "../app/slices/navigationSlice"; 3 | 4 | import { GOOGLE_MAPS_API_KEY } from "@env"; 5 | import { GooglePlacesAutocomplete } from "react-native-google-places-autocomplete"; 6 | import NavFavorites from "../components/NavFavorites"; 7 | import NavOptions from "../components/NavOptions"; 8 | import React from "react"; 9 | import { SafeAreaView } from "react-native-safe-area-context"; 10 | import tailwind from "tailwind-react-native-classnames"; 11 | import { useDispatch } from "react-redux"; 12 | 13 | const HomeScreen = () => { 14 | const dispatch = useDispatch(); 15 | 16 | return ( 17 | 18 | 19 | 25 | { 33 | dispatch( 34 | setOrigin({ 35 | location: details?.geometry.location, 36 | description: data.description, 37 | }) 38 | ); 39 | dispatch(setDestination(null)); 40 | }} 41 | query={{ 42 | key: GOOGLE_MAPS_API_KEY, 43 | language: "en", 44 | }} 45 | styles={{ 46 | container: { 47 | flex: 0, 48 | }, 49 | }} 50 | /> 51 | 52 | 53 | 54 | 55 | ); 56 | }; 57 | 58 | export default HomeScreen; 59 | -------------------------------------------------------------------------------- /screens/MapScreen.tsx: -------------------------------------------------------------------------------- 1 | import { TouchableOpacity, View } from "react-native"; 2 | 3 | import { HomeScreenProp } from "../components/NavOptions"; 4 | import { Icon } from "react-native-elements"; 5 | import Map from "../components/Map"; 6 | import MapScreenNavigation from "../components/MapScreenNavigation"; 7 | import React from "react"; 8 | import tailwind from "tailwind-react-native-classnames"; 9 | import { useNavigation } from "@react-navigation/native"; 10 | 11 | const MapScreen = () => { 12 | const navigation = useNavigation(); 13 | 14 | return ( 15 | 16 | navigation.navigate("HomeScreen")} 18 | style={tailwind`bg-gray-50 absolute top-8 left-4 z-50 p-3 rounded-full shadow-lg`} 19 | > 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | ); 30 | }; 31 | 32 | export default MapScreen; 33 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "expo/tsconfig.base", 3 | "compilerOptions": { 4 | "strict": true 5 | } 6 | } 7 | --------------------------------------------------------------------------------