mobadara commited on
Commit
ed483bc
·
1 Parent(s): a38e020

initialized frontend

Browse files
frontend/.gitignore ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Logs
2
+ logs
3
+ *.log
4
+ npm-debug.log*
5
+ yarn-debug.log*
6
+ yarn-error.log*
7
+ pnpm-debug.log*
8
+ lerna-debug.log*
9
+
10
+ node_modules
11
+ dist
12
+ dist-ssr
13
+ *.local
14
+
15
+ # Editor directories and files
16
+ .vscode/*
17
+ !.vscode/extensions.json
18
+ .idea
19
+ .DS_Store
20
+ *.suo
21
+ *.ntvs*
22
+ *.njsproj
23
+ *.sln
24
+ *.sw?
frontend/README.md ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # React + Vite
2
+
3
+ This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
4
+
5
+ Currently, two official plugins are available:
6
+
7
+ - [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react) uses [Oxc](https://oxc.rs)
8
+ - [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react-swc) uses [SWC](https://swc.rs/)
9
+
10
+ ## React Compiler
11
+
12
+ The React Compiler is not enabled on this template because of its impact on dev & build performances. To add it, see [this documentation](https://react.dev/learn/react-compiler/installation).
13
+
14
+ ## Expanding the ESLint configuration
15
+
16
+ If you are developing a production application, we recommend using TypeScript with type-aware lint rules enabled. Check out the [TS template](https://github.com/vitejs/vite/tree/main/packages/create-vite/template-react-ts) for information on how to integrate TypeScript and [`typescript-eslint`](https://typescript-eslint.io) in your project.
frontend/eslint.config.js ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import js from '@eslint/js'
2
+ import globals from 'globals'
3
+ import reactHooks from 'eslint-plugin-react-hooks'
4
+ import reactRefresh from 'eslint-plugin-react-refresh'
5
+ import { defineConfig, globalIgnores } from 'eslint/config'
6
+
7
+ export default defineConfig([
8
+ globalIgnores(['dist']),
9
+ {
10
+ files: ['**/*.{js,jsx}'],
11
+ extends: [
12
+ js.configs.recommended,
13
+ reactHooks.configs.flat.recommended,
14
+ reactRefresh.configs.vite,
15
+ ],
16
+ languageOptions: {
17
+ globals: globals.browser,
18
+ parserOptions: { ecmaFeatures: { jsx: true } },
19
+ },
20
+ },
21
+ ])
frontend/index.html ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
+ <title>frontend</title>
8
+ </head>
9
+ <body>
10
+ <div id="root"></div>
11
+ <script type="module" src="/src/main.jsx"></script>
12
+ </body>
13
+ </html>
frontend/package-lock.json ADDED
The diff for this file is too large to render. See raw diff
 
frontend/package.json ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "frontend",
3
+ "private": true,
4
+ "version": "0.0.0",
5
+ "type": "module",
6
+ "scripts": {
7
+ "dev": "vite",
8
+ "build": "vite build",
9
+ "lint": "eslint .",
10
+ "preview": "vite preview"
11
+ },
12
+ "dependencies": {
13
+ "axios": "^1.16.1",
14
+ "lucide-react": "^1.17.0",
15
+ "react": "^19.2.6",
16
+ "react-dom": "^19.2.6",
17
+ "react-router-dom": "^7.16.0"
18
+ },
19
+ "devDependencies": {
20
+ "@eslint/js": "^10.0.1",
21
+ "@tailwindcss/vite": "^4.3.0",
22
+ "@types/react": "^19.2.14",
23
+ "@types/react-dom": "^19.2.3",
24
+ "@vitejs/plugin-react": "^6.0.1",
25
+ "eslint": "^10.3.0",
26
+ "eslint-plugin-react-hooks": "^7.1.1",
27
+ "eslint-plugin-react-refresh": "^0.5.2",
28
+ "globals": "^17.6.0",
29
+ "tailwindcss": "^4.3.0",
30
+ "vite": "^8.0.12"
31
+ }
32
+ }
frontend/public/favicon.svg ADDED
frontend/public/icons.svg ADDED
frontend/src/App.css ADDED
@@ -0,0 +1,184 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ .counter {
2
+ font-size: 16px;
3
+ padding: 5px 10px;
4
+ border-radius: 5px;
5
+ color: var(--accent);
6
+ background: var(--accent-bg);
7
+ border: 2px solid transparent;
8
+ transition: border-color 0.3s;
9
+ margin-bottom: 24px;
10
+
11
+ &:hover {
12
+ border-color: var(--accent-border);
13
+ }
14
+ &:focus-visible {
15
+ outline: 2px solid var(--accent);
16
+ outline-offset: 2px;
17
+ }
18
+ }
19
+
20
+ .hero {
21
+ position: relative;
22
+
23
+ .base,
24
+ .framework,
25
+ .vite {
26
+ inset-inline: 0;
27
+ margin: 0 auto;
28
+ }
29
+
30
+ .base {
31
+ width: 170px;
32
+ position: relative;
33
+ z-index: 0;
34
+ }
35
+
36
+ .framework,
37
+ .vite {
38
+ position: absolute;
39
+ }
40
+
41
+ .framework {
42
+ z-index: 1;
43
+ top: 34px;
44
+ height: 28px;
45
+ transform: perspective(2000px) rotateZ(300deg) rotateX(44deg) rotateY(39deg)
46
+ scale(1.4);
47
+ }
48
+
49
+ .vite {
50
+ z-index: 0;
51
+ top: 107px;
52
+ height: 26px;
53
+ width: auto;
54
+ transform: perspective(2000px) rotateZ(300deg) rotateX(40deg) rotateY(39deg)
55
+ scale(0.8);
56
+ }
57
+ }
58
+
59
+ #center {
60
+ display: flex;
61
+ flex-direction: column;
62
+ gap: 25px;
63
+ place-content: center;
64
+ place-items: center;
65
+ flex-grow: 1;
66
+
67
+ @media (max-width: 1024px) {
68
+ padding: 32px 20px 24px;
69
+ gap: 18px;
70
+ }
71
+ }
72
+
73
+ #next-steps {
74
+ display: flex;
75
+ border-top: 1px solid var(--border);
76
+ text-align: left;
77
+
78
+ & > div {
79
+ flex: 1 1 0;
80
+ padding: 32px;
81
+ @media (max-width: 1024px) {
82
+ padding: 24px 20px;
83
+ }
84
+ }
85
+
86
+ .icon {
87
+ margin-bottom: 16px;
88
+ width: 22px;
89
+ height: 22px;
90
+ }
91
+
92
+ @media (max-width: 1024px) {
93
+ flex-direction: column;
94
+ text-align: center;
95
+ }
96
+ }
97
+
98
+ #docs {
99
+ border-right: 1px solid var(--border);
100
+
101
+ @media (max-width: 1024px) {
102
+ border-right: none;
103
+ border-bottom: 1px solid var(--border);
104
+ }
105
+ }
106
+
107
+ #next-steps ul {
108
+ list-style: none;
109
+ padding: 0;
110
+ display: flex;
111
+ gap: 8px;
112
+ margin: 32px 0 0;
113
+
114
+ .logo {
115
+ height: 18px;
116
+ }
117
+
118
+ a {
119
+ color: var(--text-h);
120
+ font-size: 16px;
121
+ border-radius: 6px;
122
+ background: var(--social-bg);
123
+ display: flex;
124
+ padding: 6px 12px;
125
+ align-items: center;
126
+ gap: 8px;
127
+ text-decoration: none;
128
+ transition: box-shadow 0.3s;
129
+
130
+ &:hover {
131
+ box-shadow: var(--shadow);
132
+ }
133
+ .button-icon {
134
+ height: 18px;
135
+ width: 18px;
136
+ }
137
+ }
138
+
139
+ @media (max-width: 1024px) {
140
+ margin-top: 20px;
141
+ flex-wrap: wrap;
142
+ justify-content: center;
143
+
144
+ li {
145
+ flex: 1 1 calc(50% - 8px);
146
+ }
147
+
148
+ a {
149
+ width: 100%;
150
+ justify-content: center;
151
+ box-sizing: border-box;
152
+ }
153
+ }
154
+ }
155
+
156
+ #spacer {
157
+ height: 88px;
158
+ border-top: 1px solid var(--border);
159
+ @media (max-width: 1024px) {
160
+ height: 48px;
161
+ }
162
+ }
163
+
164
+ .ticks {
165
+ position: relative;
166
+ width: 100%;
167
+
168
+ &::before,
169
+ &::after {
170
+ content: '';
171
+ position: absolute;
172
+ top: -4.5px;
173
+ border: 5px solid transparent;
174
+ }
175
+
176
+ &::before {
177
+ left: 0;
178
+ border-left-color: var(--border);
179
+ }
180
+ &::after {
181
+ right: 0;
182
+ border-right-color: var(--border);
183
+ }
184
+ }
frontend/src/App.jsx ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import React from 'react';
2
+ import { AuthProvider } from './AuthContext';
3
+ import { useAuth } from './useAuth';
4
+ import LoginScreen from './LoginScreen';
5
+ import Dashboard from './Dashboard';
6
+
7
+ // The Gatekeeper Component
8
+ const MainRouter = () => {
9
+ const { user } = useAuth();
10
+
11
+ // If no user exists in global state, lock them out
12
+ if (!user) {
13
+ return <LoginScreen />;
14
+ }
15
+
16
+ // Otherwise, let them into the system
17
+ return <Dashboard />;
18
+ };
19
+
20
+ export default function App() {
21
+ return (
22
+ <AuthProvider>
23
+ <MainRouter />
24
+ </AuthProvider>
25
+ );
26
+ }
frontend/src/AuthContext.jsx ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { useState } from 'react';
2
+ import { AuthContext } from './authContext';
3
+
4
+ export const AuthProvider = ({ children }) => {
5
+ const [user, setUser] = useState(() => {
6
+ const storedUser = localStorage.getItem('debutron_user');
7
+ return storedUser ? JSON.parse(storedUser) : null;
8
+ });
9
+
10
+ const login = (email, password) => {
11
+ // Hardcoded for MVP phase
12
+ if (email === "doctor@clinic.com" && password === "password123") {
13
+ const userData = { email, role: "physician", name: "Dr. Smith" };
14
+ setUser(userData);
15
+ localStorage.setItem('debutron_user', JSON.stringify(userData));
16
+ return true;
17
+ }
18
+ return false;
19
+ };
20
+
21
+ const logout = () => {
22
+ setUser(null);
23
+ localStorage.removeItem('debutron_user');
24
+ };
25
+
26
+ return (
27
+ <AuthContext.Provider value={{ user, login, logout }}>
28
+ {children}
29
+ </AuthContext.Provider>
30
+ );
31
+ };
frontend/src/Dashboard.jsx ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import React from 'react';
2
+ import { useAuth } from './useAuth';
3
+ import { LogOut, Activity } from 'lucide-react';
4
+
5
+ export default function Dashboard() {
6
+ const { user, logout } = useAuth();
7
+
8
+ return (
9
+ <div className="min-h-screen bg-gray-50">
10
+ {/* Top Navigation Bar */}
11
+ <nav className="bg-navy text-white p-4 shadow-md flex justify-between items-center">
12
+ <div className="flex items-center gap-3">
13
+ <Activity className="w-6 h-6 text-trust-cyan" />
14
+ <span className="font-bold tracking-wide">DEBUTRON LAB</span>
15
+ </div>
16
+ <div className="flex items-center gap-6">
17
+ <span className="text-sm text-gray-200">Welcome, {user?.name}</span>
18
+ <button
19
+ onClick={logout}
20
+ className="flex items-center gap-2 hover:text-red-300 transition-colors text-sm font-medium"
21
+ >
22
+ <LogOut className="w-4 h-4" /> Logout
23
+ </button>
24
+ </div>
25
+ </nav>
26
+
27
+ {/* Main Content Area */}
28
+ <main className="max-w-7xl mx-auto p-6 mt-8">
29
+ <div className="bg-white rounded-xl shadow-sm border border-gray-100 p-12 text-center">
30
+ <h2 className="text-2xl font-semibold text-navy mb-2">Diagnostic Engine Active</h2>
31
+ <p className="text-gray-500">The main X-Ray upload interface will go here.</p>
32
+ </div>
33
+ </main>
34
+ </div>
35
+ );
36
+ }
frontend/src/LoginScreen.jsx ADDED
@@ -0,0 +1,67 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import React, { useState } from 'react';
2
+ import { useAuth } from './useAuth';
3
+ import { Activity } from 'lucide-react';
4
+
5
+ export default function LoginScreen() {
6
+ const [email, setEmail] = useState('');
7
+ const [password, setPassword] = useState('');
8
+ const [error, setError] = useState('');
9
+ const { login } = useAuth();
10
+
11
+ const handleLogin = (e) => {
12
+ e.preventDefault();
13
+ const success = login(email, password);
14
+ if (!success) setError("Invalid credentials. Use doctor@clinic.com / password123");
15
+ };
16
+
17
+ return (
18
+ <div className="min-h-screen bg-gray-50 flex items-center justify-center p-4">
19
+ <div className="max-w-md w-full bg-white rounded-xl shadow-lg p-8">
20
+ <div className="flex flex-col items-center justify-center mb-8">
21
+ <div className="bg-navy p-3 rounded-full mb-4">
22
+ <Activity className="text-white w-8 h-8" />
23
+ </div>
24
+ <h2 className="text-2xl font-bold text-navy">DEBUTRON LAB</h2>
25
+ <p className="text-gray-500 text-sm mt-1">Precision Diagnostics Portal</p>
26
+ </div>
27
+
28
+ {error && (
29
+ <div className="mb-4 p-3 bg-red-50 text-critical-red text-sm rounded-md border border-red-100">
30
+ {error}
31
+ </div>
32
+ )}
33
+
34
+ <form onSubmit={handleLogin} className="space-y-6">
35
+ <div>
36
+ <label className="block text-sm font-medium text-gray-700 mb-1">Email Address</label>
37
+ <input
38
+ type="email"
39
+ required
40
+ className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-trust-cyan focus:border-transparent outline-none transition-all"
41
+ value={email}
42
+ onChange={(e) => setEmail(e.target.value)}
43
+ placeholder="doctor@clinic.com"
44
+ />
45
+ </div>
46
+ <div>
47
+ <label className="block text-sm font-medium text-gray-700 mb-1">Password</label>
48
+ <input
49
+ type="password"
50
+ required
51
+ className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-trust-cyan focus:border-transparent outline-none transition-all"
52
+ value={password}
53
+ onChange={(e) => setPassword(e.target.value)}
54
+ placeholder="••••••••"
55
+ />
56
+ </div>
57
+ <button
58
+ type="submit"
59
+ className="w-full bg-navy hover:bg-blue-900 text-white font-semibold py-2.5 rounded-lg transition-colors duration-200"
60
+ >
61
+ Secure Login
62
+ </button>
63
+ </form>
64
+ </div>
65
+ </div>
66
+ );
67
+ }
frontend/src/assets/hero.png ADDED
frontend/src/assets/react.svg ADDED
frontend/src/assets/vite.svg ADDED
frontend/src/authContext.js ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ import { createContext } from 'react';
2
+
3
+ export const AuthContext = createContext(null);
frontend/src/index.css ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ @import "tailwindcss";
2
+
3
+ @theme {
4
+ /* Your core brand color */
5
+ --color-navy: #000080;
6
+
7
+ /* Medical Accents */
8
+ --color-clinical-teal: #0F766E;
9
+ --color-surgical-mint: #10B981;
10
+ --color-trust-cyan: #0EA5E9;
11
+
12
+ /* Alert color for "Pneumonia Detected" */
13
+ --color-critical-red: #EF4444;
14
+ }
frontend/src/main.jsx ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ import { StrictMode } from 'react'
2
+ import { createRoot } from 'react-dom/client'
3
+ import './index.css'
4
+ import App from './App.jsx'
5
+
6
+ createRoot(document.getElementById('root')).render(
7
+ <StrictMode>
8
+ <App />
9
+ </StrictMode>,
10
+ )
frontend/src/useAuth.js ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ import { useContext } from 'react';
2
+ import { AuthContext } from './authContext';
3
+
4
+ export const useAuth = () => useContext(AuthContext);
frontend/vite.config.js ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { defineConfig } from 'vite'
2
+ import react from '@vitejs/plugin-react'
3
+ import tailwindcss from '@tailwindcss/vite'
4
+
5
+ // https://vite.dev/config/
6
+ export default defineConfig({
7
+ plugins: [
8
+ react(),
9
+ tailwindcss()
10
+ ],
11
+ })