commit
883411b8a3
@ -144,10 +144,6 @@ export default function EditarLaudoPage() {
|
||||
<CardContent>
|
||||
<form onSubmit={handleSubmit} className="space-y-6">
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="order_number">Nº do Pedido</Label>
|
||||
<Input id="order_number" value={formData.order_number || ''} onChange={handleInputChange} />
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="exam">Exame</Label>
|
||||
<Input id="exam" value={formData.exam || ''} onChange={handleInputChange} />
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
|
||||
"use client";
|
||||
"use client";
|
||||
|
||||
import { useParams, useRouter } from "next/navigation";
|
||||
import { useState } from "react";
|
||||
@ -106,10 +105,6 @@ export default function NovoLaudoPage() {
|
||||
<CardContent>
|
||||
<form onSubmit={handleSubmit} className="space-y-6">
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="order_number">Nº do Pedido</Label>
|
||||
<Input id="order_number" value={formData.order_number} onChange={handleInputChange} />
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="exam">Exame</Label>
|
||||
<Input id="exam" value={formData.exam} onChange={handleInputChange} />
|
||||
|
||||
@ -8,7 +8,7 @@ import {
|
||||
DropdownMenuItem,
|
||||
DropdownMenuTrigger,
|
||||
} from "@/components/ui/dropdown-menu";
|
||||
import { Eye, Edit, Calendar, Trash2, Loader2 } from "lucide-react";
|
||||
import { Eye, Edit, Calendar, Trash2, Loader2, MoreVertical } from "lucide-react";
|
||||
import { api } from "@/services/api.mjs";
|
||||
import { PatientDetailsModal } from "@/components/ui/patient-details-modal";
|
||||
import {
|
||||
@ -283,9 +283,10 @@ export default function PacientesPage() {
|
||||
<td className="p-3 sm:p-4">
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<button className="text-primary hover:underline text-sm sm:text-base">
|
||||
Ações
|
||||
</button>
|
||||
<Button variant="ghost" className="h-8 w-8 p-0">
|
||||
<span className="sr-only">Abrir menu</span>
|
||||
<MoreVertical className="h-4 w-4" />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="end">
|
||||
<DropdownMenuItem
|
||||
@ -295,19 +296,11 @@ export default function PacientesPage() {
|
||||
Ver detalhes
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem asChild>
|
||||
<Link href={`/doctor/pacientes/${p.id}/laudos`}>
|
||||
<Link href={`/doctor/medicos/${p.id}/laudos`}>
|
||||
<Edit className="w-4 h-4 mr-2" />
|
||||
Laudos
|
||||
</Link>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem
|
||||
onClick={() =>
|
||||
alert(`Agenda para paciente ID: ${p.id}`)
|
||||
}
|
||||
>
|
||||
<Calendar className="w-4 h-4 mr-2" />
|
||||
Ver agenda
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem
|
||||
onClick={() => {
|
||||
const newPacientes = pacientes.filter(
|
||||
|
||||
@ -6,7 +6,7 @@ import { useRouter } from "next/navigation";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "@/components/ui/dropdown-menu";
|
||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
|
||||
import { Edit, Trash2, Eye, Calendar, Loader2 } from "lucide-react";
|
||||
import { Edit, Trash2, Eye, Calendar, Loader2, MoreVertical } from "lucide-react";
|
||||
import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle } from "@/components/ui/alert-dialog";
|
||||
|
||||
// Imports dos Serviços
|
||||
@ -326,7 +326,9 @@ export default function DoctorsPage() {
|
||||
<td className="px-4 py-3 text-right">
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<div className="text-blue-600 cursor-pointer inline-block hover:underline">Ações</div>
|
||||
<div className="text-black-600 cursor-pointer inline-block">
|
||||
<MoreVertical className="h-4 w-4" />
|
||||
</div>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="end">
|
||||
<DropdownMenuItem onClick={() => openDetailsDialog(doctor)}>
|
||||
|
||||
@ -3,30 +3,10 @@
|
||||
import { useState, useEffect, useCallback } from "react";
|
||||
import Link from "next/link";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuTrigger,
|
||||
} from "@/components/ui/dropdown-menu";
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "@/components/ui/select";
|
||||
import { Edit, Trash2, Eye, Calendar, Filter, Loader2 } from "lucide-react";
|
||||
import {
|
||||
AlertDialog,
|
||||
AlertDialogAction,
|
||||
AlertDialogCancel,
|
||||
AlertDialogContent,
|
||||
AlertDialogDescription,
|
||||
AlertDialogFooter,
|
||||
AlertDialogHeader,
|
||||
AlertDialogTitle,
|
||||
} from "@/components/ui/alert-dialog";
|
||||
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "@/components/ui/dropdown-menu";
|
||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
|
||||
import { Plus, Edit, Trash2, Eye, Calendar, Filter, Loader2, MoreVertical } from "lucide-react";
|
||||
import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle } from "@/components/ui/alert-dialog";
|
||||
import { patientsService } from "@/services/patientsApi.mjs";
|
||||
import Sidebar from "@/components/Sidebar";
|
||||
|
||||
@ -291,107 +271,39 @@ export default function PacientesPage() {
|
||||
<td className="p-4">
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<div className="text-blue-600 cursor-pointer">Ações</div>
|
||||
<div className="text-black-600 cursor-pointer">
|
||||
<MoreVertical className="h-4 w-4" />
|
||||
</div>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="end">
|
||||
<DropdownMenuItem onClick={() => openDetailsDialog(String(patient.id))}>
|
||||
<Eye className="w-4 h-4 mr-2" />
|
||||
Ver detalhes
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem asChild>
|
||||
<Link href={`/secretary/pacientes/${patient.id}/editar`} className="flex items-center w-full">
|
||||
<Edit className="w-4 h-4 mr-2" />
|
||||
Editar
|
||||
</Link>
|
||||
</DropdownMenuItem>
|
||||
|
||||
<DropdownMenuItem asChild>
|
||||
<Link
|
||||
href={`/secretary/pacientes/${patient.id}/editar`}
|
||||
className="flex items-center w-full"
|
||||
>
|
||||
<Edit className="w-4 h-4 mr-2" />
|
||||
Editar
|
||||
</Link>
|
||||
</DropdownMenuItem>
|
||||
|
||||
<DropdownMenuItem>
|
||||
<Calendar className="w-4 h-4 mr-2" />
|
||||
Marcar consulta
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem
|
||||
className="text-red-600"
|
||||
onClick={() =>
|
||||
openDeleteDialog(String(patient.id))
|
||||
}
|
||||
>
|
||||
<Trash2 className="w-4 h-4 mr-2" />
|
||||
Excluir
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</td>
|
||||
</tr>
|
||||
))
|
||||
)}
|
||||
</tbody>
|
||||
</table>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* --- SEÇÃO DE CARDS (VISÍVEL APENAS EM TELAS MENORES QUE MD) --- */}
|
||||
{/* Garantir que os cards apareçam em telas menores e se escondam em MD+ */}
|
||||
<div className="bg-white rounded-lg border border-gray-200 shadow-md p-4 block md:hidden">
|
||||
{error ? (
|
||||
<div className="p-6 text-red-600">{`Erro ao carregar pacientes: ${error}`}</div>
|
||||
) : loading ? (
|
||||
<div className="p-6 text-center text-gray-500 flex items-center justify-center">
|
||||
<Loader2 className="w-6 h-6 mr-2 animate-spin text-green-600" /> Carregando pacientes...
|
||||
</div>
|
||||
) : filteredPatients.length === 0 ? (
|
||||
<div className="p-8 text-center text-gray-500">
|
||||
{allPatients.length === 0 ? "Nenhum paciente cadastrado" : "Nenhum paciente encontrado com os filtros aplicados"}
|
||||
</div>
|
||||
) : (
|
||||
<div className="space-y-4">
|
||||
{currentPatients.map((patient) => (
|
||||
<div key={patient.id} className="bg-gray-50 rounded-lg p-4 flex flex-col sm:flex-row justify-between items-start sm:items-center border border-gray-200">
|
||||
<div className="flex-grow mb-2 sm:mb-0">
|
||||
<div className="font-semibold text-lg text-gray-900 flex items-center">
|
||||
{patient.nome}
|
||||
{patient.vip && (
|
||||
<span className="ml-2 px-2 py-0.5 text-xs font-semibold text-purple-600 bg-purple-100 rounded-full">VIP</span>
|
||||
)}
|
||||
</div>
|
||||
<div className="text-sm text-gray-600">Telefone: {patient.telefone}</div>
|
||||
<div className="text-sm text-gray-600">Convênio: {patient.convenio}</div>
|
||||
</div>
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<div className="w-full"><Button variant="outline" className="w-full">Ações</Button></div>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="end">
|
||||
<DropdownMenuItem onClick={() => openDetailsDialog(String(patient.id))}>
|
||||
<Eye className="w-4 h-4 mr-2" />
|
||||
Ver detalhes
|
||||
</DropdownMenuItem>
|
||||
|
||||
<DropdownMenuItem asChild>
|
||||
<Link href={`/secretary/pacientes/${patient.id}/editar`} className="flex items-center w-full">
|
||||
<Edit className="w-4 h-4 mr-2" />
|
||||
Editar
|
||||
</Link>
|
||||
</DropdownMenuItem>
|
||||
|
||||
<DropdownMenuItem>
|
||||
<Calendar className="w-4 h-4 mr-2" />
|
||||
Marcar consulta
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem className="text-red-600" onClick={() => openDeleteDialog(String(patient.id))}>
|
||||
<Trash2 className="w-4 h-4 mr-2" />
|
||||
Excluir
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
<DropdownMenuItem>
|
||||
<Calendar className="w-4 h-4 mr-2" />
|
||||
Marcar consulta
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem className="text-red-600" onClick={() => openDeleteDialog(String(patient.id))}>
|
||||
<Trash2 className="w-4 h-4 mr-2" />
|
||||
Excluir
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</td>
|
||||
</tr>
|
||||
)))}
|
||||
</tbody>
|
||||
</table>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Paginação */}
|
||||
|
||||
@ -283,33 +283,24 @@ export default function SecretaryAppointments() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex gap-2 mt-4 pt-4 border-t">
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={() => handleEdit(appointment)}
|
||||
>
|
||||
<Pencil className="mr-2 h-4 w-4" />
|
||||
Editar
|
||||
</Button>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
className="text-red-600 hover:text-red-700 hover:bg-red-50 bg-transparent"
|
||||
onClick={() => handleDelete(appointment)}
|
||||
>
|
||||
<Trash2 className="mr-2 h-4 w-4" />
|
||||
Deletar
|
||||
</Button>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
))
|
||||
) : (
|
||||
<p>Nenhuma consulta encontrada.</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex gap-2 mt-4 pt-4 border-t">
|
||||
<Button variant="outline" size="sm" onClick={() => handleEdit(appointment)}>
|
||||
<Pencil className="mr-2 h-4 w-4" />
|
||||
Editar
|
||||
</Button>
|
||||
<Button variant="outline" size="sm" className="text-red-600 hover:text-red-700 hover:bg-red-50 bg-transparent" onClick={() => handleDelete(appointment)}>
|
||||
<Trash2 className="mr-2 h-4 w-4" />
|
||||
Cancelar
|
||||
</Button>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
))
|
||||
) : (
|
||||
<p>Nenhuma consulta encontrada.</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* MODAL DE EDIÇÃO */}
|
||||
<Dialog open={editModal} onOpenChange={setEditModal}>
|
||||
|
||||
@ -4,38 +4,11 @@
|
||||
import { useState, useEffect, useCallback } from "react";
|
||||
import Link from "next/link";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuTrigger,
|
||||
} from "@/components/ui/dropdown-menu";
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "@/components/ui/select";
|
||||
import {
|
||||
Plus,
|
||||
Edit,
|
||||
Trash2,
|
||||
Eye,
|
||||
Calendar,
|
||||
Filter,
|
||||
Loader2,
|
||||
} from "lucide-react";
|
||||
import {
|
||||
AlertDialog,
|
||||
AlertDialogAction,
|
||||
AlertDialogCancel,
|
||||
AlertDialogContent,
|
||||
AlertDialogDescription,
|
||||
AlertDialogFooter,
|
||||
AlertDialogHeader,
|
||||
AlertDialogTitle,
|
||||
} from "@/components/ui/alert-dialog";
|
||||
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "@/components/ui/dropdown-menu";
|
||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
|
||||
import { Plus, Edit, Trash2, Eye, Calendar, Filter, Loader2, MoreVertical } from "lucide-react";
|
||||
import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle } from "@/components/ui/alert-dialog";
|
||||
import SecretaryLayout from "@/components/secretary-layout";
|
||||
import { patientsService } from "@/services/patientsApi.mjs";
|
||||
import Sidebar from "@/components/Sidebar";
|
||||
|
||||
@ -43,58 +16,59 @@ import Sidebar from "@/components/Sidebar";
|
||||
const PAGE_SIZE = 5;
|
||||
|
||||
export default function PacientesPage() {
|
||||
// --- ESTADOS DE DADOS E GERAL ---
|
||||
const [searchTerm, setSearchTerm] = useState("");
|
||||
const [convenioFilter, setConvenioFilter] = useState("all");
|
||||
const [vipFilter, setVipFilter] = useState("all");
|
||||
// --- ESTADOS DE DADOS E GERAL ---
|
||||
const [searchTerm, setSearchTerm] = useState("");
|
||||
const [convenioFilter, setConvenioFilter] = useState("all");
|
||||
const [vipFilter, setVipFilter] = useState("all");
|
||||
|
||||
// Lista completa, carregada da API uma única vez
|
||||
const [allPatients, setAllPatients] = useState<any[]>([]);
|
||||
// Lista após a aplicação dos filtros (base para a paginação)
|
||||
const [filteredPatients, setFilteredPatients] = useState<any[]>([]);
|
||||
// Lista completa, carregada da API uma única vez
|
||||
const [allPatients, setAllPatients] = useState<any[]>([]);
|
||||
// Lista após a aplicação dos filtros (base para a paginação)
|
||||
const [filteredPatients, setFilteredPatients] = useState<any[]>([]);
|
||||
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
|
||||
// --- ESTADOS DE PAGINAÇÃO ---
|
||||
const [page, setPage] = useState(1);
|
||||
// --- ESTADOS DE PAGINAÇÃO ---
|
||||
const [page, setPage] = useState(1);
|
||||
|
||||
// CÁLCULO DA PAGINAÇÃO
|
||||
const totalPages = Math.ceil(filteredPatients.length / PAGE_SIZE);
|
||||
const startIndex = (page - 1) * PAGE_SIZE;
|
||||
const endIndex = startIndex + PAGE_SIZE;
|
||||
// Pacientes a serem exibidos na tabela (aplicando a paginação)
|
||||
const currentPatients = filteredPatients.slice(startIndex, endIndex);
|
||||
// CÁLCULO DA PAGINAÇÃO
|
||||
const totalPages = Math.ceil(filteredPatients.length / PAGE_SIZE);
|
||||
const startIndex = (page - 1) * PAGE_SIZE;
|
||||
const endIndex = startIndex + PAGE_SIZE;
|
||||
// Pacientes a serem exibidos na tabela (aplicando a paginação)
|
||||
const currentPatients = filteredPatients.slice(startIndex, endIndex);
|
||||
|
||||
// --- ESTADOS DE DIALOGS ---
|
||||
const [deleteDialogOpen, setDeleteDialogOpen] = useState(false);
|
||||
const [patientToDelete, setPatientToDelete] = useState<string | null>(null);
|
||||
const [detailsDialogOpen, setDetailsDialogOpen] = useState(false);
|
||||
const [patientDetails, setPatientDetails] = useState<any | null>(null);
|
||||
// --- ESTADOS DE DIALOGS ---
|
||||
const [deleteDialogOpen, setDeleteDialogOpen] = useState(false);
|
||||
const [patientToDelete, setPatientToDelete] = useState<string | null>(null);
|
||||
const [detailsDialogOpen, setDetailsDialogOpen] = useState(false);
|
||||
const [patientDetails, setPatientDetails] = useState<any | null>(null);
|
||||
|
||||
// --- FUNÇÕES DE LÓGICA ---
|
||||
// --- FUNÇÕES DE LÓGICA ---
|
||||
|
||||
// 1. Função para carregar TODOS os pacientes da API
|
||||
const fetchAllPacientes = useCallback(async () => {
|
||||
setLoading(true);
|
||||
setError(null);
|
||||
try {
|
||||
// Como o backend retorna um array, chamamos sem paginação
|
||||
const res = await patientsService.list();
|
||||
// 1. Função para carregar TODOS os pacientes da API
|
||||
const fetchAllPacientes = useCallback(
|
||||
async () => {
|
||||
setLoading(true);
|
||||
setError(null);
|
||||
try {
|
||||
// Como o backend retorna um array, chamamos sem paginação
|
||||
const res = await patientsService.list();
|
||||
|
||||
const mapped = res.map((p: any) => ({
|
||||
id: String(p.id ?? ""),
|
||||
nome: p.full_name ?? "—",
|
||||
telefone: p.phone_mobile ?? p.phone1 ?? "—",
|
||||
cidade: p.city ?? "—",
|
||||
estado: p.state ?? "—",
|
||||
// Formate as datas se necessário, aqui usamos como string
|
||||
ultimoAtendimento: p.last_visit_at?.split("T")[0] ?? "—",
|
||||
proximoAtendimento: p.next_appointment_at?.split("T")[0] ?? "—",
|
||||
vip: Boolean(p.vip ?? false),
|
||||
convenio: p.convenio ?? "Particular", // Define um valor padrão
|
||||
status: p.status ?? undefined,
|
||||
}));
|
||||
const mapped = res.map((p: any) => ({
|
||||
id: String(p.id ?? ""),
|
||||
nome: p.full_name ?? "—",
|
||||
telefone: p.phone_mobile ?? p.phone1 ?? "—",
|
||||
cidade: p.city ?? "—",
|
||||
estado: p.state ?? "—",
|
||||
// Formate as datas se necessário, aqui usamos como string
|
||||
ultimoAtendimento: p.last_visit_at?.split('T')[0] ?? "—",
|
||||
proximoAtendimento: p.next_appointment_at?.split('T')[0] ?? "—",
|
||||
vip: Boolean(p.vip ?? false),
|
||||
convenio: p.convenio ?? "Particular", // Define um valor padrão
|
||||
status: p.status ?? undefined,
|
||||
}));
|
||||
|
||||
setAllPatients(mapped);
|
||||
} catch (e: any) {
|
||||
@ -105,31 +79,32 @@ export default function PacientesPage() {
|
||||
}
|
||||
}, []);
|
||||
|
||||
// 2. Efeito para aplicar filtros e calcular a lista filtrada (chama-se quando allPatients ou filtros mudam)
|
||||
useEffect(() => {
|
||||
const filtered = allPatients.filter((patient) => {
|
||||
// Filtro por termo de busca (Nome ou Telefone)
|
||||
const matchesSearch =
|
||||
patient.nome?.toLowerCase().includes(searchTerm.toLowerCase()) ||
|
||||
patient.telefone?.includes(searchTerm);
|
||||
// 2. Efeito para aplicar filtros e calcular a lista filtrada (chama-se quando allPatients ou filtros mudam)
|
||||
useEffect(() => {
|
||||
const filtered = allPatients.filter((patient) => {
|
||||
// Filtro por termo de busca (Nome ou Telefone)
|
||||
const matchesSearch =
|
||||
patient.nome?.toLowerCase().includes(searchTerm.toLowerCase()) ||
|
||||
patient.telefone?.includes(searchTerm);
|
||||
|
||||
// Filtro por Convênio
|
||||
const matchesConvenio =
|
||||
convenioFilter === "all" || patient.convenio === convenioFilter;
|
||||
// Filtro por Convênio
|
||||
const matchesConvenio =
|
||||
convenioFilter === "all" ||
|
||||
patient.convenio === convenioFilter;
|
||||
|
||||
// Filtro por VIP
|
||||
const matchesVip =
|
||||
vipFilter === "all" ||
|
||||
(vipFilter === "vip" && patient.vip) ||
|
||||
(vipFilter === "regular" && !patient.vip);
|
||||
// Filtro por VIP
|
||||
const matchesVip =
|
||||
vipFilter === "all" ||
|
||||
(vipFilter === "vip" && patient.vip) ||
|
||||
(vipFilter === "regular" && !patient.vip);
|
||||
|
||||
return matchesSearch && matchesConvenio && matchesVip;
|
||||
});
|
||||
return matchesSearch && matchesConvenio && matchesVip;
|
||||
});
|
||||
|
||||
setFilteredPatients(filtered);
|
||||
// Garante que a página atual seja válida após a filtragem
|
||||
setPage(1);
|
||||
}, [allPatients, searchTerm, convenioFilter, vipFilter]);
|
||||
setFilteredPatients(filtered);
|
||||
// Garante que a página atual seja válida após a filtragem
|
||||
setPage(1);
|
||||
}, [allPatients, searchTerm, convenioFilter, vipFilter]);
|
||||
|
||||
// 3. Efeito inicial para buscar os pacientes
|
||||
useEffect(() => {
|
||||
@ -137,18 +112,18 @@ export default function PacientesPage() {
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
// --- LÓGICA DE AÇÕES (DELETAR / VER DETALHES) ---
|
||||
// --- LÓGICA DE AÇÕES (DELETAR / VER DETALHES) ---
|
||||
|
||||
const openDetailsDialog = async (patientId: string) => {
|
||||
setDetailsDialogOpen(true);
|
||||
setPatientDetails(null);
|
||||
try {
|
||||
const res = await patientsService.getById(patientId);
|
||||
setPatientDetails(Array.isArray(res) ? res[0] : res); // Supondo que retorne um array com um item
|
||||
} catch (e: any) {
|
||||
setPatientDetails({ error: e?.message || "Erro ao buscar detalhes" });
|
||||
}
|
||||
};
|
||||
const openDetailsDialog = async (patientId: string) => {
|
||||
setDetailsDialogOpen(true);
|
||||
setPatientDetails(null);
|
||||
try {
|
||||
const res = await patientsService.getById(patientId);
|
||||
setPatientDetails(Array.isArray(res) ? res[0] : res); // Supondo que retorne um array com um item
|
||||
} catch (e: any) {
|
||||
setPatientDetails({ error: e?.message || "Erro ao buscar detalhes" });
|
||||
}
|
||||
};
|
||||
|
||||
const handleDeletePatient = async (patientId: string) => {
|
||||
try {
|
||||
@ -192,19 +167,18 @@ export default function PacientesPage() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Bloco de Filtros (Responsividade APLICADA) */}
|
||||
<div className="flex flex-wrap items-center gap-4 bg-card p-4 rounded-lg border border-border">
|
||||
<Filter className="w-5 h-5 text-gray-400" />
|
||||
{/* Bloco de Filtros (Responsividade APLICADA) */}
|
||||
<div className="flex flex-wrap items-center gap-4 bg-card p-4 rounded-lg border border-border">
|
||||
<Filter className="w-5 h-5 text-gray-400" />
|
||||
|
||||
{/* Busca - Ocupa 100% no mobile, depois cresce */}
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Buscar por nome ou telefone..."
|
||||
value={searchTerm}
|
||||
onChange={(e) => setSearchTerm(e.target.value)}
|
||||
// w-full no mobile, depois flex-grow para ocupar o espaço disponível
|
||||
className="w-full sm:flex-grow sm:max-w-[300px] p-2 border rounded-md text-sm"
|
||||
/>
|
||||
{/* Busca - Ocupa 100% no mobile, depois cresce */}
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Buscar por nome ou telefone..."
|
||||
value={searchTerm}
|
||||
onChange={(e) => setSearchTerm(e.target.value)}
|
||||
className="w-full sm:flex-grow sm:min-w-[150px] p-2 border rounded-md text-sm"
|
||||
/>
|
||||
|
||||
{/* Convênio - Ocupa a largura total em telas pequenas, depois se ajusta */}
|
||||
<div className="flex items-center gap-2 w-full sm:w-auto sm:flex-grow sm:max-w-[200px]">
|
||||
|
||||
@ -41,8 +41,10 @@ export interface ButtonProps
|
||||
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
|
||||
({ className, variant, size, asChild = false, ...props }, ref) => {
|
||||
const Comp = asChild ? Slot : 'button'
|
||||
|
||||
return (
|
||||
<Comp
|
||||
data-slot="button"
|
||||
className={cn(buttonVariants({ variant, size, className }))}
|
||||
ref={ref}
|
||||
{...props}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user