feat(): Refatoração de código, e preparação para criação do dashboard do cliente
This commit is contained in:
parent
bed3989eda
commit
bee7779e39
59 changed files with 2628 additions and 385 deletions
1046
Monitoramento Orius.postman_collection.json
Normal file
1046
Monitoramento Orius.postman_collection.json
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -0,0 +1,39 @@
|
|||
'use client';
|
||||
|
||||
import { useParams } from 'next/navigation';
|
||||
import { useLogServerHook } from '@/packages/administrativo/hooks/Log/useLogServerHook'; // importa seu hook customizado
|
||||
import { useEffect } from 'react';
|
||||
|
||||
export default function ClientePage() {
|
||||
// Captura o ID da rota (ex: /administrativo/clientes/6)
|
||||
const { id } = useParams();
|
||||
|
||||
// Hook customizado para carregar dados do log/server
|
||||
const { log, fetchLogServer } = useLogServerHook();
|
||||
|
||||
// Quando o componente montar, busca os dados do servidor/log
|
||||
useEffect(() => {
|
||||
if (id) fetchLogServer(Number(id));
|
||||
}, [id]);
|
||||
|
||||
// Caso não exista log
|
||||
if (!log) {
|
||||
return <p>Nenhum dado encontrado para o cliente {id}.</p>;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="p-4">
|
||||
<h1 className="text-2xl font-semibold mb-4">
|
||||
Detalhes do Log do Cliente #{id}
|
||||
</h1>
|
||||
|
||||
<div className="space-y-2">
|
||||
<p><strong>Nome:</strong> {log.name}</p>
|
||||
<p><strong>CNS:</strong> {log.cns}</p>
|
||||
<p><strong>Status:</strong> {log.status}</p>
|
||||
<p><strong>Email:</strong> {log.email}</p>
|
||||
{/* outros campos conforme LogInterface */}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
156
src/app/(protected)/administrativo/(client)/clientes/page.tsx
Normal file
156
src/app/(protected)/administrativo/(client)/clientes/page.tsx
Normal file
|
|
@ -0,0 +1,156 @@
|
|||
'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 cliente
|
||||
import ClientTable from '@/packages/administrativo/components/Client/ClientTable';
|
||||
import ClientForm from '@/packages/administrativo/components/Client/ClientForm';
|
||||
|
||||
// Hooks Específicos de cliente
|
||||
import { useClientIndexHook } from '@/packages/administrativo/hooks/Client/useClientIndexHook';
|
||||
import { useClientSaveHook } from '@/packages/administrativo/hooks/Client/useClientSaveHook';
|
||||
import { useClientDeleteHook } from '@/packages/administrativo/hooks/Client/useClientDeleteHook';
|
||||
|
||||
// Interface
|
||||
import { ClientInterface } from '@/packages/administrativo/interfaces/Client/ClientInterface';
|
||||
import { ClientSchema } from '@/packages/administrativo/schemas/Client/ClientSchema';
|
||||
import { SituacoesEnum } from '@/shared/enums/SituacoesEnum';
|
||||
|
||||
const initialClient: ClientInterface = {
|
||||
client_id: 0, // ID inicial padrão (auto incremento no banco)
|
||||
cns: '', // Código opcional de 10 caracteres
|
||||
name: '', // Nome obrigatório
|
||||
date_register: new Date().toISOString(), // Data atual no formato ISO
|
||||
state: '', // UF (2 caracteres)
|
||||
city: '', // Nome da cidade
|
||||
responsible: '', // Responsável pelo cliente
|
||||
consultant: '', // Consultor associado
|
||||
type_contract: '', // Tipo de contrato (ex: A, M, S...)
|
||||
}
|
||||
|
||||
export default function ClientsPage() {
|
||||
|
||||
const [buttonIsLoading, setButtonIsLoading] = useState(false);
|
||||
|
||||
// 1. Hooks de dados para cliente
|
||||
const { clients, fetchClients } = useClientIndexHook();
|
||||
const { saveClient } = useClientSaveHook();
|
||||
const { removeClient } = useClientDeleteHook(); // Presumindo que o hook existe e expõe `removeclient`
|
||||
|
||||
// 2. Estados da página
|
||||
const [selectedClient, setSelectedClient] = useState<ClientInterface | null>(null);
|
||||
const [isFormOpen, setIsFormOpen] = useState(false);
|
||||
const [clientToDelete, setClientToDelete] = useState<ClientInterface | null>(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((client: ClientInterface | null) => {
|
||||
setSelectedClient(client);
|
||||
setIsFormOpen(true);
|
||||
}, []);
|
||||
|
||||
const handleCloseForm = useCallback(() => {
|
||||
setSelectedClient(null);
|
||||
setIsFormOpen(false);
|
||||
}, []);
|
||||
|
||||
// 4. Função para salvar (criar ou editar)
|
||||
const handleSave = useCallback(
|
||||
async (formData: ClientInterface) => {
|
||||
|
||||
setButtonIsLoading(true);
|
||||
|
||||
await saveClient(formData);
|
||||
|
||||
setButtonIsLoading(false);
|
||||
|
||||
setIsFormOpen(false);
|
||||
|
||||
fetchClients(); // Atualiza a lista de clientes
|
||||
},
|
||||
[saveClient, fetchClients, handleCloseForm],
|
||||
);
|
||||
|
||||
// 5. Funções para exclusão
|
||||
const handleConfirmDelete = useCallback(
|
||||
(client: ClientInterface) => {
|
||||
setClientToDelete(client);
|
||||
openConfirmDialog();
|
||||
},
|
||||
[openConfirmDialog],
|
||||
);
|
||||
|
||||
const handleDelete = useCallback(async () => {
|
||||
if (!clientToDelete) return;
|
||||
|
||||
await removeClient(clientToDelete); // Chama o hook de remoção
|
||||
await fetchClients(); // Atualiza a lista
|
||||
setClientToDelete(null); // Limpa o estado
|
||||
handleCancel(); // Fecha o modal de confirmação
|
||||
}, [clientToDelete, fetchClients, handleCancel]);
|
||||
|
||||
// 6. Busca inicial dos dados
|
||||
useEffect(() => {
|
||||
fetchClients();
|
||||
}, []);
|
||||
|
||||
// 7. Renderização condicional de loading
|
||||
if (clients?.length == 0) {
|
||||
return <Loading type={2} />;
|
||||
}
|
||||
|
||||
// 8. Renderização da página
|
||||
return (
|
||||
<div>
|
||||
<Header
|
||||
title={'Clientes'}
|
||||
description={'Gerenciamento de Clientes do Sistema'}
|
||||
buttonText={'Novo Cliente'}
|
||||
buttonAction={(data) => handleOpenForm(data = initialClient)}
|
||||
/>
|
||||
|
||||
<Card>
|
||||
<CardContent>
|
||||
<ClientTable
|
||||
data={clients}
|
||||
onEdit={handleOpenForm}
|
||||
onDelete={handleConfirmDelete}
|
||||
/>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<ConfirmDialog
|
||||
isOpen={isConfirmOpen}
|
||||
title="Confirmar exclusão"
|
||||
description="Esta ação não pode ser desfeita."
|
||||
message={`Deseja realmente excluir o Cliente "${clientToDelete?.name}"?`}
|
||||
confirmText="Sim, excluir"
|
||||
cancelText="Cancelar"
|
||||
onConfirm={handleDelete}
|
||||
onCancel={handleCancel}
|
||||
/>
|
||||
|
||||
<ClientForm
|
||||
isOpen={isFormOpen}
|
||||
data={selectedClient}
|
||||
onClose={handleCloseForm}
|
||||
onSave={handleSave}
|
||||
buttonIsLoading={buttonIsLoading}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
17
src/components/StatusBadge.tsx
Normal file
17
src/components/StatusBadge.tsx
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
import { SituacoesEnum } from '@/shared/enums/SituacoesEnum';
|
||||
|
||||
/**
|
||||
* Exibe um selo (badge) visual para status do usuário: Ativo / Inativo
|
||||
*/
|
||||
export 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 (
|
||||
<span className={`${baseClasses} ${isActive ? activeClasses : inactiveClasses}`}>
|
||||
{isActive ? 'Ativo' : 'Inativo'}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
|
@ -35,8 +35,8 @@ const data = {
|
|||
isActive: false,
|
||||
items: [
|
||||
{
|
||||
title: 'Dashboard',
|
||||
url: '/dashboard/',
|
||||
title: 'Clientes',
|
||||
url: '/administrativo/clientes/',
|
||||
},
|
||||
],
|
||||
},
|
||||
|
|
@ -48,7 +48,7 @@ const data = {
|
|||
items: [
|
||||
{
|
||||
title: 'Usuários',
|
||||
url: '/usuarios/',
|
||||
url: '/administrativo/usuarios/',
|
||||
},
|
||||
],
|
||||
},
|
||||
|
|
|
|||
|
|
@ -37,10 +37,12 @@ export function NavUser({ user }: { user: UserAuthenticatedInterface }) {
|
|||
setIsConfirmOpen(true);
|
||||
}, []);
|
||||
|
||||
// Consifrma ação de log-out
|
||||
const handleLogoutConfirm = useCallback(async () => {
|
||||
logoutUsuario();
|
||||
}, []);
|
||||
|
||||
// Cancela ação de log-out
|
||||
const handleLogoutCancel = useCallback(async () => {
|
||||
setIsConfirmOpen(false);
|
||||
}, []);
|
||||
|
|
@ -110,7 +112,7 @@ export function NavUser({ user }: { user: UserAuthenticatedInterface }) {
|
|||
|
||||
<DropdownMenuItem className="cursor-pointer" onClick={() => handleConfirmOpen()}>
|
||||
<LogOut />
|
||||
Log out
|
||||
Sair do sistema
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
|
|
|
|||
195
src/packages/administrativo/components/Client/ClientForm.tsx
Normal file
195
src/packages/administrativo/components/Client/ClientForm.tsx
Normal file
|
|
@ -0,0 +1,195 @@
|
|||
'use client'; // Define que este componente será executado no lado do cliente (Client Component)
|
||||
|
||||
import z from 'zod';
|
||||
import { useEffect } from 'react';
|
||||
import { useForm, Controller } from 'react-hook-form';
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
|
||||
// Importação dos componentes da UI (botões, inputs, dialogs, etc.)
|
||||
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';
|
||||
|
||||
// Componente de botão com estado de carregamento
|
||||
import LoadingButton from '@/shared/components/loadingButton/LoadingButton';
|
||||
|
||||
// Importa a interface tipada separadamente
|
||||
import { UserFormInterface, FormValues } from '../../interfaces/User/UserFormInterface';
|
||||
|
||||
// Importa o hook que gerencia o formulário
|
||||
import { useUserFormHook } from '../../hooks/User/useUserFormHook';
|
||||
|
||||
// Componente principal do formulário de usuário
|
||||
export default function UserForm({ isOpen, data, onClose, onSave, buttonIsLoading }: UserFormInterface) {
|
||||
|
||||
// Usa o hook que centraliza toda a lógica do form
|
||||
const form = useUserFormHook(data);
|
||||
|
||||
// Callback de erro da submissão do formulário
|
||||
function onError(error: any) {
|
||||
console.log("error", error);
|
||||
}
|
||||
|
||||
return (
|
||||
// Componente de diálogo (modal)
|
||||
<Dialog
|
||||
open={isOpen} // Define se o diálogo está aberto
|
||||
onOpenChange={(open) => {
|
||||
if (!open) onClose(null, false); // Fecha o diálogo quando necessário
|
||||
}}
|
||||
>
|
||||
{/* Conteúdo do modal */}
|
||||
<DialogContent className="sm:max-w-[425px]">
|
||||
<DialogHeader>
|
||||
<DialogTitle>{data?.user_id ? 'Editar Usuário' : 'Novo Usuário'}</DialogTitle>
|
||||
<DialogDescription>Gerencie os dados do usuário aqui.</DialogDescription>
|
||||
</DialogHeader>
|
||||
|
||||
{/* Wrapper do formulário com react-hook-form */}
|
||||
<Form {...form}>
|
||||
<form onSubmit={form.handleSubmit(onSave, onError)} className="space-y-4">
|
||||
|
||||
{/* Campo: Nome */}
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="name"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Nome</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} placeholder="Digite o nome completo" />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
{/* Campo: Email */}
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="email"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Email</FormLabel>
|
||||
<FormControl>
|
||||
<Input type="email" {...field} placeholder="exemplo@email.com" />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
{/* Campo: Senha */}
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="password"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Senha</FormLabel>
|
||||
<FormControl>
|
||||
<Input
|
||||
type="password"
|
||||
{...field}
|
||||
placeholder={data ? 'Deixe em branco para não alterar' : 'Digite a senha'}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
{/* Campo: Equipe */}
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="team"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Equipe</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} placeholder="Digite o nome da equipe" />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
{/* Campo: Cargo */}
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="cargo"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Cargo</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} value={field.value ?? ''} placeholder="Digite o cargo do usuário" />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
{/* Campo: Status (Ativo/Inativo) */}
|
||||
<Controller
|
||||
name="status"
|
||||
control={form.control}
|
||||
render={({ field }) => (
|
||||
<div className="flex items-center space-x-2">
|
||||
<Checkbox
|
||||
checked={field.value === 'A'}
|
||||
onCheckedChange={(checked) => field.onChange(checked ? 'A' : 'I')}
|
||||
/>
|
||||
<Label>Ativo</Label>
|
||||
</div>
|
||||
)}
|
||||
/>
|
||||
|
||||
{/* Rodapé do formulário (botões) */}
|
||||
<DialogFooter className="mt-4">
|
||||
<DialogClose asChild>
|
||||
<Button
|
||||
variant="outline"
|
||||
type="button"
|
||||
onClick={() => onClose(null, false)}
|
||||
className="cursor-pointer"
|
||||
>
|
||||
Cancelar
|
||||
</Button>
|
||||
</DialogClose>
|
||||
|
||||
{/* Botão de salvar com loading */}
|
||||
<LoadingButton
|
||||
text={data?.user_id ? 'Salvar' : 'Cadastrar'}
|
||||
textLoading="Aguarde..."
|
||||
type="submit"
|
||||
loading={buttonIsLoading}
|
||||
/>
|
||||
</DialogFooter>
|
||||
|
||||
{/* Campos ocultos para dados técnicos */}
|
||||
<input type="hidden" {...form.register('user_id')} />
|
||||
<input type="hidden" {...form.register('date_register')} />
|
||||
<input type="hidden" {...form.register('date_update')} />
|
||||
</form>
|
||||
</Form>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
104
src/packages/administrativo/components/Client/ClientTable.tsx
Normal file
104
src/packages/administrativo/components/Client/ClientTable.tsx
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
'use client';
|
||||
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuGroup,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuSeparator,
|
||||
DropdownMenuTrigger,
|
||||
} from '@/components/ui/dropdown-menu';
|
||||
import {
|
||||
Table,
|
||||
TableBody,
|
||||
TableCell,
|
||||
TableFooter,
|
||||
TableHead,
|
||||
TableHeader,
|
||||
TableRow,
|
||||
} from '@/components/ui/table';
|
||||
|
||||
import { ChartPie, EllipsisIcon, PencilIcon, Trash2Icon } from 'lucide-react';
|
||||
import { ClientTableInterface } from '../../interfaces/Client/ClienteTableInterface';
|
||||
import { StatusBadge } from '@/components/StatusBadge';
|
||||
|
||||
export default function ClientTable({ data, pagination, onEdit, onDelete }: ClientTableInterface) {
|
||||
|
||||
// Inicializa o roteador
|
||||
const router = useRouter();
|
||||
|
||||
return (
|
||||
<Table>
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
<TableHead>#</TableHead>
|
||||
<TableHead>Status</TableHead>
|
||||
<TableHead>CNS</TableHead>
|
||||
<TableHead>Nome</TableHead>
|
||||
<TableHead className="text-right">Ações</TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
|
||||
<TableBody>
|
||||
{data.map((client) => (
|
||||
<TableRow key={client.client_id}>
|
||||
<TableCell className="font-medium">{client.client_id}</TableCell>
|
||||
<TableCell>
|
||||
<StatusBadge status={client.status as any} />
|
||||
</TableCell>
|
||||
<TableCell>{client.cns}</TableCell>
|
||||
<TableCell>{client.name}</TableCell>
|
||||
<TableCell className="text-right">
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button variant="outline" size="icon" className="cursor-pointer">
|
||||
<EllipsisIcon />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
|
||||
<DropdownMenuContent side="left" align="start">
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuItem
|
||||
className="cursor-pointer"
|
||||
onSelect={() => onEdit(client)}
|
||||
>
|
||||
<PencilIcon className="mr-2 h-4 w-4" />
|
||||
Editar
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItem
|
||||
className="cursor-pointer"
|
||||
onSelect={() => router.push(`/administrativo/clientes/${client.client_id}`)}
|
||||
>
|
||||
<ChartPie className="mr-2 h-4 w-4" />
|
||||
Dashboard
|
||||
</DropdownMenuItem>
|
||||
{/* <DropdownMenuSeparator />
|
||||
<DropdownMenuItem
|
||||
className="cursor-pointer"
|
||||
onSelect={() => onDelete(client)}
|
||||
>
|
||||
<Trash2Icon className="mr-2 h-4 w-4" />
|
||||
Remover
|
||||
</DropdownMenuItem> */}
|
||||
|
||||
</DropdownMenuGroup>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
<TableFooter>
|
||||
<TableRow>
|
||||
<TableCell colSpan={5}>
|
||||
{/* Se existir paginação, mostra o total de registros; senão, usa o tamanho da lista */}
|
||||
Total de clientes: {pagination?.total_records ?? data.length}
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
</TableFooter>
|
||||
</Table>
|
||||
);
|
||||
}
|
||||
|
|
@ -1,10 +1,11 @@
|
|||
'use client';
|
||||
'use client'; // Define que este componente será executado no lado do cliente (Client Component)
|
||||
|
||||
import z from 'zod';
|
||||
import { useEffect } from 'react';
|
||||
import { useForm, Controller } from 'react-hook-form';
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
|
||||
// Importação dos componentes da UI (botões, inputs, dialogs, etc.)
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Checkbox } from '@/components/ui/checkbox';
|
||||
import {
|
||||
|
|
@ -26,68 +27,47 @@ import {
|
|||
} 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';
|
||||
|
||||
// Componente de botão com estado de carregamento
|
||||
import LoadingButton from '@/shared/components/loadingButton/LoadingButton';
|
||||
|
||||
type FormValues = z.infer<typeof UserSchema>;
|
||||
// Importa a interface tipada separadamente
|
||||
import { UserFormInterface, FormValues } from '../../interfaces/User/UserFormInterface';
|
||||
|
||||
interface Props {
|
||||
isOpen: boolean;
|
||||
data: FormValues | null;
|
||||
onClose: (item: null, isFormStatus: boolean) => void;
|
||||
onSave: (data: FormValues) => void;
|
||||
buttonIsLoading: boolean;
|
||||
}
|
||||
// Importa o hook que gerencia o formulário
|
||||
import { useUserFormHook } from '../../hooks/User/useUserFormHook';
|
||||
|
||||
export default function UserForm({ isOpen, data, onClose, onSave, buttonIsLoading }: Props) {
|
||||
const form = useForm<FormValues>({
|
||||
resolver: zodResolver(UserSchema),
|
||||
defaultValues: {
|
||||
user_id: 0,
|
||||
name: '',
|
||||
email: '',
|
||||
password: '',
|
||||
team: '',
|
||||
position: 'string',
|
||||
status: SituacoesEnum.ATIVO,
|
||||
user_id_create: null,
|
||||
user_id_update: null,
|
||||
date_register: new Date().toISOString(),
|
||||
date_update: null
|
||||
},
|
||||
});
|
||||
// Componente principal do formulário de usuário
|
||||
export default function UserForm({ isOpen, data, onClose, onSave, buttonIsLoading }: UserFormInterface) {
|
||||
|
||||
// Atualiza o formulário quando recebe dados para edição
|
||||
useEffect(() => {
|
||||
if (data) form.reset(data);
|
||||
console.log("form", form.getValues())
|
||||
}, [data, form]);
|
||||
// Usa o hook que centraliza toda a lógica do form
|
||||
const form = useUserFormHook(data);
|
||||
|
||||
// Callback de erro da submissão do formulário
|
||||
function onError(error: any) {
|
||||
console.log("error", error)
|
||||
}
|
||||
|
||||
function submit(response: any) {
|
||||
console.log("submit", response)
|
||||
console.log("error", error);
|
||||
}
|
||||
|
||||
return (
|
||||
// Componente de diálogo (modal)
|
||||
<Dialog
|
||||
open={isOpen}
|
||||
open={isOpen} // Define se o diálogo está aberto
|
||||
onOpenChange={(open) => {
|
||||
if (!open) onClose(null, false);
|
||||
if (!open) onClose(null, false); // Fecha o diálogo quando necessário
|
||||
}}
|
||||
>
|
||||
{/* Conteúdo do modal */}
|
||||
<DialogContent className="sm:max-w-[425px]">
|
||||
<DialogHeader>
|
||||
<DialogTitle>{data?.user_id ? 'Editar Usuário' : 'Novo Usuário'}</DialogTitle>
|
||||
<DialogDescription>Gerencie os dados do usuário aqui.</DialogDescription>
|
||||
</DialogHeader>
|
||||
|
||||
{/* Wrapper do formulário com react-hook-form */}
|
||||
<Form {...form}>
|
||||
<form onSubmit={form.handleSubmit(onSave, onError)} className="space-y-4">
|
||||
{/* Nome */}
|
||||
|
||||
{/* Campo: Nome */}
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="name"
|
||||
|
|
@ -101,7 +81,8 @@ export default function UserForm({ isOpen, data, onClose, onSave, buttonIsLoadin
|
|||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
{/* Email */}
|
||||
|
||||
{/* Campo: Email */}
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="email"
|
||||
|
|
@ -115,7 +96,8 @@ export default function UserForm({ isOpen, data, onClose, onSave, buttonIsLoadin
|
|||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
{/* Senha */}
|
||||
|
||||
{/* Campo: Senha */}
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="password"
|
||||
|
|
@ -123,13 +105,18 @@ export default function UserForm({ isOpen, data, onClose, onSave, buttonIsLoadin
|
|||
<FormItem>
|
||||
<FormLabel>Senha</FormLabel>
|
||||
<FormControl>
|
||||
<Input type="password" {...field} placeholder={data ? 'Deixe em branco para não alterar' : 'Digite a senha'} />
|
||||
<Input
|
||||
type="password"
|
||||
{...field}
|
||||
placeholder={data ? 'Deixe em branco para não alterar' : 'Digite a senha'}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
{/* Equipe */}
|
||||
|
||||
{/* Campo: Equipe */}
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="team"
|
||||
|
|
@ -144,22 +131,22 @@ export default function UserForm({ isOpen, data, onClose, onSave, buttonIsLoadin
|
|||
)}
|
||||
/>
|
||||
|
||||
{/* Cargo */}
|
||||
{/* Campo: Cargo */}
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="position"
|
||||
name="cargo"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Cargo</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} placeholder="Digite o cargo do usuário" />
|
||||
<Input {...field} value={field.value ?? ''} placeholder="Digite o cargo do usuário" />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
{/* Status */}
|
||||
{/* Campo: Status (Ativo/Inativo) */}
|
||||
<Controller
|
||||
name="status"
|
||||
control={form.control}
|
||||
|
|
@ -173,7 +160,8 @@ export default function UserForm({ isOpen, data, onClose, onSave, buttonIsLoadin
|
|||
</div>
|
||||
)}
|
||||
/>
|
||||
{/* Rodapé */}
|
||||
|
||||
{/* Rodapé do formulário (botões) */}
|
||||
<DialogFooter className="mt-4">
|
||||
<DialogClose asChild>
|
||||
<Button
|
||||
|
|
@ -185,6 +173,8 @@ export default function UserForm({ isOpen, data, onClose, onSave, buttonIsLoadin
|
|||
Cancelar
|
||||
</Button>
|
||||
</DialogClose>
|
||||
|
||||
{/* Botão de salvar com loading */}
|
||||
<LoadingButton
|
||||
text={data?.user_id ? 'Salvar' : 'Cadastrar'}
|
||||
textLoading="Aguarde..."
|
||||
|
|
@ -192,7 +182,8 @@ export default function UserForm({ isOpen, data, onClose, onSave, buttonIsLoadin
|
|||
loading={buttonIsLoading}
|
||||
/>
|
||||
</DialogFooter>
|
||||
{/* Campo oculto para o ID */}
|
||||
|
||||
{/* Campos ocultos para dados técnicos */}
|
||||
<input type="hidden" {...form.register('user_id')} />
|
||||
<input type="hidden" {...form.register('date_register')} />
|
||||
<input type="hidden" {...form.register('date_update')} />
|
||||
|
|
@ -201,4 +192,4 @@ export default function UserForm({ isOpen, data, onClose, onSave, buttonIsLoadin
|
|||
</DialogContent>
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,41 +4,17 @@ import Image from 'next/image';
|
|||
import { cn } from '@/lib/utils';
|
||||
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 { useForm } from 'react-hook-form';
|
||||
import { useState } from 'react';
|
||||
import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from '../../../../components/ui/form';
|
||||
import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from '@/components/ui/form';
|
||||
import { Checkbox } from '@/components/ui/checkbox';
|
||||
import LoadingButton from '@/shared/components/loadingButton/LoadingButton';
|
||||
import { Button } from '../../../../components/ui/button';
|
||||
import { UserLoginSchema } from '@/packages/administrativo/schemas/User/UserLoginSchema';
|
||||
import { useUserFormLoginHook } from '../../hooks/User/useUserFormLoginHook';
|
||||
import { UserFormLoginInterface } from '../../interfaces/User/UserFormLoginInterface';
|
||||
|
||||
type FormValues = z.infer<typeof UserLoginSchema>;
|
||||
|
||||
export function LoginForm({ className, ...props }: React.ComponentProps<'div'>) {
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
const form = useForm<FormValues>({
|
||||
resolver: zodResolver(UserLoginSchema),
|
||||
defaultValues: {
|
||||
email: '',
|
||||
password: '',
|
||||
},
|
||||
});
|
||||
|
||||
// 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);
|
||||
|
||||
// Realiza o login
|
||||
await UserLoginService(values);
|
||||
|
||||
// Removo o estado de loading do botão
|
||||
setLoading(false);
|
||||
};
|
||||
/**
|
||||
* Componente de login — utiliza hook para gerenciar estado e lógica.
|
||||
*/
|
||||
export function LoginForm({ className, ...props }: UserFormLoginInterface) {
|
||||
const { form, onSubmit, loading } = useUserFormLoginHook(); // Hook customizado
|
||||
|
||||
return (
|
||||
<div className={cn('flex flex-col gap-6', className)} {...props}>
|
||||
|
|
@ -46,12 +22,15 @@ export function LoginForm({ className, ...props }: React.ComponentProps<'div'>)
|
|||
<CardContent className="grid p-0 md:grid-cols-2">
|
||||
<Form {...form}>
|
||||
<form onSubmit={form.handleSubmit(onSubmit)} className="flex flex-col gap-3 p-6 md:p-8">
|
||||
{/* Cabeçalho */}
|
||||
<div className="mb-6 flex flex-col items-center text-center">
|
||||
<h1 className="text-2xl font-bold">Bem vindo de volta!</h1>
|
||||
<h1 className="text-2xl font-bold">Bem-vindo de volta!</h1>
|
||||
<p className="text-muted-foreground text-balance">
|
||||
Entre na sua conta Orius Tecnologia.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Campo: Login */}
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="email"
|
||||
|
|
@ -65,6 +44,8 @@ export function LoginForm({ className, ...props }: React.ComponentProps<'div'>)
|
|||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
{/* Campo: Senha */}
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="password"
|
||||
|
|
@ -78,28 +59,35 @@ export function LoginForm({ className, ...props }: React.ComponentProps<'div'>)
|
|||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
{/* Botão de loading */}
|
||||
|
||||
{/* Checkbox: Lembrar acesso */}
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="rememberMe"
|
||||
render={({ field }) => (
|
||||
<FormItem className="flex items-center space-x-2 cursor-pointer">
|
||||
<FormControl>
|
||||
<Checkbox
|
||||
checked={field.value}
|
||||
onCheckedChange={field.onChange}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormLabel className="text-sm font-normal cursor-pointer">Lembrar acesso</FormLabel>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
{/* Botão de envio com loading */}
|
||||
<LoadingButton
|
||||
text="Entrar"
|
||||
textLoading="Aguarde..."
|
||||
type="submit"
|
||||
loading={loading}
|
||||
/>
|
||||
<div className="after:border-border relative my-4 text-center text-sm after:absolute after:inset-0 after:top-1/2 after:z-0 after:flex after:items-center after:border-t">
|
||||
<span className="bg-card text-muted-foreground relative z-10 px-2">
|
||||
Ou entre em contato
|
||||
</span>
|
||||
</div>
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<Button variant="outline" type="button" className="w-full">
|
||||
Chamar no Whatsapp
|
||||
</Button>
|
||||
<Button variant="outline" type="button" className="w-full">
|
||||
Chamar no Local
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
</Form>
|
||||
|
||||
{/* Lado direito (imagem) */}
|
||||
<div className="bg-brand relative hidden items-center justify-center md:flex">
|
||||
<Image
|
||||
src="/images/logo-login.svg"
|
||||
|
|
@ -111,11 +99,12 @@ export function LoginForm({ className, ...props }: React.ComponentProps<'div'>)
|
|||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
{/* Rodapé */}
|
||||
<div className="text-muted-foreground text-center text-xs">
|
||||
Ao clicar você concorda com <a href="#">Nossos termos de serviços</a> e{' '}
|
||||
<a href="#">
|
||||
Políticas de Privacidade
|
||||
</a>.
|
||||
Ao clicar você concorda com{' '}
|
||||
<a href="#">Nossos termos de serviços</a> e{' '}
|
||||
<a href="#">Políticas de Privacidade</a>.
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -19,32 +19,10 @@ import {
|
|||
} 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';
|
||||
import { UserTableInterface } from '../../interfaces/User/UserTableInterface';
|
||||
import { StatusBadge } from '@/components/StatusBadge';
|
||||
|
||||
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 (
|
||||
<span className={`${baseClasses} ${isActive ? activeClasses : inactiveClasses}`}>
|
||||
{isActive ? 'Ativo' : 'Inativo'}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
export default function UserTable({ data, onEdit, onDelete }: UserTableProps) {
|
||||
export default function UserTable({ data, onEdit, onDelete }: UserTableInterface) {
|
||||
return (
|
||||
<Table>
|
||||
<TableHeader>
|
||||
|
|
|
|||
32
src/packages/administrativo/data/Client/ClientDeleteData.ts
Normal file
32
src/packages/administrativo/data/Client/ClientDeleteData.ts
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
'use server'
|
||||
// Define que este módulo será executado no lado do servidor (Server Action do Next.js)
|
||||
|
||||
import { Methods } from '@/shared/services/api/enums/ApiMethodEnum';
|
||||
// Importa o enumerador que contém os métodos HTTP disponíveis (GET, POST, PUT, DELETE)
|
||||
|
||||
import API from '@/shared/services/api/Api';
|
||||
// Importa a classe responsável por centralizar e padronizar as chamadas HTTP na aplicação
|
||||
|
||||
import { withClientErrorHandler } from '@/withClientErrorHandler/withClientErrorHandler';
|
||||
// Importa o decorador que adiciona tratamento global de erros às funções assíncronas
|
||||
|
||||
// Função principal responsável por enviar a requisição de exclusão de um cliente
|
||||
async function executeClientDeleteData(usuarioId: number) {
|
||||
|
||||
// Cria uma nova instância da classe API, que gerencia headers, baseURL e envio das requisições
|
||||
const api = new API();
|
||||
|
||||
// Envia a requisição DELETE para o endpoint correspondente ao cliente informado
|
||||
const response = await api.send({
|
||||
'method': Methods.DELETE, // Define o método HTTP como DELETE
|
||||
'endpoint': `administrativo/client/${usuarioId}` // Define o endpoint incluindo o ID do cliente
|
||||
});
|
||||
|
||||
// Retorna a resposta da API, contendo status, mensagem e possíveis dados adicionais
|
||||
return response;
|
||||
}
|
||||
|
||||
// Exporta a função encapsulada com o tratador global de erros
|
||||
export const ClientDeleteData = withClientErrorHandler(executeClientDeleteData);
|
||||
// `withClientErrorHandler` garante que qualquer exceção durante a execução da função seja capturada
|
||||
// Isso permite um tratamento padronizado de erros e evita quebra no fluxo de execução do app
|
||||
39
src/packages/administrativo/data/Client/ClientIndexData.ts
Normal file
39
src/packages/administrativo/data/Client/ClientIndexData.ts
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
'use server';
|
||||
// Indica que este módulo será executado no lado do servidor (Server Action do Next.js)
|
||||
|
||||
import { Methods } from '@/shared/services/api/enums/ApiMethodEnum';
|
||||
// Importa o enum com os tipos de métodos HTTP disponíveis (GET, POST, PUT, DELETE...)
|
||||
|
||||
import API from '@/shared/services/api/Api';
|
||||
// Importa a classe responsável por centralizar chamadas à API (wrapper de fetch ou axios)
|
||||
|
||||
import { withClientErrorHandler } from '@/withClientErrorHandler/withClientErrorHandler';
|
||||
// Importa um decorador/função HOC que trata erros de forma padronizada nas requisições
|
||||
|
||||
/**
|
||||
* Função principal responsável por buscar a lista de clientes na API.
|
||||
* Executa uma requisição HTTP GET para o endpoint administrativo/client.
|
||||
*/
|
||||
async function executeClientIndexData() {
|
||||
|
||||
// Instancia o serviço de API para uso nesta função
|
||||
const api = new API();
|
||||
|
||||
// Executa uma requisição GET para o endpoint administrativo/client/
|
||||
// - Usa o método 'send' da classe API
|
||||
// - Passa o método HTTP e o endpoint como parâmetros
|
||||
const response = await api.send({
|
||||
method: Methods.GET, // Método HTTP GET
|
||||
endpoint: `administrativo/client/`, // Rota da API que retorna a lista de clientes
|
||||
});
|
||||
|
||||
// Retorna a resposta obtida da API
|
||||
return response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Exporta a função encapsulada com o handler de erro.
|
||||
* Caso ocorra falha na requisição, o withClientErrorHandler
|
||||
* intercepta o erro e o trata de forma uniforme (ex: logging, toast, etc.)
|
||||
*/
|
||||
export const ClientIndexData = withClientErrorHandler(executeClientIndexData);
|
||||
42
src/packages/administrativo/data/Client/ClientSaveData.ts
Normal file
42
src/packages/administrativo/data/Client/ClientSaveData.ts
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
'use server'
|
||||
// Define que este módulo será executado no lado do servidor (Server Action do Next.js)
|
||||
|
||||
import { Methods } from '@/shared/services/api/enums/ApiMethodEnum';
|
||||
// Importa o enumerador que define os métodos HTTP disponíveis (GET, POST, PUT, DELETE)
|
||||
|
||||
import API from '@/shared/services/api/Api';
|
||||
// Importa a classe responsável por realizar as chamadas HTTP centralizadas da aplicação
|
||||
|
||||
import { withClientErrorHandler } from '@/withClientErrorHandler/withClientErrorHandler';
|
||||
// Importa o decorador que adiciona tratamento global de erros à função principal
|
||||
|
||||
import { ClientInterface } from '../../interfaces/Client/ClientInterface';
|
||||
// Importa a tipagem do objeto de cliente, garantindo consistência nos dados enviados
|
||||
|
||||
// Função principal responsável por salvar (criar ou atualizar) os dados de um cliente
|
||||
async function executeClientSaveData(form: ClientInterface) {
|
||||
// Verifica se existe um `client_id`; se sim, trata-se de uma atualização (PUT), caso contrário, é um novo cadastro (POST)
|
||||
const isUpdate = Boolean(form.client_id);
|
||||
|
||||
// Cria uma nova instância da classe API para enviar a requisição
|
||||
const api = new API();
|
||||
|
||||
// Envia a requisição para o endpoint responsável por salvar os dados do cliente
|
||||
const response = await api.send({
|
||||
// Define o método HTTP dinamicamente com base no tipo de operação (POST ou PUT)
|
||||
'method': isUpdate ? Methods.PUT : Methods.POST,
|
||||
|
||||
// Define o endpoint, incluindo o `client_id` se for atualização
|
||||
'endpoint': `administrativo/client/${form.client_id || ''}`,
|
||||
|
||||
// Corpo da requisição contendo os dados do formulário
|
||||
'body': form
|
||||
});
|
||||
|
||||
// Retorna a resposta da API (pode conter status, dados ou mensagens)
|
||||
return response;
|
||||
}
|
||||
|
||||
// Exporta a função encapsulada com o tratador global de erros
|
||||
export const ClientSaveData = withClientErrorHandler(executeClientSaveData);
|
||||
// `withClientErrorHandler` assegura que qualquer erro durante a execução será capturado e tratado de forma padronizada
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
'use server'
|
||||
// Indica que este módulo será executado no lado do servidor (Server Action do Next.js)
|
||||
|
||||
import { Methods } from '@/shared/services/api/enums/ApiMethodEnum';
|
||||
// Importa o enumerador que contém os métodos HTTP padronizados (GET, POST, PUT, DELETE)
|
||||
|
||||
import API from '@/shared/services/api/Api';
|
||||
// Importa a classe responsável por realizar requisições HTTP à API backend
|
||||
|
||||
import { withClientErrorHandler } from '@/withClientErrorHandler/withClientErrorHandler';
|
||||
// Importa o wrapper que padroniza o tratamento de erros e respostas para o cliente
|
||||
|
||||
// Função principal responsável por buscar um usuário específico pelo seu ID
|
||||
async function executeLogIndexByIDData(client_id: number) {
|
||||
|
||||
// Cria uma nova instância da classe de comunicação com a API
|
||||
const api = new API();
|
||||
|
||||
// Envia uma requisição GET ao endpoint que retorna os dados de um usuário específico
|
||||
const response = await api.send({
|
||||
'method': Methods.GET, // Define o método HTTP da requisição
|
||||
'endpoint': `administrativo/log/${client_id}` // Monta dinamicamente o endpoint com o ID do usuário
|
||||
});
|
||||
|
||||
// Retorna a resposta recebida da API (dados do usuário ou erro)
|
||||
return response;
|
||||
}
|
||||
|
||||
// Exporta a função encapsulada com o handler de erro
|
||||
// Isso garante que exceções sejam tratadas de forma padronizada na camada superior
|
||||
export const LogIndexByClientIDData = withClientErrorHandler(executeLogIndexByIDData);
|
||||
39
src/packages/administrativo/data/Log/LogIndexData.ts
Normal file
39
src/packages/administrativo/data/Log/LogIndexData.ts
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
'use server';
|
||||
// Indica que este módulo será executado no lado do servidor (Server Action do Next.js)
|
||||
|
||||
import { Methods } from '@/shared/services/api/enums/ApiMethodEnum';
|
||||
// Importa o enum com os tipos de métodos HTTP disponíveis (GET, POST, PUT, DELETE...)
|
||||
|
||||
import API from '@/shared/services/api/Api';
|
||||
// Importa a classe responsável por centralizar chamadas à API (wrapper de fetch ou axios)
|
||||
|
||||
import { withClientErrorHandler } from '@/withClientErrorHandler/withClientErrorHandler';
|
||||
// Importa um decorador/função HOC que trata erros de forma padronizada nas requisições
|
||||
|
||||
/**
|
||||
* Função principal responsável por buscar a lista de loges na API.
|
||||
* Executa uma requisição HTTP GET para o endpoint administrativo/log.
|
||||
*/
|
||||
async function executeLogIndexData() {
|
||||
|
||||
// Instancia o serviço de API para uso nesta função
|
||||
const api = new API();
|
||||
|
||||
// Executa uma requisição GET para o endpoint administrativo/log/
|
||||
// - Usa o método 'send' da classe API
|
||||
// - Passa o método HTTP e o endpoint como parâmetros
|
||||
const response = await api.send({
|
||||
method: Methods.GET, // Método HTTP GET
|
||||
endpoint: `administrativo/log/`, // Rota da API que retorna a lista de loges
|
||||
});
|
||||
|
||||
// Retorna a resposta obtida da API
|
||||
return response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Exporta a função encapsulada com o handler de erro.
|
||||
* Caso ocorra falha na requisição, o withlogErrorHandler
|
||||
* intercepta o erro e o trata de forma uniforme (ex: logging, toast, etc.)
|
||||
*/
|
||||
export const LogIndexData = withClientErrorHandler(executeLogIndexData);
|
||||
31
src/packages/administrativo/data/Log/LogServerData.ts
Normal file
31
src/packages/administrativo/data/Log/LogServerData.ts
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
'use server'
|
||||
// Indica que este módulo será executado no lado do servidor (Server Action do Next.js)
|
||||
|
||||
import { Methods } from '@/shared/services/api/enums/ApiMethodEnum';
|
||||
// Importa o enumerador que contém os métodos HTTP padronizados (GET, POST, PUT, DELETE)
|
||||
|
||||
import API from '@/shared/services/api/Api';
|
||||
// Importa a classe responsável por realizar requisições HTTP à API backend
|
||||
|
||||
import { withClientErrorHandler } from '@/withClientErrorHandler/withClientErrorHandler';
|
||||
// Importa o wrapper que padroniza o tratamento de erros e respostas para o cliente
|
||||
|
||||
// Função principal responsável por buscar um usuário específico pelo seu ID
|
||||
async function executeLogServerData(client_id: number) {
|
||||
|
||||
// Cria uma nova instância da classe de comunicação com a API
|
||||
const api = new API();
|
||||
|
||||
// Envia uma requisição GET ao endpoint que retorna os dados de um usuário específico
|
||||
const response = await api.send({
|
||||
'method': Methods.GET, // Define o método HTTP da requisição
|
||||
'endpoint': `administrativo/log/server/${client_id}` // Monta dinamicamente o endpoint com o ID do usuário
|
||||
});
|
||||
|
||||
// Retorna a resposta recebida da API (dados do usuário ou erro)
|
||||
return response;
|
||||
}
|
||||
|
||||
// Exporta a função encapsulada com o handler de erro
|
||||
// Isso garante que exceções sejam tratadas de forma padronizada na camada superior
|
||||
export const LogServerData = withClientErrorHandler(executeLogServerData);
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
import { withClientErrorHandler } from "@/shared/actions/withClientErrorHandler/withClientErrorHandler";
|
||||
import ApiResponseInterface from "@/shared/services/api/interfaces/ApiResponseInterface";
|
||||
import API from "@/shared/services/api/Api";
|
||||
import { Methods } from "@/shared/services/api/enums/ApiMethodEnum";
|
||||
import TImovelInterface from "../../interfaces/TImovel/TImovelInterface";
|
||||
|
||||
async function executeTImovelDeleteData(data: TImovelInterface): Promise<ApiResponseInterface> {
|
||||
|
||||
const api = new API();
|
||||
|
||||
return await api.send({
|
||||
method: Methods.DELETE,
|
||||
endpoint: `administrativo/t_imovel/${data.imovel_id}`
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
export const TImovelDeleteData = withClientErrorHandler(executeTImovelDeleteData);
|
||||
|
|
@ -1,17 +0,0 @@
|
|||
import { withClientErrorHandler } from "@/shared/actions/withClientErrorHandler/withClientErrorHandler";
|
||||
import API from "@/shared/services/api/Api";
|
||||
import { Methods } from "@/shared/services/api/enums/ApiMethodEnum";
|
||||
import ApiResponseInterface from "@/shared/services/api/interfaces/ApiResponseInterface";
|
||||
|
||||
async function executeTImovelIndexData(): Promise<ApiResponseInterface> {
|
||||
|
||||
const api = new API();
|
||||
|
||||
return api.send({
|
||||
method: Methods.GET,
|
||||
endpoint: `administrativo/t_imovel/classe/1`
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
export const TImovelIndexData = withClientErrorHandler(executeTImovelIndexData);
|
||||
|
|
@ -1,24 +0,0 @@
|
|||
import { withClientErrorHandler } from "@/shared/actions/withClientErrorHandler/withClientErrorHandler";
|
||||
import TImovelInterface from "../../interfaces/TImovel/TImovelInterface";
|
||||
import ApiResponseInterface from "@/shared/services/api/interfaces/ApiResponseInterface";
|
||||
import API from "@/shared/services/api/Api";
|
||||
import { Methods } from "@/shared/services/api/enums/ApiMethodEnum";
|
||||
|
||||
async function executeTImovelSaveData(data: TImovelInterface): Promise<ApiResponseInterface> {
|
||||
|
||||
// Verifica se existe ID da cidade para decidir se é atualização (PUT) ou criação (POST)
|
||||
const isUpdate = Boolean(data.imovel_id);
|
||||
|
||||
// Instancia o cliente da API para enviar a requisição
|
||||
const api = new API();
|
||||
|
||||
// Executa a requisição para a API com o método apropriado e envia os dados no corpo
|
||||
return await api.send({
|
||||
method: isUpdate ? Methods.PUT : Methods.POST, // PUT se atualizar, POST se criar
|
||||
endpoint: `administrativo/t_imovel/${data.imovel_id || ''}`, // endpoint dinâmico
|
||||
body: data, // payload enviado para a API
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
export const TImovelSaveData = withClientErrorHandler(executeTImovelSaveData);
|
||||
|
|
@ -1,19 +1,31 @@
|
|||
'use server'
|
||||
import { Methods } from '@/shared/services/api/enums/ApiMethodEnum';
|
||||
import API from '@/shared/services/api/Api';
|
||||
import { withClientErrorHandler } from '@/withClientErrorHandler/withClientErrorHandler';
|
||||
// Indica que este módulo será executado no lado do servidor (Server Action do Next.js)
|
||||
|
||||
import { Methods } from '@/shared/services/api/enums/ApiMethodEnum';
|
||||
// Importa o enumerador que contém os métodos HTTP padronizados (GET, POST, PUT, DELETE)
|
||||
|
||||
import API from '@/shared/services/api/Api';
|
||||
// Importa a classe responsável por realizar requisições HTTP à API backend
|
||||
|
||||
import { withClientErrorHandler } from '@/withClientErrorHandler/withClientErrorHandler';
|
||||
// Importa o wrapper que padroniza o tratamento de erros e respostas para o cliente
|
||||
|
||||
// Função principal responsável por buscar um usuário específico pelo seu ID
|
||||
async function executeUserIndexByIDData(user_id: number) {
|
||||
|
||||
// Cria uma nova instância da classe de comunicação com a API
|
||||
const api = new API();
|
||||
|
||||
// Envia uma requisição GET ao endpoint que retorna os dados de um usuário específico
|
||||
const response = await api.send({
|
||||
'method': Methods.GET,
|
||||
'endpoint': `administrativo/user/${user_id}`
|
||||
'method': Methods.GET, // Define o método HTTP da requisição
|
||||
'endpoint': `administrativo/user/${user_id}` // Monta dinamicamente o endpoint com o ID do usuário
|
||||
});
|
||||
|
||||
// Retorna a resposta recebida da API (dados do usuário ou erro)
|
||||
return response;
|
||||
|
||||
}
|
||||
|
||||
export const UserIndexByIDData = withClientErrorHandler(executeUserIndexByIDData)
|
||||
// Exporta a função encapsulada com o handler de erro
|
||||
// Isso garante que exceções sejam tratadas de forma padronizada na camada superior
|
||||
export const UserIndexByIDData = withClientErrorHandler(executeUserIndexByIDData);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,37 @@
|
|||
'use client';
|
||||
// Define que este módulo será executado no lado do cliente (Client Component do Next.js)
|
||||
|
||||
import { useState } from 'react';
|
||||
// Importa o hook `useState` do React (embora não esteja sendo usado aqui, pode ser útil em versões futuras)
|
||||
|
||||
import { useResponse } from '@/shared/components/response/ResponseContext';
|
||||
// Importa o hook de contexto responsável por exibir feedbacks globais (como toasts, alerts ou modais)
|
||||
|
||||
import { ClientDeleteService } from '../../services/Client/ClientDeleteService';
|
||||
// Importa o serviço responsável por realizar a exclusão do cliente via API
|
||||
|
||||
import { ClientInterface } from '../../interfaces/Client/ClientInterface';
|
||||
// Importa a tipagem do objeto `ClientInterface` para garantir segurança de tipo e padronização dos dados
|
||||
|
||||
// Hook personalizado responsável por encapsular a lógica de exclusão de clientes
|
||||
export const useClientDeleteHook = () => {
|
||||
// Obtém a função `setResponse` do contexto global, usada para exibir feedbacks ao usuário
|
||||
const { setResponse } = useResponse();
|
||||
|
||||
// Função assíncrona que executa a exclusão de um cliente específico
|
||||
const removeClient = async (client: ClientInterface) => {
|
||||
try {
|
||||
// Chama o serviço de exclusão, enviando o ID do cliente como parâmetro
|
||||
const response = await ClientDeleteService(client.client_id);
|
||||
|
||||
// Define a resposta no contexto global, permitindo exibir mensagem de sucesso/erro na interface
|
||||
setResponse(response);
|
||||
} catch (error) {
|
||||
// Captura e exibe o erro no console (embora o handler global já trate exceções)
|
||||
console.error('Erro ao remover usuário:', error);
|
||||
}
|
||||
};
|
||||
|
||||
// Retorna a função principal de exclusão, permitindo que o componente que usa este hook a invoque
|
||||
return { removeClient };
|
||||
};
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
'use client';
|
||||
// Define que este arquivo será executado no lado do cliente (Next.js Client Component)
|
||||
|
||||
import { useState } from 'react';
|
||||
import { ClientInterface } from '../../interfaces/Client/ClientInterface';
|
||||
import { ClientIndexService } from '../../services/Client/ClientIndexService';
|
||||
import { useResponse } from '@/shared/components/response/ResponseContext';
|
||||
|
||||
// Hook personalizado responsável por gerenciar a listagem de clientes
|
||||
export const useClientIndexHook = () => {
|
||||
// Obtém a função para definir mensagens globais de resposta (toast, modal, etc.)
|
||||
const { setResponse } = useResponse();
|
||||
|
||||
// Estado local que armazena a lista de clientes retornados pela API
|
||||
const [clients, setClients] = useState<ClientInterface[]>([]);
|
||||
|
||||
// Função responsável por buscar os clientes da API
|
||||
const fetchClients = async () => {
|
||||
try {
|
||||
// Chama o serviço que faz a requisição HTTP
|
||||
const response = await ClientIndexService();
|
||||
|
||||
// Atualiza o estado local com os dados retornados
|
||||
setClients(response.data);
|
||||
|
||||
// Define a resposta global (útil para exibir mensagens de sucesso/erro)
|
||||
setResponse(response);
|
||||
} catch (error) {
|
||||
// Caso ocorra erro na requisição, registra no console
|
||||
console.error('Erro ao buscar clientes:', error);
|
||||
|
||||
// Atualiza o contexto de resposta com erro
|
||||
setResponse({
|
||||
status: 'error',
|
||||
message: 'Falha ao carregar a lista de clientes.',
|
||||
data: [],
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// Retorna as variáveis e funções que o componente poderá utilizar
|
||||
return { clients, fetchClients };
|
||||
};
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
'use client';
|
||||
// Indica que este arquivo será executado no lado do cliente (Client Component do Next.js)
|
||||
|
||||
import { useState } from 'react';
|
||||
import { ClientInterface } from '../../interfaces/Client/ClientInterface';
|
||||
import { ClientSaveService } from '../../services/Client/ClientSaveService';
|
||||
import { useResponse } from '@/shared/components/response/ResponseContext'; // 🔧 corrigido nome de import (clientesponse → clientResponse)
|
||||
|
||||
// Hook personalizado responsável por salvar (criar ou atualizar) clientes
|
||||
export const useClientSaveHook = () => {
|
||||
// Obtém a função global para definir mensagens de resposta (toast, modal, etc.)
|
||||
const { setResponse } = useResponse();
|
||||
|
||||
// Estado local para armazenar o cliente salvo/retornado pela API
|
||||
const [cliente, setCliente] = useState<ClientInterface>();
|
||||
|
||||
// Função responsável por enviar os dados do cliente para a API
|
||||
const saveClient = async (clientData: ClientInterface) => {
|
||||
try {
|
||||
// Faz a chamada ao serviço que salva os dados do cliente
|
||||
const response = await ClientSaveService(clientData);
|
||||
|
||||
// Atualiza o estado com o cliente retornado (pode conter ID ou dados processados)
|
||||
setCliente(response.data);
|
||||
|
||||
// Define a resposta global (útil para feedback de sucesso)
|
||||
setResponse(response);
|
||||
} catch (error) {
|
||||
// Em caso de erro, exibe no console para depuração
|
||||
console.error('Erro ao salvar cliente:', error);
|
||||
|
||||
// Define resposta de erro global
|
||||
setResponse({
|
||||
status: 'error',
|
||||
message: 'Falha ao salvar o cliente.',
|
||||
data: null,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// Retorna o cliente salvo e a função responsável por salvar
|
||||
return { cliente, saveClient };
|
||||
};
|
||||
30
src/packages/administrativo/hooks/Log/useLogServerHook.ts
Normal file
30
src/packages/administrativo/hooks/Log/useLogServerHook.ts
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
'use client';
|
||||
|
||||
import { useState } from 'react';
|
||||
import { LogInterface } from '../../interfaces/Log/LogInterface';
|
||||
import { LogServerService } from '../../services/Log/LogServerService';
|
||||
import { useResponse } from '@/shared/components/response/ResponseContext';
|
||||
|
||||
export const useLogServerHook = () => {
|
||||
const { setResponse } = useResponse();
|
||||
|
||||
const [log, setLog] = useState<LogInterface | null>(null);
|
||||
|
||||
const fetchLogServer = async (client_id: number) => {
|
||||
|
||||
try {
|
||||
const response = await LogServerService(client_id);
|
||||
|
||||
console.log(response)
|
||||
|
||||
setLog(response.data);
|
||||
setResponse(response);
|
||||
} catch (error) {
|
||||
// O withClientErrorHandler já deve tratar o erro e formatar a 'response',
|
||||
// mas um catch local pode ser útil para lógicas adicionais se necessário.
|
||||
console.error("Erro ao buscar informação do servidor por ID:", error);
|
||||
}
|
||||
};
|
||||
|
||||
return { log, fetchLogServer };
|
||||
};
|
||||
|
|
@ -1,20 +0,0 @@
|
|||
import { useResponse } from '@/shared/components/response/ResponseContext';
|
||||
import { useState } from 'react';
|
||||
import TImovelInterface from '../../interfaces/TImovel/TImovelInterface';
|
||||
import { TImovelDeleteService } from '../../services/TImovel/TImovelDeleteService';
|
||||
|
||||
export const useTImovelDeleteHook = () => {
|
||||
const { setResponse } = useResponse();
|
||||
|
||||
const [tImovel, setTImovel] = useState<TImovelInterface>();
|
||||
|
||||
const deleteTImovel = async (data: TImovelInterface) => {
|
||||
const response = await TImovelDeleteService(data);
|
||||
|
||||
setTImovel(data);
|
||||
|
||||
setResponse(response);
|
||||
};
|
||||
|
||||
return { tImovel, deleteTImovel };
|
||||
};
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
import { useForm } from "react-hook-form";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { TImovelFormValues, TImovelSchema } from "../../schemas/TImovel/TImovelSchema";
|
||||
|
||||
export function useTImovelFormHook(defaults?: Partial<TImovelFormValues>) {
|
||||
return useForm<TImovelFormValues>({
|
||||
resolver: zodResolver(TImovelSchema),
|
||||
defaultValues: {
|
||||
...defaults,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
|
@ -1,27 +0,0 @@
|
|||
'use client';
|
||||
|
||||
import { useResponse } from '@/shared/components/response/ResponseContext';
|
||||
import { useState } from 'react';
|
||||
import TImovelInterface from '../../interfaces/TImovel/TImovelInterface';
|
||||
import { TImovelIndexData } from '../../data/TImovel/TImovelIndexData';
|
||||
|
||||
export const useTImovelIndexHook = () => {
|
||||
const { setResponse } = useResponse();
|
||||
|
||||
const [tImovel, setTImovel] = useState<TImovelInterface[]>([]);
|
||||
|
||||
const indexTImovel = async () => {
|
||||
const response = await TImovelIndexData();
|
||||
|
||||
// Armazena os dados consultados
|
||||
setTImovel(response.data);
|
||||
|
||||
// Define os dados do componente de resposta (toast, modal, etc)
|
||||
setResponse(response);
|
||||
};
|
||||
|
||||
return {
|
||||
tImovel,
|
||||
indexTImovel
|
||||
};
|
||||
};
|
||||
|
|
@ -1,33 +0,0 @@
|
|||
'use client';
|
||||
|
||||
import { useResponse } from '@/shared/components/response/ResponseContext';
|
||||
import { useState } from 'react';
|
||||
import TImovelInterface from '../../interfaces/TImovel/TImovelInterface';
|
||||
import { TImovelSaveService } from '../../services/TImovel/TImovelSaveService';
|
||||
|
||||
export const useTImovelSaveHook = () => {
|
||||
const { setResponse } = useResponse();
|
||||
|
||||
const [tImovel, setTImovel] = useState<TImovelInterface>();
|
||||
|
||||
// controla se o formulário está aberto ou fechado
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
|
||||
const saveTImovel = async (data: TImovelInterface) => {
|
||||
const response = await TImovelSaveService(data);
|
||||
|
||||
// Armazena os dados da repsota
|
||||
setTImovel(response.data);
|
||||
|
||||
// Define os dados da respota(toast, modal, etc)
|
||||
setResponse(response);
|
||||
|
||||
// Fecha o formulário automaticamente após salvar
|
||||
setIsOpen(false);
|
||||
|
||||
// Retorna os valores de forma imediata
|
||||
return response.data;
|
||||
};
|
||||
|
||||
return { tImovel, saveTImovel };
|
||||
};
|
||||
68
src/packages/administrativo/hooks/User/useUserFormHook.ts
Normal file
68
src/packages/administrativo/hooks/User/useUserFormHook.ts
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
'use client';
|
||||
|
||||
import { useEffect } from 'react';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
|
||||
// Importa o schema de validação (Zod)
|
||||
import { UserSchema } from '../../schemas/User/UserSchema';
|
||||
|
||||
// Importa o enum com o status
|
||||
import { SituacoesEnum } from '@/shared/enums/SituacoesEnum';
|
||||
|
||||
// Tipagem do formulário (interface compartilhada)
|
||||
import { FormValues } from '../../interfaces/User/UserFormInterface';
|
||||
|
||||
/**
|
||||
* Hook responsável por inicializar e gerenciar o estado do formulário de usuários.
|
||||
* Centraliza a lógica de criação, reset e carregamento de dados.
|
||||
*/
|
||||
export function useUserFormHook(data: FormValues | null) {
|
||||
// Inicializa o React Hook Form com validação baseada no Zod
|
||||
const form = useForm<FormValues>({
|
||||
resolver: zodResolver(UserSchema), // Aplica o schema para validação automática
|
||||
defaultValues: {
|
||||
user_id: 0,
|
||||
name: '',
|
||||
email: '',
|
||||
password: '',
|
||||
team: '',
|
||||
cargo: '',
|
||||
status: SituacoesEnum.ATIVO,
|
||||
user_id_create: null,
|
||||
user_id_update: null,
|
||||
date_register: new Date().toISOString(),
|
||||
date_update: null,
|
||||
} as FormValues,
|
||||
});
|
||||
|
||||
/**
|
||||
* Efeito responsável por atualizar o formulário
|
||||
* sempre que houver dados (modo edição) ou resetar (modo criação).
|
||||
*/
|
||||
useEffect(() => {
|
||||
if (data) {
|
||||
// Modo edição → carrega dados do usuário
|
||||
form.reset(data);
|
||||
console.log('Form carregado com dados:', data);
|
||||
} else {
|
||||
// Modo criação → limpa o formulário
|
||||
form.reset({
|
||||
user_id: 0,
|
||||
name: '',
|
||||
email: '',
|
||||
password: '',
|
||||
team: '',
|
||||
cargo: '',
|
||||
status: SituacoesEnum.ATIVO,
|
||||
user_id_create: null,
|
||||
user_id_update: null,
|
||||
date_register: new Date().toISOString(),
|
||||
date_update: null,
|
||||
});
|
||||
}
|
||||
}, [data]); // Atualiza sempre que "data" mudar
|
||||
|
||||
// Retorna o objeto form para uso no componente
|
||||
return form;
|
||||
}
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
'use client';
|
||||
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { UserLoginSchema } from '../../schemas/User/UserLoginSchema';
|
||||
import UserLoginService from '../../services/User/UserLoginService';
|
||||
import z from 'zod';
|
||||
|
||||
/**
|
||||
* Tipagem dos valores do formulário.
|
||||
* Inclui o campo "rememberMe" que não está no schema Zod original.
|
||||
*/
|
||||
export type LoginFormValues = z.infer<typeof UserLoginSchema> & {
|
||||
rememberMe: boolean;
|
||||
};
|
||||
|
||||
/**
|
||||
* Hook responsável por gerenciar o formulário de login e o comportamento
|
||||
* de lembrar acesso (localStorage + API).
|
||||
*/
|
||||
export function useUserFormLoginHook() {
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
// Inicializa o formulário com validação Zod
|
||||
const form = useForm<LoginFormValues>({
|
||||
resolver: zodResolver(UserLoginSchema),
|
||||
defaultValues: {
|
||||
email: '',
|
||||
password: '',
|
||||
rememberMe: false,
|
||||
},
|
||||
});
|
||||
|
||||
// Carrega o e-mail salvo no localStorage, se existir
|
||||
useEffect(() => {
|
||||
const savedEmail = localStorage.getItem('remembered_email');
|
||||
if (savedEmail) {
|
||||
form.setValue('email', savedEmail);
|
||||
form.setValue('rememberMe', true);
|
||||
}
|
||||
}, [form]);
|
||||
|
||||
/**
|
||||
* Função de envio do formulário — autentica o usuário e
|
||||
* salva o e-mail no localStorage se o "Lembrar acesso" estiver marcado.
|
||||
*/
|
||||
const onSubmit = async (values: LoginFormValues) => {
|
||||
try {
|
||||
setLoading(true);
|
||||
await UserLoginService(values);
|
||||
|
||||
if (values.rememberMe) {
|
||||
localStorage.setItem('remembered_email', values.email);
|
||||
} else {
|
||||
localStorage.removeItem('remembered_email');
|
||||
}
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
// Retorna o formulário e os estados necessários para o componente
|
||||
return { form, onSubmit, loading };
|
||||
}
|
||||
|
|
@ -1,11 +1,26 @@
|
|||
'use client';
|
||||
'use client'; // Indica que este código roda no lado do cliente (Next.js)
|
||||
|
||||
import { UserLogoutService } from '../../services/User/UserLogoutService';
|
||||
import { useRouter } from 'next/navigation'; // Hook do Next.js para redirecionamentos no cliente
|
||||
import { UserLogoutService } from '../../services/User/UserLogoutService'; // Importa o serviço de logout
|
||||
|
||||
// Hook customizado responsável por encapsular a lógica de logout
|
||||
export const useUserLogoutHook = () => {
|
||||
const router = useRouter(); // Inicializa o roteador do Next.js
|
||||
|
||||
// Função assíncrona responsável por executar o logout
|
||||
const logoutUsuario = async () => {
|
||||
await UserLogoutService('access_token');
|
||||
try {
|
||||
// Chama o serviço no servidor para apagar o cookie do token
|
||||
await UserLogoutService('access_token');
|
||||
|
||||
// Redireciona o usuário para a tela de login após o logout
|
||||
router.push('/login');
|
||||
} catch (error) {
|
||||
// Captura e exibe eventuais erros no processo de logout
|
||||
console.error('Erro ao fazer logout:', error);
|
||||
}
|
||||
};
|
||||
|
||||
// Retorna a função de logout para ser usada em qualquer componente
|
||||
return { logoutUsuario };
|
||||
};
|
||||
|
|
|
|||
|
|
@ -0,0 +1,16 @@
|
|||
/**
|
||||
* Interface que representa a tabela `client` do banco de dados `monitoring`.
|
||||
* Cada campo reflete a tipagem e as restrições da DDL original.
|
||||
*/
|
||||
export interface ClientInterface {
|
||||
client_id?: number; // ID único do cliente (chave primária, gerada automaticamente)
|
||||
cns?: string | null; // Código CNS (campo opcional)
|
||||
name: string; // Nome do cliente (campo obrigatório)
|
||||
date_register?: string | null; // Data/hora do registro (timestamp gerado automaticamente)
|
||||
state?: string | null; // Sigla do estado (ex: 'SP', 'RJ', etc.)
|
||||
city?: string | null; // Nome da cidade
|
||||
responsible?: string | null; // Responsável principal pelo cliente
|
||||
consultant?: string | null; // Nome do consultor associado
|
||||
type_contract?: string | null; // Tipo de contrato (ex: 'A' = anual, 'M' = mensal, etc.)
|
||||
status?: string | null; // Tipo de contrato (ex: 'A' = Ativo, 'I' = Inativo, etc.)
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
import { ClientInterface } from './ClientInterface';
|
||||
|
||||
/**
|
||||
* Interface que define as propriedades esperadas pelo componente ClientTable.
|
||||
*/
|
||||
export interface ClientTableInterface {
|
||||
data: ClientInterface[]; // Lista de clientes a exibir
|
||||
|
||||
// Objeto opcional de paginação retornado pela API
|
||||
pagination?: {
|
||||
total_records: number; // Total de registros encontrados
|
||||
total_pages: number; // Total de páginas disponíveis
|
||||
current_page: number; // Página atual
|
||||
next_page?: number | null; // Próxima página (opcional)
|
||||
first?: number; // Quantidade padrão por página
|
||||
skip?: number; // Offset inicial
|
||||
};
|
||||
|
||||
onEdit: (client: ClientInterface) => void; // Ação ao clicar em editar
|
||||
onDelete: (client: ClientInterface) => void; // Ação ao clicar em remover
|
||||
}
|
||||
10
src/packages/administrativo/interfaces/Log/LogInterface.ts
Normal file
10
src/packages/administrativo/interfaces/Log/LogInterface.ts
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
/**
|
||||
* Interface que representa a tabela `log` do banco de dados `monitoring`.
|
||||
* Cada campo reflete a tipagem e as restrições definidas na DDL original.
|
||||
*/
|
||||
export interface LogInterface {
|
||||
log_id?: number; // ID único do log (chave primária, gerada automaticamente pelo banco)
|
||||
client_id: number; // ID do cliente relacionado (chave estrangeira obrigatória)
|
||||
date_post?: string; // Data e hora do registro (gerada automaticamente pelo banco)
|
||||
file: object; // Dados em formato JSON (ex: informações do arquivo ou operação)
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
// Define o tipo base dos valores do formulário (importa do schema do usuário)
|
||||
import { z } from 'zod';
|
||||
import { UserSchema } from '../../schemas/User/UserSchema';
|
||||
|
||||
// Cria o tipo inferido a partir do schema do usuário
|
||||
export type FormValues = z.infer<typeof UserSchema>;
|
||||
|
||||
/**
|
||||
* Interface com as propriedades aceitas pelo componente UserForm.
|
||||
* Isso facilita a reutilização e deixa o código mais limpo.
|
||||
*/
|
||||
export interface UserFormInterface {
|
||||
isOpen: boolean; // Controla se o diálogo está aberto
|
||||
data: FormValues | null; // Dados do usuário para edição (ou null no modo de criação)
|
||||
onClose: (item: null, isFormStatus: boolean) => void; // Função executada ao fechar o diálogo
|
||||
onSave: (data: FormValues) => void; // Função executada ao salvar o formulário
|
||||
buttonIsLoading: boolean; // Define se o botão de envio está em modo de carregamento
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
import React from 'react';
|
||||
|
||||
/**
|
||||
* Interface de tipagem para o componente LoginForm.
|
||||
*/
|
||||
export interface UserFormLoginInterface extends React.ComponentProps<'div'> {
|
||||
className?: string; // Classe CSS opcional
|
||||
}
|
||||
|
|
@ -13,3 +13,4 @@ export interface UserInterface {
|
|||
user_id_create: number | null,
|
||||
user_id_update: number | null
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,10 @@
|
|||
import { UserInterface } from './UserInterface';
|
||||
|
||||
/**
|
||||
* Interface que define as propriedades esperadas pelo componente UserTable.
|
||||
*/
|
||||
export interface UserTableInterface {
|
||||
data: UserInterface[]; // Lista de usuários a exibir
|
||||
onEdit: (user: UserInterface) => void; // Ação ao clicar em editar
|
||||
onDelete: (user: UserInterface) => void; // Ação ao clicar em remover
|
||||
}
|
||||
67
src/packages/administrativo/schemas/Client/ClientSchema.ts
Normal file
67
src/packages/administrativo/schemas/Client/ClientSchema.ts
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
import { z } from "zod";
|
||||
|
||||
/**
|
||||
* Schema de validação para a tabela `client`
|
||||
* Baseado na DDL do banco de dados `monitoring.client`
|
||||
*/
|
||||
export const ClientSchema = z.object({
|
||||
client_id: z.number().optional(), // ID gerado automaticamente (AUTO_INCREMENT)
|
||||
|
||||
cns: z
|
||||
.string()
|
||||
.max(10, { message: "O campo CNS deve ter no máximo 10 caracteres." })
|
||||
.nullable()
|
||||
.optional(), // Campo opcional e pode ser nulo
|
||||
|
||||
name: z
|
||||
.string()
|
||||
.min(3, { message: "O nome deve ter no mínimo 3 caracteres." })
|
||||
.max(550, { message: "O nome deve ter no máximo 550 caracteres." }), // Campo obrigatório
|
||||
|
||||
date_register: z
|
||||
.string()
|
||||
.nullable()
|
||||
.optional(), // Timestamp gerado automaticamente pelo banco
|
||||
|
||||
state: z
|
||||
.string()
|
||||
.length(2, { message: "O estado deve conter exatamente 2 caracteres (ex: 'SP')." })
|
||||
.nullable()
|
||||
.optional(), // Campo opcional
|
||||
|
||||
city: z
|
||||
.string()
|
||||
.max(160, { message: "O nome da cidade deve ter no máximo 160 caracteres." })
|
||||
.nullable()
|
||||
.optional(),
|
||||
|
||||
responsible: z
|
||||
.string()
|
||||
.max(160, { message: "O nome do responsável deve ter no máximo 160 caracteres." })
|
||||
.nullable()
|
||||
.optional(),
|
||||
|
||||
consultant: z
|
||||
.string()
|
||||
.max(160, { message: "O nome do consultor deve ter no máximo 160 caracteres." })
|
||||
.nullable()
|
||||
.optional(),
|
||||
|
||||
type_contract: z
|
||||
.string()
|
||||
.length(1, { message: "O tipo de contrato deve conter apenas 1 caractere." })
|
||||
.nullable()
|
||||
.optional(), // Pode representar tipo de contrato (ex: 'A' = anual, 'M' = mensal)
|
||||
|
||||
status: z
|
||||
.string()
|
||||
.length(1, { message: "O status de deve conter apenas 1 caractere." })
|
||||
.nullable()
|
||||
.optional(), // Pode representar tipo de status (ex: 'A' = ativo, 'I' = inativo)
|
||||
});
|
||||
|
||||
/**
|
||||
* Tipo TypeScript inferido automaticamente a partir do schema.
|
||||
* Permite utilizar a tipagem do Zod em qualquer lugar do código.
|
||||
*/
|
||||
export type ClientSchemaType = z.infer<typeof ClientSchema>;
|
||||
43
src/packages/administrativo/schemas/Log/LogShcema.ts
Normal file
43
src/packages/administrativo/schemas/Log/LogShcema.ts
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
import { z } from "zod";
|
||||
|
||||
/**
|
||||
* Schema de validação para a tabela `log`
|
||||
* Baseado na DDL do banco de dados `monitoring.log`
|
||||
*/
|
||||
export const LogSchema = z.object({
|
||||
// ID do log, gerado automaticamente pelo banco (AUTO_INCREMENT)
|
||||
log_id: z.number().optional(),
|
||||
|
||||
// ID do cliente relacionado — campo obrigatório
|
||||
client_id: z
|
||||
.number({
|
||||
message: "O campo client_id deve ser um número.",
|
||||
})
|
||||
.int()
|
||||
.positive({ message: "O client_id deve ser um número positivo." }),
|
||||
|
||||
// Data e hora da inserção — gerada automaticamente pelo banco (CURRENT_TIMESTAMP)
|
||||
date_post: z
|
||||
.string()
|
||||
.datetime({ message: "O campo date_post deve ser uma data/hora válida (ISO 8601)." })
|
||||
.optional()
|
||||
.nullable(),
|
||||
|
||||
// Campo JSON que armazena informações sobre o arquivo
|
||||
// Pode ser um objeto com qualquer estrutura válida em JSON
|
||||
file: z
|
||||
.any()
|
||||
.refine((val) => val !== undefined, {
|
||||
message: "O campo file é obrigatório e deve conter um JSON válido.",
|
||||
})
|
||||
.refine(
|
||||
(val) => typeof val === "object" && val !== null,
|
||||
{ message: "O campo file deve ser um objeto JSON válido." }
|
||||
),
|
||||
});
|
||||
|
||||
/**
|
||||
* Tipo TypeScript inferido automaticamente a partir do schema.
|
||||
* Permite utilizar a tipagem do Zod em qualquer parte do código.
|
||||
*/
|
||||
export type LogSchemaType = z.infer<typeof LogSchema>;
|
||||
|
|
@ -1,6 +1,12 @@
|
|||
import { z } from 'zod';
|
||||
|
||||
/**
|
||||
* Schema de validação do login do usuário
|
||||
* - Garante que email e senha sejam obrigatórios
|
||||
* - `rememberMe` é opcional e booleano
|
||||
*/
|
||||
export const UserLoginSchema = z.object({
|
||||
email: z.string().min(1, 'O campo deve ser preenchido'),
|
||||
password: z.string().min(1, 'O campo deve ser preenchido'),
|
||||
rememberMe: z.boolean().optional(),
|
||||
});
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ export const UserSchema = z.object({
|
|||
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().min(6, { message: "A senha deve ter pelo menos 6 caracteres." }),
|
||||
position: z.string().nullable().optional(),
|
||||
cargo: z.string().nullable().optional(),
|
||||
team: z.string().min(1, { message: "A equipe é obrigatória." }),
|
||||
status: z.enum(SituacoesEnum), // 'A' ou 'I'
|
||||
date_register: z.string().optional(),
|
||||
|
|
|
|||
|
|
@ -0,0 +1,31 @@
|
|||
'use server'
|
||||
// Indica que este módulo será executado no lado do servidor (Server Action do Next.js)
|
||||
|
||||
import { withClientErrorHandler } from "@/withClientErrorHandler/withClientErrorHandler"
|
||||
// Importa o decorador responsável por tratar erros de forma padronizada em funções assíncronas
|
||||
|
||||
import { ClientDeleteData } from "../../data/Client/ClientDeleteData"
|
||||
// Importa a função responsável por realizar a operação real de exclusão do Cliente (camada de acesso a dados)
|
||||
|
||||
// Função principal que executa o processo de exclusão de um Cliente
|
||||
async function executeClientDeleteService(usuarioId: number) {
|
||||
|
||||
// Validação básica: impede que IDs inválidos ou menores que 1 sejam processados
|
||||
if (usuarioId <= 0) {
|
||||
return {
|
||||
'code': 400, // Código HTTP indicando requisição inválida
|
||||
'message': 'Cliente informado inválido', // Mensagem de erro clara e descritiva
|
||||
}
|
||||
}
|
||||
|
||||
// Chama a função que realiza a exclusão no banco ou API, passando o ID do Cliente
|
||||
const response = await ClientDeleteData(usuarioId)
|
||||
|
||||
// Retorna a resposta vinda da camada de dados, que pode conter status e mensagem
|
||||
return response
|
||||
}
|
||||
|
||||
// Exporta a função encapsulada com o tratador global de erros
|
||||
export const ClientDeleteService = withClientErrorHandler(executeClientDeleteService)
|
||||
// `withClientErrorHandler` garante que exceções não tratadas sejam capturadas e formatadas de forma uniforme
|
||||
// Dessa forma, evita que erros internos quebrem o fluxo da aplicação
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
'use server';
|
||||
// Indica que este código será executado no lado do servidor (Server Component ou ação server-side do Next.js)
|
||||
|
||||
import { withClientErrorHandler } from "@/withClientErrorHandler/withClientErrorHandler";
|
||||
import { ClientIndexData } from "../../data/Client/ClientIndexData";
|
||||
|
||||
// Função principal que executa a chamada para buscar a lista de clientes
|
||||
async function executeClientIndexService() {
|
||||
try {
|
||||
// Chama o método responsável por buscar os dados da API (camada "data")
|
||||
const response = await ClientIndexData();
|
||||
|
||||
console.log('Kenão')
|
||||
|
||||
// Retorna a resposta recebida da API (geralmente um objeto com status, mensagem e dados)
|
||||
return response;
|
||||
} catch (error) {
|
||||
// Caso ocorra algum erro inesperado, lança o erro para ser tratado pelo wrapper
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
// Exporta o serviço com tratamento global de erros usando o wrapper `withClientErrorHandler`
|
||||
export const ClientIndexService = withClientErrorHandler(executeClientIndexService);
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
'use server'
|
||||
// Indica que este módulo será executado no lado do servidor (Server Action do Next.js)
|
||||
|
||||
import { withClientErrorHandler } from "@/withClientErrorHandler/withClientErrorHandler";
|
||||
// Importa o utilitário responsável por envolver a função com tratamento global de erros do cliente
|
||||
|
||||
import { ClientSaveData } from "../../data/Client/ClientSaveData";
|
||||
// Importa a função que realiza a operação de salvamento de dados do cliente (chamada à API ou banco de dados)
|
||||
|
||||
// Função principal que executa o salvamento de dados de um cliente
|
||||
async function executeClientSave(form: any) {
|
||||
|
||||
// Chama a função que realmente salva os dados, repassando o formulário recebido
|
||||
return await ClientSaveData(form);
|
||||
}
|
||||
|
||||
// Exporta o serviço, agora protegido pelo tratador de erros
|
||||
export const ClientSaveService = withClientErrorHandler(executeClientSave);
|
||||
// `withClientErrorHandler` adiciona camadas de controle de exceção e formatação de erro à função principal
|
||||
// Assim, qualquer falha em `executeClientSave` será capturada e tratada de forma padronizada
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
'use server'
|
||||
// Indica que este arquivo é um "Server Action", executado no lado do servidor pelo Next.js
|
||||
|
||||
import { withClientErrorHandler } from "@/withClientErrorHandler/withClientErrorHandler";
|
||||
// Importa o wrapper responsável por padronizar o tratamento de erros nas requisições do cliente
|
||||
|
||||
import { LogIndexByClientIDData } from "../../data/Log/LogIndexByClientIDData";
|
||||
// Importa a função que acessa a camada de dados e retorna as informações do usuário a partir do ID
|
||||
|
||||
// Função assíncrona principal responsável por buscar um usuário pelo seu ID
|
||||
async function executeLogIndexByIDService(client_id: number) {
|
||||
|
||||
// Executa a função de busca de usuário, passando o ID recebido como parâmetro
|
||||
const response = await LogIndexByClientIDData(client_id);
|
||||
|
||||
// Retorna a resposta vinda da camada de dados (usuário encontrado ou erro)
|
||||
return response;
|
||||
}
|
||||
|
||||
// Exporta o serviço com o tratamento de erros encapsulado
|
||||
// O wrapper "withClientErrorHandler" assegura respostas consistentes em caso de falhas
|
||||
export const LogIndexByIDService = withClientErrorHandler(executeLogIndexByIDService);
|
||||
22
src/packages/administrativo/services/Log/LogServerService.ts
Normal file
22
src/packages/administrativo/services/Log/LogServerService.ts
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
'use server'
|
||||
// Indica que este arquivo é um "Server Action", executado no lado do servidor pelo Next.js
|
||||
|
||||
import { withClientErrorHandler } from "@/withClientErrorHandler/withClientErrorHandler";
|
||||
// Importa o wrapper responsável por padronizar o tratamento de erros nas requisições do Loge
|
||||
|
||||
import { LogServerData } from "../../data/Log/LogServerData";
|
||||
// Importa a função que acessa a camada de dados e retorna as informações do usuário a partir do ID
|
||||
|
||||
// Função assíncrona principal responsável por buscar um usuário pelo seu ID
|
||||
async function executeLogServerService(client_id: number) {
|
||||
|
||||
// Executa a função de busca de usuário, passando o ID recebido como parâmetro
|
||||
const response = await LogServerData(client_id);
|
||||
|
||||
// Retorna a resposta vinda da camada de dados (usuário encontrado ou erro)
|
||||
return response;
|
||||
}
|
||||
|
||||
// Exporta o serviço com o tratamento de erros encapsulado
|
||||
// O wrapper "withClientErrorHandler" assegura respostas consistentes em caso de falhas
|
||||
export const LogServerService = withClientErrorHandler(executeLogServerService);
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
import { withClientErrorHandler } from '@/shared/actions/withClientErrorHandler/withClientErrorHandler';
|
||||
import { TImovelDeleteData } from '../../data/TImovel/TImovelDeleteData';
|
||||
import TImovelInterface from '../../interfaces/TImovel/TImovelInterface';
|
||||
|
||||
async function executeTImovelDeleteService(data: TImovelInterface) {
|
||||
const response = await TImovelDeleteData(data);
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
export const TImovelDeleteService = withClientErrorHandler(executeTImovelDeleteService);
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
import { withClientErrorHandler } from '@/shared/actions/withClientErrorHandler/withClientErrorHandler';
|
||||
import { TImovelIndexData } from '../../data/TImovel/TImovelIndexData';
|
||||
|
||||
export default async function executeTImovelIndexService() {
|
||||
const response = await TImovelIndexData();
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
export const TImovelIndexService = withClientErrorHandler(executeTImovelIndexService);
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
import { withClientErrorHandler } from '@/shared/actions/withClientErrorHandler/withClientErrorHandler';
|
||||
import { TImovelSaveData } from '../../data/TImovel/TImovelSaveData';
|
||||
import TImovelInterface from '../../interfaces/TImovel/TImovelInterface';
|
||||
|
||||
async function executeTImovelSaveService(data: TImovelInterface) {
|
||||
const response = await TImovelSaveData(data);
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
export const TImovelSaveService = withClientErrorHandler(executeTImovelSaveService);
|
||||
|
|
@ -1,20 +1,30 @@
|
|||
'use server'
|
||||
'use server'
|
||||
// Indica que este módulo será executado no lado do servidor (Server Actions do Next.js)
|
||||
|
||||
import { withClientErrorHandler } from "@/withClientErrorHandler/withClientErrorHandler"
|
||||
import { UserDeleteData } from "../../data/User/UserDeleteData"
|
||||
// Importa um wrapper responsável por tratar erros de forma padronizada no cliente
|
||||
|
||||
import { UserDeleteData } from "../../data/User/UserDeleteData"
|
||||
// Importa a função responsável por realizar a exclusão do usuário no nível de dados (requisição à API ou banco)
|
||||
|
||||
// Função assíncrona principal que executa o serviço de exclusão de usuário
|
||||
async function executeUserDeleteService(usuarioId: number) {
|
||||
|
||||
// Verifica se o ID do usuário informado é inválido (zero, negativo ou inexistente)
|
||||
if (usuarioId <= 0) {
|
||||
return {
|
||||
'code': 400,
|
||||
'message': 'Usuário informado inválido',
|
||||
'code': 400, // Código HTTP 400 - requisição inválida
|
||||
'message': 'Usuário informado inválido', // Mensagem de erro clara
|
||||
}
|
||||
}
|
||||
|
||||
// Chama a função de exclusão no módulo de dados, passando o ID do usuário
|
||||
const response = await UserDeleteData(usuarioId)
|
||||
return response
|
||||
|
||||
// Retorna a resposta obtida da camada de dados (sucesso ou erro)
|
||||
return response
|
||||
}
|
||||
|
||||
export const UserDeleteService = withClientErrorHandler(executeUserDeleteService)
|
||||
// Exporta o serviço já encapsulado com o handler de erros
|
||||
// Isso garante que qualquer exceção seja tratada de forma uniforme no frontend
|
||||
export const UserDeleteService = withClientErrorHandler(executeUserDeleteService)
|
||||
|
|
|
|||
|
|
@ -1,14 +1,22 @@
|
|||
'use server'
|
||||
'use server'
|
||||
// Define que este módulo será executado no lado do servidor (Server Actions do Next.js)
|
||||
|
||||
import { withClientErrorHandler } from "@/withClientErrorHandler/withClientErrorHandler";
|
||||
import { UserIndexByEmailData } from "../../data/User/UserIndexByEmailData";
|
||||
// Importa um wrapper para padronizar o tratamento de erros em chamadas do cliente
|
||||
|
||||
import { UserIndexByEmailData } from "../../data/User/UserIndexByEmailData";
|
||||
// Importa a função responsável por buscar informações do usuário no banco de dados (ou API) com base no e-mail
|
||||
|
||||
// Função assíncrona principal que executa a busca de um usuário pelo e-mail
|
||||
async function executeUserIndexByEmailService(email: string) {
|
||||
|
||||
// Chama a função de acesso a dados passando o e-mail como parâmetro
|
||||
const response = await UserIndexByEmailData(email);
|
||||
|
||||
// Retorna a resposta obtida da camada de dados (usuário encontrado ou erro)
|
||||
return response;
|
||||
|
||||
}
|
||||
|
||||
export const UserIndexByEmailService = withClientErrorHandler(executeUserIndexByEmailService)
|
||||
// Exporta o serviço encapsulado com o handler de erros
|
||||
// Isso garante tratamento uniforme de erros e mensagens entre cliente e servidor
|
||||
export const UserIndexByEmailService = withClientErrorHandler(executeUserIndexByEmailService);
|
||||
|
|
|
|||
|
|
@ -1,14 +1,22 @@
|
|||
'use server'
|
||||
'use server'
|
||||
// Indica que este arquivo é um "Server Action", executado no lado do servidor pelo Next.js
|
||||
|
||||
import { withClientErrorHandler } from "@/withClientErrorHandler/withClientErrorHandler";
|
||||
import { UserIndexByIDData } from "../../data/User/UserIndexByIDData";
|
||||
// Importa o wrapper responsável por padronizar o tratamento de erros nas requisições do cliente
|
||||
|
||||
import { UserIndexByIDData } from "../../data/User/UserIndexByIDData";
|
||||
// Importa a função que acessa a camada de dados e retorna as informações do usuário a partir do ID
|
||||
|
||||
// Função assíncrona principal responsável por buscar um usuário pelo seu ID
|
||||
async function executeUserIndexByIDService(user_id: number) {
|
||||
|
||||
// Executa a função de busca de usuário, passando o ID recebido como parâmetro
|
||||
const response = await UserIndexByIDData(user_id);
|
||||
|
||||
// Retorna a resposta vinda da camada de dados (usuário encontrado ou erro)
|
||||
return response;
|
||||
|
||||
}
|
||||
|
||||
export const UserIndexByIDService = withClientErrorHandler(executeUserIndexByIDService)
|
||||
// Exporta o serviço com o tratamento de erros encapsulado
|
||||
// O wrapper "withClientErrorHandler" assegura respostas consistentes em caso de falhas
|
||||
export const UserIndexByIDService = withClientErrorHandler(executeUserIndexByIDService);
|
||||
|
|
|
|||
|
|
@ -1,14 +1,22 @@
|
|||
'use server'
|
||||
'use server'
|
||||
// Define que este módulo será executado no lado do servidor (Server Action do Next.js)
|
||||
|
||||
import { withClientErrorHandler } from "@/withClientErrorHandler/withClientErrorHandler";
|
||||
import { UserIndexData } from "../../data/User/UserIndexData";
|
||||
// Importa o wrapper responsável por tratar erros de forma padronizada entre cliente e servidor
|
||||
|
||||
import { UserIndexData } from "../../data/User/UserIndexData";
|
||||
// Importa a função responsável por buscar a lista de usuários na camada de dados (API ou banco de dados)
|
||||
|
||||
// Função assíncrona principal que executa a listagem de todos os usuários
|
||||
async function executeUserIndexService() {
|
||||
|
||||
// Chama a função da camada de dados que retorna todos os usuários
|
||||
const response = await UserIndexData();
|
||||
|
||||
// Retorna o resultado obtido da função de dados (lista de usuários ou erro)
|
||||
return response;
|
||||
|
||||
}
|
||||
|
||||
export const UserIndexService = withClientErrorHandler(executeUserIndexService)
|
||||
// Exporta o serviço encapsulado com o handler de erros
|
||||
// Isso garante que qualquer erro seja capturado e tratado de forma consistente no frontend
|
||||
export const UserIndexService = withClientErrorHandler(executeUserIndexService);
|
||||
|
|
|
|||
|
|
@ -1,36 +1,47 @@
|
|||
'use server';
|
||||
'use server';
|
||||
// Define que este módulo será executado no lado do servidor (Server Action do Next.js)
|
||||
|
||||
import { cookies } from 'next/headers';
|
||||
import { cookies } from 'next/headers';
|
||||
// Importa o utilitário do Next.js responsável por manipular cookies no lado do servidor
|
||||
|
||||
import UserLoginData from '../../data/User/UserLoginData';
|
||||
import { redirect } from 'next/navigation';
|
||||
import { withClientErrorHandler } from '@/withClientErrorHandler/withClientErrorHandler';
|
||||
import UserLoginData from '../../data/User/UserLoginData';
|
||||
// Importa a função da camada de dados responsável por validar o login do usuário e retornar o token
|
||||
|
||||
import { redirect } from 'next/navigation';
|
||||
// Importa a função de redirecionamento do Next.js para navegação após o login
|
||||
|
||||
import { withClientErrorHandler } from '@/withClientErrorHandler/withClientErrorHandler';
|
||||
// Importa o wrapper genérico que trata erros de forma padronizada (não utilizado diretamente aqui)
|
||||
|
||||
// Função principal responsável por autenticar o usuário
|
||||
export default async function UserLoginService(form: any) {
|
||||
// Obtem a resposta da requisição
|
||||
|
||||
// Envia os dados do formulário para a camada de dados e aguarda a resposta
|
||||
const response = await UserLoginData(form);
|
||||
|
||||
console.log("service",response)
|
||||
// Verifica se localizou o usuário
|
||||
// Exibe a resposta no console (útil para debug no ambiente de desenvolvimento)
|
||||
console.log("service", response);
|
||||
|
||||
// Verifica se o usuário foi encontrado (caso contrário, retorna erro 404)
|
||||
if (response.data.user_id <= 0) {
|
||||
return {
|
||||
code: 404,
|
||||
message: 'Não foi localizado o usuário',
|
||||
code: 404, // Código de erro HTTP simulando "não encontrado"
|
||||
message: 'Não foi localizado o usuário', // Mensagem informativa ao cliente
|
||||
};
|
||||
}
|
||||
|
||||
// Importação do manipulador de cookies
|
||||
// Obtém o manipulador de cookies do contexto do servidor
|
||||
const cookieStore = await cookies();
|
||||
|
||||
// Cria um novo cookie
|
||||
// Define um cookie com o token de autenticação
|
||||
cookieStore.set('access_token', response.data.token, {
|
||||
httpOnly: true,
|
||||
secure: process.env.NODE_ENV === 'production',
|
||||
sameSite: 'strict',
|
||||
path: '/',
|
||||
maxAge: 60 * 60 * 24,
|
||||
httpOnly: true, // Impede acesso via JavaScript (segurança contra XSS)
|
||||
secure: process.env.NODE_ENV === 'production', // Garante HTTPS em produção
|
||||
sameSite: 'strict', // Restringe envio de cookies entre domínios
|
||||
path: '/', // Torna o cookie acessível em toda a aplicação
|
||||
maxAge: 60 * 60 * 24, // Define validade de 24 horas (em segundos)
|
||||
});
|
||||
|
||||
// Redireciona para a págian desejada
|
||||
// Redireciona o usuário autenticado para a página administrativa de usuários
|
||||
redirect('/administrativo/usuarios');
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,18 +1,20 @@
|
|||
'use server';
|
||||
'use server'; // Indica que este arquivo será executado apenas no servidor (Server Action)
|
||||
|
||||
import { withClientErrorHandler } from '@/withClientErrorHandler/withClientErrorHandler';
|
||||
import { cookies } from 'next/headers';
|
||||
|
||||
import { redirect } from 'next/navigation';
|
||||
import { withClientErrorHandler } from '@/withClientErrorHandler/withClientErrorHandler'; // Middleware para capturar erros controladamente
|
||||
import { cookies } from 'next/headers'; // API do Next.js para manipular cookies no servidor
|
||||
|
||||
// Função principal que apaga o cookie de autenticação
|
||||
async function executeUserLogoutService(token: string) {
|
||||
// Obtém o gerenciador de cookies do contexto do servidor
|
||||
const cookieStore = await cookies();
|
||||
cookieStore.set(token, '', {
|
||||
expires: new Date(0),
|
||||
path: '/',
|
||||
});
|
||||
|
||||
redirect('/login');
|
||||
// Remove o cookie do token, definindo expiração retroativa (logout efetivo)
|
||||
cookieStore.set(token, '', {
|
||||
expires: new Date(0), // Define data de expiração no passado
|
||||
path: '/', // Garante que o cookie seja removido em toda a aplicação
|
||||
});
|
||||
}
|
||||
|
||||
export const UserLogoutService = withClientErrorHandler(executeUserLogoutService)
|
||||
// Exporta a função com tratamento de erro aplicado
|
||||
// Assim, qualquer exceção dentro de executeUserLogoutService é tratada de forma controlada
|
||||
export const UserLogoutService = withClientErrorHandler(executeUserLogoutService);
|
||||
|
|
|
|||
|
|
@ -1,22 +1,30 @@
|
|||
'use server'
|
||||
// Define que este módulo é executado no lado do servidor (Server Actions do Next.js)
|
||||
|
||||
import { withClientErrorHandler } from "@/withClientErrorHandler/withClientErrorHandler";
|
||||
import { UserReadData } from "../../data/User/UserReadData";
|
||||
// Importa o wrapper responsável por tratar erros de forma padronizada entre cliente e servidor
|
||||
|
||||
import { UserReadData } from "../../data/User/UserReadData";
|
||||
// Importa a função que acessa o banco de dados (ou API) para obter os dados completos de um usuário específico
|
||||
|
||||
// Função principal do serviço que busca detalhes de um usuário com base no ID informado
|
||||
async function executeUserReadService(usuarioId: number) {
|
||||
|
||||
// Verifica se o id informado é válido
|
||||
// Validação simples do ID, evitando requisições desnecessárias ou inválidas
|
||||
if (usuarioId <= 0) {
|
||||
return {
|
||||
'code': 400,
|
||||
'message': 'Usuário informado inválido',
|
||||
'code': 400, // Código de erro para requisição inválida
|
||||
'message': 'Usuário informado inválido', // Mensagem clara ao cliente
|
||||
}
|
||||
}
|
||||
|
||||
// Chama a função da camada de dados para buscar as informações do usuário
|
||||
const response = await UserReadData(usuarioId);
|
||||
|
||||
// Retorna o resultado vindo da camada de dados (dados do usuário ou erro)
|
||||
return response
|
||||
|
||||
|
||||
}
|
||||
|
||||
export const UserReadService = withClientErrorHandler(executeUserReadService)
|
||||
// Exporta o serviço encapsulado com o tratamento automático de erros
|
||||
// Garantindo uma resposta consistente para o frontend em caso de falhas
|
||||
export const UserReadService = withClientErrorHandler(executeUserReadService);
|
||||
|
|
|
|||
|
|
@ -1,12 +1,20 @@
|
|||
'use server'
|
||||
'use server'
|
||||
// Define que este módulo é uma Server Action, ou seja, será executado no lado do servidor (Next.js)
|
||||
|
||||
import { withClientErrorHandler } from "@/withClientErrorHandler/withClientErrorHandler";
|
||||
import { UserSaveData } from "../../data/User/UserSaveData";
|
||||
// Importa o wrapper responsável por capturar e padronizar erros em chamadas do cliente
|
||||
|
||||
import { UserSaveData } from "../../data/User/UserSaveData";
|
||||
// Importa a função da camada de dados responsável por salvar (inserir ou atualizar) informações de um usuário no banco
|
||||
|
||||
// Função assíncrona principal que executa o salvamento dos dados de um usuário
|
||||
async function executeUserSave(form: any) {
|
||||
|
||||
// Chama diretamente a função de persistência passando o formulário recebido
|
||||
// O "await" garante que a função aguarde o resultado antes de retornar
|
||||
return await UserSaveData(form);
|
||||
|
||||
}
|
||||
|
||||
export const UserSaveService = withClientErrorHandler(executeUserSave)
|
||||
// Exporta o serviço encapsulado com o handler de erros
|
||||
// Isso garante que qualquer exceção seja tratada de forma uniforme no frontend
|
||||
export const UserSaveService = withClientErrorHandler(executeUserSave);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue