Replace CRA boilerplate with custom dashboard setup, remove unused files, and add new styles and components.
Some checks failed
continuous-integration/drone Build was killed

This commit is contained in:
2025-11-16 11:52:12 -04:00
parent a78a146129
commit deb38ca331
27 changed files with 1458 additions and 164 deletions

View File

@@ -0,0 +1,58 @@
import React from 'react';
import StatsCard from './StatsCard';
import '../../styles/components.css';
const DashboardCards = () => {
const statsData = [
{
type: 'primary',
value: '42',
title: 'Solicitudes Programadas',
trend: '12% desde la semana pasada',
trendDirection: 'up',
icon: 'fas fa-clock'
},
{
type: 'warning',
value: '28',
title: 'Solicitudes Pendientes',
trend: '5% desde ayer',
trendDirection: 'down',
icon: 'fas fa-hourglass-half'
},
{
type: 'success',
value: '156',
title: 'Solicitudes Ejecutadas',
trend: '8% desde ayer',
trendDirection: 'up',
icon: 'fas fa-check-circle'
},
{
type: 'danger',
value: '12',
title: 'Solicitudes Fallidas',
trend: '3% desde ayer',
trendDirection: 'down',
icon: 'fas fa-exclamation-circle'
}
];
return (
<div className="dashboard-cards">
{statsData.map((stat, index) => (
<StatsCard
key={index}
type={stat.type}
value={stat.value}
title={stat.title}
trend={stat.trend}
trendDirection={stat.trendDirection}
icon={stat.icon}
/>
))}
</div>
);
};
export default DashboardCards;

View File

@@ -0,0 +1,23 @@
import React from 'react';
import '../../styles/components.css';
const StatsCard = ({ type, value, title, trend, trendDirection, icon }) => {
return (
<div className={`card ${type}`}>
<div className="card-header">
<div>
<div className="card-value">{value}</div>
<div className="card-title">{title}</div>
<div className={`card-trend ${trendDirection}`}>
<i className={`fas fa-arrow-${trendDirection}`}></i> {trend}
</div>
</div>
<div className={`card-icon ${type}`}>
<i className={icon}></i>
</div>
</div>
</div>
);
};
export default StatsCard;

View File

@@ -0,0 +1,2 @@
export { default as DashboardCards } from './DashboardCards';
export { default as StatsCard } from './StatsCard';

View File

@@ -0,0 +1,24 @@
import React from 'react';
import '../../styles/components.css';
const Header = () => {
return (
<div className="header">
<div className="page-title">
<i className="fas fa-tachometer-alt"></i>
<span>Dashboard</span>
</div>
<div className="header-actions">
<div className="search-box">
<i className="fas fa-search"></i>
<input type="text" placeholder="Buscar solicitudes..." />
</div>
<button className="btn btn-primary">
<i className="fas fa-plus"></i> Nueva Solicitud
</button>
</div>
</div>
);
};
export default Header;

View File

@@ -0,0 +1,69 @@
import React from 'react';
import '../../styles/components.css';
const Sidebar = ({ isMobileMenuOpen, onToggleMobileMenu }) => {
const navItems = [
{ icon: 'fas fa-tachometer-alt', label: 'Dashboard', active: true, badge: null },
{ icon: 'fas fa-list', label: 'Solicitudes Programadas', active: false, badge: '12' },
{ icon: 'fas fa-plus-circle', label: 'Crear Solicitud', active: false, badge: null },
{ icon: 'fas fa-history', label: 'Historial', active: false, badge: null },
{ icon: 'fas fa-cog', label: 'Configuración', active: false, badge: null },
{ icon: 'fas fa-question-circle', label: 'Ayuda', active: false, badge: null }
];
return (
<>
<button
className="menu-toggle"
id="menuToggle"
onClick={onToggleMobileMenu}
>
<i className="fas fa-bars"></i>
</button>
<div className={`sidebar ${isMobileMenuOpen ? 'active' : ''}`} id="sidebar">
<div className="logo-container">
<div className="logo">
<div className="logo-icon">
<i className="fas fa-clock"></i>
</div>
<div className="logo-text">Request <span>Scheduler</span></div>
</div>
</div>
<div className="nav-container">
<ul className="nav-links">
{navItems.map((item, index) => (
<li
key={index}
className={item.active ? 'active' : ''}
data-tooltip={item.label}
>
<a href="#">
<i className={item.icon}></i>
<span>{item.label}</span>
{item.badge && <span className="badge">{item.badge}</span>}
</a>
</li>
))}
</ul>
</div>
<div className="sidebar-footer">
<div className="user-info">
<div className="user-avatar">JP</div>
<div className="user-details">
<div className="user-name">Juan Pérez</div>
<div className="user-role">Administrador</div>
</div>
<a href="#" style={{color: 'white'}}>
<i className="fas fa-sign-out-alt"></i>
</a>
</div>
</div>
</div>
</>
);
};
export default Sidebar;

View File

@@ -0,0 +1,2 @@
export { default as Sidebar } from './Sidebar';
export { default as Header } from './Header';

View File

@@ -0,0 +1,127 @@
import React, { useState } from 'react';
import '../../styles/components.css';
const RequestForm = () => {
const [formData, setFormData] = useState({
url: '',
method: 'POST',
headers: '',
body: '',
executeDate: '',
executeTime: ''
});
const handleChange = (e) => {
const { name, value } = e.target;
setFormData((prev) => ({ ...prev, [name]: value }));
};
const handleSubmit = (e) => {
e.preventDefault();
// Aquí podrías enviar los datos al backend
// console.log('Form data', formData);
// Mostrar notificación de éxito
const notification = document.createElement('div');
notification.textContent = 'Solicitud guardada correctamente';
notification.style.cssText = `
position: fixed;
top: 20px;
right: 20px;
background: var(--success);
color: white;
padding: 12px 16px;
border-radius: 8px;
box-shadow: var(--shadow);
z-index: 2000;
`;
document.body.appendChild(notification);
setTimeout(() => notification.remove(), 2500);
};
return (
<div className="form-container">
<div className="form-header">
<h3><i className="fas fa-paper-plane"></i> Nueva Solicitud</h3>
</div>
<form onSubmit={handleSubmit}>
<div className="form-group">
<label>URL del Endpoint</label>
<input
type="url"
name="url"
value={formData.url}
onChange={handleChange}
placeholder="https://api.ejemplo.com/endpoint"
required
/>
</div>
<div className="form-row">
<div className="form-group">
<label>Método</label>
<select name="method" value={formData.method} onChange={handleChange}>
<option>GET</option>
<option>POST</option>
<option>PUT</option>
<option>DELETE</option>
<option>PATCH</option>
</select>
</div>
<div className="form-group">
<label>Fecha de Ejecución</label>
<input
type="date"
name="executeDate"
value={formData.executeDate}
onChange={handleChange}
/>
</div>
<div className="form-group">
<label>Hora de Ejecución</label>
<input
type="time"
name="executeTime"
value={formData.executeTime}
onChange={handleChange}
/>
</div>
</div>
<div className="form-group">
<label>Headers (JSON)</label>
<textarea
name="headers"
rows="3"
value={formData.headers}
onChange={handleChange}
placeholder='{"Authorization": "Bearer ..."}'
/>
</div>
<div className="form-group">
<label>Cuerpo (JSON)</label>
<textarea
name="body"
rows="4"
value={formData.body}
onChange={handleChange}
placeholder='{"campo": "valor"}'
/>
</div>
<div className="form-actions">
<button type="submit" className="btn btn-primary">
<i className="fas fa-save"></i> Guardar
</button>
<button type="reset" className="btn btn-outline" onClick={() => setFormData({ url: '', method: 'POST', headers: '', body: '', executeDate: '', executeTime: '' })}>
<i className="fas fa-eraser"></i> Limpiar
</button>
</div>
</form>
</div>
);
};
export default RequestForm;

View File

@@ -0,0 +1,100 @@
import React from 'react';
import '../../styles/components.css';
const RequestTable = () => {
const requests = [
{
id: '#00125',
url: 'https://api.ejemplo.com/users',
method: 'POST',
date: '15/10/2023 14:30',
status: 'pending',
statusText: 'Pendiente'
},
{
id: '#00124',
url: 'https://api.ejemplo.com/products/update',
method: 'PUT',
date: '15/10/2023 12:15',
status: 'completed',
statusText: 'Completada'
},
{
id: '#00123',
url: 'https://api.ejemplo.com/orders',
method: 'GET',
date: '15/10/2023 10:45',
status: 'failed',
statusText: 'Fallida'
}
];
const getStatusIcon = (status) => {
switch (status) {
case 'pending': return 'fas fa-clock';
case 'completed': return 'fas fa-check';
case 'failed': return 'fas fa-exclamation-triangle';
default: return 'fas fa-circle';
}
};
return (
<div className="table-container">
<div className="table-header">
<h3>Solicitudes Recientes</h3>
<div className="table-actions">
<button className="btn btn-outline btn-sm">
<i className="fas fa-filter"></i> Filtrar
</button>
<button className="btn btn-outline btn-sm">
<i className="fas fa-download"></i> Exportar
</button>
</div>
</div>
<table>
<thead>
<tr>
<th>ID</th>
<th>URL</th>
<th>Método</th>
<th>Fecha de Ejecución</th>
<th>Estado</th>
<th>Acciones</th>
</tr>
</thead>
<tbody>
{requests.map((request, index) => (
<tr key={index}>
<td>{request.id}</td>
<td>{request.url}</td>
<td>{request.method}</td>
<td>{request.date}</td>
<td>
<span className={`status ${request.status}`}>
<i className={getStatusIcon(request.status)}></i> {request.statusText}
</span>
</td>
<td className="actions">
<button className="view" title="Ver detalles">
<i className="fas fa-eye"></i>
</button>
<button
className="execute"
title={request.status === 'completed' ? 'Ejecutar ahora' : 'Reintentar'}
disabled={request.status === 'completed'}
>
<i className={request.status === 'failed' ? 'fas fa-redo' : 'fas fa-play'}></i>
</button>
<button className="cancel" title="Cancelar">
<i className="fas fa-times"></i>
</button>
</td>
</tr>
))}
</tbody>
</table>
</div>
);
};
export default RequestTable;