AuthProvider.tsx 4.4 KB

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