From 471853e6318d9518e4a3c43953e8797c193ce086 Mon Sep 17 00:00:00 2001 From: rafael Date: Thu, 20 Nov 2025 20:39:59 -0400 Subject: [PATCH] Add header credits display with reload functionality Introduced a dynamic credits system displaying available credits in the header and allowing users to reload them via prompt-based input. Updated `Header.js` to include the credits badge and reload button. Adjusted `App.js` to manage credits state with localStorage synchronization. Enhanced styles for new header elements. --- src/App.js | 39 ++++++++++++++++++++++++++++++--- src/components/Layout/Header.js | 15 ++++++++++++- src/styles/components.css | 28 +++++++++++++++++++++++ 3 files changed, 78 insertions(+), 4 deletions(-) diff --git a/src/App.js b/src/App.js index b19c42b..7c5c707 100644 --- a/src/App.js +++ b/src/App.js @@ -1,4 +1,4 @@ -import React, { useState } from 'react'; +import React, { useEffect, useState } from 'react'; import './styles/globals.css'; import { Sidebar, Header } from './components/Layout'; import { DashboardCards } from './components/Dashboard'; @@ -11,7 +11,27 @@ import SettingsPage from './components/Settings/SettingsPage'; function App() { const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false); - const [activeView, setActiveView] = useState('dashboard'); // 'dashboard' | 'scheduled' | 'create' + 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) => { @@ -19,6 +39,19 @@ function App() { setIsMobileMenuOpen(false); }; + const handleReloadCredits = () => { + const input = window.prompt('¿Cuántos créditos desea recargar?'); + if (input == null) return; + const add = parseInt(input, 10); + if (Number.isNaN(add) || add <= 0) { + alert('Ingrese un número válido mayor a 0.'); + return; + } + const next = credits + add; + setCredits(next); + try { localStorage.setItem('credits', String(next)); } catch {} + }; + const headerTitle = activeView === 'scheduled' ? 'Solicitudes Programadas' : activeView === 'create' @@ -38,7 +71,7 @@ function App() { onNavigate={handleNavigate} />
-
+
{activeView === 'scheduled' ? ( ) : activeView === 'create' ? ( diff --git a/src/components/Layout/Header.js b/src/components/Layout/Header.js index bdc002f..71cb7c6 100644 --- a/src/components/Layout/Header.js +++ b/src/components/Layout/Header.js @@ -1,7 +1,7 @@ import React from 'react'; import '../../styles/components.css'; -const Header = ({ title = 'Dashboard' }) => { +const Header = ({ title = 'Dashboard', credits = 0, onReloadCredits }) => { const handleLogout = () => { try { localStorage.setItem('auth', 'false'); @@ -23,6 +23,19 @@ const Header = ({ title = 'Dashboard' }) => { +
+ + + Créditos: {credits} + + +
diff --git a/src/styles/components.css b/src/styles/components.css index e1bf986..08df202 100644 --- a/src/styles/components.css +++ b/src/styles/components.css @@ -148,11 +148,16 @@ } .header { + position: sticky; + top: 0; + z-index: 100; + background: white; display: flex; justify-content: space-between; align-items: center; margin-bottom: 30px; padding: 20px 0; + box-shadow: 0 2px 8px rgba(0,0,0,0.06); } .page-title { @@ -181,6 +186,29 @@ gap: 16px; } +/* Header credits */ +.header-credits { + display: flex; + align-items: center; + gap: 10px; +} + +.credits-badge { + display: inline-flex; + align-items: center; + gap: 8px; + background: rgba(16, 185, 129, 0.1); + color: var(--secondary); + border: 1px solid rgba(16, 185, 129, 0.25); + padding: 8px 12px; + border-radius: 999px; + font-weight: 600; +} + +.credits-badge i { + color: var(--success); +} + .search-box { position: relative; background: white;