2025-10-21 13:02:56 -03:00

419 lines
15 KiB
TypeScript

import React, { useEffect, useState } from "react";
import {
Card,
CardContent,
CardHeader,
CardTitle,
CardDescription,
} from "./MetricCard";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@/components/ui/select";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import { Calendar } from "@/components/ui/calendar";
import { Textarea } from "@/components/ui/textarea";
import {
Dialog,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
} from "@/components/ui/dialog";
import { ENDPOINTS } from "../services/endpoints";
import api from "../services/api";
// Adapte conforme o seu projeto
const months = [
"Janeiro",
"Fevereiro",
"Março",
"Abril",
"Maio",
"Junho",
"Julho",
"Agosto",
"Setembro",
"Outubro",
"Novembro",
"Dezembro",
];
const currentYear = new Date().getFullYear();
const years = Array.from({ length: 10 }, (_, i) => currentYear - 2 + i);
export default function BookAppointment() {
const [doctors, setDoctors] = useState<any[]>([]);
const [searchTerm, setSearchTerm] = useState("");
const [selectedSpecialty, setSelectedSpecialty] = useState("all");
const [selectedDate, setSelectedDate] = useState<Date | undefined>(
new Date()
);
const [currentMonth, setCurrentMonth] = useState(new Date());
const [selectedDoctor, setSelectedDoctor] = useState<any | null>(null);
const [selectedTime, setSelectedTime] = useState("");
const [appointmentType, setAppointmentType] = useState<
"presential" | "online"
>("presential");
const [showConfirmDialog, setShowConfirmDialog] = useState(false);
const [reason, setReason] = useState("");
const [loading, setLoading] = useState(false);
useEffect(() => {
// Busca médicos da API
api
.get(ENDPOINTS.DOCTORS)
.then((res) => setDoctors(res.data))
.catch(() => setDoctors([]));
}, []);
const filteredDoctors = doctors.filter((doctor) => {
const matchesSearch =
doctor.name?.toLowerCase().includes(searchTerm.toLowerCase()) ||
doctor.specialty?.toLowerCase().includes(searchTerm.toLowerCase());
const matchesSpecialty =
selectedSpecialty === "all" || doctor.specialty === selectedSpecialty;
return matchesSearch && matchesSpecialty;
});
const handleBookAppointment = () => {
if (selectedDoctor && selectedTime) {
setShowConfirmDialog(true);
}
};
const confirmAppointment = async () => {
if (!selectedDoctor || !selectedTime || !selectedDate) return;
setLoading(true);
try {
await api.post(ENDPOINTS.APPOINTMENTS, {
doctor_id: selectedDoctor.id,
date: selectedDate.toISOString().split("T")[0],
time: selectedTime,
type: appointmentType,
reason,
});
alert("Agendamento realizado com sucesso!");
setShowConfirmDialog(false);
setSelectedDoctor(null);
setSelectedTime("");
setReason("");
} catch (e) {
alert("Erro ao agendar consulta");
} finally {
setLoading(false);
}
};
const handleMonthChange = (month: string) => {
const newDate = new Date(currentMonth.getFullYear(), Number(month));
setCurrentMonth(newDate);
};
const handleYearChange = (year: string) => {
const newDate = new Date(Number(year), currentMonth.getMonth());
setCurrentMonth(newDate);
};
return (
<div className="space-y-6">
<div>
<h1>Agendar Consulta</h1>
<p className="text-muted-foreground">
Escolha um médico e horário disponível
</p>
</div>
<Card>
<CardHeader>
<CardTitle>Buscar Médicos</CardTitle>
</CardHeader>
<CardContent className="space-y-4">
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div className="space-y-2">
<Label>Buscar por nome ou especialidade</Label>
<Input
placeholder="Ex: Cardiologia, Dr. Silva..."
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
/>
</div>
<div className="space-y-2">
<Label>Especialidade</Label>
<Select
value={selectedSpecialty}
onValueChange={setSelectedSpecialty}
>
<SelectTrigger>
<SelectValue placeholder="Todas as especialidades" />
</SelectTrigger>
<SelectContent>
<SelectItem value="all">Todas as especialidades</SelectItem>
{/* Adapte para especialidades reais */}
<SelectItem value="Cardiologia">Cardiologia</SelectItem>
<SelectItem value="Dermatologia">Dermatologia</SelectItem>
<SelectItem value="Ortopedia">Ortopedia</SelectItem>
<SelectItem value="Pediatria">Pediatria</SelectItem>
<SelectItem value="Ginecologia">Ginecologia</SelectItem>
</SelectContent>
</Select>
</div>
</div>
</CardContent>
</Card>
<div className="grid grid-cols-1 lg:grid-cols-2 gap-4">
{filteredDoctors.map((doctor) => (
<Card
key={doctor.id}
className={selectedDoctor?.id === doctor.id ? "border-primary" : ""}
>
<CardContent className="pt-6">
<div className="flex gap-4">
{/* Adapte para seu componente de avatar */}
<div className="h-16 w-16 rounded-full bg-gray-200 flex items-center justify-center">
{doctor.name
?.split(" ")
.map((n: string) => n[0])
.join("")}
</div>
<div className="flex-1 space-y-2">
<div>
<h3>{doctor.name}</h3>
<p className="text-muted-foreground">{doctor.specialty}</p>
</div>
<div className="flex items-center gap-4 text-muted-foreground">
<div className="flex items-center gap-1">
<span>{doctor.rating || "-"}</span>
</div>
<div className="flex items-center gap-1">
<span>{doctor.location || "-"}</span>
</div>
</div>
<div className="flex items-center justify-between">
<span className="text-foreground">
{doctor.price || "-"}
</span>
<div className="flex gap-2">
<Button
size="sm"
variant="outline"
onClick={() => setSelectedDoctor(doctor)}
>
Ver Agenda
</Button>
<Button
size="sm"
variant={
selectedDoctor?.id === doctor.id
? "default"
: "outline"
}
onClick={() => setSelectedDoctor(doctor)}
>
{selectedDoctor?.id === doctor.id
? "Selecionado"
: "Selecionar"}
</Button>
</div>
</div>
</div>
</div>
</CardContent>
</Card>
))}
</div>
{selectedDoctor && (
<Card>
<CardHeader>
<CardTitle>Detalhes do Agendamento</CardTitle>
<CardDescription>
Consulta com {selectedDoctor.name} - {selectedDoctor.specialty}
</CardDescription>
</CardHeader>
<CardContent className="space-y-6">
<Tabs
value={appointmentType}
onValueChange={(v) =>
setAppointmentType(v as "presential" | "online")
}
>
<TabsList className="grid w-full grid-cols-2">
<TabsTrigger value="presential">Presencial</TabsTrigger>
<TabsTrigger value="online">Online</TabsTrigger>
</TabsList>
</Tabs>
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
<div className="space-y-4">
<div className="flex items-center gap-2">
<Select
value={String(currentMonth.getMonth())}
onValueChange={handleMonthChange}
>
<SelectTrigger className="w-[130px]">
<SelectValue />
</SelectTrigger>
<SelectContent>
{months.map((month, index) => (
<SelectItem key={index} value={String(index)}>
{month}
</SelectItem>
))}
</SelectContent>
</Select>
<Select
value={String(currentMonth.getFullYear())}
onValueChange={handleYearChange}
>
<SelectTrigger className="w-[90px]">
<SelectValue />
</SelectTrigger>
<SelectContent>
{years.map((year) => (
<SelectItem key={year} value={String(year)}>
{year}
</SelectItem>
))}
</SelectContent>
</Select>
</div>
<Calendar
mode="single"
selected={selectedDate}
onSelect={setSelectedDate}
month={currentMonth}
onMonthChange={setCurrentMonth}
className="rounded-md border w-full"
disabled={(date) =>
date < new Date() ||
date.getDay() === 0 ||
date.getDay() === 6
}
/>
<p className="text-muted-foreground">
🔴 Finais de semana não disponíveis
</p>
</div>
<div className="space-y-4">
<div>
<div className="mb-3">
<Label>Horários Disponíveis</Label>
<p className="text-muted-foreground">
{selectedDate?.toLocaleDateString("pt-BR", {
weekday: "long",
day: "numeric",
month: "long",
year: "numeric",
})}
</p>
</div>
{/* Adapte para buscar horários reais da API se disponível */}
<div className="grid grid-cols-3 gap-2">
{["09:00", "10:00", "14:00", "15:00", "16:00"].map(
(slot) => (
<Button
key={slot}
variant={
selectedTime === slot ? "default" : "outline"
}
size="sm"
onClick={() => setSelectedTime(slot)}
>
{slot}
</Button>
)
)}
</div>
</div>
<div className="space-y-2">
<Label>Motivo da Consulta</Label>
<Textarea
placeholder="Descreva brevemente o motivo da consulta..."
value={reason}
onChange={(e) => setReason(e.target.value)}
rows={4}
/>
</div>
<div className="p-4 bg-accent rounded-lg space-y-2">
<h4>Resumo</h4>
<div className="space-y-1 text-muted-foreground">
<p>Data: {selectedDate?.toLocaleDateString("pt-BR")}</p>
<p>Horário: {selectedTime || "Não selecionado"}</p>
<p>
Tipo:{" "}
{appointmentType === "online" ? "Online" : "Presencial"}
</p>
<p>Valor: {selectedDoctor.price || "-"}</p>
</div>
</div>
<Button
className="w-full"
disabled={!selectedTime || !reason || loading}
onClick={handleBookAppointment}
>
Confirmar Agendamento
</Button>
</div>
</div>
</CardContent>
</Card>
)}
<Dialog open={showConfirmDialog} onOpenChange={setShowConfirmDialog}>
<DialogContent>
<DialogHeader>
<DialogTitle>Confirmar Agendamento</DialogTitle>
<DialogDescription>
Revise os detalhes da sua consulta antes de confirmar
</DialogDescription>
</DialogHeader>
<div className="space-y-4">
<div className="flex items-center gap-3">
<div className="h-12 w-12 rounded-full bg-gray-200 flex items-center justify-center">
{selectedDoctor?.name
?.split(" ")
.map((n: string) => n[0])
.join("")}
</div>
<div>
<p className="text-foreground">{selectedDoctor?.name}</p>
<p className="text-muted-foreground">
{selectedDoctor?.specialty}
</p>
</div>
</div>
<div className="space-y-2 text-muted-foreground">
<p>📅 Data: {selectedDate?.toLocaleDateString("pt-BR")}</p>
<p> Horário: {selectedTime}</p>
<p>
📍 Tipo:{" "}
{appointmentType === "online"
? "Consulta Online"
: "Consulta Presencial"}
</p>
<p>💰 Valor: {selectedDoctor?.price || "-"}</p>
<div className="mt-4">
<p className="text-foreground">Motivo:</p>
<p>{reason}</p>
</div>
</div>
</div>
<DialogFooter>
<Button
variant="outline"
onClick={() => setShowConfirmDialog(false)}
>
Cancelar
</Button>
<Button onClick={confirmAppointment} disabled={loading}>
{loading ? "Agendando..." : "Confirmar"}
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
</div>
);
}