AuthProvider.tsx 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  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. // 添加状态跟踪根布局是否已挂载
  18. const [isLayoutMounted, setIsLayoutMounted] = useState(false);
  19. const isUserEmpty = (user: User | null): boolean => {
  20. return !user || Object.values(user).every((value) => value === undefined);
  21. };
  22. useEffect(() => {
  23. // 标记根布局已挂载
  24. setIsLayoutMounted(true);
  25. }, []);
  26. useEffect(() => {
  27. // 等待根布局挂载完成且路由段准备好
  28. if (!isLayoutMounted || !segments.length) return;
  29. const inAuthGroup = segments[0] === '(auth)';
  30. const inPublicGroup = segments[0] === '(public)';
  31. if (isUserEmpty(user) && !inPublicGroup) {
  32. router.replace('/login');
  33. } else if (!isUserEmpty(user) && inPublicGroup) {
  34. router.replace('/(auth)/(tabs)/(home)/mainPage');
  35. }
  36. }, [user, segments, isLayoutMounted]); // 添加 isLayoutMounted 依赖
  37. }
  38. export const AuthContext = createContext<AuthProvider>({
  39. user: null,
  40. login: async () => false,
  41. logout: () => {},
  42. setUser: () => {}
  43. });
  44. export function useAuth() {
  45. const context = useContext(AuthContext);
  46. if (!context) {
  47. throw new Error('useAuth must be used within a <AuthProvider />');
  48. }
  49. return context;
  50. }
  51. export default function AuthProvider({ children }: { children: ReactNode }) {
  52. const [user, setUser] = useState<User | null>(null);
  53. useEffect(() => {
  54. const checkToken = async () => {
  55. const token = await SecureStore.getItemAsync('accessToken');
  56. if (token) {
  57. const userInfo = await getUserFromAccessToken();
  58. if (userInfo) {
  59. setUser(userInfo);
  60. }
  61. }
  62. };
  63. checkToken();
  64. }, []);
  65. const login = async (username: string, password: string, isBinding: boolean) => {
  66. try {
  67. const result = await authenticationService.phoneLogin(username, password, isBinding);
  68. if (result === 'login successful') {
  69. const token = await SecureStore.getItemAsync('accessToken');
  70. if (token) {
  71. const userInfo = await getUserFromAccessToken();
  72. if (userInfo) {
  73. setUser(userInfo);
  74. return 'login successful';
  75. }
  76. }
  77. return 'login successful';
  78. } else {
  79. return result;
  80. }
  81. } catch (error) {
  82. console.error('Login error:', error);
  83. return error;
  84. }
  85. };
  86. const getUserFromAccessToken = async () => {
  87. SecureStore.getItemAsync('accessToken').then((aa) => {
  88. console.log('sssssss:', aa);
  89. });
  90. const token = await SecureStore.getItemAsync('accessToken');
  91. try {
  92. const res = await axios.get(`${EXPO_PUBLIC_API_URL}/clients/customer`, {
  93. headers: {
  94. Authorization: `Bearer ${token}`
  95. }
  96. });
  97. const items = {
  98. address: res.data.address,
  99. birthday: res.data.birthday,
  100. gender: res.data.gender,
  101. email: res.data.email,
  102. nickname: res.data.nickname,
  103. phone: res.data.phone,
  104. car: res.data?.defaultCar?.license_plate
  105. };
  106. return items;
  107. } catch (error) {
  108. console.error('GetUser Error:', error);
  109. }
  110. };
  111. const logout = async () => {
  112. try {
  113. await authenticationService.logout();
  114. await SecureStore.deleteItemAsync('accessToken');
  115. setUser(null);
  116. router.replace('/login');
  117. } catch (error) {
  118. console.log('error during logout', error);
  119. }
  120. };
  121. // console.log('user', user);
  122. useProtectedRoute(user);
  123. return <AuthContext.Provider value={{ user, login, logout, setUser }}>{children}</AuthContext.Provider>;
  124. }