diff --git a/4_Shop_App/App.js b/4_Shop_App/App.js index b47ca82..2bc2a60 100644 --- a/4_Shop_App/App.js +++ b/4_Shop_App/App.js @@ -1,15 +1,14 @@ -import React, { useState } from 'react'; -import { createStore, combineReducers, applyMiddleware } from 'redux'; -import { Provider } from 'react-redux'; import { AppLoading } from 'expo'; import * as Font from 'expo-font'; +import React, { useState } from 'react'; +import { Provider } from 'react-redux'; +import { applyMiddleware, combineReducers, createStore } from 'redux'; import ReduxThunk from 'redux-thunk'; - -import productsReducer from './store/reducers/products'; +import NavigationContainer from './navigation/NavigationContainer'; +import authReducer from './store/reducers/auth'; import cartReducer from './store/reducers/cart'; import ordersReducer from './store/reducers/orders'; -import authReducer from './store/reducers/auth'; -import ShopNavigator from './navigation/ShopNavigator'; +import productsReducer from './store/reducers/products'; const rootReducer = combineReducers({ products: productsReducer, @@ -43,7 +42,7 @@ export default function App() { return ( - + ); } diff --git a/4_Shop_App/README.md b/4_Shop_App/README.md index d641e2d..48ea7cb 100644 --- a/4_Shop_App/README.md +++ b/4_Shop_App/README.md @@ -22,6 +22,7 @@ - [When The App Launches](#whenapplaunches) - [Authentication Screen](#authscreen) - [Auth Config](#actionauth) +- [Local Storage - AsyncStorage](#localstorage)

Shop App

@@ -905,3 +906,69 @@ export default authReducer; ``` + +

Local Storage - AsyncStorage

+ +[Go Back to Summary](#summary) + +- In `store/actions/auth.js` + + - Import **AsyncStorage** from `react-native` + - `removeItem('key')` to remove key/value from local storage + - `setItem('key', 'value')` to add key/value pair in the local storage + - It has to be a string, so we have to JSON.stringify() + - `getItem('key')` to get an item from local storage + + ```JavaScript + import { AsyncStorage } from 'react-native'; + import { FIREBASE_KEY } from 'react-native-dotenv'; + export const AUTHENTICATE = 'AUTHENTICATE'; + export const LOGOUT = 'LOGOUT'; + let timer; + + export const authenticate = (userId, token, expiryTime) => { + return (dispatch) => { + dispatch(setLogoutTimer(expiryTime)); + dispatch({ type: AUTHENTICATE, userId, token }); + }; + }; + + export const signup = (email, password) => { + return async (dispatch) => {...}; + }; + + export const login = (email, password) => { + return async (dispatch) => {...}; + }; + + export const logout = () => { + clearLogoutTimer(); + AsyncStorage.removeItem('userData'); + return { type: LOGOUT }; + }; + + const clearLogoutTimer = () => { + if (timer) { + clearTimeout(timer); + } + }; + + const setLogoutTimer = (expirationTime) => { + return (dispatch) => { + timer = setTimeout(() => { + dispatch(logout()); + }, expirationTime); + }; + }; + + const saveDataToStorage = (token, userId, expirationDate) => { + AsyncStorage.setItem( + 'userData', + JSON.stringify({ + token, + userId, + expiryDate: expirationDate.toISOString(), + }), + ); + }; + ``` diff --git a/4_Shop_App/navigation/NavigationContainer.js b/4_Shop_App/navigation/NavigationContainer.js new file mode 100644 index 0000000..283fa77 --- /dev/null +++ b/4_Shop_App/navigation/NavigationContainer.js @@ -0,0 +1,19 @@ +import React, { useEffect, useRef } from 'react'; +import { NavigationActions } from 'react-navigation'; +import { useSelector } from 'react-redux'; +import ShopNavigator from './ShopNavigator'; + +function NavigationContainer(props) { + const navRef = useRef(); + const isAuth = useSelector((state) => !!state.auth.token); + + useEffect(() => { + if (!isAuth) { + navRef.current.dispatch(NavigationActions.navigate({ routeName: 'Auth' })); + } + }, [isAuth]); + + return ; +} + +export default NavigationContainer; diff --git a/4_Shop_App/navigation/ShopNavigator.js b/4_Shop_App/navigation/ShopNavigator.js index 8429059..573f999 100644 --- a/4_Shop_App/navigation/ShopNavigator.js +++ b/4_Shop_App/navigation/ShopNavigator.js @@ -1,19 +1,20 @@ +import { Ionicons } from '@expo/vector-icons'; import React from 'react'; -import { createStackNavigator } from 'react-navigation-stack'; +import { Button, Platform, SafeAreaView, StyleSheet, View } from 'react-native'; import { createAppContainer, createSwitchNavigator } from 'react-navigation'; -import { createDrawerNavigator } from 'react-navigation-drawer'; -import { Platform } from 'react-native'; -import { Ionicons } from '@expo/vector-icons'; - +import { createDrawerNavigator, DrawerNavigatorItems } from 'react-navigation-drawer'; +import { createStackNavigator } from 'react-navigation-stack'; +import { useDispatch } from 'react-redux'; import Colors from '../css/Colors'; - -import ProductsOverviewScreen from '../screens/shop/ProductsOverviewScreen'; -import ProductDetailsScreen from '../screens/shop/ProductDetailsScreen'; import CartScreen from '../screens/shop/CartScreen'; import OrdersScreen from '../screens/shop/OrdersScreen'; -import UserProductsScreen from '../screens/user/UserProductsScreen'; -import EditProductScreen from '../screens/user/EditProductScreen'; +import ProductDetailsScreen from '../screens/shop/ProductDetailsScreen'; +import ProductsOverviewScreen from '../screens/shop/ProductsOverviewScreen'; +import StartupScreen from '../screens/StartupScreen'; import AuthScreen from '../screens/user/AuthScreen'; +import EditProductScreen from '../screens/user/EditProductScreen'; +import UserProductsScreen from '../screens/user/UserProductsScreen'; +import * as authActions from '../store/actions/auth'; const defaultNavOptions = { headerStyle: { @@ -104,12 +105,38 @@ const ShopNavigator = createDrawerNavigator( contentOptions: { activeTintColor: Colors.primary, }, + contentComponent: (props) => { + const dispatch = useDispatch(); + return ( + + + +