forked from RiseUP/riseup-squad21
medicos ordem alfabetica
This commit is contained in:
parent
83bdaed7aa
commit
c41d561dd6
@ -9,15 +9,20 @@ import { AvailabilityService } from "@/services/availabilityApi.mjs";
|
|||||||
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import { Label } from "@/components/ui/label";
|
import { Label } from "@/components/ui/label";
|
||||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
|
import {
|
||||||
|
Select,
|
||||||
|
SelectContent,
|
||||||
|
SelectItem,
|
||||||
|
SelectTrigger,
|
||||||
|
SelectValue,
|
||||||
|
} from "@/components/ui/select";
|
||||||
import { Textarea } from "@/components/ui/textarea";
|
import { Textarea } from "@/components/ui/textarea";
|
||||||
import { Calendar as CalendarShadcn } from "@/components/ui/calendar";
|
import { Calendar as CalendarShadcn } from "@/components/ui/calendar";
|
||||||
import { format, addDays } from "date-fns";
|
import { format, addDays } from "date-fns";
|
||||||
import { User, StickyNote, Calendar } from "lucide-react";
|
import { User, StickyNote, Calendar } from "lucide-react";
|
||||||
import {smsService } from "@/services/Sms.mjs"
|
import { smsService } from "@/services/Sms.mjs";
|
||||||
import { toast } from "@/hooks/use-toast";
|
import { toast } from "@/hooks/use-toast";
|
||||||
|
|
||||||
|
|
||||||
export default function ScheduleForm() {
|
export default function ScheduleForm() {
|
||||||
// Estado do usuário e role
|
// Estado do usuário e role
|
||||||
const [role, setRole] = useState<string>("paciente");
|
const [role, setRole] = useState<string>("paciente");
|
||||||
@ -39,17 +44,32 @@ export default function ScheduleForm() {
|
|||||||
const [tipoConsulta] = useState("presencial");
|
const [tipoConsulta] = useState("presencial");
|
||||||
const [duracao] = useState("30");
|
const [duracao] = useState("30");
|
||||||
const [disponibilidades, setDisponibilidades] = useState<any[]>([]);
|
const [disponibilidades, setDisponibilidades] = useState<any[]>([]);
|
||||||
const [availabilityCounts, setAvailabilityCounts] = useState<Record<string, number>>({});
|
const [availabilityCounts, setAvailabilityCounts] = useState<
|
||||||
const [tooltip, setTooltip] = useState<{ x: number; y: number; text: string } | null>(null);
|
Record<string, number>
|
||||||
|
>({});
|
||||||
|
const [tooltip, setTooltip] = useState<{
|
||||||
|
x: number;
|
||||||
|
y: number;
|
||||||
|
text: string;
|
||||||
|
} | null>(null);
|
||||||
const calendarRef = useRef<HTMLDivElement | null>(null);
|
const calendarRef = useRef<HTMLDivElement | null>(null);
|
||||||
|
|
||||||
// Funções auxiliares
|
// Funções auxiliares
|
||||||
const getWeekdayNumber = (weekday: string) =>
|
const getWeekdayNumber = (weekday: string) =>
|
||||||
["monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday"]
|
[
|
||||||
.indexOf(weekday.toLowerCase()) + 1;
|
"monday",
|
||||||
|
"tuesday",
|
||||||
|
"wednesday",
|
||||||
|
"thursday",
|
||||||
|
"friday",
|
||||||
|
"saturday",
|
||||||
|
"sunday",
|
||||||
|
].indexOf(weekday.toLowerCase()) + 1;
|
||||||
|
|
||||||
const getBrazilDate = (date: Date) =>
|
const getBrazilDate = (date: Date) =>
|
||||||
new Date(Date.UTC(date.getFullYear(), date.getMonth(), date.getDate(), 12, 0, 0));
|
new Date(
|
||||||
|
Date.UTC(date.getFullYear(), date.getMonth(), date.getDate(), 12, 0, 0)
|
||||||
|
);
|
||||||
|
|
||||||
// 🔹 Buscar dados do usuário e role
|
// 🔹 Buscar dados do usuário e role
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -78,7 +98,10 @@ export default function ScheduleForm() {
|
|||||||
setDoctors(data || []);
|
setDoctors(data || []);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error("Erro ao buscar médicos:", err);
|
console.error("Erro ao buscar médicos:", err);
|
||||||
toast({ title: "Erro", description: "Não foi possível carregar médicos." });
|
toast({
|
||||||
|
title: "Erro",
|
||||||
|
description: "Não foi possível carregar médicos.",
|
||||||
|
});
|
||||||
} finally {
|
} finally {
|
||||||
setLoadingDoctors(false);
|
setLoadingDoctors(false);
|
||||||
}
|
}
|
||||||
@ -101,7 +124,10 @@ export default function ScheduleForm() {
|
|||||||
}
|
}
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const computeAvailabilityCountsPreview = async (doctorId: string, dispList: any[]) => {
|
const computeAvailabilityCountsPreview = async (
|
||||||
|
doctorId: string,
|
||||||
|
dispList: any[]
|
||||||
|
) => {
|
||||||
try {
|
try {
|
||||||
const today = new Date();
|
const today = new Date();
|
||||||
const start = format(today, "yyyy-MM-dd");
|
const start = format(today, "yyyy-MM-dd");
|
||||||
@ -123,7 +149,9 @@ export default function ScheduleForm() {
|
|||||||
const d = addDays(today, i);
|
const d = addDays(today, i);
|
||||||
const key = format(d, "yyyy-MM-dd");
|
const key = format(d, "yyyy-MM-dd");
|
||||||
const dayOfWeek = d.getDay() === 0 ? 7 : d.getDay();
|
const dayOfWeek = d.getDay() === 0 ? 7 : d.getDay();
|
||||||
const dailyDisp = dispList.filter((p) => getWeekdayNumber(p.weekday) === dayOfWeek);
|
const dailyDisp = dispList.filter(
|
||||||
|
(p) => getWeekdayNumber(p.weekday) === dayOfWeek
|
||||||
|
);
|
||||||
if (dailyDisp.length === 0) {
|
if (dailyDisp.length === 0) {
|
||||||
counts[key] = 0;
|
counts[key] = 0;
|
||||||
continue;
|
continue;
|
||||||
@ -135,7 +163,8 @@ export default function ScheduleForm() {
|
|||||||
const startMin = sh * 60 + sm;
|
const startMin = sh * 60 + sm;
|
||||||
const endMin = eh * 60 + em;
|
const endMin = eh * 60 + em;
|
||||||
const slot = p.slot_minutes || 30;
|
const slot = p.slot_minutes || 30;
|
||||||
if (endMin >= startMin) possible += Math.floor((endMin - startMin) / slot) + 1;
|
if (endMin >= startMin)
|
||||||
|
possible += Math.floor((endMin - startMin) / slot) + 1;
|
||||||
});
|
});
|
||||||
const occupied = apptsByDate[key] || 0;
|
const occupied = apptsByDate[key] || 0;
|
||||||
counts[key] = Math.max(0, possible - occupied);
|
counts[key] = Math.max(0, possible - occupied);
|
||||||
@ -161,166 +190,175 @@ export default function ScheduleForm() {
|
|||||||
}, [selectedDoctor, loadDoctorDisponibilidades]);
|
}, [selectedDoctor, loadDoctorDisponibilidades]);
|
||||||
|
|
||||||
// 🔹 Buscar horários disponíveis
|
// 🔹 Buscar horários disponíveis
|
||||||
const fetchAvailableSlots = useCallback(async (doctorId: string, date: string) => {
|
const fetchAvailableSlots = useCallback(
|
||||||
if (!doctorId || !date) return;
|
async (doctorId: string, date: string) => {
|
||||||
setLoadingSlots(true);
|
if (!doctorId || !date) return;
|
||||||
setAvailableTimes([]);
|
setLoadingSlots(true);
|
||||||
try {
|
setAvailableTimes([]);
|
||||||
const disponibilidades = await AvailabilityService.listById(doctorId);
|
try {
|
||||||
const consultas = await appointmentsService.search_appointment(
|
const disponibilidades = await AvailabilityService.listById(doctorId);
|
||||||
`doctor_id=eq.${doctorId}&scheduled_at=gte.${date}T00:00:00Z&scheduled_at=lt.${date}T23:59:59Z`
|
const consultas = await appointmentsService.search_appointment(
|
||||||
);
|
`doctor_id=eq.${doctorId}&scheduled_at=gte.${date}T00:00:00Z&scheduled_at=lt.${date}T23:59:59Z`
|
||||||
const diaJS = new Date(date).getDay();
|
);
|
||||||
const diaAPI = diaJS === 0 ? 7 : diaJS;
|
const diaJS = new Date(date).getDay();
|
||||||
const disponibilidadeDia = disponibilidades.find(
|
const diaAPI = diaJS === 0 ? 7 : diaJS;
|
||||||
(d: any) => getWeekdayNumber(d.weekday) === diaAPI
|
const disponibilidadeDia = disponibilidades.find(
|
||||||
);
|
(d: any) => getWeekdayNumber(d.weekday) === diaAPI
|
||||||
if (!disponibilidadeDia) {
|
);
|
||||||
toast({ title: "Nenhuma disponibilidade", description: "Nenhum horário para este dia." });
|
if (!disponibilidadeDia) {
|
||||||
return setAvailableTimes([]);
|
toast({
|
||||||
|
title: "Nenhuma disponibilidade",
|
||||||
|
description: "Nenhum horário para este dia.",
|
||||||
|
});
|
||||||
|
return setAvailableTimes([]);
|
||||||
|
}
|
||||||
|
const [startHour, startMin] = disponibilidadeDia.start_time
|
||||||
|
.split(":")
|
||||||
|
.map(Number);
|
||||||
|
const [endHour, endMin] = disponibilidadeDia.end_time
|
||||||
|
.split(":")
|
||||||
|
.map(Number);
|
||||||
|
const slot = disponibilidadeDia.slot_minutes || 30;
|
||||||
|
const horariosGerados: string[] = [];
|
||||||
|
let atual = new Date(date);
|
||||||
|
atual.setHours(startHour, startMin, 0, 0);
|
||||||
|
const end = new Date(date);
|
||||||
|
end.setHours(endHour, endMin, 0, 0);
|
||||||
|
while (atual <= end) {
|
||||||
|
horariosGerados.push(atual.toTimeString().slice(0, 5));
|
||||||
|
atual = new Date(atual.getTime() + slot * 60000);
|
||||||
|
}
|
||||||
|
const ocupados = (consultas || []).map((c: any) =>
|
||||||
|
String(c.scheduled_at).split("T")[1]?.slice(0, 5)
|
||||||
|
);
|
||||||
|
const livres = horariosGerados.filter((h) => !ocupados.includes(h));
|
||||||
|
setAvailableTimes(livres);
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err);
|
||||||
|
toast({ title: "Erro", description: "Falha ao carregar horários." });
|
||||||
|
} finally {
|
||||||
|
setLoadingSlots(false);
|
||||||
}
|
}
|
||||||
const [startHour, startMin] = disponibilidadeDia.start_time.split(":").map(Number);
|
},
|
||||||
const [endHour, endMin] = disponibilidadeDia.end_time.split(":").map(Number);
|
[]
|
||||||
const slot = disponibilidadeDia.slot_minutes || 30;
|
);
|
||||||
const horariosGerados: string[] = [];
|
|
||||||
let atual = new Date(date);
|
|
||||||
atual.setHours(startHour, startMin, 0, 0);
|
|
||||||
const end = new Date(date);
|
|
||||||
end.setHours(endHour, endMin, 0, 0);
|
|
||||||
while (atual <= end) {
|
|
||||||
horariosGerados.push(atual.toTimeString().slice(0, 5));
|
|
||||||
atual = new Date(atual.getTime() + slot * 60000);
|
|
||||||
}
|
|
||||||
const ocupados = (consultas || []).map((c: any) =>
|
|
||||||
String(c.scheduled_at).split("T")[1]?.slice(0, 5)
|
|
||||||
);
|
|
||||||
const livres = horariosGerados.filter((h) => !ocupados.includes(h));
|
|
||||||
setAvailableTimes(livres);
|
|
||||||
} catch (err) {
|
|
||||||
console.error(err);
|
|
||||||
toast({ title: "Erro", description: "Falha ao carregar horários." });
|
|
||||||
} finally {
|
|
||||||
setLoadingSlots(false);
|
|
||||||
}
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (selectedDoctor && selectedDate) fetchAvailableSlots(selectedDoctor, selectedDate);
|
if (selectedDoctor && selectedDate)
|
||||||
|
fetchAvailableSlots(selectedDoctor, selectedDate);
|
||||||
}, [selectedDoctor, selectedDate, fetchAvailableSlots]);
|
}, [selectedDoctor, selectedDate, fetchAvailableSlots]);
|
||||||
|
|
||||||
// 🔹 Submeter agendamento
|
// 🔹 Submeter agendamento
|
||||||
// 🔹 Submeter agendamento
|
// 🔹 Submeter agendamento
|
||||||
// 🔹 Submeter agendamento
|
// 🔹 Submeter agendamento
|
||||||
// 🔹 Submeter agendamento
|
// 🔹 Submeter agendamento
|
||||||
// 🔹 Submeter agendamento
|
// 🔹 Submeter agendamento
|
||||||
const handleSubmit = async (e: React.FormEvent) => {
|
const handleSubmit = async (e: React.FormEvent) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
const isSecretaryLike = ["secretaria", "admin", "gestor"].includes(role);
|
const isSecretaryLike = ["secretaria", "admin", "gestor"].includes(role);
|
||||||
const patientId = isSecretaryLike ? selectedPatient : userId;
|
const patientId = isSecretaryLike ? selectedPatient : userId;
|
||||||
|
|
||||||
if (!patientId || !selectedDoctor || !selectedDate || !selectedTime) {
|
if (!patientId || !selectedDoctor || !selectedDate || !selectedTime) {
|
||||||
toast({ title: "Campos obrigatórios", description: "Preencha todos os campos." });
|
toast({
|
||||||
return;
|
title: "Campos obrigatórios",
|
||||||
}
|
description: "Preencha todos os campos.",
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const body = {
|
const body = {
|
||||||
doctor_id: selectedDoctor,
|
doctor_id: selectedDoctor,
|
||||||
patient_id: patientId,
|
patient_id: patientId,
|
||||||
scheduled_at: `${selectedDate}T${selectedTime}:00`,
|
scheduled_at: `${selectedDate}T${selectedTime}:00`,
|
||||||
duration_minutes: Number(duracao),
|
duration_minutes: Number(duracao),
|
||||||
notes,
|
notes,
|
||||||
appointment_type: tipoConsulta,
|
appointment_type: tipoConsulta,
|
||||||
};
|
};
|
||||||
|
|
||||||
// ✅ mantém o fluxo original de criação (funcional)
|
// ✅ mantém o fluxo original de criação (funcional)
|
||||||
await appointmentsService.create(body);
|
await appointmentsService.create(body);
|
||||||
|
|
||||||
const dateFormatted = selectedDate.split("-").reverse().join("/");
|
const dateFormatted = selectedDate.split("-").reverse().join("/");
|
||||||
|
|
||||||
toast({
|
toast({
|
||||||
title: "Consulta agendada!",
|
title: "Consulta agendada!",
|
||||||
description: `Consulta marcada para ${dateFormatted} às ${selectedTime} com o(a) médico(a) ${
|
description: `Consulta marcada para ${dateFormatted} às ${selectedTime} com o(a) médico(a) ${
|
||||||
doctors.find((d) => d.id === selectedDoctor)?.full_name || ""
|
doctors.find((d) => d.id === selectedDoctor)?.full_name || ""
|
||||||
}.`,
|
}.`,
|
||||||
});
|
});
|
||||||
|
|
||||||
let phoneNumber = "+5511999999999"; // fallback
|
let phoneNumber = "+5511999999999"; // fallback
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (isSecretaryLike) {
|
if (isSecretaryLike) {
|
||||||
// Secretária/admin → telefone do paciente selecionado
|
// Secretária/admin → telefone do paciente selecionado
|
||||||
const patient = patients.find((p: any) => p.id === patientId);
|
const patient = patients.find((p: any) => p.id === patientId);
|
||||||
|
|
||||||
// Pacientes criados no sistema podem ter phone ou phone_mobile
|
// Pacientes criados no sistema podem ter phone ou phone_mobile
|
||||||
const rawPhone = patient?.phone || patient?.phone_mobile || null;
|
const rawPhone = patient?.phone || patient?.phone_mobile || null;
|
||||||
|
|
||||||
if (rawPhone) phoneNumber = rawPhone;
|
if (rawPhone) phoneNumber = rawPhone;
|
||||||
} else {
|
} else {
|
||||||
// Paciente → telefone vem do perfil do próprio usuário logado
|
// Paciente → telefone vem do perfil do próprio usuário logado
|
||||||
const me = await usersService.getMe();
|
const me = await usersService.getMe();
|
||||||
|
|
||||||
|
const rawPhone =
|
||||||
const rawPhone =
|
me?.profile?.phone ||
|
||||||
me?.profile?.phone ||
|
(typeof me?.profile === "object" && "phone_mobile" in me.profile
|
||||||
(typeof me?.profile === "object" && "phone_mobile" in me.profile ? (me.profile as any).phone_mobile : null) ||
|
? (me.profile as any).phone_mobile
|
||||||
(typeof me === "object" && "user_metadata" in me ? (me as any).user_metadata?.phone : null) ||
|
: null) ||
|
||||||
null;
|
(typeof me === "object" && "user_metadata" in me
|
||||||
|
? (me as any).user_metadata?.phone
|
||||||
|
: null) ||
|
||||||
|
null;
|
||||||
|
|
||||||
if (rawPhone) phoneNumber = rawPhone;
|
if (rawPhone) phoneNumber = rawPhone;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 🔹 Normaliza para formato internacional (+55)
|
// 🔹 Normaliza para formato internacional (+55)
|
||||||
if (phoneNumber) {
|
if (phoneNumber) {
|
||||||
phoneNumber = phoneNumber.replace(/\D/g, "");
|
phoneNumber = phoneNumber.replace(/\D/g, "");
|
||||||
if (!phoneNumber.startsWith("55")) phoneNumber = `55${phoneNumber}`;
|
if (!phoneNumber.startsWith("55")) phoneNumber = `55${phoneNumber}`;
|
||||||
phoneNumber = `+${phoneNumber}`;
|
phoneNumber = `+${phoneNumber}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log("📞 Telefone usado:", phoneNumber);
|
|
||||||
} catch (err) {
|
|
||||||
console.warn("⚠️ Não foi possível obter telefone do paciente:", err);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// 💬 envia o SMS de confirmação
|
|
||||||
// 💬 Envia o SMS de lembrete (sem mostrar nada ao paciente)
|
|
||||||
// 💬 Envia o SMS de lembrete (somente loga no console, não mostra no sistema)
|
|
||||||
try {
|
|
||||||
const smsRes = await smsService.sendSms({
|
|
||||||
phone_number: phoneNumber,
|
|
||||||
message: `Lembrete: sua consulta é em ${dateFormatted} às ${selectedTime} na Clínica MediConnect.`,
|
|
||||||
patient_id: patientId,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (smsRes?.success) {
|
|
||||||
console.log("✅ SMS enviado com sucesso:", smsRes.message_sid);
|
|
||||||
} else {
|
|
||||||
console.warn("⚠️ Falha no envio do SMS:", smsRes);
|
|
||||||
}
|
|
||||||
} catch (smsErr) {
|
|
||||||
console.error("❌ Erro ao enviar SMS:", smsErr);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// 🧹 limpa os campos
|
|
||||||
setSelectedDoctor("");
|
|
||||||
setSelectedDate("");
|
|
||||||
setSelectedTime("");
|
|
||||||
setNotes("");
|
|
||||||
setSelectedPatient("");
|
|
||||||
} catch (err) {
|
|
||||||
console.error("❌ Erro ao agendar consulta:", err);
|
|
||||||
toast({ title: "Erro", description: "Falha ao agendar consulta." });
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
console.log("📞 Telefone usado:", phoneNumber);
|
||||||
|
} catch (err) {
|
||||||
|
console.warn("⚠️ Não foi possível obter telefone do paciente:", err);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 💬 envia o SMS de confirmação
|
||||||
|
// 💬 Envia o SMS de lembrete (sem mostrar nada ao paciente)
|
||||||
|
// 💬 Envia o SMS de lembrete (somente loga no console, não mostra no sistema)
|
||||||
|
try {
|
||||||
|
const smsRes = await smsService.sendSms({
|
||||||
|
phone_number: phoneNumber,
|
||||||
|
message: `Lembrete: sua consulta é em ${dateFormatted} às ${selectedTime} na Clínica MediConnect.`,
|
||||||
|
patient_id: patientId,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (smsRes?.success) {
|
||||||
|
console.log("✅ SMS enviado com sucesso:", smsRes.message_sid);
|
||||||
|
} else {
|
||||||
|
console.warn("⚠️ Falha no envio do SMS:", smsRes);
|
||||||
|
}
|
||||||
|
} catch (smsErr) {
|
||||||
|
console.error("❌ Erro ao enviar SMS:", smsErr);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 🧹 limpa os campos
|
||||||
|
setSelectedDoctor("");
|
||||||
|
setSelectedDate("");
|
||||||
|
setSelectedTime("");
|
||||||
|
setNotes("");
|
||||||
|
setSelectedPatient("");
|
||||||
|
} catch (err) {
|
||||||
|
console.error("❌ Erro ao agendar consulta:", err);
|
||||||
|
toast({ title: "Erro", description: "Falha ao agendar consulta." });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// 🔹 Tooltip no calendário
|
// 🔹 Tooltip no calendário
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -359,19 +397,27 @@ try {
|
|||||||
<CardTitle>Dados da Consulta</CardTitle>
|
<CardTitle>Dados da Consulta</CardTitle>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent>
|
<CardContent>
|
||||||
<form onSubmit={handleSubmit} className="grid grid-cols-1 lg:grid-cols-2 gap-6">
|
<form
|
||||||
|
onSubmit={handleSubmit}
|
||||||
|
className="grid grid-cols-1 lg:grid-cols-2 gap-6"
|
||||||
|
>
|
||||||
<div className="space-y-3">
|
<div className="space-y-3">
|
||||||
{/* Se secretária/gestor/admin → mostrar campo Paciente */}
|
{/* Se secretária/gestor/admin → mostrar campo Paciente */}
|
||||||
{["secretaria", "gestor", "admin"].includes(role) && (
|
{["secretaria", "gestor", "admin"].includes(role) && (
|
||||||
<div>
|
<div>
|
||||||
<Label>Paciente</Label>
|
<Label>Paciente</Label>
|
||||||
<Select value={selectedPatient} onValueChange={setSelectedPatient}>
|
<Select
|
||||||
|
value={selectedPatient}
|
||||||
|
onValueChange={setSelectedPatient}
|
||||||
|
>
|
||||||
<SelectTrigger>
|
<SelectTrigger>
|
||||||
<SelectValue placeholder="Selecione o paciente" />
|
<SelectValue placeholder="Selecione o paciente" />
|
||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
<SelectContent>
|
<SelectContent>
|
||||||
{patients.map((p) => (
|
{patients.map((p) => (
|
||||||
<SelectItem key={p.id} value={p.id}>{p.full_name}</SelectItem>
|
<SelectItem key={p.id} value={p.id}>
|
||||||
|
{p.full_name}
|
||||||
|
</SelectItem>
|
||||||
))}
|
))}
|
||||||
</SelectContent>
|
</SelectContent>
|
||||||
</Select>
|
</Select>
|
||||||
@ -380,19 +426,28 @@ try {
|
|||||||
|
|
||||||
<div>
|
<div>
|
||||||
<Label>Médico</Label>
|
<Label>Médico</Label>
|
||||||
<Select value={selectedDoctor} onValueChange={setSelectedDoctor}>
|
<Select
|
||||||
|
value={selectedDoctor}
|
||||||
|
onValueChange={setSelectedDoctor}
|
||||||
|
>
|
||||||
<SelectTrigger>
|
<SelectTrigger>
|
||||||
<SelectValue placeholder="Selecione o médico" />
|
<SelectValue placeholder="Selecione o médico" />
|
||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
<SelectContent>
|
<SelectContent>
|
||||||
{loadingDoctors ? (
|
{loadingDoctors ? (
|
||||||
<SelectItem value="loading" disabled>Carregando...</SelectItem>
|
<SelectItem value="loading" disabled>
|
||||||
|
Carregando...
|
||||||
|
</SelectItem>
|
||||||
) : (
|
) : (
|
||||||
doctors.map((d) => (
|
[...doctors]
|
||||||
<SelectItem key={d.id} value={d.id}>
|
.sort((a, b) =>
|
||||||
{d.full_name} — {d.specialty}
|
String(a.full_name).localeCompare(String(b.full_name))
|
||||||
</SelectItem>
|
)
|
||||||
))
|
.map((d) => (
|
||||||
|
<SelectItem key={d.id} value={d.id}>
|
||||||
|
{d.full_name} — {d.specialty}
|
||||||
|
</SelectItem>
|
||||||
|
))
|
||||||
)}
|
)}
|
||||||
</SelectContent>
|
</SelectContent>
|
||||||
</Select>
|
</Select>
|
||||||
@ -404,10 +459,17 @@ try {
|
|||||||
<CalendarShadcn
|
<CalendarShadcn
|
||||||
mode="single"
|
mode="single"
|
||||||
disabled={!selectedDoctor}
|
disabled={!selectedDoctor}
|
||||||
selected={selectedDate ? new Date(selectedDate + "T12:00:00") : undefined}
|
selected={
|
||||||
|
selectedDate
|
||||||
|
? new Date(selectedDate + "T12:00:00")
|
||||||
|
: undefined
|
||||||
|
}
|
||||||
onSelect={(date) => {
|
onSelect={(date) => {
|
||||||
if (!date) return;
|
if (!date) return;
|
||||||
const formatted = format(new Date(date.getTime() + 12 * 60 * 60 * 1000), "yyyy-MM-dd");
|
const formatted = format(
|
||||||
|
new Date(date.getTime() + 12 * 60 * 60 * 1000),
|
||||||
|
"yyyy-MM-dd"
|
||||||
|
);
|
||||||
setSelectedDate(formatted);
|
setSelectedDate(formatted);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
@ -436,7 +498,8 @@ try {
|
|||||||
<User className="h-4 w-4 text-blue-600" />
|
<User className="h-4 w-4 text-blue-600" />
|
||||||
<div className="text-xs">
|
<div className="text-xs">
|
||||||
{selectedDoctor
|
{selectedDoctor
|
||||||
? doctors.find((d) => d.id === selectedDoctor)?.full_name
|
? doctors.find((d) => d.id === selectedDoctor)
|
||||||
|
?.full_name
|
||||||
: "Médico"}
|
: "Médico"}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -447,7 +510,10 @@ try {
|
|||||||
|
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<Label>Horário</Label>
|
<Label>Horário</Label>
|
||||||
<Select onValueChange={setSelectedTime} disabled={loadingSlots || availableTimes.length === 0}>
|
<Select
|
||||||
|
onValueChange={setSelectedTime}
|
||||||
|
disabled={loadingSlots || availableTimes.length === 0}
|
||||||
|
>
|
||||||
<SelectTrigger>
|
<SelectTrigger>
|
||||||
<SelectValue
|
<SelectValue
|
||||||
placeholder={
|
placeholder={
|
||||||
@ -461,7 +527,9 @@ try {
|
|||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
<SelectContent>
|
<SelectContent>
|
||||||
{availableTimes.map((h) => (
|
{availableTimes.map((h) => (
|
||||||
<SelectItem key={h} value={h}>{h}</SelectItem>
|
<SelectItem key={h} value={h}>
|
||||||
|
{h}
|
||||||
|
</SelectItem>
|
||||||
))}
|
))}
|
||||||
</SelectContent>
|
</SelectContent>
|
||||||
</Select>
|
</Select>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user