101 lines
2.6 KiB
TypeScript
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,
|
|
};
|
|
}
|