Add static password protection to the dashboard
This commit is contained in:
+93
-5
@@ -1,18 +1,106 @@
|
||||
import React from 'react';
|
||||
import { BrowserRouter, Routes, Route } from 'react-router-dom';
|
||||
import React, { useState } from 'react';
|
||||
import { BrowserRouter, Routes, Route, Navigate } from 'react-router-dom';
|
||||
import ConsolidatedHome from './components/ConsolidatedHome';
|
||||
import ChangeoverDetail from './components/ChangeoverDetail';
|
||||
import EventTimeline from './components/EventTimeline';
|
||||
import './index.css';
|
||||
|
||||
const STATIC_PASSWORD = "SOP-Monitor-99";
|
||||
|
||||
function ProtectedRoute({ children, isAuthenticated }) {
|
||||
if (!isAuthenticated) {
|
||||
return <Navigate to="/login" replace />;
|
||||
}
|
||||
return children;
|
||||
}
|
||||
|
||||
function Login({ onLogin }) {
|
||||
const [password, setPassword] = useState('');
|
||||
const [error, setError] = useState('');
|
||||
|
||||
const handleSubmit = (e) => {
|
||||
e.preventDefault();
|
||||
if (password === STATIC_PASSWORD) {
|
||||
onLogin();
|
||||
} else {
|
||||
setError('Incorrect password');
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="container animate-fade-in" style={{ display: 'flex', justifyContent: 'center', alignItems: 'center', height: '100vh', maxWidth: '100%' }}>
|
||||
<div className="glass-panel" style={{ padding: '3rem', width: '100%', maxWidth: '400px', textAlign: 'center' }}>
|
||||
<h2 style={{ marginBottom: '2rem' }}>AI SOP Monitoring</h2>
|
||||
<form onSubmit={handleSubmit} style={{ display: 'flex', flexDirection: 'column', gap: '1rem' }}>
|
||||
<input
|
||||
type="password"
|
||||
placeholder="Enter Access Password"
|
||||
value={password}
|
||||
onChange={e => setPassword(e.target.value)}
|
||||
style={{
|
||||
padding: '0.75rem 1rem',
|
||||
borderRadius: '8px',
|
||||
border: '1px solid var(--panel-border)',
|
||||
background: 'rgba(255,255,255,0.05)',
|
||||
color: 'var(--text)',
|
||||
fontSize: '1rem',
|
||||
outline: 'none',
|
||||
boxShadow: 'inset 0 2px 4px rgba(0,0,0,0.2)'
|
||||
}}
|
||||
/>
|
||||
{error && <p style={{ color: '#ff6b6b', margin: 0, fontSize: '0.875rem' }}>{error}</p>}
|
||||
<button type="submit" style={{
|
||||
padding: '0.75rem',
|
||||
background: 'var(--accent)',
|
||||
color: 'white',
|
||||
border: 'none',
|
||||
borderRadius: '8px',
|
||||
fontSize: '1rem',
|
||||
fontWeight: '600',
|
||||
cursor: 'pointer',
|
||||
transition: 'background 0.2s ease'
|
||||
}}
|
||||
onMouseEnter={(e) => e.currentTarget.style.background = '#0e705b'}
|
||||
onMouseLeave={(e) => e.currentTarget.style.background = 'var(--accent)'}
|
||||
>
|
||||
Access Dashboard
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function App() {
|
||||
const [isAuthenticated, setIsAuthenticated] = useState(() => {
|
||||
return localStorage.getItem('sop_auth') === 'true';
|
||||
});
|
||||
|
||||
const handleLogin = () => {
|
||||
setIsAuthenticated(true);
|
||||
localStorage.setItem('sop_auth', 'true');
|
||||
};
|
||||
|
||||
return (
|
||||
<BrowserRouter>
|
||||
<div className="App">
|
||||
<Routes>
|
||||
<Route path="/" element={<ConsolidatedHome />} />
|
||||
<Route path="/changeover/:id" element={<ChangeoverDetail />} />
|
||||
<Route path="/changeover/:id/timeline" element={<EventTimeline />} />
|
||||
<Route path="/login" element={<Login onLogin={handleLogin} />} />
|
||||
<Route path="/" element={
|
||||
<ProtectedRoute isAuthenticated={isAuthenticated}>
|
||||
<ConsolidatedHome />
|
||||
</ProtectedRoute>
|
||||
} />
|
||||
<Route path="/changeover/:id" element={
|
||||
<ProtectedRoute isAuthenticated={isAuthenticated}>
|
||||
<ChangeoverDetail />
|
||||
</ProtectedRoute>
|
||||
} />
|
||||
<Route path="/changeover/:id/timeline" element={
|
||||
<ProtectedRoute isAuthenticated={isAuthenticated}>
|
||||
<EventTimeline />
|
||||
</ProtectedRoute>
|
||||
} />
|
||||
</Routes>
|
||||
</div>
|
||||
</BrowserRouter>
|
||||
|
||||
Reference in New Issue
Block a user