# All files / src/context AuthContext.tsx

0% Statements 0/51
0% Branches 0/8
0% Functions 0/9
0% Lines 0/48

Press n or j to go to the next uncovered block, b, p or k for the previous block.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103

     import { createContext, useState, useEffect, useCallback, type ReactNode } from 'react';
    import { authApi } from '../api/auth';

    export interface AuthUser {
      id: number;
      email: string;
      username: string;
      avatar: string;
      userLevel: string;
      createTime: string;
    }

    interface AuthContextType {
      user: AuthUser | null;
      isAuthenticated: boolean;
      loading: boolean;
      login: (email: string, password: string) => Promise<void>;
      register: (email: string, password: string, code: string, username?: string) => Promise<void>;
      logout: () => Promise<void>;
      sendCode: (email: string) => Promise<void>;
      sendResetCode: (email: string) => Promise<void>;
      refreshUser: () => Promise<void>;
    }

    export const AuthContext = createContext<AuthContextType | null>(null);

    export function AuthProvider({ children }: { children: ReactNode }) {
      const [user, setUser] = useState<AuthUser | null>(null);
      const [loading, setLoading] = useState(true);

      useEffect(() => {
        const token = localStorage.getItem('authToken');
        const info = localStorage.getItem('userInfo');
        if (token && info) {
          try {
            const parsed = JSON.parse(info);
            setUser(parsed);
            // 验证 token 是否仍然有效
            refreshUser().finally(() => setLoading(false));
          } catch {
            localStorage.removeItem('authToken');
            localStorage.removeItem('userInfo');
            setLoading(false);
          }
        } else {
          setLoading(false);
        }
      }, []); // eslint-disable-line react-hooks/exhaustive-deps

      const refreshUser = useCallback(async () => {
        try {
          const { data } = await authApi.getProfile();
          setUser(data);
          localStorage.setItem('userInfo', JSON.stringify(data));
        } catch {
          setUser(null);
          localStorage.removeItem('authToken');
          localStorage.removeItem('userInfo');
        }
      }, []);

      const login = useCallback(async (email: string, password: string) => {
        const result = await authApi.login({ email, password, from: 'web' });
        const token = result.token;
        if (!token) throw new Error('登录失败：未获取到 token');
        localStorage.setItem('authToken', token);
        localStorage.setItem('userInfo', JSON.stringify(result.data));
        setUser(result.data);
      }, []);

      const register = useCallback(async (email: string, password: string, code: string, username?: string) => {
        const result = await authApi.register({ email, password, code, username });
        const token = result.token;
        if (!token) throw new Error('注册失败：未获取到 token');
        localStorage.setItem('authToken', token);
        localStorage.setItem('userInfo', JSON.stringify(result.data));
        setUser(result.data);
      }, []);

      const logout = useCallback(async () => {
        try {
          await authApi.logout();
        } catch { /* ignore */ }
        localStorage.removeItem('authToken');
        localStorage.removeItem('userInfo');
        setUser(null);
      }, []);

      const sendCode = useCallback(async (email: string) => {
        await authApi.sendCode(email);
      }, []);

      const sendResetCode = useCallback(async (email: string) => {
        await authApi.sendResetCode(email);
      }, []);

      return (
        <AuthContext.Provider value={{ user, isAuthenticated: !!user, loading, login, register, logout, sendCode, sendResetCode, refreshUser }}>
          {children}
        </AuthContext.Provider>
      );
    }