AppointmentCard.tsx 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. import { Card, CardContent, CardHeader } from "@/components/ui/card";
  2. import { Button } from "@/components/ui/button";
  3. import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
  4. import { AppointmentStatusBadge } from "./AppointmentStatusBadge";
  5. import { Calendar, Clock, User, FileText } from "lucide-react";
  6. import { format } from "date-fns";
  7. import { es } from "date-fns/locale";
  8. import Link from "next/link";
  9. import type { Appointment } from "@/types/appointments";
  10. interface AppointmentCardProps {
  11. appointment: Appointment;
  12. userRole: "PATIENT" | "DOCTOR" | "ADMIN";
  13. onApprove?: (id: string) => void;
  14. onReject?: (id: string) => void;
  15. onCancel?: (id: string) => void;
  16. }
  17. export const AppointmentCard = ({
  18. appointment,
  19. userRole,
  20. onApprove,
  21. onReject,
  22. onCancel,
  23. }: AppointmentCardProps) => {
  24. const fecha = new Date(appointment.fechaSolicitada);
  25. const otherUser = userRole === "PATIENT" ? appointment.medico : appointment.paciente;
  26. return (
  27. <Card className="hover:shadow-md transition-shadow">
  28. <CardHeader className="pb-3">
  29. <div className="flex items-start justify-between">
  30. <div className="flex items-center gap-3">
  31. {otherUser && (
  32. <Avatar>
  33. <AvatarImage src={otherUser.profileImage || undefined} />
  34. <AvatarFallback>
  35. {otherUser.name[0]}{otherUser.lastname[0]}
  36. </AvatarFallback>
  37. </Avatar>
  38. )}
  39. <div>
  40. <h3 className="font-semibold text-lg">
  41. {otherUser
  42. ? `${otherUser.name} ${otherUser.lastname}`
  43. : userRole === "DOCTOR"
  44. ? "Sin asignar"
  45. : "Médico por asignar"}
  46. </h3>
  47. <div className="flex items-center gap-2 text-sm text-muted-foreground mt-1">
  48. <Calendar className="h-4 w-4" />
  49. <span>{format(fecha, "PPP", { locale: es })}</span>
  50. <Clock className="h-4 w-4 ml-2" />
  51. <span>{format(fecha, "p", { locale: es })}</span>
  52. </div>
  53. </div>
  54. </div>
  55. <AppointmentStatusBadge status={appointment.estado} />
  56. </div>
  57. </CardHeader>
  58. <CardContent className="space-y-3">
  59. <div className="flex items-start gap-2 text-sm">
  60. <FileText className="h-4 w-4 mt-0.5 text-muted-foreground" />
  61. <div>
  62. <p className="font-medium">Motivo de consulta:</p>
  63. <p className="text-muted-foreground">{appointment.motivoConsulta}</p>
  64. </div>
  65. </div>
  66. {appointment.motivoRechazo && (
  67. <div className="bg-destructive/10 p-3 rounded-md text-sm">
  68. <p className="font-medium text-destructive">Motivo de rechazo:</p>
  69. <p className="text-muted-foreground mt-1">{appointment.motivoRechazo}</p>
  70. </div>
  71. )}
  72. <div className="flex gap-2 pt-2">
  73. {userRole === "DOCTOR" && appointment.estado === "PENDIENTE" && (
  74. <>
  75. <Button
  76. onClick={() => onApprove?.(appointment.id)}
  77. className="flex-1"
  78. size="sm"
  79. >
  80. Aprobar
  81. </Button>
  82. <Button
  83. onClick={() => onReject?.(appointment.id)}
  84. variant="outline"
  85. className="flex-1"
  86. size="sm"
  87. >
  88. Rechazar
  89. </Button>
  90. </>
  91. )}
  92. {userRole === "PATIENT" && appointment.estado === "PENDIENTE" && (
  93. <Button
  94. onClick={() => onCancel?.(appointment.id)}
  95. variant="outline"
  96. className="flex-1"
  97. size="sm"
  98. >
  99. Cancelar cita
  100. </Button>
  101. )}
  102. {appointment.estado === "APROBADA" && (
  103. <Button asChild className="flex-1" size="sm">
  104. <Link href={`/appointments/${appointment.id}/meet`}>
  105. Unirse a la consulta
  106. </Link>
  107. </Button>
  108. )}
  109. <Button asChild variant="outline" size="sm">
  110. <Link href={`/appointments/${appointment.id}`}>
  111. Ver detalles
  112. </Link>
  113. </Button>
  114. </div>
  115. </CardContent>
  116. </Card>
  117. );
  118. };