AppointmentModalFromChat.tsx 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. "use client";
  2. import { useState } from "react";
  3. import { Button } from "@/components/ui/button";
  4. import {
  5. Dialog,
  6. DialogContent,
  7. DialogDescription,
  8. DialogFooter,
  9. DialogHeader,
  10. DialogTitle,
  11. } from "@/components/ui/dialog";
  12. import { Label } from "@/components/ui/label";
  13. import { Textarea } from "@/components/ui/textarea";
  14. import { Calendar, AlertCircle } from "lucide-react";
  15. import { notifications } from "@/lib/notifications";
  16. interface AppointmentModalFromChatProps {
  17. open: boolean;
  18. onClose: () => void;
  19. onSuccess?: () => void;
  20. }
  21. export const AppointmentModalFromChat = ({
  22. open,
  23. onClose,
  24. onSuccess,
  25. }: AppointmentModalFromChatProps) => {
  26. const [motivoConsulta, setMotivoConsulta] = useState("");
  27. const [isSubmitting, setIsSubmitting] = useState(false);
  28. const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
  29. e.preventDefault();
  30. if (!motivoConsulta.trim()) {
  31. notifications.validation.requiredField("motivo de consulta");
  32. return;
  33. }
  34. setIsSubmitting(true);
  35. try {
  36. const response = await fetch("/api/appointments", {
  37. method: "POST",
  38. headers: { "Content-Type": "application/json" },
  39. body: JSON.stringify({
  40. motivoConsulta: motivoConsulta.trim(),
  41. // No enviamos fechaSolicitada - el doctor la asignará
  42. }),
  43. });
  44. if (!response.ok) {
  45. const error = await response.json();
  46. throw new Error(error.error || "Error al crear cita");
  47. }
  48. notifications.appointments.created();
  49. setMotivoConsulta("");
  50. onClose();
  51. onSuccess?.();
  52. } catch (error) {
  53. const message = error instanceof Error ? error.message : undefined;
  54. notifications.appointments.createError(message);
  55. } finally {
  56. setIsSubmitting(false);
  57. }
  58. };
  59. const handleClose = () => {
  60. if (!isSubmitting) {
  61. setMotivoConsulta("");
  62. onClose();
  63. }
  64. };
  65. return (
  66. <Dialog open={open} onOpenChange={handleClose}>
  67. <DialogContent className="sm:max-w-[500px]">
  68. <DialogHeader>
  69. <div className="flex items-center gap-2">
  70. <Calendar className="h-5 w-5 text-primary" />
  71. <DialogTitle>Solicitar Cita Médica</DialogTitle>
  72. </div>
  73. <DialogDescription className="pt-2">
  74. Describe el motivo de tu consulta. Un médico revisará tu solicitud y
  75. te asignará una fecha y hora para la cita telemática.
  76. </DialogDescription>
  77. </DialogHeader>
  78. <form onSubmit={handleSubmit} className="space-y-4">
  79. <div className="space-y-2">
  80. <Label htmlFor="motivo-consulta">
  81. Motivo de la consulta <span className="text-destructive">*</span>
  82. </Label>
  83. <Textarea
  84. id="motivo-consulta"
  85. placeholder="Ejemplo: Necesito consultar sobre los síntomas que mencioné en el chat..."
  86. value={motivoConsulta}
  87. onChange={(e) => setMotivoConsulta(e.target.value)}
  88. rows={5}
  89. required
  90. disabled={isSubmitting}
  91. className="resize-none"
  92. />
  93. <p className="text-xs text-muted-foreground">
  94. {motivoConsulta.length}/500 caracteres
  95. </p>
  96. </div>
  97. <div className="flex items-start gap-2 p-3 bg-muted rounded-lg">
  98. <AlertCircle className="h-4 w-4 text-muted-foreground mt-0.5 flex-shrink-0" />
  99. <p className="text-xs text-muted-foreground">
  100. Tu solicitud quedará pendiente hasta que un médico la revise y asigne
  101. una fecha. Recibirás una notificación cuando sea aprobada.
  102. </p>
  103. </div>
  104. <DialogFooter>
  105. <Button
  106. type="button"
  107. variant="outline"
  108. onClick={handleClose}
  109. disabled={isSubmitting}
  110. >
  111. Cancelar
  112. </Button>
  113. <Button
  114. type="submit"
  115. disabled={!motivoConsulta.trim() || isSubmitting}
  116. >
  117. {isSubmitting ? "Enviando..." : "Solicitar cita"}
  118. </Button>
  119. </DialogFooter>
  120. </form>
  121. </DialogContent>
  122. </Dialog>
  123. );
  124. };