Local storage successful but some error remaining on darkmode
continuous-integration/drone/push Build is passing Details

pull/14/head
Emre KARTAL 2 years ago
parent adf327eb11
commit dfabaa9ffa

@ -17,7 +17,7 @@ type CustomCardMusic = { //Props
export default function CardMusic(CBP: CustomCardMusic) { export default function CardMusic(CBP: CustomCardMusic) {
const isDark = useSelector(state => state.userReducer.dark); const isDark = useSelector(state => state.userReducer.dark);
const style = isDark ? GraphicalCharterLight : GraphicalCharterDark; const style = isDark ? GraphicalCharterDark : GraphicalCharterLight;
const currentMusic = useSelector(state => state.appReducer.currentMusic); const currentMusic = useSelector(state => state.appReducer.currentMusic);
const source = typeof CBP.image === 'string' ? { uri: CBP.image } : CBP.image; const source = typeof CBP.image === 'string' ? { uri: CBP.image } : CBP.image;

@ -9,6 +9,7 @@
"web": "expo start --web" "web": "expo start --web"
}, },
"dependencies": { "dependencies": {
"@react-native-async-storage/async-storage": "^1.17.11",
"@react-navigation/bottom-tabs": "^6.5.4", "@react-navigation/bottom-tabs": "^6.5.4",
"@react-navigation/native": "^6.1.4", "@react-navigation/native": "^6.1.4",
"@react-navigation/native-stack": "^6.9.8", "@react-navigation/native-stack": "^6.9.8",

@ -3,15 +3,15 @@ import { userTypes } from "../types/userTypes";
export interface Credentials { export interface Credentials {
email : string, email: string,
password : string password: string
} }
export interface CredentialsRegister { export interface CredentialsRegister {
email : string, email: string,
password : string, password: string,
name : string, name: string,
idFlad : string, idFlad: string,
idSpotify : string idSpotify: string
} }
// export const setLoggedInState = loggedInState => ( // export const setLoggedInState = loggedInState => (
// { // {
@ -19,34 +19,47 @@ export interface CredentialsRegister {
// loggedInState, // loggedInState,
// } // }
// ); // );
export const setLoginState = (cred : Credentials) => { export const setLoginState = (cred: Credentials) => {
return { return {
type: userTypes.LOGIN, type: userTypes.LOGIN,
playload : cred playload: cred
}; };
} }
export const restoreToken = (token : string) => { export const restoreToken = (token: string) => {
return { return {
type: userTypes.RESTORE_TOKEN, type: userTypes.RESTORE_TOKEN,
playload : token playload: token
};
}
export const userSignUp = (user: User) => {
return {
type: userTypes.LOGIN,
playload: user
};
}
export const UserLogout = () => {
return {
type: userTypes.USER_LOGOUT,
};
}
export const userChangeMode = (value: boolean) => {
return {
type: userTypes.CHANGE_MODE,
playload: value
}; };
} }
export const userSignUp = (user : User) => {
return {
type: userTypes.LOGIN,
playload : user
};
}
export const UserLogout = () => { export const ChangeErrorLogin = () => {
return { return {
type: userTypes.USER_LOGOUT, type: userTypes.CHANGE_ERROR_LOGIN,
}; };
} }
export const userChangeMode = () => { export const ChangeErrorSignup = () => {
return { return {
type: userTypes.CHANGE_MODE, type: userTypes.CHANGE_ERROR_SIGNUP,
}; };
} }

@ -1,3 +1,4 @@
import AsyncStorage from '@react-native-async-storage/async-storage';
import { User } from "../../Model/User"; import { User } from "../../Model/User";
import { userTypes } from "../types/userTypes"; import { userTypes } from "../types/userTypes";
const initialState = { const initialState = {
@ -7,7 +8,9 @@ const initialState = {
userSpotifyToken: null, userSpotifyToken: null,
error: null, error: null,
isLogedIn: false, isLogedIn: false,
dark: false, failedLogin: false,
failedSignup: false,
dark: null
} }
const userReducer = (state = initialState, action: any) => { const userReducer = (state = initialState, action: any) => {
@ -24,25 +27,38 @@ const userReducer = (state = initialState, action: any) => {
isLogedIn: resp, isLogedIn: resp,
}; };
case userTypes.LOGIN: case userTypes.LOGIN:
AsyncStorage.setItem('dark', JSON.stringify(false)).then(() => {
console.log('La nouvelle clé et sa valeur ont été créées dans le localstorage');
});
console.log("++++++++++++++++++++++++++++++++++++++userRducer+++++++++++++++++++++++++++++3"); console.log("++++++++++++++++++++++++++++++++++++++userRducer+++++++++++++++++++++++++++++3");
console.log(action.playload, "LOOGGIIINN"); console.log(action.playload, "LOOGGIIINN");
console.log("++++++++++++++++++++++++++++++++++++++userRducer+++++++++++++++++++++++++++++3"); console.log("++++++++++++++++++++++++++++++++++++++userRducer+++++++++++++++++++++++++++++3");
return { return {
...state, ...state,
user: action.playload, user: action.playload,
isLogedIn: true failedLogin: false,
isLogedIn: true,
dark: false
}; };
case userTypes.SIGNUP: case userTypes.SIGNUP:
AsyncStorage.setItem('dark', JSON.stringify(false)).then(() => {
console.log('La nouvelle clé et sa valeur ont été créées dans le localstorage');
});
console.log("++++++++++++++++++++++++++++++++++++++userRducer+++++++++++++++++++++++++++++3"); console.log("++++++++++++++++++++++++++++++++++++++userRducer+++++++++++++++++++++++++++++3");
console.log(action.playload, "LOOGGIIINN"); console.log(action.playload, "SIGNNNNNUUUUPPPPPPP");
console.log("++++++++++++++++++++++++++++++++++++++userRducer+++++++++++++++++++++++++++++3"); console.log("++++++++++++++++++++++++++++++++++++++userRducer+++++++++++++++++++++++++++++3");
return { return {
...state, ...state,
user: action.playload, user: action.playload,
isLogedIn: true failedSignup: false,
isLogedIn: true,
dark: false
}; };
case userTypes.USER_LOGOUT: case userTypes.USER_LOGOUT:
AsyncStorage.removeItem('dark').then(() => {
console.log('La clé a été supprimée du localstorage');
});
return { return {
...state, ...state,
user: null, user: null,
@ -53,8 +69,12 @@ const userReducer = (state = initialState, action: any) => {
...state, ...state,
userSpotifyToken: action.playload, userSpotifyToken: action.playload,
}; };
case userTypes.CHANGE_ERROR_LOGIN:
return { ...state, failedLogin: true }
case userTypes.CHANGE_ERROR_SIGNUP:
return { ...state, failedSignup: true }
case userTypes.CHANGE_MODE: case userTypes.CHANGE_MODE:
return { ...state, dark: !state.dark } return { ...state, dark: action.playload }
default: default:
return state; return state;
} }

@ -4,57 +4,59 @@ import axios from "axios";
import { json } from "express"; import { json } from "express";
import { useEffect } from "react"; import { useEffect } from "react";
import { API_URL } from "../../fladConfig"; import { API_URL } from "../../fladConfig";
import { Credentials, CredentialsRegister, restoreToken, setLoginState, UserLogout, userChangeMode, userSignUp } from "../actions/userActions"; import { Credentials, CredentialsRegister, restoreToken, setLoginState, UserLogout, userChangeMode, userSignUp, ChangeErrorLogin, ChangeErrorSignup } from "../actions/userActions";
import * as SecureStore from 'expo-secure-store'; import * as SecureStore from 'expo-secure-store';
import { User } from "../../Model/User"; import { User } from "../../Model/User";
import { UserFactory } from "../../Model/factory/UserFactory"; import { UserFactory } from "../../Model/factory/UserFactory";
const key = 'userToken'; const key = 'userToken';
export const registerUser = ( resgisterCredential : CredentialsRegister) => { export const registerUser = (resgisterCredential: CredentialsRegister) => {
//@ts-ignore //@ts-ignore
return async dispatch => { return async dispatch => {
try { try {
console.log(resgisterCredential); console.log(resgisterCredential);
const config = { const config = {
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
}, },
} }
const resp = await axios.post( const resp = await axios.post(
`${API_URL}/api/users/register`, `${API_URL}/api/users/register`,
resgisterCredential, resgisterCredential,
config config
) )
if (resp.data.token) { if (resp.data.token) {
console.log(resp.data.token); console.log(resp.data.token);
const token = resp.data.token; const token = resp.data.token;
// await SecureStore.setItemAsync(key, token); // await SecureStore.setItemAsync(key, token);
const headers = { const headers = {
'Authorization': 'Bearer ' + token}; 'Authorization': 'Bearer ' + token
};
const user = await axios.get( const user = await axios.get(
"https://flad-api-production.up.railway.app/api/users", "https://flad-api-production.up.railway.app/api/users",
{headers} { headers }
) )
dispatch(userSignUp( UserFactory.JsonToModel(user.data) )); // our action is called here dispatch(userSignUp(UserFactory.JsonToModel(user.data))); // our action is called here
// console.log(user.data); // console.log(user.data);
// dispatch(setLoginState(user.data) ); // our action is called here // dispatch(setLoginState(user.data) ); // our action is called here
} else { } else {
console.log('Login Failed', 'Username or Password is incorrect'); console.log('Login Failed', 'Username or Password is incorrect');
} }
// if (resp.data.msg === 'success') { // response success checking logic could differ // if (resp.data.msg === 'success') { // response success checking logic could differ
// await SecureStore.setItemAsync(key, resp.data.token); // await SecureStore.setItemAsync(key, resp.data.token);
// dispatch(setLoginState(resp.data.user) ); // our action is called here // dispatch(setLoginState(resp.data.user) ); // our action is called here
// } else { // } else {
// console.log('Login Failed', 'Username or Password is incorrect'); // console.log('Login Failed', 'Username or Password is incorrect');
// } // }
} catch (error) { } catch (error) {
console.log('Error---------', error); console.log('Error---------', error);
dispatch(ChangeErrorSignup())
} }
} }
} }
@ -101,6 +103,7 @@ export const userLogin = (loginCredential: Credentials) => {
} }
} catch (error) { } catch (error) {
dispatch(ChangeErrorLogin())
console.log('Error---------', error); console.log('Error---------', error);
} }
} }
@ -146,11 +149,10 @@ export const DeleteToken = () => {
} }
} }
export const ChangeMode = () => { export const ChangeMode = (value: boolean) => {
//@ts-ignore //@ts-ignore
return async dispatch => { return async dispatch => {
dispatch(userChangeMode()); dispatch(userChangeMode(value));
await SecureStore.deleteItemAsync(key);
} }
} }

@ -6,5 +6,7 @@ export const userTypes = {
UPDATE_PROFILE_PICTURE: 'UPDATE_PROFILE_PICTURE', UPDATE_PROFILE_PICTURE: 'UPDATE_PROFILE_PICTURE',
USER_LOGOUT: 'USER_LOGOUT', USER_LOGOUT: 'USER_LOGOUT',
RESTORE_TOKEN: "RESTORE_TOKEN", RESTORE_TOKEN: "RESTORE_TOKEN",
CHANGE_MODE: "CHANGE_MODE" CHANGE_MODE: "CHANGE_MODE",
CHANGE_ERROR_LOGIN: "CHANGE_ERROR_LOGIN",
CHANGE_ERROR_SIGNUP: "CHANGE_ERROR_SIGNUP"
} }

@ -12,14 +12,14 @@ import { GraphicalCharterDark } from '../assets/GraphicalCharterDark';
import { GraphicalCharterLight } from '../assets/GraphicalCharterLight'; import { GraphicalCharterLight } from '../assets/GraphicalCharterLight';
export default function favoritePage() { export default function favoritePage() {
const dispatch = useDispatch();
//Dark Mode //Dark Mode
const isDark = useSelector(state => state.userReducer.dark); const isDark = useSelector(state => state.userReducer.dark);
const style = isDark ? GraphicalCharterLight : GraphicalCharterDark; const style = isDark ? GraphicalCharterDark : GraphicalCharterLight;
const navigation = useNavigation(); const navigation = useNavigation();
//@ts-ignore //@ts-ignore
const favoritesMusic = useSelector(state => state.appReducer.favoriteMusic); const favoritesMusic = useSelector(state => state.appReducer.favoriteMusic);
const dispatch = useDispatch();
const images = [ const images = [
{ id: 1, source: require('../assets/images/FLADYLove.png') }, { id: 1, source: require('../assets/images/FLADYLove.png') },
{ id: 2, source: require('../assets/images/FLADYStar.png') }, { id: 2, source: require('../assets/images/FLADYStar.png') },

@ -3,7 +3,7 @@ import { View, Image, StyleSheet, Text, ImageBackground, TextInput, TouchableWit
import { useNavigation } from "@react-navigation/native"; import { useNavigation } from "@react-navigation/native";
import normalize from '../components/Normalize'; import normalize from '../components/Normalize';
import { userLogin } from '../redux/thunk/authThunk'; import { userLogin } from '../redux/thunk/authThunk';
import { useDispatch } from 'react-redux'; import { useDispatch, useSelector } from 'react-redux';
import { Audio } from 'expo-av'; import { Audio } from 'expo-av';
import { Credentials } from '../redux/actions/userActions'; import { Credentials } from '../redux/actions/userActions';
@ -19,6 +19,8 @@ export default function loginPage() {
const [rememberMe, setRememberMe] = useState(false); const [rememberMe, setRememberMe] = useState(false);
const navigation = useNavigation(); const navigation = useNavigation();
const failedLogin = useSelector(state => state.userReducer.failedLogin);
const [username, setUsername] = useState(''); const [username, setUsername] = useState('');
const [password, setPassword] = useState(''); const [password, setPassword] = useState('');
async function playSound() { async function playSound() {
@ -56,14 +58,19 @@ export default function loginPage() {
</Text> </Text>
<Image source={require("../assets/icons/Logo_White_Flad.png")} style={styles.imageLogo} /> <Image source={require("../assets/icons/Logo_White_Flad.png")} style={styles.imageLogo} />
<Text style={styles.text}>SE CONNECTER</Text> <Text style={styles.text}>SE CONNECTER</Text>
<View> {failedLogin && (
<TextInput placeholder="Username" <Text style={styles.textError}>Email ou mot de passe incorrect!</Text>
)}
<View style={{ marginTop: 7 }}>
<TextInput placeholder="Email"
placeholderTextColor="#B8B4B8"
value={username} value={username}
onChangeText={setUsername} style={[styles.input, styles.shadow]} /> onChangeText={setUsername} style={[styles.input, styles.shadow]} />
<Image source={require('../assets/icons/icons/User.png')} style={styles.iconUser} /> <Image source={require('../assets/icons/icons/User.png')} style={styles.iconUser} />
</View> </View>
<View> <View>
<TextInput placeholder="Password" <TextInput placeholder="Password"
placeholderTextColor="#B8B4B8"
value={password} value={password}
onChangeText={setPassword} onChangeText={setPassword}
secureTextEntry style={[styles.input, styles.shadow]} /> secureTextEntry style={[styles.input, styles.shadow]} />
@ -118,6 +125,12 @@ const styles = StyleSheet.create({
height: normalize(100), height: normalize(100),
borderRadius: 21 borderRadius: 21
}, },
textError: {
fontSize: 15,
alignSelf: "center",
color: "red",
fontWeight: 'bold'
},
buttonImage: { buttonImage: {
width: normalize(46), width: normalize(46),
height: normalize(46), height: normalize(46),
@ -152,7 +165,7 @@ const styles = StyleSheet.create({
fontSize: normalize(29), fontSize: normalize(29),
alignSelf: 'center', alignSelf: 'center',
color: 'white', color: 'white',
marginBottom: 15 marginBottom: 8
}, },
shadow: { shadow: {
shadowColor: 'black', shadowColor: 'black',

@ -7,7 +7,7 @@ import * as AuthSession from 'expo-auth-session';
import * as WebBrowser from 'expo-web-browser'; import * as WebBrowser from 'expo-web-browser';
import { makeRedirectUri, useAuthRequest } from 'expo-auth-session'; import { makeRedirectUri, useAuthRequest } from 'expo-auth-session';
import { registerUser } from '../redux/thunk/authThunk'; import { registerUser } from '../redux/thunk/authThunk';
import { useDispatch } from 'react-redux'; import { useDispatch, useSelector } from 'react-redux';
import { Audio } from 'expo-av'; import { Audio } from 'expo-av';
import { CredentialsRegister } from '../redux/actions/userActions'; import { CredentialsRegister } from '../redux/actions/userActions';
import { Buffer } from 'buffer'; import { Buffer } from 'buffer';
@ -41,6 +41,8 @@ export default function InscriptionPage() {
const navigation = useNavigation(); const navigation = useNavigation();
const [spotifyToken, setSpotifyToken] = useState(''); const [spotifyToken, setSpotifyToken] = useState('');
const [spotifyID, setSpotifyIds] = useState('') const [spotifyID, setSpotifyIds] = useState('')
const failedSignup = useSelector(state => state.userReducer.failedSignup);
async function playSound() { async function playSound() {
console.log('Loading Sound'); console.log('Loading Sound');
const { sound } = await Audio.Sound.createAsync( const { sound } = await Audio.Sound.createAsync(
@ -238,20 +240,26 @@ export default function InscriptionPage() {
</Text> </Text>
<Image source={require("../assets/icons/Logo_White_Flad.png")} style={styles.imageLogo} /> <Image source={require("../assets/icons/Logo_White_Flad.png")} style={styles.imageLogo} />
<Text style={styles.text}>S'INSCRIRE</Text> <Text style={styles.text}>S'INSCRIRE</Text>
<View> {failedSignup && (
<Text style={styles.textError}>Email ou mot de passe incorrect!</Text>
)}
<View style={{ marginTop: 7 }}>
<TextInput style={[styles.input, styles.shadow]} placeholder="Username" <TextInput style={[styles.input, styles.shadow]} placeholder="Username"
placeholderTextColor="#B8B4B8"
value={username} value={username}
onChangeText={setUsername} /> onChangeText={setUsername} />
<Image source={require('../assets/icons/icons/User.png')} style={styles.iconUser} /> <Image source={require('../assets/icons/icons/User.png')} style={styles.iconUser} />
</View> </View>
<View> <View>
<TextInput style={[styles.input, styles.shadow]} placeholder="Email" <TextInput style={[styles.input, styles.shadow]} placeholder="Email"
placeholderTextColor="#B8B4B8"
value={email} value={email}
onChangeText={setEmail} /> onChangeText={setEmail} />
<Image source={require('../assets/icons/icons/lock.png')} style={styles.iconLock} /> <Image source={require('../assets/icons/icons/lock.png')} style={styles.iconLock} />
</View> </View>
<View> <View>
<TextInput style={[styles.input, styles.shadow]} placeholder="Password" <TextInput style={[styles.input, styles.shadow]} placeholder="Password"
placeholderTextColor="#B8B4B8"
value={password} secureTextEntry={true} value={password} secureTextEntry={true}
onChangeText={setPassword} /> onChangeText={setPassword} />
<Image source={require('../assets/icons/icons/lock.png')} style={styles.iconLock} /> <Image source={require('../assets/icons/icons/lock.png')} style={styles.iconLock} />
@ -307,6 +315,12 @@ const styles = StyleSheet.create({
height: normalize(100), height: normalize(100),
borderRadius: 21 borderRadius: 21
}, },
textError: {
fontSize: 15,
alignSelf: "center",
color: "red",
fontWeight: 'bold'
},
buttonImage: { buttonImage: {
width: normalize(46), width: normalize(46),
height: normalize(46), height: normalize(46),
@ -324,7 +338,7 @@ const styles = StyleSheet.create({
fontSize: normalize(29), fontSize: normalize(29),
alignSelf: 'center', alignSelf: 'center',
color: 'white', color: 'white',
marginBottom: 15 marginBottom: 8
}, },
textIntoButton: { textIntoButton: {
fontWeight: 'bold', fontWeight: 'bold',

@ -1,4 +1,5 @@
import React, { useEffect, useRef, useState } from 'react'; import React, { useEffect, useRef, useState } from 'react';
import AsyncStorage from '@react-native-async-storage/async-storage';
import { View, StyleSheet, Text, Image, TouchableWithoutFeedback, Keyboard, TouchableOpacity, SafeAreaView } from 'react-native'; import { View, StyleSheet, Text, Image, TouchableWithoutFeedback, Keyboard, TouchableOpacity, SafeAreaView } from 'react-native';
import { Svg, Path } from 'react-native-svg'; import { Svg, Path } from 'react-native-svg';
import { useNavigation } from "@react-navigation/native"; import { useNavigation } from "@react-navigation/native";
@ -32,11 +33,30 @@ export default function Setting() {
const currentMusic = useSelector(state => state.appReducer.userCurrentMusic); const currentMusic = useSelector(state => state.appReducer.userCurrentMusic);
//Dark Mode //Dark Mode
const isDark = useSelector(state => state.userReducer.dark); const [isDark, setIsDark] = useState(null);
const style = isDark ? GraphicalCharterLight : GraphicalCharterDark; useEffect(() => {
const retrieveDarkMode = async () => {
const darkModeValue = await AsyncStorage.getItem('dark');
if (darkModeValue !== null) {
setIsDark(JSON.parse(darkModeValue));
}
};
retrieveDarkMode();
}, []);
const style = isDark ? GraphicalCharterDark : GraphicalCharterLight;
const ChangeDarkMode = () => { async function ChangeDarkMode() {
dispatch(ChangeMode()) try {
const currentValue = await AsyncStorage.getItem('dark');
if (currentValue !== null) {
const newValue = JSON.stringify(!JSON.parse(currentValue));
await AsyncStorage.setItem('dark', newValue);
setIsDark(JSON.parse(newValue));
dispatch(ChangeMode(JSON.parse(newValue)))
}
} catch (error) {
console.log(`Une erreur s'est produite lors de la mise à jour de la valeur booléenne pour la clé 'dark': `, error);
}
} }
//Notification //Notification
@ -87,7 +107,7 @@ export default function Setting() {
}, },
inputSearch: { inputSearch: {
placeholderTextColor: 'red', placeholderTextColor: 'red',
color: 'white', color: style.Text,
width: normalize(350), width: normalize(350),
}, },
profil: { profil: {
@ -319,7 +339,7 @@ export default function Setting() {
</View> </View>
<View style={styles.musicActually}> <View style={styles.musicActually}>
<CardMusic image={currentMusic.image} title={currentMusic.title} description="PNL" /> <CardMusic image="{currentMusic.image}" title="{currentMusic.title}" description="PNL" />
<Image source={require("../assets/images/FladyShadow.png")} style={styles.mascot} /> <Image source={require("../assets/images/FladyShadow.png")} style={styles.mascot} />
</View> </View>

@ -1,4 +1,4 @@
import React, { useState, useRef } from 'react'; import React, { useState, useRef, useEffect } from 'react';
import { View, Text, StyleSheet, TouchableWithoutFeedback, Keyboard, ScrollView, Image } from 'react-native'; import { View, Text, StyleSheet, TouchableWithoutFeedback, Keyboard, ScrollView, Image } from 'react-native';
import { TextInput, TouchableOpacity } from 'react-native-gesture-handler'; import { TextInput, TouchableOpacity } from 'react-native-gesture-handler';
import { Svg, Path } from 'react-native-svg'; import { Svg, Path } from 'react-native-svg';
@ -11,6 +11,7 @@ import * as ImagePicker from 'expo-image-picker';
import { SafeAreaView } from 'react-native-safe-area-context'; import { SafeAreaView } from 'react-native-safe-area-context';
import { GraphicalCharterDark } from '../assets/GraphicalCharterDark'; import { GraphicalCharterDark } from '../assets/GraphicalCharterDark';
import { GraphicalCharterLight } from '../assets/GraphicalCharterLight'; import { GraphicalCharterLight } from '../assets/GraphicalCharterLight';
import AsyncStorage from '@react-native-async-storage/async-storage';
// @ts-ignore // @ts-ignore
const DismissKeyboard = ({ children }) => ( const DismissKeyboard = ({ children }) => (
@ -22,8 +23,17 @@ const DismissKeyboard = ({ children }) => (
export default function SettingProfil() { export default function SettingProfil() {
//Dark Mode //Dark Mode
const isDark = useSelector(state => state.userReducer.dark); const [isDark, setIsDark] = useState(null);
const style = isDark ? GraphicalCharterLight : GraphicalCharterDark; useEffect(() => {
const retrieveDarkMode = async () => {
const darkModeValue = await AsyncStorage.getItem('dark');
if (darkModeValue !== null) {
setIsDark(JSON.parse(darkModeValue));
}
};
retrieveDarkMode();
}, []);
const style = isDark ? GraphicalCharterDark : GraphicalCharterLight;
const [image, setImage] = useState(null); const [image, setImage] = useState(null);
const navigation = useNavigation(); const navigation = useNavigation();

Loading…
Cancel
Save