eletrotupi / tcc / frontend/context/AuthContext.tsx master
4.3 KB Raw
import React, { createContext, useContext, useEffect, useState } from "react";
import { apiClient, User } from "@/lib/api";
import { queryClient, storage } from "@/lib/queryClient";

interface AuthProviderProps {
  children: React.ReactNode;
}

interface AuthContextType {
  user: User | null;
  isLoading: boolean;
  isAuthenticated: boolean;
  updateAuthUser: (user: User) => void;
  login: (email: string, password: string) => Promise<{ user: User } | null>;
  signup: (userData: {
    firstName: string;
    lastName?: string;
    email: string;
    password: string;
  }) => Promise<void>;
  logout: () => Promise<void>;
  forgotPassword: (
    email: string,
  ) => Promise<{ message: string; token?: string }>;
  resetPassword: (token: string, password: string) => Promise<void>;
  activate: (code: string) => Promise<void>;
  requestActivateCode: () => Promise<void>;
}

export function sanitizeUser(data: any): User {
  return {
    id: data.id,
    email: data.email,
    firstName: data.firstName,
    lastName: data.lastName,
    updatedAt: data.updatedAt,
    avatarKey: data.avatarKey,
    avatarURL: data.avatarURL,
    active: data.active,
  };
}

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

export function useAuth() {
  const context = useContext(AuthContext);
  if (!context) {
    throw new Error("useAuth must be used within an AuthProvider");
  }

  return context;
}

export const AuthProvider = ({ children }: AuthProviderProps) => {
  const [user, setUser] = useState<User | null>(null);
  const [isLoading, setIsLoading] = useState(true);
  const isAuthenticated = !!user;

  // Check for existing authentication on app start
  useEffect(() => {
    checkAuthState();
  }, []);

  const checkAuthState = async () => {
    try {
      const { token } = await apiClient.getStoredAuthData();

      if (token) {
        const verifyResponse = await apiClient.verifyToken();
        if (
          verifyResponse.valid &&
          verifyResponse.userId &&
          verifyResponse.email
        ) {
          // TODO: Fetch the full user profile
          // For now, we'll create a basic user object
          setUser({
            id: verifyResponse.userId,
            email: verifyResponse.email,
            ...verifyResponse.user,
          });
        }
      }
    } catch (error) {
      console.error("Auth check failed:", error);
      // Token is invalid, wipe out any stored data
      await apiClient.logout();
    } finally {
      setIsLoading(false);
    }
  };

  const login = async (
    email: string,
    password: string,
  ): Promise<{ user: User } | null> => {
    setIsLoading(true);

    try {
      const response = await apiClient.login(email, password);

      if (response.user) {
        setUser(response.user);
      }

      return response;
    } finally {
      setIsLoading(false);
    }
  };

  const signup = async (userData: {
    firstName: string;
    lastName?: string;
    email: string;
    password: string;
  }) => {
    setIsLoading(true);
    try {
      const response = await apiClient.signup(userData);
      setUser(response.user);
    } finally {
      setIsLoading(false);
    }
  };

  const logout = async () => {
    setIsLoading(true);
    try {
      await apiClient.logout();

      setUser(null);
      // Clear both the in-memory cache and the persisted MMKV cache
      queryClient.clear();
      storage.clearAll();
    } finally {
      setIsLoading(false);
    }
  };

  const forgotPassword = async (email: string) => {
    return apiClient.forgotPassword(email);
  };

  const resetPassword = async (token: string, password: string) => {
    await apiClient.resetPassword(token, password);
  };

  const activate = async (code: number) => {
    const response = await apiClient.activate(code);

    if (response.user) {
      setUser(response.user);
    }

    return response;
  };

  const requestActivateCode = async () => {
    await apiClient.requestActivateCode();
  };

  const updateAuthUser = (user) => {
    setUser(user);
  };

  const value: AuthContextType = {
    user,
    isLoading,
    isAuthenticated,
    login,
    signup,
    logout,
    forgotPassword,
    resetPassword,
    updateAuthUser,
    activate,
    requestActivateCode,
  };

  return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>;
};