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
Some checks failed
continuous-integration/drone Build was killed
This commit is contained in:
58
src/components/Dashboard/DashboardCards.js
Normal file
58
src/components/Dashboard/DashboardCards.js
Normal 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;
|
||||
23
src/components/Dashboard/StatsCard.js
Normal file
23
src/components/Dashboard/StatsCard.js
Normal 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;
|
||||
2
src/components/Dashboard/index.js
Normal file
2
src/components/Dashboard/index.js
Normal file
@@ -0,0 +1,2 @@
|
||||
export { default as DashboardCards } from './DashboardCards';
|
||||
export { default as StatsCard } from './StatsCard';
|
||||
24
src/components/Layout/Header.js
Normal file
24
src/components/Layout/Header.js
Normal 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;
|
||||
69
src/components/Layout/Sidebar.js
Normal file
69
src/components/Layout/Sidebar.js
Normal 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;
|
||||
2
src/components/Layout/index.js
Normal file
2
src/components/Layout/index.js
Normal file
@@ -0,0 +1,2 @@
|
||||
export { default as Sidebar } from './Sidebar';
|
||||
export { default as Header } from './Header';
|
||||
127
src/components/Requests/RequestForm.js
Normal file
127
src/components/Requests/RequestForm.js
Normal 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;
|
||||
100
src/components/Requests/RequestTable.js
Normal file
100
src/components/Requests/RequestTable.js
Normal 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;
|
||||
Reference in New Issue
Block a user