AuthProvider.tsx 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. import { ReactNode, createContext, useEffect, useState } from 'react';
  2. import { useContext } from 'react';
  3. import { router, useSegments } from 'expo-router';
  4. import * as SecureStore from 'expo-secure-store';
  5. import axios from 'axios';
  6. import { EXPO_PUBLIC_API_URL } from '@env';
  7. import { User } from '../types/user';
  8. import { authenticationService } from '../service/authService';
  9. type AuthProvider = {
  10. user: User | null;
  11. login: (username: string, password: string, isBinding: boolean) => Promise<boolean>;
  12. logout: () => void;
  13. setUser: React.Dispatch<React.SetStateAction<User | null>>;
  14. };
  15. function useProtectedRoute(user: User | null) {
  16. const segments = useSegments();
  17. const isUserEmpty = (user: User | null): boolean => {
  18. return !user || Object.values(user).every((value) => value === undefined);
  19. };
  20. useEffect(() => {
  21. if (!segments.length) return;
  22. // console.log('Current segment:', segments[0]);
  23. // console.log('Is user empty?', isUserEmpty(user));
  24. const inAuthGroup = segments[0] === '(auth)';
  25. const inPublicGroup = segments[0] === '(public)';
  26. // console.log('In auth group?', inAuthGroup);
  27. if (isUserEmpty(user) && !inPublicGroup) {
  28. router.replace('/login');
  29. } else if (!isUserEmpty(user) && inPublicGroup) {
  30. router.replace('/(auth)/(tabs)/(home)/mainPage');
  31. }
  32. }, [user, segments]);
  33. }
  34. export const AuthContext = createContext<AuthProvider>({
  35. user: null,
  36. login: async () => false,
  37. logout: () => {},
  38. setUser: () => {}
  39. });
  40. export function useAuth() {
  41. const context = useContext(AuthContext);
  42. if (!context) {
  43. throw new Error('useAuth must be used within a <AuthProvider />');
  44. }
  45. return context;
  46. }
  47. export default function AuthProvider({ children }: { children: ReactNode }) {
  48. const [user, setUser] = useState<User | null>(null);
  49. useEffect(() => {
  50. const checkToken = async () => {
  51. const token = await SecureStore.getItemAsync('accessToken');
  52. if (token) {
  53. const userInfo = await getUserFromAccessToken();
  54. if (userInfo) {
  55. setUser(userInfo);
  56. }
  57. }
  58. };
  59. checkToken();
  60. }, []);
  61. const login = async (username: string, password: string, isBinding: boolean) => {
  62. try {
  63. const result = await authenticationService.phoneLogin(username, password, isBinding);
  64. if (result === 'login successful') {
  65. const token = await SecureStore.getItemAsync('accessToken');
  66. if (token) {
  67. const userInfo = await getUserFromAccessToken();
  68. if (userInfo) {
  69. setUser(userInfo);
  70. return 'login successful';
  71. }
  72. }
  73. return 'login successful';
  74. } else {
  75. return result;
  76. }
  77. } catch (error) {
  78. console.error('Login error:', error);
  79. return error;
  80. }
  81. };
  82. //this is urgent login, only for testing & debugging
  83. // const login = async (username: string, password: string, isBinding: boolean) => {
  84. // try {
  85. // const loggedInUser = {
  86. // accessToken:
  87. // 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoiY3VzdG9tZXIiLCJjcmVhdGVkQXQiOiIyMDI0LTA5LTAzVDA2OjM4OjU3LjI5NloiLCJ1cGRhdGVkQXQiOiIyMDI0LTEyLTAyVDE3OjUwOjQyLjI1MloiLCJpZCI6IjA2ZTRkNjU0LTliNDEtNDExMy1hZjBmLTE5OTIzYjc0YzEwZSIsImZpcnN0bmFtZSI6bnVsbCwibGFzdG5hbWUiOm51bGwsIm5pY2tuYW1lIjoiVGVzdCAyIiwiZW1haWwiOiJ0ZXN0MkBnbWFpbC5jb20iLCJwaG9uZSI6NjgxMDAxMTYsImljX2NhcmQiOiIwMDAwMDAwMDAwMDAxNDk2Iiwid2FsbGV0Ijo5NzYwLCJpY29uX3VybCI6bnVsbCwicmVtYXJrIjpudWxsLCJhZGRyZXNzIjpudWxsLCJzdGF0dXNfZmsiOiIxIiwiZ2VuZGVyIjoibWFuIiwiYmlydGhkYXkiOiIwNC8wNi8xMSIsImljX2Nhcl9pZCI6bnVsbCwiaWF0IjoxNzMzMTkyNjgzLCJleHAiOjE3MzMxOTk4ODN9.1VvQacR5SJ1JiRlnmy_m5rcrKN8wXsPTZ9_QLas8CEQ',
  88. // refreshToken:
  89. // 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoiY3VzdG9tZXIiLCJjcmVhdGVkQXQiOiIyMDI0LTA5LTAzVDA2OjM4OjU3LjI5NloiLCJ1cGRhdGVkQXQiOiIyMDI0LTEyLTAyVDE3OjUwOjQyLjI1MloiLCJpZCI6IjA2ZTRkNjU0LTliNDEtNDExMy1hZjBmLTE5OTIzYjc0YzEwZSIsImZpcnN0bmFtZSI6bnVsbCwibGFzdG5hbWUiOm51bGwsIm5pY2tuYW1lIjoiVGVzdCAyIiwiZW1haWwiOiJ0ZXN0MkBnbWFpbC5jb20iLCJwaG9uZSI6NjgxMDAxMTYsImljX2NhcmQiOiIwMDAwMDAwMDAwMDAxNDk2Iiwid2FsbGV0Ijo5NzYwLCJpY29uX3VybCI6bnVsbCwicmVtYXJrIjpudWxsLCJhZGRyZXNzIjpudWxsLCJzdGF0dXNfZmsiOiIxIiwiZ2VuZGVyIjoibWFuIiwiYmlydGhkYXkiOiIwNC8wNi8xMSIsImljX2Nhcl9pZCI6bnVsbCwiaWF0IjoxNzMzMTkyMjY5LCJleHAiOjE3MzY2NDgyNjl9.OrZqQyLkHL0eojesrn3xqoxIYatanjCX-GyXTcmNoys'
  90. // };
  91. // if (loggedInUser) {
  92. // //this is only for urgent login, uncomment getItemAsync after
  93. // await SecureStore.setItemAsync('accessToken', loggedInUser.accessToken);
  94. // const token = await SecureStore.getItemAsync('accessToken');
  95. // if (token) {
  96. // const userInfo = await getUserFromAccessToken();
  97. // if (userInfo) {
  98. // console.log('userInfouserInfouserInfouserInfouserInfouserInfo', userInfo);
  99. // setUser(userInfo);
  100. // }
  101. // }
  102. // return true;
  103. // } else {
  104. // return false;
  105. // }
  106. // } catch (error) {
  107. // console.error('Login error:', error);
  108. // return false;
  109. // }
  110. // };
  111. const getUserFromAccessToken = async () => {
  112. const token = await SecureStore.getItemAsync('accessToken');
  113. try {
  114. const res = await axios.get(`${EXPO_PUBLIC_API_URL}/clients/customer`, {
  115. headers: {
  116. Authorization: `Bearer ${token}`
  117. }
  118. });
  119. const items = {
  120. address: res.data.address,
  121. birthday: res.data.birthday,
  122. gender: res.data.gender,
  123. email: res.data.email,
  124. nickname: res.data.nickname,
  125. phone: res.data.phone,
  126. car: res.data.defaultCar.license_plate
  127. };
  128. return items;
  129. } catch (error) {
  130. console.error('GetUser Error:', error);
  131. }
  132. };
  133. const logout = async () => {
  134. try {
  135. await authenticationService.logout();
  136. await SecureStore.deleteItemAsync('accessToken');
  137. setUser(null);
  138. router.replace('/login');
  139. } catch (error) {
  140. console.log('error during logout', error);
  141. }
  142. };
  143. // console.log('user', user);
  144. useProtectedRoute(user);
  145. return <AuthContext.Provider value={{ user, login, logout, setUser }}>{children}</AuthContext.Provider>;
  146. }