fuck if i know

This commit is contained in:
2025-12-04 15:06:57 -05:00
parent fb3c23fa46
commit cb16698940
76 changed files with 1197 additions and 603 deletions
+86 -83
View File
@@ -20,8 +20,8 @@ type AuthUser = {
type AuthContextValue = {
user: AuthUser;
token: string | null;
loading: boolean; // covers initial hydrate + active auth requests
token: string | null;
loading: boolean;
login: (params: { email: string; password: string }) => Promise<void>;
register: (params: {
email: string;
@@ -38,136 +38,138 @@ const TOKEN_KEY = "ballistic_auth_token";
const USER_KEY = "ballistic_auth_user";
export function AuthProvider({ children }: { children: ReactNode }) {
const [user, setUser] = useState<AuthUser>(null);
const [token, setToken] = useState<string | null>(null);
const [loading, setLoading] = useState(true); // start true while we hydrate + reuse for calls
const [user, setUser] = useState<AuthUser>(null);
const [loading, setLoading] = useState<boolean>(true);
// hydrate from localStorage
// Hydrate from localStorage on first load
useEffect(() => {
try {
if (typeof window === "undefined") return;
if (typeof window === "undefined") return;
const storedToken = window.localStorage.getItem(TOKEN_KEY);
const storedUser = window.localStorage.getItem(USER_KEY);
const storedToken = window.localStorage.getItem(TOKEN_KEY);
const storedUser = window.localStorage.getItem(USER_KEY);
if (storedToken && storedUser) {
setToken(storedToken);
if (storedToken) {
setToken(storedToken);
}
if (storedUser) {
try {
setUser(JSON.parse(storedUser));
} catch {
// bad JSON? wipe it
window.localStorage.removeItem(USER_KEY);
}
} catch {
// ignore
} finally {
setLoading(false);
}
setLoading(false);
}, []);
const setSession = useCallback((newToken: string, newUser: AuthUser) => {
setToken(newToken);
setUser(newUser);
const persistAuth = useCallback((nextToken: string | null, nextUser: AuthUser) => {
if (typeof window === "undefined") return;
if (typeof window !== "undefined") {
window.localStorage.setItem(TOKEN_KEY, newToken);
window.localStorage.setItem(USER_KEY, JSON.stringify(newUser));
}
}, []);
const clearSession = useCallback(() => {
setToken(null);
setUser(null);
if (typeof window !== "undefined") {
if (nextToken) {
window.localStorage.setItem(TOKEN_KEY, nextToken);
} else {
window.localStorage.removeItem(TOKEN_KEY);
}
if (nextUser) {
window.localStorage.setItem(USER_KEY, JSON.stringify(nextUser));
} else {
window.localStorage.removeItem(USER_KEY);
}
}, []);
const register = useCallback(
async (params: { email: string; password: string; displayName?: string }) => {
const login = useCallback(
async ({ email, password }: { email: string; password: string }) => {
setLoading(true);
try {
const res = await fetch(`${API_BASE_URL}/api/auth/register`, {
const res = await fetch(`${API_BASE_URL}/auth/login`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
email: params.email,
password: params.password,
displayName: params.displayName,
}),
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ email, password }),
});
if (!res.ok) {
const text = await res.text();
throw new Error(text || "Failed to create account");
const text = await res.text().catch(() => res.statusText);
throw new Error(text || "Login failed");
}
const data: {
token: string;
email: string;
displayName?: string;
role: string;
} = await res.json();
const data = await res.json();
setSession(data.token, {
email: data.email,
displayName: data.displayName ?? null,
role: data.role,
});
// Adjust these to match your backend response shape
const nextToken: string = data.token ?? data.accessToken;
const nextUser: AuthUser =
data.user ??
({
email: data.email ?? email,
displayName: data.displayName ?? null,
role: data.role ?? "USER",
} as AuthUser);
setToken(nextToken);
setUser(nextUser);
persistAuth(nextToken, nextUser);
} finally {
setLoading(false);
}
},
[setSession],
[persistAuth]
);
const login = useCallback(
async (params: { email: string; password: string }) => {
const register = useCallback(
async ({
email,
password,
displayName,
}: {
email: string;
password: string;
displayName?: string;
}) => {
setLoading(true);
try {
const res = await fetch(`${API_BASE_URL}/api/auth/login`, {
const res = await fetch(`${API_BASE_URL}/auth/register`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
email: params.email,
password: params.password,
}),
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ email, password, displayName }),
});
if (!res.ok) {
const text = await res.text();
throw new Error(text || "Failed to log in");
const text = await res.text().catch(() => res.statusText);
throw new Error(text || "Registration failed");
}
const data: {
token: string;
email: string;
displayName?: string;
role: string;
} = await res.json();
const data = await res.json();
setSession(data.token, {
email: data.email,
displayName: data.displayName ?? null,
role: data.role,
});
const nextToken: string = data.token ?? data.accessToken;
const nextUser: AuthUser =
data.user ??
({
email: data.email ?? email,
displayName: data.displayName ?? displayName ?? null,
role: data.role ?? "USER",
} as AuthUser);
setToken(nextToken);
setUser(nextUser);
persistAuth(nextToken, nextUser);
} finally {
setLoading(false);
}
},
[setSession],
[persistAuth]
);
const logout = useCallback(() => {
clearSession();
}, [clearSession]);
setToken(null);
setUser(null);
persistAuth(null, null);
}, [persistAuth]);
const getAuthHeaders = useCallback((): HeadersInit => {
if (!token) return {};
return {
Authorization: `Bearer ${token}`,
};
return token ? { Authorization: `Bearer ${token}` } : {};
}, [token]);
const value: AuthContextValue = {
@@ -183,6 +185,7 @@ export function AuthProvider({ children }: { children: ReactNode }) {
return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>;
}
// 🔑 This is what your useApi hook imports
export function useAuth(): AuthContextValue {
const ctx = useContext(AuthContext);
if (!ctx) {