mirror of
https://github.com/s-frick/effigenix.git
synced 2026-03-28 17:29:58 +01:00
feat(frontend): TypeScript-Monorepo mit Terminal-UI für Effigenix ERP
Monorepo-Setup (pnpm workspaces) mit vier shared Packages und einer TUI-App: Shared Packages: - @effigenix/types: TypeScript-DTOs (UserDTO, RoleDTO, AuthDTO, Enums) - @effigenix/config: API-Konfiguration und Shared Constants - @effigenix/validation: Zod-Schemas für Username, E-Mail und Passwort - @effigenix/api-client: axios-Client mit JWT-Handling (proaktiver + reaktiver Token-Refresh), AuthInterceptor, ErrorInterceptor, Resources für auth/users/roles TUI (apps/cli, Ink 5 / React): - Authentication: Login/Logout, Session-Restore beim Start, JWT-Refresh - User Management: Liste, Anlage (Zod-Inline-Validation), Detailansicht, Passwort ändern, Sperren/Entsperren mit ConfirmDialog - Role Management: Liste, Detailansicht, Zuweisen/Entfernen per RoleSelectList (↑↓) - UX: SuccessDisplay (Auto-Dismiss 3 s), ConfirmDialog (J/N), FormInput mit Inline-Fehlern, StatusBar mit API-URL - Layout: Fullscreen-Modus (alternate screen buffer), Header mit eingeloggtem User - Tests: vitest + ink-testing-library (15 Tests)
This commit is contained in:
parent
87123df2e4
commit
bbe9e87c33
65 changed files with 6955 additions and 1 deletions
137
frontend/apps/cli/src/hooks/useUsers.ts
Normal file
137
frontend/apps/cli/src/hooks/useUsers.ts
Normal file
|
|
@ -0,0 +1,137 @@
|
|||
import { useState, useCallback } from 'react';
|
||||
import type { UserDTO } from '@effigenix/api-client';
|
||||
import { client } from '../utils/api-client.js';
|
||||
|
||||
interface UsersState {
|
||||
users: UserDTO[];
|
||||
loading: boolean;
|
||||
error: string | null;
|
||||
}
|
||||
|
||||
function errorMessage(err: unknown): string {
|
||||
return err instanceof Error ? err.message : 'Unbekannter Fehler';
|
||||
}
|
||||
|
||||
export function useUsers() {
|
||||
const [state, setState] = useState<UsersState>({
|
||||
users: [],
|
||||
loading: false,
|
||||
error: null,
|
||||
});
|
||||
|
||||
const fetchUsers = useCallback(async () => {
|
||||
setState((s) => ({ ...s, loading: true, error: null }));
|
||||
try {
|
||||
const users = await client.users.list();
|
||||
setState({ users, loading: false, error: null });
|
||||
} catch (err) {
|
||||
setState((s) => ({ ...s, loading: false, error: errorMessage(err) }));
|
||||
}
|
||||
}, []);
|
||||
|
||||
const createUser = useCallback(
|
||||
async (username: string, email: string, password: string, roleName?: string) => {
|
||||
setState((s) => ({ ...s, loading: true, error: null }));
|
||||
try {
|
||||
const user = await client.users.create({
|
||||
username,
|
||||
email,
|
||||
password,
|
||||
roleNames: roleName ? [roleName] : [],
|
||||
});
|
||||
setState((s) => ({ users: [...s.users, user], loading: false, error: null }));
|
||||
return user;
|
||||
} catch (err) {
|
||||
setState((s) => ({ ...s, loading: false, error: errorMessage(err) }));
|
||||
return null;
|
||||
}
|
||||
},
|
||||
[],
|
||||
);
|
||||
|
||||
const lockUser = useCallback(async (id: string) => {
|
||||
try {
|
||||
const user = await client.users.lock(id);
|
||||
setState((s) => ({
|
||||
...s,
|
||||
users: s.users.map((u) => (u.id === id ? user : u)),
|
||||
}));
|
||||
return user;
|
||||
} catch (err) {
|
||||
setState((s) => ({ ...s, error: errorMessage(err) }));
|
||||
return null;
|
||||
}
|
||||
}, []);
|
||||
|
||||
const unlockUser = useCallback(async (id: string) => {
|
||||
try {
|
||||
const user = await client.users.unlock(id);
|
||||
setState((s) => ({
|
||||
...s,
|
||||
users: s.users.map((u) => (u.id === id ? user : u)),
|
||||
}));
|
||||
return user;
|
||||
} catch (err) {
|
||||
setState((s) => ({ ...s, error: errorMessage(err) }));
|
||||
return null;
|
||||
}
|
||||
}, []);
|
||||
|
||||
const assignRole = useCallback(async (id: string, roleName: string) => {
|
||||
try {
|
||||
const user = await client.users.assignRole(id, { roleName });
|
||||
setState((s) => ({
|
||||
...s,
|
||||
users: s.users.map((u) => (u.id === id ? user : u)),
|
||||
}));
|
||||
return user;
|
||||
} catch (err) {
|
||||
setState((s) => ({ ...s, error: errorMessage(err) }));
|
||||
return null;
|
||||
}
|
||||
}, []);
|
||||
|
||||
const removeRole = useCallback(async (id: string, roleName: string) => {
|
||||
try {
|
||||
await client.users.removeRole(id, roleName);
|
||||
const updated = await client.users.getById(id);
|
||||
setState((s) => ({
|
||||
...s,
|
||||
users: s.users.map((u) => (u.id === id ? updated : u)),
|
||||
}));
|
||||
return true;
|
||||
} catch (err) {
|
||||
setState((s) => ({ ...s, error: errorMessage(err) }));
|
||||
return false;
|
||||
}
|
||||
}, []);
|
||||
|
||||
const changePassword = useCallback(
|
||||
async (id: string, currentPassword: string, newPassword: string) => {
|
||||
try {
|
||||
await client.users.changePassword(id, { currentPassword, newPassword });
|
||||
return true;
|
||||
} catch (err) {
|
||||
setState((s) => ({ ...s, error: errorMessage(err) }));
|
||||
return false;
|
||||
}
|
||||
},
|
||||
[],
|
||||
);
|
||||
|
||||
const clearError = useCallback(() => {
|
||||
setState((s) => ({ ...s, error: null }));
|
||||
}, []);
|
||||
|
||||
return {
|
||||
...state,
|
||||
fetchUsers,
|
||||
createUser,
|
||||
lockUser,
|
||||
unlockUser,
|
||||
assignRole,
|
||||
removeRole,
|
||||
changePassword,
|
||||
clearError,
|
||||
};
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue