Logout: new sidebar link 'Log out (username)' that POSTs /api/logout (clears session cookie) and navigates to /login. Visible to everyone. Replaces 'no logout functionality' state where users could only get out by deleting cookies manually. Admin window: new 'Admin · Users' window (only shown when current user.is_admin) lists all users in a table with: - Add user (username + password + admin checkbox) - Reset password inline per row - Toggle admin per row - Delete user per row (blocked for self) Wraps the existing /api-admin/users CRUD endpoints in main.py. Plumbing: useCurrentUser hook fetches /me on mount; apiPatch+apiDelete helpers added to api/client.ts; new endpoint wrappers exported from api/endpoints.ts; AdminUsersWindow.tsx registered in WindowRenderer under id prefix 'adminusers'; CSS for admin table/form/buttons and the muted-red logout link. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
25 lines
910 B
TypeScript
25 lines
910 B
TypeScript
import { useEffect, useState } from 'react';
|
|
import { getCurrentUser, type CurrentUser } from '../api/endpoints';
|
|
|
|
/**
|
|
* Returns the currently-logged-in dashboard user, or null if not logged in /
|
|
* not yet loaded. Useful for conditionally showing admin-only UI bits.
|
|
*
|
|
* Fetches `/me` once on mount. Cheap — the endpoint just decodes the
|
|
* session cookie and returns {username, is_admin}.
|
|
*/
|
|
export function useCurrentUser(): { user: CurrentUser | null; loading: boolean } {
|
|
const [user, setUser] = useState<CurrentUser | null>(null);
|
|
const [loading, setLoading] = useState(true);
|
|
|
|
useEffect(() => {
|
|
let cancelled = false;
|
|
getCurrentUser()
|
|
.then(u => { if (!cancelled) setUser(u); })
|
|
.catch(() => { if (!cancelled) setUser(null); })
|
|
.finally(() => { if (!cancelled) setLoading(false); });
|
|
return () => { cancelled = true; };
|
|
}, []);
|
|
|
|
return { user, loading };
|
|
}
|