diff --git a/App.tsx b/App.tsx index c5d13ffcd18ab584fb38aea965672aa0e8b68d56..d2dd423df0dd96d322e4282c5bc0d5dcdff2ef44 100644 --- a/App.tsx +++ b/App.tsx @@ -1,71 +1,25 @@ import React, {useState} from 'react'; import Lottie from 'lottie-react-native'; -import Home from './src/components/Home'; -import Login from './src/components/Login'; -import Signup from './src/components/Signup'; -import Cart from './src/components/Cart'; -import Icon from 'react-native-vector-icons/FontAwesome'; -import ProductDetail from './src/components/ProductDetail'; -import MedicineList from './src/components/MedicineList'; -import {NavigationContainer} from '@react-navigation/native'; -import {createNativeStackNavigator} from '@react-navigation/native-stack'; import CartProvider from './src/store/CartContext'; -import {Colors} from './src/constants/Constants'; - -const Stack = createNativeStackNavigator(); +import RootNavigation from './src/navigation'; +import AuthContextProvider from './src/store/AuthContext'; function App() { const [isLoading, setLoading] = useState(true); setTimeout(() => { setLoading(false); - }, 6000); + }, 3000); if (isLoading) { - return ( - <Lottie - source={require('./src/assets/splash_screen.json')} - autoPlay - loop - /> - ); + const img = require('./src/assets/splash_screen.json'); + return <Lottie source={img} autoPlay loop />; } return ( <CartProvider> - <NavigationContainer> - <Stack.Navigator> - <Stack.Screen name="Home" component={Home} options={{title: ''}} /> - <Stack.Screen name="Signup" component={Signup} /> - <Stack.Screen name="Login" component={Login} /> - <Stack.Screen - name="MedicineList" - component={MedicineList} - options={{ - title: 'Product List', - headerRight: () => ( - <Icon - name="shopping-cart" - size={30} - color={Colors.primary500}></Icon> - ), - }} - /> - <Stack.Screen - name="ProductDetail" - component={ProductDetail} - options={{ - title: 'Product Detail', - headerRight: () => ( - <Icon - name="shopping-cart" - size={30} - color={Colors.primary500}></Icon> - ), - }} - /> - <Stack.Screen name="Cart" component={Cart} /> - </Stack.Navigator> - </NavigationContainer> + <AuthContextProvider> + <RootNavigation /> + </AuthContextProvider> </CartProvider> ); } diff --git a/ios/testPrj/Info.plist b/ios/testPrj/Info.plist index fd402ec71b01d3c5a9690d60f40424a312b75814..964de6d00220ecc27ee2ae04bdbae5c125513b94 100644 --- a/ios/testPrj/Info.plist +++ b/ios/testPrj/Info.plist @@ -20,6 +20,17 @@ <string>$(MARKETING_VERSION)</string> <key>CFBundleSignature</key> <string>????</string> + <key>CFBundleURLTypes</key> + <array> + <dict> + <key>CFBundleTypeRole</key> + <string>Editor</string> + <key>CFBundleURLSchemes</key> + <array> + <string>com.googleusercontent.apps.84917563501-sa7pcjfh516f7ljlb6eln2tkpk4ko98f</string> + </array> + </dict> + </array> <key>CFBundleVersion</key> <string>$(CURRENT_PROJECT_VERSION)</string> <key>LSRequiresIPhoneOS</key> @@ -37,20 +48,6 @@ </dict> <key>NSLocationWhenInUseUsageDescription</key> <string></string> - <key>UILaunchStoryboardName</key> - <string>LaunchScreen</string> - <key>UIRequiredDeviceCapabilities</key> - <array> - <string>armv7</string> - </array> - <key>UISupportedInterfaceOrientations</key> - <array> - <string>UIInterfaceOrientationPortrait</string> - <string>UIInterfaceOrientationLandscapeLeft</string> - <string>UIInterfaceOrientationLandscapeRight</string> - </array> - <key>UIViewControllerBasedStatusBarAppearance</key> - <false/> <key>UIAppFonts</key> <array> <string>AntDesign.ttf</string> @@ -70,5 +67,19 @@ <string>Octicons.ttf</string> <string>Zocial.ttf</string> </array> + <key>UILaunchStoryboardName</key> + <string>LaunchScreen</string> + <key>UIRequiredDeviceCapabilities</key> + <array> + <string>armv7</string> + </array> + <key>UISupportedInterfaceOrientations</key> + <array> + <string>UIInterfaceOrientationPortrait</string> + <string>UIInterfaceOrientationLandscapeLeft</string> + <string>UIInterfaceOrientationLandscapeRight</string> + </array> + <key>UIViewControllerBasedStatusBarAppearance</key> + <false/> </dict> </plist> diff --git a/package.json b/package.json index d63bbb210bd21e7e8c2602f7d144db8b24b5063d..8dd40576f68eaf8898f9365f78f6178090e97b06 100644 --- a/package.json +++ b/package.json @@ -10,12 +10,15 @@ "test": "jest" }, "dependencies": { - "@react-native-firebase/app": "^17.2.0", + "@react-native-firebase/app": "^17.3.0", + "@react-native-google-signin/google-signin": "^9.0.2", "@react-navigation/native": "^6.1.3", "@react-navigation/native-stack": "^6.9.9", "lottie-react-native": "^5.1.5", "react": "18.2.0", + "react-devtools": "^4.27.2", "react-native": "0.71.1", + "react-native-axios": "^0.17.1", "react-native-safe-area-context": "^4.5.0", "react-native-screens": "^3.19.0", "react-native-vector-icons": "^9.2.0", diff --git a/src/components/Background.js b/src/components/Background.js index 6815a408a3d31484728cbe7be30ca5900d4377e5..abfd3814d745e7cff2beb1173375ac8183d5b332 100644 --- a/src/components/Background.js +++ b/src/components/Background.js @@ -1,10 +1,8 @@ import React from 'react'; -import {View, ImageBackground} from 'react-native'; +import {View} from 'react-native'; -const Background = ({ children }) => { - return ( - <View style={{ position: "absolute" }}>{children}</View> - ); -} +const Background = ({children}) => { + return <View style={{position: 'absolute', padding: 16}}>{children}</View>; +}; -export default Background; \ No newline at end of file +export default Background; diff --git a/src/components/Field.js b/src/components/Field.js deleted file mode 100644 index 3685e22c56e6abe611202289f92dfa5f9e975c89..0000000000000000000000000000000000000000 --- a/src/components/Field.js +++ /dev/null @@ -1,14 +0,0 @@ -import React from 'react'; -import {TextInput} from 'react-native'; -import {Colors} from '../constants/Constants'; - -const Field = props => { - return ( - <TextInput - {...props} - style={{borderRadius: 100, color: Colors.darkGreen, paddingHorizontal: 10, width: '78%', backgroundColor: 'rgb(220,220, 220)', marginVertical: 10}} - placeholderTextColor={Colors.darkGreen}></TextInput> - ); -}; - -export default Field; \ No newline at end of file diff --git a/src/components/Login.js b/src/components/Login.js deleted file mode 100644 index 02d1f6f5d433655c8a3ff80f3f2e748f6b6e99b7..0000000000000000000000000000000000000000 --- a/src/components/Login.js +++ /dev/null @@ -1,109 +0,0 @@ -import React from 'react'; -import {View, Text, StyleSheet, TouchableOpacity} from 'react-native'; -import Icon from 'react-native-vector-icons/FontAwesome'; -import Background from './Background'; -import Btn from './Button'; -import {Colors} from '../constants/Constants'; -import Field from './Field'; - -const Login = props => { - return ( - <Background> - <View style={{alignItems: 'center', width: '100%'}}> - <Text - style={{ - color: Colors.green, - fontSize: 32, - fontWeight: 'bold', - marginVertical: 20, - }}> - Sign In - </Text> - <View - style={{ - height: 400, - width: 360, - paddingTop: 100, - alignItems: 'center', - }}> - <Field - placeholder="Email / Username" - keyboardType={'email-address'} - /> - <Field placeholder="Password" secureTextEntry={true} /> - <View - style={{ - alignItems: 'flex-end', - width: '78%', - paddingRight: 16, - marginBottom: 200, - }}> - <Text style={{color: Colors.darkGreen, fontWeight: 'bold', fontSize: 16}}> - Forgot Password ? - </Text> - </View> - <Btn - textColor="white" - bgColor={Colors.darkGreen} - btnLabel="Login" - Press={() => alert('Logged In')} - /> - <View - style={{ - display: 'flex', - flexDirection: 'row', - justifyContent: 'center', - }}> - <Text style={{fontSize: 16, fontWeight: 'bold'}}> - Don't have an account ?{' '} - </Text> - <TouchableOpacity - onPress={() => props.navigation.navigate('Signup')}> - <Text - style={{color: Colors.darkGreen, fontWeight: 'bold', fontSize: 16}}> - Signup - </Text> - </TouchableOpacity> - </View> - <View style={styles.container}> - <TouchableOpacity style={styles.button}> - <Icon.Button name="facebook" style={styles.facebook}> - Login with Facebook - </Icon.Button> - </TouchableOpacity> - <TouchableOpacity style={styles.button}> - <Icon.Button name="google" style={styles.google}> - Login with Google - </Icon.Button> - </TouchableOpacity> - </View> - </View> - </View> - </Background> - ); -}; - -const styles = StyleSheet.create({ - container: { - flexDirection: 'row', - justifyContent: 'space-between', - paddingHorizontal: 10, - }, - button: { - paddingVertical: 10, - paddingHorizontal: 10, - borderRadius: 5, - }, - buttonText: { - color: 'white', - fontWeight: 'bold', - }, - facebook: { - backgroundColor: '#3b5998', - }, - google: { - backgroundColor: '#ff3333', - }, -}); - -export default Login; diff --git a/src/components/Signup.js b/src/components/Signup.js deleted file mode 100644 index 7632d7cafebee5028d16eb7def83dac67af33586..0000000000000000000000000000000000000000 --- a/src/components/Signup.js +++ /dev/null @@ -1,111 +0,0 @@ -import React from 'react'; -import {View, Text, StyleSheet, TouchableOpacity} from 'react-native'; -import Icon from 'react-native-vector-icons/FontAwesome'; -import Background from './Background'; -import Btn from './Button'; -import {Colors} from '../constants/Constants'; -import Field from './Field'; - -const Signup = props => { - return ( - <Background> - <View style={{alignItems: 'center', width: '100%'}}> - <Text - style={{ - color: Colors.green, - fontSize: 32, - fontWeight: 'bold', - marginTop: 10, - }}> - Sign Up - </Text> - <View - style={{ - width: 360, - alignItems: 'center', - }}> - <Field placeholder="First Name" /> - <Field placeholder="Last Name" /> - <Field - placeholder="Email / Username" - keyboardType={'email-address'} - /> - <Field placeholder="Contact Number" keyboardType={'default'} /> - <Field placeholder="Password" secureTextEntry={true} /> - <Field placeholder="Confirm Password" secureTextEntry={true} /> - <View - style={{ - display: 'flex', - flexDirection: 'row', - width: '78%', - paddingRight: 12, - }}></View> - <Btn - textColor="white" - bgColor={Colors.darkGreen} - btnLabel="Signup" - Press={() => { - alert('Accoutn created'); - props.navigation.navigate('Login'); - }} - /> - <View - style={{ - display: 'flex', - flexDirection: 'row', - justifyContent: 'center', - }}> - <Text style={{fontSize: 16, fontWeight: 'bold'}}> - Already have an account ?{' '} - </Text> - <TouchableOpacity - onPress={() => props.navigation.navigate('Login')}> - <Text - style={{color: Colors.darkGreen, fontWeight: 'bold', fontSize: 16}}> - Login - </Text> - </TouchableOpacity> - </View> - <View style={styles.container}> - <TouchableOpacity style={styles.button}> - <Icon.Button name="facebook" style={styles.facebook}> - Login with Facebook - </Icon.Button> - </TouchableOpacity> - <TouchableOpacity style={styles.button}> - <Icon.Button name="google" style={styles.google}> - Login with Google - </Icon.Button> - </TouchableOpacity> - </View> - </View> - </View> - </Background> - ); -}; - - -const styles = StyleSheet.create({ - container: { - flexDirection: 'row', - justifyContent: 'space-between', - paddingHorizontal: 10, - }, - button: { - paddingVertical: 10, - paddingHorizontal: 10, - borderRadius: 5, - }, - buttonText: { - color: 'white', - fontWeight: 'bold', - }, - facebook: { - backgroundColor: '#3b5998', - }, - google: { - backgroundColor: '#ff3333', - }, -}); - -export default Signup; diff --git a/src/components/Cart.js b/src/components/screens/Cart.js similarity index 93% rename from src/components/Cart.js rename to src/components/screens/Cart.js index 2c90fcea15398124977abc3ac24900dbba3c1427..6ed86cc65a79321d829fd98a6d6fd833e35623dc 100644 --- a/src/components/Cart.js +++ b/src/components/screens/Cart.js @@ -1,6 +1,7 @@ import React, {useContext, useState} from 'react'; import {View, Text, StyleSheet, Button, Image} from 'react-native'; -import {CartContext} from '../store/CartContext'; +import {CartContext} from '../../store/CartContext'; + const CartItem = ({item}) => { const {removeFromCart, updateQuantity} = useContext(CartContext); @@ -56,14 +57,13 @@ const Cart = () => { const styles = StyleSheet.create({ cartContiner: { - flex: 1, + // flex: 1, }, itemContainer: { - flex: 0.5, + // flex: 0.5, padding: 10, - flexDirection: 'row', - justifyContent: 'flex-start', - height: '10%', + // flexDirection: 'row', + // justifyContent: 'flex-start', }, imageContainer: { flex: 1, diff --git a/src/components/Home.js b/src/components/screens/Home.js similarity index 83% rename from src/components/Home.js rename to src/components/screens/Home.js index 57c862e48bc562ea273871ea61c68176962cf6c9..5a054fbe2d759229c2f8fcad47e75a2999c1f4d6 100644 --- a/src/components/Home.js +++ b/src/components/screens/Home.js @@ -1,8 +1,8 @@ import React from 'react'; import {View, StyleSheet} from 'react-native'; -import Background from './Background'; -import Btn from './Button'; -import {Colors} from '../constants/Constants'; +import Background from '../Background'; +import Btn from '../Button'; +import {Colors} from '../../constants/Constants'; const Home = props => { return ( @@ -20,12 +20,12 @@ const Home = props => { btnLabel="Signup" Press={() => props.navigation.navigate('Signup')} /> - <Btn + {/* <Btn bgColor="white" textColor="blue" btnLabel="Products" Press={() => props.navigation.navigate('MedicineList')} - /> + /> */} </View> </Background> ); diff --git a/src/components/screens/Login.js b/src/components/screens/Login.js new file mode 100644 index 0000000000000000000000000000000000000000..deacab211f7dd7d08ad1ef0df24d3ed1c147e126 --- /dev/null +++ b/src/components/screens/Login.js @@ -0,0 +1,162 @@ +import React, {useState, useEffect, useContext} from 'react'; +import {View, Text, StyleSheet, TouchableOpacity, Alert} from 'react-native'; +import Icon from 'react-native-vector-icons/FontAwesome'; +import Background from '../Background'; +import Btn from '../Button'; +import {Colors} from '../../constants/Constants'; +import Field from '../ui/Field'; +import {useNavigation} from '@react-navigation/native'; +import {googleLogin, login} from '../../util/auth'; +import {AuthContext} from '../../store/AuthContext'; +// import Button from '../ui/Button'; +import {GoogleSignin} from '@react-native-google-signin/google-signin'; + +const Login = () => { + const navigation = useNavigation(); + const authCtx = useContext(AuthContext); + const [email, setEmail] = useState(''); + const [password, setPassword] = useState(''); + useEffect(() => { + GoogleSignin.configure(); + }, []); + const loginHandler = async () => { + try { + const res = await login(email, password); + authCtx.authenticate(res.data.idToken); + } catch (error) { + console.log(error); + Alert.alert('Signup Failed', 'Something went wrong!'); + } + // navigation.navigate('MedicineList'); + // Alert.alert('Logged In', `you are login as ${email} with ${password}`); + }; + const googleLoginHandler = async () => { + try { + const res = await googleLogin(); + console.log(res.idToken); + authCtx.authenticate(res.idToken); + } catch (error) { + console.log(error); + Alert.alert('Signup Failed', 'Something went wrong!'); + } + // navigation.navigate('MedicineList'); + }; + const facebookLoginHandler = () => { + console.log('i am in facebookLoginHandler'); + const result = googleLogin(); + console.log(result); + }; + + return ( + <Background> + <View style={styles.mainContainer}> + <View style={styles.formContainer}> + <Field + placeholder="Email / Username" + value={email} + onChangeText={setEmail} + keyboardType={'email-address'} + /> + <Field + placeholder="Password" + value={password} + onChangeText={setPassword} + secureTextEntry={true} + /> + <View style={styles.forgotContiner}> + <Text style={styles.forgotText}>Forgot Password ?</Text> + </View> + <Btn + textColor="white" + bgColor={Colors.darkGreen} + btnLabel="Login" + Press={loginHandler} + /> + <View style={styles.noAccountContiner}> + <Text style={styles.noAccText}>Don't have an account ?</Text> + <TouchableOpacity onPress={() => navigation.navigate('Signup')}> + <Text style={styles.sigupText}>Signup</Text> + </TouchableOpacity> + </View> + <View style={styles.socialLoginContainer}> + <TouchableOpacity style={styles.button}> + <Icon.Button + name="facebook" + style={styles.facebook} + // onPress={() => { + // // onFacebookButtonPress().then(() => + // console.log('Signed in with Facebook!') + // // ) + // } + > + Login with Facebook + </Icon.Button> + </TouchableOpacity> + <TouchableOpacity style={styles.button}> + <Icon.Button + name="google" + style={styles.google} + onPress={googleLoginHandler}> + Login with Google + </Icon.Button> + </TouchableOpacity> + </View> + </View> + </View> + </Background> + ); +}; + +const styles = StyleSheet.create({ + mainContainer: {alignItems: 'center', width: '100%'}, + formContainer: { + height: 400, + width: 360, + paddingTop: 100, + alignItems: 'center', + }, + forgotContiner: { + alignItems: 'flex-end', + width: '78%', + paddingRight: 16, + marginBottom: 200, + }, + forgotText: { + color: Colors.darkGreen, + fontWeight: 'bold', + fontSize: 16, + }, + socialLoginContainer: { + flexDirection: 'row', + justifyContent: 'space-between', + paddingHorizontal: 10, + }, + button: { + paddingVertical: 10, + paddingHorizontal: 10, + borderRadius: 5, + }, + sigupText: { + color: Colors.darkGreen, + fontWeight: 'bold', + fontSize: 16, + }, + buttonText: { + color: 'white', + fontWeight: 'bold', + }, + noAccountContiner: { + display: 'flex', + flexDirection: 'row', + justifyContent: 'center', + }, + noAccText: {fontSize: 16, fontWeight: 'bold'}, + facebook: { + backgroundColor: '#3b5998', + }, + google: { + backgroundColor: '#ff3333', + }, +}); + +export default Login; diff --git a/src/components/MedicineList.js b/src/components/screens/MedicineList.js similarity index 80% rename from src/components/MedicineList.js rename to src/components/screens/MedicineList.js index 87ac24e3de43abd48c326f781a1eae5ec4e247c4..c6af6ecf4691b27e66a112fd92d229247204c46c 100644 --- a/src/components/MedicineList.js +++ b/src/components/screens/MedicineList.js @@ -15,37 +15,37 @@ const items = [ id: 1, name: 'Panadol', price: 18.0, - image: require('../assets/images/products/panadol.png'), + image: require('../../assets/images/products/panadol.png'), }, { id: 2, name: 'Amoxil 125mg Syrup', price: 128.0, - image: require('../assets/images/products/amoxil-syrup-125mg.jpg'), + image: require('../../assets/images/products/amoxil-syrup-125mg.jpg'), }, { id: 3, name: 'Arinac Forte', price: 50.0, - image: require('../assets/images/products/arinac-forte.jpg'), + image: require('../../assets/images/products/arinac-forte.jpg'), }, { id: 4, name: 'Telfast 120mg', price: 75.0, - image: require('../assets/images/products/telfast-120mg.jpg'), + image: require('../../assets/images/products/telfast-120mg.jpg'), }, { id: 5, name: 'Risek 40mg Tablet', price: 120.0, - image: require('../assets/images/products/risek-40mg.jpg'), + image: require('../../assets/images/products/risek-40mg.jpg'), }, { id: 6, name: 'Coferb Cough Syrup', price: 90.0, - image: require('../assets/images/products/coferb-syp.jpg'), + image: require('../../assets/images/products/coferb-syp.jpg'), }, ]; diff --git a/src/components/ProductDetail.js b/src/components/screens/ProductDetail.js similarity index 95% rename from src/components/ProductDetail.js rename to src/components/screens/ProductDetail.js index 663b4e12a6aaea4fd0e8431ea590b61448b700a1..d87b0ebcdb89336da9f478c169c2045e872233dd 100644 --- a/src/components/ProductDetail.js +++ b/src/components/screens/ProductDetail.js @@ -1,8 +1,8 @@ import React, {useContext, useState} from 'react'; import {View, Text, Image, Button, StyleSheet} from 'react-native'; import {useNavigation} from '@react-navigation/native'; -import {CartContext} from '../store/CartContext'; -import FlatButton from './ui/FlatButton'; +import {CartContext} from '../../store/CartContext'; +import FlatButton from '../ui/FlatButton'; const ProductDetail = porps => { const item = porps.route.params.item; @@ -18,10 +18,9 @@ const ProductDetail = porps => { }; const handleAddToCart = () => { addToCart({...item, quantity}); - navigation.navigate('ProductDetail'); + navigation.navigate('MedicineList'); }; - const incrementQuantity = () => { setQuantity(prevQuantity => prevQuantity + 1); }; diff --git a/src/components/screens/Signup.js b/src/components/screens/Signup.js new file mode 100644 index 0000000000000000000000000000000000000000..d665420ac5de5291f79c6c87a3ecd344a77ccdfe --- /dev/null +++ b/src/components/screens/Signup.js @@ -0,0 +1,179 @@ +import React, {useState, useContext} from 'react'; +import {View, Text, StyleSheet, TouchableOpacity, Alert} from 'react-native'; +import Icon from 'react-native-vector-icons/FontAwesome'; +import Background from '../Background'; +import Btn from '../Button'; +import {Colors} from '../../constants/Constants'; +import Field from '../ui/Field'; +import {useNavigation} from '@react-navigation/native'; +import {AuthContext} from '../../store/AuthContext'; +import {signup} from '../../util/auth'; + +const Signup = () => { + const navigation = useNavigation(); + const [firstName, setFirstName] = useState(''); + const [lastName, setLastName] = useState(''); + const [email, setEmail] = useState(''); + const [confirmEmail, setConfirmEmail] = useState(''); + const [password, setPassword] = useState(''); + const [confirmPassword, setConfirmPassword] = useState(''); + const [contact, setContact] = useState(''); + const authCtx = useContext(AuthContext); + + const submitHandler = async () => { + const emailIsValid = email.includes('@'); + const passwordIsValid = password.length > 6; + const emailsAreEqual = email === confirmEmail; + const passwordsAreEqual = password === confirmPassword; + + if ( + !emailIsValid || + !passwordIsValid || + !emailsAreEqual || + !passwordsAreEqual + ) { + Alert.alert('Invalid input', 'Please check your entered credentials.'); + return; + } else { + try { + const res = await signup(email, password); + authCtx.authenticate(res.data.idToken); + } catch (error) { + console.log(error); + Alert.alert('Signup Failed', 'Something went wrong!'); + } + navigation.navigate('MedicineList'); + } + }; + + return ( + <Background> + <View style={styles.mainContiner}> + <Text style={styles.signupText}>Sign Up</Text> + <View style={styles.formContiner}> + <Field + placeholder="First Name" + value={firstName} + onChangeText={setFirstName} + /> + <Field + placeholder="Last Name" + value={lastName} + onChangeText={setLastName} + /> + <Field + placeholder="Email / Username" + keyboardType={'email-address'} + value={email} + onChangeText={setEmail} + /> + <Field + placeholder="Confirm Email" + keyboardType={'email-address'} + value={confirmEmail} + onChangeText={setConfirmEmail} + /> + <Field + placeholder="Password" + secureTextEntry={true} + value={password} + onChangeText={setPassword} + /> + <Field + placeholder="Confirm Password" + secureTextEntry={true} + value={confirmPassword} + onChangeText={setConfirmPassword} + /> + <Field + placeholder="Contact Number" + keyboardType={'default'} + value={contact} + onChangeText={setContact} + /> + <View + style={{ + display: 'flex', + flexDirection: 'row', + width: '78%', + paddingRight: 12, + }}></View> + <Btn + textColor="white" + bgColor={Colors.darkGreen} + btnLabel="Signup" + Press={submitHandler} + /> + <View + style={{ + display: 'flex', + flexDirection: 'row', + justifyContent: 'center', + }}> + <Text style={{fontSize: 16, fontWeight: 'bold'}}> + Already have an account ?{' '} + </Text> + <TouchableOpacity onPress={() => navigation.navigate('Login')}> + <Text + style={{ + color: Colors.darkGreen, + fontWeight: 'bold', + fontSize: 16, + }}> + Login + </Text> + </TouchableOpacity> + </View> + <View style={styles.socialContainer}> + <TouchableOpacity style={styles.button}> + <Icon.Button name="facebook" style={styles.facebook}> + Login with Facebook + </Icon.Button> + </TouchableOpacity> + <TouchableOpacity style={styles.button}> + <Icon.Button name="google" style={styles.google}> + Login with Google + </Icon.Button> + </TouchableOpacity> + </View> + </View> + </View> + </Background> + ); +}; + +const styles = StyleSheet.create({ + mainContiner: {alignItems: 'center', width: '100%', padding: 10}, + signupText: { + color: Colors.green, + fontSize: 32, + fontWeight: 'bold', + marginTop: 10, + }, + formContiner: { + width: 360, + alignItems: 'center', + }, + socialContainer: { + flexDirection: 'row', + justifyContent: 'space-between', + paddingHorizontal: 10, + }, + button: { + paddingVertical: 10, + paddingHorizontal: 10, + borderRadius: 5, + }, + buttonText: { + color: 'white', + fontWeight: 'bold', + }, + facebook: { + backgroundColor: '#3b5998', + }, + google: { + backgroundColor: '#ff3333', + }, +}); + +export default Signup; diff --git a/src/components/ui/Field.js b/src/components/ui/Field.js new file mode 100644 index 0000000000000000000000000000000000000000..b9041137a0406f27841bbcada9c5291174f58bbc --- /dev/null +++ b/src/components/ui/Field.js @@ -0,0 +1,27 @@ +import React from 'react'; +import {StyleSheet, TextInput} from 'react-native'; +import {Colors} from '../../constants/Constants'; + +const Field = props => { + return ( + <TextInput + {...props} + style={styles.textInput} + placeholderTextColor={Colors.darkGreen} + /> + ); +}; + +const styles = StyleSheet.create({ + textInput: { + borderRadius: 100, + color: Colors.darkGreen, + paddingHorizontal: 10, + height: 40, + width: '78%', + backgroundColor: 'rgb(220,220, 220)', + marginVertical: 10, + }, +}); + +export default Field; diff --git a/src/constants/APIs.js b/src/constants/APIs.js new file mode 100644 index 0000000000000000000000000000000000000000..c6a71e80cf14fa6e645978d5e578e9fb01d72374 --- /dev/null +++ b/src/constants/APIs.js @@ -0,0 +1,2 @@ +export const API_KEY = 'AIzaSyCfHdM8i97bYT4YQgC52sUWmkef2uZsxWA'; +export const FB_APP_ID = '921156519073351'; \ No newline at end of file diff --git a/src/navigation/AuthStack.js b/src/navigation/AuthStack.js new file mode 100644 index 0000000000000000000000000000000000000000..86f22ba32dd98cfef6c7e246a974da98311f33d5 --- /dev/null +++ b/src/navigation/AuthStack.js @@ -0,0 +1,56 @@ +import React, {useContext} from 'react'; +import {NavigationContainer} from '@react-navigation/native'; +import {createNativeStackNavigator} from '@react-navigation/native-stack'; +import Cart from '../components/screens/Cart'; +import MedicineList from '../components/screens/MedicineList'; +import ProductDetail from '../components/screens/ProductDetail'; +import Icon from 'react-native-vector-icons/FontAwesome'; +import {Colors} from '../constants/Constants'; +import {AuthContext} from '../store/AuthContext'; + +const Stack = createNativeStackNavigator(); + +export default function AuthStack() { + const authCtx = useContext(AuthContext); + return ( + <NavigationContainer> + <Stack.Navigator + screenOptions={{ + headerShown: true, + tabBarStyle: {backgroundColor: '#0e1529'}, + }} + sceneContainerStyle={{backgroundColor: '#0e1529'}}> + <Stack.Screen + name="MedicineList" + component={MedicineList} + options={{ + title: 'Product List', + headerRight: () => { + return ( + <Icon + onPress={authCtx.logout} + name="sign-out" + size={30} + color={Colors.primary500}></Icon> + ); + }, + }} + /> + <Stack.Screen + name="ProductDetail" + component={ProductDetail} + options={{ + title: 'Product Detail', + headerRight: () => ( + <Icon + name="shopping-cart" + size={30} + color={Colors.primary500}></Icon> + ), + }} + /> + <Stack.Screen name="Cart" component={Cart} /> + </Stack.Navigator> + </NavigationContainer> + ); +} diff --git a/src/navigation/UnauthStack.js b/src/navigation/UnauthStack.js new file mode 100644 index 0000000000000000000000000000000000000000..1f1b8cc983c6cb67a98d5729b1488d002e24cc13 --- /dev/null +++ b/src/navigation/UnauthStack.js @@ -0,0 +1,27 @@ +import React from 'react'; +import {NavigationContainer} from '@react-navigation/native'; +import {createNativeStackNavigator} from '@react-navigation/native-stack'; + +import Home from '../components/screens/Home'; +import Signup from '../components/screens/Signup'; +import Login from '../components/screens/Login'; + +const Stack = createNativeStackNavigator(); + +export default function UnauthStack() { + return ( + <NavigationContainer> + <Stack.Navigator + screenOptions={{ + cardStyle: { + backgroundColor: '#0e1529', + }, + headerShown: false, + }}> + <Stack.Screen name="Home" component={Home} /> + <Stack.Screen name="Signup" component={Signup} /> + <Stack.Screen name="Login" component={Login} /> + </Stack.Navigator> + </NavigationContainer> + ); +} diff --git a/src/navigation/index.js b/src/navigation/index.js new file mode 100644 index 0000000000000000000000000000000000000000..83b0f646ad7a821b3fd4af846504ba31258405ad --- /dev/null +++ b/src/navigation/index.js @@ -0,0 +1,10 @@ +import React, {useContext} from 'react'; +import AuthStack from './AuthStack'; +import UnauthStack from './UnauthStack'; +import {AuthContext} from '../store/AuthContext'; + +export default function RootNavigation() { + const authCtx = useContext(AuthContext); + return authCtx.isAuthenticated == false ? <UnauthStack /> : <AuthStack />; + // return user ? <UserStack /> : <AuthStack />; +} diff --git a/src/store/AuthContext.js b/src/store/AuthContext.js new file mode 100644 index 0000000000000000000000000000000000000000..0a6ef53b19ea9e6aab42ad44b6bb2c04e3b0aa5f --- /dev/null +++ b/src/store/AuthContext.js @@ -0,0 +1,27 @@ +import {createContext, useState} from 'react'; + +export const AuthContext = createContext({ + token: '', + isAuthenticated: false, + authenticate: token => {}, + logout: () => {}, +}); + +function AuthContextProvider({children}) { + const [authToken, setAuthToken] = useState(null); + + const value = { + token: authToken, + isAuthenticated: !!authToken, + authenticate: token => { + setAuthToken(token); + }, + logout: () => { + setAuthToken(null); + }, + }; + + return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>; +} + +export default AuthContextProvider; diff --git a/src/util/auth.js b/src/util/auth.js new file mode 100644 index 0000000000000000000000000000000000000000..7daa8439f2224e740b49039c7a3314d008a8ca36 --- /dev/null +++ b/src/util/auth.js @@ -0,0 +1,76 @@ +import axios from 'react-native-axios'; +import { + GoogleSignin, + statusCodes, +} from '@react-native-google-signin/google-signin'; +// import auth from '@react-native-firebase/auth'; +// import {LoginManager, AccessToken} from 'react-native-fbsdk-next'; + +// import axios from 'axios'; +import {API_KEY} from '../constants/APIs'; + +export const signup = (email, password) => { + const url = `https://identitytoolkit.googleapis.com/v1/accounts:signUp?key=${API_KEY}`; + return axios.post(url, { + email, + password, + returnSecureToken: true, + }); +}; + +export const login = (email, password) => { + const url = `https://identitytoolkit.googleapis.com/v1/accounts:signInWithPassword?key=${API_KEY}`; + return axios.post(url, { + email, + password, + returnSecureToken: true, + }); +}; + +export const googleLogin = async () => { + try { + GoogleSignin.signOut(); + await GoogleSignin.hasPlayServices(); + const userInfo = await GoogleSignin.signIn(); + // this.setState({userInfo}); + // console.log(userInfo); + return userInfo; + } catch (error) { + if (error.code === statusCodes.SIGN_IN_CANCELLED) { + // user cancelled the login flow + } else if (error.code === statusCodes.IN_PROGRESS) { + // operation (e.g. sign in) is in progress already + } else if (error.code === statusCodes.PLAY_SERVICES_NOT_AVAILABLE) { + // play services not available or outdated + } else { + // some other error happened + } + } +}; + +// export const onFacebookButtonPress = async () => { +// // // Attempt login with permissions +// // const result = await LoginManager.logInWithPermissions([ +// // 'public_profile', +// // 'email', +// // ]); + +// // if (result.isCancelled) { +// // throw 'User cancelled the login process'; +// // } + +// // // Once signed in, get the users AccesToken +// // const data = await AccessToken.getCurrentAccessToken(); + +// // if (!data) { +// // throw 'Something went wrong obtaining access token'; +// // } + +// // // Create a Firebase credential with the AccessToken +// // const facebookCredential = auth.FacebookAuthProvider.credential( +// // data.accessToken, +// // ); + +// // // Sign-in the user with the credential +// // return auth().signInWithCredential(facebookCredential); +// };