Files
leocrm/frontend/src/api/users.ts
T
Agent Zero e017da9d12 feat: navigation restructure + drag-and-drop menu ordering
Navigation:
- Remove Plugins header from sidebar
- Merge static items and plugin items into unified sorted list
- Group related menu items (Dateien, E-Mail, Kalender, Automation)
- German labels for all menu items
- Sort by order field, alphabetical fallback for ties

Drag-and-Drop Menu:
- New backend endpoints: GET/PUT /api/v1/users/me/menu-order
- Store menu order in user preferences JSONB field
- New SettingsMenuOrder page with @dnd-kit drag-and-drop
- New Settings tab: Menu ordering
- Sidebar reads saved menu order and sorts accordingly
- Reset to default option
2026-07-24 21:46:27 +02:00

115 lines
2.7 KiB
TypeScript

/**
* User CRUD hooks.
*/
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
import { apiGet, apiPost, apiPut, apiPatch, apiDelete } from './client';
import { PaginatedResponse } from './types';
// ── Types matching backend schemas ──
export interface UserResponse {
id: string;
email: string;
name: string;
first_name: string | null;
last_name: string | null;
avatar_url: string | null;
role: string;
role_id: string | null;
is_active: boolean;
tenant_id: string;
}
export interface UserCreate {
email: string;
name: string;
password: string;
role?: string;
role_id?: string | null;
is_active?: boolean;
}
export interface UserUpdate {
name?: string;
first_name?: string;
last_name?: string;
email?: string;
avatar_url?: string | null;
role?: string;
role_id?: string | null;
is_active?: boolean;
current_password?: string;
new_password?: string;
}
export function useUsers(page = 1, pageSize = 25) {
return useQuery({
queryKey: ['users', page, pageSize],
queryFn: () =>
apiGet<PaginatedResponse<UserResponse>>(`/users?page=${page}&page_size=${pageSize}`),
});
}
export function useUser(id?: string) {
return useQuery({
queryKey: ['users', id],
queryFn: () => apiGet<UserResponse>(`/users/${id}`),
enabled: !!id,
});
}
export function useCreateUser() {
const queryClient = useQueryClient();
return useMutation({
mutationFn: (data: UserCreate) => apiPost('/users', data),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['users'] });
},
});
}
export function useUpdateUser() {
const queryClient = useQueryClient();
return useMutation({
mutationFn: ({ id, data }: { id: string; data: UserUpdate }) =>
apiPatch(`/users/${id}`, data),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['users'] });
},
});
}
// ── Menu Order ──
export interface MenuOrderResponse {
menu_order: string[];
}
export function useMenuOrder() {
return useQuery({
queryKey: ['menu-order'],
queryFn: () => apiGet<MenuOrderResponse>('/users/me/menu-order'),
});
}
export function useUpdateMenuOrder() {
const queryClient = useQueryClient();
return useMutation({
mutationFn: (menu_order: string[]) => apiPut('/users/me/menu-order', { menu_order }),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['menu-order'] });
},
});
}
export function useDeleteUser() {
const queryClient = useQueryClient();
return useMutation({
mutationFn: (id: string) => apiDelete(`/users/${id}`),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['users'] });
},
});
}