Appearance
Archivos de la Carpeta src/utils
La carpeta src/utils es el hogar de las funciones utilitarias y helpers que no pertenecen directamente a un componente o a un hook específico, pero que son necesarias para realizar operaciones comunes en toda la aplicación. Agrupar estas funciones aquí promueve la reutilización de código y mantiene el resto de la base de código más limpia.
auth.utils.ts
Este archivo contiene funciones de utilidad relacionadas con la autenticación de usuarios, específicamente para interactuar con la API de autenticación del backend.
- Descripción:
auth.utils.tsexporta una función clave,authenticateUser, que maneja el proceso de inicio de sesión enviando las credenciales del usuario al backend y procesando la respuesta de la API. - Propósito: Centralizar la lógica de comunicación con la API de autenticación, separándola de los componentes de la UI y los hooks de estado. Esto facilita el mantenimiento, las pruebas y la reutilización de la lógica de autenticación en diferentes partes de la aplicación.
- Funcionalidad clave:
authenticateUser(email: string, password: string):- Toma el
emaily lapassworddel usuario como argumentos. - Realiza una petición
POSTa la URL de autenticación del backend (construida usandoi).mport.meta.env.VITE_API_BASE_URL - Configura los
headerspara indicar que el cuerpo de la petición esapplication/json. - Envía las credenciales del usuario (
emailypassword) en el cuerpo de la petición, convertidas a formato JSON. - Manejo de Errores: Si la respuesta de la API no es
ok(por ejemplo, si el estado HTTP es 4xx o 5xx), la función parsea el error del JSON de la respuesta y lanza unaErrorcon el mensaje proporcionado por el backend o un "Error desconocido". Esto permite que el componente que llama a esta función capture y maneje el error. - Procesamiento de Respuesta Exitosa: Si la respuesta es
ok, la función parsea el JSON de la respuesta y extrae eltokende autenticación. - Retorno: Devuelve el
tokende autenticación recibido del servidor.
- Toma el
- Rol en la aplicación:
auth.utils.tses un proveedor de servicios para la autenticación. Permite que cualquier parte de la aplicación que necesite iniciar sesión a un usuario lo haga de manera consistente y con el manejo de errores ya integrado, sin necesidad de replicar la lógica defetchyJSON.stringify.
tsx
// src/utils/auth.utils.ts
export const authenticateUser = async (email: string, password: string) => {
const response = await fetch(
`${import.meta.env.VITE_API_BASE_URL}/api/auth`, // URL base de la API y endpoint de autenticación
{
method: "POST", // Método HTTP para el inicio de sesión
headers: { "Content-Type": "application/json" }, // Indica que el cuerpo es JSON
body: JSON.stringify({ email, password }), // Envía las credenciales como JSON
}
);
// Si la respuesta no fue exitosa (ej. estado HTTP 4xx, 5xx)
if (!response.ok) {
const json = await response.json(); // Parsea el cuerpo del error
throw new Error(json.error || "Error desconocido"); // Lanza un error con el mensaje del backend o uno genérico
}
const { token } = await response.json(); // Extrae el token de la respuesta exitosa
return token; // Retorna el token de autenticación
};
fetch.students.ts
Este archivo contiene funciones de utilidad para realizar operaciones CRUD (Crear, Leer, Actualizar, Eliminar) básicas sobre los recursos de estudiantes en la API del backend.
- Descripción:
fetch.students.tsexporta la funciónaddStudentpara registrar nuevos estudiantes yfetchStudentsListpara obtener la lista completa de estudiantes. Ambas funciones manejan la comunicación con la API, la inclusión de tokens de autenticación y el manejo de errores detallado. - Propósito: Centralizar la lógica de comunicación con el endpoint
/api/studentsdel backend. Esto separa las preocupaciones de la lógica de negocio y la presentación de la interfaz de usuario, facilitando el mantenimiento, las pruebas y la reutilización de las operaciones con estudiantes. - Funcionalidad clave:
addStudent(token: string, studentData: FormData):- Toma un
tokende autenticación y un objetostudentData(ahora en formatoFormData) como argumentos. - Realiza una validación inicial del
tokenpara asegurar su presencia. - Ejecuta una petición
POSTal endpoint/api/studentspara crear un nuevo registro de estudiante. - Gestión de
headersparaFormData: La clave aquí es que NO se establece manualmente elContent-Typeaapplication/json. El navegador lo establece automáticamente amultipart/form-datacuando detecta un objetoFormDataen elbody, lo cual es correcto para el envío de formularios con archivos. - Envía
studentData(elFormDatadirectamente) en el cuerpo de la petición. - Manejo de Errores Mejorado: Si la respuesta de la API no es
ok(por ejemplo, si el estado HTTP es 4xx o 5xx), la función intenta parsear el cuerpo del error como JSON. Luego, lanza unErrorcon el mensaje específico del backend (sierrorBody.messageoerrorBody.errorexisten), o un mensaje genérico si no se encuentra un error detallado. Este manejo es crucial para brindar feedback preciso al usuario. - Retorno: Devuelve la respuesta parseada como JSON (presumiblemente el estudiante recién creado o una confirmación de éxito).
- Toma un
fetchStudentsList(token: string):- Toma un
tokende autenticación como argumento. - Realiza una validación inicial del
tokenpara asegurar su presencia. - Ejecuta una petición
GETal endpoint/api/studentspara obtener la lista completa de estudiantes. - Configura los
headersparaapplication/json(ya que una petición GET generalmente espera JSON) y añade elAuthorizationcon eltoken Bearer. - Manejo de Errores: Si la respuesta de la API no es
ok, lanza unErrorcon un mensaje genérico ("Error al obtener los estudiantes. Por favor, intente de nuevo."). - Retorno: Devuelve la lista de estudiantes parseada como JSON.
- Toma un
- Rol en la aplicación:
fetch.students.tsactúa como un adaptador de la API para las operaciones relacionadas con estudiantes. Las funciones que exporta son utilizadas por hooks (comouseStudentsListouseAddStudent) y componentes para interactuar con el backend, manteniendo la lógica de red centralizada y desacoplada del resto de la aplicación.
tsx
// src/utils/fetch.students.ts
import { Student } from "../interface/student/student"; // Importa la interfaz Student (para tipado, aunque no se usa directamente en este archivo)
/**
* Agrega un nuevo estudiante al sistema.
* @param token El token de autenticación del usuario.
* @param studentData Los datos del estudiante a agregar (en formato FormData).
* @returns La respuesta de la API (generalmente el estudiante recién creado).
* @throws Error si el token no es válido o si hay un error en la API.
*/
export const addStudent = async (token: string, studentData: FormData) => {
// Verificar si el token es válido y está presente
if (!token) {
throw new Error("Token no válido o no presente.");
}
const response = await fetch(
`${import.meta.env.VITE_API_BASE_URL}/api/students`,
{
method: "POST", // Método HTTP
headers: {
// ¡IMPORTANTE! NO establecer 'Content-Type' aquí cuando se envía FormData.
// El navegador lo establece automáticamente a 'multipart/form-data; boundary=...'.
Authorization: `Bearer ${token}`, // Mantener la cabecera de autorización
},
body: studentData, // Enviar el FormData directamente como cuerpo de la petición
}
);
// Si la respuesta no es exitosa (estado HTTP 4xx o 5xx), lanza un error
if (!response.ok) {
const errorBody = await response.json(); // Intentar parsear el cuerpo del error como JSON
console.error("Error de la API al agregar estudiante:", errorBody); // Log detallado del error de la API
// Lanzar un error con el mensaje específico del backend si existe, o uno genérico.
throw new Error(
errorBody.message ||
errorBody.error ||
"Error al agregar el estudiante. Por favor, intente de nuevo."
);
}
// Devolver la respuesta en formato JSON si la solicitud fue exitosa
return response.json();
};
/**
* Obtiene la lista completa de estudiantes del sistema.
* @param token El token de autenticación del usuario.
* @returns Un array de objetos Student.
* @throws Error si el token no está presente o si hay un error en la API.
*/
export const fetchStudentsList = async (token: string) => {
// Verificar si el token está presente
if (!token) {
throw new Error("Token de autenticación no proporcionado.");
}
const response = await fetch(
`${import.meta.env.VITE_API_BASE_URL}/api/students`,
{
method: "GET", // Método HTTP
headers: {
"Content-Type": "application/json", // Tipo de contenido esperado para una petición GET
Authorization: `Bearer ${token}`, // Token de autorización
},
}
);
// Si la respuesta no es exitosa, lanza un error
if (!response.ok) {
throw new Error(
"Error al obtener los estudiantes. Por favor, intente de nuevo."
);
}
// Devolver la lista de estudiantes en formato JSON
return await response.json();
};
students.profile.ts
Este archivo contiene funciones de utilidad para realizar operaciones específicas de lectura, actualización y eliminación de un solo perfil de estudiante en la API del backend.
- Descripción:
students.profile.tsexporta tres funciones clave:fetchStudentpara obtener los detalles de un estudiante,updateStudentpara modificar su información, ydeleteStudentpara eliminar un registro de estudiante. Todas estas funciones interactúan con endpoints de la API que requieren el ID de un estudiante específico y un token de autenticación. - Propósito: Centralizar la lógica de comunicación con los endpoints de la API relacionados con la gestión individual de perfiles de estudiantes. Esto separa las preocupaciones de la lógica de red de los componentes de la UI y los hooks, facilitando el mantenimiento y la prueba de estas operaciones.
- Funcionalidad clave:
fetchStudent(id: string, token: string):- Toma el
iddel estudiante y untokende autenticación. - Realiza una petición
GETa la URL del estudiante específico (/api/students/${id}). - Incluye los
headersnecesarios, incluyendo elAuthorizationcon eltoken Bearer. - Manejo de Errores Mejorado: Si la respuesta de la API no es
ok, la función intenta parsear el cuerpo del error como JSON y lanza unErrorcon un mensaje específico proporcionado por el backend o un mensaje genérico. - Retorno: Devuelve los datos del estudiante parseados como JSON.
- Toma el
updateStudent(id: string, token: string, updatedData: FormData):- Toma el
iddel estudiante a actualizar, untokende autenticación y losupdatedDatadel estudiante como un objetoFormData. - Realiza una petición
PUTa la URL del estudiante específico (/api/students/${id}). - Incluye solo el
Authorizationheader, permitiendo que el navegador gestione automáticamente elContent-TypeparaFormData. - Envía los
updatedDatacomoFormDatadirectamente en el cuerpo de la petición. - Manejo de Errores Mejorado: Si la respuesta de la API no es
ok, la función intenta parsear el cuerpo del error como JSON y lanza unErrorcon un mensaje específico proporcionado por el backend o un mensaje genérico. - Retorno: Devuelve la respuesta parseada como JSON (generalmente el estudiante actualizado o una confirmación).
- Toma el
deleteStudent(id: string, token: string):- Toma el
iddel estudiante a eliminar y untokende autenticación. - Realiza una petición
DELETEa la URL del estudiante específico (/api/students/${id}). - Configura los
headersparaapplication/jsony añade elAuthorizationcon eltoken Bearer. - Manejo de Errores Mejorado: Si la respuesta de la API no es
ok, la función intenta parsear el cuerpo del error como JSON y lanza unErrorcon un mensaje específico proporcionado por el backend o un mensaje genérico. - Retorno: Devuelve la respuesta parseada como JSON (generalmente una confirmación de eliminación).
- Toma el
- Rol en la aplicación:
students.profile.tssirve como una API Service Layer para las operaciones de un solo estudiante. Estas funciones son utilizadas principalmente por el hookuseStudentProfilepara interactuar con el backend, manteniendo la lógica de la capa de acceso a datos centralizada y desacoplada de la interfaz de usuario.
tsx
// src/utils/students.profile.ts
/**
* Obtiene los datos de un estudiante específico por su ID.
* @param id El ID del estudiante a obtener.
* @param token El token de autenticación del usuario.
* @returns Los datos del estudiante.
* @throws Error si no se pueden obtener los datos del estudiante o si hay un error específico de la API.
*/
export const fetchStudent = async (id: string, token: string) => {
// Realiza una petición GET a la URL del estudiante específico
const response = await fetch(
`${import.meta.env.VITE_API_BASE_URL}/api/students/${id}`,
{
method: "GET", // Método HTTP
headers: {
"Content-Type": "application/json", // Tipo de contenido esperado
Authorization: `Bearer ${token}`, // Token de autorización
},
}
);
// Si la respuesta no es exitosa, lanza un error con un mensaje específico
if (!response.ok) {
const errorBody = await response.json(); // Intenta parsear el cuerpo del error como JSON
console.error(`Error de la API al obtener estudiante ${id}:`, errorBody); // Log detallado del error de la API
// Lanza un error con el mensaje específico del backend si existe, de lo contrario, un mensaje genérico.
throw new Error(
errorBody.message ||
errorBody.error ||
"Error al obtener los datos del estudiante."
);
}
// Devuelve los datos del estudiante en formato JSON
return response.json();
};
/**
* Actualiza los datos de un estudiante existente.
* Esta función está diseñada para aceptar FormData para manejar la subida de archivos
* junto con otros datos del formulario.
* @param id El ID del estudiante a actualizar.
* @param token El token de autenticación del usuario.
* @param updatedData Los datos actualizados del estudiante (FormData).
* @returns Los datos del estudiante actualizados.
* @throws Error si no se puede actualizar el estudiante o si hay un error específico de la API.
*/
export const updateStudent = async (
id: string,
token: string,
updatedData: FormData // Ahora acepta FormData directamente
) => {
// Realiza una petición PUT a la URL del estudiante específico
const response = await fetch(
`${import.meta.env.VITE_API_BASE_URL}/api/students/${id}`,
{
method: "PUT", // Método HTTP
headers: {
// Para FormData, el navegador establece automáticamente el 'Content-Type' con el 'boundary'.
// NO incluyas "Content-Type": "application/json" aquí si envías FormData, ya que lo sobrescribiría incorrectamente.
Authorization: `Bearer ${token}`, // Token de autorización
},
body: updatedData, // Pasa FormData directamente como cuerpo
}
);
// Si la respuesta no es exitosa, lanza un error con un mensaje específico
if (!response.ok) {
const errorBody = await response.json(); // Intenta parsear el cuerpo del error como JSON
console.error(`Error de la API al actualizar estudiante ${id}:`, errorBody); // Log detallado
// Lanza un error con el mensaje específico del backend si existe
throw new Error(
errorBody.message ||
errorBody.error ||
"Error al actualizar el estudiante."
);
}
// Devuelve los datos del estudiante actualizados en formato JSON
return response.json();
};
/**
* Elimina un estudiante del sistema.
* @param id El ID del estudiante a eliminar.
* @param token El token de autenticación del usuario.
* @returns Una confirmación de la eliminación.
* @throws Error si no se puede eliminar el estudiante o si hay un error específico de la API.
*/
export const deleteStudent = async (id: string, token: string) => {
// Realiza una petición DELETE a la URL del estudiante específico
const response = await fetch(
`${import.meta.env.VITE_API_BASE_URL}/api/students/${id}`,
{
method: "DELETE", // Método HTTP
headers: {
"Content-Type": "application/json", // Tipo de contenido esperado
Authorization: `Bearer ${token}`, // Token de autorización
},
}
);
// Si la respuesta no es exitosa, lanza un error con un mensaje específico
if (!response.ok) {
const errorBody = await response.json(); // Intenta parsear el cuerpo del error como JSON
console.error(`Error de la API al eliminar estudiante ${id}:`, errorBody); // Log detallado
// Lanza un error con el mensaje específico del backend si existe
throw new Error(
errorBody.message || errorBody.error || "Error al eliminar el estudiante."
);
}
// Devuelve la respuesta (ej. un mensaje de éxito o confirmación) en formato JSON
return response.json();
};
constants.ts
Este archivo es el repositorio central para valores constantes y datos estáticos que se utilizan en múltiples partes de la aplicación. Su propósito es evitar la duplicación de datos y asegurar que, si un valor necesita ser cambiado, se haga en un único lugar.
- Descripción:
constants.tsexporta la constanteallFeedbacks, que contiene una lista exhaustiva de todas las posibles opciones de retroalimentación o estado de un estudiante. - Propósito: Centralizar la definición de valores inmutables que son compartidos a través de varios componentes o lógicas de la aplicación. Esto mejora la consistencia de los datos, facilita el mantenimiento y la actualización, y reduce la probabilidad de errores por inconsistencias.
- Funcionalidad clave:
allFeedbacks: Un array destringque define todos los estados de retroalimentación posibles para los estudiantes. Estos valores se utilizan, por ejemplo, en selectores de filtro, en la lógica de normalización de estadísticas (como enstatistics.tsx), o en cualquier lugar donde se necesite una lista fija de estos estados.
- Rol en la aplicación:
constants.tsactúa como una fuente de verdad única para datos estáticos comunes. Ayuda a mantener el código DRY (Don't Repeat Yourself) y asegura que las lógicas de negocio que dependen de listas fijas de opciones siempre trabajen con los mismos valores definidos.
typescript
// src/utils/constants.ts
// Array constante que define todas las posibles opciones de retroalimentación
// o estado para los estudiantes.
export const allFeedbacks = [
"AÚN SIN RESPUESTAS",
"NO SE MATRICULARÁ",
"INCONTACTABLE",
"PERSONA INTERESADA QUE ENVIARÁ DOCUMENTACIÓN",
"PERSONA QUE ENVIÓ DOCUMENTACIÓN PERO LE FALTA FIRMAR SU MATRÍCULA",
"PERSONA QUE IRÁ A MATRICULARSE DIRECTAMENTE A LA ESCUELA",
"PERSONA CON DOCUMENTACIÓN Y MATRÍCULA FIRMADA EN ESCUELA",
"INTERESADA PARA PRÓXIMO AÑO",
"PERSONA QUE ENVÍA DOCUMENTACIÓN Y SE DEBE TRASLADAR A OTRA PLANILLA",
];
// Opciones para el campo Género
export const GENDER_OPTIONS = ["", "MASCULINO", "FEMENINO", "OTROS"];
// Opciones para el campo Fuente
export const SOURCE_OPTIONS = ["", "REDES SOCIALES", "CAPTADOR"];
// Opciones para el campo Escuela
export const SCHOOL_OPTIONS = [
"",
"QUINTA NORMAL",
"BUÍN",
"LA GRANJA",
"ÑUÑOA",
"PUDAHUEL",
"SAN MIGUEL",
];
// Opciones para el campo Curso
export const COURSE_OPTIONS = [
"",
"1° NIVEL BÁSICO",
"2° NIVEL BÁSICO",
"3° NIVEL BÁSICO",
"1° NIVEL MEDIO",
"2° NIVEL MEDIO",
];
// Opciones para el campo Contacto (Quién realizó el contacto)
export const CONTACT_PERSON_OPTIONS = [
"",
"LORENA",
"ARLETTE",
"MARÍA",
"ROWINA",
];
// Opciones para el campo Preferencia de Comunicación
export const COMMUNICATION_PREFERENCE_OPTIONS = ["", "WHATSAPP", "TELÉFONO"];
// Opciones para los campos de Llamada completada (SÍ/NO)
export const CALL_STATUS_OPTIONS = ["", "SÍ", "NO"];
// NUEVA CONSTANTE para la altura de los ítems del dropdown
export const DROPDOWN_ITEM_HEIGHT_PX = 40;
student.form.mapper.ts
Este archivo contiene una función de utilidad clave, mapStudentToFormData, que se encarga de transformar un objeto de datos de estudiante (que puede incluir información y archivos) en un formato FormData. Este formato es esencial para enviar datos a un backend que espera la codificación multipart/form-data, común para la subida de archivos.
- Descripción:
mapStudentToFormDataes una función utilitaria que toma un objetoStudent(o un parcial de él) y lo convierte en una instancia deFormData. Esta función maneja inteligentemente diferentes tipos de datos, incluyendo la identificación de nuevos archivos, la preservación de URLs de archivos existentes y la señalización de archivos para eliminación. - Propósito: Centralizar la lógica compleja de construcción de
FormDatapara las operaciones de actualización o creación de estudiantes que implican archivos. Esto desacopla esta lógica de manipulación de datos de los hooks y componentes de la UI, haciendo el código más limpio, mantenible y reutilizable. - Funcionalidad clave:
mapStudentToFormData(studentData: Partial<Student>):- Toma un objeto
studentDatade tipoPartial<Student>, lo que significa que puede aceptar un objetoStudentcompleto o solo algunas de sus propiedades. - Crea una nueva instancia de
FormData. - Iteración y Mapeo de Campos: Recorre cada par clave-valor del
studentDatade entrada y aplica una lógica condicional para determinar cómo añadirlo alFormData:- Archivos a Eliminar (
null): Si un valor esnully la clave corresponde a un campo de archivo (ej.,studentImage,birthCertificate), se añade un marcador especial (ej.,${key}_delete: "true") alFormData. Esto indica al backend que el archivo asociado debe ser eliminado. - Nuevos Archivos (
Fileinstances): Si un valor es una instancia deFile(indicando que se ha subido un nuevo archivo), se añade directamente alFormDatacon su clave original. - URLs de Archivos Existentes (
stringempezando con "http"): Si un valor es una cadena que representa una URL de un archivo existente, se añade un marcador (ej.,${key}_url: "la_url_existente") alFormData. Esto le dice al backend que mantenga el archivo previamente subido si no ha sido reemplazado o marcado para eliminación. - Otros Datos (
string,number,boolean, etc.): Cualquier otro valor primitivo o tipo simple se convierte astringy se añade alFormData. Los valoresundefinedse omiten, lo cual es el comportamiento estándar para campos opcionales no definidos.
- Archivos a Eliminar (
- Retorno: Devuelve el objeto
FormDatacompletamente construido, listo para ser utilizado en una peticiónfetch.
- Toma un objeto
- Rol en la aplicación:
student.form.mapper.tsactúa como un transformador de datos para las operaciones de la API. Permite que los hooks de negocio (comouseStudentProfile) trabajen con objetosStudenttipados, y luego convierte estos objetos en el formato específico (FormData) que el backend espera para las peticiones con archivos.
tsx
// src/utils/student.form.mapper.ts
import type { Student } from "../interface/student/student"; // Importa la interfaz Student (como tipo)
/**
* Convierte un objeto Student (o un objeto parcial de Student) en un objeto FormData.
* Esto es útil para enviar datos que pueden incluir archivos a una API que espera `multipart/form-data`.
* @param studentData Los datos del estudiante a mapear. Puede ser un objeto Student completo o parcial.
* @returns Un objeto FormData listo para ser enviado en una petición HTTP.
*/
export const mapStudentToFormData = (
studentData: Partial<Student>
): FormData => {
const formData = new FormData();
// Itera sobre todas las entradas (clave-valor) de los datos del estudiante proporcionados.
Object.entries(studentData).forEach(([key, value]) => {
// Caso 1: El valor es `null`. Esto generalmente indica que un archivo existente debe ser eliminado.
// Se añade un campo con el sufijo '_delete' para que el backend lo interprete.
if (value === null) {
// Se comprueba si la clave corresponde a un campo que podría ser un archivo.
if (
[
"studentImage",
"birthCertificate",
"studyCertificate",
"linkDni",
].includes(key)
) {
formData.append(`${key}_delete`, "true");
}
}
// Caso 2: El valor es una instancia de `File`. Esto indica un nuevo archivo que se va a subir.
// Se añade directamente al FormData.
else if (value instanceof File) {
formData.append(key, value);
}
// Caso 3: El valor es una cadena de texto que parece una URL de un archivo existente.
// Esto se usa para decirle al backend que mantenga el archivo original, si no ha cambiado.
else if (
typeof value === "string" &&
[
"studentImage",
"birthCertificate",
"studyCertificate",
"linkDni",
].includes(key) &&
value.startsWith("http") // Heurística: asumimos que las URLs existentes comienzan con "http"
) {
formData.append(`${key}_url`, value);
}
// Caso 4: Cualquier otro valor que no sea un objeto complejo o `undefined`.
// Esto cubre strings, números, booleanos, enums, etc.
else if (typeof value !== "object" && value !== undefined) {
formData.append(key, String(value)); // Se convierte a string para añadirlo al FormData
}
// Los valores `undefined` se omiten por defecto, lo cual es el comportamiento deseado
// para campos opcionales que no se han establecido.
});
return formData;
};
date.formatters.ts
Este archivo contiene una función de utilidad clave, formatDateForInput, diseñada para estandarizar el formato de las fechas para su uso en los inputs HTML de tipo date.
- Descripción:
formatDateForInputes una función pura que toma un valor de fecha en diferentes formatos (cadena, objetoDate, oundefined) y lo convierte a una cadena con el formatoyyyy-MM-dd. Este formato es crucial porque los elementos<input type="date">de HTML requieren este formato específico para funcionar correctamente. La función utiliza la potente libreríaluxonpara manejar el parseo y formateo de fechas. - Propósito: Asegurar que los valores de fecha se muestren y se procesen de manera uniforme en los formularios de la interfaz de usuario, independientemente de cómo se almacenen internamente las fechas. Esto previene errores de formato y mejora la experiencia del usuario.
- Funcionalidad clave:
formatDateForInput(date: string | Date | undefined)Función:- Toma un parámetro
dateque puede ser una cadena de texto, un objetoDateoundefined. - Manejo de entradas vacías: Si
dateesnull,undefinedo una cadena vacía, la función retorna una cadena vacía (""), lo que es adecuado para los inputs de fecha HTML. - Formato
yyyy-MM-ddya existente: Realiza una comprobación inicial usando una expresión regular (/^\d{4}-\d{2}-\d{2}$/.test(date)) para ver si la cadena ya está en el formatoyyyy-MM-dd. Si es así, la retorna directamente sin procesarla. - Objetos
Date: Sidatees una instancia deDate, utilizaDateTime.fromJSDate()deluxonpara convertirlo y luego lo formatea ayyyy-MM-dd. - Cadenas de fecha ISO o de otro formato: Si
datees una cadena,luxon(DateTime.fromISO(date)) intenta parsearla como una fecha en formato ISO. Si el parseo es válido, la fecha se formatea ayyyy-MM-dd. - Retorno de Fallback: Si ningún formato coincide o la fecha es inválida, la función retorna una cadena vacía (
"").
- Toma un parámetro
- Rol en la aplicación:
date.formatters.tsactúa como una herramienta de transformación de datos a nivel de la interfaz de usuario. Al centralizar la lógica de formato de fechas, permite que los componentes de formulario (comoAddStudentFormoUpdateStudentForm) se mantengan limpios y legibles, delegando la complejidad del manejo de fechas a esta utilidad dedicada.
tsx
// src/utils/date.formatters.ts
import { DateTime } from "luxon"; // Importa la librería Luxon para manejo de fechas y tiempos
/**
* Formatea un valor de fecha a una cadena "yyyy-MM-dd" para inputs HTML.
* Este formato es el estándar esperado por los elementos `<input type="date">`.
* @param date La fecha a formatear. Puede ser de tipo `string`, `Date`, o `undefined`.
* @returns La fecha formateada como string "yyyy-MM-dd", o una cadena vacía si la entrada es inválida o nula.
*/
export const formatDateForInput = (date: string | Date | undefined): string => {
// Si la fecha es nula, indefinida o una cadena vacía, retorna una cadena vacía.
if (!date) return "";
// Si la entrada ya es una cadena en el formato "yyyy-MM-dd", la retorna directamente
// para evitar procesamientos innecesarios y posibles cambios de zona horaria.
if (typeof date === "string" && /^\d{4}-\d{2}-\d{2}$/.test(date)) {
return date;
}
// Si la entrada es una instancia del objeto Date nativo de JavaScript,
// la convierte a un objeto Luxon DateTime y luego la formatea.
if (date instanceof Date) {
return DateTime.fromJSDate(date).toFormat("yyyy-MM-dd");
}
// Si la entrada es una cadena (y no fue capturada por el test anterior de yyyy-MM-dd),
// intenta parsearla como una fecha ISO. Si es válida, la formatea.
// La aserción 'as string' es segura aquí ya que el typeof 'string' lo garantiza.
if (typeof date === "string" && DateTime.fromISO(date as string).isValid) {
return DateTime.fromISO(date as string).toFormat("yyyy-MM-dd");
}
// Si ninguno de los formatos anteriores coincide o la fecha es inválida,
// retorna una cadena vacía como valor por defecto.
return "";
};