fix atendimentos.ts
Signed-off-by: Rodrigo Martins <rodrigo.sousa.577@gmail.com>
This commit is contained in:
1 parent
ea0481e09e
commit
479bc5d2d6
3 files changed
+194
-397
No files matched your search
@@ -0,0 +1,120 @@
|
||||
import React, { useState, useCallback } from 'react';
|
||||
import { Calendar } from '@fullcalendar/react';
|
||||
import dayGridPlugin from '@fullcalendar/daygrid';
|
||||
import timeGridPlugin from '@fullcalendar/timegrid';
|
||||
import interactionPlugin from '@fullcalendar/interaction';
|
||||
import ptBrLocale from '@fullcalendar/core/locales/pt-br';
|
||||
import { format } from 'date-fns';
|
||||
import { api } from '../services/api';
|
||||
import { toast } from 'react-toastify';
|
||||
|
||||
interface Agendamento {
|
||||
id: string;
|
||||
data: string;
|
||||
observacoes?: string;
|
||||
status: string;
|
||||
cliente: {
|
||||
id: string;
|
||||
nome: string;
|
||||
};
|
||||
}
|
||||
|
||||
interface CalendarEvent {
|
||||
id: string;
|
||||
title: string;
|
||||
start: string;
|
||||
end: string;
|
||||
backgroundColor?: string;
|
||||
borderColor?: string;
|
||||
extendedProps: {
|
||||
agendamento: Agendamento;
|
||||
};
|
||||
}
|
||||
|
||||
interface AgendamentoCalendarioProps {
|
||||
onEventClick?: (event: any) => void;
|
||||
onDateSelect?: (selectInfo: any) => void;
|
||||
}
|
||||
|
||||
export const AgendamentoCalendario: React.FC<AgendamentoCalendarioProps> = ({
|
||||
onEventClick,
|
||||
onDateSelect
|
||||
}) => {
|
||||
const [eventos, setEventos] = useState<CalendarEvent[]>([]);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
|
||||
const formatEventos = useCallback((agendamentos: Agendamento[]): CalendarEvent[] => {
|
||||
return agendamentos.map(ag => ({
|
||||
id: ag.id,
|
||||
title: `${ag.cliente.nome} ${ag.observacoes ? `- ${ag.observacoes}` : ''}`,
|
||||
start: ag.data,
|
||||
end: ag.data,
|
||||
backgroundColor: ag.status === 'CANCELADO' ? '#FEE2E2' : '#E0F2FE',
|
||||
borderColor: ag.status === 'CANCELADO' ? '#EF4444' : '#0EA5E9',
|
||||
extendedProps: {
|
||||
agendamento: ag
|
||||
}
|
||||
}));
|
||||
}, []);
|
||||
|
||||
const loadAgendamentos = useCallback(async ({ start, end }: { start: Date, end: Date }) => {
|
||||
try {
|
||||
setLoading(true);
|
||||
setError(null);
|
||||
|
||||
const response = await api.get('/atendimentos/agendamentos', {
|
||||
params: {
|
||||
inicio: format(start, 'yyyy-MM-dd'),
|
||||
fim: format(end, 'yyyy-MM-dd')
|
||||
}
|
||||
});
|
||||
|
||||
setEventos(formatEventos(response.data));
|
||||
} catch (err: any) {
|
||||
const mensagem = err.response?.data?.error || 'Erro ao carregar agendamentos';
|
||||
setError(mensagem);
|
||||
toast.error(mensagem);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}, [formatEventos]);
|
||||
|
||||
return (
|
||||
<div className="relative h-full">
|
||||
{loading && (
|
||||
<div className="absolute inset-0 bg-white/50 flex items-center justify-center z-10">
|
||||
<div className="animate-spin rounded-full h-8 w-8 border-b-2 border-blue-500" />
|
||||
</div>
|
||||
)}
|
||||
|
||||
{error && (
|
||||
<div className="absolute top-0 left-0 right-0 p-4 bg-red-100 text-red-700">
|
||||
{error}
|
||||
</div>
|
||||
)}
|
||||
|
||||
<Calendar
|
||||
plugins={[dayGridPlugin, timeGridPlugin, interactionPlugin]}
|
||||
initialView="dayGridMonth"
|
||||
locale={ptBrLocale}
|
||||
events={eventos}
|
||||
editable={false}
|
||||
selectable={true}
|
||||
selectMirror={true}
|
||||
dayMaxEvents={3}
|
||||
weekends={true}
|
||||
datesSet={({ start, end }) => loadAgendamentos({ start, end })}
|
||||
eventClick={({ event }) => onEventClick?.(event)}
|
||||
select={(selectInfo) => onDateSelect?.(selectInfo)}
|
||||
headerToolbar={{
|
||||
left: 'prev,next today',
|
||||
center: 'title',
|
||||
right: 'dayGridMonth,timeGridWeek,timeGridDay'
|
||||
}}
|
||||
slotMinTime="08:00:00"
|
||||
slotMaxTime="18:00:00"
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -1,18 +1,9 @@
|
||||
import {
|
||||
format,
|
||||
startOfWeek,
|
||||
addDays,
|
||||
isSameDay,
|
||||
parseISO,
|
||||
getHours,
|
||||
} from "date-fns";
|
||||
import { ptBR } from "date-fns/locale";
|
||||
import { useState, useEffect } from "react";
|
||||
|
||||
import api from "../../services/api";
|
||||
|
||||
import { AgendamentoForm } from "./AgendamentoForm";
|
||||
import { AtendimentoForm } from "./AtendimentoForm";
|
||||
import { useState, useEffect } from 'react';
|
||||
import { format, startOfWeek, addDays, isSameDay, parseISO, getHours } from 'date-fns';
|
||||
import { ptBR } from 'date-fns/locale';
|
||||
import { AgendamentoForm } from './AgendamentoForm';
|
||||
import { AtendimentoForm } from './AtendimentoForm';
|
||||
import api from '../../services/api';
|
||||
|
||||
interface Agendamento {
|
||||
id: string;
|
||||
@@ -24,18 +15,13 @@ interface Agendamento {
|
||||
status: string;
|
||||
tipo?: string;
|
||||
observacoes?: string;
|
||||
atendimentoInicial?: {
|
||||
id: string;
|
||||
[key: string]: any;
|
||||
};
|
||||
}
|
||||
|
||||
export function AgendamentoCalendario() {
|
||||
const [selectedDate, setSelectedDate] = useState(new Date());
|
||||
const [agendamentos, setAgendamentos] = useState([]);
|
||||
const [formOpen, setFormOpen] = useState(false);
|
||||
const [selectedAgendamento, setSelectedAgendamento] =
|
||||
useState<Agendamento | null>(null);
|
||||
const [selectedAgendamento, setSelectedAgendamento] = useState<Agendamento | null>(null);
|
||||
const [atendimentoFormOpen, setAtendimentoFormOpen] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -44,23 +30,18 @@ export function AgendamentoCalendario() {
|
||||
|
||||
const loadAgendamentos = async (date: Date) => {
|
||||
try {
|
||||
// Formatando a data para YYYY-MM-DD, que é um formato mais simples e confiável
|
||||
const formattedDate = date.toISOString().split('T')[0];
|
||||
console.log("Buscando agendamentos para a data:", formattedDate);
|
||||
|
||||
const response = await api.get("/atendimentos/agendamentos", {
|
||||
params: { data: formattedDate },
|
||||
const response = await api.get('/agendamentos', {
|
||||
params: { data: date.toISOString() }
|
||||
});
|
||||
console.log("Resposta da API de agendamentos:", response.data);
|
||||
setAgendamentos(response.data);
|
||||
} catch (error) {
|
||||
console.error("Erro ao carregar agendamentos:", error);
|
||||
console.error('Erro ao carregar agendamentos:', error);
|
||||
}
|
||||
};
|
||||
|
||||
const weekDays = [...Array(7)].map((_, i) => {
|
||||
const day = addDays(startOfWeek(selectedDate, { locale: ptBR }), i);
|
||||
return format(day, "EEEE", { locale: ptBR });
|
||||
return format(day, 'EEEE', { locale: ptBR });
|
||||
});
|
||||
|
||||
const timeSlots = [...Array(9)].map((_, i) => {
|
||||
@@ -71,25 +52,17 @@ export function AgendamentoCalendario() {
|
||||
const getAgendamentosForSlot = (dayIndex: number, hour: number) => {
|
||||
return agendamentos.filter((agendamento: Agendamento) => {
|
||||
const agendamentoDate = parseISO(agendamento.data);
|
||||
const slotDate = addDays(
|
||||
startOfWeek(selectedDate, { locale: ptBR }),
|
||||
dayIndex,
|
||||
);
|
||||
const slotDate = addDays(startOfWeek(selectedDate, { locale: ptBR }), dayIndex);
|
||||
|
||||
return (
|
||||
isSameDay(agendamentoDate, slotDate) &&
|
||||
getHours(agendamentoDate) === hour
|
||||
);
|
||||
return isSameDay(agendamentoDate, slotDate) && getHours(agendamentoDate) === hour;
|
||||
});
|
||||
};
|
||||
|
||||
const handleAgendamentoClick = async (agendamento: Agendamento) => {
|
||||
try {
|
||||
// Buscar atendimento inicial se o tipo não for INICIAL
|
||||
if (agendamento.tipo !== "INICIAL") {
|
||||
const response = await api.get(
|
||||
`/atendimentos/iniciais/${agendamento.cliente.id}`,
|
||||
);
|
||||
if (agendamento.tipo !== 'INICIAL') {
|
||||
const response = await api.get(`/atendimentos/iniciais/${agendamento.cliente.id}`);
|
||||
const atendimentosIniciais = response.data;
|
||||
|
||||
// Pegar o atendimento inicial mais recente
|
||||
@@ -97,14 +70,14 @@ export function AgendamentoCalendario() {
|
||||
|
||||
setSelectedAgendamento({
|
||||
...agendamento,
|
||||
atendimentoInicial: atendimentoInicial,
|
||||
atendimentoInicial: atendimentoInicial
|
||||
});
|
||||
} else {
|
||||
setSelectedAgendamento(agendamento);
|
||||
}
|
||||
setAtendimentoFormOpen(true);
|
||||
} catch (error) {
|
||||
console.error("Erro ao buscar atendimento inicial:", error);
|
||||
console.error('Erro ao buscar atendimento inicial:', error);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -114,17 +87,17 @@ export function AgendamentoCalendario() {
|
||||
setSelectedAgendamento(agendamento);
|
||||
setFormOpen(true);
|
||||
} catch (error) {
|
||||
console.error("Erro ao editar agendamento:", error);
|
||||
console.error('Erro ao editar agendamento:', error);
|
||||
}
|
||||
};
|
||||
|
||||
const handleDeleteAgendamento = async (id: string) => {
|
||||
if (window.confirm("Tem certeza que deseja excluir este agendamento?")) {
|
||||
if (window.confirm('Tem certeza que deseja excluir este agendamento?')) {
|
||||
try {
|
||||
await api.delete(`/atendimentos/agendamentos/${id}`);
|
||||
await api.delete(`/agendamentos/${id}`);
|
||||
await loadAgendamentos(selectedDate);
|
||||
} catch (error) {
|
||||
console.error("Erro ao excluir agendamento:", error);
|
||||
console.error('Erro ao excluir agendamento:', error);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -145,11 +118,8 @@ export function AgendamentoCalendario() {
|
||||
{/* Coluna de horários */}
|
||||
<div className="col-span-1">
|
||||
<div className="h-10" /> {/* Espaço para alinhar com cabeçalho */}
|
||||
{timeSlots.map((time) => (
|
||||
<div
|
||||
key={time}
|
||||
className="h-20 flex items-center justify-center text-sm text-gray-500"
|
||||
>
|
||||
{timeSlots.map(time => (
|
||||
<div key={time} className="h-20 flex items-center justify-center text-sm text-gray-500">
|
||||
{time}
|
||||
</div>
|
||||
))}
|
||||
@@ -177,9 +147,7 @@ export function AgendamentoCalendario() {
|
||||
className={`absolute inset-x-1 p-1 rounded text-sm ${getStatusColor(agendamento.status)}`}
|
||||
>
|
||||
<div className="flex justify-between items-center">
|
||||
<div className="font-medium truncate">
|
||||
{agendamento.cliente.nome}
|
||||
</div>
|
||||
<div className="font-medium truncate">{agendamento.cliente.nome}</div>
|
||||
<div className="flex space-x-1">
|
||||
<button
|
||||
onClick={(e) => {
|
||||
@@ -191,7 +159,7 @@ export function AgendamentoCalendario() {
|
||||
>
|
||||
✏️
|
||||
</button>
|
||||
{agendamento.status !== "REALIZADO" && (
|
||||
{agendamento.status !== 'REALIZADO' && (
|
||||
<button
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
@@ -216,7 +184,7 @@ export function AgendamentoCalendario() {
|
||||
</div>
|
||||
</div>
|
||||
<div className="text-xs truncate">
|
||||
{format(parseISO(agendamento.data), "HH:mm")}
|
||||
{format(parseISO(agendamento.data), 'HH:mm')}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
@@ -252,8 +220,8 @@ export function AgendamentoCalendario() {
|
||||
initialData={{
|
||||
titulo: `Atendimento - ${selectedAgendamento.cliente.nome}`,
|
||||
agendamentoId: selectedAgendamento.id,
|
||||
tipo: selectedAgendamento.tipo || "INICIAL",
|
||||
atendimentoInicialId: selectedAgendamento.atendimentoInicial?.id,
|
||||
tipo: selectedAgendamento.tipo || 'INICIAL',
|
||||
atendimentoInicialId: selectedAgendamento.atendimentoInicial?.id
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
@@ -263,17 +231,17 @@ export function AgendamentoCalendario() {
|
||||
|
||||
function getStatusColor(status: string) {
|
||||
switch (status) {
|
||||
case "AGENDADO":
|
||||
return "bg-blue-100 text-blue-800";
|
||||
case "CONFIRMADO":
|
||||
return "bg-green-100 text-green-800";
|
||||
case "CANCELADO":
|
||||
return "bg-red-100 text-red-800";
|
||||
case "REALIZADO":
|
||||
return "bg-purple-100 text-purple-800";
|
||||
case "NAO_COMPARECEU":
|
||||
return "bg-gray-100 text-gray-800";
|
||||
case 'AGENDADO':
|
||||
return 'bg-blue-100 text-blue-800';
|
||||
case 'CONFIRMADO':
|
||||
return 'bg-green-100 text-green-800';
|
||||
case 'CANCELADO':
|
||||
return 'bg-red-100 text-red-800';
|
||||
case 'REALIZADO':
|
||||
return 'bg-purple-100 text-purple-800';
|
||||
case 'NAO_COMPARECEU':
|
||||
return 'bg-gray-100 text-gray-800';
|
||||
default:
|
||||
return "bg-gray-100 text-gray-800";
|
||||
return 'bg-gray-100 text-gray-800';
|
||||
}
|
||||
}
|
||||
@@ -1,301 +1,23 @@
|
||||
import { Router, Request, Response } from "express";
|
||||
import multer from "multer";
|
||||
import { startOfWeek, endOfWeek, parseISO } from 'date-fns';
|
||||
import { ptBR } from 'date-fns/locale';
|
||||
|
||||
import { authMiddleware } from "../../middleware/auth";
|
||||
import { NextCloudService } from "../../services/nextcloud";
|
||||
import { prisma } from "../prismaClient";
|
||||
import { Router } from 'express';
|
||||
import { prisma } from '../prismaClient';
|
||||
import { authMiddleware } from '../../middleware/auth';
|
||||
import multer from 'multer';
|
||||
import { NextCloudService } from '../../services/nextcloud';
|
||||
|
||||
const router = Router();
|
||||
const upload = multer({ storage: multer.memoryStorage() });
|
||||
|
||||
router.use(authMiddleware);
|
||||
|
||||
// Função auxiliar para validar se uma string é um UUID válido
|
||||
function isValidUUID(uuid: string): boolean {
|
||||
if (!uuid) return false;
|
||||
|
||||
try {
|
||||
// Validação principal com regex para UUID padrão
|
||||
const regexUUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
||||
|
||||
// Se passar na validação principal, retorna verdadeiro
|
||||
if (regexUUID.test(uuid)) return true;
|
||||
|
||||
// Caso contrário, verifica se é um ID válido de alguma outra forma
|
||||
// (como um ID numérico ou string que possa ser convertida em UUID)
|
||||
console.log(`ID recebido em formato não-UUID padrão: ${uuid}`);
|
||||
|
||||
// Se for "agendamentos", é uma rota especial que não precisa de validação UUID
|
||||
if (uuid === "agendamentos") return true;
|
||||
|
||||
// Se chegou aqui e não é um UUID válido, retorna falso
|
||||
return false;
|
||||
} catch (error) {
|
||||
console.error("Erro ao validar UUID:", error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Rota para listar agendamentos
|
||||
router.get("/agendamentos", async (req: Request, res: Response) => {
|
||||
try {
|
||||
const { data } = req.query;
|
||||
console.log("Requisição de agendamentos recebida, data:", data);
|
||||
|
||||
let dateFilter = {};
|
||||
|
||||
if (data) {
|
||||
try {
|
||||
// Aceitar e validar o formato da data de forma mais flexível
|
||||
const parsedDate = new Date(data as string);
|
||||
|
||||
// Verificar se a data é válida
|
||||
if (isNaN(parsedDate.getTime())) {
|
||||
console.error("Data inválida recebida:", data);
|
||||
// Em vez de retornar erro, continue sem filtro
|
||||
console.log("Continuando sem filtro de data devido a data inválida");
|
||||
} else {
|
||||
console.log("Data parseada:", parsedDate);
|
||||
|
||||
const weekStart = startOfWeek(parsedDate, { locale: ptBR });
|
||||
const weekEnd = endOfWeek(parsedDate, { locale: ptBR });
|
||||
|
||||
console.log("Período de busca:", {
|
||||
weekStart: weekStart.toISOString(),
|
||||
weekEnd: weekEnd.toISOString()
|
||||
});
|
||||
|
||||
dateFilter = {
|
||||
data: {
|
||||
gte: weekStart,
|
||||
lte: weekEnd,
|
||||
},
|
||||
};
|
||||
}
|
||||
} catch (parseError) {
|
||||
console.error("Erro ao analisar data:", parseError);
|
||||
// Continuar sem filtro de data em caso de erro, em vez de falhar
|
||||
console.log("Continuando sem filtro de data devido ao erro");
|
||||
}
|
||||
}
|
||||
|
||||
console.log("Filtro de data:", JSON.stringify(dateFilter));
|
||||
|
||||
// Usando o modelo correto e com tratamento de erro adequado
|
||||
try {
|
||||
const agendamentos = await prisma.agendamentoAtendimento.findMany({
|
||||
where: dateFilter,
|
||||
include: {
|
||||
cliente: {
|
||||
select: {
|
||||
id: true,
|
||||
nome: true,
|
||||
},
|
||||
},
|
||||
usuario: {
|
||||
select: {
|
||||
id: true,
|
||||
nome: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
orderBy: {
|
||||
data: 'asc',
|
||||
},
|
||||
});
|
||||
|
||||
console.log(`Encontrados ${agendamentos.length} agendamentos`);
|
||||
|
||||
return res.json(agendamentos);
|
||||
} catch (dbError) {
|
||||
console.error("Erro na consulta do banco de dados:", dbError);
|
||||
return res.status(500).json({
|
||||
error: "Erro ao buscar agendamentos no banco de dados",
|
||||
details: dbError.message
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Erro geral ao listar agendamentos:", error);
|
||||
return res.status(500).json({
|
||||
error: "Erro ao listar agendamentos",
|
||||
details: error.message
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Rota para criar um novo agendamento
|
||||
router.post("/agendamentos", async (req: Request, res: Response) => {
|
||||
try {
|
||||
const { clienteId, data, observacoes, tipo } = req.body;
|
||||
console.log("Criando agendamento:", { clienteId, data, observacoes, tipo });
|
||||
|
||||
if (!clienteId || !data) {
|
||||
return res.status(400).json({ error: "Cliente e data são obrigatórios" });
|
||||
}
|
||||
|
||||
// Verificar se o cliente existe
|
||||
const cliente = await prisma.cliente.findUnique({
|
||||
where: { id: clienteId }
|
||||
});
|
||||
|
||||
if (!cliente) {
|
||||
return res.status(404).json({ error: "Cliente não encontrado" });
|
||||
}
|
||||
|
||||
// Criar o agendamento - usando agendamentoAtendimento
|
||||
const agendamento = await prisma.agendamentoAtendimento.create({
|
||||
data: {
|
||||
clienteId,
|
||||
data: new Date(data),
|
||||
observacoes,
|
||||
tipo,
|
||||
status: "AGENDADO",
|
||||
usuarioId: req.user?.id // Adicionando usuarioId do middleware auth
|
||||
},
|
||||
include: {
|
||||
cliente: {
|
||||
select: {
|
||||
id: true,
|
||||
nome: true
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
console.log("Agendamento criado:", {
|
||||
id: agendamento.id,
|
||||
data: agendamento.data,
|
||||
clienteNome: agendamento.cliente.nome
|
||||
});
|
||||
|
||||
res.status(201).json(agendamento);
|
||||
} catch (error) {
|
||||
console.error("Erro ao criar agendamento:", error);
|
||||
res.status(500).json({ error: "Erro ao criar agendamento", details: error.message });
|
||||
}
|
||||
});
|
||||
|
||||
// Rota para atualizar um agendamento
|
||||
router.put("/agendamentos/:id", async (req: Request, res: Response) => {
|
||||
try {
|
||||
const { id } = req.params;
|
||||
const { clienteId, data, observacoes, tipo } = req.body;
|
||||
|
||||
// Validação do UUID antes de consultar o banco de dados
|
||||
if (!isValidUUID(id)) {
|
||||
console.error(`ID de agendamento inválido: ${id}. Não é um UUID válido.`);
|
||||
return res.status(400).json({
|
||||
error: "ID de agendamento inválido",
|
||||
details: "O formato do ID fornecido não é um UUID válido."
|
||||
});
|
||||
}
|
||||
|
||||
console.log("Atualizando agendamento:", { id, clienteId, data, observacoes, tipo });
|
||||
|
||||
// Verificar se o agendamento existe usando a tabela correta
|
||||
const existingAgendamento = await prisma.agendamentoAtendimento.findUnique({
|
||||
where: { id }
|
||||
});
|
||||
|
||||
if (!existingAgendamento) {
|
||||
return res.status(404).json({ error: "Agendamento não encontrado" });
|
||||
}
|
||||
|
||||
// Atualizar o agendamento usando a tabela correta
|
||||
const agendamento = await prisma.agendamentoAtendimento.update({
|
||||
where: { id },
|
||||
data: {
|
||||
clienteId,
|
||||
data: data ? new Date(data) : undefined,
|
||||
observacoes,
|
||||
tipo
|
||||
},
|
||||
include: {
|
||||
cliente: {
|
||||
select: {
|
||||
id: true,
|
||||
nome: true
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
console.log("Agendamento atualizado:", {
|
||||
id: agendamento.id,
|
||||
data: agendamento.data,
|
||||
clienteNome: agendamento.cliente.nome
|
||||
});
|
||||
|
||||
res.json(agendamento);
|
||||
} catch (error) {
|
||||
console.error("Erro ao atualizar agendamento:", error);
|
||||
res.status(500).json({ error: "Erro ao atualizar agendamento", details: error.message });
|
||||
}
|
||||
});
|
||||
|
||||
// Rota para excluir um agendamento
|
||||
router.delete("/agendamentos/:id", async (req: Request, res: Response) => {
|
||||
try {
|
||||
const { id } = req.params;
|
||||
console.log("Excluindo agendamento:", id);
|
||||
|
||||
// Validação do UUID antes de consultar o banco de dados
|
||||
if (!isValidUUID(id)) {
|
||||
console.error(`ID de agendamento inválido: ${id}. Não é um UUID válido.`);
|
||||
return res.status(400).json({
|
||||
error: "ID de agendamento inválido",
|
||||
details: "O formato do ID fornecido não é um UUID válido."
|
||||
});
|
||||
}
|
||||
|
||||
// Verificar se o agendamento existe usando a tabela correta
|
||||
const agendamento = await prisma.agendamentoAtendimento.findUnique({
|
||||
where: { id },
|
||||
include: { cliente: true }
|
||||
});
|
||||
|
||||
if (!agendamento) {
|
||||
console.error("Agendamento não encontrado:", id);
|
||||
return res.status(404).json({ error: "Agendamento não encontrado" });
|
||||
}
|
||||
|
||||
console.log("Agendamento encontrado:", {
|
||||
id: agendamento.id,
|
||||
data: agendamento.data,
|
||||
clienteNome: agendamento.cliente?.nome
|
||||
});
|
||||
|
||||
// Excluir o agendamento usando a tabela correta
|
||||
await prisma.agendamentoAtendimento.delete({
|
||||
where: { id }
|
||||
});
|
||||
|
||||
console.log("Agendamento excluído com sucesso");
|
||||
res.status(200).json({ message: "Agendamento excluído com sucesso" });
|
||||
} catch (error) {
|
||||
console.error("Erro ao excluir agendamento:", error);
|
||||
res.status(500).json({ error: "Erro ao excluir agendamento", details: error.message });
|
||||
}
|
||||
});
|
||||
// ...existing routes...
|
||||
|
||||
// Rota para atualizar atendimento com anexos
|
||||
router.patch("/:id", async (req: Request, res: Response) => {
|
||||
router.patch('/:id', async (req, res) => {
|
||||
try {
|
||||
const { id } = req.params;
|
||||
const { anexos, ...data } = req.body;
|
||||
|
||||
// Validação do UUID antes de consultar o banco de dados
|
||||
if (!isValidUUID(id)) {
|
||||
console.error(`ID de atendimento inválido: ${id}. Não é um UUID válido.`);
|
||||
return res.status(400).json({
|
||||
error: "ID de atendimento inválido",
|
||||
details: "O formato do ID fornecido não é um UUID válido."
|
||||
});
|
||||
}
|
||||
|
||||
console.log("Atualizando atendimento:", id, { anexos, data }); // Debug log
|
||||
console.log('Atualizando atendimento:', id, { anexos, data }); // Debug log
|
||||
|
||||
const atendimento = await prisma.atendimento.update({
|
||||
where: { id },
|
||||
@@ -308,73 +30,60 @@ router.patch("/:id", async (req: Request, res: Response) => {
|
||||
nome: anexo.nome,
|
||||
url: anexo.url,
|
||||
tipo: anexo.tipo,
|
||||
tamanho: anexo.tamanho,
|
||||
})),
|
||||
},
|
||||
},
|
||||
}),
|
||||
tamanho: anexo.tamanho
|
||||
}))
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
include: {
|
||||
anexos: true,
|
||||
cliente: true,
|
||||
},
|
||||
cliente: true
|
||||
}
|
||||
});
|
||||
|
||||
console.log("Atendimento atualizado:", atendimento); // Debug log
|
||||
console.log('Atendimento atualizado:', atendimento); // Debug log
|
||||
res.json(atendimento);
|
||||
} catch (error) {
|
||||
console.error("Erro ao atualizar atendimento:", error);
|
||||
res.status(500).json({ error: "Erro ao atualizar atendimento" });
|
||||
console.error('Erro ao atualizar atendimento:', error);
|
||||
res.status(500).json({ error: 'Erro ao atualizar atendimento' });
|
||||
}
|
||||
});
|
||||
|
||||
// Nova rota para upload de arquivo via proxy
|
||||
router.post("/upload", upload.single("file"), async (req: Request, res: Response) => {
|
||||
router.post('/upload', upload.single('file'), async (req, res) => {
|
||||
try {
|
||||
if (!req.file || !req.body.clienteNome) {
|
||||
return res
|
||||
.status(400)
|
||||
.json({ error: "Arquivo e nome do cliente são obrigatórios" });
|
||||
return res.status(400).json({ error: 'Arquivo e nome do cliente são obrigatórios' });
|
||||
}
|
||||
|
||||
// Enviar para o NextCloud usando a estrutura de pastas correta
|
||||
const buffer = req.file.buffer;
|
||||
Object.defineProperty(buffer, "name", {
|
||||
Object.defineProperty(buffer, 'name', {
|
||||
value: req.file.originalname,
|
||||
writable: true,
|
||||
enumerable: true,
|
||||
enumerable: true
|
||||
});
|
||||
|
||||
const filePath = await NextCloudService.uploadFile(
|
||||
buffer,
|
||||
req.body.clienteNome,
|
||||
"atendimento",
|
||||
req.body.protocolo,
|
||||
'atendimento',
|
||||
req.body.protocolo
|
||||
);
|
||||
|
||||
res.json({ url: filePath });
|
||||
} catch (error) {
|
||||
console.error("Erro no upload:", error);
|
||||
res.status(500).json({ error: "Erro no upload do arquivo" });
|
||||
console.error('Erro no upload:', error);
|
||||
res.status(500).json({ error: 'Erro no upload do arquivo' });
|
||||
}
|
||||
});
|
||||
|
||||
router.get("/:id", async (req: Request, res: Response) => {
|
||||
router.get('/:id', async (req, res) => {
|
||||
try {
|
||||
const { id } = req.params;
|
||||
|
||||
// Validação do UUID antes de consultar o banco de dados
|
||||
if (!isValidUUID(id)) {
|
||||
console.error(`ID de atendimento inválido: ${id}. Não é um UUID válido.`);
|
||||
return res.status(400).json({
|
||||
error: "ID de atendimento inválido",
|
||||
details: "O formato do ID fornecido não é um UUID válido."
|
||||
});
|
||||
}
|
||||
|
||||
const atendimento = await prisma.atendimento.findUnique({
|
||||
where: {
|
||||
id: id,
|
||||
id: req.params.id
|
||||
},
|
||||
include: {
|
||||
cliente: true,
|
||||
@@ -384,20 +93,20 @@ router.get("/:id", async (req: Request, res: Response) => {
|
||||
id: true,
|
||||
nome: true,
|
||||
oab: true,
|
||||
oabUF: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
oabUF: true
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (!atendimento) {
|
||||
return res.status(404).json({ error: "Atendimento não encontrado" });
|
||||
return res.status(404).json({ error: 'Atendimento não encontrado' });
|
||||
}
|
||||
|
||||
res.json(atendimento);
|
||||
} catch (error) {
|
||||
console.error("Erro ao buscar atendimento:", error);
|
||||
res.status(500).json({ error: "Erro ao buscar atendimento" });
|
||||
console.error('Erro ao buscar atendimento:', error);
|
||||
res.status(500).json({ error: 'Erro ao buscar atendimento' });
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
Reference in new issue
Block a user