├── src ├── screens │ ├── home │ │ ├── style.js │ │ └── index.js │ ├── profile │ │ ├── style.js │ │ └── index.js │ ├── setting │ │ ├── style.js │ │ └── index.js │ ├── car │ │ ├── listYourCar │ │ │ ├── styles.js │ │ │ └── index.js │ │ ├── pastBookingScreen │ │ │ └── index.js │ │ ├── reserveCar │ │ │ ├── styles.js │ │ │ └── index.js │ │ ├── drivingScreen │ │ │ ├── styles.js │ │ │ └── index.js │ │ └── index.js │ └── index.js ├── utilities │ ├── Consants │ │ ├── Strings.js │ │ ├── Colors.js │ │ └── apiKey.js │ ├── Constants.js │ ├── AppStatusBar.js │ ├── ImagePicker.js │ ├── DatePicker.js │ ├── dummyData │ │ └── index.js │ └── AppUtils.js ├── actions │ ├── types.js │ ├── reservedCar.js │ ├── returnedCar.js │ └── rentCarList.js ├── reducers │ ├── index.js │ ├── reservedCar.js │ ├── returnedCar.js │ └── myCarList.js ├── customHooks │ └── useForm.js ├── Main.js ├── components │ ├── carListWrapper │ │ ├── styles.js │ │ └── index.js │ ├── pastBookingItem │ │ ├── index.js │ │ └── styles.js │ ├── carItem │ │ ├── styles.js │ │ └── index.js │ └── activeCar │ │ ├── styles.js │ │ └── index.js ├── store.js └── styles │ └── global.js ├── assets ├── car.png ├── end.png ├── icon.png ├── lock.png ├── time.png ├── favicon.png ├── splash.png ├── car_image.png ├── lock_open.png ├── reserved.png └── adaptive-icon.png ├── babel.config.js ├── .expo-shared └── assets.json ├── .gitignore ├── App.js ├── app.json ├── README.md └── package.json /src/screens/home/style.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/screens/profile/style.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/screens/setting/style.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/utilities/Consants/Strings.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/car.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hamzaahmed95/car_rental_app_react_native/HEAD/assets/car.png -------------------------------------------------------------------------------- /assets/end.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hamzaahmed95/car_rental_app_react_native/HEAD/assets/end.png -------------------------------------------------------------------------------- /assets/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hamzaahmed95/car_rental_app_react_native/HEAD/assets/icon.png -------------------------------------------------------------------------------- /assets/lock.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hamzaahmed95/car_rental_app_react_native/HEAD/assets/lock.png -------------------------------------------------------------------------------- /assets/time.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hamzaahmed95/car_rental_app_react_native/HEAD/assets/time.png -------------------------------------------------------------------------------- /src/utilities/Constants.js: -------------------------------------------------------------------------------- 1 | export const name = "hamza"; 2 | export const statusBarColor = "#56CCF2"; 3 | -------------------------------------------------------------------------------- /assets/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hamzaahmed95/car_rental_app_react_native/HEAD/assets/favicon.png -------------------------------------------------------------------------------- /assets/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hamzaahmed95/car_rental_app_react_native/HEAD/assets/splash.png -------------------------------------------------------------------------------- /assets/car_image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hamzaahmed95/car_rental_app_react_native/HEAD/assets/car_image.png -------------------------------------------------------------------------------- /assets/lock_open.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hamzaahmed95/car_rental_app_react_native/HEAD/assets/lock_open.png -------------------------------------------------------------------------------- /assets/reserved.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hamzaahmed95/car_rental_app_react_native/HEAD/assets/reserved.png -------------------------------------------------------------------------------- /assets/adaptive-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hamzaahmed95/car_rental_app_react_native/HEAD/assets/adaptive-icon.png -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = function(api) { 2 | api.cache(true); 3 | return { 4 | presets: ['babel-preset-expo'], 5 | }; 6 | }; 7 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /src/actions/types.js: -------------------------------------------------------------------------------- 1 | export const GET_ALL_CARS = "GET_ALL_CARS"; 2 | export const CREATE_A_CAR = "CREATE_A_CAR"; 3 | export const RESERVE_CAR = "RESERVE_CAR"; 4 | export const RETURN_CAR = "RETURN_CAR"; 5 | export const GET_MY_PAST_BOOKINGS = "GET_MY_PAST_BOOKINGS"; 6 | -------------------------------------------------------------------------------- /src/reducers/index.js: -------------------------------------------------------------------------------- 1 | import { combineReducers } from "redux"; 2 | import my_car from "./myCarList"; 3 | import reserve_car from "./reservedCar"; 4 | import returned_car from "./returnedCar"; 5 | 6 | export default combineReducers({ 7 | my_car, 8 | reserve_car, 9 | returned_car 10 | }); 11 | -------------------------------------------------------------------------------- /src/utilities/Consants/Colors.js: -------------------------------------------------------------------------------- 1 | export const appBackgrounColor = "#ffffff"; 2 | export const appColor = "#56CCF2"; 3 | export const btnFontColor = "#ffffff"; 4 | export const appFontColor = "#000000"; 5 | export const appDisableColor = "rgba(0, 0, 0, 0.6)"; 6 | export const appDecisionMakingBtnColor = "#2F80ED"; 7 | -------------------------------------------------------------------------------- /src/customHooks/useForm.js: -------------------------------------------------------------------------------- 1 | import { useState } from "react"; 2 | export const useForm = initialValues => { 3 | const [values, setValues] = useState(initialValues); 4 | 5 | return [ 6 | values, 7 | (name, value) => { 8 | setValues({ 9 | ...values, 10 | [name]: value 11 | }); 12 | } 13 | ]; 14 | }; 15 | -------------------------------------------------------------------------------- /src/reducers/reservedCar.js: -------------------------------------------------------------------------------- 1 | const initialState = { 2 | isDataLoaded: false 3 | }; 4 | 5 | export default function (state = initialState, action) { 6 | switch (action.type) { 7 | case "RESERVE_CAR": 8 | return { 9 | ...state, 10 | isDataLoaded: action.payload 11 | }; 12 | default: 13 | return state; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/reducers/returnedCar.js: -------------------------------------------------------------------------------- 1 | const initialState = { 2 | pastCar: [], 3 | status: false 4 | }; 5 | 6 | export default function (state = initialState, action) { 7 | switch (action.type) { 8 | case "PAST": 9 | return { 10 | ...state, 11 | pastCar: action.payload 12 | }; 13 | default: 14 | return state; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/Main.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { Text, View } from "react-native"; 3 | import Screens from "./screens"; 4 | import store from "./store"; 5 | import { Provider } from "react-redux"; 6 | 7 | const Main = () => { 8 | return ( 9 | 10 | 11 | 12 | ); 13 | }; 14 | 15 | export default Main; 16 | -------------------------------------------------------------------------------- /src/components/carListWrapper/styles.js: -------------------------------------------------------------------------------- 1 | import { StyleSheet, StatusBar } from "react-native"; 2 | 3 | export const styles = StyleSheet.create({ 4 | container: { 5 | flex: 1, 6 | marginTop: StatusBar.currentHeight || 0 7 | }, 8 | item: { 9 | padding: 20, 10 | marginVertical: 8, 11 | marginHorizontal: 16, 12 | color: "black" 13 | }, 14 | title: { 15 | fontSize: 32 16 | } 17 | }); 18 | -------------------------------------------------------------------------------- /src/store.js: -------------------------------------------------------------------------------- 1 | import { createStore, applyMiddleware } from "redux"; 2 | import { composeWithDevTools } from "redux-devtools-extension"; 3 | import thunk from "redux-thunk"; 4 | import rootReducer from "./reducers"; 5 | 6 | const initialState = {}; 7 | 8 | const middleware = [thunk]; 9 | 10 | const store = createStore( 11 | rootReducer, 12 | initialState, 13 | composeWithDevTools(applyMiddleware(...middleware)) 14 | ); 15 | 16 | export default store; 17 | -------------------------------------------------------------------------------- /src/utilities/Consants/apiKey.js: -------------------------------------------------------------------------------- 1 | export const firebaseConfig = { 2 | apiKey: "AIzaSyDEJMBlridzimKpNKvpYbM1iedg7RCnKdM", 3 | authDomain: "socar-3b084.firebaseapp.com", 4 | databaseURL: "https://socar-3b084-default-rtdb.firebaseio.com", 5 | projectId: "socar-3b084", 6 | storageBucket: "socar-3b084.appspot.com", 7 | messagingSenderId: "168562982707", 8 | appId: "1:168562982707:web:02680135d0325d3a228846", 9 | measurementId: "G-N3EWN5ZDH6" 10 | }; 11 | -------------------------------------------------------------------------------- /src/reducers/myCarList.js: -------------------------------------------------------------------------------- 1 | const initialState = { 2 | myCar: [], 3 | status: false 4 | }; 5 | 6 | export default function (state = initialState, action) { 7 | switch (action.type) { 8 | case "GET_ALL_CARS": 9 | return { 10 | ...state, 11 | myCar: action.payload 12 | }; 13 | case "CREATE_A_CAR": 14 | return { 15 | ...state, 16 | status: action.payload 17 | }; 18 | default: 19 | return state; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/screens/home/index.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { View } from "react-native"; 3 | import AppStatusBar from "../../utilities/AppStatusBar"; 4 | import { commonNavigation } from "../../utilities/AppUtils"; 5 | 6 | const Home = props => { 7 | return ( 8 | 9 | 10 | 11 | ); 12 | }; 13 | Home.navigationOptions = commonNavigation("Home"); 14 | 15 | export default Home; 16 | -------------------------------------------------------------------------------- /src/screens/profile/index.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { Text, View } from "react-native"; 3 | import AppStatusBar from "../../utilities/AppStatusBar"; 4 | import { commonNavigation } from "../../utilities/AppUtils"; 5 | 6 | const Profile = props => { 7 | return ( 8 | 9 | 10 | 11 | {Profile} 12 | 13 | ); 14 | }; 15 | Profile.navigationOptions = commonNavigation("Profile"); 16 | 17 | export default Profile; 18 | -------------------------------------------------------------------------------- /src/screens/setting/index.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { Text, View } from "react-native"; 3 | import AppStatusBar from "../../utilities/AppStatusBar"; 4 | import { commonNavigation } from "../../utilities/AppUtils"; 5 | 6 | const Setting = props => { 7 | return ( 8 | 9 | 10 | 11 | {Setting} 12 | 13 | ); 14 | }; 15 | Setting.navigationOptions = commonNavigation("Setting"); 16 | 17 | export default Setting; 18 | -------------------------------------------------------------------------------- /src/utilities/AppStatusBar.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { StyleSheet, StatusBar, View } from "react-native"; 3 | import { statusBarColor } from "../utilities/Constants"; 4 | 5 | const AppStatusBar = ({ backgroundColor, ...props }) => { 6 | return ( 7 | 8 | 9 | 10 | ); 11 | }; 12 | 13 | const BAR_HEIGHT = StatusBar.currentHeight; 14 | 15 | const styles = StyleSheet.create({ 16 | statusBar: { 17 | height: BAR_HEIGHT 18 | } 19 | }); 20 | 21 | export default AppStatusBar; 22 | -------------------------------------------------------------------------------- /App.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from "react"; 2 | import MainApp from "./src/Main"; 3 | import Toast from "react-native-toast-message"; 4 | 5 | import { firebaseConfig } from "./src/utilities/Consants/apiKey"; 6 | import firebase from "firebase/app"; 7 | 8 | export default class App extends Component { 9 | constructor(props) { 10 | super(props); 11 | if (!firebase.apps.length) { 12 | firebase.initializeApp(firebaseConfig); 13 | } else { 14 | firebase.app(); // if already initialized, use that one 15 | } 16 | } 17 | render() { 18 | return ( 19 | <> 20 | 21 | Toast.setRef(ref)} /> 22 | 23 | ); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/components/carListWrapper/index.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import CarItem from "../carItem/index"; 3 | import { SafeAreaView, FlatList, StatusBar } from "react-native"; 4 | 5 | //lit of rent a car 6 | const CarList = props => { 7 | return ( 8 | 14 | ( 17 | 23 | )} 24 | /> 25 | 26 | ); 27 | }; 28 | 29 | export default CarList; 30 | -------------------------------------------------------------------------------- /app.json: -------------------------------------------------------------------------------- 1 | { 2 | "expo": { 3 | "name": "socar", 4 | "slug": "socar", 5 | "version": "1.0.0", 6 | "platforms": ["ios", "android"], 7 | "orientation": "portrait", 8 | "icon": "./assets/icon.png", 9 | "splash": { 10 | "image": "./assets/splash.png", 11 | "resizeMode": "contain", 12 | "backgroundColor": "#ffffff" 13 | }, 14 | "updates": { 15 | "fallbackToCacheTimeout": 1500 16 | }, 17 | "assetBundlePatterns": ["**/*"], 18 | "ios": { 19 | "supportsTablet": true 20 | }, 21 | "android": { 22 | "adaptiveIcon": { 23 | "foregroundImage": "./assets/adaptive-icon.png", 24 | "backgroundColor": "#FFFFFF" 25 | } 26 | }, 27 | "web": { 28 | "favicon": "./assets/favicon.png" 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CAR RENTAL APP 2 | 3 | A cross platform car rental app built on react native 4 | 5 | Screenshot 2021-02-06 at 10 12 40 PM 6 | 7 | ## Features 8 | 9 | 1. Users can list their cars on rent 10 | 2. Users can book for cars per hours 11 | 3. Users can view previous bookings 12 | 13 | ## Development Environment /Tools/Languages 14 | 1. ReactNative v0.63 15 | 2. Material Ui v4.11.2 16 | 3. React hooks 17 | 4. Redux v^7.2.2 18 | 5. Firebase v^8.2.2 19 | 6. Moment v^2.29.1 20 | 7. ReactNavigationStack v^2.10.1 21 | 8. ReduxThunk v^2.3.0 22 | 23 | ## Getting Started 24 | ```bash 25 | git clone 26 | cd 27 | yarn install //install all the dependencies using yarn 28 | npm start //run your react native app 29 | ``` 30 | -------------------------------------------------------------------------------- /src/actions/reservedCar.js: -------------------------------------------------------------------------------- 1 | import firebase from "firebase"; 2 | import { RESERVE_CAR } from "./types"; 3 | 4 | import Toast from "react-native-toast-message"; 5 | 6 | export const reserve_car = (registeredCar, props) => dispatch => { 7 | let registeredCarRef = firebase.database().ref("registeredCar"); 8 | let newCarRegisteredRef = registeredCarRef.push(); 9 | newCarRegisteredRef 10 | .set(registeredCar) 11 | .then(() => { 12 | dispatch({ 13 | type: RESERVE_CAR, 14 | payload: true 15 | }); 16 | setTimeout(() => { 17 | props.navigation.goBack(); 18 | Toast.show({ 19 | text1: "Congrats", 20 | text2: "Car has been registered 👋" 21 | }); 22 | }, 2000); 23 | }) 24 | .catch(err => 25 | dispatch({ 26 | type: RESERVE_CAR, 27 | payload: false 28 | }) 29 | ); 30 | }; 31 | -------------------------------------------------------------------------------- /src/utilities/ImagePicker.js: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect } from "react"; 2 | import { 3 | Button, 4 | Image, 5 | View, 6 | TouchableOpacity, 7 | Platform, 8 | Text 9 | } from "react-native"; 10 | 11 | import { globalStyles } from "../styles/global"; 12 | import Constants from "expo-constants"; 13 | import { MaterialCommunityIcons } from "@expo/vector-icons"; 14 | 15 | const ImagePickerComp = props => { 16 | return ( 17 | 18 | {!props.image ? ( 19 | 20 | Upload car images 21 | 22 | 23 | ) : ( 24 | 25 | )} 26 | 27 | ); 28 | }; 29 | export default ImagePickerComp; 30 | -------------------------------------------------------------------------------- /src/screens/car/listYourCar/styles.js: -------------------------------------------------------------------------------- 1 | import { StyleSheet } from "react-native"; 2 | export const styles = StyleSheet.create({ 3 | container: { 4 | flex: 1, 5 | justifyContent: "flex-start" 6 | }, 7 | container1: { 8 | flex: 1, 9 | justifyContent: "space-between", 10 | flexDirection: "row" 11 | }, 12 | containerSub: { 13 | flexDirection: "row", 14 | alignItems: "baseline" 15 | }, 16 | input: { 17 | width: "50%", 18 | borderWidth: 1, 19 | borderColor: "#ddd", 20 | padding: 10, 21 | margin: 2, 22 | fontSize: 18, 23 | borderRadius: 6 24 | }, 25 | inputs: { 26 | flexBasis: "48%", 27 | marginBottom: 10, 28 | marginTop: 10, 29 | borderWidth: 1, 30 | paddingLeft: 10, 31 | borderColor: "#3B5998", 32 | fontSize: 18, 33 | borderRadius: 6 34 | }, 35 | animatedCircular: { 36 | flex: 1, 37 | justifyContent: "center", 38 | alignItems: "center" 39 | } 40 | }); 41 | -------------------------------------------------------------------------------- /src/utilities/DatePicker.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { StyleSheet, View, Text } from "react-native"; 3 | import moment from "moment"; 4 | import DateRangePicker from "react-native-daterange-picker"; 5 | 6 | export default class DatePicker extends React.Component { 7 | constructor(props) { 8 | super(props); 9 | this.state = { 10 | startDate: null, 11 | endDate: null, 12 | displayedDate: moment() 13 | }; 14 | } 15 | 16 | setDates = dates => { 17 | this.setState({ 18 | ...dates 19 | }); 20 | }; 21 | 22 | render() { 23 | const { startDate, endDate, displayedDate } = this.state; 24 | return ( 25 | 26 | 33 | Click me! 34 | 35 | 36 | ); 37 | } 38 | } 39 | 40 | const styles = StyleSheet.create({ 41 | container: { 42 | backgroundColor: "#fff" 43 | } 44 | }); 45 | -------------------------------------------------------------------------------- /src/screens/car/pastBookingScreen/index.js: -------------------------------------------------------------------------------- 1 | import React, { useEffect } from "react"; 2 | import { Text, View } from "react-native"; 3 | import { SafeAreaView, FlatList } from "react-native"; 4 | import PastBookingItem from "../../../components/pastBookingItem/index"; 5 | import { getMyPastBooking } from "../../../actions/returnedCar"; 6 | import { connect } from "react-redux"; 7 | 8 | const PastBookingScreen = props => { 9 | useEffect(() => { 10 | props.getMyPastBooking(); 11 | }, []); 12 | return ( 13 | 14 | 15 | ( 18 | 25 | )} 26 | /> 27 | 28 | 29 | ); 30 | }; 31 | 32 | const mapStateToProps = state => ({ 33 | past_car: state.returned_car.pastCar 34 | }); 35 | 36 | export default connect(mapStateToProps, { getMyPastBooking })( 37 | PastBookingScreen 38 | ); 39 | -------------------------------------------------------------------------------- /src/components/pastBookingItem/index.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { View, Text, Image, TouchableOpacity } from "react-native"; 3 | import { styles } from "./styles"; 4 | 5 | const PastBookingItem = props => { 6 | return ( 7 | 8 | 9 | 13 | 14 | {props.name} 15 | {props.color} 16 | Available 17 | 18 | 19 | 26 | 27 | MYR 20.00 / HR 28 | 29 | console.log("clicked!")}> 30 | Check Details 31 | 32 | 33 | 34 | ); 35 | }; 36 | 37 | export default PastBookingItem; 38 | -------------------------------------------------------------------------------- /src/actions/returnedCar.js: -------------------------------------------------------------------------------- 1 | import firebase from "firebase"; 2 | import { RETURN_CAR } from "./types"; 3 | 4 | import Toast from "react-native-toast-message"; 5 | 6 | export const returned_car = (pastBooking, props) => dispatch => { 7 | let pastBookingRef = firebase.database().ref("pastBooking"); 8 | let newPastBookingRef = pastBookingRef.push(); 9 | newPastBookingRef 10 | .set(pastBooking) 11 | .then(() => { 12 | dispatch({ 13 | type: RETURN_CAR, 14 | payload: true 15 | }); 16 | setTimeout(() => { 17 | props.navigation.goBack(); 18 | Toast.show({ 19 | text1: "Congrats", 20 | text2: "Car has been safely returned 👋" 21 | }); 22 | }, 2000); 23 | }) 24 | .catch(err => 25 | dispatch({ 26 | type: RETURN_CAR, 27 | payload: false 28 | }) 29 | ); 30 | }; 31 | 32 | export const getMyPastBooking = () => dispatch => { 33 | firebase 34 | .database() 35 | .ref("pastBooking") 36 | .orderByChild("name") 37 | .on("value", snapshot => { 38 | let dataList = []; 39 | snapshot.forEach(child => { 40 | dataList.push(child.val()); 41 | }); 42 | dispatch({ 43 | type: "PAST", 44 | payload: dataList 45 | }); 46 | }); 47 | }; 48 | -------------------------------------------------------------------------------- /src/screens/car/reserveCar/styles.js: -------------------------------------------------------------------------------- 1 | import { StyleSheet } from "react-native"; 2 | 3 | export const styles = StyleSheet.create({ 4 | container: { 5 | flex: 1, 6 | backgroundColor: "#fff", 7 | flexDirection: "column" 8 | }, 9 | subcontainer: { 10 | backgroundColor: "#56CCF2", 11 | alignItems: "center", 12 | width: "100%" 13 | }, 14 | tinyLogo: { 15 | width: 20.61, 16 | marginRight: 10, 17 | height: 20 18 | }, 19 | content: { 20 | fontSize: 14, 21 | marginTop: 30, 22 | color: "black", 23 | fontWeight: "bold", 24 | fontFamily: "Roboto" 25 | }, 26 | buttonContent: { 27 | fontFamily: "Roboto", 28 | fontSize: 16, 29 | color: "black" 30 | }, 31 | buttonContainer: { 32 | backgroundColor: "#ffffff", 33 | marginTop: 15, 34 | paddingLeft: 15, 35 | flexDirection: "row", 36 | marginBottom: 15, 37 | alignItems: "center", 38 | justifyContent: "flex-start", 39 | width: 328, 40 | height: 46 41 | }, 42 | buttonBottomContainer: { 43 | backgroundColor: "#56CCF2", 44 | marginTop: 10, 45 | alignItems: "center", 46 | justifyContent: "center", 47 | width: 143, 48 | height: 36 49 | }, 50 | bottomContainer: { 51 | paddingBottom: 50, 52 | position: "absolute", 53 | alignItems: "center", 54 | bottom: 0 55 | } 56 | }); 57 | -------------------------------------------------------------------------------- /src/components/carItem/styles.js: -------------------------------------------------------------------------------- 1 | import { StyleSheet } from "react-native"; 2 | 3 | export const styles = StyleSheet.create({ 4 | container: { 5 | flex: 1, 6 | backgroundColor: "#fff", 7 | marginTop: 15, 8 | marginBottom: 0, 9 | marginLeft: 15, 10 | marginRight: 15, 11 | padding: 15, 12 | borderWidth: 1, 13 | borderColor: "#ddd" 14 | }, 15 | carrateContainer: { 16 | flex: 1, 17 | flexDirection: "row", 18 | paddingTop: 10, 19 | paddingLeft: 10, 20 | paddingRight: 10, 21 | justifyContent: "space-between", 22 | color: "#828282", 23 | fontSize: 12 24 | }, 25 | carratefont: { 26 | color: "#828282", 27 | fontSize: 12 28 | }, 29 | carratefontB: { 30 | color: "#56CCF2", 31 | fontSize: 12 32 | }, 33 | 34 | subcontainers: { 35 | flex: 1, 36 | alignItems: "center", 37 | flexDirection: "row" 38 | }, 39 | carname: { 40 | fontSize: 16 41 | }, 42 | cardetail: { 43 | fontSize: 12 44 | }, 45 | subcontainer: { 46 | paddingLeft: 20, 47 | flexDirection: "column", 48 | alignItems: "flex-start" 49 | }, 50 | tinyLogo: { 51 | width: 78, 52 | height: 59 53 | }, 54 | input: { 55 | width: "50%", 56 | borderWidth: 1, 57 | borderColor: "#ddd", 58 | padding: 10, 59 | margin: 2, 60 | fontSize: 18, 61 | borderRadius: 6 62 | } 63 | }); 64 | -------------------------------------------------------------------------------- /src/components/pastBookingItem/styles.js: -------------------------------------------------------------------------------- 1 | import { StyleSheet } from "react-native"; 2 | 3 | export const styles = StyleSheet.create({ 4 | container: { 5 | flex: 1, 6 | backgroundColor: "#fff", 7 | marginTop: 15, 8 | marginBottom: 0, 9 | marginLeft: 15, 10 | marginRight: 15, 11 | padding: 15, 12 | borderWidth: 1, 13 | borderColor: "#ddd" 14 | }, 15 | carrateContainer: { 16 | flex: 1, 17 | flexDirection: "row", 18 | paddingTop: 10, 19 | paddingLeft: 10, 20 | paddingRight: 10, 21 | justifyContent: "space-between", 22 | color: "#828282", 23 | fontSize: 12 24 | }, 25 | carratefont: { 26 | color: "#828282", 27 | fontSize: 12 28 | }, 29 | carratefontB: { 30 | color: "#56CCF2", 31 | fontSize: 12 32 | }, 33 | 34 | subcontainers: { 35 | flex: 1, 36 | alignItems: "center", 37 | flexDirection: "row" 38 | }, 39 | carname: { 40 | fontSize: 16 41 | }, 42 | cardetail: { 43 | fontSize: 12 44 | }, 45 | subcontainer: { 46 | paddingLeft: 20, 47 | flexDirection: "column", 48 | alignItems: "flex-start" 49 | }, 50 | tinyLogo: { 51 | width: 78, 52 | height: 59 53 | }, 54 | input: { 55 | width: "50%", 56 | borderWidth: 1, 57 | borderColor: "#ddd", 58 | padding: 10, 59 | margin: 2, 60 | fontSize: 18, 61 | borderRadius: 6 62 | } 63 | }); 64 | -------------------------------------------------------------------------------- /src/screens/car/drivingScreen/styles.js: -------------------------------------------------------------------------------- 1 | import { StyleSheet } from "react-native"; 2 | import { 3 | appBackgrounColor, 4 | appColor, 5 | btnFontColor 6 | } from "../../../utilities/Consants/Colors"; 7 | 8 | export const styles = StyleSheet.create({ 9 | container: { 10 | flex: 1, 11 | flexDirection: "column", 12 | backgroundColor: appBackgrounColor 13 | }, 14 | containersub: { 15 | flex: 1, 16 | justifyContent: "flex-start", 17 | alignItems: "center", 18 | flexDirection: "column" 19 | }, 20 | tinyLogo: { 21 | width: 286, 22 | height: 211 23 | }, 24 | content: { 25 | fontSize: 14, 26 | marginTop: 30, 27 | color: "black", 28 | fontWeight: "bold", 29 | fontFamily: "Roboto" 30 | }, 31 | buttonContent: { 32 | fontFamily: "Roboto", 33 | fontSize: 14, 34 | color: btnFontColor 35 | }, 36 | buttonContainer: { 37 | backgroundColor: appColor, 38 | marginTop: 10, 39 | alignItems: "center", 40 | justifyContent: "center", 41 | width: 196, 42 | height: 36 43 | }, 44 | buttonBottomContainer: { 45 | backgroundColor: appColor, 46 | marginTop: 10, 47 | alignItems: "center", 48 | justifyContent: "center", 49 | width: 143, 50 | height: 36 51 | }, 52 | bottomContainer: { 53 | paddingBottom: 50, 54 | position: "absolute", 55 | alignItems: "center", 56 | bottom: 0 57 | } 58 | }); 59 | -------------------------------------------------------------------------------- /src/screens/car/index.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | import { createAppContainer } from "react-navigation"; 4 | import { createMaterialTopTabNavigator } from "react-navigation-tabs"; 5 | import { createStackNavigator } from "react-navigation-stack"; 6 | 7 | import DrivingScreen from "./drivingScreen/index"; 8 | import PastBookingScreen from "./pastBookingScreen/index"; 9 | 10 | const DrivingStack = createStackNavigator( 11 | { 12 | Driving: DrivingScreen 13 | }, 14 | { 15 | defaultNavigationOptions: { 16 | header: null 17 | } 18 | } 19 | ); 20 | 21 | const PastBookStack = createStackNavigator( 22 | { 23 | PastBook: PastBookingScreen 24 | }, 25 | { 26 | defaultNavigationOptions: { 27 | header: null 28 | } 29 | } 30 | ); 31 | 32 | const TabNavigator = createMaterialTopTabNavigator({ 33 | DriveScreen: { 34 | screen: DrivingStack, 35 | navigationOptions: { 36 | tabBarLabel: "DRIVING NOW", 37 | tabBarOptions: { 38 | style: { 39 | backgroundColor: "#56CCF2" //color you want to change 40 | } 41 | } 42 | } 43 | }, 44 | PastBookingScreen: { 45 | screen: PastBookStack, 46 | navigationOptions: { 47 | tabBarLabel: "PAST BOOKINGS", 48 | tabBarOptions: { 49 | style: { 50 | backgroundColor: "#56CCF2" //color you want to change 51 | } 52 | } 53 | } 54 | } 55 | }); 56 | 57 | export default createAppContainer(TabNavigator); 58 | -------------------------------------------------------------------------------- /src/styles/global.js: -------------------------------------------------------------------------------- 1 | import { StyleSheet } from "react-native"; 2 | 3 | export const globalStyles = StyleSheet.create({ 4 | container: { 5 | flex: 1, 6 | padding: 20, 7 | backgroundColor: "#fff" 8 | }, 9 | titleText: { 10 | fontFamily: "nunito-bold", 11 | fontSize: 18, 12 | color: "#333" 13 | }, 14 | paragraph: { 15 | marginVertical: 8, 16 | lineHeight: 20 17 | }, 18 | input: { 19 | borderWidth: 1, 20 | borderColor: "#003e59", 21 | padding: 13, 22 | marginTop: 10, 23 | marginBottom: 10, 24 | fontSize: 18, 25 | borderRadius: 6 26 | }, 27 | heading: { 28 | fontSize: 24, 29 | fontFamily: "sans-serif", 30 | fontWeight: "bold", 31 | color: "#003e59" 32 | }, 33 | appButtonContainer: { 34 | elevation: 8, 35 | backgroundColor: "#56CCF2", 36 | borderRadius: 10, 37 | paddingVertical: 10, 38 | paddingHorizontal: 12 39 | }, 40 | appButtonText: { 41 | fontSize: 18, 42 | color: "#fff", 43 | fontWeight: "bold", 44 | alignSelf: "center", 45 | textTransform: "uppercase" 46 | }, 47 | 48 | upload: { 49 | alignItems: "flex-start", 50 | justifyContent: "center", 51 | flexDirection: "row", 52 | padding: 10, 53 | marginBottom: 10, 54 | borderWidth: 1, 55 | borderColor: "#003e59" 56 | }, 57 | imageUpload: { 58 | alignItems: "flex-start", 59 | justifyContent: "center", 60 | width: 200, 61 | height: 200, 62 | borderWidth: 1, 63 | padding: 10, 64 | marginBottom: 10, 65 | borderColor: "#003e59" 66 | } 67 | }); 68 | -------------------------------------------------------------------------------- /src/utilities/dummyData/index.js: -------------------------------------------------------------------------------- 1 | export const carData = [ 2 | { 3 | id: "1", 4 | address: "Titiwangsa", 5 | color: "Black", 6 | fuel: "Diesel", 7 | image: 8 | "file:/data/user/0/host.exp.exponent/cache/ExperienceData/%2540bidcholhamzaahmed%252Fsocar/ImagePicker/c274c84d-e4f2-4b41-a547-203a54edb56e.jpg", 9 | name: "Civic", 10 | rate: 57, 11 | seating: "4", 12 | transmission: "Manual", 13 | type: "COUPE" 14 | }, 15 | { 16 | id: "2", 17 | address: "Titiwangsa", 18 | color: "White", 19 | fuel: "Diesel", 20 | image: 21 | "file:/data/user/0/host.exp.exponent/cache/ExperienceData/%2540bidcholhamzaahmed%252Fsocar/ImagePicker/c274c84d-e4f2-4b41-a547-203a54edb56e.jpg", 22 | name: "HRV", 23 | rate: 57, 24 | seating: "4", 25 | transmission: "Manual", 26 | type: "COUPE" 27 | }, 28 | { 29 | id: "3", 30 | address: "Titiwangsa", 31 | color: "Brown", 32 | fuel: "Diesel", 33 | image: 34 | "file:/data/user/0/host.exp.exponent/cache/ExperienceData/%2540bidcholhamzaahmed%252Fsocar/ImagePicker/c274c84d-e4f2-4b41-a547-203a54edb56e.jpg", 35 | name: "City", 36 | rate: 57, 37 | seating: "4", 38 | transmission: "Manual", 39 | type: "COUPE" 40 | }, 41 | { 42 | id: "4", 43 | address: "Titiwangsa", 44 | color: "Grey", 45 | fuel: "Diesel", 46 | image: 47 | "file:/data/user/0/host.exp.exponent/cache/ExperienceData/%2540bidcholhamzaahmed%252Fsocar/ImagePicker/c274c84d-e4f2-4b41-a547-203a54edb56e.jpg", 48 | name: "Myvi", 49 | rate: 57, 50 | seating: "4", 51 | transmission: "Manual", 52 | type: "COUPE" 53 | } 54 | ]; 55 | -------------------------------------------------------------------------------- /src/components/carItem/index.js: -------------------------------------------------------------------------------- 1 | import React, { useEffect, useState } from "react"; 2 | import { View, Text, Image, TouchableOpacity } from "react-native"; 3 | import { styles } from "./styles"; 4 | import { connect } from "react-redux"; 5 | import { reserve_car } from "../../actions/reservedCar"; 6 | 7 | const CarItem = props => { 8 | const handleSubmit = item => { 9 | const registeredCar = { 10 | car: item, 11 | isRegistered: true, 12 | registeredBy: "Hamza", 13 | isDriving: false 14 | }; 15 | props.reserve_car(registeredCar, props); 16 | }; 17 | console.log("=>" + props.flag); 18 | 19 | return ( 20 | 21 | 22 | 26 | 27 | {props.name} 28 | {props.color} 29 | Available 30 | 31 | 32 | 39 | 40 | MYR 20.00 / HR 41 | handleSubmit(props.name)}> 42 | BOOK NOW 43 | 44 | 45 | 46 | ); 47 | }; 48 | const mapStateToProps = state => ({ 49 | isDataLoaded: state.reserve_car.isDataLoaded 50 | }); 51 | 52 | export default connect(mapStateToProps, { reserve_car })(CarItem); 53 | -------------------------------------------------------------------------------- /src/screens/car/reserveCar/index.js: -------------------------------------------------------------------------------- 1 | import React, { useEffect, useState } from "react"; 2 | import { Text, View, Image, TouchableOpacity } from "react-native"; 3 | import { commonNavigation } from "../../../utilities/AppUtils"; 4 | import CarListWrapper from "../../../components/carListWrapper"; 5 | import { styles } from "./styles"; 6 | import { getAllCar } from "../../../actions/rentCarList"; 7 | import { connect } from "react-redux"; 8 | 9 | const ReserveCarScreen = props => { 10 | useEffect(() => { 11 | props.getAllCar(); 12 | }, []); 13 | return ( 14 | 15 | 16 | { 19 | props.navigation.navigate("Reservation"); 20 | }} 21 | > 22 | 26 | 00:30 AM - Wed, 28/09/2020 27 | 28 | { 31 | props.navigation.navigate("Reservation"); 32 | }} 33 | > 34 | 38 | 00:30 AM - Wed, 28/09/2020 39 | 40 | 41 | 46 | 47 | ); 48 | }; 49 | 50 | ReserveCarScreen.navigationOptions = commonNavigation("Make a Reservation"); 51 | 52 | const mapStateToProps = state => ({ 53 | mycar: state.my_car.myCar 54 | }); 55 | 56 | export default connect(mapStateToProps, { getAllCar })(ReserveCarScreen); 57 | -------------------------------------------------------------------------------- /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-native-community/masked-view": "0.1.10", 12 | "@react-native-community/slider": "^3.0.3", 13 | "@react-navigation/material-top-tabs": "^5.3.10", 14 | "date-fns": "^2.16.1", 15 | "expo": "~39.0.2", 16 | "expo-constants": "^9.2.0", 17 | "expo-image-picker": "~9.2.0", 18 | "expo-secure-store": "^9.2.0", 19 | "expo-status-bar": "~1.0.2", 20 | "firebase": "^8.2.2", 21 | "moment": "^2.29.1", 22 | "react": "16.13.1", 23 | "react-dom": "16.13.1", 24 | "react-native": "https://github.com/expo/react-native/archive/sdk-39.0.4.tar.gz", 25 | "react-native-circular-progress": "^1.3.6", 26 | "react-native-daterange-picker": "^1.5.1", 27 | "react-native-gesture-handler": "~1.7.0", 28 | "react-native-markdown-renderer": "^3.2.8", 29 | "react-native-material-dropdown": "git+https://github.com/noway/react-native-material-dropdown.git", 30 | "react-native-reanimated": "~1.13.0", 31 | "react-native-safe-area-context": "3.1.4", 32 | "react-native-screens": "~2.10.1", 33 | "react-native-slider-picker": "^1.1.3", 34 | "react-native-svg": "^12.1.0", 35 | "react-native-tab-view": "2.14.2", 36 | "react-native-toast-message": "^1.4.2", 37 | "react-native-web": "~0.13.12", 38 | "react-navigation": "^4.4.3", 39 | "react-navigation-stack": "^2.10.1", 40 | "react-navigation-tabs": "^2.10.1", 41 | "react-redux": "^7.2.2", 42 | "redux": "^4.0.5", 43 | "redux-devtools-extension": "^2.13.8", 44 | "redux-thunk": "^2.3.0" 45 | }, 46 | "devDependencies": { 47 | "@babel/core": "~7.9.0", 48 | "babel-preset-expo": "^8.3.0", 49 | "eslint": "^7.13.0", 50 | "eslint-config-prettier": "^6.15.0", 51 | "eslint-plugin-react-native": "^3.10.0", 52 | "prettier": "^2.1.2" 53 | }, 54 | "private": true 55 | } 56 | -------------------------------------------------------------------------------- /src/components/activeCar/styles.js: -------------------------------------------------------------------------------- 1 | import { StyleSheet } from "react-native"; 2 | import { appDisableColor } from "../../utilities/Consants/Colors"; 3 | export const styles = StyleSheet.create({ 4 | container: { 5 | backgroundColor: "#fff", 6 | marginTop: 15, 7 | marginBottom: 0, 8 | marginLeft: 15, 9 | marginRight: 15, 10 | padding: 15, 11 | borderWidth: 1, 12 | borderColor: "#ddd" 13 | }, 14 | subContainer: { 15 | alignItems: "center" 16 | }, 17 | statusContent: { 18 | alignItems: "center", 19 | paddingTop: 30 20 | }, 21 | tinyLogo: { 22 | width: 254, 23 | height: 163 24 | }, 25 | lock: { 26 | width: 16, 27 | margin: 10, 28 | height: 21 29 | }, 30 | subContent: { 31 | flexDirection: "row", 32 | justifyContent: "space-around" 33 | }, 34 | lockItem: { 35 | padding: 5, 36 | borderWidth: 1, 37 | borderColor: "#ddd" 38 | }, 39 | lockContent: { 40 | flexDirection: "row" 41 | }, 42 | timeEndingContent: { 43 | flexDirection: "row", 44 | paddingTop: 10 45 | }, 46 | timeEndingText: { 47 | color: appDisableColor, 48 | paddingTop: 3, 49 | paddingRight: 3, 50 | fontSize: 16 51 | }, 52 | buttonActiveContainer: { 53 | flexDirection: "row", 54 | justifyContent: "flex-end" 55 | }, 56 | buttonActiveContent: { 57 | fontFamily: "Roboto", 58 | fontSize: 14, 59 | paddingLeft: 15, 60 | paddingRight: 15, 61 | color: "#2F80ED" 62 | }, 63 | timeEndingDayText: { 64 | color: appDisableColor, 65 | fontWeight: "bold", 66 | fontSize: 20 67 | }, 68 | animatedCircular: { 69 | paddingTop: 30, 70 | justifyContent: "center", 71 | alignItems: "center" 72 | }, 73 | lockItemContent: { 74 | justifyContent: "center", 75 | paddingLeft: 10 76 | }, 77 | lockItemText: { 78 | fontSize: 14, 79 | fontWeight: "500", 80 | color: "#000" 81 | }, 82 | buttonContainer: { 83 | margin: 10, 84 | justifyContent: "center", 85 | alignItems: "center" 86 | }, 87 | buttonContent: { 88 | fontFamily: "Roboto", 89 | fontSize: 14, 90 | alignItems: "center", 91 | color: "#2F80ED" 92 | } 93 | }); 94 | -------------------------------------------------------------------------------- /src/actions/rentCarList.js: -------------------------------------------------------------------------------- 1 | import firebase from "firebase"; 2 | import { GET_ALL_CARS } from "./types"; 3 | import Toast from "react-native-toast-message"; 4 | 5 | export const getAllCar = () => dispatch => { 6 | let dataList = []; 7 | firebase 8 | .database() 9 | .ref("rentCarsList") 10 | .orderByChild("name") 11 | .once("value") 12 | .then(snapshot => { 13 | snapshot.forEach(child => { 14 | dataList.push(child.val()); 15 | }); 16 | dispatch({ 17 | type: GET_ALL_CARS, 18 | payload: dataList 19 | }); 20 | }) 21 | .catch(error => { 22 | dispatch({ 23 | type: GET_ALL_CARS, 24 | payload: [] 25 | }); 26 | }); 27 | }; 28 | 29 | //CREATE 30 | export const createCarList = (item, props) => async dispatch => { 31 | let carListRef = firebase.database().ref("rentCarsList"); 32 | let newCarRef = carListRef.push(); 33 | await newCarRef 34 | .set(item) 35 | .then(uploadImageAsync(item.image, item.name)) 36 | .then(resp => { 37 | setTimeout(() => { 38 | props.navigation.goBack(); 39 | Toast.show({ 40 | text1: "Congrats", 41 | text2: "Car added succesfully 👋" 42 | }); 43 | }, 2000); 44 | dispatch({ 45 | type: CREATE_A_CAR, 46 | payload: true 47 | }); 48 | }) 49 | .catch(err => { 50 | dispatch({ 51 | type: CREATE_A_CAR, 52 | payload: false 53 | }); 54 | }); 55 | }; 56 | 57 | async function uploadImageAsync(uri, name) { 58 | const blob = await new Promise((resolve, reject) => { 59 | const xhr = new XMLHttpRequest(); 60 | xhr.onload = function () { 61 | resolve(xhr.response); 62 | }; 63 | xhr.onerror = function (e) { 64 | reject(new TypeError("Network request failed")); 65 | }; 66 | xhr.responseType = "blob"; 67 | xhr.open("GET", uri, true); 68 | xhr.send(null); 69 | }); 70 | 71 | const ref = firebase 72 | .storage() 73 | .ref() 74 | .child("uploads/" + name); 75 | const snapshot = await ref.put(blob); 76 | 77 | // We're done with the blob, close and release it 78 | blob.close(); 79 | 80 | return await snapshot.ref.getDownloadURL(); 81 | } 82 | -------------------------------------------------------------------------------- /src/utilities/AppUtils.js: -------------------------------------------------------------------------------- 1 | import { Alert } from "react-native"; 2 | import * as ImagePicker from "expo-image-picker"; 3 | 4 | export const fuelData = [ 5 | { 6 | value: "E85" 7 | }, 8 | { 9 | value: "Gasoline" 10 | }, 11 | { 12 | value: "Diesel" 13 | } 14 | ]; 15 | 16 | export const typeData = [ 17 | { 18 | value: "SEDAN" 19 | }, 20 | { 21 | value: "COUPE" 22 | }, 23 | { 24 | value: "SPORTS CAR" 25 | }, 26 | { 27 | value: "STATION WAGON" 28 | } 29 | ]; 30 | 31 | export const transmissionData = [ 32 | { 33 | value: "Manual" 34 | }, 35 | { 36 | value: "Automatic" 37 | }, 38 | { 39 | value: "Continuously variable transmission" 40 | } 41 | ]; 42 | 43 | export const seatingData = [ 44 | { 45 | value: "1" 46 | }, 47 | { 48 | value: "2" 49 | }, 50 | { 51 | value: "3" 52 | }, 53 | { 54 | value: "4" 55 | }, 56 | { 57 | value: "5" 58 | }, 59 | { 60 | value: "6" 61 | } 62 | ]; 63 | 64 | export const commonNavigation = name => { 65 | return { 66 | title: name, 67 | headerStyle: { 68 | backgroundColor: "#56CCF2", 69 | elevation: 0, 70 | shadowOpacity: 0 71 | }, 72 | headerTintColor: "#ffffff", 73 | headerTitleStyle: { 74 | fontWeight: "bold", 75 | color: "#ffffff" 76 | } 77 | }; 78 | }; 79 | 80 | export const isEmpty = values => { 81 | let isEmptys = false; 82 | Object.entries(values).map(([key, value]) => { 83 | if (key === "image" && value === null) { 84 | isEmptys = true; 85 | } else { 86 | if (value.length === 0) { 87 | isEmptys = true; 88 | } 89 | } 90 | }); 91 | 92 | return isEmptys; 93 | }; 94 | 95 | export const showAlert = name => 96 | Alert.alert( 97 | "Error", 98 | name, 99 | [{ text: "OK", onPress: () => console.log("OK Pressed") }], 100 | { cancelable: false } 101 | ); 102 | 103 | export const pickImages = async () => { 104 | let result = await ImagePicker.launchImageLibraryAsync({ 105 | mediaTypes: ImagePicker.MediaTypeOptions.All, 106 | multiple: true, 107 | allowsEditing: true, 108 | aspect: [4, 3], 109 | quality: 1 110 | }); 111 | 112 | if (!result.cancelled) { 113 | return result.uri; 114 | } else { 115 | return null; 116 | } 117 | }; 118 | 119 | export const checkImageStatus = async () => { 120 | if (Platform.OS !== "web") { 121 | const { status } = await ImagePicker.requestMediaLibraryPermissionsAsync(); 122 | if (status !== "granted") { 123 | alert("Sorry, we need camera roll permissions to make this work!"); 124 | } 125 | } 126 | }; 127 | -------------------------------------------------------------------------------- /src/screens/car/drivingScreen/index.js: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect } from "react"; 2 | import { Text, View, Image, TouchableOpacity } from "react-native"; 3 | import { commonNavigation } from "../../../utilities/AppUtils"; 4 | import ActiveCar from "../../../components/activeCar/index"; 5 | import { styles } from "./styles"; 6 | import firebase from "firebase"; 7 | 8 | const DriveNowScreen = props => { 9 | const [isDriving, setDriving] = useState(false); 10 | const [carDetails, setCarDetails] = useState(false); 11 | useEffect(() => { 12 | getData(); 13 | }, []); 14 | 15 | const getData = () => { 16 | firebase 17 | .database() 18 | .ref("registeredCar") 19 | .orderByChild("registeredBy") 20 | .equalTo("Hamza") 21 | .on("value", snapshot => { 22 | let isCarRegistered = false; 23 | let car = ""; 24 | snapshot.forEach(function (data) { 25 | car = data.child("car").val(); 26 | if (car) { 27 | getCarDetails(car); 28 | } 29 | if (data.child("isRegistered").val()) { 30 | isCarRegistered = true; 31 | } 32 | }); 33 | setDriving(isCarRegistered); 34 | }); 35 | }; 36 | getCarDetails = car => { 37 | firebase 38 | .database() 39 | .ref("rentCarsList") 40 | .orderByChild("name") 41 | .equalTo(car) 42 | .on("value", snapshot => { 43 | snapshot.forEach(function (data) { 44 | setCarDetails(data.val()); 45 | }); 46 | }); 47 | }; 48 | return ( 49 | 50 | {isDriving ? ( 51 | 52 | ) : ( 53 | 54 | 58 | Not driving a car yet 59 | { 62 | props.navigation.navigate("ReserveCar"); 63 | }} 64 | > 65 | MAKE A RESERVATION 66 | 67 | 68 | Want to earn using your car? 69 | { 72 | props.navigation.navigate("ListYourCar"); 73 | }} 74 | > 75 | LIST YOUR CAR 76 | 77 | 78 | 79 | )} 80 | 81 | ); 82 | }; 83 | 84 | DriveNowScreen.navigationOptions = commonNavigation("Drive Now"); 85 | export default DriveNowScreen; 86 | -------------------------------------------------------------------------------- /src/screens/index.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { createAppContainer } from "react-navigation"; 3 | import { createBottomTabNavigator } from "react-navigation-tabs"; 4 | import { createStackNavigator } from "react-navigation-stack"; 5 | import { MaterialCommunityIcons } from "@expo/vector-icons"; 6 | 7 | // import screen components 8 | import HomeScreen from "./home"; 9 | import ListYourCarScreen from "./car/listYourCar/index"; 10 | import ProfileScreen from "./profile"; 11 | import SettingScreen from "./setting"; 12 | import ReserveCarScreen from "./car/reserveCar/index"; 13 | import CarScreen from "./car"; 14 | 15 | const HomeStack = createStackNavigator({ 16 | Home: HomeScreen 17 | }); 18 | 19 | const CarStack = createStackNavigator( 20 | { 21 | Car: CarScreen, 22 | ListYourCar: ListYourCarScreen, 23 | ReserveCar: ReserveCarScreen 24 | }, 25 | { 26 | defaultNavigationOptions: { 27 | headerStyle: { 28 | backgroundColor: "#56CCF2" 29 | }, 30 | headerTintColor: "#fff", 31 | headerTitleStyle: { 32 | fontWeight: "bold" 33 | } 34 | } 35 | } 36 | ); 37 | 38 | const ProfileStack = createStackNavigator({ 39 | Profile: ProfileScreen 40 | }); 41 | 42 | const SettingStack = createStackNavigator({ 43 | Setting: SettingScreen 44 | }); 45 | 46 | const TabNavigator = createBottomTabNavigator({ 47 | HomeScreen: { 48 | screen: HomeStack, 49 | navigationOptions: { 50 | tabBarLabel: "Home", 51 | tabBarOptions: { 52 | activeTintColor: "#56CCF2", 53 | inactiveTintColor: "rgba(0, 0, 0, 0.38)" 54 | }, 55 | tabBarIcon: ({ tintColor }) => ( 56 | 57 | ) 58 | } 59 | }, 60 | CarScreen: { 61 | screen: CarStack, 62 | navigationOptions: { 63 | tabBarLabel: "Car", 64 | tabBarOptions: { 65 | activeTintColor: "#56CCF2", 66 | inactiveTintColor: "rgba(0, 0, 0, 0.38)" 67 | }, 68 | tabBarIcon: ({ tintColor }) => ( 69 | 70 | ) 71 | } 72 | }, 73 | ProfileScreen: { 74 | screen: ProfileStack, 75 | navigationOptions: { 76 | tabBarLabel: "profile", 77 | tabBarOptions: { 78 | activeTintColor: "#56CCF2", 79 | inactiveTintColor: "rgba(0, 0, 0, 0.38)" 80 | }, 81 | tabBarIcon: ({ tintColor }) => ( 82 | 83 | ) 84 | } 85 | }, 86 | SettingScreen: { 87 | screen: SettingStack, 88 | navigationOptions: { 89 | tabBarLabel: "Setting", 90 | tabBarOptions: { 91 | activeTintColor: "#56CCF2", 92 | inactiveTintColor: "rgba(0, 0, 0, 0.38)" 93 | }, 94 | tabBarIcon: ({ tintColor }) => ( 95 | 96 | ) 97 | } 98 | } 99 | }); 100 | 101 | export default createAppContainer(TabNavigator); 102 | -------------------------------------------------------------------------------- /src/screens/car/listYourCar/index.js: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect } from "react"; 2 | import { Dropdown } from "react-native-material-dropdown"; 3 | import { SliderPicker } from "react-native-slider-picker"; 4 | import { globalStyles } from "../../../styles/global"; 5 | import { styles } from "./styles"; 6 | import ImagePickerComp from "../../../utilities/ImagePicker"; 7 | import { useForm } from "../../../customHooks/useForm"; 8 | import { AnimatedCircularProgress } from "react-native-circular-progress"; 9 | import { createCarList } from "../../../actions/rentCarList"; 10 | import { connect } from "react-redux"; 11 | import { 12 | fuelData, 13 | typeData, 14 | seatingData, 15 | transmissionData, 16 | commonNavigation, 17 | showAlert, 18 | pickImages, 19 | isEmpty, 20 | checkImageStatus 21 | } from "../../../utilities/AppUtils"; 22 | import { 23 | TextInput, 24 | View, 25 | Text, 26 | YellowBox, 27 | LogBox, 28 | TouchableOpacity, 29 | ScrollView 30 | } from "react-native"; 31 | 32 | LogBox.ignoreLogs(["Warning: ..."]); 33 | LogBox.ignoreAllLogs(); 34 | 35 | const ListYourCarScreen = props => { 36 | const [values, handleChange] = useForm({ 37 | name: "", 38 | color: "", 39 | type: "", 40 | fuel: "", 41 | seating: "", 42 | address: "", 43 | transmission: "" 44 | }); 45 | const [image, setImage] = useState(null); 46 | const [rate, setRate] = useState(25); 47 | const [Loading, isLoading] = useState(false); 48 | 49 | const handleSubmit = e => { 50 | const object = { 51 | ...values, 52 | rate, 53 | image 54 | }; 55 | if (isEmpty(object)) { 56 | showAlert("Kindly fill all the fields"); 57 | } else { 58 | isLoading(true); 59 | props.createCarList(object, props); 60 | } 61 | }; 62 | 63 | useEffect(() => { 64 | YellowBox.ignoreWarnings(["Animated: `useNativeDriver`"]); 65 | checkImageStatus(); 66 | }, []); 67 | 68 | return ( 69 | 70 | {Loading ? ( 71 | 80 | ) : ( 81 | 82 | 83 | Car Information 84 | handleChange("name", txt)} 88 | value={values.name} 89 | /> 90 | handleChange("color", txt)} 94 | value={values.color} 95 | /> 96 | 97 | 98 | handleChange("type", txt)} 105 | /> 106 | 107 | 108 | handleChange("fuel", txt)} 115 | /> 116 | 117 | 118 | 119 | 120 | handleChange("transmission", txt)} 126 | /> 127 | 128 | 129 | handleChange("seating", txt)} 136 | /> 137 | 138 | 139 | Rate 140 | { 142 | setRate(position); 143 | }} 144 | defaultValue={values.rate} 145 | maxValue={100} 146 | labelFontColor={"#6c7682"} 147 | labelFontWeight={"600"} 148 | fillColor={"#3B5998"} 149 | labelFontWeight={"bold"} 150 | heightPercentage={1} 151 | widthPercentage={80} 152 | /> 153 | {values.rate} 154 | Address line 155 | handleChange("address", txt)} 159 | value={values.address} 160 | /> 161 | setImage(await pickImages())} 164 | /> 165 | 169 | Submit 170 | 171 | 172 | 173 | )} 174 | 175 | ); 176 | }; 177 | 178 | ListYourCarScreen.navigationOptions = commonNavigation("List your car"); 179 | 180 | const mapStateToProps = state => ({ 181 | status: state.my_car.status 182 | }); 183 | 184 | export default connect(mapStateToProps, { createCarList })(ListYourCarScreen); 185 | -------------------------------------------------------------------------------- /src/components/activeCar/index.js: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect } from "react"; 2 | import { Text, TouchableOpacity, View, Image } from "react-native"; 3 | import { styles } from "./styles"; 4 | import firebase from "firebase"; 5 | import { connect } from "react-redux"; 6 | import { returned_car } from "../../actions/returnedCar"; 7 | import { AnimatedCircularProgress } from "react-native-circular-progress"; 8 | const ActiveCarScreen = props => { 9 | const [active, isCarActive] = useState(false); 10 | const [loading, isLoading] = useState(false); 11 | 12 | useEffect(() => { 13 | getData(); 14 | }, []); 15 | 16 | const isCarStarted = () => { 17 | firebase 18 | .database() 19 | .ref("registeredCar") 20 | .orderByChild("registeredBy") 21 | .equalTo("Hamza") 22 | .once("value", snapshot => { 23 | snapshot.forEach(function (data) { 24 | data.ref.child("isDriving").set(true); 25 | }); 26 | }); 27 | }; 28 | const getData = () => { 29 | firebase 30 | .database() 31 | .ref("registeredCar") 32 | .orderByChild("registeredBy") 33 | .equalTo("Hamza") 34 | .on("value", snapshot => { 35 | let isCarStarted = false; 36 | snapshot.forEach(function (data) { 37 | if (data.child("isDriving").val()) { 38 | isCarStarted = true; 39 | } 40 | }); 41 | isCarActive(isCarStarted); 42 | }); 43 | }; 44 | 45 | const setPastBooking = () => { 46 | props.returned_car(props.carDetails, props.navigate); 47 | returnedCar(); 48 | }; 49 | 50 | const returnedCar = () => { 51 | firebase 52 | .database() 53 | .ref("registeredCar") 54 | .orderByChild("registeredBy") 55 | .equalTo("Hamza") 56 | .once("value", snapshot => { 57 | snapshot.forEach(function (data) { 58 | data.ref.child("isRegistered").set(false); 59 | }); 60 | }); 61 | }; 62 | 63 | return ( 64 | 65 | 66 | {props.carDetails.name} 67 | 68 | 69 | {props.carDetails.color} 70 | 71 | 72 | 76 | 77 | 78 | 79 | 80 | Car Type 81 | 82 | {props.carDetails.type} 83 | 84 | 85 | 86 | Seater 87 | 88 | {props.carDetails.seating} 89 | 90 | 91 | 92 | Transmission 93 | 94 | {props.carDetails.transmission} 95 | 96 | 97 | {loading && ( 98 | { 106 | // isCarActive(!isCarActive); 107 | isCarActive(true); 108 | isLoading(false); 109 | }} 110 | backgroundColor="#3d5875" 111 | /> 112 | )} 113 | {!active ? ( 114 | 115 | 116 | 117 | Booking starts at 118 | 119 | 126 | Wed 09/09/2020 127 | 128 | 129 | 137 | { 140 | // props.navigation.navigate("Reservation"); 141 | isCarStarted(); 142 | isLoading(true); 143 | }} 144 | > 145 | START DRIVING 146 | 147 | 148 | ) : ( 149 | 150 | 151 | 152 | 153 | 157 | 158 | 159 | 163 | 164 | 165 | LOCK CAR 166 | 167 | 168 | 169 | Time ending in 170 | 1 Day 171 | 172 | 173 | 181 | { 184 | // props.navigation.navigate("Reservation"); 185 | //isLoading(true); 186 | setPastBooking(); 187 | }} 188 | > 189 | EXTEND 190 | RETURN 191 | 192 | 193 | )} 194 | 195 | ); 196 | }; 197 | const mapStateToProps = state => ({ 198 | isDataLoaded: state.reserve_car.isDataLoaded 199 | }); 200 | 201 | export default connect(mapStateToProps, { returned_car })(ActiveCarScreen); 202 | --------------------------------------------------------------------------------