Refactor and centralize user and pagination interfaces in useAdmin hook

- Unified `User` and `PaginationMeta` type definitions into `useAdmin` to improve maintainability and consistency.
- Updated affected components (`UserManagementContent`, `UserListTable`, `UserFormDialog`, `UserActionMenu`) to reference the centralized types.
- Enhanced test coverage for user-related hooks to include create, update, delete, activate, deactivate, and bulk actions.
This commit is contained in:
Felipe Cardoso
2025-11-06 12:49:46 +01:00
parent 91bc4f190d
commit f22f87250c
6 changed files with 316 additions and 49 deletions

View File

@@ -30,17 +30,9 @@ import {
useActivateUser,
useDeactivateUser,
useDeleteUser,
type User,
} from '@/lib/api/hooks/useAdmin';
interface User {
id: string;
email: string;
first_name: string;
last_name: string | null;
is_active: boolean;
is_superuser: boolean;
}
interface UserActionMenuProps {
user: User;
isCurrentUser: boolean;

View File

@@ -26,6 +26,7 @@ import { toast } from 'sonner';
import {
useCreateUser,
useUpdateUser,
type User,
} from '@/lib/api/hooks/useAdmin';
// ============================================================================
@@ -58,15 +59,6 @@ type UserFormData = z.infer<typeof userFormSchema>;
// Component
// ============================================================================
interface User {
id: string;
email: string;
first_name: string;
last_name: string | null;
is_active: boolean;
is_superuser: boolean;
}
interface UserFormDialogProps {
open: boolean;
onOpenChange: (open: boolean) => void;

View File

@@ -29,25 +29,7 @@ import {
SelectValue,
} from '@/components/ui/select';
import { UserActionMenu } from './UserActionMenu';
interface User {
id: string;
email: string;
first_name: string;
last_name: string | null;
is_active: boolean;
is_superuser: boolean;
created_at: string;
}
interface PaginationMeta {
total: number;
page: number;
page_size: number;
total_pages: number;
has_next: boolean;
has_prev: boolean;
}
import type { User, PaginationMeta } from '@/lib/api/hooks/useAdmin';
interface UserListTableProps {
users: User[];

View File

@@ -10,7 +10,7 @@ import { useSearchParams, useRouter } from 'next/navigation';
import { Plus } from 'lucide-react';
import { Button } from '@/components/ui/button';
import { useAuth } from '@/lib/auth/AuthContext';
import { useAdminUsers } from '@/lib/api/hooks/useAdmin';
import { useAdminUsers, type User, type PaginationMeta } from '@/lib/api/hooks/useAdmin';
import { UserListTable } from './UserListTable';
import { UserFormDialog } from './UserFormDialog';
import { BulkActionToolbar } from './BulkActionToolbar';
@@ -30,13 +30,13 @@ export function UserManagementContent() {
const [selectedUsers, setSelectedUsers] = useState<string[]>([]);
const [dialogOpen, setDialogOpen] = useState(false);
const [dialogMode, setDialogMode] = useState<'create' | 'edit'>('create');
const [editingUser, setEditingUser] = useState<any | null>(null);
const [editingUser, setEditingUser] = useState<User | null>(null);
// Fetch users with query params
const { data, isLoading } = useAdminUsers(page, 20);
const users = data?.data || [];
const pagination = data?.pagination || {
const users: User[] = data?.data || [];
const pagination: PaginationMeta = data?.pagination || {
total: 0,
page: 1,
page_size: 20,
@@ -107,7 +107,7 @@ export function UserManagementContent() {
setDialogOpen(true);
};
const handleEditUser = (user: any) => {
const handleEditUser = (user: User) => {
setDialogMode('edit');
setEditingUser(user);
setDialogOpen(true);

View File

@@ -123,6 +123,39 @@ export function useAdminStats() {
});
}
/**
* Pagination metadata structure
*/
export interface PaginationMeta {
total: number;
page: number;
page_size: number;
total_pages: number;
has_next: boolean;
has_prev: boolean;
}
/**
* User interface matching backend UserResponse
*/
export interface User {
id: string;
email: string;
first_name: string;
last_name: string | null;
is_active: boolean;
is_superuser: boolean;
created_at: string;
}
/**
* Paginated user list response
*/
export interface PaginatedUserResponse {
data: User[];
pagination: PaginationMeta;
}
/**
* Hook to fetch paginated list of all users (for admin)
*
@@ -135,7 +168,7 @@ export function useAdminUsers(page = 1, limit = DEFAULT_PAGE_LIMIT) {
return useQuery({
queryKey: ['admin', 'users', page, limit],
queryFn: async () => {
queryFn: async (): Promise<PaginatedUserResponse> => {
const response = await adminListUsers({
query: { page, limit },
throwOnError: false,
@@ -146,7 +179,7 @@ export function useAdminUsers(page = 1, limit = DEFAULT_PAGE_LIMIT) {
}
// Type assertion: if no error, response has data
return (response as { data: unknown }).data;
return (response as { data: PaginatedUserResponse }).data;
},
// Only fetch if user is a superuser (frontend guard)
enabled: user?.is_superuser === true,