develop #83
@ -9,7 +9,7 @@ import { useAuth } from "@/hooks/useAuth";
|
|||||||
import { useToast } from "@/hooks/use-toast";
|
import { useToast } from "@/hooks/use-toast";
|
||||||
import { useAvatarUrl } from "@/hooks/useAvatarUrl";
|
import { useAvatarUrl } from "@/hooks/useAvatarUrl";
|
||||||
import { UploadAvatar } from '@/components/ui/upload-avatar';
|
import { UploadAvatar } from '@/components/ui/upload-avatar';
|
||||||
import { buscarPacientes, listarPacientes, buscarPacientePorId, buscarPacientesPorIds, buscarMedicoPorId, buscarMedicosPorIds, buscarMedicos, listarAgendamentos, type Paciente, buscarRelatorioPorId, atualizarMedico } from "@/lib/api";
|
import { buscarPacientes, listarPacientes, buscarPacientePorId, buscarPacientesPorIds, buscarMedicoPorId, buscarMedicosPorIds, buscarMedicos, listarAgendamentos, type Paciente, buscarRelatorioPorId, atualizarMedico, listarDisponibilidades, DoctorAvailability, deletarDisponibilidade, listarExcecoes, DoctorException, deletarExcecao } from "@/lib/api";
|
||||||
import { ENV_CONFIG } from '@/lib/env-config';
|
import { ENV_CONFIG } from '@/lib/env-config';
|
||||||
import { useReports } from "@/hooks/useReports";
|
import { useReports } from "@/hooks/useReports";
|
||||||
import { CreateReportData } from "@/types/report-types";
|
import { CreateReportData } from "@/types/report-types";
|
||||||
@ -19,6 +19,8 @@ import { Input } from "@/components/ui/input";
|
|||||||
import { Label } from "@/components/ui/label";
|
import { Label } from "@/components/ui/label";
|
||||||
import { Textarea } from "@/components/ui/textarea";
|
import { Textarea } from "@/components/ui/textarea";
|
||||||
import { Select, SelectTrigger, SelectContent, SelectItem, SelectValue } from "@/components/ui/select";
|
import { Select, SelectTrigger, SelectContent, SelectItem, SelectValue } from "@/components/ui/select";
|
||||||
|
import AvailabilityForm from '@/components/features/forms/availability-form';
|
||||||
|
import ExceptionForm from '@/components/features/forms/exception-form';
|
||||||
import { SimpleThemeToggle } from "@/components/ui/simple-theme-toggle";
|
import { SimpleThemeToggle } from "@/components/ui/simple-theme-toggle";
|
||||||
import {
|
import {
|
||||||
Table,
|
Table,
|
||||||
@ -65,6 +67,29 @@ const colorsByType = {
|
|||||||
Oftalmologia: "#2ecc71"
|
Oftalmologia: "#2ecc71"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Função para traduzir dias da semana
|
||||||
|
function translateWeekday(w?: string) {
|
||||||
|
if (!w) return '';
|
||||||
|
const key = w.toString().toLowerCase().normalize('NFD').replace(/\p{Diacritic}/gu, '').replace(/[^a-z0-9]/g, '');
|
||||||
|
const map: Record<string, string> = {
|
||||||
|
'segunda': 'Segunda',
|
||||||
|
'terca': 'Terça',
|
||||||
|
'quarta': 'Quarta',
|
||||||
|
'quinta': 'Quinta',
|
||||||
|
'sexta': 'Sexta',
|
||||||
|
'sabado': 'Sábado',
|
||||||
|
'domingo': 'Domingo',
|
||||||
|
'monday': 'Segunda',
|
||||||
|
'tuesday': 'Terça',
|
||||||
|
'wednesday': 'Quarta',
|
||||||
|
'thursday': 'Quinta',
|
||||||
|
'friday': 'Sexta',
|
||||||
|
'saturday': 'Sábado',
|
||||||
|
'sunday': 'Domingo',
|
||||||
|
};
|
||||||
|
return map[key] ?? w;
|
||||||
|
}
|
||||||
|
|
||||||
// Helpers para normalizar dados de paciente (suporta schema antigo e novo)
|
// Helpers para normalizar dados de paciente (suporta schema antigo e novo)
|
||||||
const getPatientName = (p: any) => p?.full_name ?? p?.nome ?? '';
|
const getPatientName = (p: any) => p?.full_name ?? p?.nome ?? '';
|
||||||
const getPatientCpf = (p: any) => p?.cpf ?? '';
|
const getPatientCpf = (p: any) => p?.cpf ?? '';
|
||||||
@ -132,6 +157,16 @@ const ProfissionalPage = () => {
|
|||||||
const [isEditingProfile, setIsEditingProfile] = useState(false);
|
const [isEditingProfile, setIsEditingProfile] = useState(false);
|
||||||
const [doctorId, setDoctorId] = useState<string | null>(null);
|
const [doctorId, setDoctorId] = useState<string | null>(null);
|
||||||
|
|
||||||
|
// Estados para disponibilidades e exceções do médico logado
|
||||||
|
const [availabilities, setAvailabilities] = useState<DoctorAvailability[]>([]);
|
||||||
|
const [exceptions, setExceptions] = useState<DoctorException[]>([]);
|
||||||
|
const [availLoading, setAvailLoading] = useState(false);
|
||||||
|
const [exceptLoading, setExceptLoading] = useState(false);
|
||||||
|
const [editingAvailability, setEditingAvailability] = useState<DoctorAvailability | null>(null);
|
||||||
|
const [editingException, setEditingException] = useState<DoctorException | null>(null);
|
||||||
|
const [showAvailabilityForm, setShowAvailabilityForm] = useState(false);
|
||||||
|
const [showExceptionForm, setShowExceptionForm] = useState(false);
|
||||||
|
|
||||||
// Hook para carregar automaticamente o avatar do médico
|
// Hook para carregar automaticamente o avatar do médico
|
||||||
const { avatarUrl: retrievedAvatarUrl } = useAvatarUrl(doctorId);
|
const { avatarUrl: retrievedAvatarUrl } = useAvatarUrl(doctorId);
|
||||||
// Removemos o placeholder extenso — inicializamos com valores minimalistas e vazios.
|
// Removemos o placeholder extenso — inicializamos com valores minimalistas e vazios.
|
||||||
@ -286,6 +321,48 @@ const ProfissionalPage = () => {
|
|||||||
}
|
}
|
||||||
}, [retrievedAvatarUrl]);
|
}, [retrievedAvatarUrl]);
|
||||||
|
|
||||||
|
// Carregar disponibilidades e exceções do médico logado
|
||||||
|
const reloadAvailabilities = async (medId?: string) => {
|
||||||
|
const id = medId || doctorId;
|
||||||
|
if (!id) return;
|
||||||
|
try {
|
||||||
|
setAvailLoading(true);
|
||||||
|
const avails = await listarDisponibilidades({ doctorId: id, active: true });
|
||||||
|
setAvailabilities(Array.isArray(avails) ? avails : []);
|
||||||
|
} catch (e) {
|
||||||
|
console.warn('[ProfissionalPage] Erro ao carregar disponibilidades:', e);
|
||||||
|
setAvailabilities([]);
|
||||||
|
} finally {
|
||||||
|
setAvailLoading(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const reloadExceptions = async (medId?: string) => {
|
||||||
|
const id = medId || doctorId;
|
||||||
|
if (!id) return;
|
||||||
|
try {
|
||||||
|
setExceptLoading(true);
|
||||||
|
console.log('[ProfissionalPage] Recarregando exceções para médico:', id);
|
||||||
|
const excepts = await listarExcecoes({ doctorId: id });
|
||||||
|
console.log('[ProfissionalPage] Exceções carregadas:', excepts);
|
||||||
|
setExceptions(Array.isArray(excepts) ? excepts : []);
|
||||||
|
} catch (e) {
|
||||||
|
console.warn('[ProfissionalPage] Erro ao carregar exceções:', e);
|
||||||
|
setExceptions([]);
|
||||||
|
} finally {
|
||||||
|
setExceptLoading(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Carrega disponibilidades quando doctorId muda
|
||||||
|
useEffect(() => {
|
||||||
|
if (doctorId) {
|
||||||
|
reloadAvailabilities(doctorId);
|
||||||
|
reloadExceptions(doctorId);
|
||||||
|
}
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, [doctorId]);
|
||||||
|
|
||||||
|
|
||||||
// Estados para campos principais da consulta
|
// Estados para campos principais da consulta
|
||||||
const [consultaAtual, setConsultaAtual] = useState({
|
const [consultaAtual, setConsultaAtual] = useState({
|
||||||
@ -2746,7 +2823,129 @@ const ProfissionalPage = () => {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const renderDisponibilidadesSection = () => {
|
||||||
|
// Filtrar apenas a primeira disponibilidade de cada dia da semana
|
||||||
|
const availabilityByDay = new Map<string, DoctorAvailability>();
|
||||||
|
(availabilities || []).forEach((a) => {
|
||||||
|
const day = String(a.weekday ?? '').toLowerCase();
|
||||||
|
if (!availabilityByDay.has(day)) {
|
||||||
|
availabilityByDay.set(day, a);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const filteredAvailabilities = Array.from(availabilityByDay.values());
|
||||||
|
|
||||||
|
// Filtrar apenas a primeira exceção de cada data
|
||||||
|
const exceptionByDate = new Map<string, DoctorException>();
|
||||||
|
(exceptions || []).forEach((ex) => {
|
||||||
|
const date = String(ex.exception_date ?? ex.date ?? '');
|
||||||
|
if (!exceptionByDate.has(date)) {
|
||||||
|
exceptionByDate.set(date, ex);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const filteredExceptions = Array.from(exceptionByDate.values());
|
||||||
|
|
||||||
|
return (
|
||||||
|
<section className="bg-card shadow-md rounded-lg border border-border p-3 sm:p-4 md:p-6 w-full">
|
||||||
|
<div className="flex flex-col sm:flex-row items-start sm:items-center justify-between gap-3 mb-6">
|
||||||
|
<h2 className="text-xl sm:text-2xl font-bold">Minhas Disponibilidades</h2>
|
||||||
|
<div className="flex gap-2 w-full sm:w-auto">
|
||||||
|
<Button
|
||||||
|
size="sm"
|
||||||
|
className="flex-1 sm:flex-initial bg-blue-600 hover:bg-blue-700 text-xs sm:text-sm"
|
||||||
|
onClick={() => {
|
||||||
|
setEditingAvailability(null);
|
||||||
|
setShowAvailabilityForm(true);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
+ Disponibilidade
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Disponibilidades */}
|
||||||
|
{availLoading ? (
|
||||||
|
<div className="text-sm text-muted-foreground p-4">Carregando disponibilidades…</div>
|
||||||
|
) : filteredAvailabilities && filteredAvailabilities.length > 0 ? (
|
||||||
|
<div className="space-y-2">
|
||||||
|
{filteredAvailabilities.map((a) => (
|
||||||
|
<div key={String(a.id)} className="p-3 border rounded flex justify-between items-start">
|
||||||
|
<div className="flex-1">
|
||||||
|
<div className="font-medium text-sm sm:text-base">{translateWeekday(a.weekday)} • {a.start_time} — {a.end_time}</div>
|
||||||
|
<div className="text-xs text-muted-foreground">Duração: {a.slot_minutes} min • Tipo: {a.appointment_type || '—'} • {a.active ? 'Ativa' : 'Inativa'}</div>
|
||||||
|
</div>
|
||||||
|
<div className="flex gap-2 ml-2">
|
||||||
|
<Button
|
||||||
|
size="sm"
|
||||||
|
variant="outline"
|
||||||
|
className="text-xs"
|
||||||
|
onClick={() => {
|
||||||
|
setEditingAvailability(a);
|
||||||
|
setShowAvailabilityForm(true);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Editar
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
size="sm"
|
||||||
|
variant="destructive"
|
||||||
|
className="text-xs"
|
||||||
|
onClick={async () => {
|
||||||
|
if (!confirm('Excluir esta disponibilidade?')) return;
|
||||||
|
try {
|
||||||
|
await deletarDisponibilidade(String(a.id));
|
||||||
|
reloadAvailabilities();
|
||||||
|
toast({ title: 'Disponibilidade excluída', variant: 'default' });
|
||||||
|
} catch (e) {
|
||||||
|
console.warn('Erro ao deletar disponibilidade:', e);
|
||||||
|
toast({ title: 'Erro ao excluir', description: (e as any)?.message || String(e), variant: 'destructive' });
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Excluir
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div className="text-sm text-muted-foreground p-4 border rounded-lg bg-muted/50">
|
||||||
|
Nenhuma disponibilidade cadastrada.
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* Exceções */}
|
||||||
|
<div className="mt-8">
|
||||||
|
<h3 className="text-lg sm:text-xl font-bold mb-4">Exceções (Bloqueios/Liberações)</h3>
|
||||||
|
{exceptLoading ? (
|
||||||
|
<div className="text-sm text-muted-foreground p-4">Carregando exceções…</div>
|
||||||
|
) : filteredExceptions && filteredExceptions.length > 0 ? (
|
||||||
|
<div className="space-y-2">
|
||||||
|
{filteredExceptions.map((ex) => (
|
||||||
|
<div key={String(ex.id)} className="p-3 border rounded flex justify-between items-start">
|
||||||
|
<div className="flex-1">
|
||||||
|
<div className="font-medium text-sm sm:text-base">
|
||||||
|
{new Date(ex.exception_date ?? ex.date).toLocaleDateString('pt-BR')}
|
||||||
|
</div>
|
||||||
|
<div className="text-xs text-muted-foreground">
|
||||||
|
Tipo: bloqueio • Motivo: {ex.reason || '—'}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="flex gap-2 ml-2">
|
||||||
|
{/* Sem ações para exceções */}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div className="text-sm text-muted-foreground p-4 border rounded-lg bg-muted/50">
|
||||||
|
Nenhuma exceção cadastrada.
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
const renderPerfilSection = () => (
|
const renderPerfilSection = () => (
|
||||||
<div className="mx-auto flex w-full max-w-6xl flex-col gap-4 sm:gap-6 px-0 py-4 sm:py-8 md:px-4">
|
<div className="mx-auto flex w-full max-w-6xl flex-col gap-4 sm:gap-6 px-0 py-4 sm:py-8 md:px-4">
|
||||||
{/* Header com Título e Botão */}
|
{/* Header com Título e Botão */}
|
||||||
@ -3022,6 +3221,8 @@ const ProfissionalPage = () => {
|
|||||||
);
|
);
|
||||||
case 'laudos':
|
case 'laudos':
|
||||||
return renderLaudosSection();
|
return renderLaudosSection();
|
||||||
|
case 'disponibilidades':
|
||||||
|
return renderDisponibilidadesSection();
|
||||||
case 'comunicacao':
|
case 'comunicacao':
|
||||||
return renderComunicacaoSection();
|
return renderComunicacaoSection();
|
||||||
case 'perfil':
|
case 'perfil':
|
||||||
@ -3158,6 +3359,17 @@ const ProfissionalPage = () => {
|
|||||||
<FileText className="mr-2 h-4 w-4" />
|
<FileText className="mr-2 h-4 w-4" />
|
||||||
Laudos
|
Laudos
|
||||||
</Button>
|
</Button>
|
||||||
|
<Button
|
||||||
|
variant={activeSection === 'disponibilidades' ? 'default' : 'ghost'}
|
||||||
|
className="w-full justify-start text-sm md:text-base transition-colors hover:bg-primary! hover:text-white! cursor-pointer"
|
||||||
|
onClick={() => {
|
||||||
|
setActiveSection('disponibilidades');
|
||||||
|
setSidebarOpen(false);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Clock className="mr-2 h-4 w-4" />
|
||||||
|
Disponibilidades
|
||||||
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
variant={activeSection === 'comunicacao' ? 'default' : 'ghost'}
|
variant={activeSection === 'comunicacao' ? 'default' : 'ghost'}
|
||||||
className="w-full justify-start text-sm md:text-base transition-colors hover:bg-primary! hover:text-white! cursor-pointer"
|
className="w-full justify-start text-sm md:text-base transition-colors hover:bg-primary! hover:text-white! cursor-pointer"
|
||||||
@ -3194,7 +3406,29 @@ const ProfissionalPage = () => {
|
|||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{}
|
{/* AvailabilityForm para criar/editar disponibilidades */}
|
||||||
|
{showAvailabilityForm && (
|
||||||
|
<AvailabilityForm
|
||||||
|
open={showAvailabilityForm}
|
||||||
|
onOpenChange={(open) => {
|
||||||
|
if (!open) {
|
||||||
|
setShowAvailabilityForm(false);
|
||||||
|
setEditingAvailability(null);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
doctorId={editingAvailability?.doctor_id ?? doctorId}
|
||||||
|
availability={editingAvailability}
|
||||||
|
mode={editingAvailability ? "edit" : "create"}
|
||||||
|
onSaved={(saved) => {
|
||||||
|
console.log('Disponibilidade salva', saved);
|
||||||
|
setEditingAvailability(null);
|
||||||
|
setShowAvailabilityForm(false);
|
||||||
|
reloadAvailabilities();
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* Popup antigo (manter para compatibilidade) */}
|
||||||
{showPopup && (
|
{showPopup && (
|
||||||
<div className="fixed inset-0 bg-black/50 backdrop-blur-sm flex justify-center items-center z-50">
|
<div className="fixed inset-0 bg-black/50 backdrop-blur-sm flex justify-center items-center z-50">
|
||||||
|
|
||||||
|
|||||||
@ -28,6 +28,19 @@ export default function ExceptionForm({ open, onOpenChange, doctorId = null, onS
|
|||||||
const [showDatePicker, setShowDatePicker] = useState(false)
|
const [showDatePicker, setShowDatePicker] = useState(false)
|
||||||
const { toast } = useToast()
|
const { toast } = useToast()
|
||||||
|
|
||||||
|
// Resetar form quando dialog fecha
|
||||||
|
const handleOpenChange = (newOpen: boolean) => {
|
||||||
|
if (!newOpen) {
|
||||||
|
setDate('')
|
||||||
|
setStartTime('')
|
||||||
|
setEndTime('')
|
||||||
|
setKind('bloqueio')
|
||||||
|
setReason('')
|
||||||
|
setShowDatePicker(false)
|
||||||
|
}
|
||||||
|
onOpenChange(newOpen)
|
||||||
|
}
|
||||||
|
|
||||||
async function handleSubmit(e?: React.FormEvent) {
|
async function handleSubmit(e?: React.FormEvent) {
|
||||||
e?.preventDefault()
|
e?.preventDefault()
|
||||||
if (!doctorId) {
|
if (!doctorId) {
|
||||||
@ -53,7 +66,7 @@ export default function ExceptionForm({ open, onOpenChange, doctorId = null, onS
|
|||||||
const saved = await criarExcecao(payload)
|
const saved = await criarExcecao(payload)
|
||||||
toast({ title: 'Exceção criada', description: `${payload.date} • ${kind}`, variant: 'default' })
|
toast({ title: 'Exceção criada', description: `${payload.date} • ${kind}`, variant: 'default' })
|
||||||
onSaved?.(saved)
|
onSaved?.(saved)
|
||||||
onOpenChange(false)
|
handleOpenChange(false)
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
console.error('Erro ao criar exceção:', err)
|
console.error('Erro ao criar exceção:', err)
|
||||||
toast({ title: 'Erro', description: err?.message || String(err), variant: 'destructive' })
|
toast({ title: 'Erro', description: err?.message || String(err), variant: 'destructive' })
|
||||||
@ -63,7 +76,7 @@ export default function ExceptionForm({ open, onOpenChange, doctorId = null, onS
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Dialog open={open} onOpenChange={onOpenChange}>
|
<Dialog open={open} onOpenChange={handleOpenChange}>
|
||||||
<DialogContent>
|
<DialogContent>
|
||||||
<DialogHeader>
|
<DialogHeader>
|
||||||
<DialogTitle>Criar exceção</DialogTitle>
|
<DialogTitle>Criar exceção</DialogTitle>
|
||||||
@ -103,6 +116,7 @@ export default function ExceptionForm({ open, onOpenChange, doctorId = null, onS
|
|||||||
mode="single"
|
mode="single"
|
||||||
selected={date ? (() => {
|
selected={date ? (() => {
|
||||||
try {
|
try {
|
||||||
|
// Parse como local date para compatibilidade com Calendar
|
||||||
const [y, m, d] = String(date).split('-').map(Number);
|
const [y, m, d] = String(date).split('-').map(Number);
|
||||||
return new Date(y, m - 1, d);
|
return new Date(y, m - 1, d);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@ -111,10 +125,12 @@ export default function ExceptionForm({ open, onOpenChange, doctorId = null, onS
|
|||||||
})() : undefined}
|
})() : undefined}
|
||||||
onSelect={(selectedDate) => {
|
onSelect={(selectedDate) => {
|
||||||
if (selectedDate) {
|
if (selectedDate) {
|
||||||
|
// Extrair data como local para evitar problemas de timezone
|
||||||
const y = selectedDate.getFullYear();
|
const y = selectedDate.getFullYear();
|
||||||
const m = String(selectedDate.getMonth() + 1).padStart(2, '0');
|
const m = String(selectedDate.getMonth() + 1).padStart(2, '0');
|
||||||
const d = String(selectedDate.getDate()).padStart(2, '0');
|
const d = String(selectedDate.getDate()).padStart(2, '0');
|
||||||
const dateStr = `${y}-${m}-${d}`;
|
const dateStr = `${y}-${m}-${d}`;
|
||||||
|
console.log('[ExceptionForm] Data selecionada:', dateStr, 'de', selectedDate);
|
||||||
setDate(dateStr);
|
setDate(dateStr);
|
||||||
setShowDatePicker(false);
|
setShowDatePicker(false);
|
||||||
}
|
}
|
||||||
@ -160,7 +176,7 @@ export default function ExceptionForm({ open, onOpenChange, doctorId = null, onS
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<DialogFooter>
|
<DialogFooter>
|
||||||
<Button variant="ghost" onClick={() => onOpenChange(false)} disabled={submitting}>Cancelar</Button>
|
<Button variant="ghost" onClick={() => handleOpenChange(false)} disabled={submitting}>Cancelar</Button>
|
||||||
<Button type="submit" disabled={submitting}>{submitting ? 'Salvando...' : 'Criar exceção'}</Button>
|
<Button type="submit" disabled={submitting}>{submitting ? 'Salvando...' : 'Criar exceção'}</Button>
|
||||||
</DialogFooter>
|
</DialogFooter>
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
@ -488,11 +488,10 @@ export async function deletarDisponibilidade(id: string): Promise<void> {
|
|||||||
headers: withPrefer({ ...baseHeaders() }, 'return=minimal'),
|
headers: withPrefer({ ...baseHeaders() }, 'return=minimal'),
|
||||||
});
|
});
|
||||||
|
|
||||||
if (res.status === 204) return;
|
if (res.status === 204 || res.status === 200) return;
|
||||||
// Some deployments may return 200 with a representation — accept that too
|
|
||||||
if (res.status === 200) return;
|
// Se chegou aqui e não foi sucesso, lance erro
|
||||||
// Otherwise surface a friendly error using parse()
|
throw new Error(`Erro ao deletar disponibilidade: ${res.status}`);
|
||||||
await parse(res as Response);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ===== EXCEÇÕES (Doctor Exceptions) =====
|
// ===== EXCEÇÕES (Doctor Exceptions) =====
|
||||||
@ -580,14 +579,21 @@ export async function listarExcecoes(params?: { doctorId?: string; date?: string
|
|||||||
export async function deletarExcecao(id: string): Promise<void> {
|
export async function deletarExcecao(id: string): Promise<void> {
|
||||||
if (!id) throw new Error('ID da exceção é obrigatório');
|
if (!id) throw new Error('ID da exceção é obrigatório');
|
||||||
const url = `${REST}/doctor_exceptions?id=eq.${encodeURIComponent(String(id))}`;
|
const url = `${REST}/doctor_exceptions?id=eq.${encodeURIComponent(String(id))}`;
|
||||||
|
console.log('[deletarExcecao] Deletando exceção:', id, 'URL:', url);
|
||||||
const res = await fetch(url, {
|
const res = await fetch(url, {
|
||||||
method: 'DELETE',
|
method: 'DELETE',
|
||||||
headers: withPrefer({ ...baseHeaders() }, 'return=minimal'),
|
headers: withPrefer({ ...baseHeaders() }, 'return=minimal'),
|
||||||
});
|
});
|
||||||
|
|
||||||
if (res.status === 204) return;
|
console.log('[deletarExcecao] Status da resposta:', res.status);
|
||||||
if (res.status === 200) return;
|
|
||||||
await parse(res as Response);
|
if (res.status === 204 || res.status === 200) {
|
||||||
|
console.log('[deletarExcecao] Exceção deletada com sucesso');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Se chegou aqui e não foi sucesso, lance erro
|
||||||
|
throw new Error(`Erro ao deletar exceção: ${res.status}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user