Files
schedule/src/App.js
rafael f038fe4c69
Some checks failed
continuous-integration/drone/push Build was killed
Add payment modal for reloading credits with simulated payment flow
Integrated a modal to handle credit reloading with a simulated payment process. Updated logic to manage payment amount, successful payment handling, and credit updates. Improved UI with validations and placeholders for future payment gateway integration.
2025-11-22 22:46:35 -04:00

198 lines
6.8 KiB
JavaScript

import React, { useEffect, useState } from 'react';
import './styles/globals.css';
import { Sidebar, Header } from './components/Layout';
import { DashboardCards } from './components/Dashboard';
import RequestTable from './components/Requests/RequestTable';
import RequestForm from './components/Requests/RequestForm';
import ScheduledPage from './components/Scheduled/ScheduledPage';
import NewRequestPage from './components/Requests/NewRequestPage';
import HistoryPage from './components/History/HistoryPage';
import SettingsPage from './components/Settings/SettingsPage';
import HelpPage from './components/Help/HelpPage';
import ProfilePage from './components/Profile/ProfilePage';
function App() {
const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false);
const [activeView, setActiveView] = useState('dashboard'); // 'dashboard' | 'scheduled' | 'create' | 'history' | 'settings'
const [credits, setCredits] = useState(() => {
try {
const raw = localStorage.getItem('credits');
const n = raw != null ? parseInt(raw, 10) : 0;
return Number.isNaN(n) ? 0 : n;
} catch {
return 0;
}
});
useEffect(() => {
const onStorage = (e) => {
if (e.key === 'credits') {
const n = parseInt(e.newValue, 10);
if (!Number.isNaN(n)) setCredits(n);
}
};
window.addEventListener('storage', onStorage);
return () => window.removeEventListener('storage', onStorage);
}, []);
const handleToggleMobileMenu = () => setIsMobileMenuOpen(!isMobileMenuOpen);
const handleNavigate = (key) => {
setActiveView(key);
setIsMobileMenuOpen(false);
};
const [showPayment, setShowPayment] = useState(false);
const handleReloadCredits = () => {
// Abrir modal de pasarela de pago
setShowPayment(true);
};
const handlePaymentClose = () => setShowPayment(false);
const handlePaymentSuccess = (amount) => {
// Actualizar créditos después de un pago exitoso
const add = parseInt(amount, 10);
if (!Number.isNaN(add) && add > 0) {
const next = credits + add;
setCredits(next);
try { localStorage.setItem('credits', String(next)); } catch {}
}
setShowPayment(false);
};
const headerTitle = activeView === 'scheduled'
? 'Solicitudes Programadas'
: activeView === 'create'
? 'Nueva Solicitud'
: activeView === 'history'
? 'Historial'
: activeView === 'settings'
? 'Configuración'
: activeView === 'help'
? 'Ayuda'
: activeView === 'profile'
? 'Perfil'
: 'Dashboard';
const [paymentAmount, setPaymentAmount] = useState('');
const [isPaying, setIsPaying] = useState(false);
const proceedPayment = async () => {
const val = parseInt(paymentAmount, 10);
if (Number.isNaN(val) || val <= 0) {
alert('Ingrese un monto válido mayor a 0.');
return;
}
// Simulación de pasarela de pago
try {
setIsPaying(true);
await new Promise((res) => setTimeout(res, 1200));
handlePaymentSuccess(val);
} finally {
setIsPaying(false);
}
};
return (
<div className="container">
<Sidebar
isMobileMenuOpen={isMobileMenuOpen}
onToggleMobileMenu={handleToggleMobileMenu}
activeView={activeView}
onNavigate={handleNavigate}
/>
<main className="main-content">
<Header title={headerTitle} credits={credits} onReloadCredits={handleReloadCredits} />
{activeView === 'scheduled' ? (
<ScheduledPage />
) : activeView === 'create' ? (
<NewRequestPage />
) : activeView === 'history' ? (
<HistoryPage />
) : activeView === 'settings' ? (
<SettingsPage />
) : activeView === 'help' ? (
<HelpPage />
) : activeView === 'profile' ? (
<ProfilePage />
) : (
<section className="content-wrapper">
<DashboardCards />
<div className="content-grid">
<RequestForm />
<RequestTable />
</div>
</section>
)}
{showPayment && (
<div className="modal-overlay" onClick={handlePaymentClose}>
<div className="modal" onClick={(e) => e.stopPropagation()}>
<div className="modal-header">
<h3>
<i className="fas fa-credit-card"></i>
Recargar créditos
</h3>
<button className="btn btn-outline btn-sm" onClick={handlePaymentClose} disabled={isPaying}>
<i className="fas fa-times"></i> Cerrar
</button>
</div>
<div className="modal-body">
<div className="form-container">
<div className="form-row">
<div className="form-group" style={{ flex: 1 }}>
<label>
<i className="fas fa-coins" aria-hidden="true"></i> Monto a recargar (créditos)
</label>
<input
className="input"
type="number"
min={1}
step={1}
value={paymentAmount}
onChange={(e) => setPaymentAmount(e.target.value)}
placeholder="Ej: 10"
disabled={isPaying}
autoFocus
/>
</div>
</div>
{/* Placeholder de pasarela de pago: reemplace con su integración real (Mercado Pago, Stripe, etc.) */}
<div className="card" style={{ marginTop: 12 }}>
<div className="form-header">
<h3>
<i className="fas fa-shield-alt" style={{ marginRight: 8 }}></i>
Pasarela de pago
</h3>
</div>
<div style={{ padding: 12 }}>
<p style={{ marginTop: 0, color: 'var(--gray)' }}>
Esta es una simulación. Conecte aquí su pasarela (iframe, checkout, etc.).
</p>
<button className="btn btn-primary" onClick={proceedPayment} disabled={isPaying}>
{isPaying ? (
<>
<i className="fas fa-spinner fa-spin"></i> Procesando...
</>
) : (
<>
<i className="fas fa-lock"></i> Pagar y recargar
</>
)}
</button>
</div>
</div>
</div>
</div>
</div>
</div>
)}
</main>
</div>
);
}
export default App;