mmkv bug fix
This commit is contained in:
245
App.tsx
245
App.tsx
@@ -1,4 +1,5 @@
|
||||
// App.tsx
|
||||
import AsyncStorage from '@react-native-async-storage/async-storage';
|
||||
import { NavigationContainer } from '@react-navigation/native';
|
||||
import { createNativeStackNavigator } from '@react-navigation/native-stack';
|
||||
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
||||
@@ -7,18 +8,18 @@ import { navigationRef } from 'components/NavigationRef';
|
||||
import i18n from 'i18n/i18n';
|
||||
import React, { useEffect, useMemo, useRef, useState } from 'react';
|
||||
import { I18nextProvider } from 'react-i18next';
|
||||
import { Animated, Dimensions, LogBox, StatusBar, View } from 'react-native';
|
||||
import {
|
||||
Animated,
|
||||
Dimensions,
|
||||
LogBox,
|
||||
StatusBar,
|
||||
StyleSheet,
|
||||
View,
|
||||
} from 'react-native';
|
||||
import Toast from 'react-native-toast-message';
|
||||
import SplashScreen from './src/components/SplashScreen';
|
||||
|
||||
// Screens
|
||||
import {
|
||||
authEvents,
|
||||
getLanguage,
|
||||
getToken,
|
||||
loadInitialAuthData,
|
||||
storage,
|
||||
} from 'helpers/event';
|
||||
import Login from 'screens/auth/login/ui';
|
||||
import Confirm from 'screens/auth/login/ui/Confirm';
|
||||
import Register from 'screens/auth/registeration/ui';
|
||||
@@ -46,81 +47,137 @@ import PaymentQrCode from 'screens/wallet/successPayment/ui/PaymentQrCode';
|
||||
import Onboarding from 'screens/welcome/Onboarding';
|
||||
|
||||
LogBox.ignoreLogs([
|
||||
'Non-serializable values were found in the navigation state',
|
||||
'ViewPropTypes will be removed',
|
||||
// NOTE: I recommend NOT ignoring "Non-serializable values were found in the navigation state"
|
||||
// because it hides bugs that can cause crashes. Keep only if you understand the implications.
|
||||
]);
|
||||
|
||||
const Stack = createNativeStackNavigator();
|
||||
const screenWidth = Dimensions.get('window').width;
|
||||
const queryClient = new QueryClient();
|
||||
|
||||
// const saveNotification = async (remoteMessage: any) => {
|
||||
// try {
|
||||
// const stored = await AsyncStorage.getItem('notifications');
|
||||
// const notifications = stored ? JSON.parse(stored) : [];
|
||||
|
||||
// const newNotification = {
|
||||
// id: Date.now(),
|
||||
// title:
|
||||
// remoteMessage.notification?.title ||
|
||||
// remoteMessage.data?.title ||
|
||||
// 'Yangi bildirishnoma',
|
||||
// message:
|
||||
// remoteMessage.notification?.body ||
|
||||
// remoteMessage.data?.body ||
|
||||
// 'Matn yo‘q',
|
||||
// sentTime: remoteMessage.sentTime || Date.now(),
|
||||
// };
|
||||
|
||||
// await AsyncStorage.setItem(
|
||||
// 'notifications',
|
||||
// JSON.stringify([newNotification, ...notifications]),
|
||||
// );
|
||||
// } catch (e) {
|
||||
// console.error('Notification saqlashda xato:', e);
|
||||
// }
|
||||
// };
|
||||
|
||||
// async function onDisplayNotification(remoteMessage: any) {
|
||||
// const channelId = await notifee.createChannel({
|
||||
// id: 'default',
|
||||
// name: 'Umumiy bildirishnomalar',
|
||||
// sound: 'default',
|
||||
// importance: AndroidImportance.HIGH,
|
||||
// });
|
||||
|
||||
// await notifee.displayNotification({
|
||||
// title:
|
||||
// remoteMessage.notification?.title ||
|
||||
// remoteMessage.data?.title ||
|
||||
// 'Yangi xabar',
|
||||
// body:
|
||||
// remoteMessage.notification?.body ||
|
||||
// remoteMessage.data?.body ||
|
||||
// 'Matn yo‘q',
|
||||
// android: {
|
||||
// channelId,
|
||||
// largeIcon: 'ic_launcher_foreground',
|
||||
// sound: 'default',
|
||||
// pressAction: {
|
||||
// id: 'default',
|
||||
// },
|
||||
// },
|
||||
// });
|
||||
// }
|
||||
|
||||
// async function requestNotificationPermission() {
|
||||
// if (Platform.OS === 'android' && Platform.Version >= 33) {
|
||||
// const granted = await PermissionsAndroid.request(
|
||||
// PermissionsAndroid.PERMISSIONS.POST_NOTIFICATIONS,
|
||||
// );
|
||||
// console.log('POST_NOTIFICATIONS permission:', granted);
|
||||
// }
|
||||
// }
|
||||
|
||||
export default function App() {
|
||||
const [initialRoute, setInitialRoute] = useState<string | null>(null);
|
||||
const slideAnim = useRef(new Animated.Value(0)).current;
|
||||
const [isSplashVisible, setIsSplashVisible] = useState(true);
|
||||
const isMounted = useRef(false);
|
||||
const currentAnimation = useRef<Animated.CompositeAnimation | null>(null);
|
||||
const token = getToken();
|
||||
|
||||
useEffect(() => {
|
||||
loadInitialAuthData();
|
||||
}, []);
|
||||
// useEffect(() => {
|
||||
// requestNotificationPermission();
|
||||
|
||||
useEffect(() => {
|
||||
const logoutListener = () => {
|
||||
if (navigationRef.isReady()) {
|
||||
navigationRef.reset({
|
||||
index: 0,
|
||||
routes: [{ name: 'Login' }],
|
||||
});
|
||||
}
|
||||
};
|
||||
// const messagingInstance = getMessaging();
|
||||
|
||||
authEvents.on('logout', logoutListener);
|
||||
// const unsubscribe = onMessage(messagingInstance, async remoteMessage => {
|
||||
// console.log('Foreground message:', remoteMessage);
|
||||
// await saveNotification(remoteMessage);
|
||||
// await onDisplayNotification(remoteMessage);
|
||||
// });
|
||||
|
||||
return () => {
|
||||
authEvents.removeListener('logout', logoutListener);
|
||||
};
|
||||
}, []);
|
||||
// const unsubscribeOpened = onNotificationOpenedApp(
|
||||
// messagingInstance,
|
||||
// remoteMessage => {
|
||||
// console.log('Backgrounddan ochildi:', remoteMessage);
|
||||
// saveNotification(remoteMessage);
|
||||
// },
|
||||
// );
|
||||
|
||||
useEffect(() => {
|
||||
isMounted.current = true;
|
||||
return () => {
|
||||
isMounted.current = false;
|
||||
if (currentAnimation.current) {
|
||||
currentAnimation.current.stop();
|
||||
}
|
||||
};
|
||||
}, []);
|
||||
// (async () => {
|
||||
// const remoteMessage = await getInitialNotification(messagingInstance);
|
||||
// if (remoteMessage) {
|
||||
// console.log('Killeddan ochildi:', remoteMessage);
|
||||
// saveNotification(remoteMessage);
|
||||
// }
|
||||
// })();
|
||||
|
||||
// return () => {
|
||||
// unsubscribe();
|
||||
// unsubscribeOpened();
|
||||
// };
|
||||
// }, []);
|
||||
|
||||
useEffect(() => {
|
||||
const initializeApp = async () => {
|
||||
try {
|
||||
const seen = storage.getString('hasSeenOnboarding');
|
||||
const token = getToken();
|
||||
const lang = getLanguage();
|
||||
const [seen, token, lang] = await Promise.all([
|
||||
AsyncStorage.getItem('hasSeenOnboarding'),
|
||||
AsyncStorage.getItem('token'),
|
||||
|
||||
if (lang) {
|
||||
try {
|
||||
await i18n.changeLanguage(lang);
|
||||
} catch (e) {
|
||||
console.warn('i18n.changeLanguage failed:', e);
|
||||
}
|
||||
}
|
||||
AsyncStorage.getItem('language'),
|
||||
]);
|
||||
|
||||
if (lang) await i18n.changeLanguage(lang);
|
||||
|
||||
const initialRouteName = !seen
|
||||
? 'Onboarding'
|
||||
: token
|
||||
? 'Home'
|
||||
: 'select-auth';
|
||||
|
||||
if (isMounted.current) {
|
||||
setInitialRoute(initialRouteName);
|
||||
}
|
||||
setInitialRoute(initialRouteName);
|
||||
} catch (error) {
|
||||
console.error('App initialization error:', error);
|
||||
if (isMounted.current) setInitialRoute('select-auth');
|
||||
setInitialRoute('select-auth');
|
||||
}
|
||||
};
|
||||
|
||||
@@ -129,50 +186,52 @@ export default function App() {
|
||||
|
||||
const handleSplashFinish = useMemo(
|
||||
() => () => {
|
||||
// create animation and keep ref so we can stop it on unmount
|
||||
const animation = Animated.timing(slideAnim, {
|
||||
Animated.timing(slideAnim, {
|
||||
toValue: -screenWidth,
|
||||
duration: 600,
|
||||
useNativeDriver: true,
|
||||
});
|
||||
currentAnimation.current = animation;
|
||||
animation.start(() => {
|
||||
// ensure component still mounted before setting state
|
||||
if (isMounted.current) {
|
||||
setIsSplashVisible(false);
|
||||
}
|
||||
currentAnimation.current = null;
|
||||
});
|
||||
}).start(() => setIsSplashVisible(false));
|
||||
},
|
||||
[slideAnim],
|
||||
);
|
||||
|
||||
const handleOnboardingFinish = useMemo(
|
||||
() => async (navigation: any) => {
|
||||
try {
|
||||
storage.set('hasSeenOnboarding', 'true');
|
||||
} catch (e) {
|
||||
console.warn('Failed to set hasSeenOnboarding', e);
|
||||
}
|
||||
await AsyncStorage.setItem('hasSeenOnboarding', 'true');
|
||||
navigation.replace('select-auth');
|
||||
},
|
||||
[],
|
||||
);
|
||||
// const [firebaseToken, setFirebseToken] = useState<{
|
||||
// fcmToken: string;
|
||||
// deviceId: string;
|
||||
// deviceName: string;
|
||||
// } | null>();
|
||||
// const app = getApp();
|
||||
// const messaging = getMessaging(app);
|
||||
|
||||
if (!initialRoute || isSplashVisible || !currentAnimation) {
|
||||
return (
|
||||
<View
|
||||
style={{
|
||||
flex: 1,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
backgroundColor: '#ffff',
|
||||
}}
|
||||
>
|
||||
<SplashScreen onFinish={handleSplashFinish} />
|
||||
</View>
|
||||
);
|
||||
}
|
||||
// const getDeviceData = async () => {
|
||||
// try {
|
||||
// const fcmToken = await getToken(messaging);
|
||||
// return {
|
||||
// fcmToken,
|
||||
// deviceId: await DeviceInfo.getUniqueId(),
|
||||
// deviceName: await DeviceInfo.getDeviceName(),
|
||||
// };
|
||||
// } catch (e) {
|
||||
// console.log('Xato:', e);
|
||||
// return null;
|
||||
// }
|
||||
// };
|
||||
// console.log(firebaseToken);
|
||||
|
||||
// useEffect(() => {
|
||||
// getDeviceData().then(data => {
|
||||
// setFirebseToken(data);
|
||||
// });
|
||||
// }, []);
|
||||
|
||||
if (!initialRoute) return null;
|
||||
|
||||
return (
|
||||
<QueryClientProvider client={queryClient}>
|
||||
@@ -183,7 +242,7 @@ export default function App() {
|
||||
<Stack.Navigator
|
||||
screenOptions={{
|
||||
headerShown: false,
|
||||
animation: 'slide_from_right',
|
||||
animation: 'none',
|
||||
gestureEnabled: false,
|
||||
}}
|
||||
initialRouteName={initialRoute}
|
||||
@@ -214,6 +273,9 @@ export default function App() {
|
||||
<Stack.Screen name="PaymentQrCode" component={PaymentQrCode} />
|
||||
<Stack.Screen name="Profile" component={Profile} />
|
||||
<Stack.Screen name="Settings" component={Settings} />
|
||||
{/* {Platform.OS === 'android' && (
|
||||
<Stack.Screen name="Notifications" component={Notifications} />
|
||||
)} */}
|
||||
<Stack.Screen name="Warehouses" component={Warehouses} />
|
||||
<Stack.Screen name="Support" component={Support} />
|
||||
<Stack.Screen name="ListBranches" component={ListBranches} />
|
||||
@@ -229,6 +291,19 @@ export default function App() {
|
||||
</Stack.Navigator>
|
||||
</NavigationContainer>
|
||||
|
||||
{/* Splash transition */}
|
||||
{isSplashVisible && (
|
||||
<Animated.View
|
||||
style={{
|
||||
...StyleSheet.absoluteFillObject,
|
||||
transform: [{ translateX: slideAnim }],
|
||||
zIndex: 10,
|
||||
}}
|
||||
>
|
||||
<SplashScreen onFinish={handleSplashFinish} />
|
||||
</Animated.View>
|
||||
)}
|
||||
|
||||
<Toast config={toastConfig} />
|
||||
</View>
|
||||
</I18nextProvider>
|
||||
|
||||
13
package-lock.json
generated
13
package-lock.json
generated
@@ -37,7 +37,7 @@
|
||||
"react-native-linear-gradient": "^2.8.3",
|
||||
"react-native-localize": "^3.5.1",
|
||||
"react-native-mask-input": "^1.2.3",
|
||||
"react-native-mmkv": "^4.0.1",
|
||||
"react-native-mmkv": "^2.2.4",
|
||||
"react-native-modal": "^14.0.0-rc.1",
|
||||
"react-native-nitro-modules": "^0.31.10",
|
||||
"react-native-push-notification": "^8.1.1",
|
||||
@@ -13146,14 +13146,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/react-native-mmkv": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/react-native-mmkv/-/react-native-mmkv-4.0.1.tgz",
|
||||
"integrity": "sha512-0JjO0U33b2hngFACsGwxoMCOZlCChP6R42aqvU85kXBaxY/kltSYr0FW9T6lkU3uEkE4IWMV1eLjoJplEY920w==",
|
||||
"license": "MIT",
|
||||
"version": "2.12.2",
|
||||
"resolved": "https://registry.npmjs.org/react-native-mmkv/-/react-native-mmkv-2.12.2.tgz",
|
||||
"integrity": "sha512-6058Aq0p57chPrUutLGe9fYoiDVDNMU2PKV+lLFUJ3GhoHvUrLdsS1PDSCLr00yqzL4WJQ7TTzH+V8cpyrNcfg==",
|
||||
"license": "(MIT AND BSD-3-Clause)",
|
||||
"peerDependencies": {
|
||||
"react": "*",
|
||||
"react-native": "*",
|
||||
"react-native-nitro-modules": "*"
|
||||
"react-native": ">=0.71.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react-native-modal": {
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
"react-native-linear-gradient": "^2.8.3",
|
||||
"react-native-localize": "^3.5.1",
|
||||
"react-native-mask-input": "^1.2.3",
|
||||
"react-native-mmkv": "^4.0.1",
|
||||
"react-native-mmkv": "^2.2.4",
|
||||
"react-native-modal": "^14.0.0-rc.1",
|
||||
"react-native-nitro-modules": "^0.31.10",
|
||||
"react-native-push-notification": "^8.1.1",
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
// axiosInstance
|
||||
import axios from 'axios';
|
||||
import { authEvents, getLanguage, getToken, setToken } from 'helpers/event';
|
||||
|
||||
let isLoggingOut = false;
|
||||
import AsyncStorage from '@react-native-async-storage/async-storage';
|
||||
import axios, { AxiosError } from 'axios';
|
||||
import { navigate } from 'components/NavigationRef';
|
||||
|
||||
const axiosInstance = axios.create({
|
||||
baseURL: 'https://api.cpcargo.uz/api/v1',
|
||||
@@ -12,38 +10,30 @@ const axiosInstance = axios.create({
|
||||
},
|
||||
});
|
||||
|
||||
axiosInstance.interceptors.request.use(config => {
|
||||
const token = getToken();
|
||||
const lang = getLanguage();
|
||||
|
||||
axiosInstance.interceptors.request.use(async config => {
|
||||
// Tokenni olish
|
||||
const token = await AsyncStorage.getItem('token');
|
||||
if (token) {
|
||||
config.headers.Authorization = `Bearer ${token}`;
|
||||
}
|
||||
|
||||
if (lang) {
|
||||
config.headers['Accept-Language'] = lang;
|
||||
// Language’ni olish
|
||||
const language = await AsyncStorage.getItem('language');
|
||||
if (language) {
|
||||
config.headers['Accept-Language'] = language;
|
||||
}
|
||||
|
||||
return config;
|
||||
});
|
||||
|
||||
axiosInstance.interceptors.response.use(
|
||||
res => res,
|
||||
err => {
|
||||
const status = err.response?.status;
|
||||
|
||||
if (status === 401 && !isLoggingOut) {
|
||||
isLoggingOut = true;
|
||||
|
||||
setToken(null);
|
||||
authEvents.emit('logout');
|
||||
|
||||
setTimeout(() => {
|
||||
isLoggingOut = false;
|
||||
}, 500);
|
||||
response => response,
|
||||
async (error: AxiosError) => {
|
||||
if (error.response?.status === 401) {
|
||||
await AsyncStorage.removeItem('token');
|
||||
navigate('Login');
|
||||
}
|
||||
|
||||
return Promise.reject(err);
|
||||
return Promise.reject(error);
|
||||
},
|
||||
);
|
||||
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
// helpers/event.ts
|
||||
import { EventEmitter } from 'events';
|
||||
import { createMMKV } from 'react-native-mmkv';
|
||||
|
||||
export const authEvents = new EventEmitter();
|
||||
|
||||
export const enum AUTH {
|
||||
USER = 'user',
|
||||
AUTH = 'auth',
|
||||
}
|
||||
|
||||
// MMKV instance
|
||||
export const storage = createMMKV();
|
||||
|
||||
// Memory cache
|
||||
let tokenCache: string | null = null;
|
||||
let languageCache: string | null = null;
|
||||
|
||||
// Load on app start (synchronous)
|
||||
export function loadInitialAuthData() {
|
||||
tokenCache = storage.getString('token') || null;
|
||||
languageCache = storage.getString('language') || null;
|
||||
}
|
||||
|
||||
export function getToken() {
|
||||
return storage.getString('token');
|
||||
}
|
||||
|
||||
export function setToken(token: string | null) {
|
||||
tokenCache = token;
|
||||
if (token) {
|
||||
storage.set('token', token);
|
||||
} else {
|
||||
storage.remove('token');
|
||||
}
|
||||
}
|
||||
|
||||
export function saveAuth() {
|
||||
storage.set('user', AUTH.USER);
|
||||
}
|
||||
|
||||
export function removeAuth() {
|
||||
storage.set('user', AUTH.AUTH);
|
||||
}
|
||||
|
||||
export function getAuth() {
|
||||
storage.getString('user');
|
||||
}
|
||||
|
||||
export function getLanguage() {
|
||||
return languageCache;
|
||||
}
|
||||
|
||||
export function setLanguage(lang: string) {
|
||||
languageCache = lang;
|
||||
storage.set('language', lang);
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import AsyncStorage from '@react-native-async-storage/async-storage';
|
||||
import { useNavigation } from '@react-navigation/native';
|
||||
import { NativeStackNavigationProp } from '@react-navigation/native-stack';
|
||||
import { useMutation } from '@tanstack/react-query';
|
||||
@@ -5,7 +6,6 @@ import { authApi } from 'api/auth';
|
||||
import { otpPayload, resendPayload } from 'api/auth/type';
|
||||
import AppText from 'components/AppText';
|
||||
import ErrorNotification from 'components/ErrorNotification';
|
||||
import { saveAuth, setToken } from 'helpers/event';
|
||||
import formatPhone from 'helpers/formatPhone';
|
||||
import React, { useEffect, useRef, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
@@ -77,12 +77,8 @@ const Confirm = () => {
|
||||
const { mutate, isPending } = useMutation({
|
||||
mutationFn: (payload: otpPayload) => authApi.verifyOtp(payload),
|
||||
onSuccess: async res => {
|
||||
setToken(res.data.accessToken);
|
||||
saveAuth();
|
||||
navigation.reset({
|
||||
index: 0,
|
||||
routes: [{ name: 'Home' }], // login sahifasiga qaytarish
|
||||
});
|
||||
await AsyncStorage.setItem('token', res.data.accessToken);
|
||||
navigation.navigate('Home');
|
||||
setVisible(false);
|
||||
},
|
||||
onError: (err: any) => {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import AsyncStorage from '@react-native-async-storage/async-storage';
|
||||
// import { getApp } from '@react-native-firebase/app';
|
||||
// import { getMessaging, getToken } from '@react-native-firebase/messaging';
|
||||
import { useNavigation } from '@react-navigation/native';
|
||||
@@ -7,7 +8,6 @@ import { authApi } from 'api/auth';
|
||||
import { otpPayload, resendPayload } from 'api/auth/type';
|
||||
import AppText from 'components/AppText';
|
||||
import ErrorNotification from 'components/ErrorNotification';
|
||||
import { setToken } from 'helpers/event';
|
||||
import formatPhone from 'helpers/formatPhone';
|
||||
import React, { useRef, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
@@ -83,11 +83,8 @@ const Confirm = ({
|
||||
const { mutate, isPending } = useMutation({
|
||||
mutationFn: (payload: otpPayload) => authApi.verifyOtp(payload),
|
||||
onSuccess: async res => {
|
||||
setToken(res.data.accessToken);
|
||||
navigation.reset({
|
||||
index: 0,
|
||||
routes: [{ name: 'Home' }], // login sahifasiga qaytarish
|
||||
});
|
||||
await AsyncStorage.setItem('token', res.data.accessToken);
|
||||
navigation.navigate('Confirm');
|
||||
setErrorConfirm(null);
|
||||
},
|
||||
onError: (err: any) => {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import AsyncStorage from '@react-native-async-storage/async-storage';
|
||||
import { useNavigation } from '@react-navigation/native';
|
||||
import { NativeStackNavigationProp } from '@react-navigation/native-stack';
|
||||
import AppText from 'components/AppText';
|
||||
import { removeAuth, setToken } from 'helpers/event';
|
||||
import * as React from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import {
|
||||
@@ -36,8 +36,7 @@ const ProfilePages = (props: componentNameProps) => {
|
||||
style: 'destructive',
|
||||
onPress: async () => {
|
||||
try {
|
||||
setToken('');
|
||||
removeAuth();
|
||||
await AsyncStorage.removeItem('token');
|
||||
navigation.reset({
|
||||
index: 0,
|
||||
routes: [{ name: 'Login' }], // login sahifasiga qaytarish
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import AsyncStorage from '@react-native-async-storage/async-storage';
|
||||
import AnimatedScreen from 'components/AnimatedScreen';
|
||||
import { getLanguage, storage } from 'helpers/event';
|
||||
import { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import FirstStep from 'screens/welcome/FirstStep';
|
||||
import SecondStep from 'screens/welcome/SecondStep';
|
||||
@@ -17,7 +17,7 @@ const Onboarding = ({ onFinish }: OnboardingProps) => {
|
||||
|
||||
useEffect(() => {
|
||||
const loadLang = async () => {
|
||||
const savedLang = getLanguage();
|
||||
const savedLang = await AsyncStorage.getItem('selectedLanguage');
|
||||
if (savedLang === 'ru' || savedLang === 'uz') {
|
||||
setLang(savedLang);
|
||||
setStep(1);
|
||||
@@ -30,7 +30,7 @@ const Onboarding = ({ onFinish }: OnboardingProps) => {
|
||||
if (step < 3) {
|
||||
setStep(step + 1);
|
||||
} else {
|
||||
storage.set('hasSeenOnboarding', 'true');
|
||||
await AsyncStorage.setItem('hasSeenOnboarding', 'true');
|
||||
onFinish();
|
||||
}
|
||||
}, [step, onFinish]);
|
||||
|
||||
Reference in New Issue
Block a user