aki-008 commited on
Commit
bc852fb
·
2 Parent(s): 88e511a 7e99777

Merge remote-tracking branch 'origin/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,73 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # React + TypeScript + 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 [Babel](https://babeljs.io/) (or [oxc](https://oxc.rs) when used in [rolldown-vite](https://vite.dev/guide/rolldown)) for Fast Refresh
8
+ - [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh
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 updating the configuration to enable type-aware lint rules:
17
+
18
+ ```js
19
+ export default defineConfig([
20
+ globalIgnores(['dist']),
21
+ {
22
+ files: ['**/*.{ts,tsx}'],
23
+ extends: [
24
+ // Other configs...
25
+
26
+ // Remove tseslint.configs.recommended and replace with this
27
+ tseslint.configs.recommendedTypeChecked,
28
+ // Alternatively, use this for stricter rules
29
+ tseslint.configs.strictTypeChecked,
30
+ // Optionally, add this for stylistic rules
31
+ tseslint.configs.stylisticTypeChecked,
32
+
33
+ // Other configs...
34
+ ],
35
+ languageOptions: {
36
+ parserOptions: {
37
+ project: ['./tsconfig.node.json', './tsconfig.app.json'],
38
+ tsconfigRootDir: import.meta.dirname,
39
+ },
40
+ // other options...
41
+ },
42
+ },
43
+ ])
44
+ ```
45
+
46
+ You can also install [eslint-plugin-react-x](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-x) and [eslint-plugin-react-dom](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-dom) for React-specific lint rules:
47
+
48
+ ```js
49
+ // eslint.config.js
50
+ import reactX from 'eslint-plugin-react-x'
51
+ import reactDom from 'eslint-plugin-react-dom'
52
+
53
+ export default defineConfig([
54
+ globalIgnores(['dist']),
55
+ {
56
+ files: ['**/*.{ts,tsx}'],
57
+ extends: [
58
+ // Other configs...
59
+ // Enable lint rules for React
60
+ reactX.configs['recommended-typescript'],
61
+ // Enable lint rules for React DOM
62
+ reactDom.configs.recommended,
63
+ ],
64
+ languageOptions: {
65
+ parserOptions: {
66
+ project: ['./tsconfig.node.json', './tsconfig.app.json'],
67
+ tsconfigRootDir: import.meta.dirname,
68
+ },
69
+ // other options...
70
+ },
71
+ },
72
+ ])
73
+ ```
Frontend/eslint.config.js ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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 tseslint from 'typescript-eslint'
6
+ import { defineConfig, globalIgnores } from 'eslint/config'
7
+
8
+ export default defineConfig([
9
+ globalIgnores(['dist']),
10
+ {
11
+ files: ['**/*.{ts,tsx}'],
12
+ extends: [
13
+ js.configs.recommended,
14
+ tseslint.configs.recommended,
15
+ reactHooks.configs['recommended-latest'],
16
+ reactRefresh.configs.vite,
17
+ ],
18
+ languageOptions: {
19
+ ecmaVersion: 2020,
20
+ globals: globals.browser,
21
+ },
22
+ },
23
+ ])
Frontend/index.html ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!doctype html>
2
+ <html lang="en">
3
+
4
+ <head>
5
+ <meta charset="UTF-8" />
6
+ <link rel="icon" type="image/svg+xml" href="/vite.svg" />
7
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
8
+ <title>Prep-AI</title>
9
+ <link rel="preconnect" href="https://fonts.googleapis.com">
10
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
11
+ <link href="https://fonts.googleapis.com/css2?family=Open+Sans:ital,wght@0,300..800;1,300..800&display=swap"
12
+ rel="stylesheet">
13
+ </head>
14
+
15
+ <body>
16
+ <div id="root"></div>
17
+ <script type="module" src="/src/main.tsx"></script>
18
+ </body>
19
+
20
+ </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,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "package",
3
+ "private": true,
4
+ "version": "0.0.0",
5
+ "type": "module",
6
+ "scripts": {
7
+ "dev": "vite",
8
+ "build": "tsc -b && vite build",
9
+ "lint": "eslint .",
10
+ "preview": "vite preview"
11
+ },
12
+ "dependencies": {
13
+ "@splinetool/react-spline": "^4.1.0",
14
+ "@splinetool/runtime": "^1.11.2",
15
+ "@tailwindcss/vite": "^4.1.17",
16
+ "clsx": "^2.1.1",
17
+ "dayjs": "^1.11.19",
18
+ "framer-motion": "^12.23.24",
19
+ "lucide-react": "^0.553.0",
20
+ "react": "^19.2.0",
21
+ "react-dom": "^19.2.0",
22
+ "react-router-dom": "^7.9.5",
23
+ "recharts": "^3.4.1",
24
+ "tailwind-merge": "^3.4.0",
25
+ "tailwindcss": "^4.1.17"
26
+ },
27
+ "devDependencies": {
28
+ "@eslint/js": "^9.39.1",
29
+ "@types/node": "^24.10.0",
30
+ "@types/react": "^19.2.2",
31
+ "@types/react-dom": "^19.2.2",
32
+ "@vitejs/plugin-react": "^5.1.0",
33
+ "eslint": "^9.39.1",
34
+ "eslint-plugin-react-hooks": "^5.2.0",
35
+ "eslint-plugin-react-refresh": "^0.4.24",
36
+ "globals": "^16.5.0",
37
+ "typescript": "~5.9.3",
38
+ "typescript-eslint": "^8.46.3",
39
+ "vite": "^7.2.2"
40
+ }
41
+ }
Frontend/public/vite.svg ADDED
Frontend/src/App.tsx ADDED
@@ -0,0 +1,69 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import React, { useState } from "react";
2
+ import { BrowserRouter as Router, Routes, Route, Navigate } from "react-router-dom";
3
+ import Dashboard from "./pages/dashboard";
4
+ import Notes from "./pages/note";
5
+ import AIInterview from "./pages/AiInterview";
6
+ import Quize from "./pages/quize";
7
+ import Home from "./pages/home";
8
+ import Sidebar from "./components/dashboard/Sidebar";
9
+
10
+ const App: React.FC = () => {
11
+ const [isAuthenticated, setIsAuthenticated] = useState<boolean>(false);
12
+
13
+ const handleLogin = () => {
14
+ setIsAuthenticated(true);
15
+ };
16
+
17
+ const handleLogout = () => {
18
+ setIsAuthenticated(false);
19
+ };
20
+
21
+ return (
22
+ <Router>
23
+ <Routes>
24
+
25
+ {/* Public Route */}
26
+ <Route
27
+ path="/"
28
+ element={
29
+ isAuthenticated ? (
30
+ <Navigate to="/dashboard" replace />
31
+ ) : (
32
+ <Home onLogin={handleLogin} />
33
+ )
34
+ }
35
+ />
36
+
37
+ {/* Protected Routes */}
38
+ <Route
39
+ path="/*"
40
+ element={
41
+ isAuthenticated ? (
42
+ <div className="flex h-screen bg-gray-100">
43
+
44
+ {/* Sidebar (only once) */}
45
+ <Sidebar onLogout={handleLogout} />
46
+
47
+ {/* Main Content */}
48
+ <main className="flex-1 overflow-y-auto">
49
+ <Routes>
50
+ <Route path="/dashboard" element={<Dashboard />} />
51
+ <Route path="/notes" element={<Notes />} />
52
+ <Route path="/AIInterview" element={<AIInterview />} />
53
+ <Route path="/quize" element={<Quize />} />
54
+ </Routes>
55
+ </main>
56
+
57
+ </div>
58
+ ) : (
59
+ <Navigate to="/" replace />
60
+ )
61
+ }
62
+ />
63
+
64
+ </Routes>
65
+ </Router>
66
+ );
67
+ };
68
+
69
+ export default App;
Frontend/src/components/auth/AuthModal.tsx ADDED
@@ -0,0 +1,43 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // src/components/AuthModal.tsx
2
+
3
+ import React from 'react';
4
+ import { X } from 'lucide-react';
5
+
6
+ interface AuthModalProps {
7
+ isOpen: boolean;
8
+ onClose: () => void;
9
+ children: React.ReactNode;
10
+ }
11
+
12
+ const AuthModal: React.FC<AuthModalProps> = ({ isOpen, onClose, children }) => {
13
+ if (!isOpen) return null;
14
+
15
+ return (
16
+ // Backdrop/Overlay: Fixed position, full screen, dark, and translucent
17
+ <div
18
+ className="fixed inset-0 z-[100] bg-black bg-opacity-80 backdrop-blur-sm flex items-center justify-center p-4 transition-opacity duration-300"
19
+ onClick={onClose} // Close the modal when clicking outside
20
+ >
21
+ {/* Modal Content Container: Prevent closing when clicking on the form itself */}
22
+ <div
23
+ className="relative w-full max-w-md bg-slate-900 border border-blue-500/30 rounded-xl shadow-2xl animate-fade-in-up"
24
+ onClick={(e) => e.stopPropagation()}
25
+ >
26
+ {/* Close Button */}
27
+ <button
28
+ className="absolute top-4 right-4 p-2 text-gray-400 hover:text-blue-400 transition-colors z-10"
29
+ onClick={onClose}
30
+ >
31
+ <X className="w-6 h-6" />
32
+ </button>
33
+
34
+ {/* Children (SignIn or SignUp content) */}
35
+ <div className="p-8 pt-10">
36
+ {children}
37
+ </div>
38
+ </div>
39
+ </div>
40
+ );
41
+ };
42
+
43
+ export default AuthModal;
Frontend/src/components/auth/SignIn.tsx ADDED
@@ -0,0 +1,121 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import React, { type FormEvent } from 'react'; // FIXED: Use 'type' import for FormEvent
2
+ import { Mail, Lock, LogIn, Chrome, X } from 'lucide-react'; // Added 'X' icon for close button
3
+
4
+ interface SignInProps {
5
+ onClose: () => void;
6
+ onSwitchToSignUp: () => void;
7
+ onAuthSuccess: () => void; // New prop to handle successful auth
8
+ }
9
+
10
+ const SignIn: React.FC<SignInProps> = ({ onClose, onSwitchToSignUp, onAuthSuccess }) => {
11
+
12
+ const handleSubmit = (e: FormEvent) => {
13
+ e.preventDefault();
14
+ // TODO: Add your actual authentication logic here
15
+
16
+ // Simulate successful login
17
+ onAuthSuccess();
18
+ };
19
+
20
+ const handleGoogleSignIn = () => {
21
+ // TODO: Add Google OAuth logic here
22
+ // For now, simulate successful login
23
+ onAuthSuccess();
24
+ };
25
+
26
+ return (
27
+ <>
28
+ {/* Close Button - Uses the 'onClose' prop */}
29
+ <button
30
+ onClick={onClose}
31
+ className="absolute top-4 right-4 text-gray-400 hover:text-white transition-colors p-2 rounded-full hover:bg-slate-800"
32
+ aria-label="Close"
33
+ >
34
+ <X className="w-5 h-5" />
35
+ </button>
36
+
37
+ <h2 className="text-3xl font-bold mb-8 text-center text-white">
38
+ Welcome Back
39
+ </h2>
40
+
41
+ {/* Sign In Form */}
42
+ <form className="space-y-5" onSubmit={handleSubmit}>
43
+ {/* Email Input */}
44
+ <div>
45
+ <label htmlFor="email" className="block text-sm font-medium mb-1 text-gray-300">
46
+ Email Address
47
+ </label>
48
+ <div className="relative">
49
+ <Mail className="w-5 h-5 absolute left-3 top-1/2 transform -translate-y-1/2 text-blue-400" />
50
+ <input
51
+ id="email"
52
+ type="email"
53
+ placeholder="you@example.com"
54
+ className="w-full pl-10 pr-4 py-3 border rounded-lg focus:outline-none focus:ring-2 bg-slate-800 border-slate-700 text-white focus:ring-blue-500 transition-colors"
55
+ required
56
+ />
57
+ </div>
58
+ </div>
59
+
60
+ {/* Password Input */}
61
+ <div>
62
+ <label htmlFor="password" className="block text-sm font-medium mb-1 text-gray-300">
63
+ Password
64
+ </label>
65
+ <div className="relative">
66
+ <Lock className="w-5 h-5 absolute left-3 top-1/2 transform -translate-y-1/2 text-blue-400" />
67
+ <input
68
+ id="password"
69
+ type="password"
70
+ placeholder="••••••••"
71
+ className="w-full pl-10 pr-4 py-3 border rounded-lg focus:outline-none focus:ring-2 bg-slate-800 border-slate-700 text-white focus:ring-blue-500 transition-colors"
72
+ required
73
+ />
74
+ </div>
75
+ </div>
76
+
77
+ {/* Sign In Button */}
78
+ <button
79
+ type="submit"
80
+ // FIXED: Changed bg-gradient-to-r to bg-linear-to-r (canonical class)
81
+ className="w-full px-5 py-3 rounded-lg bg-linear-to-r from-blue-500 to-gray-500 hover:from-blue-600 hover:to-blue-500 transition shadow-lg shadow-blue-500/50 text-lg font-semibold flex items-center justify-center gap-2 mt-6 text-white"
82
+ >
83
+ <LogIn className="w-5 h-5" />
84
+ Sign In
85
+ </button>
86
+ </form>
87
+
88
+ <div className="flex items-center my-6">
89
+ {/* FIXED: Changed flex-grow to grow (canonical class) */}
90
+ <div className="grow border-t border-slate-700"></div>
91
+ {/* FIXED: Changed flex-shrink to shrink (canonical class) */}
92
+ <span className="shrink mx-4 text-sm text-gray-400">OR</span>
93
+ {/* FIXED: Changed flex-grow to grow (canonical class) */}
94
+ <div className="grow border-t border-slate-700"></div>
95
+ </div>
96
+
97
+ {/* Social Sign In */}
98
+ <button
99
+ type="button"
100
+ onClick={handleGoogleSignIn}
101
+ className="w-full px-5 py-3 rounded-lg border-2 border-blue-400 text-blue-400 hover:bg-blue-400/10 transition-all font-semibold flex items-center justify-center gap-3 bg-slate-900"
102
+ >
103
+ <Chrome className="w-5 h-5" />
104
+ Sign In with Google
105
+ </button>
106
+
107
+ <p className="mt-8 text-center text-sm text-gray-400">
108
+ Don't have an account?
109
+ <button
110
+ type="button"
111
+ onClick={onSwitchToSignUp}
112
+ className="ml-2 font-medium text-blue-400 hover:text-blue-300 transition-colors"
113
+ >
114
+ Sign Up
115
+ </button>
116
+ </p>
117
+ </>
118
+ );
119
+ };
120
+
121
+ export default SignIn;
Frontend/src/components/auth/SignUp.tsx ADDED
@@ -0,0 +1,141 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import React from 'react';
2
+ import { User, Mail, Lock, UserPlus, Chrome, X } from 'lucide-react'; // Added 'X' icon for close button
3
+
4
+ // Added onClose prop to handle form-internal links/closing
5
+ interface SignUpProps {
6
+ onClose: () => void;
7
+ onSwitchToSignIn: () => void;
8
+ onAuthSuccess: () => void;// You might want to add onAuthSuccess here later, similar to SignIn
9
+ }
10
+
11
+ const SignUp: React.FC<SignUpProps> = ({ onClose, onSwitchToSignIn }) => {
12
+
13
+ // TODO: Implement actual form submission logic here
14
+ const handleSubmit = (e: React.FormEvent) => {
15
+ e.preventDefault();
16
+ console.log("Sign Up form submitted");
17
+ // Example: If successful, call a prop like onAuthSuccess()
18
+ };
19
+
20
+ // TODO: Implement actual Google OAuth logic here
21
+ const handleGoogleSignUp = () => {
22
+ console.log("Google Sign Up clicked");
23
+ };
24
+
25
+ return (
26
+ <>
27
+ {/* Close Button - Uses the 'onClose' prop */}
28
+ <button
29
+ onClick={onClose}
30
+ className="absolute top-4 right-4 text-gray-400 hover:text-white transition-colors p-2 rounded-full hover:bg-slate-800"
31
+ aria-label="Close"
32
+ >
33
+ <X className="w-5 h-5" />
34
+ </button>
35
+
36
+ <h2 className="text-3xl font-bold mb-8 text-center text-white">
37
+ Create Your Account
38
+ </h2>
39
+ {/* --- Sign Up Form --- */}
40
+ <form className="space-y-5" onSubmit={handleSubmit}>
41
+ {/* Name Input */}
42
+ <div>
43
+ <label htmlFor="name" className="block text-sm font-medium mb-1 text-gray-300">Full Name</label>
44
+ <div className="relative">
45
+ <User className="w-5 h-5 absolute left-3 top-1/2 transform -translate-y-1/2 text-blue-400" />
46
+ <input
47
+ id="name"
48
+ type="text"
49
+ placeholder="John Doe"
50
+ className="w-full pl-10 pr-4 py-3 border rounded-lg focus:outline-none focus:ring-2 bg-slate-800 border-slate-700 text-white focus:ring-blue-500 transition-colors"
51
+ required
52
+ />
53
+ </div>
54
+ </div>
55
+
56
+ {/* Email Input */}
57
+ <div>
58
+ <label htmlFor="email" className="block text-sm font-medium mb-1 text-gray-300">Email Address</label>
59
+ <div className="relative">
60
+ <Mail className="w-5 h-5 absolute left-3 top-1/2 transform -translate-y-1/2 text-blue-400" />
61
+ <input
62
+ id="email"
63
+ type="email"
64
+ placeholder="you@example.com"
65
+ className="w-full pl-10 pr-4 py-3 border rounded-lg focus:outline-none focus:ring-2 bg-slate-800 border-slate-700 text-white focus:ring-blue-500 transition-colors"
66
+ required
67
+ />
68
+ </div>
69
+ </div>
70
+
71
+ {/* Password Input */}
72
+ <div>
73
+ <label htmlFor="password" className="block text-sm font-medium mb-1 text-gray-300">Password</label>
74
+ <div className="relative">
75
+ <Lock className="w-5 h-5 absolute left-3 top-1/2 transform -translate-y-1/2 text-blue-400" />
76
+ <input
77
+ id="password"
78
+ type="password"
79
+ placeholder="••••••••"
80
+ className="w-full pl-10 pr-4 py-3 border rounded-lg focus:outline-none focus:ring-2 bg-slate-800 border-slate-700 text-white focus:ring-blue-500 transition-colors"
81
+ required
82
+ />
83
+ </div>
84
+ </div>
85
+
86
+ {/* Confirm Password Input */}
87
+ <div>
88
+ <label htmlFor="confirm-password" className="block text-sm font-medium mb-1 text-gray-300">Confirm Password</label>
89
+ <div className="relative">
90
+ <Lock className="w-5 h-5 absolute left-3 top-1/2 transform -translate-y-1/2 text-blue-400" />
91
+ <input
92
+ id="confirm-password"
93
+ type="password"
94
+ placeholder="••••••••"
95
+ className="w-full pl-10 pr-4 py-3 border rounded-lg focus:outline-none focus:ring-2 bg-slate-800 border-slate-700 text-white focus:ring-blue-500 transition-colors"
96
+ required
97
+ />
98
+ </div>
99
+ </div>
100
+
101
+ {/* Sign Up Button */}
102
+ <button
103
+ type="submit"
104
+ // FIXED: Changed bg-gradient-to-r to bg-linear-to-r (canonical class)
105
+ className="w-full px-5 py-3 rounded-lg bg-linear-to-r from-blue-500 to-gray-500 hover:from-blue-600 hover:to-blue-500 transition shadow-lg shadow-blue-500/50 text-lg font-semibold flex items-center justify-center gap-2 mt-6 text-white"
106
+ >
107
+ <UserPlus className="w-5 h-5" />
108
+ Sign Up
109
+ </button>
110
+ </form>
111
+
112
+ <div className="flex items-center my-6">
113
+ {/* FIXED: Changed flex-grow to grow (canonical class) */}
114
+ <div className="grow border-t border-slate-700"></div>
115
+ {/* FIXED: Changed flex-shrink to shrink (canonical class) */}
116
+ <span className="shrink mx-4 text-sm text-gray-400">OR</span>
117
+ {/* FIXED: Changed flex-grow to grow (canonical class) */}
118
+ <div className="grow border-t border-slate-700"></div>
119
+ </div>
120
+
121
+ {/* --- Social Sign Up --- */}
122
+ <button
123
+ type="button"
124
+ onClick={handleGoogleSignUp}
125
+ className="w-full px-5 py-3 rounded-lg border-2 border-blue-400 text-blue-400 hover:bg-blue-400/10 transition-all font-semibold flex items-center justify-center gap-3 bg-slate-900"
126
+ >
127
+ <Chrome className="w-5 h-5" />
128
+ Sign Up with Google
129
+ </button>
130
+
131
+ <p className="mt-8 text-center text-sm text-gray-400">
132
+ Already have an account?
133
+ <button type="button" onClick={onSwitchToSignIn} className="ml-2 font-medium text-blue-400 hover:text-blue-300 transition-colors">
134
+ Sign In
135
+ </button>
136
+ </p>
137
+ </>
138
+ );
139
+ };
140
+
141
+ export default SignUp;
Frontend/src/components/dashboard/FeedBackScore.tsx ADDED
@@ -0,0 +1,46 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import React from "react";
2
+
3
+ interface Props {
4
+ confidence: number;
5
+ clarity: number;
6
+ accuracy: number;
7
+ speed: number;
8
+ improvements: string[];
9
+ }
10
+
11
+ const ScoreCard = ({ label, value }: any) => (
12
+ <div className="p-4 text-center bg-gray-100 rounded-xl">
13
+ <p className="text-3xl font-bold text-black">{value}%</p>
14
+ <p className="text-gray-600">{label}</p>
15
+ </div>
16
+ );
17
+
18
+ const FeedbackScore: React.FC<Props> = ({
19
+ confidence,
20
+ clarity,
21
+ accuracy,
22
+ speed,
23
+ improvements,
24
+ }) => {
25
+ return (
26
+ <div className="bg-white p-5 shadow rounded-xl">
27
+ <h3 className="text-xl font-bold mb-3 text-black">AI Feedback Summary</h3>
28
+
29
+ <div className="grid grid-cols-2 md:grid-cols-4 gap-4">
30
+ <ScoreCard label="Confidence" value={confidence} />
31
+ <ScoreCard label="Clarity" value={clarity} />
32
+ <ScoreCard label="Technical Accuracy" value={accuracy} />
33
+ <ScoreCard label="Speed" value={speed} />
34
+ </div>
35
+
36
+ <h4 className="text-lg font-semibold mt-5 text-black">Suggested Improvements</h4>
37
+ <ul className="list-disc pl-5 text-blue-600">
38
+ {improvements.map((item, i) => (
39
+ <li key={i}>{item}</li>
40
+ ))}
41
+ </ul>
42
+ </div>
43
+ );
44
+ };
45
+
46
+ export default FeedbackScore;
Frontend/src/components/dashboard/InterviewPlayback.tsx ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ const InterviewPlayback = ({
2
+ audioUrl,
3
+ transcript,
4
+ highlights,
5
+ }: any) => (
6
+ <div className="bg-white p-5 shadow rounded-xl">
7
+ <h3 className="text-xl font-bold mb-4 text-black"> Interview Playback</h3>
8
+
9
+ {audioUrl && (
10
+ <audio controls className="w-full mb-4">
11
+ <source src={audioUrl} type="audio/mp3" />
12
+ </audio>
13
+ )}
14
+
15
+ <h4 className="font-semibold mb-2 text-black"> Transcript</h4>
16
+ <p className="text-gray-700 whitespace-pre-wrap">{transcript}</p>
17
+
18
+ <h4 className="font-semibold mt-4 text-black"> AI Highlights</h4>
19
+ <ul className="list-disc pl-5 text-blue-600">
20
+ {highlights.map((h: string, i: number) => (
21
+ <li key={i}>{h}</li>
22
+ ))}
23
+ </ul>
24
+ </div>
25
+ );
26
+
27
+ export default InterviewPlayback;
Frontend/src/components/dashboard/Sidebar.tsx ADDED
@@ -0,0 +1,68 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import React from "react";
2
+ import { Link, useLocation } from "react-router-dom";
3
+ import {
4
+ Home, FileText, Brain, BookOpen,
5
+ Bell, Settings, User, LogOut
6
+ } from "lucide-react";
7
+
8
+ interface SidebarProps {
9
+ onLogout?: () => void;
10
+ }
11
+
12
+ const Sidebar: React.FC<SidebarProps> = ({ onLogout }) => {
13
+ const location = useLocation();
14
+
15
+ const navItems = [
16
+ { path: "/", label: "Dashboard", icon: <Home size={18} /> },
17
+ { path: "/notes", label: "Notes", icon: <BookOpen size={18} /> },
18
+ { path: "/AIInterview", label: "AI Interview", icon: <Brain size={18} /> },
19
+ { path: "/quize", label: "Resume Quiz", icon: <FileText size={18} /> },
20
+ ];
21
+ return (
22
+ <aside className="w-64 bg-linear-to-r from-blue-700 to-gray-900/50 text-white flex flex-col justify-between">
23
+
24
+ {/* Top Section */}
25
+ <div>
26
+ <div className="text-2xl font-bold text-center py-6 border-b border-gray-700">
27
+ InterviewAI
28
+ </div>
29
+
30
+ <nav className="p-4 space-y-3">
31
+ {navItems.map((item) => (
32
+ <Link
33
+ key={item.path}
34
+ to={item.path}
35
+ className={`flex items-center space-x-3 p-3 rounded-lg hover:bg-gray-800 transition ${
36
+ location.pathname === item.path ? "bg-gray-800" : ""
37
+ }`}
38
+ >
39
+ {item.icon}
40
+ <span>{item.label}</span>
41
+ </Link>
42
+ ))}
43
+ </nav>
44
+ </div>
45
+
46
+ {/* Bottom Section (From Header) */}
47
+ <div className="p-4 border-t border-gray-700 space-y-4">
48
+ <button className="flex items-center space-x-3 p-3 rounded-lg hover:bg-gray-800 transition w-full text-left">
49
+ <Settings size={18} />
50
+ <span>Settings</span>
51
+ </button>
52
+
53
+ <button className="flex items-center space-x-3 p-3 rounded-lg hover:bg-gray-800 transition w-full text-left">
54
+ <User size={18} />
55
+ <span>John Doe</span>
56
+ </button>
57
+
58
+ <button className="flex items-center space-x-3 p-3 rounded-lg hover:bg-red-600 text-black transition w-full text-left">
59
+ <LogOut size={18} />
60
+ <span>Logout</span>
61
+ </button>
62
+ </div>
63
+
64
+ </aside>
65
+ );
66
+ };
67
+
68
+ export default Sidebar;
Frontend/src/components/dashboard/SkillRadarChart.tsx ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import {
2
+ Radar, RadarChart, PolarGrid, PolarAngleAxis, PolarRadiusAxis, ResponsiveContainer
3
+ } from "recharts";
4
+
5
+ const SkillRadarChart = ({ data }: { data: any[] }) => (
6
+ <div className="bg-white p-5 shadow rounded-xl">
7
+ <h3 className="text-xl font-bold mb-3 text-black">Skill Strength Chart</h3>
8
+
9
+ <div className="w-full h-80">
10
+ <ResponsiveContainer>
11
+ <RadarChart cx="50%" cy="50%" outerRadius="70%" data={data}>
12
+ <PolarGrid />
13
+ <PolarAngleAxis dataKey="skill" />
14
+ <PolarRadiusAxis angle={30} domain={[0, 100]} />
15
+ <Radar
16
+ name="Skill Level"
17
+ dataKey="value"
18
+ stroke="#1170d6"
19
+ fill="#1170d6"
20
+ fillOpacity={0.4}
21
+ />
22
+ </RadarChart>
23
+ </ResponsiveContainer>
24
+ </div>
25
+ </div>
26
+ );
27
+
28
+ export default SkillRadarChart;
Frontend/src/components/dashboard/WeakAreaBanner.tsx ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ const WeakAreaBanner = ({ topic }: { topic: string | null }) => {
2
+ if (!topic) return null;
3
+
4
+ return (
5
+ <div className="bg-red-100 p-4 rounded-xl border border-red-300 mt-4">
6
+ <p className="text-red-700 font-semibold">
7
+ ⚠️ You are weak in <strong>{topic}</strong>.
8
+ </p>
9
+ <p className="text-red-600">Start targeted practice today.</p>
10
+ </div>
11
+ );
12
+ };
13
+
14
+ export default WeakAreaBanner;
Frontend/src/components/dashboard/YearlyStreak.tsx ADDED
@@ -0,0 +1,80 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ interface StreakData {
2
+ date: string;
3
+ count: number;
4
+ weekday: number;
5
+ week: number;
6
+ month: string;
7
+ }
8
+
9
+ const getColor = (count: number) => {
10
+ if (count === 0) return "#2e2e2e";
11
+ if (count === 1) return "#9be9f8";
12
+ if (count === 2) return "#40c4f3";
13
+ if (count === 3) return "#30a1c4";
14
+ return "#216e9c";
15
+ };
16
+ const YearlyStreak = ({ data }: { data: StreakData[] }) => {
17
+ const totalSubmissions = data.reduce((a, b) => a + b.count, 0);
18
+ const activeDays = data.filter((d) => d.count > 0).length;
19
+
20
+ let streak = 0;
21
+ let maxStreak = 0;
22
+ data.forEach((d) => {
23
+ if (d.count > 0) {
24
+ streak++;
25
+ maxStreak = Math.max(maxStreak, streak);
26
+ } else {
27
+ streak = 0;
28
+ }
29
+ });
30
+
31
+ const weeks = data.reduce((acc: any, day) => {
32
+ acc[day.week] = acc[day.week] || [];
33
+ acc[day.week].push(day);
34
+ return acc;
35
+ }, {});
36
+
37
+ return (
38
+ <div className="bg-gray-900 p-6 rounded-xl text-white shadow-xl">
39
+ <div className="flex justify-between mb-4">
40
+ <h3 className="text-xl font-semibold">
41
+ {totalSubmissions} Hour Platform Activities This Year
42
+ </h3>
43
+
44
+ <div className="flex gap-6 text-gray-300">
45
+ <p>Total active days: <span className="text-white">{activeDays}</span></p>
46
+ <p>Max streak: <span className="text-white">{maxStreak}</span></p>
47
+ </div>
48
+ </div>
49
+
50
+ <div className="flex">
51
+ {Object.keys(weeks).map((weekIndex) => (
52
+ <div key={weekIndex} className="flex flex-col mr-1">
53
+ {weeks[weekIndex].map((day: StreakData) => (
54
+ <div
55
+ key={day.date}
56
+ title={`${day.date} — ${day.count} tasks`}
57
+ className="w-4 h-4 rounded-sm mb-1"
58
+ style={{ backgroundColor: getColor(day.count) }}
59
+ />
60
+ ))}
61
+ </div>
62
+ ))}
63
+ </div>
64
+
65
+ <div className="flex mt-3 text-gray-400 text-xs">
66
+ {Object.keys(weeks).map((weekIndex) => {
67
+ const firstDay = weeks[weekIndex][0];
68
+ const showLabel = firstDay.date.endsWith("01");
69
+ return (
70
+ <div key={weekIndex} className="w-4 mx-[2px]">
71
+ {showLabel && <span>{firstDay.month}</span>}
72
+ </div>
73
+ );
74
+ })}
75
+ </div>
76
+ </div>
77
+ );
78
+ };
79
+
80
+ export default YearlyStreak;
Frontend/src/components/ui/splite.tsx ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ 'use client'
2
+
3
+ import { Suspense, lazy } from 'react'
4
+ const Spline = lazy(() => import('@splinetool/react-spline'))
5
+
6
+ interface SplineSceneProps {
7
+ scene: string
8
+ className?: string
9
+ }
10
+
11
+ export function SplineScene({ scene, className }: SplineSceneProps) {
12
+ return (
13
+ <Suspense
14
+ fallback={
15
+ <div className="w-full h-full flex items-center justify-center">
16
+ <div className="w-12 h-12 border-4 border-blue-500 border-t-transparent rounded-full animate-spin"></div>
17
+ </div>
18
+ }
19
+ >
20
+ <Spline
21
+ scene={scene}
22
+ className={className}
23
+ />
24
+ </Suspense>
25
+ )
26
+ }
Frontend/src/components/ui/spotlight.tsx ADDED
@@ -0,0 +1,64 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { useEffect, useState } from "react";
2
+ import type { RefObject } from "react";
3
+ import { cn } from "../../lib/utils";
4
+
5
+ type SpotlightProps = {
6
+ parentRef: RefObject<HTMLDivElement|null>;
7
+ className?: string;
8
+ };
9
+
10
+ export const Spotlight = ({ parentRef, className }: SpotlightProps) => {
11
+ const [pos, setPos] = useState({ x: -9999, y: -9999 });
12
+
13
+ useEffect(() => {
14
+ const parent = parentRef.current;
15
+ if (!parent) return;
16
+
17
+ const handleMove = (e: MouseEvent) => {
18
+ const rect = parent.getBoundingClientRect();
19
+ setPos({
20
+ x: e.clientX - rect.left,
21
+ y: e.clientY - rect.top,
22
+ });
23
+ };
24
+
25
+ const handleLeave = () => {
26
+ setPos({ x: -9999, y: -9999 });
27
+ };
28
+
29
+ parent.addEventListener("mousemove", handleMove);
30
+ parent.addEventListener("mouseleave", handleLeave);
31
+
32
+ return () => {
33
+ parent.removeEventListener("mousemove", handleMove);
34
+ parent.removeEventListener("mouseleave", handleLeave);
35
+ };
36
+ }, [parentRef]);
37
+
38
+ return (
39
+ <div
40
+ className={cn(
41
+ "pointer-events-none absolute inset-0 z-0 transition-transform duration-75 ease-out",
42
+ className
43
+ )}
44
+ style={{
45
+ transform: `translate(${pos.x - 600}px, ${pos.y - 600}px)`,
46
+ }}
47
+ >
48
+ <svg
49
+ className="w-[1200px] h-[1200px] opacity-40 blur-3xl"
50
+ viewBox="0 0 1200 1200"
51
+ fill="none"
52
+ >
53
+ <defs>
54
+ <radialGradient id="spot" cx="50%" cy="50%" r="50%">
55
+ <stop offset="0%" stopColor="white" stopOpacity="0.35" />
56
+ <stop offset="100%" stopColor="white" stopOpacity="0" />
57
+ </radialGradient>
58
+ </defs>
59
+
60
+ <circle cx="600" cy="600" r="600" fill="url(#spot)" />
61
+ </svg>
62
+ </div>
63
+ );
64
+ };
Frontend/src/index.css ADDED
@@ -0,0 +1 @@
 
 
1
+ @import "tailwindcss";
Frontend/src/lib/utils.ts ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ import { type ClassValue, clsx } from "clsx"
2
+ import { twMerge } from "tailwind-merge"
3
+
4
+ export function cn(...inputs: ClassValue[]) {
5
+ return twMerge(clsx(inputs))
6
+ }
Frontend/src/main.tsx 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.tsx'
5
+
6
+ createRoot(document.getElementById('root')!).render(
7
+ <StrictMode>
8
+ <App />
9
+ </StrictMode>,
10
+ )
Frontend/src/pages/AiInterview.tsx ADDED
@@ -0,0 +1,155 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import React, { useState } from "react";
2
+ import { Send, Settings, CheckCircle } from "lucide-react";
3
+
4
+ // Define the structure for the interview state
5
+ type InterviewState = 'config' | 'chat' | 'results';
6
+
7
+ const AIInterview: React.FC = () => {
8
+ const [interviewState, setInterviewState] = useState<InterviewState>('config');
9
+ const [jobRole, setJobRole] = useState('');
10
+ const [experience, setExperience] = useState('');
11
+ const [level, setLevel] = useState('Medium');
12
+
13
+ // Placeholder for the AI Chat bubble/ball
14
+ const InterviewBall: React.FC = () => (
15
+ <div className="flex items-center justify-center w-24 h-24 bg-purple-600 rounded-full shadow-2xl animate-pulse cursor-pointer">
16
+ <span className="text-white font-bold text-xl">AI</span>
17
+ </div>
18
+ );
19
+
20
+ // --- RENDER FUNCTIONS ---
21
+
22
+ // 1. Configuration Phase
23
+ const renderConfig = () => (
24
+ <div className="bg-white p-6 rounded-xl shadow-lg border border-gray-200">
25
+ <h3 className="text-2xl font-semibold mb-6 flex items-center gap-2 text-blue-700">
26
+ <Settings size={24} /> Configure Your Interview
27
+ </h3>
28
+
29
+ <div className="space-y-6">
30
+ {/* Job Role Input */}
31
+ <label className="block">
32
+ <span className="text-gray-700 font-medium">1. Job Role/Position (e.g., Senior Frontend Developer)</span>
33
+ <input
34
+ type="text"
35
+ value={jobRole}
36
+ onChange={(e) => setJobRole(e.target.value)}
37
+ placeholder="Enter the job role for tailored questions"
38
+ className="mt-1 block w-full px-4 py-3 border border-gray-300 rounded-lg shadow-sm focus:ring-blue-500 focus:border-blue-500"
39
+ />
40
+ </label>
41
+
42
+ {/* Experience Input */}
43
+ <label className="block">
44
+ <span className="text-gray-700 font-medium">2. Years of Professional Experience</span>
45
+ <input
46
+ type="number"
47
+ min="0"
48
+ value={experience}
49
+ onChange={(e) => setExperience(e.target.value)}
50
+ placeholder="e.g., 5"
51
+ className="mt-1 block w-full px-4 py-3 border border-gray-300 rounded-lg shadow-sm focus:ring-blue-500 focus:border-blue-500"
52
+ />
53
+ </label>
54
+
55
+ {/* Level Select */}
56
+ <label className="block">
57
+ <span className="text-gray-700 font-medium">3. Difficulty Level</span>
58
+ <select
59
+ value={level}
60
+ onChange={(e) => setLevel(e.target.value)}
61
+ className="mt-1 block w-full px-4 py-3 border border-gray-300 rounded-lg shadow-sm focus:ring-blue-500 focus:border-blue-500 bg-white"
62
+ >
63
+ <option value="Basic">Basic (Beginner)</option>
64
+ <option value="Medium">Medium (Intermediate)</option>
65
+ <option value="Hard">Hard (Senior/Expert)</option>
66
+ </select>
67
+ </label>
68
+ </div>
69
+
70
+ <button
71
+ onClick={() => {
72
+ if (jobRole && experience) {
73
+ setInterviewState('chat');
74
+ } else {
75
+ alert('Please fill in the Job Role and Experience.');
76
+ }
77
+ }}
78
+ className="mt-8 px-8 py-3 bg-blue-600 text-white font-semibold rounded-lg hover:bg-blue-700 transition duration-150 flex items-center gap-2"
79
+ disabled={!jobRole || !experience}
80
+ >
81
+ <Send size={20} /> Start Interview
82
+ </button>
83
+ </div>
84
+ );
85
+
86
+ // 2. Chat/Interview Phase
87
+ const renderChat = () => (
88
+ <div className="flex flex-col items-center bg-white p-6 rounded-xl shadow-lg h-[600px] overflow-hidden relative">
89
+ <h3 className="text-xl font-bold mb-4">Interview in Progress</h3>
90
+ <p className="text-gray-600 mb-6">
91
+ Role: {jobRole} | Experience: {experience} yrs | Level: {level}
92
+ </p>
93
+
94
+ {/* The AI Ball UI Element */}
95
+ <InterviewBall />
96
+
97
+ {/* Placeholder for Chat Messages */}
98
+ <div className="flex-1 w-full mt-4 p-4 border border-dashed border-gray-300 rounded-lg overflow-y-auto bg-gray-50">
99
+ <div className="bg-purple-100 p-3 rounded-lg text-purple-800 mb-2">
100
+ **AI:** Welcome! Based on your configuration, let's start with your first question...
101
+ </div>
102
+ {/* User messages and AI responses would go here */}
103
+ </div>
104
+
105
+ {/* Input area */}
106
+ <div className="w-full flex gap-2 mt-4">
107
+ <input
108
+ type="text"
109
+ placeholder="Type your answer here..."
110
+ className="flex-1 px-4 py-3 border border-gray-300 rounded-lg focus:ring-purple-500 focus:border-purple-500"
111
+ />
112
+ <button className="px-4 py-3 bg-purple-600 text-white rounded-lg hover:bg-purple-700">
113
+ <Send size={20} />
114
+ </button>
115
+ </div>
116
+
117
+ <button
118
+ onClick={() => setInterviewState('results')}
119
+ className="mt-4 text-sm text-red-500 hover:text-red-700 underline"
120
+ >
121
+ End Interview
122
+ </button>
123
+ </div>
124
+ );
125
+
126
+ // 3. Results Phase (Simple Placeholder)
127
+ const renderResults = () => (
128
+ <div className="bg-green-50 p-8 rounded-xl shadow-xl text-center">
129
+ <CheckCircle size={48} className="text-green-600 mx-auto mb-4" />
130
+ <h3 className="text-3xl font-bold text-green-700 mb-2">Interview Ended</h3>
131
+ <p className="text-gray-700 mb-6">Thank you for practicing! Your detailed feedback and results are being compiled now.</p>
132
+ <button
133
+ onClick={() => setInterviewState('config')}
134
+ className="px-6 py-3 bg-green-600 text-white rounded-lg hover:bg-green-700 transition duration-150"
135
+ >
136
+ Start New Interview
137
+ </button>
138
+ </div>
139
+ );
140
+
141
+ // --- MAIN RENDER ---
142
+
143
+ return (
144
+ <div className="p-8 max-w-4xl mx-auto">
145
+ <h1 className="text-4xl font-extrabold text-gray-800 mb-6">AI Interview Practice 🤖</h1>
146
+
147
+ {/* State rendering */}
148
+ {interviewState === 'config' && renderConfig()}
149
+ {interviewState === 'chat' && renderChat()}
150
+ {interviewState === 'results' && renderResults()}
151
+ </div>
152
+ );
153
+ };
154
+
155
+ export default AIInterview;
Frontend/src/pages/dashboard.tsx ADDED
@@ -0,0 +1,112 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import YearlyStreak from "../components/dashboard/YearlyStreak";
2
+ import FeedbackScore from "../components/dashboard/FeedBackScore";
3
+ import SkillRadarChart from "../components/dashboard/SkillRadarChart";
4
+ import WeakAreaBanner from "../components/dashboard/WeakAreaBanner";
5
+ import InterviewPlayback from "../components/dashboard/InterviewPlayback";
6
+ import { generateYearlyStreakData } from "../utils/generateYearlyStreakData";
7
+
8
+ const Dashboard = () => {
9
+ const streakData = generateYearlyStreakData();
10
+
11
+ const radarData = [
12
+ { skill: "DSA", value: 70 },
13
+ { skill: "System Design", value: 60 },
14
+ { skill: "Communication", value: 85 },
15
+ { skill: "Problem Solving", value: 75 },
16
+ { skill: "Accuracy", value: 68 },
17
+ { skill: "Time Mgmt", value: 80 },
18
+ ];
19
+
20
+ const weakTopic = "Dynamic Programming";
21
+
22
+ return (
23
+ // PRIMARY CHANGE: Background Gradient inspired by landing page
24
+ // Using a custom CSS class for a more complex gradient if needed, or approximating with Tailwind.
25
+ // For now, let's use a subtle linear gradient that implies the dark blue-black.
26
+ <div className="px-6 py-8 space-y-10 min-h-screen text-gray-100 bg-black font-OpenSans">
27
+ {/* Font sans is a good default for modern look */}
28
+
29
+ {/* ----------- HEADER SECTION (Updated for new theme) ----------- */}
30
+ <div className="flex flex-col md:flex-row md:items-center justify-between mb-4">
31
+ <h1 className="text-3xl lg:text-4xl font-extrabold text-gray-50 tracking-tight">
32
+ 👋 Welcome back, <span className="text-blue-400">Prakhar</span>
33
+ </h1>
34
+
35
+ <div className="flex items-center space-x-3 mt-4 md:mt-0">
36
+ {/* PRIMARY BUTTON: Vibrant Purple Theme Color, matching "Start Free Trial" */}
37
+ <button className="px-6 py-2 bg-gradient-to-r from-blue-600 to-blue-800 text-white rounded-lg shadow-lg shadow-purple-500/30 hover:from-blue-500 hover:to-blue-700 transition-all duration-300 ease-in-out font-semibold">
38
+ Start Interview
39
+ </button>
40
+ </div>
41
+ </div>
42
+
43
+ {/* ----------- GRID MAIN LAYOUT (2 COLUMNS for top content) ----------- */}
44
+ <div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
45
+
46
+ {/* LEFT PANEL (Feedback Score) */}
47
+ <div className="space-y-6 col-span-1">
48
+ {/* CARD BACKGROUND CHANGE: Dark Card Color, subtle border/shadow */}
49
+ <div className="bg-gradient-to-br from-[#1a202c] to-[#2d3748] rounded-xl shadow-lg p-6 border border-gray-700/50 h-full">
50
+ <h2 className="text-xl font-bold mb-4 text-gray-50">AI Feedback Score</h2>
51
+ <FeedbackScore
52
+ confidence={78}
53
+ clarity={82}
54
+ accuracy={70}
55
+ speed={65}
56
+ improvements={[
57
+ "Improve explanation clarity",
58
+ "Practice more DP problems",
59
+ "Reduce filler words in answers",
60
+ ]}
61
+ />
62
+ </div>
63
+ </div>
64
+
65
+ {/* RIGHT PANEL (Skill Chart) */}
66
+ <div className="space-y-6 col-span-1">
67
+ {/* CARD BACKGROUND CHANGE: Dark Card Color, subtle border/shadow */}
68
+ <div className="bg-gradient-to-br from-[#1a202c] to-[#2d3748] rounded-xl shadow-lg p-6 border border-gray-700/50 h-full">
69
+ <h2 className="text-xl font-bold mb-4 text-gray-50">Skill Strength Chart</h2>
70
+ <SkillRadarChart data={radarData} />
71
+ </div>
72
+ </div>
73
+ </div>
74
+
75
+ {/* ----------- MIDDLE ROW: INTERVIEW PLAYBACK (LEFT) AND WEAK AREA (RIGHT) ----------- */}
76
+ <div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
77
+
78
+ {/* INTERVIEW PLAYBACK (2/3 width on large screens, LEFT) */}
79
+ {/* CARD BACKGROUND CHANGE: Dark Card Color, subtle border/shadow */}
80
+ <div className="bg-gradient-to-br from-[#1a202c] to-[#2d3748] rounded-xl shadow-lg p-6 border border-gray-700/50 lg:col-span-2">
81
+ <h2 className="text-xl font-bold mb-4 text-gray-50">Interview Playback AI Feedback</h2>
82
+ <InterviewPlayback
83
+ audioUrl="https://example.com/audio.mp3"
84
+ transcript={`Interviewer: Explain polymorphism.\nYou: Polymorphism means...`}
85
+ highlights={[
86
+ "Answer lacked real-world example",
87
+ "Need more clarity in describing LLD concepts",
88
+ "Example Interview Playback",
89
+ ]}
90
+ />
91
+ </div>
92
+
93
+ {/* WEAK AREA (1/3 width on large screens, RIGHT) */}
94
+ {/* CARD BACKGROUND CHANGE: Dark Card Color, subtle border/shadow */}
95
+ <div className="bg-gradient-to-br from-[#1a202c] to-[#2d3748] rounded-xl shadow-lg p-5 border border-gray-700/50 col-span-1 flex-col items-center justify-center">
96
+ {/* WeakAreaBanner will need internal styling adjustments for its alert nature */}
97
+ <h2 className="text-xl font-bold mb-4 text-gray-50">WeakAreaBanner</h2>
98
+ <WeakAreaBanner topic={weakTopic} />
99
+ </div>
100
+ </div>
101
+
102
+ {/* ----------- BOTTOM ROW: YEARLY STREAK (FULL WIDTH) ----------- */}
103
+ {/* CARD BACKGROUND CHANGE: Dark Card Color, subtle border/shadow */}
104
+ <div className="bg-gradient-to-br from-[#1a202c] to-[#2d3748] rounded-xl shadow-lg p-6 border border-gray-700/50">
105
+ <h2 className="text-xl font-bold mb-3 text-gray-50">Yearly Streak</h2>
106
+ <YearlyStreak data={streakData} />
107
+ </div>
108
+ </div>
109
+ );
110
+ };
111
+
112
+ export default Dashboard;
Frontend/src/pages/home.tsx ADDED
@@ -0,0 +1,409 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import React, { useState, useEffect, useRef } from 'react';
2
+ import { Sparkles, Zap, Target, Clock, Award, ChevronRight, Menu, X } from 'lucide-react';
3
+ import AuthModal from '../components/auth/AuthModal';
4
+ import SignIn from '../components/auth/SignIn';
5
+ import SignUp from '../components/auth/SignUp';
6
+ import { SplineScene } from '../components/ui/splite';
7
+ import { Spotlight } from '../components/ui/spotlight';
8
+
9
+ interface Feature {
10
+ icon: React.ReactNode;
11
+ title: string;
12
+ description: string;
13
+ }
14
+
15
+ interface Step {
16
+ step: string;
17
+ title: string;
18
+ desc: string;
19
+ }
20
+
21
+ // Add onLogin prop
22
+ interface AIInterviewPlatformProps {
23
+ onLogin: () => void;
24
+ }
25
+
26
+ const AIInterviewPlatform: React.FC<AIInterviewPlatformProps> = ({ onLogin }) => {
27
+ const [isMenuOpen, setIsMenuOpen] = useState<boolean>(false);
28
+ const [scrolled, setScrolled] = useState<boolean>(false);
29
+ const [modalType, setModalType] = useState<'none' | 'signIn' | 'signUp'>('none');
30
+
31
+ // Handlers for opening/closing modals
32
+ const openSignInModal = () => {
33
+ setModalType('signIn');
34
+ setIsMenuOpen(false);
35
+ };
36
+
37
+ const openSignUpModal = () => {
38
+ setModalType('signUp');
39
+ setIsMenuOpen(false);
40
+ };
41
+
42
+ const closeModal = () => setModalType('none');
43
+
44
+ // Handle successful authentication
45
+ const handleAuthSuccess = () => {
46
+ closeModal();
47
+ onLogin(); // Call the parent function to update auth state
48
+ };
49
+
50
+ useEffect(() => {
51
+ const handleScroll = (): void => {
52
+ setScrolled(window.scrollY > 50);
53
+ };
54
+ window.addEventListener('scroll', handleScroll);
55
+ return () => window.removeEventListener('scroll', handleScroll);
56
+ }, []);
57
+
58
+ const features: Feature[] = [
59
+ {
60
+ icon: <Sparkles className="w-8 h-8" />,
61
+ title: "AI-Powered Questions",
62
+ description: "Dynamic questions adapted to your skill level and role"
63
+ },
64
+ {
65
+ icon: <Zap className="w-8 h-8" />,
66
+ title: "Instant Feedback",
67
+ description: "Get real-time analysis and improvement suggestions"
68
+ },
69
+ {
70
+ icon: <Target className="w-8 h-8" />,
71
+ title: "Role-Specific Prep",
72
+ description: "Tailored scenarios for your target position"
73
+ },
74
+ {
75
+ icon: <Clock className="w-8 h-8" />,
76
+ title: "Practice Anytime",
77
+ description: "24/7 access to unlimited mock interviews"
78
+ },
79
+ {
80
+ icon: <Award className="w-8 h-8" />,
81
+ title: "Performance Analytics",
82
+ description: "Track your progress with detailed insights"
83
+ }
84
+ ];
85
+
86
+ const steps: Step[] = [
87
+ { step: "01", title: "Choose Your Role", desc: "Select the job position you're preparing for" },
88
+ { step: "02", title: "Practice Interview", desc: "Answer AI-generated questions in real-time" },
89
+ { step: "03", title: "Get Feedback", desc: "Receive detailed analysis and improvement tips" }
90
+ ];
91
+
92
+ const heroRef = useRef<HTMLDivElement>(null);
93
+
94
+ return (
95
+ <div className="w-full min-h-screen bg-linear-to-br from-blue-900 to-gray-400 text-white overflow-x-hidden font-opensans">
96
+ {/* Navigation Bar */}
97
+ <nav className={`fixed top-0 left-0 right-0 w-full z-50 transition-all duration-300 ${scrolled ? 'bg-slate-900/95 backdrop-blur-md shadow-xl' : 'bg-slate-900/80 backdrop-blur-sm'}`}>
98
+ <div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
99
+ <div className="flex justify-between items-center h-20">
100
+ {/* Logo */}
101
+ <div className="flex items-center space-x-3">
102
+ <div className="bg-linear-to-br from-blue-500 to-gray-400 p-2 rounded-lg">
103
+ <Sparkles className="w-6 h-6 text-white" />
104
+ </div>
105
+ <span className="text-2xl font-bold bg-linear-to-br from-blue-500 to-gray-400 bg-clip-text text-transparent">
106
+ InterviewAI
107
+ </span>
108
+ </div>
109
+
110
+ {/* Desktop Navigation */}
111
+ <div className="hidden lg:flex items-center space-x-8">
112
+ <a href="#home" className="text-gray-200 hover:text-blue-400 transition-colors font-medium">
113
+ Home
114
+ </a>
115
+ <a href="#about" className="text-gray-200 hover:text-blue-400 transition-colors font-medium">
116
+ About
117
+ </a>
118
+ <a href="#features" className="text-gray-200 hover:text-blue-400 transition-colors font-medium">
119
+ Features
120
+ </a>
121
+ <a href="#how-it-works" className="text-gray-200 hover:text-blue-400 transition-colors font-medium">
122
+ How It Works
123
+ </a>
124
+ <button onClick={openSignInModal} className="px-6 py-2.5 rounded-lg border-2 border-blue-400 text-blue-400 hover:bg-blue-400/10 transition-all font-medium">
125
+ Sign In
126
+ </button>
127
+ <button onClick={openSignUpModal} className="px-6 py-2.5 rounded-lg bg-linear-to-br from-blue-500 to-blue-500 hover:from-blue-600 hover:to-blue-900 transition-all shadow-lg shadow-blue-500/30 font-medium">
128
+ Sign Up
129
+ </button>
130
+ </div>
131
+
132
+ {/* Mobile Menu Button */}
133
+ <button
134
+ className="lg:hidden p-2 rounded-lg hover:bg-white/10 transition-colors"
135
+ onClick={() => setIsMenuOpen(!isMenuOpen)}
136
+ >
137
+ {isMenuOpen ? <X className="w-6 h-6" /> : <Menu className="w-6 h-6" />}
138
+ </button>
139
+ </div>
140
+ </div>
141
+
142
+ {/* Mobile Menu */}
143
+ {isMenuOpen && (
144
+ <div className="lg:hidden border-t border-white/10 bg-slate-900/98 backdrop-blur-md">
145
+ <div className="px-4 py-4 space-y-3 max-w-7xl mx-auto">
146
+ <a
147
+ href="#home"
148
+ className="block py-3 px-4 rounded-lg text-gray-200 hover:bg-blue-500/10 hover:text-blue-400 transition-all font-medium"
149
+ onClick={() => setIsMenuOpen(false)}
150
+ >
151
+ Home
152
+ </a>
153
+ <a
154
+ href="#about"
155
+ className="block py-3 px-4 rounded-lg text-gray-200 hover:bg-blue-500/10 hover:text-blue-400 transition-all font-medium"
156
+ onClick={() => setIsMenuOpen(false)}
157
+ >
158
+ About
159
+ </a>
160
+ <a
161
+ href="#features"
162
+ className="block py-3 px-4 rounded-lg text-gray-200 hover:bg-blue-500/10 hover:text-blue-400 transition-all font-medium"
163
+ onClick={() => setIsMenuOpen(false)}
164
+ >
165
+ Features
166
+ </a>
167
+ <a
168
+ href="#how-it-works"
169
+ className="block py-3 px-4 rounded-lg text-gray-200 hover:bg-blue-500/10 hover:text-blue-400 transition-all font-medium"
170
+ onClick={() => setIsMenuOpen(false)}
171
+ >
172
+ How It Works
173
+ </a>
174
+ <button onClick={openSignInModal} className="w-full py-3 rounded-lg border-2 border-blue-400 text-blue-400 hover:bg-blue-400/10 transition-all font-medium">
175
+ Sign In
176
+ </button>
177
+ <button onClick={openSignUpModal} className="w-full py-3 rounded-lg bg-linear-to-br from-blue-500 to-blue-500 hover:from-blue-600 hover:to-blue-900 transition-all font-medium">
178
+ Sign Up
179
+ </button>
180
+ </div>
181
+ </div>
182
+ )}
183
+ </nav>
184
+
185
+ {/* Auth Modals */}
186
+ <AuthModal isOpen={modalType === 'signIn'} onClose={closeModal}>
187
+ <SignIn
188
+ onClose={closeModal}
189
+ onSwitchToSignUp={openSignUpModal}
190
+ onAuthSuccess={handleAuthSuccess}
191
+ />
192
+ </AuthModal>
193
+
194
+ <AuthModal isOpen={modalType === 'signUp'} onClose={closeModal}>
195
+ <SignUp
196
+ onClose={closeModal}
197
+ onSwitchToSignIn={openSignInModal}
198
+ onAuthSuccess={handleAuthSuccess}
199
+ />
200
+ </AuthModal>
201
+
202
+ {/* Hero Section */}
203
+ <section ref={heroRef} id="home" className="min-h-[calc(100vh-68px)] flex items-center pt-20 pb-20 px-4 sm:px-6 lg:px-8 relative overflow-hidden bg-black">
204
+ {/* Spotlight applied directly to the container as per the demo structure */}
205
+ <Spotlight parentRef={heroRef} color="#4b9fff" className="mix-blend-screen" />
206
+ <div className="max-w-7xl mx-auto w-full relative z-10">
207
+ <div className="grid grid-cols-1 lg:grid-cols-2 gap-12 items-center">
208
+ {/* Left side - Text content */}
209
+ <div>
210
+ <h1 className="text-5xl sm:text-6xl lg:text-7xl font-bold mb-6 leading-tight">
211
+ Master Your Next
212
+ <span className="block bg-linear-to-br from-blue-500 via-gray-400 to-blue-500 bg-clip-text text-transparent">
213
+ Interview with AI
214
+ </span>
215
+ </h1>
216
+ <p className="text-xl text-gray-300 mb-10 max-w-lg">
217
+ Practice with our intelligent AI interviewer, get instant feedback, and land your dream job with confidence.
218
+ </p>
219
+ <button
220
+ onClick={openSignUpModal}
221
+ className="px-8 py-4 rounded-xl bg-linear-to-br from-blue-600 to-purple-600 hover:from-blue-700 hover:to-purple-700 transition duration-300 shadow-xl shadow-blue-600/30 flex items-center gap-2 text-lg font-semibold transform hover:scale-[1.03]"
222
+ >
223
+ Start Free Trial
224
+ <ChevronRight className="w-5 h-5" />
225
+ </button>
226
+ </div>
227
+
228
+ {/* Right side - 3D Scene */}
229
+ <div className="h-[500px] lg:h-[600px] relative">
230
+ <SplineScene
231
+ scene="https://prod.spline.design/kZDDjO5HuC9GJUM2/scene.splinecode"
232
+ className="w-full h-full"
233
+ />
234
+ </div>
235
+ </div>
236
+ </div>
237
+ </section>
238
+
239
+ {/* About Section */}
240
+ <section id="about" className="py-20 px-4 sm:px-6 lg:px-8 bg-black/40">
241
+ <div className="max-w-6xl mx-auto">
242
+ <div className="grid grid-cols-1 lg:grid-cols-2 gap-12 items-center">
243
+ <div>
244
+ <h2 className="text-4xl sm:text-5xl font-bold mb-6">
245
+ About InterviewAI
246
+ </h2>
247
+ <p className="text-lg text-gray-300 mb-6">
248
+ We're revolutionizing interview preparation with cutting-edge AI technology. Our platform helps candidates practice, learn, and succeed in their job interviews.
249
+ </p>
250
+ <p className="text-lg text-gray-300 mb-6">
251
+ Founded by industry experts and powered by advanced machine learning, InterviewAI provides personalized interview experiences that adapt to your unique needs and goals.
252
+ </p>
253
+ <div className="space-y-4">
254
+ <div className="flex items-center gap-3">
255
+ <div className="w-2 h-2 bg-blue-400 rounded-full"></div>
256
+ <span className="text-gray-300">Advanced AI interview simulations</span>
257
+ </div>
258
+ <div className="flex items-center gap-3">
259
+ <div className="w-2 h-2 bg-blue-600 rounded-full"></div>
260
+ <span className="text-gray-300">Personalized feedback and coaching</span>
261
+ </div>
262
+ <div className="flex items-center gap-3">
263
+ <div className="w-2 h-2 bg-blue-400 rounded-full"></div>
264
+ <span className="text-gray-300">Industry-leading success rates</span>
265
+ </div>
266
+ </div>
267
+ </div>
268
+ <div className="bg-linear-to-br from-blue-900/50 to-gray-900/50 rounded-2xl p-8 border border-gray-200/30">
269
+ <div className="space-y-6">
270
+ <div className="bg-white/5 backdrop-blur-sm rounded-lg p-6">
271
+ <div className="text-3xl font-bold text-blue-400 mb-2">2020</div>
272
+ <div className="text-gray-400">Founded</div>
273
+ </div>
274
+ <div className="bg-white/5 backdrop-blur-sm rounded-lg p-6">
275
+ <div className="text-3xl font-bold text-blue-500 mb-2">50K+</div>
276
+ <div className="text-gray-400">Happy Users</div>
277
+ </div>
278
+ <div className="bg-white/5 backdrop-blur-sm rounded-lg p-6">
279
+ <div className="text-3xl font-bold text-blue-400 mb-2">500+</div>
280
+ <div className="text-gray-400">Companies Trust Us</div>
281
+ </div>
282
+ </div>
283
+ </div>
284
+ </div>
285
+ </div>
286
+ </section>
287
+
288
+ {/* Features Section */}
289
+ <section id="features" className="py-20 px-4 sm:px-6 lg:px-8 bg-black">
290
+ <div className="max-w-7xl mx-auto">
291
+ <div className="text-center mb-16">
292
+ <h2 className="text-4xl sm:text-5xl font-bold mb-4">
293
+ Why Choose InterviewAI?
294
+ </h2>
295
+ <p className="text-xl text-gray-400">
296
+ Everything you need to ace your next interview
297
+ </p>
298
+ </div>
299
+ <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8">
300
+ {features.map((feature: Feature, index: number) => (
301
+ <div
302
+ key={index}
303
+ className="bg-linear-to-br from-blue-900/50 to-gray-900/50 backdrop-blur-sm rounded-xl p-8 border border-blue-500/20 hover:border-gray-500/50 transition-all duration-300 hover:transform hover:scale-105"
304
+ >
305
+ <div className="bg-linear-to-br from-blue-500 to-gray-400 w-16 h-16 rounded-lg flex items-center justify-center mb-4 shadow-lg shadow-blue-500/50">
306
+ {feature.icon}
307
+ </div>
308
+ <h3 className="text-xl font-bold mb-3">{feature.title}</h3>
309
+ <p className="text-gray-400">{feature.description}</p>
310
+ </div>
311
+ ))}
312
+ </div>
313
+ </div>
314
+ </section>
315
+
316
+ {/* How It Works */}
317
+ <section id="how-it-works" className="py-20 px-4 sm:px-6 lg:px-8 bg-linear-to-br from-blue-900/50 to-gray-900/50 rounded-2xl border border-gray-200/30">
318
+ <div className="max-w-7xl mx-auto">
319
+ <div className="text-center mb-16">
320
+ <h2 className="text-4xl sm:text-5xl font-bold mb-4">
321
+ How It Works
322
+ </h2>
323
+ <p className="text-xl text-gray-400">
324
+ Get started in three simple steps
325
+ </p>
326
+ </div>
327
+
328
+ <div className="grid grid-cols-1 md:grid-cols-3 gap-8">
329
+ {steps.map((item: Step, index: number) => (
330
+ <div key={index} className="relative text-center">
331
+ <div className="text-7xl font-bold text-white mb-4">
332
+ {item.step}
333
+ </div>
334
+ <h3 className="text-2xl font-bold mb-3">{item.title}</h3>
335
+ <p className="text-gray-400">{item.desc}</p>
336
+
337
+ {index < 2 && (
338
+ <ChevronRight className="hidden md:block absolute top-12 -right-12 w-8 h-8 text-white" />
339
+ )}
340
+ </div>
341
+ ))}
342
+ </div>
343
+ </div>
344
+ </section>
345
+
346
+
347
+ {/* CTA Section */}
348
+ <section className="py-20 px-4 sm:px-6 lg:px-8 bg-black">
349
+ <div className="max-w-4xl mx-auto text-center">
350
+ <h2 className="text-4xl sm:text-5xl font-bold mb-6">
351
+ Ready to Ace Your Interview?
352
+ </h2>
353
+ <p className="text-xl text-gray-300 mb-10">
354
+ Join thousands of successful candidates who prepared with InterviewAI
355
+ </p>
356
+ <button
357
+ onClick={openSignUpModal}
358
+ className="px-10 py-5 rounded-lg bg-linear-to-r from-blue-400 to-blue-700 hover:from-blue-600 hover:to-blue-900 transition shadow-lg shadow-blue-500/50 text-lg font-semibold"
359
+ >
360
+ Start Your Free Trial Today
361
+ </button>
362
+ </div>
363
+ </section>
364
+
365
+ {/* Footer */}
366
+ <footer className="w-full py-6 px-6 bg-slate-900/95 backdrop-blur-md text-gray-200 flex flex-col sm:flex-row items-center justify-between shadow-inner">
367
+ {/* Left Side */}
368
+ <div className="flex items-center space-x-3">
369
+ {/* Logo */}
370
+ <div className="bg-linear-to-br from-blue-500 to-gray-400 p-2 rounded-lg">
371
+ <Sparkles className="w-6 h-6 text-white" />
372
+ </div>
373
+
374
+ <p className="text-sm">
375
+ Copyright © {new Date().getFullYear()} — All rights reserved
376
+ </p>
377
+ </div>
378
+
379
+ {/* Right Side */}
380
+ <div className="flex items-center gap-5 mt-4 sm:mt-0">
381
+ {/* Twitter */}
382
+ <a href="#" className="hover:text-blue-400 transition">
383
+ <svg
384
+ xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" className="fill-current">
385
+ <path d="M24 4.557a9.93 9.93 0 01-2.828.775A4.93 4.93 0 0023.337 3a9.864 9.864 0 01-3.127 1.195A4.92 4.92 0 0016.616 3c-2.72 0-4.924 2.21-4.924 4.932 0 .39.042.765.124 1.126C7.728 8.89 4.1 6.91 1.67 3.917a4.936 4.936 0 00-.665 2.48c0 1.71.86 3.213 2.17 4.096A4.9 4.9 0 01.96 9.96v.06c0 2.387 1.68 4.374 3.91 4.828a4.93 4.93 0 01-2.224.086c.626 1.956 2.444 3.384 4.6 3.425A9.874 9.874 0 010 21.54 13.945 13.945 0 007.548 24c9.056 0 14.01-7.512 14.01-14.015 0-.213-.005-.426-.015-.637A9.94 9.94 0 0024 4.557z" />
386
+ </svg>
387
+ </a>
388
+
389
+ {/* YouTube */}
390
+ <a href="#" className="hover:text-red-500 transition">
391
+ <svg
392
+ xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" className="fill-current">
393
+ <path d="M19.615 3.184C21.403 3.67 22 5.84 22 12s-.597 8.33-2.385 8.816C17.42 21.27 12 21.27 12 21.27s-5.42 0-7.615-.454C2.597 20.33 2 18.16 2 12s.597-8.33 2.385-8.816C6.58 2.73 12 2.73 12 2.73s5.42 0 7.615.454zM10 8.5l6 3.5-6 3.5v-7z" />
394
+ </svg>
395
+ </a>
396
+
397
+ {/* Facebook */}
398
+ <a href="#" className="hover:text-blue-500 transition">
399
+ <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" className="fill-current">
400
+ <path d="M9 8H6v4h3v12h5V12h3.642L18 8h-4V6.333C14 5.378 14.2 5 15.112 5H18V0h-3.667C10.55 0 9 1.517 9 4.308V8z" />
401
+ </svg>
402
+ </a>
403
+ </div>
404
+ </footer>
405
+ </div>
406
+ );
407
+ };
408
+
409
+ export default AIInterviewPlatform;
Frontend/src/pages/note.tsx ADDED
@@ -0,0 +1,168 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import React from "react";
2
+ import { FileText, History, RefreshCw, Plus, Download, Upload, Save, Star, Menu, X } from "lucide-react";
3
+
4
+ // Placeholder data for the Summary/Important Parts section
5
+ const sampleSummary = [
6
+ "DP weakness identified. Must solve 10 hard DP problems this week.",
7
+ "Crucial to articulate Time/Space Complexity for every solution.",
8
+ "Practice conversational pacing to reduce filler words.",
9
+ ];
10
+
11
+ const Notes: React.FC = () => {
12
+ // State for the notes content
13
+ const [notesContent, setNotesContent] = React.useState(
14
+ `Goal: Focus on Dynamic Programming and explanation clarity.\n\nKey DP Concepts to review:\n1. Overlapping Subproblems\n2. Optimal Substructure\n3. Memoization vs. Tabulation\n\nInterview Explanation Focus:\n1. State the approach (e.g., "I will use DP with memoization").\n2. Clearly define the state/subproblem (e.g., "dp[i] represents...").\n3. State the base case(s).\n4. Define the recurrence relation.\n5. Analyze Time/Space Complexity (O(n)).\n\n*Self-Reminder: Use fewer 'um's and 'like's.*`
15
+ );
16
+
17
+ // NEW STATE: State to manage the sidebar's open/close status
18
+ const [isSidebarOpen, setIsSidebarOpen] = React.useState(true);
19
+
20
+ // Toggle function
21
+ const toggleSidebar = () => {
22
+ setIsSidebarOpen(!isSidebarOpen);
23
+ };
24
+
25
+ // A function to simulate saving the notes (placeholder)
26
+ const handleSave = () => {
27
+ alert("Notes Saved!");
28
+ // In a real app, you would call an API here
29
+ };
30
+
31
+ return (
32
+ // Ensure the overall container is flex and full viewport height
33
+ <div className="flex bg-black h-screen overflow-hidden">
34
+
35
+ {/* 1. Left Sidebar: Navigation & Utility (New, History, Upload) */}
36
+ <div
37
+ className={`
38
+ // Full height and transition for sliding
39
+ h-screen flex-shrink-0 transition-all duration-300 ease-in-out
40
+ bg-gray-800 flex flex-col gap-4 shadow-xl
41
+ ${isSidebarOpen ? 'w-56 p-4' : 'w-0 p-0 overflow-hidden'} // Transition controls width and padding
42
+ `}
43
+ >
44
+ {isSidebarOpen && ( // Only show content when open
45
+ <>
46
+ <h3 className="text-xl font-bold text-white mb-2 border-b border-gray-700 pb-2">My Notes</h3>
47
+
48
+ <button
49
+ className="flex items-center gap-3 w-full bg-blue-600 text-white px-4 py-3 rounded-xl hover:bg-blue-700 transition duration-150 font-semibold whitespace-nowrap"
50
+ aria-label="Create New Note"
51
+ >
52
+ <Plus size={20} />
53
+ New Note
54
+ </button>
55
+
56
+ <button
57
+ className="flex items-center gap-3 w-full text-gray-300 px-4 py-3 rounded-xl hover:bg-gray-700 hover:text-white transition duration-150 whitespace-nowrap"
58
+ aria-label="Upload Notes"
59
+ >
60
+ <Upload size={20} />
61
+ Upload
62
+ </button>
63
+
64
+ <button
65
+ className="flex items-center gap-3 w-full text-gray-300 px-4 py-3 rounded-xl hover:bg-gray-700 hover:text-white transition duration-150 whitespace-nowrap"
66
+ aria-label="View History"
67
+ >
68
+ <History size={20} />
69
+ History
70
+ </button>
71
+ </>
72
+ )}
73
+ </div>
74
+
75
+ {/* 2. Main Content Area */}
76
+ <div className="flex-1 p-8 overflow-y-auto"> {/* Allow main content to scroll */}
77
+
78
+ <header className="flex justify-between items-center mb-6">
79
+ {/* Toggle Button for Sidebar - Moved to the header of the main content */}
80
+ <div className="flex items-center gap-4">
81
+ <button
82
+ onClick={toggleSidebar}
83
+ className="p-2 rounded-full bg-gray-200 hover:bg-gray-300 text-gray-800 transition-colors duration-200"
84
+ aria-label={isSidebarOpen ? "Close Sidebar" : "Open Sidebar"}
85
+ >
86
+ {isSidebarOpen ? <X size={24} /> : <Menu size={24} />}
87
+ </button>
88
+ <h2 className="text-4xl font-extrabold text-white"> My Prep Notes</h2>
89
+ </div>
90
+
91
+ {/* Top Right Actions (Save, Rephrase, Download) */}
92
+ <div className="flex gap-3">
93
+ <button
94
+ onClick={handleSave}
95
+ className="flex items-center gap-2 bg-green-600 text-white px-4 py-2 rounded-lg hover:bg-green-700 transition duration-150 font-medium shadow-md"
96
+ aria-label="Save Current Note"
97
+ >
98
+ <Save size={18} />
99
+ Save
100
+ </button>
101
+
102
+ <button
103
+ className="flex items-center gap-2 bg-purple-600 text-white px-4 py-2 rounded-lg hover:bg-purple-700 transition duration-150"
104
+ aria-label="Rephrase Selected Text"
105
+ >
106
+ <RefreshCw size={18} />
107
+ Rephrase
108
+ </button>
109
+
110
+ <button
111
+ className="flex items-center gap-2 bg-indigo-600 text-white px-4 py-2 rounded-lg hover:bg-indigo-700 transition duration-150"
112
+ aria-label="Download Notes"
113
+ >
114
+ <Download size={18} />
115
+ Download
116
+ </button>
117
+ </div>
118
+ </header>
119
+
120
+ {/* Note Editor and Summary Section */}
121
+ <div className="grid grid-cols-1 md:grid-cols-3 gap-8">
122
+
123
+ {/* Middle Section: Notes Text Area (Takes 2/3 width on large screens) */}
124
+ <div className="md:col-span-2">
125
+ <p className="text-white mb-2 font-medium">Current Note: Dynamic Programming & Clarity</p>
126
+ <textarea
127
+ className="w-full h-[600px] p-6 text-lg border-2 bg-white border-gray-300 rounded-xl shadow-lg focus:outline-none focus:ring-4 focus:ring-blue-500/50 resize-none font-mono leading-relaxed"
128
+ placeholder="Write your notes here..."
129
+ value={notesContent}
130
+ onChange={(e) => setNotesContent(e.target.value)}
131
+ ></textarea>
132
+ </div>
133
+
134
+ {/* Right Section: Summary/Important Parts (Takes 1/3 width) */}
135
+ <div className="md:col-span-1">
136
+ <div className="bg-white p-6 rounded-xl shadow-lg h-full border border-gray-200">
137
+ <h3 className="text-xl font-bold text-gray-800 mb-4 flex items-center gap-2 border-b pb-2">
138
+ <Star className="text-yellow-500" size={20} />
139
+ AI Summary & Key Takeaways
140
+ </h3>
141
+ <p className="text-sm text-gray-600 mb-4">
142
+ This section extracts or highlights the most important parts of your current note or feedback.
143
+ </p>
144
+ <ul className="space-y-3">
145
+ {sampleSummary.map((item, index) => (
146
+ <li key={index} className="flex items-start gap-2 text-gray-700">
147
+ <span className="text-yellow-500 font-extrabold text-lg">•</span>
148
+ <span className="text-sm">{item}</span>
149
+ </li>
150
+ ))}
151
+ </ul>
152
+
153
+ <button
154
+ className="mt-6 flex items-center gap-2 bg-gray-200 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-300 transition duration-150 text-sm w-full justify-center"
155
+ aria-label="Generate Summary"
156
+ >
157
+ <FileText size={16} />
158
+ Generate Summary
159
+ </button>
160
+ </div>
161
+ </div>
162
+ </div>
163
+ </div>
164
+ </div>
165
+ );
166
+ };
167
+
168
+ export default Notes;
Frontend/src/pages/quize.tsx ADDED
@@ -0,0 +1,125 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import React from "react";
2
+ import { FileText, FileSpreadsheet, Code2, ListChecks, UploadCloud, Type } from "lucide-react";
3
+
4
+ // The structure of this component is heavily modified to meet the new layout requirements.
5
+ const ResumeGeneratedQuize: React.FC = () => {
6
+
7
+ // Consistent purple button style
8
+ const buttonClass = "w-full py-3 rounded-lg bg-gradient-to-r from-blue-500 to-blue-700 hover:from-blue-400 hover:to-blue-600 font-medium transition shadow-lg shadow-blue-500/30 text-white mt-4";
9
+
10
+ const OutputTypeOption = ({ icon, title, desc }: { icon: React.ReactNode; title: string; desc: string }) => (
11
+ // These cards inherently take full width of their parent container (which is now the right column)
12
+ <div className="p-4 bg-slate-900/50 rounded-xl border border-slate-700 hover:bg-slate-800/60 transition cursor-pointer">
13
+ <div className="flex items-center gap-3 mb-2">
14
+ {icon}
15
+ <h4 className="text-xl font-semibold text-gray-50">{title}</h4>
16
+ </div>
17
+ <p className="text-gray-400 text-sm">{desc}</p>
18
+ </div>
19
+ );
20
+
21
+ const SourceCard = ({ icon, title, desc, actionText }: { icon: React.ReactNode; title: string; desc: string; actionText: string }) => (
22
+ <div className="p-6 bg-slate-900/60 rounded-2xl shadow-xl border border-slate-700 hover:bg-slate-800/70 transition flex flex-col h-full">
23
+ <div className="flex items-start gap-4 mb-4">
24
+ {icon}
25
+ <div>
26
+ <h2 className="text-2xl font-bold">{title}</h2>
27
+ <p className="text-gray-400 mt-1 text-sm">{desc}</p>
28
+ </div>
29
+ </div>
30
+ {/* The SourceCard button width is intentionally set to w-fit px-6 to be narrower */}
31
+ <button className={buttonClass.replace('w-full', 'w-fit px-6')} >
32
+ {actionText}
33
+ </button>
34
+ </div>
35
+ );
36
+
37
+ return (
38
+ <div className="min-h-screen bg-black text-white py-20 px-6 lg:px-12">
39
+
40
+ {/* Page Title */}
41
+ <h1 className="text-4xl font-bold mb-16 text-center">
42
+ Smart AI-Powered Quiz Generator
43
+ </h1>
44
+
45
+ {/* ===== MAIN TWO-COLUMN LAYOUT (Source Selection vs. Configuration) ===== */}
46
+ <div className="grid grid-cols-1 lg:grid-cols-2 gap-12">
47
+
48
+ {/* --- LEFT SIDE: INPUT SOURCE SELECTION --- */}
49
+ <div>
50
+ <h3 className="text-3xl font-bold mb-6 text-gray-100 border-b border-blue-700 pb-2">
51
+ 1. Select Quiz Source
52
+ </h3>
53
+ <div className="space-y-8">
54
+ {/* Consolidated Resume/Note PDF Upload Card */}
55
+ <SourceCard
56
+ icon={<FileSpreadsheet className="w-8 h-8 text-cyan-400" />}
57
+ title="Resume/Note PDF Upload"
58
+ desc="Generate quizzes based on skills and experience listed in your resume file."
59
+ actionText="Upload"
60
+ />
61
+ </div>
62
+ </div>
63
+
64
+
65
+ {/* --- RIGHT SIDE: PROMPT & OUTPUT CONFIGURATION (The full width section) --- */}
66
+ <div className="lg:sticky lg:top-8 self-start">
67
+ <h3 className="text-3xl font-bold mb-6 text-gray-100 border-b border-blue-700 pb-2">
68
+ 2. Configure & Generate
69
+ </h3>
70
+
71
+ {/* Prompt/Text Area Section */}
72
+ <div className="bg-slate-900/60 rounded-2xl shadow-2xl p-6 border border-slate-800 mb-8">
73
+ <label htmlFor="prompt-area" className="text-lg font-semibold block mb-3 text-gray-200">
74
+ Custom Prompt/Instructions (Optional)
75
+ </label>
76
+ <textarea
77
+ id="prompt-area"
78
+ rows={4}
79
+ placeholder="e.g., 'Focus only on Python and OOP concepts' or 'Generate a quiz on the content uploaded in step 1'"
80
+ className="w-full p-3 rounded-lg bg-black/40 border border-slate-700 text-gray-100 placeholder-gray-500 focus:outline-none focus:ring-2 focus:ring-purple-600 transition"
81
+ ></textarea>
82
+ <p className="text-gray-500 text-sm mt-2">
83
+ This prompt refines the quiz generation based on the selected source.
84
+ </p>
85
+ </div>
86
+
87
+ {/* Output Type Section - NOW CORRECTLY PLACED INSIDE THE RIGHT COLUMN */}
88
+ </div>
89
+
90
+ </div>
91
+
92
+ <div className="lg:sticky lg:top-8 self-start">
93
+ <h4 className="text-2xl font-semibold mb-4 text-gray-200">
94
+ Choose Output Type:
95
+ </h4>
96
+
97
+ {/* NEW: Use grid-cols-2 and gap-4 to place the options side-by-side */}
98
+ <div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
99
+
100
+ {/* MCQ Quiz Option - takes full width of its column */}
101
+ <OutputTypeOption
102
+ icon={<ListChecks className="w-6 h-6 text-blue-400" />}
103
+ title="Multiple Choice Quiz (MCQ)"
104
+ desc="Ideal for quick assessment of knowledge and comprehension."
105
+ />
106
+
107
+ {/* Coding Quiz Option - takes full width of its column */}
108
+ <OutputTypeOption
109
+ icon={<Code2 className="w-6 h-6 text-blue-400" />}
110
+ title="Coding Challenge Quiz"
111
+ desc="Generates problems requiring code snippets or full functions for evaluation."
112
+ />
113
+ </div>
114
+
115
+ {/* Main Generation Button - Full width (w-full is in buttonClass) */}
116
+ <button className={buttonClass + ' text-xl mt-8'}>
117
+ Generate Quiz Now
118
+ </button>
119
+
120
+ </div>
121
+ </div>
122
+ );
123
+ };
124
+
125
+ export default ResumeGeneratedQuize;
Frontend/src/utils/generateYearlyStreakData.ts ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import dayjs from "dayjs";
2
+
3
+ export const generateYearlyStreakData = () => {
4
+ const today = dayjs();
5
+ const days = [];
6
+
7
+ for (let i = 0; i < 365; i++) {
8
+ const date = today.subtract(i, "day");
9
+
10
+ days.push({
11
+ date: date.format("YYYY-MM-DD"),
12
+ count: Math.floor(Math.random() * 4), // 0–3 activity
13
+ weekday: date.day(),
14
+ week: Math.floor(i / 7),
15
+ month: date.format("MMM"),
16
+ });
17
+ }
18
+
19
+ return days.reverse();
20
+ };
Frontend/tailwind.config.cjs ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /** @type {import('tailwindcss').Config} */
2
+ module.exports = {
3
+ content: [
4
+ "./src/**/*.{js,jsx,ts,tsx}",
5
+ ],
6
+ theme: {
7
+ extend: {
8
+ animation: {
9
+ spotlight: "spotlight 2s ease .75s 1 forwards",
10
+ },
11
+ keyframes: {
12
+ spotlight: {
13
+ "0%": {
14
+ opacity: 0,
15
+ transform: "translate(-72%, -62%) scale(0.5)",
16
+ },
17
+ "100%": {
18
+ opacity: 1,
19
+ transform: "translate(-50%,-40%) scale(1)",
20
+ },
21
+ },
22
+ },
23
+ },
24
+ },
25
+ plugins: [],
26
+ }
Frontend/tsconfig.app.json ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "compilerOptions": {
3
+ "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
4
+ "target": "ES2022",
5
+ "useDefineForClassFields": true,
6
+ "lib": ["ES2022", "DOM", "DOM.Iterable"],
7
+ "module": "ESNext",
8
+ "types": ["vite/client"],
9
+ "skipLibCheck": true,
10
+
11
+ /* Bundler mode */
12
+ "moduleResolution": "bundler",
13
+ "allowImportingTsExtensions": true,
14
+ "verbatimModuleSyntax": true,
15
+ "moduleDetection": "force",
16
+ "noEmit": true,
17
+ "jsx": "react-jsx",
18
+
19
+ /* Linting */
20
+ "strict": true,
21
+ "noUnusedLocals": true,
22
+ "noUnusedParameters": true,
23
+ "erasableSyntaxOnly": true,
24
+ "noFallthroughCasesInSwitch": true,
25
+ "noUncheckedSideEffectImports": true
26
+ },
27
+ "include": ["src"]
28
+ }
Frontend/tsconfig.json ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "files": [],
3
+ "references": [
4
+ { "path": "./tsconfig.app.json" },
5
+ { "path": "./tsconfig.node.json" }
6
+ ],
7
+ "compilerOptions": {
8
+ "baseUrl": ".",
9
+ "paths": {
10
+ "@/*": ["./src/*"]
11
+ }
12
+ }
13
+ }
Frontend/tsconfig.node.json ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "compilerOptions": {
3
+ "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
4
+ "target": "ES2023",
5
+ "lib": ["ES2023"],
6
+ "module": "ESNext",
7
+ "types": ["node"],
8
+ "skipLibCheck": true,
9
+
10
+ /* Bundler mode */
11
+ "moduleResolution": "bundler",
12
+ "allowImportingTsExtensions": true,
13
+ "verbatimModuleSyntax": true,
14
+ "moduleDetection": "force",
15
+ "noEmit": true,
16
+
17
+ /* Linting */
18
+ "strict": true,
19
+ "noUnusedLocals": true,
20
+ "noUnusedParameters": true,
21
+ "erasableSyntaxOnly": true,
22
+ "noFallthroughCasesInSwitch": true,
23
+ "noUncheckedSideEffectImports": true
24
+ },
25
+ "include": ["vite.config.ts"]
26
+ }
Frontend/vite.config.ts ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { defineConfig } from 'vite'
2
+ import tailwindcss from '@tailwindcss/vite'
3
+ import react from '@vitejs/plugin-react'
4
+ import { fileURLToPath } from 'url'; // Required for path resolution
5
+ import path from 'path'; // Required for path resolution
6
+
7
+ // Define the root directory helper function
8
+ const __filename = fileURLToPath(import.meta.url);
9
+ const __dirname = path.dirname(__filename);
10
+
11
+ // https://vitejs.dev/config/
12
+ export default defineConfig({
13
+ plugins: [
14
+ react(),
15
+ tailwindcss()
16
+ ],
17
+ // Explicitly configure path aliases for Vite's module resolution
18
+ // This resolves the "Cannot find module '@/lib/utils'" error during runtime
19
+ resolve: {
20
+ alias: {
21
+ // Maps the '@/...' import path to the absolute path of the './src' directory
22
+ '@': path.resolve(__dirname, './src'),
23
+ },
24
+ },
25
+ })