diff --git a/src/app/(protected)/administrativo/(user)/usuarios/page.tsx b/src/app/(protected)/administrativo/(user)/usuarios/page.tsx index e69de29..3c7f0d1 100644 --- a/src/app/(protected)/administrativo/(user)/usuarios/page.tsx +++ b/src/app/(protected)/administrativo/(user)/usuarios/page.tsx @@ -0,0 +1,134 @@ +'use client'; + +import { useEffect, useState, useCallback } from 'react'; + +// Componentes de UI Genéricos +import z from 'zod'; +import { Card, CardContent } from '@/components/ui/card'; +import Loading from '@/shared/components/loading/loading'; +import Header from '@/shared/components/structure/Header'; +import ConfirmDialog from '@/shared/components/confirmDialog/ConfirmDialog'; +import { useConfirmDialog } from '@/shared/components/confirmDialog/useConfirmDialog'; + +// Componentes de UI Específicos de Usuário +import UserTable from '@/packages/administrativo/components/User/UserTable'; +import UserForm from '@/packages/administrativo/components/User/UserForm'; + +// Hooks Específicos de Usuário +import { useUserIndexHook } from '@/packages/administrativo/hooks/User/useUserIndexHook'; +import { useUserSaveHook } from '@/packages/administrativo/hooks/User/useUserSaveHook'; +import { useUserDeleteHook } from '@/packages/administrativo/hooks/User/useUserDeleteHook'; + +// Interface +import { UserInterface } from '@/packages/administrativo/interfaces/User/UserInterface'; +import { UserSchema } from '@/packages/administrativo/schemas/User/UserSchema'; + +type FormValues = z.infer; + +export default function UsersPage() { + // 1. Hooks de dados para Usuário + const { usuarios, fetchUsuarios } = useUserIndexHook(); + const { saveUser } = useUserSaveHook(); + const { removeUser } = useUserDeleteHook(); // Presumindo que o hook existe e expõe `removeUser` + + // 2. Estados da página + const [selectedUser, setSelectedUser] = useState(null); + const [isFormOpen, setIsFormOpen] = useState(false); + const [userToDelete, setUserToDelete] = useState(null); + + // Hook do modal de confirmação + const { + isOpen: isConfirmOpen, + openDialog: openConfirmDialog, + handleCancel, + } = useConfirmDialog(); + + // 3. Funções de manipulação do formulário + const handleOpenForm = useCallback((user: UserInterface | null) => { + setSelectedUser(user); + setIsFormOpen(true); + }, []); + + const handleCloseForm = useCallback(() => { + setSelectedUser(null); + setIsFormOpen(false); + }, []); + + // 4. Função para salvar (criar ou editar) + const handleSave = useCallback( + async (formData: FormValues) => { + await saveUser(formData); + handleCloseForm(); // Fecha o modal após salvar + await fetchUsuarios(); // Atualiza a lista de usuários + }, + [saveUser, fetchUsuarios, handleCloseForm], + ); + + // 5. Funções para exclusão + const handleConfirmDelete = useCallback( + (user: UserInterface) => { + setUserToDelete(user); + openConfirmDialog(); + }, + [openConfirmDialog], + ); + + const handleDelete = useCallback(async () => { + if (!userToDelete) return; + + await removeUser(userToDelete); // Chama o hook de remoção + await fetchUsuarios(); // Atualiza a lista + setUserToDelete(null); // Limpa o estado + handleCancel(); // Fecha o modal de confirmação + }, [userToDelete, removeUser, fetchUsuarios, handleCancel]); + + // 6. Busca inicial dos dados + useEffect(() => { + fetchUsuarios(); + }, []); + + // 7. Renderização condicional de loading + if (!usuarios) { + return ; + } + + // 8. Renderização da página + return ( +
+
handleOpenForm(null)} + /> + + + + + + + + + + +
+ ); +} \ No newline at end of file diff --git a/src/packages/administrativo/components/User/UserForm.tsx b/src/packages/administrativo/components/User/UserForm.tsx new file mode 100644 index 0000000..b01c797 --- /dev/null +++ b/src/packages/administrativo/components/User/UserForm.tsx @@ -0,0 +1,164 @@ +'use client'; + +import z from 'zod'; +import { useEffect } from 'react'; +import { useForm, Controller } from 'react-hook-form'; +import { zodResolver } from '@hookform/resolvers/zod'; + +import { Button } from '@/components/ui/button'; +import { Checkbox } from '@/components/ui/checkbox'; +import { + Dialog, + DialogClose, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogTitle, +} from '@/components/ui/dialog'; +import { + Form, + FormControl, + FormField, + FormItem, + FormLabel, + FormMessage, +} from '@/components/ui/form'; +import { Input } from '@/components/ui/input'; +import { Label } from '@/components/ui/label'; +import { SituacoesEnum } from '@/shared/enums/SituacoesEnum'; +import { UserSchema } from '../../schemas/User/UserSchema'; + +type FormValues = z.infer; + +interface Props { + isOpen: boolean; + data: FormValues | null; + onClose: () => void; + onSave: (data: FormValues) => void; +} + +export default function UserForm({ isOpen, data, onClose, onSave }: Props) { + const form = useForm({ + resolver: zodResolver(UserSchema), + defaultValues: { + name: '', + email: '', + password: '', + team: '', + status: SituacoesEnum.ATIVO, + }, + }); + + // Atualiza o formulário quando recebe dados para edição + useEffect(() => { + if (data) { + form.reset(data); + } else { + form.reset({ // Garante que o form limpe ao abrir para criar novo + name: '', + email: '', + password: '', + team: '', + status: SituacoesEnum.ATIVO, + }); + } + }, [data, form, isOpen]); // isOpen garante o reset ao reabrir + + return ( + !open && onClose()}> + + + {data ? 'Editar Usuário' : 'Novo Usuário'} + Gerencie os dados do usuário aqui. + + +
+ + {/* Nome */} + ( + + Nome + + + + + + )} + /> + {/* Email */} + ( + + Email + + + + + + )} + /> + {/* Senha */} + ( + + Senha + + + + + + )} + /> + {/* Equipe */} + ( + + Equipe + + + + + + )} + /> + {/* Status */} + ( +
+ field.onChange(checked ? 'A' : 'I')} + /> + +
+ )} + /> + {/* Rodapé */} + + + + + + + {/* Campo oculto para o ID */} + + + +
+
+ ); +} \ No newline at end of file diff --git a/src/packages/administrativo/components/User/UserLoginForm.tsx b/src/packages/administrativo/components/User/UserLoginForm.tsx index a0c1cb6..9caa67d 100644 --- a/src/packages/administrativo/components/User/UserLoginForm.tsx +++ b/src/packages/administrativo/components/User/UserLoginForm.tsx @@ -6,7 +6,7 @@ import { Card, CardContent } from '@/components/ui/card'; import { Input } from '@/components/ui/input'; import z from 'zod'; import { zodResolver } from '@hookform/resolvers/zod'; -import { UserLoginService } from '@/packages/administrativo/services/User/UserLoginService'; +import UserLoginService from '@/packages/administrativo/services/User/UserLoginService'; import { useForm } from 'react-hook-form'; import { useState } from 'react'; import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from '../../../../components/ui/form'; @@ -29,6 +29,7 @@ export function LoginForm({ className, ...props }: React.ComponentProps<'div'>) // onSubmit agora recebe o evento do form através do handleSubmit const onSubmit = async (values: FormValues) => { + console.log("dados para login",values) // Ativa o estado de loading do botão setLoading(true); diff --git a/src/packages/administrativo/components/User/UserTable.tsx b/src/packages/administrativo/components/User/UserTable.tsx new file mode 100644 index 0000000..e0aa804 --- /dev/null +++ b/src/packages/administrativo/components/User/UserTable.tsx @@ -0,0 +1,105 @@ +'use client'; + +import { Button } from '@/components/ui/button'; +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuGroup, + DropdownMenuItem, + DropdownMenuSeparator, + DropdownMenuTrigger, +} from '@/components/ui/dropdown-menu'; +import { + Table, + TableBody, + TableCell, + TableHead, + TableHeader, + TableRow, +} from '@/components/ui/table'; + +import { EllipsisIcon, PencilIcon, Trash2Icon } from 'lucide-react'; +import { UserInterface } from '../../interfaces/User/UserInterface'; // Ajuste o caminho conforme necessário +import { SituacoesEnum } from '@/shared/enums/SituacoesEnum'; + +interface UserTableProps { + data: UserInterface[]; + onEdit: (user: UserInterface) => void; + onDelete: (user: UserInterface) => void; +} + +/** + * Renderiza o badge de situação (Ativo/Inativo) + */ +function StatusBadge({ status }: { status: SituacoesEnum }) { + const isActive = status === 'A'; + const baseClasses = 'text-xs font-medium px-2.5 py-0.5 rounded-sm me-2'; + const activeClasses = 'bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-300'; + const inactiveClasses = 'bg-yellow-100 text-yellow-800 dark:bg-yellow-900 dark:text-yellow-300'; + + return ( + + {isActive ? 'Ativo' : 'Inativo'} + + ); +} + +export default function UserTable({ data, onEdit, onDelete }: UserTableProps) { + return ( + + + + # + Status + Nome + Email + Equipe + Ações + + + + + {data.map((user) => ( + + {user.user_id} + + + + {user.name} + {user.email} + {user.team} + + + + + + + + + onEdit(user)} + > + + Editar + + + onDelete(user)} + > + + Remover + + + + + + + ))} + +
+ ); +} \ No newline at end of file diff --git a/src/packages/administrativo/data/User/UserLoginData.ts b/src/packages/administrativo/data/User/UserLoginData.ts index b7de7b1..41944e2 100644 --- a/src/packages/administrativo/data/User/UserLoginData.ts +++ b/src/packages/administrativo/data/User/UserLoginData.ts @@ -5,7 +5,7 @@ import API from '@/shared/services/api/Api'; import { AuthenticateUserInterface } from '@/shared/interfaces/AuthenticateUserInterface'; import { withClientErrorHandler } from '@/withClientErrorHandler/withClientErrorHandler'; -async function executeUserLoginData(form: AuthenticateUserInterface) { +export default async function UserLoginData(form: any) { const api = new API(); const response = await api.send({ @@ -14,8 +14,8 @@ async function executeUserLoginData(form: AuthenticateUserInterface) { body: form, }); + console.log("resposta da api",response) + return response; -} - -export const UserLoginData = withClientErrorHandler(executeUserLoginData) \ No newline at end of file +} \ No newline at end of file diff --git a/src/packages/administrativo/hooks/User/useUserDeleteHook.ts b/src/packages/administrativo/hooks/User/useUserDeleteHook.ts new file mode 100644 index 0000000..6fc8815 --- /dev/null +++ b/src/packages/administrativo/hooks/User/useUserDeleteHook.ts @@ -0,0 +1,28 @@ +'use client'; + +import { useState } from 'react'; +import { useResponse } from '@/shared/components/response/ResponseContext'; +import { UserDeleteService } from '../../services/User/UserDeleteService'; // Ajuste o caminho conforme necessário +import { UserInterface } from '../../interfaces/User/UserInterface'; // Ajuste o caminho + +export const useUserDeleteHook = () => { + // Hook de contexto para fornecer feedback (toast, modal, etc.) + const { setResponse } = useResponse(); + + const removeUser = async (user: UserInterface) => { + + try { + // Chama o serviço de exclusão, passando apenas o ID do usuário + const response = await UserDeleteService(user.user_id); + + // Define a resposta para que o ResponseContext possa exibir um feedback + setResponse(response); + } catch (error) { + // O withClientErrorHandler já trata o erro, mas um log pode ser útil + console.error('Erro ao remover usuário:', error); + } + }; + + // Retorna a função de remoção e o estado de carregamento + return { removeUser }; +}; \ No newline at end of file diff --git a/src/packages/administrativo/hooks/User/useGUsuarioReadHooks.ts b/src/packages/administrativo/hooks/User/useUserReadHooks.ts similarity index 93% rename from src/packages/administrativo/hooks/User/useGUsuarioReadHooks.ts rename to src/packages/administrativo/hooks/User/useUserReadHooks.ts index b1ef5a6..9a71e61 100644 --- a/src/packages/administrativo/hooks/User/useGUsuarioReadHooks.ts +++ b/src/packages/administrativo/hooks/User/useUserReadHooks.ts @@ -5,7 +5,7 @@ import { UserInterface } from '../../interfaces/User/UserInterface'; import { UserReadService } from '../../services/User/UserReadService'; import { useResponse } from '@/shared/components/response/ResponseContext'; -export const useGUserReadHooks = () => { +export const useUserReadHooks = () => { const { setResponse } = useResponse(); const [User, setUser] = useState(); diff --git a/src/packages/administrativo/hooks/User/useGUsuarioSaveHook.ts b/src/packages/administrativo/hooks/User/useUserSaveHook.ts similarity index 93% rename from src/packages/administrativo/hooks/User/useGUsuarioSaveHook.ts rename to src/packages/administrativo/hooks/User/useUserSaveHook.ts index 8cd265c..2de2a22 100644 --- a/src/packages/administrativo/hooks/User/useGUsuarioSaveHook.ts +++ b/src/packages/administrativo/hooks/User/useUserSaveHook.ts @@ -5,7 +5,7 @@ import { UserInterface } from '../../interfaces/User/UserInterface'; import { UserSaveService } from '../../services/User/UserSaveService'; import { useResponse } from '@/shared/components/response/ResponseContext'; -export const useGUserSaveHook = () => { +export const useUserSaveHook = () => { const { setResponse } = useResponse(); const [User, setUser] = useState(); diff --git a/src/packages/administrativo/schemas/User/UserSchema.ts b/src/packages/administrativo/schemas/User/UserSchema.ts new file mode 100644 index 0000000..8ccfeea --- /dev/null +++ b/src/packages/administrativo/schemas/User/UserSchema.ts @@ -0,0 +1,11 @@ +import z from 'zod'; +import { SituacoesEnum } from '@/shared/enums/SituacoesEnum'; + +export const UserSchema = z.object({ + user_id: z.number().optional(), + name: z.string().min(3, { message: 'O nome deve ter no mínimo 3 caracteres.' }), + email: z.email({ message: 'Por favor, insira um email válido.' }), + password: z.string().optional(), + team: z.string().min(1, { message: 'A equipe é obrigatória.' }), + status: z.enum(SituacoesEnum), +}); \ No newline at end of file diff --git a/src/packages/administrativo/services/User/UserLoginService.ts b/src/packages/administrativo/services/User/UserLoginService.ts index 2e3e671..c5d5835 100644 --- a/src/packages/administrativo/services/User/UserLoginService.ts +++ b/src/packages/administrativo/services/User/UserLoginService.ts @@ -2,13 +2,15 @@ import { cookies } from 'next/headers'; -import { UserLoginData } from '../../data/User/UserLoginData'; +import UserLoginData from '../../data/User/UserLoginData'; import { redirect } from 'next/navigation'; import { withClientErrorHandler } from '@/withClientErrorHandler/withClientErrorHandler'; -async function executeUserLoginService(form: any) { +export default async function UserLoginService(form: any) { // Obtem a resposta da requisição const response = await UserLoginData(form); + + console.log("service",response) // Verifica se localizou o usuário if (response.data.user_id <= 0) { return { @@ -30,7 +32,5 @@ async function executeUserLoginService(form: any) { }); // Redireciona para a págian desejada - redirect('/user'); + redirect('/administrativo/usuarios'); } - -export const UserLoginService = withClientErrorHandler(executeUserLoginService) diff --git a/src/shared/enums/SituacoesEnum.ts b/src/shared/enums/SituacoesEnum.ts index 0392d90..3bb180a 100644 --- a/src/shared/enums/SituacoesEnum.ts +++ b/src/shared/enums/SituacoesEnum.ts @@ -1,4 +1,4 @@ export enum SituacoesEnum { - A = 'A', - I = 'I', + ATIVO = 'A', + INATIVO = 'I', } diff --git a/src/shared/services/api/Api.ts b/src/shared/services/api/Api.ts index cc2660a..a0ae006 100644 --- a/src/shared/services/api/Api.ts +++ b/src/shared/services/api/Api.ts @@ -48,7 +48,7 @@ export default class API { headers: { Accept: `${this.ApiSchema.contentType}`, 'Content-Type': `${this.ApiSchema.contentType}`, - Authorization: `Bearer ${this.ApiSchema.token}`, + Authorization: `Bearear ${this.ApiSchema.token}`, }, ...(filteredBody && { body: JSON.stringify(filteredBody) }), },