Pre-launch — Gluecron is in final validation. Public signups and git hosting for non-owner users open after launch review.
CodeIssuesPull RequestsActionsSecurityInsightsSettings
✨ AI
More
Blame · Line-by-line history

useAuth.ts

Each line is annotated with the commit that last touched it. Click any SHA to jump to that commit and see the surrounding change.

useAuth.tsBlame101 lines · 1 contributor
c53cf00Claude1import { useState, useEffect, useCallback } from 'react';
2import { api, type User } from '../api/client';
3import {
4 saveToken,
5 loadToken,
6 clearAll,
7 saveUser,
8 loadUser,
9 saveHost,
10 loadHost,
11} from '../store/auth';
12import { setBaseUrl } from '../api/client';
13
14export interface AuthState {
15 user: User | null;
16 token: string | null;
17 loading: boolean;
18 error: string | null;
19}
20
21export function useAuth() {
22 const [state, setState] = useState<AuthState>({
23 user: null,
24 token: null,
25 loading: true,
26 error: null,
27 });
28
29 // Hydrate from secure storage on mount
30 useEffect(() => {
31 (async () => {
32 try {
33 const [token, user, host] = await Promise.all([
34 loadToken(),
35 loadUser(),
36 loadHost(),
37 ]);
38 if (host) {
39 setBaseUrl(host);
40 }
41 if (token && user) {
42 setState({ user, token, loading: false, error: null });
43 } else {
44 setState({ user: null, token: null, loading: false, error: null });
45 }
46 } catch {
47 setState({ user: null, token: null, loading: false, error: null });
48 }
49 })();
50 }, []);
51
52 const login = useCallback(async (usernameOrToken: string, passwordOrEmpty?: string, host?: string) => {
53 setState((s) => ({ ...s, loading: true, error: null }));
54 try {
55 if (host) {
56 setBaseUrl(host);
57 await saveHost(host);
58 }
59
60 let token: string;
61 let user: User;
62
63 // PAT token login: if passwordOrEmpty is empty, treat usernameOrToken as raw token
64 if (!passwordOrEmpty) {
65 token = usernameOrToken;
66 api.setToken(token);
67 user = await api.getMe();
68 } else {
69 // Username + password login
70 const res = await api.login(usernameOrToken, passwordOrEmpty);
71 token = res.token;
72 api.setToken(token);
73 user = await api.getMe();
74 }
75
76 await Promise.all([saveToken(token), saveUser(user)]);
77 setState({ user, token, loading: false, error: null });
78 } catch (err: unknown) {
79 const msg = err instanceof Error ? err.message : 'Login failed';
80 setState((s) => ({ ...s, loading: false, error: msg }));
81 throw err;
82 }
83 }, []);
84
85 const logout = useCallback(async () => {
86 await clearAll();
87 setState({ user: null, token: null, loading: false, error: null });
88 }, []);
89
90 const clearError = useCallback(() => {
91 setState((s) => ({ ...s, error: null }));
92 }, []);
93
94 return {
95 ...state,
96 isAuthenticated: !!state.token && !!state.user,
97 login,
98 logout,
99 clearError,
100 };
101}