Introducción
En este tutorial, construiremos una aplicación de Gestión de Recursos Humanos con el Marco de Refine y la desplegaremos en la Plataforma de Aplicaciones de DigitalOcean.
Al final de este tutorial, tendremos una aplicación de gestión de recursos humanos que incluirá:
- Página de inicio de sesión: Permite a los usuarios iniciar sesión como gerente o empleado. Los gerentes tienen acceso a las páginas de
Días Libres
ySolicitudes
, mientras que los empleados solo tienen acceso a la página deDías Libres
. - Páginas de Días Libres: Permite a los empleados solicitar, ver y cancelar sus días libres. Además, los gerentes pueden asignar nuevos días libres.
- Página de Solicitudes: Accesible solo para los gerentes de Recursos Humanos para aprobar o rechazar las solicitudes de días libres.
Nota: Puedes obtener el código fuente completo de la aplicación que construiremos en este tutorial desde este repositorio de GitHub
Mientras hacemos esto, utilizaremos:
- API REST: Para obtener y actualizar los datos. Refine tiene paquetes de proveedores de datos y API REST integrados, pero también puedes construir los tuyos para adaptarlos a tus requisitos específicos. En esta guía, vamos a utilizar NestJs CRUD como nuestro servicio backend y el paquete @refinedev/nestjsx-crud como nuestro proveedor de datos.
- Material UI: Lo utilizaremos para los componentes de la interfaz de usuario y lo personalizaremos completamente según nuestro propio diseño. Refine tiene soporte integrado para Material UI, pero puedes utilizar cualquier biblioteca de interfaz de usuario que desees.
Una vez que hayamos construido la aplicación, la pondremos en línea utilizando la Plataforma de Aplicaciones de DigitalOcean, que facilita la configuración, el lanzamiento y el crecimiento de aplicaciones y sitios web estáticos. Puedes implementar código simplemente apuntando a un repositorio de GitHub y dejar que la Plataforma de Aplicaciones se encargue de la infraestructura, los tiempos de ejecución de la aplicación y las dependencias.
Requisitos previos
- Un entorno de desarrollo local para Node.js. Puedes seguir el tutorial sobre cómo instalar Node.js y crear un entorno de desarrollo local.
- Algunos conocimientos preliminares de React y TypeScript. Puedes seguir la serie Cómo codificar en React.js y Usar TypeScript con React.
- Una cuenta de GitHub
- Una cuenta de DigitalOcean
¿Qué es Refine?
Refine es un metaframework de React de código abierto para construir aplicaciones web B2B complejas, principalmente enfocado en casos de uso de gestión de datos como herramientas internas, paneles de administración y tableros. Está diseñado para proporcionar un conjunto de ganchos y componentes que mejoren el proceso de desarrollo con un mejor flujo de trabajo para el desarrollador.
Ofrece características completas y listas para producción para aplicaciones de nivel empresarial con el fin de simplificar tareas pagas como la gestión de estado y datos, la autenticación y el control de acceso. Esto permite a los desarrolladores mantenerse enfocados en el núcleo de su aplicación de una manera que está abstracta de muchos detalles de implementación abrumadores.
Paso 1: Configurar el Proyecto
Usaremos el comando npm create refine-app
para inicializar el proyecto de forma interactiva.
Selecciona las siguientes opciones cuando se te solicite:
Una vez que la configuración esté completa, navega hasta la carpeta del proyecto y inicia tu aplicación con:
Abre http://localhost:5173
en tu navegador para ver la aplicación.
Preparando el Proyecto
Ahora que tenemos nuestro proyecto configurado, hagamos algunos cambios en la estructura del proyecto y eliminemos los archivos innecesarios.
Primero, instala las dependencias de terceros:
@mui/x-date-pickers
,@mui/x-date-pickers-pro
: Estos son componentes de selector de fecha para Material UI. Los usaremos para seleccionar el rango de fechas para las solicitudes de tiempo libre.react-hot-toast
: Una biblioteca de toasts minimalista para React. La usaremos para mostrar mensajes de éxito y error.react-infinite-scroll-component
: Un componente de React para facilitar el scroll infinito. Lo usaremos para cargar más solicitudes de tiempo libre a medida que el usuario hace scroll hacia abajo en la página para ver más solicitudes.dayjs
: Una biblioteca de fechas liviana para analizar, validar, manipular y formatear fechas.vite-tsconfig-paths
: Un plugin de Vite que te permite usar alias de rutas TypeScript en tu proyecto Vite.
Después de instalar las dependencias, actualiza vite.config.ts
y tsconfig.json
para usar el plugin vite-tsconfig-paths
. Esto habilita los alias de ruta de TypeScript en los proyectos de Vite, permitiendo importaciones con el alias @
.
A continuación, eliminemos los archivos y carpetas innecesarios:
src/contexts
: Esta carpeta contiene un solo archivo que esColorModeContext
. Maneja el modo oscuro/claro para la aplicación. No lo usaremos en este tutorial.src/components
: Esta carpeta contiene el componente<Header />
. Usaremos un componente de encabezado personalizado en este tutorial.
Después de eliminar los archivos y carpetas, App.tsx
arroja un error que resolveremos en los próximos pasos.
A lo largo del tutorial, cubriremos la codificación de las páginas y componentes principales. Así que, obtén los archivos y carpetas necesarios del repositorio de GitHub. Con estos archivos, tendremos una estructura básica para nuestra aplicación de Gestión de Recursos Humanos.
- íconos: Carpeta de íconos que contiene todos los íconos de la aplicación.
- tipos:
index.ts
: Tipos de la aplicación.
- utilidades:
constants.ts
: Constantes de la aplicación.axios.ts
: Instancia de Axios para solicitudes API, gestionando tokens de acceso, tokens de refresco y errores.init-dayjs.ts
: Inicializa Day.js con los plugins requeridos.
- proveedores:
access-control
: Gestiona los permisos de usuario utilizandoaccessControlProvider
; controla la visibilidad de la página deRequests
según el rol del usuario.auth-provider
: Gestiona la autenticación conauthProvider
; asegura que todas las páginas estén protegidas y requieran inicio de sesión.notification-provider
: Muestra mensajes de éxito y error a través dereact-hot-toast
.query-client
: Cliente de consulta personalizado para un control y personalización completos.theme-provider
: Gestiona el tema de Material UI.
- componentes:
layout
: Componentes de diseño.loading-overlay
: Muestra una superposición de carga durante la obtención de datos.input
: Renderiza campos de entrada de formulario.frame
: Componente personalizado que añade bordes, títulos e íconos a secciones de la página.modal
: Componente de diálogo modal personalizado.
Después de copiar los archivos y carpetas, la estructura de archivos debería verse así:
└── 📁src
└── 📁components
└── 📁frame
└── 📁input
└── 📁layout
└── 📁header
└── 📁page-header
└── 📁sider
└── 📁loading-overlay
└── 📁modal
└── 📁icons
└── 📁providers
└── 📁access-control
└── 📁auth-provider
└── 📁notification-provider
└── 📁query-client
└── 📁theme-provider
└── 📁types
└── 📁utilities
└── App.tsx
└── index.tsx
└── vite-env.d.ts
A continuación, actualiza el archivo App.tsx
para incluir los proveedores y componentes necesarios.
Desglosemos los cambios importantes que hicimos en el archivo App.tsx
:
<Refine />
: El componente principal de@refinedev/core
que envuelve toda la aplicación para proporcionar recuperación de datos, gestión de estado y otras características.<DevtoolsProvider />
y<DevtoolsPanel />
: Utilizados para depuración y propósitos de desarrollo.<ThemeProvider />
: Aplica una personalización del tema a través de la aplicación.- Inicializando Day.js: Para la manipulación de fechas y horas.
- recursos: Un array que especifica las entidades de datos (
empleado
ygerente
) que Refine obtendrá. Usamos recursos padre e hijo para organizar los datos y gestionar permisos. Cada recurso tiene unscope
que define el rol del usuario, lo que controla el acceso a diferentes partes de la aplicación. - queryClient: Un cliente de consulta personalizado para un control y personalización completos de la obtención de datos.
- syncWithLocation: Permite sincronizar el estado de la aplicación (filtros, ordenamientos, paginación, etc.) con la URL.
- warnWhenUnsavedChanges: Muestra una advertencia cuando el usuario intenta navegar fuera de una página con cambios no guardados.
<Layout />
: Un componente de diseño personalizado que envuelve el contenido de la aplicación. Contiene el encabezado, la barra lateral y el área de contenido principal. Explicaremos este componente en los siguientes pasos.
Ahora estamos listos para comenzar a construir la aplicación de gestión de recursos humanos.
Paso 2— Personalización y estilo
Examina más de cerca el theme-provider
. Hemos personalizado en gran medida el tema de Material UI para que coincida con el diseño de la aplicación de gestión de recursos humanos, creando dos temas, uno para gerentes y otro para empleados, para diferenciarlos con diferentes colores.
Además, hemos añadido Inter como fuente personalizada para la aplicación. Para instalar, necesitas añadir la siguiente línea al archivo index.html
:
Inspección personalizada <Layout />
Componente
En el paso anterior, agregamos un componente de diseño personalizado a la aplicación. Normalmente, podríamos usar el diseño predeterminado del marco de trabajo de la interfaz de usuario, pero queremos mostrar cómo puedes personalizarlo.
El componente de diseño contiene el encabezado, la barra lateral y el área de contenido principal. Utiliza <ThemedLayoutV2 />
como base y lo personalizó para que coincida con el diseño de la aplicación de Gestión de RRHH.
<Sider />
La barra lateral contiene el logotipo de la aplicación y enlaces de navegación. En los dispositivos móviles, es una barra lateral colapsable que se abre cuando el usuario hace clic en el ícono de menú. Los enlaces de navegación se preparan con el useMenu
hook de Refine y se renderizan según el rol del usuario con la ayuda del componente <CanAccess />
.
<UserSelect />
Montado en la barra lateral, muestra el avatar y el nombre del usuario conectado. Al hacer clic, se abre un popover con los detalles del usuario y un botón de cierre de sesión. Los usuarios pueden cambiar entre diferentes roles seleccionando del menú desplegable. Este componente permite probar cambiando entre usuarios con diferentes roles.
<Header />
No renderiza nada en dispositivos de escritorio. En dispositivos móviles, muestra el logotipo de la aplicación y un ícono de menú para abrir la barra lateral. El encabezado es fijo y siempre visible en la parte superior de la página.
<PageHeader />
Esto muestra el título de la página y los botones de navegación. El título de la página se genera automáticamente con el useResource
hook, que obtiene el nombre del recurso del contexto de Refine. Esto nos permite compartir el mismo estilo y diseño en toda la aplicación.
Paso 3 — Implementación de la Autenticación y Autorización
En este paso, implementaremos la lógica de autenticación y autorización para nuestra aplicación de Gestión de Recursos Humanos. Esto servirá como un gran ejemplo de control de acceso en aplicaciones empresariales.
Cuando los usuarios inicien sesión como gerentes, podrán ver las páginas de Tiempo Libre
y Solicitudes
. Si inician sesión como empleados, solo verán la página de Tiempo Libre
. Los gerentes pueden aprobar o rechazar las solicitudes de tiempo libre en la página de Solicitudes
.
Los empleados pueden solicitar tiempo libre y ver su historial en la página de Time Off
. Para implementar esto, utilizaremos las funciones authProvider
y accessControlProvider
de Refine.
Autenticación
En Refine, la autenticación es manejada por el authProvider
. Te permite definir la lógica de autenticación para tu aplicación. En el paso anterior, ya copiamos el authProvider
del repositorio de GitHub y lo pasamos como una propiedad al componente <Refine />
. Utilizaremos los siguientes hooks y componentes para controlar el comportamiento de nuestra aplicación según si el usuario ha iniciado sesión o no.
useLogin
: Un hook que proporciona una funciónmutate
para iniciar sesión en el usuario.useLogout
: Un hook que proporciona una funciónmutate
para cerrar sesión en el usuario.useIsAuthenticated
: Un gancho que devuelve un booleano que indica si el usuario está autenticado.<Authenticated />
: Un componente que renderiza sus hijos solo si el usuario está autenticado.
Autorización
En Refine, la autorización se maneja mediante el accessControlProvider
. Te permite definir roles y permisos de usuario, y controlar el acceso a diferentes partes de la aplicación según el rol del usuario. En el paso anterior, ya copiamos el accessControlProvider
del repositorio de GitHub y se lo pasamos al componente <Refine />
como una propiedad. Veamos más de cerca el accessControlProvider
para ver cómo funciona.
En nuestra aplicación, tenemos dos roles: GERENTE
y EMPLEADO
.
Los gerentes tienen acceso a la página de Solicitudes
, mientras que los empleados solo tienen acceso a la página de Días libres
. El accessControlProvider
verifica el rol del usuario y el alcance del recurso para determinar si el usuario puede acceder al recurso. Si el rol del usuario coincide con el alcance del recurso, puede acceder al recurso. De lo contrario, se le niega el acceso. Usaremos el useCan
hook y el <CanAccess />
componente para controlar el comportamiento de nuestra aplicación en función del rol del usuario.
Configurando la Página de Inicio de Sesión
En el paso anterior, agregamos el authProvider
al componente <Refine />
. El authProvider
es responsable de manejar la autenticación.
Primero, necesitamos obtener imágenes. Usaremos estas imágenes como imágenes de fondo para la página de inicio de sesión. Crea una nueva carpeta llamada images
en la carpeta public
y obtén las imágenes del repositorio de GitHub.
Después de obtener las imágenes, vamos a crear un nuevo archivo llamado index.tsx
en la carpeta src/pages/login
y agregar el siguiente código:
Para simplificar el proceso de autenticación, hemos creado un objeto mockUsers
con dos arreglos: managers
y employees
. Cada arreglo contiene objetos de usuario predefinidos. Cuando un usuario selecciona un correo electrónico del menú desplegable y hace clic en el botón Iniciar sesión
, se llama a la función login
con el correo electrónico seleccionado. La función login
es una función de mutación proporcionada por el hook useLogin
de Refine. Llama a authProvider.login
con el correo electrónico seleccionado.
A continuación, importemos el componente <PageLogin />
y actualicemos el archivo App.tsx
con los cambios destacados.
En el archivo App.tsx
actualizado, hemos añadido el componente <Authenticated />
de Refine. Este componente se utiliza para proteger rutas que requieren autenticación. Toma una prop key
para identificar de manera única el componente, una prop fallback
para renderizar cuando el usuario no está autenticado, y una prop redirectOnFail
para redirigir al usuario a la ruta especificada cuando la autenticación falla. En el fondo, llama al método authProvider.check
para verificar si el usuario está autenticado.
Veamos más de cerca lo que tenemos en key="auth-pages"
<Authenticated />
componente envuelve la ruta “/login” para verificar el estado de autenticación del usuario.
fallback={<Outlet />}
: Si el usuario no está autenticado, renderiza la ruta anidada (es decir, muestra el componente<PageLogin />
).- Children (
<Navigate to="/" />
): Si el usuario está autenticado, redirígelo a la página de inicio (/
).
Veamos más de cerca lo que tenemos en key="catch-all"
<Authenticated />
componente envuelve la ruta path="*"
para verificar el estado de autenticación del usuario. Esta ruta es una ruta de captura que renderiza el <ErrorComponent />
cuando el usuario está autenticado. Nos permite mostrar una página 404 cuando el usuario intenta acceder a una ruta inexistente.
Ahora, cuando ejecutes la aplicación y navegues a http://localhost:5173/login
, deberías ver la página de inicio de sesión con el menú desplegable para seleccionar al usuario.
En este momento, la página “/” no está haciendo nada. En los próximos pasos implementaremos las páginas Time Off
y Requests
.
Paso 4 — Construyendo una Página de Tiempo Libre
Página de Lista de Tiempo Libre
En este paso, construiremos la página de Tiempo Libre
. Los empleados pueden solicitar tiempo libre y ver su historial de tiempo libre. Los gerentes también pueden ver su historial, pero en lugar de solicitar tiempo libre, pueden asignárselo directamente a sí mismos. Haremos que esto funcione utilizando el accessControlProvider
de Refine, el componente <CanAccess />
y el hook useCan
.

Antes de comenzar a construir la página de tiempo libre, necesitamos crear un par de componentes para mostrar el historial de tiempo libre, las solicitudes de tiempo libre pendientes y las estadísticas de los tiempos libres utilizados. Al final de este paso, utilizaremos estos componentes para construir la página de tiempo libre.
Construyendo el componente <TimeOffList />
para mostrar el historial de tiempo libre
Crea una nueva carpeta llamada time-offs
en la carpeta src/components
. Dentro de la carpeta time-offs
, crea un nuevo archivo llamado list.tsx
y agrega el siguiente código:
El archivo list.tsx
es extenso, pero la mayor parte trata sobre estilos y presentación de la interfaz de usuario.

Utilizaremos este componente <TimeOffList />
en tres contextos diferentes:
La propiedad type
determina qué tipo de lista de tiempo libre mostrar:
inReview
: Muestra las solicitudes de tiempo libre que están pendientes de aprobación.upcoming
: Muestra los próximos tiempos libres que han sido aprobados pero aún no han ocurrido.history
: Enumera los tiempos libres que han sido aprobados y que ya han tenido lugar.
Dentro del componente, crearemos filtros y ordenadores basados en la propiedad type
. Utilizaremos estos filtros y ordenadores para obtener los datos de tiempo libre de la API.
Vamos a analizar las partes clave del componente:
1. Obteniendo el Usuario Actual
useGetIdentity<Employee>()
: Obtiene la información del usuario actual.- Utilizamos el ID del empleado para filtrar los tiempos libres, de manera que cada usuario vea solo sus solicitudes.
2. Obteniendo los Datos de Tiempo Libre con Desplazamiento Infinito
-
useInfiniteList<TimeOff>()
: Obtiene datos de tiempo libre con desplazamiento infinito.resource
: Especifica el punto final de la API.sorters
yfilters
: Ajustados segúntype
para obtener los datos correctos.employeeId
filtro: Asegura que solo se obtengan los tiempos libres del usuario actual.queryOptions.enabled
: Ejecuta la consulta solo cuando los datos del empleado están disponibles.
-
<InfiniteScroll />
: Permite cargar más datos a medida que el usuario desplaza hacia abajo.next
: Función para obtener la siguiente página de datos.hasMore
: Indica si hay más datos disponibles.
3. Cancelar una solicitud de tiempo libre
useDelete
: Proporciona la funcióntimeOffCancel
para eliminar una solicitud de tiempo libre.- Se utiliza cuando un usuario cancela su tiempo libre.
- Muestra un mensaje de éxito al completarse.
4. Mostrando fechas con <DateField />
<DateField />
: Formatea y muestra fechas de manera amigable para el usuario.value
: La fecha a mostrar.format
: Especifica el formato de la fecha (por ejemplo, “5 de enero”).
5. Creando Filtros y Ordenadores basados en type
Filtros:
- Define criterios para obtener ausencias basadas en estado y fechas.
history
: Obtiene ausencias aprobadas que ya han finalizado.upcoming
: Obtiene ausencias aprobadas que están por venir.
Ordenadores:
- Determina el orden de los datos obtenidos.
history
: Ordena por fecha de inicio en orden descendente.
Construyendo el componente <TimeOffLeaveCards />
para mostrar estadísticas de las ausencias utilizadas.
Crea un nuevo archivo llamado leave-cards.tsx
en la carpeta src/components/time-offs
y añade el siguiente código:

El componente <TimeOffLeaveCards />
muestra estadísticas sobre el tiempo libre de un empleado. Muestra tres tarjetas para Licencia Anual, Licencia por Enfermedad y Licencia Casual, indicando cuántos días están disponibles o se han utilizado.
Desglosemos las partes clave del componente:
1. Obtención de Datos
- Datos del Empleado: Utiliza
useGetIdentity
para obtener la información del empleado actual, como los días de licencia anual disponibles. - Conteo de Tiempo Libre: Utiliza
useList
para obtener el número total de días de licencia por enfermedad y licencia casual utilizados por el empleado. EstablecepageSize
en 1 porque solo necesitamos el conteo total, no todos los detalles.
2. Mostrando las Tarjetas
- El componente renderiza tres componentes de tarjeta, uno para cada tipo de licencia.
- Cada tarjeta muestra:
- El tipo de licencia (por ejemplo, Licencia Anual).
- El número de días disponibles o utilizados.
- Un ícono que representa el tipo de licencia.
3. Manejo de Estados de Carga
- Si los datos todavía se están cargando, muestra un marcador de esqueleto en lugar de los números reales.
- La propiedad
cargando
se pasa a las tarjetas para gestionar este estado.
4. El Componente de Tarjeta
- Recibe
tipo
,valor
ycargando
como propiedades. - Utiliza un
variantMap
para obtener las etiquetas correctas, colores e iconos basados en el tipo de permiso. - Muestra la información del permiso con el estilo apropiado.
Construyendo <PageEmployeeTimeOffsList />
Ahora que tenemos los componentes para listar los permisos y mostrar las tarjetas de permiso, creemos el nuevo archivo en la carpeta src/pages/employee/time-offs/
llamado list.tsx
y agreguemos el siguiente código:
<PageEmployeeTimeOffsList />
es el componente principal para la página de permisos, usaremos este componente para mostrar las listas de permisos y las tarjetas de permiso cuando los usuarios naveguen a la ruta /employee/time-offs
.

Desglosemos las partes clave del componente:
1. Verificación de Roles de Usuario
- Utiliza el gancho
useCan
para determinar si el usuario actual es un gerente. - Establece
isManager
entrue
si el usuario tiene permisos de gerente.
2. Aplicación de Tema Basado en el Rol
- Envuelve el contenido dentro de un
<ThemeProvider />
. - El tema cambia según si el usuario es un gerente o un empleado.
3. Encabezado de Página con Botón Condicional
- Renderiza un
<PageHeader />
con el título “Tiempo Libre”. - Incluye un
<CreateButton />
que cambia según el rol del usuario:- Si el usuario es un gerente, el botón dice “Asignar Tiempo Libre”.
- Si el usuario no es un gerente, dice “Solicitar Tiempo Libre”.
- Esto se maneja utilizando el componente
<CanAccess />
, que verifica los permisos.
4. Mostrando Estadísticas de Licencias
- Incluye el componente
<TimeOffLeaveCards />
para mostrar saldos y uso de licencias. - Esto proporciona un resumen de licencias anuales, por enfermedad y casuales.
5. Listando Solicitudes de Tiempo Libre
- Utiliza un diseño de
<Grid />
para organizar el contenido. - En el lado izquierdo (
md={6}
), muestra:TimeOffList
contype="inReview"
: Muestra solicitudes de tiempo libre pendientes.TimeOffList
contype="upcoming"
: Muestra los próximos tiempos libres aprobados.
- En el lado derecho (
md={6}
), se muestra:TimeOffList
contype="history"
: Muestra los tiempos libres pasados que ya han ocurrido.
Agregando la ruta “/employee/time-offs”
Estamos listos para renderizar el componente <PageEmployeeTimeOffsList />
en la ruta /employee/time-offs
. Actualicemos el archivo App.tsx
para incluir esta ruta:
Desglosemos las partes clave del archivo App.tsx
actualizado:
1. Definición del recurso de tiempo libre
Agregamos un nuevo recurso para los tiempos libres como hijo del recurso de employee
. Esto indica que los tiempos libres están relacionados con los empleados y son accesibles por los empleados.
name: 'time-offs'
: Este es el identificador del recurso, utilizado internamente por Refine.list: '/employee/time-offs'
: Especifica la ruta que muestra la vista de lista del recurso.meta
: Un objeto que contiene metadatos adicionales sobre el recurso.parent: 'employee'
: Agrupa este recurso bajo el alcance deemployee
, que se puede utilizar para organizar recursos en la interfaz de usuario (como en un menú lateral) o para el control de acceso.scope: Role.EMPLOYEE
: Indica que este recurso es accesible para usuarios con el rolEMPLOYEE
. Usamos esto en elaccessControlProvider
para gestionar permisos.label: 'Time Off'
: El nombre de visualización del recurso en la interfaz de usuario.icon: <TimeOffIcon />
: Asocia elTimeOffIcon
con este recurso para su identificación visual.
2. Redirigir al recurso “time-offs” cuando los usuarios navegan a la ruta /
Usamos el <NavigateToResource />
componente para redirigir a los usuarios al recurso time-offs
cuando navegan a la ruta /
. Esto asegura que los usuarios vean la lista de ausencias por defecto.
3. Redirigiendo al recurso “time-offs” cuando los usuarios están autenticados
Cuando los usuarios están autenticados, los redirigimos al recurso time-offs
. Si no están autenticados, ven la página de inicio de sesión.
4. Agregando la Ruta /employee/time-offs
Organizamos las páginas de empleados utilizando rutas anidadas. Primero, creamos una ruta principal con path='employee'
que envuelve el contenido en un tema y diseño específico para empleados. Dentro de esta ruta, añadimos path='time-offs'
, que muestra el componente PageEmployeeTimeOffsList
. Esta estructura agrupa todas las características de empleados bajo una ruta y mantiene el estilo consistente.
Después de añadir estos cambios, puedes navegar a la ruta /employee/time-offs
para ver la página de lista de ausencias en acción.

En este momento, la página de lista de ausencias es funcional, pero carece de la capacidad de crear nuevas solicitudes de ausencias. Vamos a añadir la capacidad de crear nuevas solicitudes de ausencias.
Construyendo la Página de Creación de Ausencias
Crearemos una nueva página para solicitar o asignar tiempo libre. Esta página incluirá un formulario donde los usuarios podrán especificar el tipo de tiempo libre, las fechas de inicio y fin, y cualquier nota adicional.
Antes de empezar, necesitamos crear nuevos componentes para usar en el formulario:
Creación del Componente <TimeOffFormSummary />
Crea un nuevo archivo llamado form-summary.tsx
en la carpeta src/components/time-offs/
y agrega el siguiente código:

El componente <TimeOffFormSummary />
muestra un resumen de la solicitud de tiempo libre. Muestra los días disponibles de licencia anual, el número de días solicitados y los días restantes. Utilizaremos este componente en el formulario de tiempo libre para proporcionar a los usuarios una visión clara de su solicitud.
Creación del Componente <PageEmployeeTimeOffsCreate />
Crea un nuevo archivo llamado create.tsx
en la carpeta src/pages/employee/time-offs/
y agrega el siguiente código:

El componente <PageEmployeeTimeOffsCreate />
muestra un formulario para crear nuevas solicitudes de tiempo libre en una aplicación de gestión de recursos humanos. Tanto los empleados como los gerentes pueden usarlo para solicitar o asignar tiempo libre. El formulario incluye opciones para seleccionar el tipo de tiempo libre, elegir fechas de inicio y fin, agregar notas, y muestra un resumen del tiempo libre solicitado.
Desglosemos las partes clave del componente:
1. Verificación del Rol del Usuario
Con el gancho useCan
, verificamos si el usuario actual tiene permisos de gerente. Esto determina si el usuario puede asignar tiempo libre o solo solicitarlo. Manejaremos el envío del formulario de manera diferente en onFinishHandler
según el rol del usuario.
2. Estado y Envío del Formulario
useForm
inicializa el formulario con valores predeterminados y establece notificaciones de éxito según el rol del usuario. La función onFinishHandler
procesa los datos del formulario antes de enviarlos. Para los gerentes, el estado se establece en APPROVED
de inmediato, mientras que las solicitudes de los empleados se envían para su revisión.
3. Estilos
En nuestro diseño, el color principal cambia según el rol del usuario. Utilizamos el <ThemeProvider />
para aplicar el tema correcto en consecuencia. El texto e icono del botón de enviar también cambian dependiendo de si el usuario es un gerente o un empleado.
4. Agregar la Ruta “/employee/time-offs/create”
Necesitamos agregar la nueva ruta para la página de creación de tiempo libre. Actualicemos el archivo App.tsx
para incluir esta ruta:
Después de realizar estos cambios, puedes navegar a la ruta /employee/time-offs/create
o hacer clic en el botón “Asignar Tiempo Libre” en la página de lista de tiempos libres para acceder al formulario de creación de tiempo libre.

Paso 5 — Construcción de la Página de Gestión de Solicitudes de Tiempo Libre
En este paso, crearemos una nueva página para gestionar las solicitudes de tiempo libre. Esta página permitirá a los gerentes revisar y aprobar o rechazar las solicitudes de tiempo libre enviadas por los empleados.

Construcción de la Página de Listado de Solicitudes de Tiempo Libre
Crearemos una nueva página para gestionar las solicitudes de tiempo libre. Esta página incluirá un listado de solicitudes de tiempo libre, mostrando detalles como el nombre del empleado, el tipo de tiempo libre, las fechas solicitadas y el estado actual.
Antes de comenzar, necesitamos crear nuevos componentes para usar en el listado:
Construcción del Componente <RequestsList />
Crea un nuevo archivo llamado list.tsx
en la carpeta src/components/requests/
y agrega el siguiente código:
El componente <RequestsList />
muestra un listado de solicitudes de tiempo libre con desplazamiento infinito. Incluye un indicador de carga, marcadores de esqueleto y un mensaje cuando no hay datos. Este componente está diseñado para manejar grandes conjuntos de datos de manera eficiente y proporcionar una experiencia de usuario fluida.
Construyendo el componente <RequestsListItem />
Crea un nuevo archivo llamado list-item.tsx
en la carpeta src/components/requests/
y añade el siguiente código:
El componente <RequestsListItem />
muestra una única solicitud de tiempo libre en la lista. Incluye el avatar del empleado, nombre, descripción y un botón para ver los detalles de la solicitud. Este componente es reutilizable y puede ser utilizado para renderizar cada elemento en la lista de solicitudes de tiempo libre.
Construyendo el componente <PageManagerRequestsList />
Crea un nuevo archivo llamado list.tsx
en la carpeta src/pages/manager/requests/
y añade el siguiente código:
El componente <PageManagerRequestsList />
muestra las solicitudes de tiempo libre pendientes que los gerentes necesitan aprobar. Muestra detalles como el nombre del empleado, tipo de licencia, fechas solicitadas y cuánto tiempo ha pasado desde que se hizo la solicitud. Los gerentes pueden hacer clic en una solicitud para ver más detalles. Utiliza <RequestsList />
y <RequestsListItem />
para renderizar la lista.
Este componente también acepta children
como una propiedad. A continuación, implementaremos una ruta modal usando <Outlet />
para mostrar los detalles de la solicitud, renderizando la ruta /manager/requests/:id
dentro del componente.
Agregando la ruta “/manager/requests”
Necesitamos agregar la nueva ruta para la página de gestión de solicitudes de tiempo libre. Actualicemos el archivo App.tsx
para incluir esta ruta:
Después de agregar estos cambios, puedes navegar a la ruta /manager/requests
para ver la página de gestión de solicitudes de tiempo libre en acción

Construyendo la Página de Detalles de Solicitud de Tiempo Libre
En este paso, crearemos una nueva página para mostrar los detalles de una solicitud de tiempo libre. Esta página mostrará el nombre del empleado, el tipo de tiempo libre, las fechas solicitadas y el estado actual. Los gerentes pueden aprobar o rechazar la solicitud desde esta página.
Construyendo el Componente <TimeOffRequestModal />
Primero, crea un archivo llamado use-get-employee-time-off-usage
en la carpeta src/hooks/
y agrega el siguiente código:
Usaremos el hook useGetEmployeeTimeOffUsage
para calcular el número total de días que un empleado ha tomado para cada tipo de tiempo libre. Esta información se mostrará en la página de detalles de la solicitud de tiempo libre.
Después de eso, crea un nuevo archivo llamado time-off-request-modal.tsx
en la carpeta src/components/requests/
y agrega el siguiente código:
Desglosamos el componente <TimeOffRequestModal />
:
1. Recuperando el Uso de Tiempo Libre del Empleado
El hook useGetEmployeeTimeOffUsage
se utiliza para obtener el uso de tiempo libre del empleado. Este hook calcula los días restantes de vacaciones anuales y los días de licencia por enfermedad y días de licencia casual utilizados previamente basados en el historial de tiempo libre del empleado.
2. Obtención de Solicitudes de Tiempo Libre Aprobadas que se Superponen
El hook useList
con los filtros anteriores obtiene todas las solicitudes de tiempo libre aprobadas que se superponen con la solicitud de tiempo libre actual. Esta lista se utiliza para mostrar a los empleados que están ausentes entre las fechas solicitadas.
3. Manejo de Aprobación/Rechazo de Solicitudes de Tiempo Libre
La función handleSubmit
se llama cuando el gerente aprueba o rechaza la solicitud de tiempo libre.
Refine invalida automáticamente la caché de recursos después de que el recurso se haya mutado (time-offs
en este caso). Dado que el uso de tiempo libre del empleado se calcula en función del historial de tiempo libre, también invalidamos la caché de recursos employees
para actualizar el uso de tiempo libre del empleado.
Agregando la Ruta “/manager/requests/:id”
En este paso, crearemos una nueva ruta para mostrar la página de detalles de la solicitud de tiempo libre, donde los gerentes pueden aprobar o rechazar las solicitudes.
Creemos un nuevo archivo llamado edit.tsx
en la carpeta src/pages/manager/requests/time-offs/
y agreguemos el siguiente código:
Ahora necesitamos agregar la nueva ruta para renderizar la página de detalles de la solicitud de tiempo libre. Actualicemos el archivo App.tsx
para incluir esta ruta:
Veamos más de cerca los cambios:
El código anterior establece una estructura de rutas anidadas donde se muestra un modal al navegar a una ruta secundaria específica. El componente <PageManagerRequestsTimeOffsEdit />
es un modal y se renderiza como un hijo del componente <PageManagerRequestsList />
. Esta estructura nos permite mostrar el modal sobre la página de la lista mientras mantenemos la página de la lista visible en el fondo.
Cuando navegas a la ruta /manager/requests/:id/edit
o haces clic en una solicitud de tiempo libre en la lista, se mostrará la página de detalles de la solicitud de tiempo libre como un modal sobre la página de la lista.

Paso 6 — Implementación de Autorización y Control de Acceso
La autorización es un componente crítico en las aplicaciones a nivel empresarial, desempeñando un papel clave tanto en la seguridad como en la eficiencia operativa. Asegura que solo los usuarios autorizados puedan acceder a recursos específicos, protegiendo datos y funcionalidades sensibles. El sistema de autorización de Refine proporciona la infraestructura necesaria para proteger sus recursos y garantizar que los usuarios interactúen con su aplicación de manera segura y controlada. En este paso, implementaremos la autorización y el control de acceso para la gestión de solicitudes de tiempo libre. Restringiremos el acceso a las rutas /manager/requests
y /manager/requests/:id/edit
solo a los gerentes con la ayuda del componente <CanAccess />
.
En este momento, cuando inicias sesión como empleado, no puedes ver el enlace a la página de Solicitudes
en la barra lateral, pero aún puedes acceder a la ruta /manager/requests
escribiendo la URL en el navegador. Agregaremos una protección para evitar el acceso no autorizado a estas rutas.
Actualicemos el archivo App.tsx
para incluir las verificaciones de autorización:
En el código anterior, agregamos el componente <CanAccess />
a la ruta “/manager”. Este componente verifica si el usuario tiene el rol de “gerente” antes de renderizar las rutas secundarias. Si el usuario no tiene el rol de “gerente”, será redirigido a la página de lista de tiempo libre para empleados.
Ahora, cuando inicies sesión como empleado e intentes acceder a la ruta /manager/requests
, serás redirigido a la página de lista de tiempo libre para empleados.
Paso 7 — Desplegando en la plataforma de aplicaciones de DigitalOcean
En este paso, desplegaremos la aplicación en la plataforma de aplicaciones de DigitalOcean. Para hacer eso, alojaremos el código fuente en GitHub y conectaremos el repositorio de GitHub a la plataforma de aplicaciones.
Subiendo el código a GitHub
Inicia sesión en tu cuenta de GitHub y crea un nuevo repositorio llamado refine-hr
. Puedes hacer el repositorio público o privado:
Después de crear el repositorio, navega al directorio del proyecto y ejecuta el siguiente comando para inicializar un nuevo repositorio Git:
Luego, agrega todos los archivos al repositorio Git con este comando:
Después, confirma los archivos con este comando:
Luego, agrega el repositorio de GitHub como un repositorio remoto con este comando:
Después, especifica que deseas enviar tu código a la rama main
con este comando:
Finalmente, empuja el código al repositorio de GitHub con este comando:
Cuando se te pida, ingresa tus credenciales de GitHub para empujar tu código.
Recibirás un mensaje de éxito después de que el código se haya empujado al repositorio de GitHub.
En esta sección, empujaste tu proyecto a GitHub para que puedas acceder a él utilizando DigitalOcean Apps. El siguiente paso es crear una nueva App de DigitalOcean usando tu proyecto y configurar la implementación automática.
Desplegando en la Plataforma de Apps de DigitalOcean
Durante esto, tomarías una aplicación de React y la prepararías para su implementación a través de la Plataforma de Apps de DigitalOcean. Vincularías tu repositorio de GitHub a DigitalOcean, configurarías cómo se construirá la aplicación y luego crearías una implementación inicial de un proyecto. Después de que el proyecto se despliegue, los cambios adicionales que realices se reconstruirán y actualizarán automáticamente.
Al final de este paso, tendrás tu aplicación desplegada en DigitalOcean con entrega continua configurada.
Inicia sesión en tu cuenta de DigitalOcean y navega a la página de Apps. Haz clic en el botón Crear App:
Si no has conectado tu cuenta de GitHub a DigitalOcean, se te pedirá que lo hagas. Haz clic en el botón Conectar con GitHub. Se abrirá una nueva ventana pidiéndote que autorices a DigitalOcean a acceder a tu cuenta de GitHub.
Después de autorizar a DigitalOcean, serás redirigido de nuevo a la página de Aplicaciones de DigitalOcean. El siguiente paso es seleccionar tu repositorio de GitHub. Después de seleccionar tu repositorio, se te pedirá que elijas una rama para implementar. Selecciona la rama main
y haz clic en el botón Siguiente.
Después de eso, verás los pasos de configuración para tu aplicación. En este tutorial, puedes hacer clic en el botón Siguiente para omitir los pasos de configuración. Sin embargo, también puedes configurar tu aplicación según desees.
Espera a que se complete la compilación. Después de que la compilación esté completa, presiona Aplicación en vivo para acceder a tu proyecto en el navegador. Será igual al proyecto que probaste localmente, pero este estará en vivo en la web con una URL segura. Además, puedes seguir este tutorial disponible en el sitio de la comunidad de DigitalOcean para aprender cómo implementar aplicaciones basadas en React en la Plataforma de Aplicaciones.
Nota: En caso de que la compilación no se implemente correctamente, puedes configurar tu comando de compilación en DigitalOcean para usar npm install --production=false && npm run build && npm prune --production
en lugar de npm run build
Conclusión
En este tutorial, construimos una aplicación de gestión de recursos humanos desde cero utilizando Refine y nos familiarizamos con cómo construir una aplicación CRUD totalmente funcional.
También, demostraremos cómo implementar su aplicación en la Plataforma de Aplicaciones de DigitalOcean.
Si desea aprender más sobre Refine, puede consultar la documentación y si tiene alguna pregunta o comentario, puede unirse al Servidor de Discord de Refine.