Add "Configuración" page and update navigation to support new view
Introduced the `SettingsPage` component for managing application preferences with localStorage persistence. Updated navigation and dynamic header title logic to include the new "settings" view. Adjusted `App.js` to handle the new view state and display `SettingsPage`.
This commit is contained in:
@@ -7,6 +7,7 @@ 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';
|
||||
|
||||
function App() {
|
||||
const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false);
|
||||
@@ -24,6 +25,8 @@ function App() {
|
||||
? 'Nueva Solicitud'
|
||||
: activeView === 'history'
|
||||
? 'Historial'
|
||||
: activeView === 'settings'
|
||||
? 'Configuración'
|
||||
: 'Dashboard';
|
||||
|
||||
return (
|
||||
@@ -42,6 +45,8 @@ function App() {
|
||||
<NewRequestPage />
|
||||
) : activeView === 'history' ? (
|
||||
<HistoryPage />
|
||||
) : activeView === 'settings' ? (
|
||||
<SettingsPage />
|
||||
) : (
|
||||
<section className="content-wrapper">
|
||||
<DashboardCards />
|
||||
|
||||
151
src/components/Settings/SettingsPage.js
Normal file
151
src/components/Settings/SettingsPage.js
Normal file
@@ -0,0 +1,151 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import '../../styles/components.css';
|
||||
|
||||
// Simple settings persisted in localStorage
|
||||
const DEFAULT_SETTINGS = {
|
||||
timezone: Intl.DateTimeFormat().resolvedOptions().timeZone || 'UTC',
|
||||
theme: 'light',
|
||||
notifications: true,
|
||||
apiBaseUrl: ''
|
||||
};
|
||||
|
||||
const loadSettings = () => {
|
||||
try {
|
||||
const raw = localStorage.getItem('app_settings');
|
||||
if (!raw) return DEFAULT_SETTINGS;
|
||||
const parsed = JSON.parse(raw);
|
||||
return { ...DEFAULT_SETTINGS, ...parsed };
|
||||
} catch {
|
||||
return DEFAULT_SETTINGS;
|
||||
}
|
||||
};
|
||||
|
||||
const saveSettings = (settings) => {
|
||||
localStorage.setItem('app_settings', JSON.stringify(settings));
|
||||
};
|
||||
|
||||
const SettingsPage = () => {
|
||||
const [settings, setSettings] = useState(loadSettings);
|
||||
const [saved, setSaved] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (!saved) return;
|
||||
const t = setTimeout(() => setSaved(false), 2000);
|
||||
return () => clearTimeout(t);
|
||||
}, [saved]);
|
||||
|
||||
const handleChange = (e) => {
|
||||
const { name, value, type, checked } = e.target;
|
||||
setSettings((s) => ({
|
||||
...s,
|
||||
[name]: type === 'checkbox' ? checked : value
|
||||
}));
|
||||
};
|
||||
|
||||
const handleSubmit = (e) => {
|
||||
e.preventDefault();
|
||||
saveSettings(settings);
|
||||
setSaved(true);
|
||||
};
|
||||
|
||||
const handleReset = () => {
|
||||
setSettings(DEFAULT_SETTINGS);
|
||||
saveSettings(DEFAULT_SETTINGS);
|
||||
};
|
||||
|
||||
return (
|
||||
<section className="content-wrapper">
|
||||
<div className="card" style={{ marginBottom: 24 }}>
|
||||
<div className="form-header">
|
||||
<h3>
|
||||
<i className="fas fa-cog"></i>
|
||||
Configuración
|
||||
</h3>
|
||||
</div>
|
||||
<p style={{ color: 'var(--gray)' }}>
|
||||
Ajusta las preferencias de la aplicación. Estos valores se guardan en este navegador.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="content-grid">
|
||||
<div className="card">
|
||||
<div className="form-header">
|
||||
<h3>
|
||||
<i className="fas fa-sliders-h"></i>
|
||||
Preferencias
|
||||
</h3>
|
||||
</div>
|
||||
<form onSubmit={handleSubmit}>
|
||||
<div className="form-grid">
|
||||
<div className="form-group">
|
||||
<label htmlFor="timezone">Zona horaria</label>
|
||||
<input
|
||||
id="timezone"
|
||||
name="timezone"
|
||||
type="text"
|
||||
placeholder="Ej: America/Bogota"
|
||||
value={settings.timezone}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="form-group">
|
||||
<label htmlFor="theme">Tema</label>
|
||||
<select id="theme" name="theme" value={settings.theme} onChange={handleChange}>
|
||||
<option value="light">Claro</option>
|
||||
<option value="dark">Oscuro</option>
|
||||
<option value="system">Sistema</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div className="form-group">
|
||||
<label className="checkbox">
|
||||
<input
|
||||
type="checkbox"
|
||||
name="notifications"
|
||||
checked={settings.notifications}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
Habilitar notificaciones
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div className="form-group" style={{ gridColumn: '1 / -1' }}>
|
||||
<label htmlFor="apiBaseUrl">API Base URL</label>
|
||||
<input
|
||||
id="apiBaseUrl"
|
||||
name="apiBaseUrl"
|
||||
type="text"
|
||||
placeholder="https://api.midominio.com"
|
||||
value={settings.apiBaseUrl}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
<small style={{ color: 'var(--gray)' }}>
|
||||
Base para las solicitudes HTTP; si se deja vacío, se usará la URL por defecto del sistema.
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="form-actions" style={{ marginTop: 16 }}>
|
||||
<button type="submit" className="btn btn-primary">
|
||||
<i className="fas fa-save" style={{ marginRight: 8 }}></i>
|
||||
Guardar cambios
|
||||
</button>
|
||||
<button type="button" className="btn btn-outline" onClick={handleReset}>
|
||||
Restablecer
|
||||
</button>
|
||||
{saved && (
|
||||
<span style={{ color: 'var(--success)', marginLeft: 12 }}>
|
||||
<i className="fas fa-check-circle" style={{ marginRight: 6 }}></i>
|
||||
Guardado
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
export default SettingsPage;
|
||||
Reference in New Issue
Block a user