Files
formularios_front/src/context/formulario/formulario-reducer.ts
T
miguel d3e1441f87 feat: add bulk user upload functionality and form success page
- Implemented bulk upload for students and workers with file validation and error handling.
- Added Excel template download feature for user uploads.
- Created success page for form submissions with QR code display.
- Established context and reducer for form state management, including user search and response handling.
- Added mermaid diagrams for event registration documentation.
2026-03-08 19:18:23 -06:00

153 lines
4.3 KiB
TypeScript

import { GetCuestionario } from '@/types/evento';
import { UsuarioDataResponse } from '@/containers/formulario/formulario-registro';
export type RespuestaFormulario = Record<string, string | number>;
// ── Estado ──────────────────────────────────────────────────────────────────
export interface FormularioState {
// Datos del cuestionario cargado desde la API
data: GetCuestionario | null;
loadingData: boolean;
errorData: string | null;
// Respuestas del usuario
respuestas: RespuestaFormulario;
// Búsqueda de cuenta/rfc
cuentaBuscada: string;
busquedaCompletada: boolean;
loadingBusqueda: boolean;
errorBusqueda: string | null;
usuarioEncontrado: UsuarioDataResponse | null;
// Envío
isSending: boolean;
}
export const initialState: FormularioState = {
data: null,
loadingData: true,
errorData: null,
respuestas: {},
cuentaBuscada: '',
busquedaCompletada: false,
loadingBusqueda: false,
errorBusqueda: null,
usuarioEncontrado: null,
isSending: false,
};
// ── Acciones ─────────────────────────────────────────────────────────────────
export type FormularioAction =
// Carga del cuestionario
| { type: 'FETCH_DATA_START' }
| { type: 'FETCH_DATA_SUCCESS'; payload: GetCuestionario }
| { type: 'FETCH_DATA_ERROR'; payload: string }
// Respuestas
| { type: 'SET_RESPUESTA'; payload: { id: string; valor: string } }
| { type: 'SET_RESPUESTAS_BULK'; payload: RespuestaFormulario }
| { type: 'LIMPIAR_CAMPOS_AUTORELLENO'; payload: number[] } // ids de pregunta
// Búsqueda de cuenta
| { type: 'BUSQUEDA_START'; payload: string } // cuenta buscada
| { type: 'BUSQUEDA_SUCCESS'; payload: UsuarioDataResponse }
| { type: 'BUSQUEDA_ERROR'; payload: string }
| { type: 'BUSQUEDA_RESET' }
// Envío
| { type: 'SEND_START' }
| { type: 'SEND_END' };
// ── Reducer ──────────────────────────────────────────────────────────────────
export function formularioReducer(
state: FormularioState,
action: FormularioAction
): FormularioState {
switch (action.type) {
// Carga del cuestionario
case 'FETCH_DATA_START':
return { ...state, loadingData: true, errorData: null };
case 'FETCH_DATA_SUCCESS':
return { ...state, loadingData: false, data: action.payload };
case 'FETCH_DATA_ERROR':
return { ...state, loadingData: false, errorData: action.payload };
// Respuestas
case 'SET_RESPUESTA':
return {
...state,
respuestas: { ...state.respuestas, [action.payload.id]: action.payload.valor },
};
case 'SET_RESPUESTAS_BULK':
return {
...state,
respuestas: { ...state.respuestas, ...action.payload },
};
case 'LIMPIAR_CAMPOS_AUTORELLENO': {
const limpio = { ...state.respuestas };
action.payload.forEach((id) => delete limpio[id]);
return { ...state, respuestas: limpio };
}
// Búsqueda
case 'BUSQUEDA_START':
return {
...state,
loadingBusqueda: true,
errorBusqueda: null,
busquedaCompletada: false,
usuarioEncontrado: null,
cuentaBuscada: action.payload,
};
case 'BUSQUEDA_SUCCESS':
return {
...state,
loadingBusqueda: false,
busquedaCompletada: true,
errorBusqueda: null,
usuarioEncontrado: action.payload,
};
case 'BUSQUEDA_ERROR':
return {
...state,
loadingBusqueda: false,
busquedaCompletada: false,
errorBusqueda: action.payload,
usuarioEncontrado: null,
};
case 'BUSQUEDA_RESET':
return {
...state,
cuentaBuscada: '',
busquedaCompletada: false,
loadingBusqueda: false,
errorBusqueda: null,
usuarioEncontrado: null,
};
// Envío
case 'SEND_START':
return { ...state, isSending: true };
case 'SEND_END':
return { ...state, isSending: false };
default:
return state;
}
}