Add payment modal for reloading credits with simulated payment flow
Some checks failed
continuous-integration/drone/push Build was killed
Some checks failed
continuous-integration/drone/push Build was killed
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.
This commit is contained in:
108
src/App.js
108
src/App.js
@@ -41,17 +41,24 @@ function App() {
|
|||||||
setIsMobileMenuOpen(false);
|
setIsMobileMenuOpen(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const [showPayment, setShowPayment] = useState(false);
|
||||||
|
|
||||||
const handleReloadCredits = () => {
|
const handleReloadCredits = () => {
|
||||||
const input = window.prompt('¿Cuántos créditos desea recargar?');
|
// Abrir modal de pasarela de pago
|
||||||
if (input == null) return;
|
setShowPayment(true);
|
||||||
const add = parseInt(input, 10);
|
};
|
||||||
if (Number.isNaN(add) || add <= 0) {
|
|
||||||
alert('Ingrese un número válido mayor a 0.');
|
const handlePaymentClose = () => setShowPayment(false);
|
||||||
return;
|
|
||||||
|
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 {}
|
||||||
}
|
}
|
||||||
const next = credits + add;
|
setShowPayment(false);
|
||||||
setCredits(next);
|
|
||||||
try { localStorage.setItem('credits', String(next)); } catch {}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const headerTitle = activeView === 'scheduled'
|
const headerTitle = activeView === 'scheduled'
|
||||||
@@ -68,6 +75,25 @@ function App() {
|
|||||||
? 'Perfil'
|
? 'Perfil'
|
||||||
: 'Dashboard';
|
: '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 (
|
return (
|
||||||
<div className="container">
|
<div className="container">
|
||||||
<Sidebar
|
<Sidebar
|
||||||
@@ -99,6 +125,70 @@ function App() {
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</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>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user