p2p/src/hooks/useAuth.ts

101 lines
2.6 KiB
TypeScript

import { useState, useCallback } from "react";
import type { User } from "../zino-sdk/types";
const TOKEN_KEY = "p2p_token";
const USER_KEY = "p2p_user";
interface LoginParams {
email: string;
password: string;
orgId?: string;
}
interface AuthState {
user: User | null;
token: string | null;
loading: boolean;
error: string | null;
}
export function useAuth() {
const [state, setState] = useState<AuthState>(() => {
const token = localStorage.getItem(TOKEN_KEY);
const userJson = localStorage.getItem(USER_KEY);
let user: User | null = null;
if (userJson) {
try {
user = JSON.parse(userJson);
} catch {}
}
return { user, token, loading: false, error: null };
});
const apiUrl = (
import.meta.env.VITE_ZINO_API_URL || ""
).replace(/\/+$/, "");
const login = useCallback(
async ({ email, password, orgId }: LoginParams) => {
setState((s) => ({ ...s, loading: true, error: null }));
try {
const res = await fetch(`${apiUrl}/usr/login`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
email,
password,
...(orgId ? { org_id: orgId } : {}),
}),
});
if (!res.ok) {
let msg = "Login failed";
try {
const body = await res.json();
if (body.error) msg = body.error;
} catch {}
throw new Error(msg);
}
const data = await res.json();
const { token, user } = data as { token: string; user: User };
localStorage.setItem(TOKEN_KEY, token);
localStorage.setItem(USER_KEY, JSON.stringify(user));
// Also set on zino SDK so workflow/view calls get the token
localStorage.setItem("zino_token", token);
setState({ user, token, loading: false, error: null });
return { token, user };
} catch (err: any) {
const msg = err?.message || "Login failed";
setState((s) => ({ ...s, loading: false, error: msg }));
throw err;
}
},
[apiUrl],
);
const logout = useCallback(() => {
localStorage.removeItem(TOKEN_KEY);
localStorage.removeItem(USER_KEY);
localStorage.removeItem("zino_token");
setState({ user: null, token: null, loading: false, error: null });
}, []);
const clearError = useCallback(() => {
setState((s) => ({ ...s, error: null }));
}, []);
return {
user: state.user,
token: state.token,
isAuthenticated: !!state.token,
loading: state.loading,
error: state.error,
login,
logout,
clearError,
};
}