feat: Melhorias na UI e consolidação de

ações para formulários de agendamento

  - calendar-registration-form.tsx:
      - Otimizadas importações de ícones e
  adicionadas novas caixas de seleção para
  reembolso e impressão de etiquetas.
      - Introduzido campo 'Profissional
  solicitante' com funcionalidade de busca.
      - Removido botão 'Cancelar' interno.
  - FooterAgenda.tsx:
      - Consolidado botões de ação,
  removendo 'Cancelar' e 'Salvar as
  alterações' redundantes.
This commit is contained in:
M-Gabrielly 2025-10-03 17:53:54 -03:00
parent 90ea08cead
commit 6585187efd
5 changed files with 151 additions and 71 deletions

View File

@ -1,22 +0,0 @@
"use client"
export default function AppointmentForm() {
return (
<form className="p-4 border rounded space-y-4">
<div>
<label className="block text-sm font-medium">Paciente</label>
<input type="text" className="mt-1 w-full border p-2 rounded" />
</div>
<div>
<label className="block text-sm font-medium">Data</label>
<input type="date" className="mt-1 w-full border p-2 rounded" />
</div>
<button
type="submit"
className="px-4 py-2 bg-blue-600 text-white rounded hover:bg-blue-700"
>
Salvar
</button>
</form>
)
}

View File

@ -18,15 +18,6 @@ export default function FooterAgenda() {
<Label className="text-sm text-foreground">Bloqueio de Agenda</Label> <Label className="text-sm text-foreground">Bloqueio de Agenda</Label>
</div> </div>
<div className="flex gap-2"> <div className="flex gap-2">
<Link href={"/calendar"}>
<Button variant="ghost" className="hover:bg-muted hover:text-foreground">Cancelar</Button>
</Link>
<Link href={"/calendar"}>
<Button>
<Save className="mr-2 h-4 w-4" />
Salvar as alterações
</Button>
</Link>
</div> </div>
</div> </div>
</div> </div>

View File

@ -35,7 +35,7 @@ export function PagesHeader({ title = "", subtitle = "" }: { title?: string, sub
<SidebarTrigger /> <SidebarTrigger />
<div className="flex items-start flex-col justify-center py-2"> <div className="flex items-start flex-col justify-center py-2">
<h1 className="text-lg font-semibold text-foreground">{title}</h1> <h1 className="text-lg font-semibold text-foreground">{title}</h1>
<p className="text-gray-600">{subtitle}</p> <p className="text-muted-foreground">{subtitle}</p>
</div> </div>
</div> </div>
@ -49,42 +49,42 @@ export function PagesHeader({ title = "", subtitle = "" }: { title?: string, sub
<div className="relative" ref={dropdownRef}> <div className="relative" ref={dropdownRef}>
<Button <Button
variant="ghost" variant="ghost"
className="relative h-8 w-8 rounded-full border-2 border-gray-300 hover:border-blue-500" className="relative h-8 w-8 rounded-full border-2 border-border hover:border-primary"
onClick={() => setDropdownOpen(!dropdownOpen)} onClick={() => setDropdownOpen(!dropdownOpen)}
> >
<Avatar className="h-8 w-8"> <Avatar className="h-8 w-8">
<AvatarImage src="/avatars/01.png" alt="@usuario" /> <AvatarImage src="/avatars/01.png" alt="@usuario" />
<AvatarFallback className="bg-blue-500 text-white font-semibold">RA</AvatarFallback> <AvatarFallback className="bg-primary text-primary-foreground font-semibold">RA</AvatarFallback>
</Avatar> </Avatar>
</Button> </Button>
{/* Dropdown Content */} {/* Dropdown Content */}
{dropdownOpen && ( {dropdownOpen && (
<div className="absolute right-0 mt-2 w-80 bg-white border border-gray-200 rounded-md shadow-lg z-50"> <div className="absolute right-0 mt-2 w-80 bg-popover border border-border rounded-md shadow-lg z-50 text-popover-foreground">
<div className="p-4 border-b border-gray-100"> <div className="p-4 border-b border-border">
<div className="flex flex-col space-y-1"> <div className="flex flex-col space-y-1">
<p className="text-sm font-semibold leading-none"> <p className="text-sm font-semibold leading-none">
{user?.userType === 'administrador' ? 'Administrador da Clínica' : 'Usuário do Sistema'} {user?.userType === 'administrador' ? 'Administrador da Clínica' : 'Usuário do Sistema'}
</p> </p>
{user?.email ? ( {user?.email ? (
<p className="text-xs leading-none text-gray-600">{user.email}</p> <p className="text-xs leading-none text-muted-foreground">{user.email}</p>
) : ( ) : (
<p className="text-xs leading-none text-gray-600">Email não disponível</p> <p className="text-xs leading-none text-muted-foreground">Email não disponível</p>
)} )}
<p className="text-xs leading-none text-blue-600 font-medium"> <p className="text-xs leading-none text-primary font-medium">
Tipo: {user?.userType === 'administrador' ? 'Administrador' : user?.userType || 'Não definido'} Tipo: {user?.userType === 'administrador' ? 'Administrador' : user?.userType || 'Não definido'}
</p> </p>
</div> </div>
</div> </div>
<div className="py-1"> <div className="py-1">
<button className="w-full text-left px-4 py-2 text-sm hover:bg-gray-100 cursor-pointer"> <button className="w-full text-left px-4 py-2 text-sm hover:bg-accent cursor-pointer">
👤 Perfil 👤 Perfil
</button> </button>
<button className="w-full text-left px-4 py-2 text-sm hover:bg-gray-100 cursor-pointer"> <button className="w-full text-left px-4 py-2 text-sm hover:bg-accent cursor-pointer">
Configurações Configurações
</button> </button>
<div className="border-t border-gray-100 my-1"></div> <div className="border-t border-border my-1"></div>
<button <button
onClick={(e) => { onClick={(e) => {
e.preventDefault(); e.preventDefault();
@ -93,7 +93,7 @@ export function PagesHeader({ title = "", subtitle = "" }: { title?: string, sub
// Usar sempre o logout do hook useAuth (ele já redireciona corretamente) // Usar sempre o logout do hook useAuth (ele já redireciona corretamente)
logout(); logout();
}} }}
className="w-full text-left px-4 py-2 text-sm text-red-600 hover:bg-red-50 cursor-pointer" className="w-full text-left px-4 py-2 text-sm text-destructive hover:bg-destructive/10 cursor-pointer"
> >
🚪 Sair 🚪 Sair
</button> </button>

View File

@ -1 +0,0 @@
export { default } from '@/app/agenda/appointment-form';

View File

@ -1,26 +1,74 @@
"use client"; "use client";
import { useState, useEffect } from "react"; import { useState, useEffect } from "react";
import dynamic from 'next/dynamic';
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input"; 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 { Calendar, Search, ChevronDown, Upload, FileDown, Tag } from "lucide-react"; import { Calendar, Search, ChevronDown } from "lucide-react";
export function CalendarRegistrationForm({ initialData, onSave, onCancel }: any) { interface FormData {
const [formData, setFormData] = useState(initialData || {}); patientName?: string;
cpf?: string;
rg?: string;
birthDate?: string;
phoneCode?: string;
phoneNumber?: string;
email?: string;
convenio?: string;
matricula?: string;
validade?: string;
documentos?: string;
professionalName?: string;
unit?: string;
appointmentDate?: string;
startTime?: string;
endTime?: string;
requestingProfessional?: string;
appointmentType?: string;
notes?: string;
}
interface CalendarRegistrationFormProperties {
initialData?: FormData;
onSave: (data: FormData) => void;
onCancel: () => void;
}
const formatValidityDate = (value: string) => {
const cleaned = value.replaceAll(/\D/g, "");
if (cleaned.length > 4) {
return `${cleaned.slice(0, 2)}/${cleaned.slice(2, 4)}/${cleaned.slice(4, 8)}`;
}
if (cleaned.length > 2) {
return `${cleaned.slice(0, 2)}/${cleaned.slice(2, 4)}`;
}
return cleaned;
};
export function CalendarRegistrationForm({ initialData, onSave, onCancel }: CalendarRegistrationFormProperties) {
const [formData, setFormData] = useState<FormData>(initialData || {});
const [isAdditionalInfoOpen, setIsAdditionalInfoOpen] = useState(false);
useEffect(() => { useEffect(() => {
setFormData(initialData || {}); setFormData(initialData || {});
}, [initialData]); }, [initialData]);
const handleChange = (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement>) => { const handleChange = (event: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement>) => {
const { name, value } = e.target; const { name, value } = event.target;
setFormData((prev: any) => ({ ...prev, [name]: value }));
if (name === 'validade') {
const formattedValue = formatValidityDate(value);
setFormData((previousState) => ({ ...previousState, [name]: formattedValue }));
} else {
setFormData((previousState) => ({ ...previousState, [name]: value }));
}
}; };
const handleSubmit = (e: React.FormEvent) => { const handleSubmit = (event: React.FormEvent) => {
e.preventDefault(); event.preventDefault();
onSave(formData); onSave(formData);
}; };
@ -29,7 +77,7 @@ export function CalendarRegistrationForm({ initialData, onSave, onCancel }: any)
<div className="border border-border rounded-md p-6 space-y-4 bg-card"> <div className="border border-border rounded-md p-6 space-y-4 bg-card">
<h2 className="font-medium text-foreground">Informações do paciente</h2> <h2 className="font-medium text-foreground">Informações do paciente</h2>
<div className="grid grid-cols-1 md:grid-cols-12 gap-4"> <div className="grid grid-cols-1 md:grid-cols-12 gap-4">
<div className="md:col-span-6"> <div className="md:col-span-6 space-y-2">
<Label>Nome *</Label> <Label>Nome *</Label>
<div className="relative"> <div className="relative">
<Search className="pointer-events-none absolute left-2 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground" /> <Search className="pointer-events-none absolute left-2 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground" />
@ -42,19 +90,19 @@ export function CalendarRegistrationForm({ initialData, onSave, onCancel }: any)
/> />
</div> </div>
</div> </div>
<div className="md:col-span-3"> <div className="md:col-span-3 space-y-2">
<Label>CPF do paciente</Label> <Label>CPF do paciente</Label>
<Input name="cpf" placeholder="Número do CPF" className="h-10" value={formData.cpf || ''} onChange={handleChange} /> <Input name="cpf" placeholder="Número do CPF" className="h-10" value={formData.cpf || ''} onChange={handleChange} />
</div> </div>
<div className="md:col-span-3"> <div className="md:col-span-3 space-y-2">
<Label>RG</Label> <Label>RG</Label>
<Input name="rg" placeholder="Número do RG" className="h-10" value={formData.rg || ''} onChange={handleChange} /> <Input name="rg" placeholder="Número do RG" className="h-10" value={formData.rg || ''} onChange={handleChange} />
</div> </div>
<div className="md:col-span-3"> <div className="md:col-span-3 space-y-2">
<Label>Data de nascimento *</Label> <Label>Data de nascimento *</Label>
<Input name="birthDate" type="date" className="h-10" value={formData.birthDate || ''} onChange={handleChange} /> <Input name="birthDate" type="date" className="h-10" value={formData.birthDate || ''} onChange={handleChange} />
</div> </div>
<div className="md:col-span-3"> <div className="md:col-span-3 space-y-2">
<Label>Telefone</Label> <Label>Telefone</Label>
<div className="flex gap-2"> <div className="flex gap-2">
<select name="phoneCode" className="h-10 w-20 rounded-md border border-input bg-background text-foreground px-2 text-[13px]" value={formData.phoneCode || '+55'} onChange={handleChange}> <select name="phoneCode" className="h-10 w-20 rounded-md border border-input bg-background text-foreground px-2 text-[13px]" value={formData.phoneCode || '+55'} onChange={handleChange}>
@ -65,19 +113,60 @@ export function CalendarRegistrationForm({ initialData, onSave, onCancel }: any)
<Input name="phoneNumber" placeholder="(99) 99999-9999" className="h-10 flex-1" value={formData.phoneNumber || ''} onChange={handleChange} /> <Input name="phoneNumber" placeholder="(99) 99999-9999" className="h-10 flex-1" value={formData.phoneNumber || ''} onChange={handleChange} />
</div> </div>
</div> </div>
<div className="md:col-span-6"> <div className="md:col-span-6 space-y-2">
<Label>E-mail</Label> <Label>E-mail</Label>
<Input name="email" type="email" placeholder="email@exemplo.com" className="h-10" value={formData.email || ''} onChange={handleChange} /> <Input name="email" type="email" placeholder="email@exemplo.com" className="h-10" value={formData.email || ''} onChange={handleChange} />
</div> </div>
<div className="md:col-span-6 space-y-2">
<Label>Convênio</Label>
<div className="relative">
<select name="convenio" className="h-10 w-full rounded-md border border-input bg-background text-foreground pr-8 pl-3 text-[13px] appearance-none" value={formData.convenio || ''} onChange={handleChange}>
<option value="" disabled>Selecione um convênio</option>
<option value="sulamerica">Sulamérica</option>
<option value="bradesco">Bradesco Saúde</option>
<option value="amil">Amil</option>
<option value="unimed">Unimed</option>
</select>
<ChevronDown className="pointer-events-none absolute right-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground" />
</div>
</div>
<div className="md:col-span-6 space-y-2">
<div className="grid grid-cols-2 gap-3">
<div className="space-y-2">
<Label>Matrícula</Label>
<Input name="matricula" placeholder="000000000" maxLength={9} className="h-10" value={formData.matricula || ''} onChange={handleChange} />
</div>
<div className="space-y-2">
<Label>Validade</Label>
<Input name="validade" placeholder="00/00/0000" className="h-10" value={formData.validade || ''} onChange={handleChange} />
</div>
</div>
</div>
<div className="md:col-span-12 pt-2">
<div
className="flex items-center justify-between cursor-pointer"
onClick={() => setIsAdditionalInfoOpen(!isAdditionalInfoOpen)}
>
<h3 className="text-base font-medium text-foreground">Informações adicionais</h3>
<ChevronDown className={`h-5 w-5 text-muted-foreground transition-transform duration-200 ${isAdditionalInfoOpen ? 'rotate-180' : ''}`} />
</div>
{isAdditionalInfoOpen && (
<div className="mt-4 space-y-2">
<Label>Documentos e anexos</Label>
<Textarea name="documentos" rows={5} className="text-[13px] resize-none" value={formData.documentos || ''} onChange={handleChange} />
</div>
)}
</div>
</div> </div>
</div> </div>
{}
<div className="border border-border rounded-md p-6 space-y-4 bg-card"> <div className="border border-border rounded-md p-6 space-y-4 bg-card">
<div className="flex justify-between items-center">
<h2 className="font-medium text-foreground">Informações do atendimento</h2> <h2 className="font-medium text-foreground">Informações do atendimento</h2>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 gap-6"> <div className="grid grid-cols-1 md:grid-cols-2 gap-6">
<div className="space-y-4"> <div className="space-y-4">
<div> <div className="space-y-2">
<Label className="text-[13px]">Nome do profissional *</Label> <Label className="text-[13px]">Nome do profissional *</Label>
<div className="relative"> <div className="relative">
<Search className="pointer-events-none absolute left-2 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground" /> <Search className="pointer-events-none absolute left-2 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground" />
@ -85,14 +174,14 @@ export function CalendarRegistrationForm({ initialData, onSave, onCancel }: any)
</div> </div>
</div> </div>
<div className="grid grid-cols-2 gap-3"> <div className="grid grid-cols-2 gap-3">
<div> <div className="space-y-2">
<Label className="text-[13px]">Unidade *</Label> <Label className="text-[13px]">Unidade *</Label>
<select name="unit" className="h-10 w-full rounded-md border border-input bg-background text-foreground pr-8 pl-3 text-[13px] appearance-none" value={formData.unit || 'nei'} onChange={handleChange}> <select name="unit" className="h-10 w-full rounded-md border border-input bg-background text-foreground pr-8 pl-3 text-[13px] appearance-none" value={formData.unit || 'nei'} onChange={handleChange}>
<option value="nei">Núcleo de Especialidades Integradas</option> <option value="nei">Núcleo de Especialidades Integradas</option>
<option value="cc">Clínica Central</option> <option value="cc">Clínica Central</option>
</select> </select>
</div> </div>
<div> <div className="space-y-2">
<Label className="text-[13px]">Data *</Label> <Label className="text-[13px]">Data *</Label>
<div className="relative"> <div className="relative">
<Calendar className="pointer-events-none absolute left-2 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground" /> <Calendar className="pointer-events-none absolute left-2 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground" />
@ -100,27 +189,51 @@ export function CalendarRegistrationForm({ initialData, onSave, onCancel }: any)
</div> </div>
</div> </div>
</div> </div>
<div className="grid grid-cols-2 gap-3"> <div className="grid grid-cols-3 gap-3">
<div> <div className="space-y-2">
<Label className="text-[13px]">Início *</Label> <Label className="text-[13px]">Início *</Label>
<Input name="startTime" type="time" className="h-10 w-full rounded-md border border-input px-3 text-[13px]" value={formData.startTime || ''} onChange={handleChange} /> <Input name="startTime" type="time" className="h-10 w-full rounded-md border border-input px-3 text-[13px]" value={formData.startTime || ''} onChange={handleChange} />
</div> </div>
<div> <div className="space-y-2">
<Label className="text-[13px]">Término *</Label> <Label className="text-[13px]">Término *</Label>
<Input name="endTime" type="time" className="h-10 w-full rounded-md border border-input px-3 text-[13px]" value={formData.endTime || ''} onChange={handleChange} /> <Input name="endTime" type="time" className="h-10 w-full rounded-md border border-input px-3 text-[13px]" value={formData.endTime || ''} onChange={handleChange} />
</div> </div>
<div className="space-y-2">
<Label className="text-[13px]">Profissional solicitante</Label>
<div className="relative">
<Search className="pointer-events-none absolute left-2 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground" />
<select name="requestingProfessional" className="h-10 w-full rounded-md border border-input bg-background text-foreground pr-8 pl-8 text-[13px] appearance-none" value={formData.requestingProfessional || ''} onChange={handleChange}>
<option value="" disabled>Selecione solicitante</option>
<option value="dr-a">Dr. A</option>
<option value="dr-b">Dr. B</option>
</select>
<ChevronDown className="pointer-events-none absolute right-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground" />
</div>
</div>
</div> </div>
</div> </div>
<div className="space-y-4"> <div className="space-y-4">
<div> <div className="space-y-2">
<div className="flex items-center justify-between">
<Label className="text-[13px]">Tipo de atendimento *</Label> <Label className="text-[13px]">Tipo de atendimento *</Label>
<div className="flex items-center space-x-2">
<Input type="checkbox" id="reembolso" className="h-4 w-4" />
<Label htmlFor="reembolso" className="text-[13px] font-medium">Pagamento via Reembolso</Label>
</div>
</div>
<div className="relative mt-1"> <div className="relative mt-1">
<Search className="pointer-events-none absolute left-2 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground" /> <Search className="pointer-events-none absolute left-2 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground" />
<Input name="appointmentType" placeholder="Pesquisar" className="h-10 w-full rounded-md border border-input pl-8 pr-8 text-[13px]" value={formData.appointmentType || ''} onChange={handleChange} /> <Input name="appointmentType" placeholder="Pesquisar" className="h-10 w-full rounded-md border border-input pl-8 pr-8 text-[13px]" value={formData.appointmentType || ''} onChange={handleChange} />
</div> </div>
</div> </div>
<div> <div className="space-y-2">
<div className="flex items-center justify-between">
<Label className="text-[13px]">Observações</Label> <Label className="text-[13px]">Observações</Label>
<div className="flex items-center space-x-2">
<Input type="checkbox" id="imprimir" className="h-4 w-4" />
<Label htmlFor="imprimir" className="text-[13px] font-medium">Imprimir na Etiqueta / Pulseira</Label>
</div>
</div>
<Textarea name="notes" rows={6} className="text-[13px] min-h-[120px] resize-none" value={formData.notes || ''} onChange={handleChange} /> <Textarea name="notes" rows={6} className="text-[13px] min-h-[120px] resize-none" value={formData.notes || ''} onChange={handleChange} />
</div> </div>
</div> </div>
@ -128,7 +241,6 @@ export function CalendarRegistrationForm({ initialData, onSave, onCancel }: any)
</div> </div>
<div className="flex justify-end gap-2"> <div className="flex justify-end gap-2">
<Button type="button" variant="outline" onClick={onCancel}>Cancelar</Button>
<Button type="submit">Salvar</Button> <Button type="submit">Salvar</Button>
</div> </div>
</form> </form>