Spaces:
Running
Running
| import { createContext, ReactNode, useContext } from "react"; | |
| import { useQuery, useMutation } from "@tanstack/react-query"; | |
| import { getQueryFn, queryClient } from "@/lib/queryClient"; | |
| import { useToast } from "@/hooks/use-toast"; | |
| interface User { | |
| id: number; | |
| username: string; | |
| fullName?: string | null; | |
| location?: string | null; | |
| interests?: string[] | null; | |
| profession?: string | null; | |
| pets?: string | null; | |
| systemContext?: string | null; | |
| } | |
| type AuthContextType = { | |
| user: User | null; | |
| isLoading: boolean; | |
| error: Error | null; | |
| login: () => Promise<void>; | |
| logout: () => Promise<void>; | |
| loginMutation: any; | |
| registerMutation: any; | |
| }; | |
| export const AuthContext = createContext<AuthContextType | null>(null); | |
| function loginWithReplit() { | |
| const h = 500; | |
| const w = 350; | |
| const left = screen.width / 2 - w / 2; | |
| const top = screen.height / 2 - h / 2; | |
| return new Promise<void>((resolve) => { | |
| const authWindow = window.open( | |
| `https://replit.com/auth_with_repl_site?domain=${location.host}`, | |
| "_blank", | |
| `modal=yes,toolbar=no,location=no,directories=no,status=no,menubar=no,scrollbars=no,resizable=no,copyhistory=no,width=${w},height=${h},top=${top},left=${left}` | |
| ); | |
| window.addEventListener("message", function authComplete(e) { | |
| if (e.data !== "auth_complete") { | |
| return; | |
| } | |
| window.removeEventListener("message", authComplete); | |
| authWindow?.close(); | |
| resolve(); | |
| }); | |
| }); | |
| } | |
| export function AuthProvider({ children }: { children: ReactNode }) { | |
| const { toast } = useToast(); | |
| const { | |
| data: user, | |
| error, | |
| isLoading, | |
| } = useQuery<User | null, Error>({ | |
| queryKey: ["/api/user"], | |
| queryFn: getQueryFn({ on401: "returnNull" }), | |
| retry: false, | |
| }); | |
| const loginMutation = useMutation({ | |
| mutationFn: async () => { | |
| await loginWithReplit(); | |
| const res = await fetch("/api/auth/replit"); | |
| if (!res.ok) { | |
| throw new Error("Authentication failed"); | |
| } | |
| return res.json(); | |
| }, | |
| onSuccess: (userData) => { | |
| queryClient.setQueryData(["/api/user"], userData); | |
| toast({ | |
| title: "Welcome!", | |
| description: "You've successfully logged in.", | |
| }); | |
| }, | |
| onError: (error: Error) => { | |
| toast({ | |
| title: "Login failed", | |
| description: error.message, | |
| variant: "destructive", | |
| }); | |
| }, | |
| }); | |
| const registerMutation = useMutation({ | |
| mutationFn: async () => { | |
| await loginWithReplit(); | |
| const res = await fetch("/api/auth/replit"); | |
| if (!res.ok) { | |
| throw new Error("Registration failed"); | |
| } | |
| return res.json(); | |
| }, | |
| onSuccess: (userData) => { | |
| queryClient.setQueryData(["/api/user"], userData); | |
| toast({ | |
| title: "Welcome!", | |
| description: "Your account has been created successfully.", | |
| }); | |
| }, | |
| onError: (error: Error) => { | |
| toast({ | |
| title: "Registration failed", | |
| description: error.message, | |
| variant: "destructive", | |
| }); | |
| }, | |
| }); | |
| const logoutMutation = useMutation({ | |
| mutationFn: async () => { | |
| const res = await fetch("/api/logout", { | |
| method: "POST", | |
| credentials: "include", | |
| }); | |
| if (!res.ok) { | |
| throw new Error("Logout failed"); | |
| } | |
| // Force a full page reload to clear Replit auth state | |
| window.location.href = "/auth"; | |
| return null; | |
| }, | |
| onSuccess: () => { | |
| queryClient.clear(); | |
| queryClient.removeQueries(); | |
| queryClient.setQueryData(["/api/user"], null); | |
| }, | |
| onError: (error: Error) => { | |
| toast({ | |
| title: "Logout failed", | |
| description: error.message, | |
| variant: "destructive", | |
| }); | |
| }, | |
| }); | |
| return ( | |
| <AuthContext.Provider | |
| value={{ | |
| user: user || null, | |
| isLoading, | |
| error, | |
| login: loginMutation.mutateAsync, | |
| logout: logoutMutation.mutateAsync, | |
| loginMutation, | |
| registerMutation, | |
| }} | |
| > | |
| {children} | |
| </AuthContext.Provider> | |
| ); | |
| } | |
| export function useAuth() { | |
| const context = useContext(AuthContext); | |
| if (!context) { | |
| throw new Error("useAuth must be used within an AuthProvider"); | |
| } | |
| return context; | |
| } | |