Skip to main content
Estas acciones gestionan el flujo de atención psicológica después de que un tamizaje identifica riesgo: desde agendar una cita inicial, registrar notas de sesión, canalizar al estudiante a servicios externos, y registrar intentos de contacto con los padres.
Todas las acciones en este módulo requieren que la sesión activa tenga uno de estos roles: PSICOLOGO, ORIENTADOR o ADMIN. Solicitudes de roles DIRECTOR o ESTUDIANTE son rechazadas con "Acceso denegado".

Acciones de citas

agendarCita

export async function agendarCita(
  _prev: CitaResult,
  formData: FormData
): Promise<CitaResult>
Agenda una nueva cita para un estudiante. Si el estudiante no tiene un expediente clínico, crea uno automáticamente. Tras agendar con éxito, redirige a /citas.

Campos del FormData

CampoTipoDescripción
estudianteIdstringID del estudiante
fechastringFecha y hora en formato ISO 8601
notasstring?Notas previas (opcional)

Validaciones

  • estudianteId y fecha son obligatorios.
  • La fecha no puede ser un sábado (día 6) ni un domingo (día 0).

Retorno

export type CitaResult = { error: string } | undefined

Ejemplo

import { agendarCita } from "@/lib/actions/cita"
import { useActionState } from "react"

function FormularioCita() {
  const [state, formAction] = useActionState(agendarCita, undefined)

  return (
    <form action={formAction}>
      <input type="hidden" name="estudianteId" value="cm1abc123" />
      <input type="datetime-local" name="fecha" />
      <textarea name="notas" />
      {state?.error && <p>{state.error}</p>}
      <button type="submit">Agendar cita</button>
    </form>
  )
}

actualizarEstadoCita

export async function actualizarEstadoCita(
  citaId: string,
  estado: "PENDIENTE" | "CONFIRMADA" | "COMPLETADA" | "CANCELADA"
): Promise<void>
Cambia el estado de una cita existente e invalida la caché de /citas. No retorna error — si la sesión no tiene rol permitido, la función retorna silenciosamente sin hacer cambios.

Ejemplo

import { actualizarEstadoCita } from "@/lib/actions/cita"

await actualizarEstadoCita("cm1cita456", "CONFIRMADA")

completarCitaConSesion

export async function completarCitaConSesion(
  _prev: CompletarCitaResult,
  formData: FormData
): Promise<CompletarCitaResult>
Marca la cita como COMPLETADA y crea simultáneamente un registro de sesión clínica. Ambas operaciones ocurren en la misma transacción. Tras completar, redirige a /citas.

Campos del FormData

CampoTipoDescripción
citaIdstringID de la cita
estudianteIdstringID del estudiante
tipostringTipo de sesión — ver enum TipoSesion. Por defecto: SEGUIMIENTO
motivostring?Motivo de la sesión (opcional)
notasstringNotas clínicas — obligatorio
acuerdosstring?Acuerdos alcanzados (opcional)
planActualizadostring?Actualizaciones al plan de intervención (opcional)

Retorno

export type CompletarCitaResult = { error: string } | undefined

Ejemplo

import { completarCitaConSesion } from "@/lib/actions/cita"
import { useActionState } from "react"

function FormularioCompletarCita({ citaId, estudianteId }: Props) {
  const [state, formAction] = useActionState(completarCitaConSesion, undefined)

  return (
    <form action={formAction}>
      <input type="hidden" name="citaId" value={citaId} />
      <input type="hidden" name="estudianteId" value={estudianteId} />
      <select name="tipo">
        <option value="EVALUACION_INICIAL">Evaluación inicial</option>
        <option value="SEGUIMIENTO">Seguimiento</option>
        <option value="INTERVENCION">Intervención</option>
        <option value="CRISIS">Crisis</option>
        <option value="CIERRE">Cierre</option>
        <option value="DEVOLUCION">Devolución</option>
      </select>
      <textarea name="notas" required />
      <textarea name="acuerdos" />
      {state?.error && <p>{state.error}</p>}
      <button type="submit">Completar cita</button>
    </form>
  )
}

Modelo de datos: Cita

CampoTipoDescripción
idStringCUID autogenerado
fechaDateTimeFecha y hora de la cita
estadoEstadoCitaEstado actual de la cita
notasString?Notas previas
estudianteIdStringFK al estudiante

EstadoCita

ValorDescripción
PENDIENTECita agendada, sin confirmar (estado inicial)
CONFIRMADAConfirmada por el psicólogo u orientador
COMPLETADASe realizó — siempre tiene un registro de sesión asociado
CANCELADACancelada antes de realizarse

Acciones de sesiones

crearSesion

export async function crearSesion(
  _prev: SesionResult,
  formData: FormData
): Promise<SesionResult>
Crea una sesión clínica independiente (sin cita previa). También hace upsert del ExpedienteClinico del estudiante, actualizando actualizadaEn. Invalida la caché de /expediente/{estudianteId}.

Campos del FormData

CampoTipoDescripción
estudianteIdstringID del estudiante — obligatorio
tipostringTipo de sesión (TipoSesion). Por defecto: SEGUIMIENTO
motivostring?Motivo de la sesión
notasstringNotas clínicas — obligatorio
acuerdosstring?Acuerdos alcanzados
planActualizadostring?Actualizaciones al plan

Retorno

export type SesionResult = { error?: string; ok?: boolean }

Ejemplo

import { crearSesion } from "@/lib/actions/sesion"
import { useActionState } from "react"

function FormularioSesion({ estudianteId }: { estudianteId: string }) {
  const [state, formAction] = useActionState(crearSesion, {})

  return (
    <form action={formAction}>
      <input type="hidden" name="estudianteId" value={estudianteId} />
      <select name="tipo">
        <option value="SEGUIMIENTO">Seguimiento</option>
        <option value="CRISIS">Crisis</option>
      </select>
      <textarea name="notas" required />
      {state.error && <p>{state.error}</p>}
      {state.ok && <p>Sesión guardada.</p>}
      <button type="submit">Guardar sesión</button>
    </form>
  )
}

actualizarExpediente

export async function actualizarExpediente(
  _prev: SesionResult,
  formData: FormData
): Promise<SesionResult>
Actualiza (o crea) el expediente clínico de un estudiante con información narrativa. Usa upsert sobre estudianteId.

Campos del FormData

CampoTipoDescripción
estudianteIdstringID del estudiante
motivoConsultastring?Motivo de consulta
antecedentesstring?Antecedentes relevantes
diagnosticoPreliminarstring?Diagnóstico preliminar
planIntervencionstring?Plan de intervención
estadostringACTIVO, CERRADO, DERIVADO o EN_ESPERA. Por defecto: ACTIVO

Modelo de datos: Sesion

CampoTipoDescripción
idStringCUID autogenerado
fechaDateTimeFecha de la sesión (automática)
tipoTipoSesionTipo de sesión
motivoString?Motivo de la sesión
notasStringNotas clínicas — obligatorio
acuerdosString?Acuerdos alcanzados
planActualizadoString?Actualizaciones al plan
citaIdString?FK a Cita si la sesión surge de una cita
estudianteIdStringFK al estudiante

TipoSesion

import type { TipoSesion } from "@/lib/enums"
ValorDescripción
EVALUACION_INICIALPrimera sesión de evaluación
SEGUIMIENTOSeguimiento regular
INTERVENCIONSesión de intervención terapéutica
CRISISAtención en situación de crisis
CIERRECierre del proceso
DEVOLUCIONDevolución de resultados al estudiante o familia

Acciones de canalizaciones

crearCanalizacion

export async function crearCanalizacion(
  _prev: CanalizacionResult,
  formData: FormData
): Promise<CanalizacionResult>
Registra la canalización de un estudiante a una institución externa. Si urgente es true, actualiza automáticamente el estado del expediente clínico a DERIVADO.

Campos del FormData

CampoTipoDescripción
estudianteIdstringID del estudiante
institucionstringNombre de la institución — obligatorio
tipoInstitucionstringPUBLICA o PRIVADA. Por defecto: PUBLICA
tipoAtencionstring?Tipo de atención requerida
motivostringMotivo de la canalización — obligatorio
nivelRiesgostring?Número de 1 a 10 (valoración clínica)
urgente"on"Presente si la canalización es urgente (checkbox HTML)
notasstring?Notas adicionales

Retorno

export type CanalizacionResult = { error?: string; ok?: boolean }

Ejemplo

import { crearCanalizacion } from "@/lib/actions/canalizacion"
import { useActionState } from "react"

function FormularioCanalizacion({ estudianteId }: { estudianteId: string }) {
  const [state, formAction] = useActionState(crearCanalizacion, {})

  return (
    <form action={formAction}>
      <input type="hidden" name="estudianteId" value={estudianteId} />
      <input name="institucion" placeholder="IMSS - UMF 5" />
      <select name="tipoInstitucion">
        <option value="PUBLICA">Pública</option>
        <option value="PRIVADA">Privada</option>
      </select>
      <textarea name="motivo" required />
      <input name="nivelRiesgo" type="number" min="1" max="10" />
      <input type="checkbox" name="urgente" /> Urgente
      {state.error && <p>{state.error}</p>}
      <button type="submit">Canalizar</button>
    </form>
  )
}

actualizarSeguimientoCanalizacion

export async function actualizarSeguimientoCanalizacion(
  _prev: CanalizacionResult,
  formData: FormData
): Promise<CanalizacionResult>
Actualiza el estado y documentación de seguimiento de una canalización existente. Si documentoRecibido está marcado, registra fechaDocumento con la fecha actual.

Campos del FormData

CampoTipoDescripción
idstringID de la canalización
estudianteIdstringID del estudiante (para invalidar caché)
estadostringEstado actual de la canalización. Por defecto: PENDIENTE
firmaPadres"on"?Checkbox — indica si los padres firmaron
documentoRecibido"on"?Checkbox — indica si se recibió documentación de la institución
tipoDocumentostring?Tipo de documento recibido
notasstring?Notas de seguimiento

actualizarNivelRiesgo

export async function actualizarNivelRiesgo(
  estudianteId: string,
  nivelRiesgo: number | null
): Promise<void>
Actualiza el nivel de riesgo clínico manual (escala 1–10) en el expediente del estudiante. Usa upsert — crea el expediente si no existe.

Ejemplo

import { actualizarNivelRiesgo } from "@/lib/actions/canalizacion"

await actualizarNivelRiesgo("cm1abc123", 8)
// Para limpiar el nivel de riesgo:
await actualizarNivelRiesgo("cm1abc123", null)

Modelo de datos: Canalizacion

CampoTipoDescripción
idStringCUID autogenerado
estudianteIdStringFK al estudiante
institucionStringNombre de la institución
tipoInstitucionTipoInstitucionPUBLICA o PRIVADA
tipoAtencionString?Tipo de atención requerida
motivoStringMotivo de la canalización
nivelRiesgoInt?Nivel de riesgo 1–10
urgenteBooleanSi es urgente (por defecto false)
fechaDateTimeFecha de registro (automática)
estadoEstadoCanalizacionEstado del proceso
notasString?Notas adicionales
firmaPadresBooleanSi los padres firmaron el consentimiento
documentoRecibidoBooleanSi se recibió documentación
tipoDocumentoString?Tipo de documento recibido
fechaDocumentoDateTime?Fecha en que se recibió el documento

EstadoCanalizacion

ValorDescripción
PENDIENTECanalización registrada, sin iniciar proceso
EN_PROCESOEn proceso de atención externa
COMPLETADAAtención externa completada
SIN_SEGUIMIENTOSin respuesta o seguimiento posible

Acciones de contacto con padres

registrarContacto

export async function registrarContacto(
  _prev: ContactoResult,
  formData: FormData
): Promise<ContactoResult>
Registra un intento de contacto con los padres o tutores del estudiante.

Campos del FormData

CampoTipoDescripción
estudianteIdstringID del estudiante
tipostringTipo de contacto — ver TipoContacto
resultadostringResultado del contacto — ver ResultadoContacto
notasstring?Notas adicionales

Retorno

export type ContactoResult = { error?: string; ok?: boolean }

Ejemplo

import { registrarContacto } from "@/lib/actions/contacto"
import { useActionState } from "react"

function FormularioContacto({ estudianteId }: { estudianteId: string }) {
  const [state, formAction] = useActionState(registrarContacto, {})

  return (
    <form action={formAction}>
      <input type="hidden" name="estudianteId" value={estudianteId} />
      <select name="tipo">
        <option value="LLAMADA">Llamada</option>
        <option value="MENSAJE_TEXTO">Mensaje de texto</option>
        <option value="CONTACTO_POR_ALUMNO">Contacto por el alumno</option>
        <option value="CITA_PADRES">Cita de padres</option>
      </select>
      <select name="resultado">
        <option value="CONTESTO">Contestó</option>
        <option value="NO_CONTESTO">No contestó</option>
        <option value="MENSAJE_ENVIADO">Mensaje enviado</option>
        <option value="SIN_RESPUESTA">Sin respuesta</option>
        <option value="ACUDIO">Acudió</option>
        <option value="NO_ACUDIO">No acudió</option>
      </select>
      <textarea name="notas" />
      {state.error && <p>{state.error}</p>}
      <button type="submit">Registrar contacto</button>
    </form>
  )
}

eliminarContacto

export async function eliminarContacto(
  id: string,
  estudianteId: string
): Promise<void>
Elimina un registro de contacto. Si el ID no existe, la operación falla silenciosamente (usa .catch(() => {})). Invalida la caché del expediente.

Ejemplo

import { eliminarContacto } from "@/lib/actions/contacto"

await eliminarContacto("cm1contacto999", "cm1abc123")

Modelo de datos: ContactoPadres

CampoTipoDescripción
idStringCUID autogenerado
estudianteIdStringFK al estudiante
fechaDateTimeFecha del contacto (automática)
tipoTipoContactoMedio de contacto utilizado
resultadoResultadoContactoResultado del intento de contacto
notasString?Notas adicionales

TipoContacto

ValorDescripción
LLAMADALlamada telefónica
MENSAJE_TEXTOMensaje de texto (SMS o WhatsApp)
CONTACTO_POR_ALUMNOMensaje entregado a través del alumno
CITA_PADRESCita presencial de padres

ResultadoContacto

ValorDescripción
CONTESTOEl padre o tutor contestó
NO_CONTESTONo contestó la llamada
MENSAJE_ENVIADOMensaje enviado sin confirmación de lectura
SIN_RESPUESTASin respuesta al mensaje
ACUDIOAcudió a la cita de padres
NO_ACUDIONo acudió a la cita de padres

Build docs developers (and LLMs) love