Compare commits
No commits in common. "84d6bf8dcd738d3020a04427e160057b7c25e552" and "6d485b374fe6975c2a61d7e7e5bab355c7a246e0" have entirely different histories.
84d6bf8dcd
...
6d485b374f
|
@ -1,9 +1,50 @@
|
||||||
# Donut Shop Application with React Native
|
# Welcome to your Expo app 👋
|
||||||
|
|
||||||
This project is a donut shop mobile application, where users can search for the list of donuts of your choice, and add to you favorite list. Users can also place the order and get a receipt through this mobile application.
|
This is an [Expo](https://expo.dev) project created with [`create-expo-app`](https://www.npmjs.com/package/create-expo-app).
|
||||||
|
|
||||||
## To start the project
|
## Get started
|
||||||
* Download [Expo Go](https://expo.dev/go) on your device to launch the project.
|
|
||||||
* To start the project, run this command in your terminal `npx expo start --tunnel`
|
1. Install dependencies
|
||||||
* Scan the QR code that shows in your terminal.
|
|
||||||
* For more information about Tunneling, please read [Expo](https://docs.expo.dev/more/expo-cli/#tunneling).
|
```bash
|
||||||
|
npm install
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Start the app
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npx expo start
|
||||||
|
```
|
||||||
|
|
||||||
|
In the output, you'll find options to open the app in a
|
||||||
|
|
||||||
|
- [development build](https://docs.expo.dev/develop/development-builds/introduction/)
|
||||||
|
- [Android emulator](https://docs.expo.dev/workflow/android-studio-emulator/)
|
||||||
|
- [iOS simulator](https://docs.expo.dev/workflow/ios-simulator/)
|
||||||
|
- [Expo Go](https://expo.dev/go), a limited sandbox for trying out app development with Expo
|
||||||
|
|
||||||
|
You can start developing by editing the files inside the **app** directory. This project uses [file-based routing](https://docs.expo.dev/router/introduction).
|
||||||
|
|
||||||
|
## Get a fresh project
|
||||||
|
|
||||||
|
When you're ready, run:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm run reset-project
|
||||||
|
```
|
||||||
|
|
||||||
|
This command will move the starter code to the **app-example** directory and create a blank **app** directory where you can start developing.
|
||||||
|
|
||||||
|
## Learn more
|
||||||
|
|
||||||
|
To learn more about developing your project with Expo, look at the following resources:
|
||||||
|
|
||||||
|
- [Expo documentation](https://docs.expo.dev/): Learn fundamentals, or go into advanced topics with our [guides](https://docs.expo.dev/guides).
|
||||||
|
- [Learn Expo tutorial](https://docs.expo.dev/tutorial/introduction/): Follow a step-by-step tutorial where you'll create a project that runs on Android, iOS, and the web.
|
||||||
|
|
||||||
|
## Join the community
|
||||||
|
|
||||||
|
Join our community of developers creating universal apps.
|
||||||
|
|
||||||
|
- [Expo on GitHub](https://github.com/expo/expo): View our open source platform and contribute.
|
||||||
|
- [Discord community](https://chat.expo.dev): Chat with Expo users and ask questions.
|
||||||
|
|
|
@ -1,59 +0,0 @@
|
||||||
import { StyleSheet, Text, View, Pressable, Image} from 'react-native'
|
|
||||||
import React from 'react'
|
|
||||||
import { useNavigation } from '@react-navigation/native';
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const HomeCardItem = () => {
|
|
||||||
const navigation = useNavigation();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<View style={{padding: 5}}>
|
|
||||||
<View style={{shadowColor: '#B4B4B8', shadowOffset: { width: 0, height: 1 }, shadowOpacity: 0.5, shadowRadius: 1,}}>
|
|
||||||
<Pressable>
|
|
||||||
<View style={{borderColor: '#EEEEEE', borderWidth: 1, borderRadius: 5}}>
|
|
||||||
<Image source={require('../../assets/images/menu/coming_soon.png')} style={{width: '100%', height: 200, borderTopLeftRadius: 5, borderTopRightRadius: 5}}/>
|
|
||||||
<View style={{padding: 10}}>
|
|
||||||
<Text style={{fontSize: 16, fontWeight: 600, letterSpacing: 0.5, marginBottom: 10}}>Pokémon Donuts<Text style={{fontSize: 12, color: '#DA7297'}}>(Coming soon)</Text></Text>
|
|
||||||
<Text>The limited-edition Pokémon Donuts is coming soon!</Text>
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
</Pressable>
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<View style={{marginTop: 10, shadowColor: '#B4B4B8', shadowOffset: { width: 0, height: 1 }, shadowOpacity: 0.5, shadowRadius: 1,}}>
|
|
||||||
<Pressable onPress={() => navigation.navigate('menu')}>
|
|
||||||
<View style={{borderColor: '#EEEEEE', borderWidth: 1, borderRadius: 5}}>
|
|
||||||
<Image source={require('../../assets/images/menu/new_special.jpg')} style={{width: '100%', height: 200, borderTopLeftRadius: 5, borderTopRightRadius: 5}}/>
|
|
||||||
<View style={{padding: 10}}>
|
|
||||||
<Text style={{fontSize: 16, fontWeight: 600, letterSpacing: 0.5, marginBottom: 10}}>Mothers Day Box for your mama</Text>
|
|
||||||
<Text>Lets show our appreciation for our moms by treating them with the special Mothers Day Box!</Text>
|
|
||||||
<Pressable onPress={() => navigation.navigate('menu')} style={{marginTop: 10, padding: 10, backgroundColor: '#DA7297', width: 100, borderRadius: 5, alignItems: 'center'}}>
|
|
||||||
<Text style={{color: 'white', fontWeight: 500}}>Order Now</Text>
|
|
||||||
</Pressable>
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
</Pressable>
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<View style={{marginTop: 10, shadowColor: '#B4B4B8', shadowOffset: { width: 0, height: 1 }, shadowOpacity: 0.5, shadowRadius: 1,}}>
|
|
||||||
<Pressable onPress={() => navigation.navigate('menu')}>
|
|
||||||
<View style={{borderColor: '#EEEEEE', borderWidth: 1, borderRadius: 5}}>
|
|
||||||
<Image source={require('../../assets/images/menu/new_drink.jpg')} style={{width: '100%', height: 200, borderTopLeftRadius: 5, borderTopRightRadius: 5}}/>
|
|
||||||
<View style={{padding: 10}}>
|
|
||||||
<Text style={{fontSize: 16, fontWeight: 600, letterSpacing: 0.5, marginBottom: 10}}>Colorful Smoothies are here</Text>
|
|
||||||
<Text>The colors are not due to artificial colorings, but rather from natural fruits and vegetables</Text>
|
|
||||||
<Pressable onPress={() => navigation.navigate('menu')} style={{marginTop: 10, padding: 10, backgroundColor: '#DA7297', width: 100, borderRadius: 5, alignItems: 'center'}}>
|
|
||||||
<Text style={{color: 'white', fontWeight: 500}}>Order Now</Text>
|
|
||||||
</Pressable>
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
</Pressable>
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default HomeCardItem
|
|
||||||
|
|
||||||
const styles = StyleSheet.create({})
|
|
|
@ -1,58 +0,0 @@
|
||||||
import { Pressable, StyleSheet, Text, View } from 'react-native';
|
|
||||||
import React from 'react';
|
|
||||||
import OrderReceiptItem from '../components/OrderReceiptItem';
|
|
||||||
|
|
||||||
|
|
||||||
interface OrderHistoryCardProps {
|
|
||||||
navigationHandler: any;
|
|
||||||
CartList: any;
|
|
||||||
CartListPrice: string;
|
|
||||||
OrderDate: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
const OrderReceiptCard: React.FC<OrderHistoryCardProps> = ({
|
|
||||||
navigationHandler,
|
|
||||||
CartList,
|
|
||||||
CartListPrice,
|
|
||||||
OrderDate,
|
|
||||||
}) => {
|
|
||||||
|
|
||||||
return (
|
|
||||||
<View style={{borderColor: 'gray', borderWidth:1, marginBottom: 10}}>
|
|
||||||
<View style={{justifyContent: 'flex-end', padding: 10, backgroundColor: '#EEEEEE'}}>
|
|
||||||
<Text style={{fontWeight: 600}}>{OrderDate}</Text>
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<View style={{gap: 10}}>
|
|
||||||
<View style={{borderColor: 'black', borderWidth: 0.5, borderStyle: 'dashed'}}/>
|
|
||||||
{CartList.map((data: any, index: any) => (
|
|
||||||
<Pressable key={index.toString() + data.id} onPress={() => {
|
|
||||||
navigationHandler({
|
|
||||||
index: data.index,
|
|
||||||
id: data.id,
|
|
||||||
type: data.type,
|
|
||||||
});
|
|
||||||
}}>
|
|
||||||
<OrderReceiptItem
|
|
||||||
type={data.type}
|
|
||||||
name={data.name}
|
|
||||||
donutname={data.donutname}
|
|
||||||
image_item={data.image_item}
|
|
||||||
prices={data.prices}
|
|
||||||
ItemPrice={data.ItemPrice}
|
|
||||||
/>
|
|
||||||
</Pressable>
|
|
||||||
))}
|
|
||||||
</View>
|
|
||||||
<View style={{borderColor: 'black', borderWidth: 0.5, borderStyle: 'dashed'}}/>
|
|
||||||
<View style={{flexDirection: 'row', justifyContent: 'space-between', gap: 20, alignItems: 'center', padding: 10}}>
|
|
||||||
<Text style={{fontWeight: 600}}>Total Amount</Text>
|
|
||||||
<Text style={{fontWeight: 600}}>$ {CartListPrice}</Text>
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default OrderReceiptCard
|
|
||||||
|
|
||||||
const styles = StyleSheet.create({})
|
|
|
@ -1,53 +0,0 @@
|
||||||
import { Image, ImageProps, StyleSheet, Text, View } from 'react-native'
|
|
||||||
import React from 'react'
|
|
||||||
|
|
||||||
|
|
||||||
interface OrderReceiptItemProps{
|
|
||||||
type: string;
|
|
||||||
name: string;
|
|
||||||
donutname: string;
|
|
||||||
image_item: ImageProps;
|
|
||||||
prices: any;
|
|
||||||
ItemPrice: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const OrderReceiptItem: React.FC<OrderReceiptItemProps> = ({
|
|
||||||
type,
|
|
||||||
name,
|
|
||||||
donutname,
|
|
||||||
image_item,
|
|
||||||
prices,
|
|
||||||
ItemPrice,
|
|
||||||
}) => {
|
|
||||||
return (
|
|
||||||
<View style={{paddingHorizontal: 10, marginBottom: 10}}>
|
|
||||||
<View style={{flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center'}}>
|
|
||||||
<View style={{flexDirection: 'row', gap: 10, alignItems: 'center'}}>
|
|
||||||
<Image source={image_item} style={{width: 50, height: 50}} />
|
|
||||||
{prices.map((item: any, index: any) => (
|
|
||||||
<View key={index.toString()}>
|
|
||||||
<Text style={{width: 200}}>{name || donutname} <Text style={{fontWeight: 600}}>{item.size}</Text></Text>
|
|
||||||
</View>
|
|
||||||
))}
|
|
||||||
</View>
|
|
||||||
<View>
|
|
||||||
<Text>${ItemPrice}</Text>
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
{prices.map((data: any, index: any) => (
|
|
||||||
<View key={index.toString()} style={{flex: 1, alignItems: 'center', flexDirection: 'row', justifyContent: 'space-between', marginTop: 10}}>
|
|
||||||
<View style={{flex:1, flexDirection: 'row', gap: 10}}>
|
|
||||||
<Text>${data.price}</Text>
|
|
||||||
<Text>X {data.quantity}</Text>
|
|
||||||
</View>
|
|
||||||
<Text>${(data.quantity * data.price).toFixed(2).toString()}</Text>
|
|
||||||
</View>
|
|
||||||
))}
|
|
||||||
</View>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default OrderReceiptItem
|
|
||||||
|
|
||||||
const styles = StyleSheet.create({})
|
|
|
@ -10,7 +10,7 @@ import { TouchableWithoutFeedback } from 'react-native-gesture-handler';
|
||||||
|
|
||||||
const Detail = ({navigation, route}: any) => {
|
const Detail = ({navigation, route}: any) => {
|
||||||
const ItemOfIndex = useStore((state: any) =>
|
const ItemOfIndex = useStore((state: any) =>
|
||||||
route.params.type == 'Donut' ? state.AllDonutMenu : state.AllDrinkMenu,
|
route.params.type == 'Donut' ? state.AllDonutList2 : state.AllDrinkList2,
|
||||||
)[route.params.index];
|
)[route.params.index];
|
||||||
|
|
||||||
const addToFavoriteList = useStore((state: any) => state.addToFavoriteList);
|
const addToFavoriteList = useStore((state: any) => state.addToFavoriteList);
|
||||||
|
|
|
@ -9,7 +9,7 @@ import PaymentFooter from "../components/PaymentFooter";
|
||||||
|
|
||||||
const DetailDrink = ({navigation, route}: any) => {
|
const DetailDrink = ({navigation, route}: any) => {
|
||||||
const ItemOfIndex = useStore((state: any) =>
|
const ItemOfIndex = useStore((state: any) =>
|
||||||
route.params.type == 'Donut' ? state.AllDonutMenu : state.AllDrinkMenu,
|
route.params.type == 'Donut' ? state.AllDonutList2 : state.AllDrinkList2,
|
||||||
)[route.params.index];
|
)[route.params.index];
|
||||||
|
|
||||||
const addToFavoriteList = useStore((state: any) => state.addToFavoriteList);
|
const addToFavoriteList = useStore((state: any) => state.addToFavoriteList);
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
import { View, Text, ScrollView, StyleSheet, Image, Pressable } from 'react-native'
|
import { View, Text, ScrollView, StyleSheet } from 'react-native'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import HomeHeader from '../components/HomeHeader'
|
import HomeHeader from '../components/HomeHeader'
|
||||||
import HomeCardItem from '../components/HomeCardItem'
|
|
||||||
import { StatusBar } from 'expo-status-bar';
|
import { StatusBar } from 'expo-status-bar';
|
||||||
|
|
||||||
const Home = () => {
|
const Home = () => {
|
||||||
|
@ -11,7 +10,6 @@ const Home = () => {
|
||||||
<StatusBar style="dark"/>
|
<StatusBar style="dark"/>
|
||||||
<ScrollView showsVerticalScrollIndicator={false} contentContainerStyle={styles.ScrollViewFlex}>
|
<ScrollView showsVerticalScrollIndicator={false} contentContainerStyle={styles.ScrollViewFlex}>
|
||||||
<HomeHeader />
|
<HomeHeader />
|
||||||
<HomeCardItem />
|
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
</View>
|
</View>
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { View, Text, ScrollView, StyleSheet, Pressable, Dimensions} from 'react-native'
|
import { View, Text, ScrollView, StyleSheet, Pressable, Dimensions, ToastAndroid} from 'react-native'
|
||||||
import React, { useState } from 'react'
|
import React, { useState } from 'react'
|
||||||
import { useStore } from '../store/store';
|
import { useStore } from '../store/store';
|
||||||
import { useBottomTabBarHeight } from '@react-navigation/bottom-tabs';
|
import { useBottomTabBarHeight } from '@react-navigation/bottom-tabs';
|
||||||
|
@ -32,8 +32,8 @@ const getDonutList = (category: string, data: any) => {
|
||||||
|
|
||||||
|
|
||||||
const Menu = ({navigation}: any) => {
|
const Menu = ({navigation}: any) => {
|
||||||
const DonutList = useStore((state: any) => state.AllDonutMenu);
|
const DonutList = useStore((state: any) => state.AllDonutList2);
|
||||||
const DrinkList = useStore((state: any) => state.AllDrinkMenu);
|
const DrinkList = useStore((state: any) => state.AllDrinkList2);
|
||||||
|
|
||||||
const [categories, setCategories] = useState(getCategoriesFromData(DonutList));
|
const [categories, setCategories] = useState(getCategoriesFromData(DonutList));
|
||||||
const [searchMenu, setSearchMenu] = useState('');
|
const [searchMenu, setSearchMenu] = useState('');
|
||||||
|
|
|
@ -1,46 +1,10 @@
|
||||||
import { View, Text, ScrollView, Image } from 'react-native';
|
import { View, Text } from 'react-native'
|
||||||
import React from 'react';
|
import React from 'react'
|
||||||
import { useStore } from '../store/store';
|
|
||||||
import OrderReceiptCard from '../components/OrderReceiptCard';
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const OrderReceipt = ({navigation}: any) => {
|
|
||||||
const ReceiptList = useStore((state: any) => state.ReceiptList);
|
|
||||||
const navigationHandler = ({index, id, type}: any) => {
|
|
||||||
navigation.push('detail', {
|
|
||||||
index,
|
|
||||||
id,
|
|
||||||
type,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
const OrderReceipt = () => {
|
||||||
return (
|
return (
|
||||||
<View style={{backgroundColor: 'white', flex: 1}}>
|
<View>
|
||||||
<ScrollView showsVerticalScrollIndicator={false} contentContainerStyle={{flexGrow: 1, marginTop: 20, paddingHorizontal: 20, paddingVertical: 10}}>
|
<Text>OrderHistory</Text>
|
||||||
<View style={{flex: 1, justifyContent: 'space-between'}}>
|
|
||||||
<Text style={{fontSize: 30, fontWeight: 500}}>Receipt</Text>
|
|
||||||
{ReceiptList.length == 0 ? (
|
|
||||||
<View>
|
|
||||||
<Image source={require('../../assets/images/misc/receipt.png')} style={{ width: 200, height: 200, resizeMode: "contain"}} />
|
|
||||||
</View>
|
|
||||||
):(
|
|
||||||
<View style={{marginTop: 20}}>
|
|
||||||
{ReceiptList.map((data: any, index: any) => (
|
|
||||||
<OrderReceiptCard
|
|
||||||
key={index.toString()}
|
|
||||||
navigationHandler={navigationHandler}
|
|
||||||
CartList={data.CartList}
|
|
||||||
CartListPrice={data.CartListPrice}
|
|
||||||
OrderDate={data.OrderDate}
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
</View>
|
|
||||||
)}
|
|
||||||
</View>
|
|
||||||
</ScrollView>
|
|
||||||
</View>
|
</View>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,6 @@ import { Ionicons } from '@expo/vector-icons';
|
||||||
import PaymentOption from "../components/PaymentOption";
|
import PaymentOption from "../components/PaymentOption";
|
||||||
import PaymentFooter from "../components/PaymentFooter";
|
import PaymentFooter from "../components/PaymentFooter";
|
||||||
import { LinearGradient } from 'expo-linear-gradient';
|
import { LinearGradient } from 'expo-linear-gradient';
|
||||||
import { useStore } from '../store/store';
|
|
||||||
|
|
||||||
|
|
||||||
const PaymentOptionList = [
|
const PaymentOptionList = [
|
||||||
|
@ -30,34 +29,10 @@ const PaymentOptionList = [
|
||||||
|
|
||||||
|
|
||||||
const Payment = ({navigation, route}: any) => {
|
const Payment = ({navigation, route}: any) => {
|
||||||
const calculateCartPrice = useStore((state: any) => state.calculateCartPrice);
|
|
||||||
const addToReceiptList = useStore(((state: any) => state.addToReceiptList));
|
|
||||||
|
|
||||||
const [paymentMethod, setPaymentMenthod] = useState('Credit card');
|
const [paymentMethod, setPaymentMenthod] = useState('Credit card');
|
||||||
const [showApprove, setShowApprove] = useState(false);
|
|
||||||
|
|
||||||
|
|
||||||
const buttonPressHandler = () => {
|
|
||||||
setShowApprove(true);
|
|
||||||
addToReceiptList();
|
|
||||||
calculateCartPrice();
|
|
||||||
setTimeout(() => {
|
|
||||||
setShowApprove(false);
|
|
||||||
navigation.navigate('receipt')
|
|
||||||
}, 3000)
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={{flex:1, backgroundColor: 'white'}}>
|
<View style={{flex:1, backgroundColor: 'white'}}>
|
||||||
{showApprove ? (
|
|
||||||
<View style={{flex: 1, position: 'absolute', top: 0, bottom: 0, left: 0, right: 0, zIndex: 1000, backgroundColor: 'rgba(0, 0, 0, 0.5)', justifyContent: 'center', alignItems: 'center'}}>
|
|
||||||
<Image source={require('../../assets/images/misc/check.png')} style={{width: 100, height: 100}} />
|
|
||||||
<Text style={{marginTop: 20, marginBottom: 10, fontSize: 26, color: '#88D66C'}}>Approved!</Text>
|
|
||||||
<Text style={{fontSize: 20, color: '#88D66C'}}>Thank you for your order!</Text>
|
|
||||||
</View>
|
|
||||||
) : (
|
|
||||||
<></>
|
|
||||||
)}
|
|
||||||
<ScrollView showsVerticalScrollIndicator={false} contentContainerStyle={{flexGrow: 1}}>
|
<ScrollView showsVerticalScrollIndicator={false} contentContainerStyle={{flexGrow: 1}}>
|
||||||
<View style={{marginTop: 20, paddingHorizontal: 20, paddingVertical: 10, flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between'}}>
|
<View style={{marginTop: 20, paddingHorizontal: 20, paddingVertical: 10, flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between'}}>
|
||||||
<Pressable onPress={() => {navigation.pop()}}>
|
<Pressable onPress={() => {navigation.pop()}}>
|
||||||
|
@ -96,7 +71,7 @@ const Payment = ({navigation, route}: any) => {
|
||||||
<PaymentFooter
|
<PaymentFooter
|
||||||
buttonTitle={`Pay with ${paymentMethod}`}
|
buttonTitle={`Pay with ${paymentMethod}`}
|
||||||
price={{price: route.params.amount, currency: '$'}}
|
price={{price: route.params.amount, currency: '$'}}
|
||||||
buttonPressHandler={buttonPressHandler}
|
buttonPressHandler={() => {}}
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
)
|
)
|
||||||
|
|
|
@ -8,8 +8,8 @@ import DrinkData from "../data/DrinkData";
|
||||||
export const useStore = create(
|
export const useStore = create(
|
||||||
persist(
|
persist(
|
||||||
(set, get) => ({
|
(set, get) => ({
|
||||||
AllDonutMenu: DonutData,
|
AllDonutList1: DonutData,
|
||||||
AllDrinkMenu: DrinkData,
|
AllDrinkList: DrinkData,
|
||||||
CartPrice: 0,
|
CartPrice: 0,
|
||||||
FavoriteList: [],
|
FavoriteList: [],
|
||||||
CartList: [],
|
CartList: [],
|
||||||
|
@ -68,25 +68,25 @@ export const useStore = create(
|
||||||
set(
|
set(
|
||||||
produce(state => {
|
produce(state => {
|
||||||
if(type == 'Donut'){
|
if(type == 'Donut'){
|
||||||
for(let i = 0; i < state.AllDonutMenu.length; i++){
|
for(let i = 0; i < state.AllDonutList1.length; i++){
|
||||||
if(state.AllDonutMenu[i].id == id){
|
if(state.AllDonutList1[i].id == id){
|
||||||
if(state.AllDonutMenu[i].favourite == false){
|
if(state.AllDonutList1[i].favourite == false){
|
||||||
state.AllDonutMenu[i].favourite = true;
|
state.AllDonutList1[i].favourite = true;
|
||||||
state.FavoriteList.unshift(state.AllDonutMenu[i]);
|
state.FavoriteList.unshift(state.AllDonutList1[i]);
|
||||||
} else{
|
} else{
|
||||||
state.AllDonutMenu[i].favourite = false;
|
state.AllDonutList1[i].favourite = false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if(type == 'Drink'){
|
} else if(type == 'Drink'){
|
||||||
for(let i = 0; i < state.AllDrinkMenu.length; i++){
|
for(let i = 0; i< state.AllDrinkList.length; i++){
|
||||||
if(state.AllDrinkMenu[i].id == id){
|
if(state.AllDrinkList[i].id == id){
|
||||||
if(state.AllDrinkMenu[i].favourite == false){
|
if(state.AllDrinkList[i].favourite == false){
|
||||||
state.AllDrinkMenu[i].favourite = true;
|
state.AllDrinkList[i].favourite = true;
|
||||||
state.FavoriteList.unshift(state.AllDrinkMenu[i]);
|
state.FavoriteList.unshift(state.AllDrinkList[i]);
|
||||||
} else{
|
} else{
|
||||||
state.AllDrinkMenu[i].favourite = false;
|
state.AllDrinkList[i].favourite = false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -98,23 +98,23 @@ export const useStore = create(
|
||||||
set(
|
set(
|
||||||
produce(state => {
|
produce(state => {
|
||||||
if(type = 'Donut'){
|
if(type = 'Donut'){
|
||||||
for(let i = 0; i < state.AllDonutMenu.length; i++){
|
for(let i = 0; i < state.AllDonutList1.length; i++){
|
||||||
if(state.AllDonutMenu[i].id == id){
|
if(state.AllDonutList1[i].id == id){
|
||||||
if(state.AllDonutMenu[i].favourite == true){
|
if(state.AllDonutList1[i].favourite == true){
|
||||||
state.AllDonutMenu[i].favourite = false;
|
state.AllDonutList1[i].favourite = false;
|
||||||
} else{
|
} else{
|
||||||
state.AllDonutMenu[i].favourite = true;
|
state.AllDonutList1[i].favourite = true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if(type = 'Drink'){
|
} else if(type = 'Drink'){
|
||||||
for(let i = 0; i < state.AllDrinkMenu.length; i++){
|
for(let i = 0; i < state.AllDrinkList.length; i++){
|
||||||
if(state.AllDrinkMenu[i].id == id){
|
if(state.AllDrinkList[i].id == id){
|
||||||
if(state.AllDrinkMenu[i].favourite == true){
|
if(state.AllDrinkList[i].favourite == true){
|
||||||
state.AllDrinkMenu[i].favourite = false;
|
state.AllDrinkList[i].favourite = false;
|
||||||
} else{
|
} else{
|
||||||
state.AllDrinkMenu[i].favourite = true;
|
state.AllDrinkList[i].favourite = true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -130,72 +130,6 @@ export const useStore = create(
|
||||||
state.FavoriteList.splice(spliceIndex, 1);
|
state.FavoriteList.splice(spliceIndex, 1);
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
addCartItemQuantity:(id: string, size: string) =>
|
|
||||||
set(
|
|
||||||
produce(state => {
|
|
||||||
for(let i = 0; i < state.CartList.length; i++){
|
|
||||||
if(state.CartList[i].id == id){
|
|
||||||
for (let j = 0; j < state.CartList[i].prices.length; j++) {
|
|
||||||
if (state.CartList[i].prices[j].size == size) {
|
|
||||||
state.CartList[i].prices[j].quantity++;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
removeCartItemQuantity:(id: string, size: string) =>
|
|
||||||
set(
|
|
||||||
produce(state => {
|
|
||||||
for (let i = 0; i < state.CartList.length; i++) {
|
|
||||||
if(state.CartList[i].id == id){
|
|
||||||
for (let j = 0; j < state.CartList[i].prices.length; j++) {
|
|
||||||
if (state.CartList[i].prices[j].size == size) {
|
|
||||||
if(state.CartList[i].prices.length > 1){
|
|
||||||
if (state.CartList[i].prices[j].quantity > 1) {
|
|
||||||
state.CartList[i].prices[j].quantity--;
|
|
||||||
} else{
|
|
||||||
state.CartList[i].prices.splice(j, 1);
|
|
||||||
}
|
|
||||||
} else{
|
|
||||||
if (state.CartList[i].prices[j].quantity > 1) {
|
|
||||||
state.CartList[i].prices[j].quantity--;
|
|
||||||
} else {
|
|
||||||
state.CartList.splice(i, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
addToReceiptList:() =>
|
|
||||||
set(
|
|
||||||
produce(state => {
|
|
||||||
let temp = state.CartList.reduce(
|
|
||||||
(accumulator: number, currentValue: any) =>
|
|
||||||
accumulator + parseFloat(currentValue.ItemPrice),
|
|
||||||
0,
|
|
||||||
);
|
|
||||||
if(state.ReceiptList.length > 0){
|
|
||||||
state.ReceiptList.unshift({
|
|
||||||
OrderDate: new Date().toDateString() + ' ' + new Date().toLocaleTimeString(),
|
|
||||||
CartList: state.CartList,
|
|
||||||
CartListPrice: temp.toFixed(2).toString(),
|
|
||||||
})
|
|
||||||
} else{
|
|
||||||
state.ReceiptList.push({
|
|
||||||
OrderDate: new Date().toDateString() + ' ' + new Date().toLocaleTimeString(),
|
|
||||||
CartList: state.CartList,
|
|
||||||
CartListPrice: temp.toFixed(2).toString(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
state.CartList = [];
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
name: 'donutshop',
|
name: 'donutshop',
|
||||||
|
|
23
ev_station/.gitignore
vendored
|
@ -1,23 +0,0 @@
|
||||||
node_modules/
|
|
||||||
.expo/
|
|
||||||
dist/
|
|
||||||
npm-debug.*
|
|
||||||
*.jks
|
|
||||||
*.p8
|
|
||||||
*.p12
|
|
||||||
*.key
|
|
||||||
*.mobileprovision
|
|
||||||
*.orig.*
|
|
||||||
web-build/
|
|
||||||
|
|
||||||
# macOS
|
|
||||||
.DS_Store
|
|
||||||
|
|
||||||
# @generated expo-cli sync-2b81b286409207a5da26e14c78851eb30d8ccbdb
|
|
||||||
# The following patterns were generated by expo-cli
|
|
||||||
|
|
||||||
expo-env.d.ts
|
|
||||||
# @end expo-cli
|
|
||||||
|
|
||||||
.env
|
|
||||||
app/misc/FirebaseConfig.js
|
|
|
@ -1,9 +0,0 @@
|
||||||
# EV Charging Station Finder with React Native
|
|
||||||
|
|
||||||
EV Charging Station Finder is mobile application where users can search for the nearest EV charging station, save their list, and start their route to the picked EV station.
|
|
||||||
|
|
||||||
## To start the project
|
|
||||||
* Download [Expo Go](https://expo.dev/go) on your device to launch the project.
|
|
||||||
* To start the project, run this command in your terminal `npx expo start --tunnel`
|
|
||||||
* Scan the QR code that shows in your terminal.
|
|
||||||
* For more information about Tunneling, please read [Expo](https://docs.expo.dev/more/expo-cli/#tunneling).
|
|
|
@ -1,42 +0,0 @@
|
||||||
{
|
|
||||||
"expo": {
|
|
||||||
"name": "ev_station",
|
|
||||||
"slug": "ev_station",
|
|
||||||
"version": "1.0.0",
|
|
||||||
"orientation": "portrait",
|
|
||||||
"icon": "./assets/images/icon.png",
|
|
||||||
"scheme": "myapp",
|
|
||||||
"userInterfaceStyle": "automatic",
|
|
||||||
"splash": {
|
|
||||||
"image": "./assets/images/splash.png",
|
|
||||||
"resizeMode": "contain",
|
|
||||||
"backgroundColor": "#ffffff"
|
|
||||||
},
|
|
||||||
"ios": {
|
|
||||||
"supportsTablet": true
|
|
||||||
},
|
|
||||||
"android": {
|
|
||||||
"adaptiveIcon": {
|
|
||||||
"foregroundImage": "./assets/images/adaptive-icon.png",
|
|
||||||
"backgroundColor": "#ffffff"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"web": {
|
|
||||||
"bundler": "metro",
|
|
||||||
"output": "static",
|
|
||||||
"favicon": "./assets/images/favicon.png"
|
|
||||||
},
|
|
||||||
"plugins": [
|
|
||||||
[
|
|
||||||
"expo-location",
|
|
||||||
{
|
|
||||||
"locationAlwaysAndWhenInUsePermission": "Allow ev_station to use your location."
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"expo-router"
|
|
||||||
],
|
|
||||||
"experiments": {
|
|
||||||
"typedRoutes": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,46 +0,0 @@
|
||||||
import { View, Text, StyleSheet } from 'react-native'
|
|
||||||
import React from 'react'
|
|
||||||
import {createBottomTabNavigator} from "@react-navigation/bottom-tabs";
|
|
||||||
import HomeScreen from "../screen/HomeScreen"
|
|
||||||
import SaveScreen from "../screen/SaveScreen"
|
|
||||||
import {Entypo, MaterialIcons, AntDesign} from '@expo/vector-icons';
|
|
||||||
|
|
||||||
|
|
||||||
const Tab = createBottomTabNavigator();
|
|
||||||
|
|
||||||
const HomeNavigator = () => {
|
|
||||||
return (
|
|
||||||
<Tab.Navigator screenOptions={{headerShown: false, tabBarHideOnKeyboard: true}}>
|
|
||||||
<Tab.Screen name='home' component={HomeScreen}
|
|
||||||
options={{
|
|
||||||
tabBarLabel: "Home",
|
|
||||||
tabBarActiveTintColor: '#379777',
|
|
||||||
tabBarInactiveTintColor: 'gray',
|
|
||||||
tabBarIcon:({focused}) =>
|
|
||||||
focused? (
|
|
||||||
<Entypo name="home" size={26} color="#379777" style={{marginTop: 5, marginBottom: 5}}/>
|
|
||||||
) : (
|
|
||||||
<Entypo name="home" size={26} color="gray" style={{marginTop: 5, marginBottom: 5}}/>
|
|
||||||
)
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<Tab.Screen name='save' component={SaveScreen}
|
|
||||||
options={{
|
|
||||||
tabBarLabel: "Save",
|
|
||||||
tabBarActiveTintColor: '#379777',
|
|
||||||
tabBarInactiveTintColor: 'gray',
|
|
||||||
tabBarIcon:({focused}) =>
|
|
||||||
focused? (
|
|
||||||
<MaterialIcons name="data-saver-on" size={26} color="#379777" style={{marginTop: 5, marginBottom: 5}}/>
|
|
||||||
) : (
|
|
||||||
<MaterialIcons name="data-saver-on" size={26} color="gray" style={{marginTop: 5, marginBottom: 5}}/>
|
|
||||||
)
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</Tab.Navigator>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default HomeNavigator
|
|
||||||
|
|
||||||
const styles = StyleSheet.create({})
|
|
|
@ -1,3 +0,0 @@
|
||||||
import { createContext } from "react";
|
|
||||||
|
|
||||||
export const MarkerContext = createContext(null);
|
|
|
@ -1,3 +0,0 @@
|
||||||
import { createContext } from "react";
|
|
||||||
|
|
||||||
export const UserLocationContext = createContext(null);
|
|
|
@ -1,76 +0,0 @@
|
||||||
import { StatusBar } from "expo-status-bar";
|
|
||||||
import { View, Text } from "react-native";
|
|
||||||
import Login from "./screen/loginScreen/Login";
|
|
||||||
import { ClerkProvider, SignedIn, SignedOut } from '@clerk/clerk-expo';
|
|
||||||
import *as SecureStore from "expo-secure-store";
|
|
||||||
import * as Location from 'expo-location';
|
|
||||||
import { NavigationContainer } from "@react-navigation/native";
|
|
||||||
import HomeNavigator from "./Navigation/HomeNavigator";
|
|
||||||
import { useEffect, useState } from "react";
|
|
||||||
import { UserLocationContext } from "./context/UserLocationContext";
|
|
||||||
|
|
||||||
|
|
||||||
const tokenCache = {
|
|
||||||
async getToken(key){
|
|
||||||
try {
|
|
||||||
return SecureStore.getItemAsync(key);
|
|
||||||
} catch (error) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
async saveToken(key, value){
|
|
||||||
try {
|
|
||||||
return SecureStore.setItemAsync(key, value);
|
|
||||||
} catch (error) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
export default function Index() {
|
|
||||||
const PUBLIC_KEY = process.env.EXPO_PUBLIC_CLERK_PUBLISHABLE_KEY;
|
|
||||||
|
|
||||||
//use current location
|
|
||||||
const [location, setLocation] = useState(null);
|
|
||||||
const [errorMsg, setErrorMsg] = useState(null);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
(async () => {
|
|
||||||
|
|
||||||
let { status } = await Location.requestForegroundPermissionsAsync();
|
|
||||||
if (status !== 'granted') {
|
|
||||||
setErrorMsg('Permission to access location was denied');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let location = await Location.getCurrentPositionAsync({});
|
|
||||||
setLocation(location.coords);
|
|
||||||
})();
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
let text = 'Waiting..';
|
|
||||||
if (errorMsg) {
|
|
||||||
text = errorMsg;
|
|
||||||
} else if (location) {
|
|
||||||
text = JSON.stringify(location);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<ClerkProvider tokenCache={tokenCache} publishableKey={PUBLIC_KEY}>
|
|
||||||
<UserLocationContext.Provider value={{location, setLocation}}>
|
|
||||||
<View style={{flex: 1, backgroundColor: 'white'}}>
|
|
||||||
<StatusBar style="auto"/>
|
|
||||||
<SignedIn>
|
|
||||||
<NavigationContainer independent={true}>
|
|
||||||
<HomeNavigator />
|
|
||||||
</NavigationContainer>
|
|
||||||
</SignedIn>
|
|
||||||
<SignedOut>
|
|
||||||
<Login/>
|
|
||||||
</SignedOut>
|
|
||||||
</View>
|
|
||||||
</UserLocationContext.Provider>
|
|
||||||
</ClerkProvider>
|
|
||||||
);
|
|
||||||
}
|
|
|
@ -1,26 +0,0 @@
|
||||||
import axios from 'axios'
|
|
||||||
|
|
||||||
const BASE_URL = 'https://places.googleapis.com/v1/places:searchNearby';
|
|
||||||
const API_KEY = process.env.EXPO_PUBLIC_GOOGLE_PLACE_API_KEY;
|
|
||||||
|
|
||||||
const config = {
|
|
||||||
headers:{
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
'X-Goog-Api-Key': API_KEY,
|
|
||||||
'X-Goog-FieldMask': [
|
|
||||||
'places.displayName',
|
|
||||||
'places.formattedAddress',
|
|
||||||
'places.location',
|
|
||||||
'places.evChargeOptions',
|
|
||||||
'places.photos',
|
|
||||||
'places.id'
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const NewNearByPlace = (data) => axios.post(BASE_URL, data, config).catch(function (error) {
|
|
||||||
console.log(error.toJSON());
|
|
||||||
});
|
|
||||||
;
|
|
||||||
|
|
||||||
export default{NewNearByPlace, API_KEY}
|
|
|
@ -1,19 +0,0 @@
|
||||||
import { Image, StyleSheet, Text, View } from 'react-native'
|
|
||||||
import React from 'react'
|
|
||||||
import { useUser } from '@clerk/clerk-expo';
|
|
||||||
|
|
||||||
const HomeHeader = () => {
|
|
||||||
const {user} = useUser();
|
|
||||||
return (
|
|
||||||
<View style={{backgroundColor: 'white', paddingHorizontal: 20, paddingVertical: 10}}>
|
|
||||||
<View style={{flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center'}}>
|
|
||||||
<Image source={require('../../assets/images/ev_images/EV.png')} style={{width: 120, height: 60, objectFit: 'contain'}}/>
|
|
||||||
<Image source={{uri: user?.imageUrl}} style={{width: 40, height: 40, borderRadius: '50%'}}/>
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default HomeHeader
|
|
||||||
|
|
||||||
const styles = StyleSheet.create({})
|
|
|
@ -1,62 +0,0 @@
|
||||||
import { Image, Pressable, StyleSheet, Text, View } from 'react-native';
|
|
||||||
import React, { useContext, useEffect, useState } from 'react';
|
|
||||||
import MapViewScreen from "../screen/mapView/MapViewScreen";
|
|
||||||
import HomeHeader from './HomeHeader';
|
|
||||||
import HomeSearch from './HomeSearch';
|
|
||||||
import { UserLocationContext } from '../context/UserLocationContext';
|
|
||||||
import GlobalApi from '../misc/GlobalApi';
|
|
||||||
import EVListView from '../screen/googleList/EVListView';
|
|
||||||
import { MarkerContext } from '../context/MakerContext';
|
|
||||||
|
|
||||||
|
|
||||||
const HomeScreen = () => {
|
|
||||||
const {location, setLocation} = useContext(UserLocationContext);
|
|
||||||
const [placeList, setPlaceList] = useState([]);
|
|
||||||
|
|
||||||
const [selectedMarker, setSelectedMarker] = useState('');
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
location && GetNearByPlace();
|
|
||||||
},[location])
|
|
||||||
|
|
||||||
const GetNearByPlace = () => {
|
|
||||||
|
|
||||||
const data = {
|
|
||||||
"includedTypes": ["electric_vehicle_charging_station"],
|
|
||||||
"maxResultCount": 10,
|
|
||||||
"locationRestriction": {
|
|
||||||
"circle": {
|
|
||||||
"center": {
|
|
||||||
"latitude": location?.latitude,
|
|
||||||
"longitude": location?.longitude
|
|
||||||
},
|
|
||||||
"radius": 5000.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
GlobalApi.NewNearByPlace(data).then(res => {
|
|
||||||
console.log(JSON.stringify(res.data));
|
|
||||||
setPlaceList(res.data?.places);
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<MarkerContext.Provider value={{selectedMarker, setSelectedMarker}}>
|
|
||||||
<View style={{flex: 1, backgroundColor: 'white'}}>
|
|
||||||
<View style={{position: 'absolute', zIndex: 10, width: '100%'}}>
|
|
||||||
<HomeHeader />
|
|
||||||
<HomeSearch searchedLocation={(location) => setLocation({latitude: location.lat, longitude: location.lng})}/>
|
|
||||||
</View>
|
|
||||||
{placeList && <MapViewScreen placeList={placeList}/>}
|
|
||||||
<View style={{position: 'absolute', bottom: 0, zIndex: 20, width: '100%'}}>
|
|
||||||
{placeList && <EVListView placeList={placeList}/>}
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
</MarkerContext.Provider>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default HomeScreen
|
|
||||||
|
|
||||||
const styles = StyleSheet.create({})
|
|
|
@ -1,34 +0,0 @@
|
||||||
import { StyleSheet, Text, View } from 'react-native'
|
|
||||||
import React from 'react'
|
|
||||||
import { GooglePlacesAutocomplete } from 'react-native-google-places-autocomplete';
|
|
||||||
|
|
||||||
|
|
||||||
const mapApiKey = process.env.EXPO_PUBLIC_GOOGLE_PLACE_API_KEY;
|
|
||||||
|
|
||||||
const HomeSearch = ({searchedLocation}) => {
|
|
||||||
|
|
||||||
return (
|
|
||||||
<View style={{marginVertical: 10, marginHorizontal: 10, borderRadius: 5}}>
|
|
||||||
<GooglePlacesAutocomplete
|
|
||||||
placeholder='Search EV charging station'
|
|
||||||
textInputProps={{
|
|
||||||
placeholderTextColor: '#45474B'
|
|
||||||
}}
|
|
||||||
enablePoweredByContainer={false}
|
|
||||||
fetchDetails={true}
|
|
||||||
onPress={(data, details = null) => {
|
|
||||||
searchedLocation(details?.geometry?.location)
|
|
||||||
}}
|
|
||||||
query={{
|
|
||||||
key: mapApiKey,
|
|
||||||
language: 'en',
|
|
||||||
}}
|
|
||||||
onFail={error => console.error(error)}
|
|
||||||
/>
|
|
||||||
</View>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default HomeSearch
|
|
||||||
|
|
||||||
const styles = StyleSheet.create({})
|
|
|
@ -1,58 +0,0 @@
|
||||||
import { ActivityIndicator, FlatList, StyleSheet, Text, View } from 'react-native'
|
|
||||||
import { collection, query, where, getDocs, getFirestore } from "firebase/firestore";
|
|
||||||
import React, { useEffect, useState } from 'react'
|
|
||||||
import { useUser } from '@clerk/clerk-expo';
|
|
||||||
import { app } from '../misc/FirebaseConfig';
|
|
||||||
import ItemList from './googleList/ItemList';
|
|
||||||
|
|
||||||
const SaveScreen = () => {
|
|
||||||
const {user} = useUser();
|
|
||||||
const [saveList, setSaveList] = useState([]);
|
|
||||||
const [isLoading, setIsLoading] = useState(false);
|
|
||||||
|
|
||||||
db = getFirestore(app);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
user && getSaveList();
|
|
||||||
}, [user])
|
|
||||||
|
|
||||||
const getSaveList = async() => {
|
|
||||||
setIsLoading(true);
|
|
||||||
setSaveList([])
|
|
||||||
const q = query(collection(db, "ev-save"), where("email", "==", user?.primaryEmailAddress?.emailAddress));
|
|
||||||
|
|
||||||
const querySnapshot = await getDocs(q);
|
|
||||||
querySnapshot.forEach((doc) => {
|
|
||||||
// doc.data() is never undefined for query doc snapshots
|
|
||||||
console.log(doc.id, " => ", doc.data());
|
|
||||||
setSaveList(saveList => [...saveList, doc.data()]);
|
|
||||||
setIsLoading(false);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<View style={{flex: 1, backgroundColor: 'white'}}>
|
|
||||||
{!saveList?
|
|
||||||
<View style={{flexDirection: 'column', alignItems: 'center', justifyContent: 'center', height: '100%'}}>
|
|
||||||
<ActivityIndicator size={'large'} color={'#379777'}/>
|
|
||||||
<Text style={{marginTop: 10}}>Loading</Text>
|
|
||||||
|
|
||||||
</View> : null
|
|
||||||
}
|
|
||||||
<FlatList
|
|
||||||
onRefresh={() => getSaveList()}
|
|
||||||
refreshing={isLoading}
|
|
||||||
data={saveList}
|
|
||||||
renderItem={({item, index}) => (
|
|
||||||
<View key={index} style={{marginVertical: 5, marginHorizontal: 5, borderColor: 'gray', borderWidth: 1}}>
|
|
||||||
<ItemList place={item.place} isSave={true} markedSave={() => getSaveList()}/>
|
|
||||||
</View>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
</View>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default SaveScreen
|
|
||||||
|
|
||||||
const styles = StyleSheet.create({})
|
|
|
@ -1,71 +0,0 @@
|
||||||
import { Dimensions, FlatList, StyleSheet, Text, View } from 'react-native'
|
|
||||||
import React, { useContext, useEffect, useRef, useState } from 'react'
|
|
||||||
import ItemList from './ItemList'
|
|
||||||
import { MarkerContext } from '@/app/context/MakerContext';
|
|
||||||
import { collection, query, where, getDocs, getFirestore } from "firebase/firestore";
|
|
||||||
import { app } from '@/app/misc/FirebaseConfig';
|
|
||||||
import { useUser } from '@clerk/clerk-expo';
|
|
||||||
|
|
||||||
const EVListView = ({placeList}) => {
|
|
||||||
const {user} = useUser();
|
|
||||||
const [saveList, setSaveList] = useState([]);
|
|
||||||
const flatListRef = useRef(null);
|
|
||||||
const {selectedMarker, setSelectedMarker} = useContext(MarkerContext);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
selectedMarker && scrollToIndex(selectedMarker);
|
|
||||||
}, [selectedMarker])
|
|
||||||
|
|
||||||
const scrollToIndex = (index) => {
|
|
||||||
flatListRef.current?.scrollToIndex({animated: true, index})
|
|
||||||
}
|
|
||||||
|
|
||||||
const getItemLayout = (_,index) => ({
|
|
||||||
length: Dimensions.get('window').width,
|
|
||||||
offset: Dimensions.get('window').width*index,
|
|
||||||
index
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
const db = getFirestore(app);
|
|
||||||
useEffect(() => {
|
|
||||||
user && getSaveList();
|
|
||||||
}, [user])
|
|
||||||
|
|
||||||
const getSaveList = async() => {
|
|
||||||
setSaveList([])
|
|
||||||
const q = query(collection(db, "ev-save"), where("email", "==", user?.primaryEmailAddress?.emailAddress));
|
|
||||||
|
|
||||||
const querySnapshot = await getDocs(q);
|
|
||||||
querySnapshot.forEach((doc) => {
|
|
||||||
// doc.data() is never undefined for query doc snapshots
|
|
||||||
console.log(doc.id, " => ", doc.data());
|
|
||||||
setSaveList(saveList => [...saveList, doc.data()]);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const isSave = (place) => {
|
|
||||||
const result = saveList.find(item => item.place.id == place.id);
|
|
||||||
return result?true : false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<View>
|
|
||||||
<FlatList horizontal={true}
|
|
||||||
getItemLayout={getItemLayout}
|
|
||||||
data={placeList}
|
|
||||||
showsHorizontalScrollIndicator={false}
|
|
||||||
ref={flatListRef}
|
|
||||||
renderItem={({item, index}) => (
|
|
||||||
<View key={index}>
|
|
||||||
<ItemList place={item} isSave={isSave(item)} markedSave={() => getSaveList()}/>
|
|
||||||
</View>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
</View>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default EVListView
|
|
||||||
|
|
||||||
const styles = StyleSheet.create({})
|
|
|
@ -1,66 +0,0 @@
|
||||||
import { Dimensions, Image, Linking, Platform, Pressable, StyleSheet, Text, View } from 'react-native'
|
|
||||||
import React from 'react'
|
|
||||||
import GlobalApi from '@/app/misc/GlobalApi'
|
|
||||||
import AntDesign from '@expo/vector-icons/AntDesign';
|
|
||||||
import MaterialCommunityIcons from '@expo/vector-icons/MaterialCommunityIcons';
|
|
||||||
import { getFirestore } from "firebase/firestore";
|
|
||||||
import { app } from "../../misc/FirebaseConfig";
|
|
||||||
import { doc, setDoc, deleteDoc} from "firebase/firestore";
|
|
||||||
import { useUser } from '@clerk/clerk-expo';
|
|
||||||
|
|
||||||
const ItemList = ({place, isSave, markedSave}) => {
|
|
||||||
const placePhoto_Base_Url = 'https://places.googleapis.com/v1/'
|
|
||||||
const {user} = useUser();
|
|
||||||
const db = getFirestore(app);
|
|
||||||
const onSave = async(place) => {
|
|
||||||
await setDoc(doc(db, 'ev-save', (place.id).toString()), {
|
|
||||||
place: place,
|
|
||||||
email: user?.primaryEmailAddress?.emailAddress
|
|
||||||
});
|
|
||||||
markedSave();
|
|
||||||
};
|
|
||||||
const onRemoveSave = async(placeId) => {
|
|
||||||
await deleteDoc(doc(db, 'ev-save', placeId.toString()));
|
|
||||||
markedSave();
|
|
||||||
}
|
|
||||||
|
|
||||||
const onStartClick = () => {
|
|
||||||
const url = Platform.select({
|
|
||||||
ios: "maps:"+place?.location?.latitude+","+place?.location?.longitude+"?q="+place?.formattedAddress,
|
|
||||||
});
|
|
||||||
Linking.openURL(url);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
return (
|
|
||||||
<View style={{width: Dimensions.get('screen').width *0.92, height: 280, backgroundColor: 'white', marginLeft: 10, marginVertical: 5 ,borderRadius: 5, flexDirection: 'column', justifyContent: 'space-between'}}>
|
|
||||||
{!isSave?
|
|
||||||
<Pressable onPress={() => onSave(place)}
|
|
||||||
style={{position: 'absolute', zIndex: 20, right: 0, margin: 10, width: 40, height: 40, backgroundColor: '#379777', alignItems: 'center', justifyContent: 'center', borderRadius: '50%'}}>
|
|
||||||
<AntDesign name="pluscircleo" size={30} color="white" />
|
|
||||||
</Pressable> :
|
|
||||||
<Pressable onPress={() => onRemoveSave(place.id)}
|
|
||||||
style={{position: 'absolute', zIndex: 20, right: 0, margin: 10, width: 40, height: 40, backgroundColor: '#379777', alignItems: 'center', justifyContent: 'center', borderRadius: '50%'}}>
|
|
||||||
<MaterialCommunityIcons name="map-marker-star" size={30} color="white" />
|
|
||||||
</Pressable>
|
|
||||||
}
|
|
||||||
<Image source={place?.photos?{uri:placePhoto_Base_Url+place.photos[0].name+"/media?key="+GlobalApi.API_KEY+"&maxHeightPx=500&maxWidthPx=500"}
|
|
||||||
: require('../../../assets/images/ev_images/EV.png')} style={{width: '100%', height: 120, objectFit: 'cover', borderTopLeftRadius: 5, borderTopRightRadius: 5}}/>
|
|
||||||
<View style={{padding: 10, flexDirection: 'column', justifyContent: 'space-between'}}>
|
|
||||||
<View>
|
|
||||||
<Text style={{fontSize: 20, fontWeight: 600, color: '#379777'}}>{place.displayName.text}</Text>
|
|
||||||
<Text style={{marginTop: 5, color: '#45474B', fontWeight: 600, fontSize: 15}}>Total chargers: {place?.evChargeOptions?.connectorCount}</Text>
|
|
||||||
<Text style={{marginVertical: 5, color: '#45474B', fontSize: 15}}>{place?.formattedAddress}</Text>
|
|
||||||
</View>
|
|
||||||
<Pressable onPress={() => onStartClick()}
|
|
||||||
style={{backgroundColor: '#379777', alignItems: 'center', justifyContent: 'center', padding: 5, marginTop: 10, borderRadius: 5}}>
|
|
||||||
<Text style={{color: 'white', fontSize: 18, fontWeight: 500}}>Start</Text>
|
|
||||||
</Pressable>
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default ItemList
|
|
||||||
|
|
||||||
const styles = StyleSheet.create({})
|
|
|
@ -1,42 +0,0 @@
|
||||||
import { Image, Pressable, StyleSheet, Text, View } from 'react-native'
|
|
||||||
import React from 'react';
|
|
||||||
import *as WebBrowser from "expo-web-browser";
|
|
||||||
import { useOAuth } from '@clerk/clerk-expo';
|
|
||||||
import { useWarmUpBrowser } from '../../../hooks/warmUpBrowser'
|
|
||||||
|
|
||||||
|
|
||||||
WebBrowser.maybeCompleteAuthSession();
|
|
||||||
const Login = () => {
|
|
||||||
useWarmUpBrowser();
|
|
||||||
const {startOAuthFlow} = useOAuth({strategy: "oauth_google"})
|
|
||||||
|
|
||||||
const loginHandler = async() => {
|
|
||||||
try {
|
|
||||||
const {createdSessionId, signIn, signUp, setActive} = await startOAuthFlow();
|
|
||||||
if(createdSessionId){
|
|
||||||
setActive({session: createdSessionId});
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch (error) {
|
|
||||||
console.error("oAuth error");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<View style={{flex:1, justifyContent: 'center', alignItems: 'center'}}>
|
|
||||||
<Image source={require('../../../assets/images/ev_images/EV.png')}/>
|
|
||||||
<View style={{padding: 20, marginVertical: 10}}>
|
|
||||||
<Text style={{fontSize: 24, textAlign: 'center', paddingHorizontal: 5, fontWeight: 600, color: '#45474B'}}>Find reliable EV charging stations near you just one click</Text>
|
|
||||||
<Pressable onPress={loginHandler} style={{marginVertical: 50}}>
|
|
||||||
<View style={{justifyContent: 'center', alignItems: 'center', padding: 10, backgroundColor: '#379777', marginHorizontal: 100, borderRadius: 5}}>
|
|
||||||
<Text style={{fontSize: 20, fontWeight: 500, color: 'white'}}>Start</Text>
|
|
||||||
</View>
|
|
||||||
</Pressable>
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Login
|
|
||||||
|
|
||||||
const styles = StyleSheet.create({})
|
|
|
@ -1,38 +0,0 @@
|
||||||
import { Image, StyleSheet, Text, View } from 'react-native';
|
|
||||||
import React, { useContext } from 'react';
|
|
||||||
import MapView, { Marker, PROVIDER_DEFAULT} from 'react-native-maps';
|
|
||||||
import { UserLocationContext } from '@/app/context/UserLocationContext';
|
|
||||||
import MarkerList from '../mapView/MarkerList';
|
|
||||||
|
|
||||||
|
|
||||||
const MapViewScreen = ({placeList}) => {
|
|
||||||
const {location, setLocation} = useContext(UserLocationContext)
|
|
||||||
|
|
||||||
|
|
||||||
return location?.latitude &&(
|
|
||||||
<View>
|
|
||||||
<MapView style={{width: '100%', height: '100%'}}
|
|
||||||
provider={PROVIDER_DEFAULT}
|
|
||||||
region={{
|
|
||||||
latitude: location?.latitude,
|
|
||||||
longitude: location?.longitude,
|
|
||||||
latitudeDelta: 0.2,
|
|
||||||
longitudeDelta: 0.2
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{location? <Marker coordinate={{latitude: location?.latitude, longitude: location?.longitude}}>
|
|
||||||
<Image source={require('../../../assets/images/ev_images/car.png')} style={{width: 50, height: 50}}/>
|
|
||||||
</Marker> : null}
|
|
||||||
|
|
||||||
{placeList && placeList.map((item, index) => (
|
|
||||||
<MarkerList key={index} place={item} index={index}/>
|
|
||||||
))}
|
|
||||||
|
|
||||||
</MapView>
|
|
||||||
</View>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default MapViewScreen
|
|
||||||
|
|
||||||
const styles = StyleSheet.create({})
|
|
|
@ -1,22 +0,0 @@
|
||||||
import { Image, StyleSheet, Text, View } from 'react-native'
|
|
||||||
import React, { useContext } from 'react'
|
|
||||||
import { Marker } from 'react-native-maps'
|
|
||||||
import { MarkerContext } from '@/app/context/MakerContext'
|
|
||||||
|
|
||||||
const MarkerList = ({index, place}) => {
|
|
||||||
const {selectedMarker, setSelectedMarker} = useContext(MarkerContext);
|
|
||||||
|
|
||||||
return place && (
|
|
||||||
<Marker onPress={() => setSelectedMarker(index)}
|
|
||||||
coordinate={{
|
|
||||||
latitude: place.location?.latitude,
|
|
||||||
longitude: place.location?.longitude
|
|
||||||
}}>
|
|
||||||
<Image source={require('../../../assets/images/ev_images/charging.png')} style={{width: 50, height: 50}}/>
|
|
||||||
</Marker>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default MarkerList
|
|
||||||
|
|
||||||
const styles = StyleSheet.create({})
|
|
Before Width: | Height: | Size: 17 KiB |
Before Width: | Height: | Size: 8 KiB |
Before Width: | Height: | Size: 21 KiB |
Before Width: | Height: | Size: 9.1 KiB |
Before Width: | Height: | Size: 21 KiB |
Before Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 22 KiB |
Before Width: | Height: | Size: 5 KiB |
Before Width: | Height: | Size: 6.2 KiB |
Before Width: | Height: | Size: 14 KiB |
Before Width: | Height: | Size: 21 KiB |
Before Width: | Height: | Size: 46 KiB |
|
@ -1,6 +0,0 @@
|
||||||
module.exports = function (api) {
|
|
||||||
api.cache(true);
|
|
||||||
return {
|
|
||||||
presets: ['babel-preset-expo'],
|
|
||||||
};
|
|
||||||
};
|
|
|
@ -1,11 +0,0 @@
|
||||||
import React, { useEffect } from 'react';
|
|
||||||
import *as WebBrowser from "expo-web-browser";
|
|
||||||
|
|
||||||
export const useWarmUpBrowser = () => {
|
|
||||||
React.useEffect(() => {
|
|
||||||
void WebBrowser.warmUpAsync();
|
|
||||||
return() => {
|
|
||||||
void WebBrowser.coolDownAsync();
|
|
||||||
}
|
|
||||||
}, [])
|
|
||||||
};
|
|
19557
ev_station/package-lock.json
generated
|
@ -1,57 +0,0 @@
|
||||||
{
|
|
||||||
"name": "ev_station",
|
|
||||||
"main": "expo-router/entry",
|
|
||||||
"version": "1.0.0",
|
|
||||||
"scripts": {
|
|
||||||
"start": "expo start",
|
|
||||||
"reset-project": "node ./scripts/reset-project.js",
|
|
||||||
"android": "expo start --android",
|
|
||||||
"ios": "expo start --ios",
|
|
||||||
"web": "expo start --web",
|
|
||||||
"test": "jest --watchAll",
|
|
||||||
"lint": "expo lint"
|
|
||||||
},
|
|
||||||
"jest": {
|
|
||||||
"preset": "jest-expo"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"@clerk/clerk-expo": "^2.0.0",
|
|
||||||
"@expo/vector-icons": "^14.0.2",
|
|
||||||
"@react-navigation/native": "^6.1.18",
|
|
||||||
"axios": "^1.7.2",
|
|
||||||
"expo": "~51.0.22",
|
|
||||||
"expo-constants": "~16.0.2",
|
|
||||||
"expo-font": "~12.0.9",
|
|
||||||
"expo-linking": "~6.3.1",
|
|
||||||
"expo-location": "~17.0.1",
|
|
||||||
"expo-router": "~3.5.18",
|
|
||||||
"expo-secure-store": "^13.0.2",
|
|
||||||
"expo-splash-screen": "~0.27.5",
|
|
||||||
"expo-status-bar": "~1.12.1",
|
|
||||||
"expo-system-ui": "~3.0.7",
|
|
||||||
"expo-web-browser": "~13.0.3",
|
|
||||||
"firebase": "^10.12.4",
|
|
||||||
"react": "18.2.0",
|
|
||||||
"react-dom": "18.2.0",
|
|
||||||
"react-native": "0.74.3",
|
|
||||||
"react-native-gesture-handler": "~2.16.1",
|
|
||||||
"react-native-google-places-autocomplete": "^2.5.6",
|
|
||||||
"react-native-maps": "1.14.0",
|
|
||||||
"react-native-places-input": "^1.1.7",
|
|
||||||
"react-native-reanimated": "~3.10.1",
|
|
||||||
"react-native-safe-area-context": "4.10.5",
|
|
||||||
"react-native-screens": "3.31.1",
|
|
||||||
"react-native-web": "~0.19.10"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"@babel/core": "^7.20.0",
|
|
||||||
"@types/jest": "^29.5.12",
|
|
||||||
"@types/react": "~18.2.45",
|
|
||||||
"@types/react-test-renderer": "^18.0.7",
|
|
||||||
"jest": "^29.2.1",
|
|
||||||
"jest-expo": "~51.0.3",
|
|
||||||
"react-test-renderer": "18.2.0",
|
|
||||||
"typescript": "~5.3.3"
|
|
||||||
},
|
|
||||||
"private": true
|
|
||||||
}
|
|
|
@ -1,73 +0,0 @@
|
||||||
#!/usr/bin/env node
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This script is used to reset the project to a blank state.
|
|
||||||
* It moves the /app directory to /app-example and creates a new /app directory with an index.tsx and _layout.tsx file.
|
|
||||||
* You can remove the `reset-project` script from package.json and safely delete this file after running it.
|
|
||||||
*/
|
|
||||||
|
|
||||||
const fs = require('fs');
|
|
||||||
const path = require('path');
|
|
||||||
|
|
||||||
const root = process.cwd();
|
|
||||||
const oldDirPath = path.join(root, 'app');
|
|
||||||
const newDirPath = path.join(root, 'app-example');
|
|
||||||
const newAppDirPath = path.join(root, 'app');
|
|
||||||
|
|
||||||
const indexContent = `import { Text, View } from "react-native";
|
|
||||||
|
|
||||||
export default function Index() {
|
|
||||||
return (
|
|
||||||
<View
|
|
||||||
style={{
|
|
||||||
flex: 1,
|
|
||||||
justifyContent: "center",
|
|
||||||
alignItems: "center",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Text>Edit app/index.tsx to edit this screen.</Text>
|
|
||||||
</View>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
const layoutContent = `import { Stack } from "expo-router";
|
|
||||||
|
|
||||||
export default function RootLayout() {
|
|
||||||
return (
|
|
||||||
<Stack>
|
|
||||||
<Stack.Screen name="index" />
|
|
||||||
</Stack>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
fs.rename(oldDirPath, newDirPath, (error) => {
|
|
||||||
if (error) {
|
|
||||||
return console.error(`Error renaming directory: ${error}`);
|
|
||||||
}
|
|
||||||
console.log('/app moved to /app-example.');
|
|
||||||
|
|
||||||
fs.mkdir(newAppDirPath, { recursive: true }, (error) => {
|
|
||||||
if (error) {
|
|
||||||
return console.error(`Error creating new app directory: ${error}`);
|
|
||||||
}
|
|
||||||
console.log('New /app directory created.');
|
|
||||||
|
|
||||||
const indexPath = path.join(newAppDirPath, 'index.tsx');
|
|
||||||
fs.writeFile(indexPath, indexContent, (error) => {
|
|
||||||
if (error) {
|
|
||||||
return console.error(`Error creating index.tsx: ${error}`);
|
|
||||||
}
|
|
||||||
console.log('app/index.tsx created.');
|
|
||||||
|
|
||||||
const layoutPath = path.join(newAppDirPath, '_layout.tsx');
|
|
||||||
fs.writeFile(layoutPath, layoutContent, (error) => {
|
|
||||||
if (error) {
|
|
||||||
return console.error(`Error creating _layout.tsx: ${error}`);
|
|
||||||
}
|
|
||||||
console.log('app/_layout.tsx created.');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -1,17 +0,0 @@
|
||||||
{
|
|
||||||
"extends": "expo/tsconfig.base",
|
|
||||||
"compilerOptions": {
|
|
||||||
"strict": true,
|
|
||||||
"paths": {
|
|
||||||
"@/*": [
|
|
||||||
"./*"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"include": [
|
|
||||||
"**/*.ts",
|
|
||||||
"**/*.tsx",
|
|
||||||
".expo/types/**/*.ts",
|
|
||||||
"expo-env.d.ts"
|
|
||||||
, "app/index.js" ]
|
|
||||||
}
|
|
|
@ -1,9 +1,50 @@
|
||||||
# News application with React Native
|
# Welcome to your Expo app 👋
|
||||||
|
|
||||||
This project is a news mobile application that fetches data from [News API](https://newsapi.org/), where users will be able to share and read the latest news from different sources.
|
This is an [Expo](https://expo.dev) project created with [`create-expo-app`](https://www.npmjs.com/package/create-expo-app).
|
||||||
|
|
||||||
## To start the project
|
## Get started
|
||||||
* Download [Expo Go](https://expo.dev/go) on your device to launch the project.
|
|
||||||
* To start the project, run this command in your terminal `npx expo start --tunnel`
|
1. Install dependencies
|
||||||
* Scan the QR code that shows in your terminal.
|
|
||||||
* For more information about Tunneling, please read [Expo](https://docs.expo.dev/more/expo-cli/#tunneling).
|
```bash
|
||||||
|
npm install
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Start the app
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npx expo start
|
||||||
|
```
|
||||||
|
|
||||||
|
In the output, you'll find options to open the app in a
|
||||||
|
|
||||||
|
- [development build](https://docs.expo.dev/develop/development-builds/introduction/)
|
||||||
|
- [Android emulator](https://docs.expo.dev/workflow/android-studio-emulator/)
|
||||||
|
- [iOS simulator](https://docs.expo.dev/workflow/ios-simulator/)
|
||||||
|
- [Expo Go](https://expo.dev/go), a limited sandbox for trying out app development with Expo
|
||||||
|
|
||||||
|
You can start developing by editing the files inside the **app** directory. This project uses [file-based routing](https://docs.expo.dev/router/introduction).
|
||||||
|
|
||||||
|
## Get a fresh project
|
||||||
|
|
||||||
|
When you're ready, run:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm run reset-project
|
||||||
|
```
|
||||||
|
|
||||||
|
This command will move the starter code to the **app-example** directory and create a blank **app** directory where you can start developing.
|
||||||
|
|
||||||
|
## Learn more
|
||||||
|
|
||||||
|
To learn more about developing your project with Expo, look at the following resources:
|
||||||
|
|
||||||
|
- [Expo documentation](https://docs.expo.dev/): Learn fundamentals, or go into advanced topics with our [guides](https://docs.expo.dev/guides).
|
||||||
|
- [Learn Expo tutorial](https://docs.expo.dev/tutorial/introduction/): Follow a step-by-step tutorial where you'll create a project that runs on Android, iOS, and the web.
|
||||||
|
|
||||||
|
## Join the community
|
||||||
|
|
||||||
|
Join our community of developers creating universal apps.
|
||||||
|
|
||||||
|
- [Expo on GitHub](https://github.com/expo/expo): View our open source platform and contribute.
|
||||||
|
- [Discord community](https://chat.expo.dev): Chat with Expo users and ask questions.
|
||||||
|
|
|
@ -6,13 +6,14 @@ import HomeNavigator from './Navigation/HomeNavigator'
|
||||||
export default function Index() {
|
export default function Index() {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<NavigationContainer independent={true}>
|
|
||||||
<KeyboardAvoidingView>
|
<NavigationContainer independent={true}>
|
||||||
<View style={{height: '100%', width: '100%'}}>
|
<KeyboardAvoidingView>
|
||||||
<HomeNavigator/>
|
<View style={{height: '100%', width: '100%'}}>
|
||||||
</View>
|
<HomeNavigator/>
|
||||||
</KeyboardAvoidingView>
|
</View>
|
||||||
</NavigationContainer>
|
</KeyboardAvoidingView>
|
||||||
|
</NavigationContainer>
|
||||||
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|