1import { useState, createContext, useContext, useEffect } from "react";
2import { getSession, logout } from "../api/client";
3
4const AuthContext = createContext(null);
5
6export function AuthProvider({ children }) {
7 const [user, setUser] = useState(null);
8 const [loading, setLoading] = useState(true);
9
10 useEffect(() => {
11 checkSession();
12 }, []);
13
14 const checkSession = async () => {
15 try {
16 const data = await getSession();
17 if (data.authenticated) {
18 let avatar = null;
19 let displayName = null;
20 try {
21 const profileRes = await fetch(
22 `https://public.api.bsky.app/xrpc/app.bsky.actor.getProfile?actor=${encodeURIComponent(data.did)}`,
23 );
24 if (profileRes.ok) {
25 const profile = await profileRes.json();
26 avatar = profile.avatar;
27 displayName = profile.displayName;
28 }
29 } catch (e) {
30 console.error("Failed to fetch profile:", e);
31 }
32 setUser({
33 did: data.did,
34 handle: data.handle,
35 avatar,
36 displayName: displayName || data.handle,
37 });
38 } else {
39 setUser(null);
40 }
41 } catch {
42 setUser(null);
43 } finally {
44 setLoading(false);
45 }
46 };
47
48 const handleLogout = async () => {
49 try {
50 await logout();
51 } catch (e) {
52 console.warn("Logout failed", e);
53 }
54 setUser(null);
55 };
56
57 const value = {
58 user,
59 loading,
60 isAuthenticated: !!user,
61 login: () => (window.location.href = "/login"),
62 logout: handleLogout,
63 refresh: checkSession,
64 };
65
66 return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>;
67}
68
69// eslint-disable-next-line react-refresh/only-export-components
70export function useAuth() {
71 const context = useContext(AuthContext);
72 if (!context) {
73 throw new Error("useAuth must be used within AuthProvider");
74 }
75 return context;
76}