From 76f06d79483f28c8c227c7466886d6f32ed77ca8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Baumruck?= Date: Tue, 2 Apr 2024 09:32:49 +0200 Subject: [PATCH 1/6] add refresh token logic --- .../(tabs)/example/user-session.tsx | 3 + package.json | 1 + src/api/axios/interceptors/injectToken.ts | 4 +- src/constants/asyncStorageKeys.ts | 1 + src/hooks/forms/useSignInForm.ts | 4 +- src/i18n/translations/en.json | 1 + src/i18n/translations/pl.json | 9 ++- src/screens/ExamplesScreen.tsx | 4 + src/screens/UserSessionScreen.tsx | 50 +++++++++++++ src/screens/index.ts | 1 + src/services/TokenService.ts | 73 +++++++++++++++++-- src/store/global.ts | 5 ++ src/store/index.ts | 1 + src/utils/decodeAccessToken.ts | 16 ++++ src/utils/index.ts | 3 +- yarn.lock | 5 ++ 16 files changed, 165 insertions(+), 16 deletions(-) create mode 100644 app/(app)/(authorized)/(tabs)/example/user-session.tsx create mode 100644 src/screens/UserSessionScreen.tsx create mode 100644 src/store/global.ts create mode 100644 src/utils/decodeAccessToken.ts diff --git a/app/(app)/(authorized)/(tabs)/example/user-session.tsx b/app/(app)/(authorized)/(tabs)/example/user-session.tsx new file mode 100644 index 00000000..efc8b2df --- /dev/null +++ b/app/(app)/(authorized)/(tabs)/example/user-session.tsx @@ -0,0 +1,3 @@ +import { UserSessionScreen } from '@baca/screens' + +export default UserSessionScreen diff --git a/package.json b/package.json index 193ee4a8..73ddd681 100644 --- a/package.json +++ b/package.json @@ -133,6 +133,7 @@ "expo-web-browser": "~12.8.2", "i18next": "^23.7.20", "jotai": "^2.4.3", + "jwt-decode": "^4.0.0", "moti": "^0.25.3", "react": "18.2.0", "react-dom": "18.2.0", diff --git a/src/api/axios/interceptors/injectToken.ts b/src/api/axios/interceptors/injectToken.ts index c30485c2..19a49fa6 100644 --- a/src/api/axios/interceptors/injectToken.ts +++ b/src/api/axios/interceptors/injectToken.ts @@ -6,8 +6,8 @@ export const injectTokenToRequest = async ( ): Promise> => { const token = await getToken() - if (token) { - config.headers['Authorization'] = `Bearer ${token}` + if (token?.accessToken) { + config.headers['Authorization'] = `Bearer ${token.accessToken}` } return config diff --git a/src/constants/asyncStorageKeys.ts b/src/constants/asyncStorageKeys.ts index fc992ab4..2f6dcd01 100644 --- a/src/constants/asyncStorageKeys.ts +++ b/src/constants/asyncStorageKeys.ts @@ -4,6 +4,7 @@ export const ASYNC_STORAGE_KEYS = { NEXT_DEEP_LINK: '@navigation/next_deeplink', PUSH_TOKEN: '@notification/push-token', USER_LANGUAGE: '@language/user-language', + USER_REFRESH_TOKEN: 'user_refresh_token', // This value is used in `expo-secure-store` package and it can't include '@' and '/' USER_TOKEN: 'user_token', // This value is used in `expo-secure-store` package and it can't include '@' and '/' WAS_PUSH_TOKEN_SEND: '@notification/was-push-token-send', } as const diff --git a/src/hooks/forms/useSignInForm.ts b/src/hooks/forms/useSignInForm.ts index bddc2f77..153794c4 100644 --- a/src/hooks/forms/useSignInForm.ts +++ b/src/hooks/forms/useSignInForm.ts @@ -55,7 +55,9 @@ export const useSignInForm = () => { hapticImpact() }, onSuccess: async (response) => { - await setToken(response.accessToken) + const { user, ...token } = response + await setToken(token) + setIsSignedIn(true) // Send push token to backend diff --git a/src/i18n/translations/en.json b/src/i18n/translations/en.json index bd4cd7b4..ddb68190 100644 --- a/src/i18n/translations/en.json +++ b/src/i18n/translations/en.json @@ -175,6 +175,7 @@ "go_to_screen_with_BEdata": "Go to screen with data from BE", "go_to_settings": "Go to Settings", "go_to_typography": "Go to Typography", + "go_to_user_session": "Go to user session", "header": "This is Example screen" }, "forgot_password_screen": { diff --git a/src/i18n/translations/pl.json b/src/i18n/translations/pl.json index 3bb7e16a..d2056b37 100644 --- a/src/i18n/translations/pl.json +++ b/src/i18n/translations/pl.json @@ -166,15 +166,16 @@ "awesome": "Wspaniale 🎉" }, "examples_screen": { - "header": "To jest przykładowy widok", "go_to_application_info": "Idź do ApplicationInfo", "go_to_colors": "Idź do Kolorów", "go_to_components": "Idź do Komponentów", - "go_to_typography": "Idź do Typografii", "go_to_home_stack_details": "Idź do HomeStackDetails", - "go_to_settings": "Idź do Ustawień", + "go_to_screen_test_form": "Idź do formularza testowego", "go_to_screen_with_BEdata": "Idź do widoku z danymi z backend-u", - "go_to_screen_test_form": "Idź do formularza testowego" + "go_to_settings": "Idź do Ustawień", + "go_to_typography": "Idź do Typografii", + "go_to_user_session": "Idź do sesji użytkowania", + "header": "To jest przykładowy widok" }, "forgot_password_screen": { "back_to_login": "Wróć do logowania", diff --git a/src/screens/ExamplesScreen.tsx b/src/screens/ExamplesScreen.tsx index 1434b48c..8b493f66 100644 --- a/src/screens/ExamplesScreen.tsx +++ b/src/screens/ExamplesScreen.tsx @@ -16,6 +16,7 @@ export const ExamplesScreen = () => { const goToTypography = useCallback(() => push('/example/typography'), [push]) const goToCityListScreen_EXAMPLE = useCallback(() => push('/example/data-from-be'), [push]) const goToTestForm = useCallback(() => push('/example/test-form'), [push]) + const goToUserSession = useCallback(() => push('/example/user-session'), [push]) const goToHomeStackDetails = useCallback(() => push('/home/details'), [push]) @@ -42,6 +43,9 @@ export const ExamplesScreen = () => { + ) } diff --git a/src/screens/UserSessionScreen.tsx b/src/screens/UserSessionScreen.tsx new file mode 100644 index 00000000..fc355ed6 --- /dev/null +++ b/src/screens/UserSessionScreen.tsx @@ -0,0 +1,50 @@ +import { useAuthControllerMe } from '@baca/api/query/auth/auth' +import { Box, Button, ScrollView, Text } from '@baca/design-system' +import { Token, getToken } from '@baca/services' +import { isRefreshingTokenAtom } from '@baca/store' +import { useAtomValue } from 'jotai' +import { useCallback, useEffect, useState } from 'react' + +export const UserSessionScreen = () => { + const isRefreshing = useAtomValue(isRefreshingTokenAtom) + const { data, refetch, isInitialLoading, isRefetching } = useAuthControllerMe({ + query: { enabled: false }, + }) + + const [token1, setToken] = useState(null) + + const fetchToken = useCallback(async () => { + const token = await getToken() + if (token) { + setToken(token) + } + }, []) + + const fetchUser = useCallback(async () => { + await refetch() + }, [refetch]) + + useEffect(() => { + fetchToken() + }, [fetchToken]) + + return ( + + + User data: + + Is fetching user data: + {JSON.stringify(isInitialLoading || isRefetching, null, 10)} + + {JSON.stringify(data, null, 10)} + +