Cambiar el flujo de agendamiento para que las citas se creen desde el chatbot (sin fecha/hora específica) y el doctor asigne la fecha al aprobar.
roomName y se redirige a sala JitsiSchema actualizado (prisma/schema.prisma):
notasConsulta: String? - Texto de las notas médicasnotasGuardadas: Boolean - Si están compartidas con el pacientenotasGuardadasAt: DateTime? - Fecha de cuando se compartieronAPI de notas (/api/appointments/[id]/consultation-notes):
GET: Obtener notas (doctor ve siempre, paciente solo si están guardadas)POST: Guardar notas (solo doctor)
guardar: false → Borrador privadoguardar: true → Compartidas con pacienteComponente ConsultationNotes:
Integración en /meet:
Visualización en detalle:
notasGuardadas === truefechaSolicitada ahora es DateTime?20251008165451_make_fecha_solicitada_optionalfechaSolicitada es opcional en POSTCreateAppointmentInput sin fecha requeridaAppointmentModalFromChat.tsx
/api/appointments sin fecha[x] MedicalAlert.tsx
onAppointmentClick?: () => voidMedicalAlertType[x] ChatMessage.tsx
onAppointmentClick?: () => voidMedicalAlert[x] ChatInterface.tsx
showAppointmentModal: booleanhandleOpenAppointmentModalAppointmentModalFromChatChatMessages[x] ChatMessages.tsx
ChatMessage[x] AppointmentCard.tsx
fechaSolicitada: null[x] /appointments/[id]/page.tsx
fechaSolicitada: null en detalleappointments.ts
fechaSolicitada ahora es Date | string | nullCreateAppointmentInput.fechaSolicitada ahora es opcional/appointments/page.tsxAPPOINTMENTS_SYSTEM.mdAppointmentModalFromChat.tsx)interface Props {
open: boolean;
onClose: () => void;
onSuccess?: () => void;
}
// MedicalAlert
interface MedicalAlertProps {
alert: MedicalAlertType;
className?: string;
onAppointmentClick?: () => void; // Nuevo
}
// ChatMessage
interface ChatMessageProps {
message: Message;
onAppointmentClick?: () => void; // Nuevo
}
const [showAppointmentModal, setShowAppointmentModal] = useState(false);
const handleOpenAppointmentModal = () => {
setShowAppointmentModal(true);
};
Dialog de shadcn/uiTextarea para motivoButton para accionesuseAppointmentsanyfechaSolicitada a createdAt✅ GET /api/appointments retornaba 401: orderBy con campo nullable causaba error
fechaSolicitada: "asc" a createdAt: "desc"✅ Usuarios UTB (sin email) recibían 401 en todas las APIs
session.user.email (vacío en usuarios UTB)session.user.id en todas las APIs de appointments/api/appointments/route.ts (GET, POST)/api/appointments/[id]/route.ts (GET, PATCH)/api/appointments/[id]/approve/route.ts (POST)/api/appointments/[id]/reject/route.ts (POST)/api/appointments/[id]/complete/route.ts (POST)✅ Médicos recibían 403 al ver detalles de citas pendientes
medicoId === user.id, pero citas pendientes tienen medicoId: null/api/appointments/[id]/route.ts (GET)Antes: Chat → Link → /appointments → Form con fecha → Submit
Después: Chat → Click botón → Modal inline → Solo motivo → Submit → Doctor asigna fecha
Nuevo componente: AppointmentModalFromChat.tsx
fechaSolicitadaanyComponentes modificados:
MedicalAlert.tsx: Botón con onClick en lugar de LinkChatMessage.tsx: Prop drilling del callbackChatMessages.tsx: Prop drilling del callbackChatInterface.tsx: Estado del modal y handlersindex.ts: Export del nuevo componenteBackend:
fechaSolicitada DateTime? (nullable)20251008165451_make_fecha_solicitada_optionalmotivoConsultaany: Uso de spread operator condicionalTipos actualizados:
Appointment.fechaSolicitada: Date | string | nullCreateAppointmentInput.fechaSolicitada: Date (opcional)RECOMENDADO o URGENTEPENDIENTE sin fecha específicaNuevo componente: ApproveAppointmentModal.tsx
DateTimePicker mejorado:
date y setDateAPI actualizado (/api/appointments/[id]/approve):
fechaSolicitada en el bodyPágina de detalle modificada (/appointments/[id]/page.tsx):
handleApprove recibe fecha y notasuseAppointments: Actualizado para requerir fechaSolicitada en approveAppointmentApproveAppointmentModal en lugar de aprobar directamente9999 para que aparezca sobre el Dialog700px, modal={false} para permitir interacción con Popover, overlay manual para mantener opacidadAPI de aprobación modificada (/api/appointments/[id]/approve):
roomName al aprobarNuevo endpoint (/api/appointments/[id]/start-meeting):
roomName solo cuando se inicia la videollamadaroomName, lo reutilizaUtilidades de tiempo (/utils/appointments.ts):
canJoinMeeting(): Valida si es tiempo de unirsegetAppointmentTimeStatus(): Retorna mensaje de estado ("En 30 minutos", "Puedes unirte ahora", etc.)UI en página de detalle:
roomName y se redirige a sala Jitsi/appointments/page.tsxAPPOINTMENTS_SYSTEM.md con nuevo flujo