import { createContext, ReactNode, useContext } from "react"; import { useQuery, useMutation, UseMutationResult, } from "@tanstack/react-query"; import { insertUserSchema, User as SelectUser, InsertUser, Login } from "@shared/schema"; import { getQueryFn, apiRequest, queryClient } from "../lib/queryClient"; import { useToast } from "@/hooks/use-toast"; import { z } from "zod"; type User = Omit; type AuthContextType = { user: User | null; isLoading: boolean; error: Error | null; loginMutation: UseMutationResult; logoutMutation: UseMutationResult; registerMutation: UseMutationResult; }; export const registrationSchema = insertUserSchema.extend({ password: z.string().min(8, "Password must be at least 8 characters"), confirmPassword: z.string(), }).refine((data) => data.password === data.confirmPassword, { message: "Passwords do not match", path: ["confirmPassword"], }); export type RegistrationData = z.infer; export const AuthContext = createContext(null); export function AuthProvider({ children }: { children: ReactNode }) { const { toast } = useToast(); const { data: user, error, isLoading, } = useQuery({ queryKey: ["/api/user"], queryFn: getQueryFn({ on401: "returnNull" }), }); const loginMutation = useMutation({ mutationFn: async (credentials: Login) => { const res = await apiRequest("POST", "/api/login", credentials); return await res.json(); }, onSuccess: (user: User) => { queryClient.setQueryData(["/api/user"], user); toast({ title: "Login successful", description: `Welcome back, ${user.fullName || user.username}!`, }); }, onError: (error: Error) => { toast({ title: "Login failed", description: error.message, variant: "destructive", }); }, }); const registerMutation = useMutation({ mutationFn: async (data: InsertUser) => { const res = await apiRequest("POST", "/api/register", data); return await res.json(); }, onSuccess: (user: User) => { queryClient.setQueryData(["/api/user"], user); toast({ title: "Registration successful", description: "Your account has been created successfully.", }); }, onError: (error: Error) => { toast({ title: "Registration failed", description: error.message, variant: "destructive", }); }, }); const logoutMutation = useMutation({ mutationFn: async () => { await apiRequest("POST", "/api/logout"); }, onSuccess: () => { queryClient.setQueryData(["/api/user"], null); toast({ title: "Logged out", description: "You have been logged out successfully.", }); }, onError: (error: Error) => { toast({ title: "Logout failed", description: error.message, variant: "destructive", }); }, }); return ( {children} ); } export function useAuth() { const context = useContext(AuthContext); if (!context) { throw new Error("useAuth must be used within an AuthProvider"); } return context; }