From 1e9a52850d09f5fb863e852dabe986d8255def1a Mon Sep 17 00:00:00 2001 From: s223060317 <142484345+s223060317@users.noreply.github.com> Date: Fri, 12 Sep 2025 17:40:32 +1000 Subject: [PATCH] Add files via upload hardcode for admin dashboard --- guardian-admin-dashboard/src/App.css | 153 ++++++++++++-- guardian-admin-dashboard/src/App.jsx | 136 +++++-------- guardian-admin-dashboard/src/Assignments.jsx | 117 +++++++++++ guardian-admin-dashboard/src/Dashboard.jsx | 50 +++++ guardian-admin-dashboard/src/Login.jsx | 63 ++++++ guardian-admin-dashboard/src/Patients.jsx | 51 +++++ .../src/ProtectedRoute.jsx | 15 ++ guardian-admin-dashboard/src/Sidebar.jsx | 46 +++++ guardian-admin-dashboard/src/Staff.jsx | 52 +++++ guardian-admin-dashboard/src/index.css | 186 +++++++++++++----- guardian-admin-dashboard/src/main.jsx | 20 +- 11 files changed, 719 insertions(+), 170 deletions(-) create mode 100644 guardian-admin-dashboard/src/Assignments.jsx create mode 100644 guardian-admin-dashboard/src/Dashboard.jsx create mode 100644 guardian-admin-dashboard/src/Login.jsx create mode 100644 guardian-admin-dashboard/src/Patients.jsx create mode 100644 guardian-admin-dashboard/src/ProtectedRoute.jsx create mode 100644 guardian-admin-dashboard/src/Sidebar.jsx create mode 100644 guardian-admin-dashboard/src/Staff.jsx diff --git a/guardian-admin-dashboard/src/App.css b/guardian-admin-dashboard/src/App.css index 83c74d68..fb513ed8 100644 --- a/guardian-admin-dashboard/src/App.css +++ b/guardian-admin-dashboard/src/App.css @@ -1,43 +1,158 @@ +/* General Styles */ body { - margin: 0; font-family: 'Segoe UI', sans-serif; - background: #f0f2f5; + margin: 0; + padding: 0; + background-color: #f4f6f8; + color: #333; } +/* Login Page */ .login-container { - max-width: 400px; + width: 320px; margin: 100px auto; - padding: 30px; + padding: 25px; background: #fff; - box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); - border-radius: 8px; + border-radius: 12px; + box-shadow: 0 4px 8px rgba(0,0,0,0.1); text-align: center; } -.login-container h2 { - margin-bottom: 20px; -} - .login-form input { - width: 100%; - padding: 10px; + width: 90%; margin: 10px 0; + padding: 12px; + border-radius: 6px; border: 1px solid #ccc; - border-radius: 4px; } .login-form button { - width: 100%; - padding: 10px; - background-color: #3f51b5; + background-color: #0066cc; + color: white; + border: none; + padding: 12px 25px; + margin-top: 10px; + border-radius: 6px; + cursor: pointer; +} + +.login-form button:hover { + background-color: #004d99; +} + +/* Dashboard Layout */ +.dashboard { + display: flex; + height: 100vh; +} + +/* Sidebar */ +.sidebar { + width: 240px; + background-color: #0d47a1; color: white; + padding: 30px 20px; +} + +.sidebar h2 { + font-size: 22px; + margin-bottom: 40px; +} + +.sidebar nav button { + display: block; + width: 100%; + background: none; border: none; + color: white; + font-size: 16px; + padding: 12px 0; + text-align: left; + cursor: pointer; +} + +.sidebar nav button:hover { + background-color: #1565c0; border-radius: 4px; +} + +/* Main Content */ +.main-content { + flex: 1; + padding: 30px 40px; + overflow-y: auto; + background-color: #f9f9f9; +} + +.main-content h2 { + margin-bottom: 20px; +} + +/* Card Grid */ +.card-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); + gap: 20px; + margin-bottom: 30px; +} + +.card { + background-color: #ffffff; + padding: 20px; + border-radius: 10px; + box-shadow: 0 2px 6px rgba(0,0,0,0.05); + text-align: center; font-weight: bold; +} + +/* Assignment Button */ +.create-button { + background-color: #009688; + color: white; + padding: 12px 20px; + border: none; + border-radius: 6px; + font-size: 14px; + margin-bottom: 20px; cursor: pointer; - transition: background 0.3s; } -.login-form button:hover { - background-color: #303f9f; +.create-button:hover { + background-color: #00796b; +} + +/* Assignment Form */ +.assignment-form { + background-color: #fff; + padding: 20px; + border-radius: 10px; + width: 100%; + max-width: 600px; + box-shadow: 0 2px 6px rgba(0,0,0,0.05); +} + +.assignment-form h3 { + margin-bottom: 20px; +} + +.assignment-form select, +.assignment-form input { + width: 100%; + padding: 10px; + margin-bottom: 15px; + border-radius: 6px; + border: 1px solid #ccc; +} + +.assignment-form button { + background-color: #4caf50; + color: white; + padding: 10px 18px; + border: none; + border-radius: 6px; + cursor: pointer; +} + +.assignment-form button:hover { + background-color: #388e3c; } diff --git a/guardian-admin-dashboard/src/App.jsx b/guardian-admin-dashboard/src/App.jsx index f9354860..e2832127 100644 --- a/guardian-admin-dashboard/src/App.jsx +++ b/guardian-admin-dashboard/src/App.jsx @@ -1,92 +1,52 @@ -import React, { useState } from 'react'; -import './App.css'; - -function App() { - const [email, setEmail] = useState(''); - const [password, setPassword] = useState(''); - const [otp, setOtp] = useState(''); - const [step, setStep] = useState('login'); // login → otp → dashboard - const [isAuthenticated, setIsAuthenticated] = useState(false); - - const handleLogin = (e) => { - e.preventDefault(); - // Simulate backend login credentials (admin only) - if (email === 'dominicdiona@gmail.com' && password === 'admin123') { - setStep('otp'); // Go to 2FA step - } else { - alert('Invalid credentials. Please contact backend for admin login.'); - } - }; - - - const handleOTPVerify = (e) => { - e.preventDefault(); - // Simulated OTP check (normally generated backend) - if (otp === '123456') { - setIsAuthenticated(true); - } else { - alert('Invalid OTP'); - } - }; - - if (isAuthenticated) { - return ( -
- Guardian Logo -

Admin Dashboard

-

Welcome, {email}

- {/* Add admin dashboard components here */} -
- ); - } - +import React from "react"; +import { BrowserRouter as Router, Routes, Route } from "react-router-dom"; +import Login from "./Login"; +import Dashboard from "./Dashboard"; +import Patients from "./Patients"; +import Staff from "./Staff"; +import Assignments from "./Assignments"; +import ProtectedRoute from "./ProtectedRoute"; + +const App = () => { return ( -
- Guardian Logo -

Guardian Admin Login

- - {step === 'login' && ( -
- setEmail(e.target.value)} - required - /> - setPassword(e.target.value)} - required - /> - -
- )} - - {step === 'otp' && ( -
- setOtp(e.target.value)} - required - /> - -
- )} -
+ + + } /> + + + + } + /> + + + + } + /> + + + + } + /> + + + + } + /> + + ); -} +}; export default App; diff --git a/guardian-admin-dashboard/src/Assignments.jsx b/guardian-admin-dashboard/src/Assignments.jsx new file mode 100644 index 00000000..b23e274f --- /dev/null +++ b/guardian-admin-dashboard/src/Assignments.jsx @@ -0,0 +1,117 @@ +import React, { useState } from 'react'; + +const Assignments = () => { + const [selectedPatient, setSelectedPatient] = useState(''); + const [selectedStaff, setSelectedStaff] = useState(''); + const [notes, setNotes] = useState(''); + const [assignments, setAssignments] = useState([ + { id: 1, patient: 'Patient A', staff: 'Nurse Emma', notes: 'Checkup daily' }, + { id: 2, patient: 'Patient B', staff: 'Doctor James', notes: 'Blood test' }, + { id: 3, patient: 'Patient C', staff: 'Nurse Liam', notes: 'Vitals monitoring' }, + ]); + const [successMessage, setSuccessMessage] = useState(''); + + const handleCreateAssignment = () => { + if (!selectedPatient || !selectedStaff) return; + + const newAssignment = { + id: assignments.length + 1, + patient: selectedPatient, + staff: selectedStaff, + notes: notes, + }; + + setAssignments([...assignments, newAssignment]); + setSelectedPatient(''); + setSelectedStaff(''); + setNotes(''); + setSuccessMessage('Assignment created successfully!'); + + setTimeout(() => setSuccessMessage(''), 3000); + }; + + return ( +
+

Assignments

+ + {/* Success message */} + {successMessage && ( +
+ {successMessage} +
+ )} + + {/* Form */} +
+

Create New Assignment

+ + + + + + setNotes(e.target.value)} + className="w-full p-2 mb-4 border border-gray-300 rounded" + /> + + +
+ + {/* Table */} +
+ + + + + + + + + + + {assignments.map((a) => ( + + + + + + + ))} + +
IDPatientStaffNotes
{a.id}{a.patient}{a.staff}{a.notes}
+
+
+ ); +}; + +export default Assignments; diff --git a/guardian-admin-dashboard/src/Dashboard.jsx b/guardian-admin-dashboard/src/Dashboard.jsx new file mode 100644 index 00000000..7c241ae2 --- /dev/null +++ b/guardian-admin-dashboard/src/Dashboard.jsx @@ -0,0 +1,50 @@ +// src/Dashboard.jsx +import React from 'react'; +import './App.css'; + +const Dashboard = () => { + return ( +
+ + +
+

Dashboard Overview

+ +
+
Total Patients: 5
+
Active Staff: 4
+
Assignments: 3
+
Unassigned: 2
+
+ + + +
+

Create New Assignment

+ + + + +
+
+
+ ); +}; + +export default Dashboard; diff --git a/guardian-admin-dashboard/src/Login.jsx b/guardian-admin-dashboard/src/Login.jsx new file mode 100644 index 00000000..c26951c0 --- /dev/null +++ b/guardian-admin-dashboard/src/Login.jsx @@ -0,0 +1,63 @@ +// src/Login.jsx +import React, { useState } from 'react'; +import { useNavigate } from 'react-router-dom'; +import './App.css'; + +const Login = () => { + const [email, setEmail] = useState(''); + const [password, setPassword] = useState(''); + const [pin, setPin] = useState(''); + const navigate = useNavigate(); + + const handleSubmit = (e) => { + e.preventDefault(); + + // Hardcoded admin credentials and 2FA + const adminEmail = 'admin@guardian.com'; + const adminPassword = 'admin@123'; + const adminPin = '123456'; + + if ( + email.trim() === adminEmail && + password === adminPassword && + pin === adminPin + ) { + localStorage.setItem('isAuthenticated', 'true'); + navigate('/dashboard'); + } else { + alert('Invalid email, password or 2FA PIN'); + } + }; + + return ( +
+

Admin Login

+
+ setEmail(e.target.value)} + required + /> + setPassword(e.target.value)} + required + /> + setPin(e.target.value)} + required + /> + +
+
+ ); +}; + +export default Login; diff --git a/guardian-admin-dashboard/src/Patients.jsx b/guardian-admin-dashboard/src/Patients.jsx new file mode 100644 index 00000000..800532d4 --- /dev/null +++ b/guardian-admin-dashboard/src/Patients.jsx @@ -0,0 +1,51 @@ +import React from 'react'; +import './App.css'; // reuse same styles +import { useNavigate } from 'react-router-dom'; + +const Patients = () => { + const navigate = useNavigate(); + + const patients = [ + { id: 1, name: 'Patient A', age: 78, condition: 'Diabetes' }, + { id: 2, name: 'Patient B', age: 85, condition: 'Dementia' }, + { id: 3, name: 'Patient C', age: 72, condition: 'Hypertension' }, + ]; + + const handleLogout = () => { + localStorage.removeItem('isAuthenticated'); + navigate('/'); + }; + + return ( +
+ + +

Patient List

+ + + + + + + + + + + + {patients.map((patient) => ( + + + + + + + ))} + +
IDNameAgeCondition
{patient.id}{patient.name}{patient.age}{patient.condition}
+
+ ); +}; + +export default Patients; diff --git a/guardian-admin-dashboard/src/ProtectedRoute.jsx b/guardian-admin-dashboard/src/ProtectedRoute.jsx new file mode 100644 index 00000000..0b441f57 --- /dev/null +++ b/guardian-admin-dashboard/src/ProtectedRoute.jsx @@ -0,0 +1,15 @@ +// src/ProtectedRoute.jsx +import React from 'react'; +import { Navigate } from 'react-router-dom'; + +const ProtectedRoute = ({ children }) => { + const isAuthenticated = localStorage.getItem('isAuthenticated') === 'true'; + + if (!isAuthenticated) { + return ; + } + + return children; +}; + +export default ProtectedRoute; diff --git a/guardian-admin-dashboard/src/Sidebar.jsx b/guardian-admin-dashboard/src/Sidebar.jsx new file mode 100644 index 00000000..a0630738 --- /dev/null +++ b/guardian-admin-dashboard/src/Sidebar.jsx @@ -0,0 +1,46 @@ +import React from "react"; +import { useNavigate, useLocation } from "react-router-dom"; +import "./index.css"; + +const Sidebar = () => { + const navigate = useNavigate(); + const location = useLocation(); + + const isActive = (path) => location.pathname === path; + + return ( + + ); +}; + +export default Sidebar; diff --git a/guardian-admin-dashboard/src/Staff.jsx b/guardian-admin-dashboard/src/Staff.jsx new file mode 100644 index 00000000..320c3a14 --- /dev/null +++ b/guardian-admin-dashboard/src/Staff.jsx @@ -0,0 +1,52 @@ +import React from 'react'; +import './App.css'; +import { useNavigate } from 'react-router-dom'; + +const Staff = () => { + const navigate = useNavigate(); + + const staffMembers = [ + { id: 1, name: 'Nurse 1', role: 'Nurse', shift: 'Morning' }, + { id: 2, name: 'Doctor 2', role: 'Doctor', shift: 'Evening' }, + { id: 3, name: 'Caretaker 3', role: 'Caretaker', shift: 'Night' }, + { id: 4, name: 'Doctor 4', role: 'Doctor', shift: 'Morning' }, + ]; + + const handleLogout = () => { + localStorage.removeItem('isAuthenticated'); + navigate('/'); + }; + + return ( +
+ + +

Staff List

+ + + + + + + + + + + + {staffMembers.map((staff) => ( + + + + + + + ))} + +
IDNameRoleShift
{staff.id}{staff.name}{staff.role}{staff.shift}
+
+ ); +}; + +export default Staff; diff --git a/guardian-admin-dashboard/src/index.css b/guardian-admin-dashboard/src/index.css index 08a3ac9e..583e3db3 100644 --- a/guardian-admin-dashboard/src/index.css +++ b/guardian-admin-dashboard/src/index.css @@ -1,68 +1,146 @@ -:root { - font-family: system-ui, Avenir, Helvetica, Arial, sans-serif; - line-height: 1.5; - font-weight: 400; +/* Reset and Base Styles */ +body { + margin: 0; + padding: 0; + font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; + background-color: #f4f6f8; + color: #333; +} - color-scheme: light dark; - color: rgba(255, 255, 255, 0.87); - background-color: #242424; +h1, h2, h3 { + margin-bottom: 10px; +} - font-synthesis: none; - text-rendering: optimizeLegibility; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; +button { + cursor: pointer; + border: none; + border-radius: 6px; + padding: 10px 15px; + background-color: #0066cc; + color: white; + font-weight: bold; + transition: background-color 0.3s ease; } -a { - font-weight: 500; - color: #646cff; - text-decoration: inherit; +button:hover { + background-color: #004999; } -a:hover { - color: #535bf2; + +/* Login Page */ +.login-container { + width: 350px; + margin: 100px auto; + padding: 30px; + background-color: #ffffff; + border-radius: 12px; + box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); + text-align: center; } -body { - margin: 0; +.login-form input { + width: 100%; + padding: 12px; + margin-bottom: 15px; + border-radius: 6px; + border: 1px solid #ccc; +} + +/* Dashboard Layout */ +.dashboard { display: flex; - place-items: center; - min-width: 320px; - min-height: 100vh; + height: 100vh; } -h1 { - font-size: 3.2em; - line-height: 1.1; +.sidebar { + width: 220px; + background-color: #1f2a40; + color: white; + padding: 20px; + display: flex; + flex-direction: column; } -button { - border-radius: 8px; - border: 1px solid transparent; - padding: 0.6em 1.2em; - font-size: 1em; - font-weight: 500; - font-family: inherit; - background-color: #1a1a1a; - cursor: pointer; - transition: border-color 0.25s; +.sidebar h2 { + font-size: 20px; + margin-bottom: 30px; + line-height: 1.2; } -button:hover { - border-color: #646cff; -} -button:focus, -button:focus-visible { - outline: 4px auto -webkit-focus-ring-color; -} - -@media (prefers-color-scheme: light) { - :root { - color: #213547; - background-color: #ffffff; - } - a:hover { - color: #747bff; - } - button { - background-color: #f9f9f9; - } + +.sidebar nav button { + margin: 10px 0; + width: 100%; + background-color: #1f2a40; + border: none; + text-align: left; + padding: 12px; + border-radius: 6px; + color: #eee; +} + +.sidebar nav button:hover, +.sidebar nav button.active { + background-color: #2e4a76; +} + +/* Main Content Area */ +.main-content { + flex: 1; + padding: 40px; + background-color: #f4f6f8; + overflow-y: auto; +} + +.card-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); + gap: 20px; + margin-top: 20px; + margin-bottom: 40px; +} + +.card { + background-color: #ffffff; + padding: 20px; + border-radius: 10px; + box-shadow: 0 1px 4px rgba(0, 0, 0, 0.1); + font-weight: bold; + text-align: center; +} + +/* Assignment Form */ +.assignment-form { + background-color: #ffffff; + padding: 20px; + border-radius: 10px; + box-shadow: 0 1px 4px rgba(0, 0, 0, 0.1); +} + +.assignment-form select, +.assignment-form input { + display: block; + width: 100%; + padding: 10px; + margin: 12px 0; + border-radius: 6px; + border: 1px solid #ccc; +} + +/* Table Style */ +.data-table { + width: 100%; + border-collapse: collapse; + margin-top: 20px; +} + +.data-table th, +.data-table td { + padding: 12px 15px; + border: 1px solid #ccc; + text-align: left; + background-color: #fff; +} + +.data-table th { + background-color: #f0f0f0; + font-weight: 600; } diff --git a/guardian-admin-dashboard/src/main.jsx b/guardian-admin-dashboard/src/main.jsx index b9a1a6de..56a3bfaf 100644 --- a/guardian-admin-dashboard/src/main.jsx +++ b/guardian-admin-dashboard/src/main.jsx @@ -1,10 +1,12 @@ -import { StrictMode } from 'react' -import { createRoot } from 'react-dom/client' -import './index.css' -import App from './App.jsx' +// main.jsx +import React from 'react'; +import ReactDOM from 'react-dom/client'; +import App from './App'; +import './index.css'; -createRoot(document.getElementById('root')).render( - - - , -) + +ReactDOM.createRoot(document.getElementById('root')).render( + + + +); \ No newline at end of file