소스 검색

Initial

new-app
Lazar Kostic 3 년 전
부모
커밋
4927f99923

+ 1
- 0
.gitignore 파일 보기

@@ -8,6 +8,7 @@ npm-debug.*
*.mobileprovision
*.orig.*
web-build/
ios/

# macOS
.DS_Store

+ 22
- 47
App.js 파일 보기

@@ -1,63 +1,38 @@
import 'react-native-gesture-handler';
import React from 'react';
import { StyleSheet, Text, View } from 'react-native';
import { NavigationContainer } from '@react-navigation/native';
import { createBottomTabNavigator } from "@react-navigation/bottom-tabs";
import { Provider } from 'react-redux';
import { SafeAreaProvider } from 'react-native-safe-area-context';
import "react-native-gesture-handler";
import React, { useContext } from "react";
import { NavigationContainer } from "@react-navigation/native";
import { Provider } from "react-redux";
import store from "./store";
// import { Counter } from './screens/Counter'
import { LogIn } from './screens/LogIn';
import { Counter } from './screens/Counter';
import { createNativeStackNavigator } from '@react-navigation/native-stack';


const A = () => <View><Text>Home</Text></View>
const B = () => <View><Text>Settings</Text></View>
const C = () => <View><Text>C</Text></View>

const Tab = createBottomTabNavigator();
const Stack = createNativeStackNavigator();

const Home = () => {
return (
<Tab.Navigator>
<Tab.Screen name="A" component={A} />
<Tab.Screen name="B" component={B} />
</Tab.Navigator>
)
}
import { useFonts } from "expo-font";
import { AuthProvider } from "./context/AuthContext";
import RootNavigation from "./navigation/RootNavigation";

function App() {
return (
<NavigationContainer>
<Stack.Navigator>
{/* <Stack.Screen name='Counter' component={Counter} /> */}
<Stack.Screen name="Login" component={LogIn} />
<Stack.Screen name="Home" component={Home} />
<Stack.Screen name="Profile" component={C} />
</Stack.Navigator>
<RootNavigation />
</NavigationContainer>
);
}

const AppWrapper = () => {
const [fontsLoaded] = useFonts({
"poppins-regular": require("./assets/fonts/Poppins-Regular.ttf"),
"poppins-semibold": require("./assets/fonts/Poppins-SemiBold.ttf"),
});

if (!fontsLoaded) {
return null;
}

return (
<Provider store={store}>
<SafeAreaProvider>
<AuthProvider>
<Provider store={store}>
<App />
</SafeAreaProvider>
</Provider>
</Provider>
</AuthProvider>
);
};


const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
});
export default AppWrapper;
export default AppWrapper;

+ 12
- 4
app.json 파일 보기

@@ -1,15 +1,16 @@
{
"expo": {
"name": "native",
"name": "Diligent Template",
"slug": "native",
"version": "1.0.0",
"orientation": "portrait",
"icon": "./assets/icon.png",
"icon": "./assets/images/diligent-logo.png",
"splash": {
"image": "./assets/splash.png",
"image": "./assets/images/diligent-purple.png",
"resizeMode": "contain",
"backgroundColor": "#ffffff"
},
"scheme": "com.diligent.template",
"updates": {
"fallbackToCacheTimeout": 0
},
@@ -17,9 +18,11 @@
"**/*"
],
"ios": {
"supportsTablet": true
"supportsTablet": true,
"bundleIdentifier": "com.diligent.template"
},
"android": {
"package": "com.diligent.template",
"adaptiveIcon": {
"foregroundImage": "./assets/adaptive-icon.png",
"backgroundColor": "#FFFFFF"
@@ -27,6 +30,11 @@
},
"web": {
"favicon": "./assets/favicon.png"
},
"extra": {
"eas": {
"projectId": "cb00f072-1d4c-4c94-ac22-f34e72808a6b"
}
}
}
}

BIN
assets/fonts/Poppins-Regular.ttf 파일 보기


BIN
assets/fonts/Poppins-SemiBold.ttf 파일 보기


BIN
assets/images/diligent-logo.png 파일 보기


BIN
assets/images/diligent-purple.png 파일 보기


+ 1
- 0
assets/images/facebook.svg 파일 보기

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" data-name="Ebene 1" viewBox="0 0 1024 1024"><path fill="#1877f2" d="M1024,512C1024,229.23016,794.76978,0,512,0S0,229.23016,0,512c0,255.554,187.231,467.37012,432,505.77777V660H302V512H432V399.2C432,270.87982,508.43854,200,625.38922,200,681.40765,200,740,210,740,210V336H675.43713C611.83508,336,592,375.46667,592,415.95728V512H734L711.3,660H592v357.77777C836.769,979.37012,1024,767.554,1024,512Z"/><path fill="#fff" d="M711.3,660,734,512H592V415.95728C592,375.46667,611.83508,336,675.43713,336H740V210s-58.59235-10-114.61078-10C508.43854,200,432,270.87982,432,399.2V512H302V660H432v357.77777a517.39619,517.39619,0,0,0,160,0V660Z"/></svg>

+ 9
- 0
assets/images/google.svg 파일 보기

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<svg viewBox="0 0 24 24" width="24" height="24" xmlns="http://www.w3.org/2000/svg">
<g transform="matrix(1, 0, 0, 1, 27.009001, -39.238998)">
<path fill="#4285F4" d="M -3.264 51.509 C -3.264 50.719 -3.334 49.969 -3.454 49.239 L -14.754 49.239 L -14.754 53.749 L -8.284 53.749 C -8.574 55.229 -9.424 56.479 -10.684 57.329 L -10.684 60.329 L -6.824 60.329 C -4.564 58.239 -3.264 55.159 -3.264 51.509 Z"/>
<path fill="#34A853" d="M -14.754 63.239 C -11.514 63.239 -8.804 62.159 -6.824 60.329 L -10.684 57.329 C -11.764 58.049 -13.134 58.489 -14.754 58.489 C -17.884 58.489 -20.534 56.379 -21.484 53.529 L -25.464 53.529 L -25.464 56.619 C -23.494 60.539 -19.444 63.239 -14.754 63.239 Z"/>
<path fill="#FBBC05" d="M -21.484 53.529 C -21.734 52.809 -21.864 52.039 -21.864 51.239 C -21.864 50.439 -21.724 49.669 -21.484 48.949 L -21.484 45.859 L -25.464 45.859 C -26.284 47.479 -26.754 49.299 -26.754 51.239 C -26.754 53.179 -26.284 54.999 -25.464 56.619 L -21.484 53.529 Z"/>
<path fill="#EA4335" d="M -14.754 43.989 C -12.984 43.989 -11.404 44.599 -10.154 45.789 L -6.734 42.369 C -8.804 40.429 -11.514 39.239 -14.754 39.239 C -19.444 39.239 -23.494 41.939 -25.464 45.859 L -21.484 48.949 C -20.534 46.099 -17.884 43.989 -14.754 43.989 Z"/>
</g>
</svg>

+ 1
- 0
assets/images/login.svg
파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
파일 보기


BIN
assets/images/menu-bg.jpeg 파일 보기


+ 1
- 0
assets/images/registration.svg
파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
파일 보기


+ 1
- 0
assets/images/twitter.svg 파일 보기

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 112.197 112.197" viewBox="0 0 112.197 112.197"><circle cx="56.099" cy="56.098" r="56.098" fill="#55acee"/><path fill="#f1f2f2" d="M90.461,40.316c-2.404,1.066-4.99,1.787-7.702,2.109c2.769-1.659,4.894-4.284,5.897-7.417 c-2.591,1.537-5.462,2.652-8.515,3.253c-2.446-2.605-5.931-4.233-9.79-4.233c-7.404,0-13.409,6.005-13.409,13.409 c0,1.051,0.119,2.074,0.349,3.056c-11.144-0.559-21.025-5.897-27.639-14.012c-1.154,1.98-1.816,4.285-1.816,6.742 c0,4.651,2.369,8.757,5.965,11.161c-2.197-0.069-4.266-0.672-6.073-1.679c-0.001,0.057-0.001,0.114-0.001,0.17 c0,6.497,4.624,11.916,10.757,13.147c-1.124,0.308-2.311,0.471-3.532,0.471c-0.866,0-1.705-0.083-2.523-0.239 c1.706,5.326,6.657,9.203,12.526,9.312c-4.59,3.597-10.371,5.74-16.655,5.74c-1.08,0-2.15-0.063-3.197-0.188 c5.931,3.806,12.981,6.025,20.553,6.025c24.664,0,38.152-20.432,38.152-38.153c0-0.581-0.013-1.16-0.039-1.734 C86.391,45.366,88.664,43.005,90.461,40.316L90.461,40.316z"/></svg>

+ 3
- 0
babel.config.js 파일 보기

@@ -2,5 +2,8 @@ module.exports = function(api) {
api.cache(true);
return {
presets: ['babel-preset-expo'],
plugins: [
'react-native-reanimated/plugin'
]
};
};

+ 30
- 0
components/Buttons/CustomButton.jsx 파일 보기

@@ -0,0 +1,30 @@
import React from 'react';
import { StyleSheet, Text, TouchableOpacity } from 'react-native';

const CustomButton = ({label, onPress}) => {
return (
<TouchableOpacity onPress={onPress} style={styles.button}>
<Text style={styles.buttonText}>
{label}
</Text>
</TouchableOpacity>
)
}

const styles = StyleSheet.create({
button: {
backgroundColor: '#AD40AF',
padding: 20,
borderRadius: 10,
marginBottom: 30
},
buttonText: {
textAlign: 'center',
fontWeight: '700',
fontSize: 16,
color: '#fff',
fontFamily: 'poppins-semibold'
}
})

export default CustomButton;

+ 86
- 0
components/CustomDrawer/CustomDrawer.jsx 파일 보기

@@ -0,0 +1,86 @@
import React, {useContext} from 'react';
import { View, Text, ImageBackground, Image, TouchableOpacity, StyleSheet, Linking } from 'react-native';
import { DrawerContentScrollView, DrawerItemList } from '@react-navigation/drawer';
import { AuthContext } from '../../context/AuthContext';
import Spinner from 'react-native-loading-spinner-overlay/lib';
import Loader from '../Loader';

const CustomDrawer = props => {

const {logout, isLoading} = useContext(AuthContext);

return (
<View style={styles.container}>
<Loader visible={isLoading} />
<DrawerContentScrollView {...props} contentContainerStyle={styles.drawer}>
<ImageBackground source={require('../../assets/images/menu-bg.jpeg')} style={styles.backgroundImage}>
<Image source={require('../../assets/images/diligent-purple.png')} style={styles.profileImage} />
<Text style={styles.userName}>Diligent Software</Text>
</ImageBackground>
<View style={styles.drawerItems}>
<DrawerItemList {...props} />
</View>
</DrawerContentScrollView>
<View style={styles.footer}>
<TouchableOpacity onPress={() => Linking.openURL('mailto:office@dilig.net')} style={styles.footerButton}>
<View style={styles.buttonContent}>
<Text style={styles.footerButtonText}>Contact Us</Text>
</View>
</TouchableOpacity>
<TouchableOpacity onPress={logout} style={styles.footerButton}>
<View style={styles.buttonContent}>
<Text style={styles.footerButtonText}>Sign Out</Text>
</View>
</TouchableOpacity>
</View>
</View>
)
}

const styles = StyleSheet.create({
container: {
flex: 1
},
drawer: {
backgroundColor: '#8200d6'
},
backgroundImage: {
padding: 20
},
profileImage: {
height: 80,
width: 80,
borderRadius: 40,
marginBottom: 10
},
userName: {
color: '#fff',
fontSize: 18,
marginBottom: 5,
fontFamily: 'poppins-regular'
},
drawerItems: {
flex: 1,
backgroundColor: '#fff',
paddingTop: 10,
},
footer: {
padding: 20,
borderTopWidth: 1,
borderTopColor: '#ccc'
},
footerButton: {
paddingVertical: 15
},
buttonContent: {
flexDirection: 'row',
alignItems: 'center'
},
footerButtonText: {
fontSize: 15,
marginLeft: 5,
fontFamily: 'poppins-regular'
}
})

export default CustomDrawer;

+ 72
- 0
components/InputField.jsx 파일 보기

@@ -0,0 +1,72 @@
import React from "react";
import {
View,
Text,
TouchableOpacity,
TextInput,
StyleSheet,
} from "react-native";
import { globalStyles } from "../styles/global";

const InputField = ({
label,
icon,
inputType,
keyboardType,
filedButtonLabel,
fieldButtonFunction,
onChangeText,
text
}) => {
return (
<View style={styles.textField}>
{icon}
{inputType === "password" ? (
<TextInput
placeholder={label}
keyboardType={keyboardType}
style={styles.textInput}
secureTextEntry={true}
value={text}
onChangeText={inputText => {
if (onChangeText) {
onChangeText(inputText);
}
}}
/>
) : (
<TextInput
placeholder={label}
keyboardType={keyboardType}
style={styles.textInput}
value={text}
onChangeText={inputText => {
if (onChangeText) {
onChangeText(inputText);
}
}}
/>
)}
<TouchableOpacity onPress={fieldButtonFunction}>
<Text style={globalStyles.primaryBold}>{filedButtonLabel}</Text>
</TouchableOpacity>
</View>
);
};

const styles = StyleSheet.create({
textField: {
flexDirection: "row",
borderBottomColor: "#ccc",
borderBottomWidth: 1,
paddingBottom: 8,
marginBottom: 25,
},
textInput: {
flex: 1,
paddingVertical: 0,
fontFamily: "poppins-regular",
},
});

export default InputField;

+ 15
- 0
components/Loader.jsx 파일 보기

@@ -0,0 +1,15 @@
import React from "react";
import { PulseIndicator } from "react-native-indicators";
import Spinner from "react-native-loading-spinner-overlay/lib";

const Loader = ({visible}) => {
return (
<Spinner
color="#AD40AF"
visible={visible}
customIndicator={<PulseIndicator color="#AD40AF" />}
/>
);
};

export default Loader;

+ 115
- 0
context/AuthContext.js 파일 보기

@@ -0,0 +1,115 @@
import AsyncStorage from "@react-native-async-storage/async-storage";
import * as Google from "expo-auth-session/providers/google";
import React, { createContext, useEffect, useState } from "react";
import { googleApi, loginApi, registerApi } from "../service/user";

export const AuthContext = createContext();

export const AuthProvider = ({ children }) => {
const [userInfo, setUserInfo] = useState({});
const [isLoading, setIsLoading] = useState(false);

// Google Auth
const [request, response, promptAsync] = Google.useAuthRequest({
androidClientId:
"1032296921439-dpgvgkss3ggds0egvo6puf0r7un9em6c.apps.googleusercontent.com",
iosClientId:
"1032296921439-j7jfahhm7q3l07aj04qvdblmcns77oul.apps.googleusercontent.com",
expoClientId:
"1032296921439-vfs9k28sn7kei4nft998ck3067m8ksiq.apps.googleusercontent.com",
});

useEffect(() => {
if (response?.type === "success") {
googleApi(response.authentication.accessToken)
.then((res) => {
if (res.user) {
setUserInfo(res);
AsyncStorage.setItem("userInfo", JSON.stringify(res));
setIsLoading(false);
} else {
callback(res);
setIsLoading(false);
}
})
.catch((e) => {
console.log("error", e);
setIsLoading(false);
});
}
}, [response]);

const login = (email, password, callback) => {
setIsLoading(true);
loginApi({ identifier: email, password })
.then((res) => {
if (res.user) {
setUserInfo(res);
AsyncStorage.setItem("userInfo", JSON.stringify(res));
setIsLoading(false);
} else {
callback(res);
setIsLoading(false);
}
})
.catch((e) => {
console.log("error", e);
setIsLoading(false);
});
};

const googleAuth = () => {
promptAsync({ useProxy: false, showInRecents: true });
};

const register = (username, email, password, callback) => {
setIsLoading(true);
registerApi({ username, email, password })
.then((res) => {
if (res.user) {
setUserInfo(res);
AsyncStorage.setItem("userInfo", JSON.stringify(res));
setIsLoading(false);
} else {
callback(res);
setIsLoading(false);
}
})
.catch((e) => {
console.log("error", e);
setIsLoading(false);
});
};

const logout = () => {
setIsLoading(true);
AsyncStorage.removeItem("userInfo");
setUserInfo({});
setIsLoading(false);
};

const isLoggedIn = async () => {
try {
let userInfo = await AsyncStorage.getItem("userInfo");
userInfo = JSON.parse(userInfo);

if (userInfo) {
setUserInfo(userInfo);
}
} catch (e) {
console.log(e);
}
};

useEffect(() => {
isLoggedIn();
}, []);

return (
<AuthContext.Provider
value={{ isLoading, login, logout, userInfo, register, googleAuth }}
>
{children}
</AuthContext.Provider>
);
};

+ 26
- 0
eas.json 파일 보기

@@ -0,0 +1,26 @@
{
"cli": {
"version": ">= 3.0.0"
},
"build": {
"development": {
"developmentClient": true,
"distribution": "internal",
"ios": {
"simulator": true
}
},
"test": {
"android": {
"buildType": "apk"
}
},
"preview": {
"distribution": "internal"
},
"production": {}
},
"submit": {
"production": {}
}
}

+ 8
- 0
index.js 파일 보기

@@ -0,0 +1,8 @@
import { registerRootComponent } from 'expo';

import App from './App';

// registerRootComponent calls AppRegistry.registerComponent('main', () => App);
// It also ensures that whether you load the app in Expo Go or in a native build,
// the environment is set up appropriately
registerRootComponent(App);

+ 45
- 0
navigation/AppStack.js 파일 보기

@@ -0,0 +1,45 @@
import React from 'react';
import { createDrawerNavigator } from '@react-navigation/drawer';

import CustomDrawer from '../components/CustomDrawer/CustomDrawer';
import TabNavigator from './TabNavigator';
import Ionicons from '@expo/vector-icons/Ionicons';
import SettingsScreen from '../screens/SettingsScreen';
import ProfileScreen from '../screens/ProfileScreen';

const Drawer = createDrawerNavigator();

const AppStack = () => {
return (
<Drawer.Navigator drawerContent={props => <CustomDrawer {...props} />}
screenOptions={{
headerShown: false,
drawerActiveBackgroundColor: '#aa18ea',
drawerActiveTintColor: '#fff',
drawerInactiveTintColor: '#333',
drawerLabelStyle: {
marginLeft: 5,
fontSize: 16
}
}}
>
<Drawer.Screen name='Home' component={TabNavigator} options={{
drawerIcon: ({color}) => (
<Ionicons name='home-outline' size={22} color={color} />
)
}} />
<Drawer.Screen name='Profile' component={ProfileScreen} options={{
drawerIcon: ({color}) => (
<Ionicons name='person-outline' size={22} color={color} />
)
}} />
<Drawer.Screen name='Settings' component={SettingsScreen} options={{
drawerIcon: ({color}) => (
<Ionicons name='settings-outline' size={22} color={color} />
)
}} />
</Drawer.Navigator>
)
}

export default AppStack;

+ 21
- 0
navigation/AuthStack.js 파일 보기

@@ -0,0 +1,21 @@
import React from 'react';
import { createNativeStackNavigator } from '@react-navigation/native-stack';

import OnboardingScreen from '../screens/OnboardingScreen';
import LoginScreen from '../screens/LoginScreen';
import RegisterScreen from '../screens/RegisterScreen';


const Stack = createNativeStackNavigator();

const AuthStack = () => {
return (
<Stack.Navigator screenOptions={{headerShown: false}}>
<Stack.Screen name='Onboarding' component={OnboardingScreen} />
<Stack.Screen name='Login' component={LoginScreen} />
<Stack.Screen name='Register' component={RegisterScreen} />
</Stack.Navigator>
)
}
export default AuthStack;

+ 15
- 0
navigation/RootNavigation.js 파일 보기

@@ -0,0 +1,15 @@
import React, {useContext} from 'react'
import { AuthContext } from '../context/AuthContext'
import AppStack from './AppStack';
import AuthStack from './AuthStack';

const RootNavigation = () => {
const {userInfo} = useContext(AuthContext);
return (
!userInfo.jwt ? <AuthStack /> : <AppStack />
)

}

export default RootNavigation

+ 71
- 0
navigation/TabNavigator.js 파일 보기

@@ -0,0 +1,71 @@
import React from "react";
import { createNativeStackNavigator } from "@react-navigation/native-stack";
import { createBottomTabNavigator } from "@react-navigation/bottom-tabs";
import { getFocusedRouteNameFromRoute } from "@react-navigation/native";

import HomeScreen from "../screens/HomeScreen";
import Ionicons from "@expo/vector-icons/Ionicons";
import FavoriteScreen from "../screens/FavoriteScreen";

const Tab = createBottomTabNavigator();
const Stack = createNativeStackNavigator();

const HomeStack = () => {
return (
<Stack.Navigator>
<Stack.Screen
name="Home"
component={HomeScreen}
options={{ headerShown: false }}
/>
</Stack.Navigator>
);
};

const TabNavigator = () => {
return (
<Tab.Navigator
screenOptions={{
headerShown: false,
tabBarShowLabel: false,
tabBarStyle: { backgroundColor: "#AD40AF" },
tabBarInactiveTintColor: "#fff",
tabBarActiveTintColor: "yellow",
}}
>
<Tab.Screen
name="Home2"
component={HomeStack}
options={({ route }) => ({
tabBarStyle: {
display: getTabBarVisibility(route),
backgroundColor: "#AD40AF",
},
tabBarIcon: ({ color, size }) => (
<Ionicons name="home-outline" color={color} size={size} />
),
})}
/>
<Tab.Screen
name="Favorite"
component={FavoriteScreen}
options={{
tabBarIcon: ({ color, size }) => (
<Ionicons name="heart-outline" color={color} size={size} />
),
}}
/>
</Tab.Navigator>
);
};

const getTabBarVisibility = (route) => {
const routeName = getFocusedRouteNameFromRoute(route) ?? "Feed";

if (routeName === "Details") {
return "none";
}
return "flex";
};

export default TabNavigator;

+ 18
- 7
package.json 파일 보기

@@ -1,40 +1,51 @@
{
"main": "node_modules/expo/AppEntry.js",
"scripts": {
"start": "expo start",
"android": "expo start --android",
"ios": "expo start --ios",
"start": "expo start --dev-client",
"android": "expo run:android",
"ios": "expo run:ios",
"web": "expo start --web",
"eject": "expo eject"
},
"dependencies": {
"@react-native-async-storage/async-storage": "~1.17.3",
"@react-native-community/datetimepicker": "6.5.2",
"@react-native-google-signin/google-signin": "^8.2.2",
"@react-native-masked-view/masked-view": "0.2.8",
"@react-navigation/bottom-tabs": "^6.4.3",
"@react-navigation/drawer": "^6.5.5",
"@react-navigation/native": "^6.0.16",
"@react-navigation/native-stack": "^6.9.4",
"@reduxjs/toolkit": "^1.9.1",
"axios": "^1.2.1",
"expo": "^47.0.8",
"expo": "~47.0.8",
"expo-auth-session": "~3.7.3",
"expo-random": "~13.0.0",
"expo-status-bar": "~1.4.2",
"expo-web-browser": "~12.0.0",
"react": "18.1.0",
"react-dom": "18.1.0",
"react-native": "0.70.5",
"react-native-gesture-handler": "~2.8.0",
"react-native-indicators": "^0.17.0",
"react-native-loading-spinner-overlay": "^3.0.1",
"react-native-reanimated": "~2.12.0",
"react-native-responsive-screen": "^1.4.2",
"react-native-safe-area-context": "4.4.1",
"react-native-screens": "~3.18.0",
"react-native-svg": "13.4.0",
"react-native-svg-transformer": "^1.0.0",
"react-native-vector-icons": "^9.2.0",
"react-native-web": "~0.18.7",
"react-navigation-stack": "^2.10.4",
"react-redux": "^8.0.5",
"redux-batched-actions": "^0.5.0",
"redux-thunk": "^2.4.2"
"redux-thunk": "^2.4.2",
"expo-splash-screen": "~0.17.5"
},
"devDependencies": {
"@babel/core": "^7.19.3"
},
"private": true
"private": true,
"name": "diligent-react-native",
"version": "1.0.0"
}

+ 0
- 49
screens/Counter.jsx 파일 보기

@@ -1,49 +0,0 @@
import React from "react";
import { StyleSheet, Text, TouchableOpacity, View } from "react-native";
import { useDispatch, useSelector } from "react-redux";
import { decrement, increment } from "../store/actions";

export const Counter = () => {
const dispatch = useDispatch()
const value = useSelector(s => s.test.value)

return (
<View style={[{ width: '75%' }]}>
<Text style={[styles.textAlignCenter]}>{value}</Text>
<View style={[styles.row, styles.justifySpaceBetween]}>
<TouchableOpacity style={[styles.button, styles.justifyCenter]} onPress={() => dispatch(increment())}>
<Text style={[styles.textAlignCenter]}>Increment</Text>
</TouchableOpacity>
<TouchableOpacity style={[styles.button, styles.justifyCenter]} onPress={() => dispatch(decrement())}>
<Text style={[styles.textAlignCenter]}>Decrement</Text>
</TouchableOpacity>
</View>
</View>
)
}

const styles = StyleSheet.create({
row: {
flexDirection: "row",
},
flex: {
flex: 1
},
justifySpaceBetween: {
justifyContent: 'space-between'
},
button: {
backgroundColor: "#D9F1EC",
padding: '3%',
marginTop: '10%'
},
textAlignCenter: {
textAlign: 'center'
},
justifyCenter: {
justifyContent: 'center'
},
alignCenter: {
alignItems: 'center'
}
})

+ 20
- 0
screens/FavoriteScreen.jsx 파일 보기

@@ -0,0 +1,20 @@
import React from 'react';
import { View, Text, StyleSheet } from 'react-native';

const FavoriteScreen = () => {
return (
<View style={styles.container}>
<Text>Favorite</Text>
</View>
)
}

const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center'
}
})

export default FavoriteScreen;

+ 36
- 0
screens/HomeScreen.jsx 파일 보기

@@ -0,0 +1,36 @@
import React from 'react';
import { View, Text, SafeAreaView, ScrollView, ImageBackground, TextInput, TouchableOpacity, StyleSheet } from 'react-native';
import Feather from '@expo/vector-icons/Feather';

import { windowWidth } from '../utils/Dimensions';

const HomeScreen = ({navigation}) => {
return (
<SafeAreaView style={{flex: 1, backgroundColor: '#fff'}}>
<ScrollView style={{padding: 20}}>
<View style={styles.wrapper}>
<Text style={{fontSize: 18}}>
Hello Diligent
</Text>
<TouchableOpacity onPress={() => navigation.openDrawer()}>
<ImageBackground source={require('../assets/images/diligent-purple.png')} style={styles.imageBackground} imageStyle={{borderRadius:25}} />
</TouchableOpacity>
</View>
</ScrollView>
</SafeAreaView>
)
}

const styles = StyleSheet.create({
wrapper: {
flexDirection: 'row',
justifyContent: 'space-between',
marginBottom: 20
},
imageBackground: {
width: 35,
height: 35
}
})

export default HomeScreen;

+ 0
- 66
screens/LogIn.jsx 파일 보기

@@ -1,66 +0,0 @@
import React from "react";
import { useState } from "react";
import { View, TextInput, Text, StyleSheet } from "react-native";
import Button from "../components/Buttons/Button";
import { login } from "../thunks/user.thunk";
import { useDispatch } from "react-redux";

export const LogIn = () => {

const [username, setUsername] = useState()
const [password, setPassword] = useState()
const [error, setError] = useState()
const dispatch = useDispatch();

const loginHandler = () => {
dispatch(
login(username, password, function (result) {
console.log(result.data)
if (!result.OK) {
setUsername("");
setPassword("");
setError(result.data.Message ? result.data.Message : "Error occurred during Login,please try again!");
}
})
)
}

return (
<View style={{flex: 1, justifyContent: 'center'}}>
<Text style={styles.errorMessage}>{error && error}</Text>
<TextInput focus={true}
style={styles.input}
placeholder='Username'
placeholderTextColor='#000'
value={username}
onChangeText={setUsername}
/>
<TextInput focus={true}
style={styles.input}
placeholder='Password'
placeholderTextColor='#000'
value={password}
onChangeText={setPassword}
secureTextEntry />
<Button
onPress={loginHandler}
title='Log In'
style={{ margin: 12, backgroundColor: '#3E5076' }}
/>
</View>
)
}

const styles = StyleSheet.create({
input: {
height: 40,
margin: 12,
borderWidth: 1,
padding: 10,
borderRadius: 5
},
errorMessage: {
color: 'red',
margin: 12
}
});

+ 132
- 0
screens/LoginScreen.jsx 파일 보기

@@ -0,0 +1,132 @@
import React, {useState, useContext} from "react";
import {
SafeAreaView,
View,
Text,
TouchableOpacity,
StyleSheet,
} from "react-native";
import MaterialIcons from "@expo/vector-icons/MaterialIcons";
import Ionicons from "@expo/vector-icons/Ionicons";

import LoginSVG from "../assets/images/login.svg";
import GoogleSVG from "../assets/images/google.svg";
import FacebookSVG from "../assets/images/facebook.svg";
import TwitterSVG from "../assets/images/twitter.svg";

import CustomButton from "../components/Buttons/CustomButton";
import InputField from "../components/InputField";
import { globalStyles } from "../styles/global";
import { AuthContext } from "../context/AuthContext";
import Loader from "../components/Loader";

const LoginScreen = ({ navigation }) => {
const [email, setEmail] = useState(null);
const [password, setPassword] = useState(null);
const [error, setError] = useState(null);


const {isLoading, login, googleAuth} = useContext(AuthContext);

const handleLogin = () => {
login(email, password, function(result) {
setError(result.error.message);
});
}

return (
<SafeAreaView style={globalStyles.safeArea}>
<Loader visible={isLoading} />
<View style={{ paddingHorizontal: 25 }}>
<View style={{ alignItems: "center" }}>
<LoginSVG height={300} width={300} />
</View>
<Text style={globalStyles.boldText}>Sign In</Text>
<InputField
label={"Email"}
keyboardType="email-address"
onChangeText={text => {
setEmail(text);
}}
text={email}
icon={
<MaterialIcons
name="alternate-email"
size={20}
color="#666"
style={{ marginRight: 5 }}
/>
}
/>
<InputField
label={"Password"}
filedButtonLabel={"Forgot?"}
fieldButtonFunction={() => {}}
inputType="password"
text={password}
onChangeText={text => {
setPassword(text);
}}
icon={
<Ionicons
name="ios-lock-closed-outline"
size={20}
color="#666"
style={{ marginRight: 5 }}
/>
}
/>
{error && <Text style={styles.errorMessage}>{error}</Text>}
<CustomButton label={"Login"} onPress={handleLogin} />
<Text style={globalStyles.regularCenteredText}>Or login with ...</Text>
<View style={styles.providersContainer}>
<TouchableOpacity onPress={googleAuth} style={globalStyles.iconButton}>
<GoogleSVG height={24} width={24} />
</TouchableOpacity>
<TouchableOpacity onPress={() => {}} style={globalStyles.iconButton}>
<FacebookSVG height={24} width={24} />
</TouchableOpacity>
<TouchableOpacity onPress={() => {}} style={globalStyles.iconButton}>
<TwitterSVG height={24} width={24} />
</TouchableOpacity>
</View>
<View style={styles.registerContainer}>
<Text style={globalStyles.regularText}>Need account? </Text>
<TouchableOpacity onPress={() => navigation.navigate("Register")}>
<Text style={styles.registerButtonText}>Sign Up</Text>
</TouchableOpacity>
</View>
</View>
</SafeAreaView>
);
};

const styles = StyleSheet.create({
providerText: {
textAlign: "center",
color: "#666",
marginBottom: 30,
fontFamily: "poppins-regular",
},
providersContainer: {
flexDirection: "row",
justifyContent: "space-between",
marginBottom: 30,
},
registerContainer: {
flexDirection: "row",
justifyContent: "center",
marginBottom: 30,
},
registerButtonText: {
color: "#AD40AF",
fontWeight: "700",
fontFamily: "poppins-semibold",
},
errorMessage: {
marginBottom: 30,
color: 'red'
}
});

export default LoginScreen;

+ 58
- 0
screens/OnboardingScreen.jsx 파일 보기

@@ -0,0 +1,58 @@
import React from 'react';
import { SafeAreaView, View, Text, TouchableOpacity, StyleSheet, Image } from 'react-native';
import MaterialIcons from '@expo/vector-icons/MaterialIcons';

const OnboardingScreen = ({navigation}) => {
return (
<SafeAreaView style={styles.safeArea}>
<View style={{marginTop: 20}}>
<Text style={styles.headText}>DILIGENT</Text>
</View>
<View style={styles.logo}>
<Image style={{width: 300, height: 300}} source={require('../assets/images/diligent-logo.png')} />
</View>
<TouchableOpacity style={styles.button} onPress={() => navigation.navigate('Login')}>
<Text style={styles.buttonText}>Let's begin</Text>
<MaterialIcons name='arrow-forward-ios' size={22} color='#fff' />
</TouchableOpacity>
</SafeAreaView>
)
}

const styles = StyleSheet.create({
safeArea: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#fff'
},
headText: {
fontWeight: 'bold',
fontSize: 30,
color: '#20315f',
fontFamily: 'poppins-semibold'
},
logo: {
flex: 1,
justifyContent: 'center',
alignItems: 'center'
},
button: {
backgroundColor: '#AD40AF',
padding: 20,
width: '90%',
borderRadius: 10,
marginBottom: 50,
flexDirection: 'row',
justifyContent: 'space-between'
},
buttonText: {
color: 'white',
fontSize: 18,
textAlign: 'center',
fontWeight: 'bold',
fontFamily: 'poppins-regular'
}
})

export default OnboardingScreen;

+ 20
- 0
screens/ProfileScreen.jsx 파일 보기

@@ -0,0 +1,20 @@
import React from 'react';
import { View, Text, StyleSheet } from 'react-native';

const ProfileScreen = () => {
return (
<View style={styles.container}>
<Text>Profile</Text>
</View>
)
}

const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center'
}
})

export default ProfileScreen;

+ 197
- 0
screens/RegisterScreen.jsx 파일 보기

@@ -0,0 +1,197 @@
import React, { useState, useContext } from "react";
import {
SafeAreaView,
ScrollView,
View,
Text,
TextInput,
TouchableOpacity,
StyleSheet,
Platform,
} from "react-native";

import DateTimePicker from "@react-native-community/datetimepicker";
import InputField from "../components/InputField";

import MaterialIcons from "@expo/vector-icons/MaterialIcons";
import Ionicons from "@expo/vector-icons/Ionicons";

import RegistrationSVG from "../assets/images/registration.svg";
import GoogleSVG from "../assets/images/google.svg";
import FacebookSVG from "../assets/images/facebook.svg";
import TwitterSVG from "../assets/images/twitter.svg";

import CustomButton from "../components/Buttons/CustomButton";
import { globalStyles } from "../styles/global";
import { AuthContext } from "../context/AuthContext";
import Spinner from "react-native-loading-spinner-overlay/lib";
import Loader from "../components/Loader";

const RegisterScreen = ({ navigation }) => {
const { isLoading, register } = useContext(AuthContext);

const [date, setDate] = useState(new Date());
const [open, setOpen] = useState(false);
const [dateOfBirthLabel, setDateOfBirthLabel] = useState("Date of Birth");

const [username, setUsername] = useState(null);
const [email, setEmail] = useState(null);
const [password, setPassword] = useState(null);
const [confirmPassword, setConfirmPassword] = useState(null);
const [error, setError] = useState(null);

const onChange = (event, selectedDate) => {
const currentDate = selectedDate || date;
setDate(currentDate);
let tempDate = new Date(currentDate);
let fDate =
tempDate.getDate() +
"/" +
(tempDate.getMonth() + 1) +
"/" +
tempDate.getFullYear();
setDateOfBirthLabel(fDate);
setOpen(false);
};

const handleSignup = () => {
if (password !== confirmPassword) {
setError("Passwords must match");
return;
}

register(username, email, password, function (result) {
setError(result.error.message);
});
};

return (
<SafeAreaView style={globalStyles.safeArea}>
<Loader visible={isLoading} />
<ScrollView
showsVerticalScrollIndicator={false}
style={{ paddingHorizontal: 25 }}
>
<View style={{ alignItems: "center" }}>
<RegistrationSVG width={300} height={300} />
</View>
<Text style={globalStyles.boldText}>Sign Up</Text>
<View style={styles.providersContainer}>
<TouchableOpacity onPress={() => {}} style={globalStyles.iconButton}>
<GoogleSVG height={24} width={24} />
</TouchableOpacity>
<TouchableOpacity onPress={() => {}} style={globalStyles.iconButton}>
<FacebookSVG height={24} width={24} />
</TouchableOpacity>
<TouchableOpacity onPress={() => {}} style={globalStyles.iconButton}>
<TwitterSVG height={24} width={24} />
</TouchableOpacity>
</View>
<Text style={globalStyles.regularCenteredText}>
Or, sign up with email...
</Text>
<InputField
text={username}
onChangeText={(text) => setUsername(text)}
label={"Full Name"}
icon={
<Ionicons
name="person-outline"
size={20}
color="#666"
style={{ marginRight: 5 }}
/>
}
/>
<InputField
text={email}
onChangeText={(text) => setEmail(text)}
label={"Email"}
icon={
<MaterialIcons
name="alternate-email"
size={20}
color="#666"
style={{ marginRight: 5 }}
/>
}
keyboardType="email-address"
/>
<InputField
text={password}
onChangeText={(text) => setPassword(text)}
label={"Password"}
icon={
<Ionicons
name="ios-lock-closed-outline"
size={20}
color="#666"
style={{ marginRight: 5 }}
/>
}
inputType="password"
/>
<InputField
text={confirmPassword}
onChangeText={(text) => setConfirmPassword(text)}
label={"Confirm Password"}
icon={
<Ionicons
name="ios-lock-closed-outline"
size={20}
color="#666"
style={{ marginRight: 5 }}
/>
}
inputType="password"
/>
{/* <View style={styles.dateOfBirthContainer}>
<Ionicons name='calendar-outline' size={20} color="#666" style={{marginRight: 5}} />
<TouchableOpacity onPress={() => setOpen(true)}>
<Text style={styles.dateOfBirthLabel}>{dateOfBirthLabel}</Text>
{open && <DateTimePicker testID='dateTimePicker' value={date} mode="date" display='spinner' onChange={onChange} textColor="#000" />}
</TouchableOpacity>
</View> */}
{error && <Text style={styles.errorMessage}>{error}</Text>}
<CustomButton label={"Sign Up"} onPress={handleSignup} />
<View style={styles.alreadyRegistered}>
<Text style={globalStyles.regularText}>Already Registered? </Text>
<TouchableOpacity onPress={() => navigation.goBack()}>
<Text style={globalStyles.primaryBold}>Sign In</Text>
</TouchableOpacity>
</View>
</ScrollView>
</SafeAreaView>
);
};

const styles = StyleSheet.create({
providersContainer: {
flexDirection: "row",
justifyContent: "space-between",
marginBottom: 30,
},
dateOfBirthContainer: {
flexDirection: "row",
borderBottomColor: "#ccc",
borderBottomWidth: 1,
paddingBottom: 8,
marginBottom: 30,
},
dateOfBirthLabel: {
color: "#666",
marginLeft: 5,
marginTop: 5,
},
alreadyRegistered: {
flexDirection: "row",
justifyContent: "center",
marginBottom: 30,
},
errorMessage: {
marginBottom: 30,
color: "red",
},
});

export default RegisterScreen;

+ 20
- 0
screens/SettingsScreen.jsx 파일 보기

@@ -0,0 +1,20 @@
import React from 'react';
import { View, Text, StyleSheet } from 'react-native';

const SettingsScreen = () => {
return (
<View style={styles.container}>
<Text>Settings</Text>
</View>
)
}

const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center'
}
})

export default SettingsScreen;

+ 3
- 0
service/apiEndpoints.js 파일 보기

@@ -0,0 +1,3 @@
export default {
login: 'api/auth/local'
}

+ 26
- 0
service/asyncStorage.js 파일 보기

@@ -0,0 +1,26 @@
import AsyncStorage from "@react-native-async-storage/async-storage";

export const storeData = async (key, value) => {
try {
await AsyncStorage.setItem(key, value);
} catch (e) {
console.log(e);
}
}

export const getData = async (key) => {
try {
const value = await AsyncStorage.getItem(key);
return value;
} catch(e) {
// error reading value
}
}

export const removeData = async (key) => {
try {
await AsyncStorage.removeItem(key);
} catch(e) {
// error reading value
}
}

+ 1
- 1
service/endpointDef.js 파일 보기

@@ -1 +1 @@
export const API_ENDPOINT ="https://my.kalla.co/";
export const API_ENDPOINT ="http://localhost:1337/";

+ 30
- 100
service/index.js 파일 보기

@@ -1,111 +1,41 @@
import axios from "axios";
import { setConnectionError } from "../store/actions";
import store from "../store/index";
import { API_ENDPOINT } from './endpointDef';
import { refreshTokens } from "./tokenService/tokenApiClient";
import { API_ENDPOINT } from "./endpointDef";

const axiosApiInstance = axios.create();
const globalLog = false;

const defaultOptions = { log: false }

export const Get = (url, options) => {
return request("GET", url, { ...defaultOptions, ...options });
}

export const Post = (url, data, options) => {
return request("POST", url, { ...defaultOptions, ...options, data });
}

export const Put = (url, data, options) => {
return request("PUT", url, { ...defaultOptions, ...options, data });
}

export const Delete = (url, options) => {
return request("DELETE", url, { ...defaultOptions, ...options });
}
const request = axios.create({
baseURL: API_ENDPOINT,
headers: {
"Content-Type": "application/json",
},
});

const isLogging = (log) => {
return (globalLog || log);
}
export const getRequest = (url, params = null, options = null) =>
request.get(url, { params, ...options });

const request = (method, url, options) => {
const { data, log } = options;
if (isLogging(log)) console.log("REQUEST URL : ", url);
const requestObject = {
method,
url: API_ENDPOINT + url,
timeout: 60000
}
if (data) {
if (isLogging(log)) console.log(`DATA FOR : ${url}`, data);
requestObject.data = data;
}
else {
requestObject.data = undefined;
}
// console.log("url", url)
return axiosApiInstance(requestObject).then((response) => {
if (isLogging(log)) console.log(`RESPONSE for ${url} : `, response);
export const postRequest = (url, data, params = null, options = null) =>
request.post(url, data, { params, ...options });

return { ...response, OK: true };
})
.catch((error) => {
if (isLogging(log)) console.log(`RESPONSE for catch ${url} : `, (error.response ? error.response : error));
export const putRequest = (url, data, params = null, options = null) =>
request.put(url, data, { params, ...options });

//if we get a request timeout error
if (!error.response) {
store.dispatch(setConnectionError(error));
return { error, OK: false };
}
export const patchRequest = (url, data, params = null, options = null) =>
request.patch(url, data, { params, ...options });

//if we get a response other than OK
if (error.response) {
return { ...error.response, OK: false };
}
export const deleteRequest = (url, params = null, options = null) =>
request.delete(url, { params, ...options });

return { OK: false };
})
}
export const addHeaderToken = (token) => {
request.defaults.headers.Authorization = `Bearer ${token}`;
};

axiosApiInstance.interceptors.request.use(
(config) => {
// console.log('sending request')
const accessToken = store.getState().user.token;
config.headers = {
"Authorization": `Bearer ${accessToken}`,
"Accept": "application/json",
"Content-Type": "application/json",
"Referer": config.url
};
return config;
},
(error) => {
Promise.reject(error);
}
);
export const removeHeaderToken = () => {
delete request.defaults.headers.Authorization;
};

axiosApiInstance.interceptors.response.use(
(response) => {
return response;
},
async (error) => {
// console.log('********************************************************************', error)
const originalRequest = error.config
if (originalRequest._retried) {
console.log("Request second attempt failed.")
}
if (!originalRequest._retried && error.response && error.response.status === 401) {
try {
await refreshTokens()
}
catch (e) {
throw error;
}
return await axiosApiInstance({ ...originalRequest, _retried: true })
}
throw error;
}
);
export const attachPostRequestListener = (postRequestListener) => {
request.interceptors.response.use(
(response) => response,
(response) => postRequestListener(response)
);
};

export default axiosApiInstance;
export const apiDefaultUrl = request.defaults.baseURL;

+ 38
- 5
service/user.js 파일 보기

@@ -1,6 +1,39 @@
import { Post } from './index';
import { API_ENDPOINT } from "./endpointDef";

export const loginApi = async (payload) => {
const result = await fetch(API_ENDPOINT + 'api/auth/local', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(payload)
})

const res = await result.json();

return res;
};

export const registerApi = async (payload) => {
const result = await fetch(API_ENDPOINT + 'api/auth/local/register', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(payload)
})

const res = await result.json();

return res;
};

export const googleApi = async (accessToken) => {
const result = await fetch('https://9dae-178-220-74-194.eu.ngrok.io/' + `api/auth/google/callback?access_token=${accessToken}`);

const res = await result.json();

return res;
};


export const loginAPI = async (username, password) => {
const body = JSON.stringify({ Username: username, Password: password });
return Post(`api/login`, body);
};

+ 44
- 0
styles/global.js 파일 보기

@@ -0,0 +1,44 @@
import { StyleSheet } from "react-native";

// Fonts
const regularFont = "poppins-regular";
const semiBoldFont = "poppins-semibold";

// Colors
const primary = "#AD40AF";
const secondary = "#333";

export const globalStyles = StyleSheet.create({
boldText: {
fontSize: 28,
fontWeight: "500",
color: secondary,
marginBottom: 30,
fontFamily: semiBoldFont,
},
primaryBold: {
color: primary,
fontWeight: "700",
fontFamily: semiBoldFont,
},
iconButton: {
borderColor: "#ddd",
borderWidth: 2,
borderRadius: 10,
paddingHorizontal: 30,
paddingVertical: 10,
},
regularText: {
fontFamily: regularFont,
},
regularCenteredText: {
textAlign: "center",
color: "#666",
marginBottom: 30,
fontFamily: regularFont,
},
safeArea: {
flex: 1,
justifyContent: "center",
},
});

+ 35
- 18
thunks/user.thunk.js 파일 보기

@@ -1,19 +1,36 @@
import { loginAPI } from "../service/user";
import { setRefreshToken, setToken, setUsername } from "../store/actions";
import { batchActions } from "redux-batched-actions";
import { removeData, storeData } from "../service/asyncStorage";
import { loginApi } from "../service/user";
import { logInSuccess, setToken, setUsername } from "../store/actions";

export const login = (username, password, callback) => {
return (dispatch) =>
loginAPI(username, password)
.then((responseJson) => {
console.log('response', responseJson)
if (responseJson.OK && responseJson.data.Data.AccessToken != null) {
dispatch(batchActions([
setToken(responseJson.data.Data.AccessToken),
setRefreshToken(responseJson.data.Data.RefreshToken),
setUsername(username)]))
} else callback(responseJson);
})
.catch((error) => {
console.log("error", error);
});
};
export const login = (email, password, callback) => {
return async (dispatch) => {
const result = await loginApi({ identifier: email, password });
if (result.data === null) {
callback(result);
}else {
await removeData("TOKEN");
const token = await storeData('TOKEN', result.jwt);
console.log(result.user);
if (token) {
dispatch(batchActions([
setToken(result.jwt),
setUsername(result.user.username),
logInSuccess(true)
]))
}
}
};
};

export const logout = () => {
return async (dispatch) => {
await removeData('TOKEN');
dispatch(batchActions([
setToken(null),
setUsername(null),
logInSuccess(false)
]))
};
};

+ 4
- 0
utils/Dimensions.js 파일 보기

@@ -0,0 +1,4 @@
import { Dimensions } from "react-native";

export const windowWidth = Dimensions.get('window').width;
export const windowHeight = Dimensions.get('window').height;

+ 0
- 0
utils/api.js 파일 보기


+ 267
- 8
yarn.lock 파일 보기

@@ -1193,6 +1193,20 @@
slugify "^1.3.4"
sucrase "^3.20.0"

"@expo/configure-splash-screen@^0.6.0":
version "0.6.0"
resolved "https://registry.yarnpkg.com/@expo/configure-splash-screen/-/configure-splash-screen-0.6.0.tgz#07d97ee512fd859fcc09506ba3762fd6263ebc39"
integrity sha512-4DyPoNXJqx9bN4nEwF3HQreo//ECu7gDe1Xor3dnnzFm9P/VDxAKdbEhA0n+R6fgkNfT2onVHWijqvdpTS3Xew==
dependencies:
color-string "^1.5.3"
commander "^5.1.0"
fs-extra "^9.0.0"
glob "^7.1.6"
lodash "^4.17.15"
pngjs "^5.0.0"
xcode "^3.0.0"
xml-js "^1.6.11"

"@expo/dev-server@0.1.123":
version "0.1.123"
resolved "https://registry.yarnpkg.com/@expo/dev-server/-/dev-server-0.1.123.tgz#71304323b47db9ce300b9a774571ef2312b9d581"
@@ -1709,6 +1723,18 @@
prompts "^2.4.0"
semver "^6.3.0"

"@react-native-community/datetimepicker@6.5.2":
version "6.5.2"
resolved "https://registry.yarnpkg.com/@react-native-community/datetimepicker/-/datetimepicker-6.5.2.tgz#d2c0df9f2c6acce39f7e957743dd811547656098"
integrity sha512-9K3zhIH1zmpIGSG3GJTWLIoAx+sR4kJ1wqpGKMwWJ5IYXBsFxMdvGw023t0pz2CQStlnNbbNhnZY/HMYFBCsCg==
dependencies:
invariant "^2.2.4"

"@react-native-google-signin/google-signin@^8.2.2":
version "8.2.2"
resolved "https://registry.yarnpkg.com/@react-native-google-signin/google-signin/-/google-signin-8.2.2.tgz#c8420fea36f05dfb067eb1fc301d42f442440a65"
integrity sha512-y56SDxupkN4nvIsmvnq11OqDMLJKTihbwT4dUtnPZ+FCOO4uX62zCpCyXub5o7/N12Ei8KCHC2umd8OHpMdRFg==

"@react-native-masked-view/masked-view@0.2.8":
version "0.2.8"
resolved "https://registry.yarnpkg.com/@react-native-masked-view/masked-view/-/masked-view-0.2.8.tgz#34405a4361882dae7c81b1b771fe9f5fbd545a97"
@@ -1755,6 +1781,20 @@
react-is "^16.13.0"
use-latest-callback "^0.1.5"

"@react-navigation/drawer@^6.5.5":
version "6.5.5"
resolved "https://registry.yarnpkg.com/@react-navigation/drawer/-/drawer-6.5.5.tgz#7e65201435bd23d8418878210a670e8598337436"
integrity sha512-dkmbkv7nc7EWOqns6AlewTHIIAIa3RMwmzbucjqPBnJNJEv76YxUmYpiSQ8TBH9R3czA/Km6eGodyYmkP+3o5Q==
dependencies:
"@react-navigation/elements" "^1.3.11"
color "^4.2.3"
warn-once "^0.1.0"

"@react-navigation/elements@^1.3.11":
version "1.3.11"
resolved "https://registry.yarnpkg.com/@react-navigation/elements/-/elements-1.3.11.tgz#135c2cb3ae4a31bc835bb731110fd1ef9c38e237"
integrity sha512-o4J0g4ofJbbn68e4TpuGkuZLtq5mLll7Ndz9C4O4RvD2chchLuGQ5TycIPTKP428cz8JzuTCFqUe/ZhOPSsudw==

"@react-navigation/elements@^1.3.9":
version "1.3.9"
resolved "https://registry.yarnpkg.com/@react-navigation/elements/-/elements-1.3.9.tgz#33e26d7ad655b012e024ef0a005a3f66201287f8"
@@ -1974,6 +2014,11 @@
resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.5.tgz#5f19d2b85a98e9558036f6a3cacc8819420f05cf"
integrity sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==

"@types/qs@^6.5.3":
version "6.9.7"
resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.7.tgz#63bb7d067db107cc1e457c303bc25d511febf6cb"
integrity sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==

"@types/react@*":
version "18.0.26"
resolved "https://registry.yarnpkg.com/@types/react/-/react-18.0.26.tgz#8ad59fc01fef8eaf5c74f4ea392621749f0b7917"
@@ -2355,7 +2400,7 @@ balanced-match@^1.0.0:
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee"
integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==

base64-js@^1.1.2, base64-js@^1.2.3, base64-js@^1.3.1, base64-js@^1.5.1:
base64-js@^1.1.2, base64-js@^1.2.3, base64-js@^1.3.0, base64-js@^1.3.1, base64-js@^1.5.1:
version "1.5.1"
resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a"
integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==
@@ -2574,6 +2619,14 @@ cache-base@^1.0.1:
union-value "^1.0.0"
unset-value "^1.0.0"

call-bind@^1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c"
integrity sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==
dependencies:
function-bind "^1.1.1"
get-intrinsic "^1.0.2"

caller-callsite@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/caller-callsite/-/caller-callsite-2.0.0.tgz#847e0fce0a223750a9a027c54b33731ad3154134"
@@ -2693,6 +2746,15 @@ cliui@^6.0.0:
strip-ansi "^6.0.0"
wrap-ansi "^6.2.0"

cliui@^7.0.2:
version "7.0.4"
resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f"
integrity sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==
dependencies:
string-width "^4.2.0"
strip-ansi "^6.0.0"
wrap-ansi "^7.0.0"

clone-deep@^4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/clone-deep/-/clone-deep-4.0.1.tgz#c19fd9bdbbf85942b4fd979c84dcf7d5f07c2387"
@@ -2744,7 +2806,7 @@ color-name@^1.0.0, color-name@~1.1.4:
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==

color-string@^1.6.0, color-string@^1.9.0:
color-string@^1.5.3, color-string@^1.6.0, color-string@^1.9.0:
version "1.9.1"
resolved "https://registry.yarnpkg.com/color-string/-/color-string-1.9.1.tgz#4467f9146f036f855b764dfb5bf8582bf342c7a4"
integrity sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==
@@ -2790,6 +2852,11 @@ commander@^4.0.0:
resolved "https://registry.yarnpkg.com/commander/-/commander-4.1.1.tgz#9fd602bd936294e9e9ef46a3f4d6964044b18068"
integrity sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==

commander@^5.1.0:
version "5.1.0"
resolved "https://registry.yarnpkg.com/commander/-/commander-5.1.0.tgz#46abbd1652f8e059bddaef99bbdcb2ad9cf179ae"
integrity sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==

commander@^7.2.0:
version "7.2.0"
resolved "https://registry.yarnpkg.com/commander/-/commander-7.2.0.tgz#a36cb57d0b501ce108e4d20559a150a391d97ab7"
@@ -2810,6 +2877,13 @@ commondir@^1.0.1:
resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b"
integrity sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==

compare-urls@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/compare-urls/-/compare-urls-2.0.0.tgz#9b378c4abd43980a8700fffec9afb85de4df9075"
integrity sha512-eCJcWn2OYFEIqbm70ta7LQowJOOZZqq1a2YbbFCFI1uwSvj+TWMwXVn7vPR1ceFNcAIt5RSTDbwdlX82gYLTkA==
dependencies:
normalize-url "^2.0.1"

compare-versions@^3.4.0:
version "3.6.0"
resolved "https://registry.yarnpkg.com/compare-versions/-/compare-versions-3.6.0.tgz#1a5689913685e5a87637b8d3ffca75514ec41d62"
@@ -3374,6 +3448,18 @@ expo-asset@~8.6.2:
path-browserify "^1.0.0"
url-parse "^1.5.9"

expo-auth-session@~3.7.3:
version "3.7.3"
resolved "https://registry.yarnpkg.com/expo-auth-session/-/expo-auth-session-3.7.3.tgz#ded1afbbf88e0c6e4098e59920b4f13927fc1f3d"
integrity sha512-0mX47j6WdpEoaFVxU36VBRkEjJKwAkqnRyNdd5g+Ab1fHXQJJK3nzjOjxuBzgE8mKSS9NGHr/At9IGY6MLrg2g==
dependencies:
expo-constants "~14.0.0"
expo-crypto "~12.0.0"
expo-linking "~3.2.0"
expo-web-browser "~12.0.0"
invariant "^2.2.4"
qs "6.9.1"

expo-constants@~14.0.0, expo-constants@~14.0.2:
version "14.0.2"
resolved "https://registry.yarnpkg.com/expo-constants/-/expo-constants-14.0.2.tgz#2cb1dec8f41a64c2fc5b4eecaf77d7661cad01cc"
@@ -3382,6 +3468,11 @@ expo-constants@~14.0.0, expo-constants@~14.0.2:
"@expo/config" "~7.0.2"
uuid "^3.3.2"

expo-crypto@~12.0.0:
version "12.0.0"
resolved "https://registry.yarnpkg.com/expo-crypto/-/expo-crypto-12.0.0.tgz#015e47fec27b07098fcef3676c6bf8b20767860a"
integrity sha512-2KC52eLYsXndDZOVFyr+K3Zs9wDgpqZ7F7fwAiUg+yNbE21CJrHKDFvo/Br0FAaDf/w9pUks5/qi1azB5sDzvg==

expo-error-recovery@~4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/expo-error-recovery/-/expo-error-recovery-4.0.1.tgz#3e3333e134c992c234539d3773fe78915c883755"
@@ -3406,6 +3497,17 @@ expo-keep-awake@~11.0.1:
resolved "https://registry.yarnpkg.com/expo-keep-awake/-/expo-keep-awake-11.0.1.tgz#ee354465892a94040ffe09901b85b469e7d54fb3"
integrity sha512-44ZjgLE4lnce2d40Pv8xsjMVc6R5GvgHOwZfkLYtGmgYG9TYrEJeEj5UfSeweXPL3pBFhXKfFU8xpGYMaHdP0A==

expo-linking@~3.2.0:
version "3.2.3"
resolved "https://registry.yarnpkg.com/expo-linking/-/expo-linking-3.2.3.tgz#7b493a7fea2aadafc88a42e2fc6a5a4ba6d47df9"
integrity sha512-PgiWCao9TecLOPdtWyiNSY+UQGAwdjFx4KbHd1YsF0KnM1CJ2idcaHpDRlQPWSNmDebUZYN461/dVtJi9b2krg==
dependencies:
"@types/qs" "^6.5.3"
expo-constants "~14.0.0"
invariant "^2.2.4"
qs "^6.9.1"
url-parse "^1.5.9"

expo-modules-autolinking@1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/expo-modules-autolinking/-/expo-modules-autolinking-1.0.0.tgz#2daac20035e1ecf8e66d74dca9bd1b0d6c09166c"
@@ -3425,12 +3527,34 @@ expo-modules-core@1.0.3:
compare-versions "^3.4.0"
invariant "^2.2.4"

expo-random@~13.0.0:
version "13.0.0"
resolved "https://registry.yarnpkg.com/expo-random/-/expo-random-13.0.0.tgz#fc9c1496ac9f7555563d86de0db25966739c028f"
integrity sha512-aGb0vtUmFFuW0TF1rdOgsz89zEVD/RXUPUnnZy5+i3jJeQ2PerJ4uo72/EuWqHpCBNto8/qT+aCzFinmQDeTAA==
dependencies:
base64-js "^1.3.0"

expo-splash-screen@~0.17.5:
version "0.17.5"
resolved "https://registry.yarnpkg.com/expo-splash-screen/-/expo-splash-screen-0.17.5.tgz#a18dc59c1cc28ebbedbf0a7529a419d18ab0b311"
integrity sha512-ejSO78hwHXz8T9u8kh8t4r6CR4h70iBvA65gX8GK+dYxZl6/IANPbIb2VnUpND9vqfW+JnkDw+ZFst+gDnkpcQ==
dependencies:
"@expo/configure-splash-screen" "^0.6.0"
"@expo/prebuild-config" "5.0.7"

expo-status-bar@~1.4.2:
version "1.4.2"
resolved "https://registry.yarnpkg.com/expo-status-bar/-/expo-status-bar-1.4.2.tgz#14f2b9a6dc7d550578421f07e0046f5fafc2b403"
integrity sha512-ZWjO6D4ARGYfAd3SWDD3STNudHDhyBZDZjhhseqoEmsf7bS9ykny8KKOhlzJW24qIQNPhkgdvHhaw9fQwMJy3Q==

expo@^47.0.8:
expo-web-browser@~12.0.0:
version "12.0.0"
resolved "https://registry.yarnpkg.com/expo-web-browser/-/expo-web-browser-12.0.0.tgz#c8e117bfd6357df05ae3cf85acb423b44c4f6304"
integrity sha512-7/RUuE0sv5kf+mTw5/SOnks0Am1ctoxvT1Xi53Nom2EuXTKBV+b2Kf5xAw3ItoW5W4MHJUX3FdNI6qc9sS9+Pw==
dependencies:
compare-urls "^2.0.0"

expo@~47.0.8:
version "47.0.8"
resolved "https://registry.yarnpkg.com/expo/-/expo-47.0.8.tgz#80390fd63f8305103445069c647011915f7c32dd"
integrity sha512-PGNCIvrnYwHH4TDFsVocq/xhWZ5DW8N3bLkZJPZZgX6VgjtVLNsbZ+0lm1inLCZHP+6xSpSKRccjGHO/QQoMBQ==
@@ -3761,11 +3885,20 @@ gensync@^1.0.0-beta.2:
resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0"
integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==

get-caller-file@^2.0.1:
get-caller-file@^2.0.1, get-caller-file@^2.0.5:
version "2.0.5"
resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e"
integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==

get-intrinsic@^1.0.2:
version "1.1.3"
resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.1.3.tgz#063c84329ad93e83893c7f4f243ef63ffa351385"
integrity sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==
dependencies:
function-bind "^1.1.1"
has "^1.0.3"
has-symbols "^1.0.3"

get-port@^3.2.0:
version "3.2.0"
resolved "https://registry.yarnpkg.com/get-port/-/get-port-3.2.0.tgz#dd7ce7de187c06c8bf353796ac71e099f0980ebc"
@@ -3874,6 +4007,11 @@ has-flag@^4.0.0:
resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b"
integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==

has-symbols@^1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8"
integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==

has-value@^0.3.1:
version "0.3.1"
resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f"
@@ -4257,6 +4395,11 @@ is-path-inside@^3.0.2:
resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283"
integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==

is-plain-obj@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e"
integrity sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==

is-plain-obj@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-2.1.0.tgz#45e42e37fccf1f40da8e5f76ee21515840c09287"
@@ -4614,7 +4757,7 @@ lodash.throttle@^4.1.1:
resolved "https://registry.yarnpkg.com/lodash.throttle/-/lodash.throttle-4.1.1.tgz#c23e91b710242ac70c37f1e1cda9274cc39bf2f4"
integrity sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ==

lodash@^4.17.13, lodash@^4.17.21, lodash@^4.17.4:
lodash@^4.17.13, lodash@^4.17.15, lodash@^4.17.21, lodash@^4.17.4:
version "4.17.21"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
@@ -5284,6 +5427,15 @@ normalize-path@^3.0.0:
resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65"
integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==

normalize-url@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-2.0.1.tgz#835a9da1551fa26f70e92329069a23aa6574d7e6"
integrity sha512-D6MUW4K/VzoJ4rJ01JFKxDrtY1v9wrgzCX5f2qj/lzH1m/lW6MhUZFKerVsnyjOhOsYzI9Kqqak+10l4LvLpMw==
dependencies:
prepend-http "^2.0.0"
query-string "^5.0.1"
sort-keys "^2.0.0"

npm-package-arg@^7.0.0:
version "7.0.0"
resolved "https://registry.yarnpkg.com/npm-package-arg/-/npm-package-arg-7.0.0.tgz#52cdf08b491c0c59df687c4c925a89102ef794a5"
@@ -5332,6 +5484,11 @@ object-copy@^0.1.0:
define-property "^0.2.5"
kind-of "^3.0.3"

object-inspect@^1.9.0:
version "1.12.2"
resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.2.tgz#c0641f26394532f28ab8d796ab954e43c009a8ea"
integrity sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==

object-visit@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb"
@@ -5641,6 +5798,11 @@ pngjs@^3.3.0:
resolved "https://registry.yarnpkg.com/pngjs/-/pngjs-3.4.0.tgz#99ca7d725965fb655814eaf65f38f12bbdbf555f"
integrity sha512-NCrCHhWmnQklfH4MtJMRjZ2a8c80qXeMlQMv2uVp9ISJMTt562SbGd6n2oq0PaPgKm7Z6pL9E2UlLIhC+SHL3w==

pngjs@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/pngjs/-/pngjs-5.0.0.tgz#e79dd2b215767fd9c04561c01236df960bce7fbb"
integrity sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw==

posix-character-classes@^0.1.0:
version "0.1.1"
resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab"
@@ -5651,6 +5813,11 @@ postcss-value-parser@^4.2.0:
resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz#723c09920836ba6d3e5af019f92bc0971c02e514"
integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==

prepend-http@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-2.0.0.tgz#e92434bfa5ea8c19f41cdfd401d741a3c819d897"
integrity sha512-ravE6m9Atw9Z/jjttRUZ+clIXogdghyZAuWJ3qEzjT+jI/dL1ifAqhZeC5VHzQp1MSt1+jxKkFNemj/iO7tVUA==

pretty-bytes@5.6.0:
version "5.6.0"
resolved "https://registry.yarnpkg.com/pretty-bytes/-/pretty-bytes-5.6.0.tgz#356256f643804773c82f64723fe78c92c62beaeb"
@@ -5703,7 +5870,7 @@ prompts@^2.3.2, prompts@^2.4.0:
kleur "^3.0.3"
sisteransi "^1.0.5"

prop-types@^15.7.2:
prop-types@^15.5.10, prop-types@^15.7.2:
version "15.8.1"
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5"
integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==
@@ -5735,6 +5902,27 @@ qs@6.7.0:
resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc"
integrity sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==

qs@6.9.1:
version "6.9.1"
resolved "https://registry.yarnpkg.com/qs/-/qs-6.9.1.tgz#20082c65cb78223635ab1a9eaca8875a29bf8ec9"
integrity sha512-Cxm7/SS/y/Z3MHWSxXb8lIFqgqBowP5JMlTUFyJN88y0SGQhVmZnqFK/PeuMX9LzUyWsqqhNxIyg0jlzq946yA==

qs@^6.9.1:
version "6.11.0"
resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.0.tgz#fd0d963446f7a65e1367e01abd85429453f0c37a"
integrity sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==
dependencies:
side-channel "^1.0.4"

query-string@^5.0.1:
version "5.1.1"
resolved "https://registry.yarnpkg.com/query-string/-/query-string-5.1.1.tgz#a78c012b71c17e05f2e3fa2319dd330682efb3cb"
integrity sha512-gjWOsm2SoGlgLEdAGt7a6slVOk9mGiXmPFMqrEhLQ68rhQuBnpfs3+EmlvqKyxnCo9/PPlF+9MtY02S1aFg+Jw==
dependencies:
decode-uri-component "^0.2.0"
object-assign "^4.1.0"
strict-uri-encode "^1.0.0"

query-string@^7.0.0:
version "7.1.3"
resolved "https://registry.yarnpkg.com/query-string/-/query-string-7.1.3.tgz#a1cf90e994abb113a325804a972d98276fe02328"
@@ -5842,11 +6030,23 @@ react-native-gradle-plugin@^0.70.3:
resolved "https://registry.yarnpkg.com/react-native-gradle-plugin/-/react-native-gradle-plugin-0.70.3.tgz#cbcf0619cbfbddaa9128701aa2d7b4145f9c4fc8"
integrity sha512-oOanj84fJEXUg9FoEAQomA8ISG+DVIrTZ3qF7m69VQUJyOGYyDZmPqKcjvRku4KXlEH6hWO9i4ACLzNBh8gC0A==

react-native-indicators@^0.17.0:
version "0.17.0"
resolved "https://registry.yarnpkg.com/react-native-indicators/-/react-native-indicators-0.17.0.tgz#92f95efaf5fb53be576dfe4e1980a25655a93f55"
integrity sha512-s23em477GHGxWeGczWrixScAZD6tQU4mx1fttlrwhEGKOxhBgp55Kh3RoD9Wj4yna4e5W35xQNoPqoJAT6QW5A==
dependencies:
prop-types "^15.5.10"

react-native-iphone-x-helper@^1.3.0:
version "1.3.1"
resolved "https://registry.yarnpkg.com/react-native-iphone-x-helper/-/react-native-iphone-x-helper-1.3.1.tgz#20c603e9a0e765fd6f97396638bdeb0e5a60b010"
integrity sha512-HOf0jzRnq2/aFUcdCJ9w9JGzN3gdEg0zFE4FyYlp4jtidqU03D5X7ZegGKfT1EWteR0gPBGp9ye5T5FvSWi9Yg==

react-native-loading-spinner-overlay@^3.0.1:
version "3.0.1"
resolved "https://registry.yarnpkg.com/react-native-loading-spinner-overlay/-/react-native-loading-spinner-overlay-3.0.1.tgz#092481b8cce157d3af5ef942f845ad981f96bd36"
integrity sha512-4GdR54HQnKg2HPSSisVizfTLuyhSh4splY9eb8mKiYF1Ihjn/5EmdNo5bN3S7uKPFRC3WLzIZIouX6G6fXfnjw==

react-native-reanimated@~2.12.0:
version "2.12.0"
resolved "https://registry.yarnpkg.com/react-native-reanimated/-/react-native-reanimated-2.12.0.tgz#5821eecfb1769b1617a67a2d4dec12fdeedb2b6e"
@@ -5895,6 +6095,14 @@ react-native-svg@13.4.0:
css-select "^5.1.0"
css-tree "^1.1.3"

react-native-vector-icons@^9.2.0:
version "9.2.0"
resolved "https://registry.yarnpkg.com/react-native-vector-icons/-/react-native-vector-icons-9.2.0.tgz#3c0c82e95defd274d56363cbe8fead8d53167ebd"
integrity sha512-wKYLaFuQST/chH3AJRjmOLoLy3JEs1JR6zMNgTaemFpNoXs0ztRnTxcxFD9xhX7cJe1/zoN5BpQYe7kL0m5yyA==
dependencies:
prop-types "^15.7.2"
yargs "^16.1.1"

react-native-web@~0.18.7:
version "0.18.10"
resolved "https://registry.yarnpkg.com/react-native-web/-/react-native-web-0.18.10.tgz#fb4db047f4be7f9cf35f37ec8d52f7d1c450600f"
@@ -6274,7 +6482,7 @@ safe-regex@^1.1.0:
resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==

sax@>=0.6.0:
sax@>=0.6.0, sax@^1.2.4:
version "1.2.4"
resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9"
integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==
@@ -6415,6 +6623,15 @@ shell-quote@^1.6.1, shell-quote@^1.7.3:
resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.7.4.tgz#33fe15dee71ab2a81fcbd3a52106c5cfb9fb75d8"
integrity sha512-8o/QEhSSRb1a5i7TFR0iM4G16Z0vYB2OQVs4G3aAFXjn3T6yEx8AZxy1PgDF7I00LZHYA3WxaSYIf5e5sAX8Rw==

side-channel@^1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf"
integrity sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==
dependencies:
call-bind "^1.0.0"
get-intrinsic "^1.0.2"
object-inspect "^1.9.0"

signal-exit@^3.0.0, signal-exit@^3.0.2:
version "3.0.7"
resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9"
@@ -6490,6 +6707,13 @@ snapdragon@^0.8.1:
source-map-resolve "^0.5.0"
use "^3.1.0"

sort-keys@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/sort-keys/-/sort-keys-2.0.0.tgz#658535584861ec97d730d6cf41822e1f56684128"
integrity sha512-/dPCrG1s3ePpWm6yBbxZq5Be1dXGLyLn9Z791chDC3NFrpkVbWGzkBwPN1knaciexFXgRJ7hzdnwZ4stHSDmjg==
dependencies:
is-plain-obj "^1.0.0"

source-map-resolve@^0.5.0:
version "0.5.3"
resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.3.tgz#190866bece7553e1f8f267a2ee82c606b5509a1a"
@@ -6600,6 +6824,11 @@ stream-buffers@2.2.x:
resolved "https://registry.yarnpkg.com/stream-buffers/-/stream-buffers-2.2.0.tgz#91d5f5130d1cef96dcfa7f726945188741d09ee4"
integrity sha512-uyQK/mx5QjHun80FLJTfaWE7JtwfRMKBLkMne6udYOmvH0CawotVa7TfgYHzAnpphn4+TweIx1QKMnRIbipmUg==

strict-uri-encode@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz#279b225df1d582b1f54e65addd4352e18faa0713"
integrity sha512-R3f198pcvnB+5IpnBlRkphuE9n46WyVl8I39W/ZUTZLz4nqSP/oLYUrcnJrw462Ds8he4YKMov2efsTIw1BDGQ==

strict-uri-encode@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz#b9c7330c7042862f6b142dc274bbcc5866ce3546"
@@ -7260,7 +7489,7 @@ ws@^7, ws@^7.5.1:
resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.9.tgz#54fa7db29f4c7cec68b1ddd3a89de099942bb591"
integrity sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==

xcode@^3.0.1:
xcode@^3.0.0, xcode@^3.0.1:
version "3.0.1"
resolved "https://registry.yarnpkg.com/xcode/-/xcode-3.0.1.tgz#3efb62aac641ab2c702458f9a0302696146aa53c"
integrity sha512-kCz5k7J7XbJtjABOvkc5lJmkiDh8VhjVCGNiqdKCscmVpdVUpEAyXv1xmCLkQJ5dsHqx3IPO4XW+NTDhU/fatA==
@@ -7268,6 +7497,13 @@ xcode@^3.0.1:
simple-plist "^1.1.0"
uuid "^7.0.3"

xml-js@^1.6.11:
version "1.6.11"
resolved "https://registry.yarnpkg.com/xml-js/-/xml-js-1.6.11.tgz#927d2f6947f7f1c19a316dd8eea3614e8b18f8e9"
integrity sha512-7rVi2KMfwfWFl+GpPg6m80IVMWXLRjO+PxTq7V2CDhoGak0wzYzFgUY2m4XJ47OGdXd8eLE8EmwfAmdjw7lC1g==
dependencies:
sax "^1.2.4"

xml2js@0.4.23:
version "0.4.23"
resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.23.tgz#a0c69516752421eb2ac758ee4d4ccf58843eac66"
@@ -7301,6 +7537,11 @@ y18n@^4.0.0:
resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.3.tgz#b5f259c82cd6e336921efd7bfd8bf560de9eeedf"
integrity sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==

y18n@^5.0.5:
version "5.0.8"
resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55"
integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==

yallist@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72"
@@ -7319,6 +7560,11 @@ yargs-parser@^18.1.2:
camelcase "^5.0.0"
decamelize "^1.2.0"

yargs-parser@^20.2.2:
version "20.2.9"
resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee"
integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==

yargs@^15.1.0, yargs@^15.3.1:
version "15.4.1"
resolved "https://registry.yarnpkg.com/yargs/-/yargs-15.4.1.tgz#0d87a16de01aee9d8bec2bfbf74f67851730f4f8"
@@ -7336,6 +7582,19 @@ yargs@^15.1.0, yargs@^15.3.1:
y18n "^4.0.0"
yargs-parser "^18.1.2"

yargs@^16.1.1:
version "16.2.0"
resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66"
integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==
dependencies:
cliui "^7.0.2"
escalade "^3.1.1"
get-caller-file "^2.0.5"
require-directory "^2.1.1"
string-width "^4.2.0"
y18n "^5.0.5"
yargs-parser "^20.2.2"

yocto-queue@^0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b"

Loading…
취소
저장