diff --git a/index.html b/index.html
index 0c589ec..7f2abc5 100644
--- a/index.html
+++ b/index.html
@@ -2,7 +2,7 @@
-
+
Vite + React
diff --git a/package-lock.json b/package-lock.json
index 64a96e2..3384e4f 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -15,7 +15,8 @@
"axios": "^1.7.9",
"react": "^18.3.1",
"react-dom": "^18.3.1",
- "react-redux": "^9.2.0"
+ "react-redux": "^9.2.0",
+ "react-router-dom": "^7.1.3"
},
"devDependencies": {
"@eslint/js": "^9.17.0",
@@ -1721,6 +1722,12 @@
"@babel/types": "^7.20.7"
}
},
+ "node_modules/@types/cookie": {
+ "version": "0.6.0",
+ "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.6.0.tgz",
+ "integrity": "sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==",
+ "license": "MIT"
+ },
"node_modules/@types/estree": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz",
@@ -2282,6 +2289,15 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/cookie": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.0.2.tgz",
+ "integrity": "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ }
+ },
"node_modules/cosmiconfig": {
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz",
@@ -4453,6 +4469,46 @@
"node": ">=0.10.0"
}
},
+ "node_modules/react-router": {
+ "version": "7.1.3",
+ "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.1.3.tgz",
+ "integrity": "sha512-EezYymLY6Guk/zLQ2vRA8WvdUhWFEj5fcE3RfWihhxXBW7+cd1LsIiA3lmx+KCmneAGQuyBv820o44L2+TtkSA==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/cookie": "^0.6.0",
+ "cookie": "^1.0.1",
+ "set-cookie-parser": "^2.6.0",
+ "turbo-stream": "2.4.0"
+ },
+ "engines": {
+ "node": ">=20.0.0"
+ },
+ "peerDependencies": {
+ "react": ">=18",
+ "react-dom": ">=18"
+ },
+ "peerDependenciesMeta": {
+ "react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/react-router-dom": {
+ "version": "7.1.3",
+ "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.1.3.tgz",
+ "integrity": "sha512-qQGTE+77hleBzv9SIUIkGRvuFBQGagW+TQKy53UTZAO/3+YFNBYvRsNIZ1GT17yHbc63FylMOdS+m3oUriF1GA==",
+ "license": "MIT",
+ "dependencies": {
+ "react-router": "7.1.3"
+ },
+ "engines": {
+ "node": ">=20.0.0"
+ },
+ "peerDependencies": {
+ "react": ">=18",
+ "react-dom": ">=18"
+ }
+ },
"node_modules/react-transition-group": {
"version": "4.4.5",
"resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz",
@@ -4680,6 +4736,12 @@
"semver": "bin/semver.js"
}
},
+ "node_modules/set-cookie-parser": {
+ "version": "2.7.1",
+ "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.1.tgz",
+ "integrity": "sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==",
+ "license": "MIT"
+ },
"node_modules/set-function-length": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz",
@@ -4989,6 +5051,12 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/turbo-stream": {
+ "version": "2.4.0",
+ "resolved": "https://registry.npmjs.org/turbo-stream/-/turbo-stream-2.4.0.tgz",
+ "integrity": "sha512-FHncC10WpBd2eOmGwpmQsWLDoK4cqsA/UT/GqNoaKOQnT8uzhtCbg3EoUDMvqpOSAI0S26mr0rkjzbOO6S3v1g==",
+ "license": "ISC"
+ },
"node_modules/type-check": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
diff --git a/package.json b/package.json
index 20a3a40..e8c9537 100644
--- a/package.json
+++ b/package.json
@@ -17,7 +17,8 @@
"axios": "^1.7.9",
"react": "^18.3.1",
"react-dom": "^18.3.1",
- "react-redux": "^9.2.0"
+ "react-redux": "^9.2.0",
+ "react-router-dom": "^7.1.3"
},
"devDependencies": {
"@eslint/js": "^9.17.0",
diff --git a/src/App.css b/src/App.css
index b9d355d..e69de29 100644
--- a/src/App.css
+++ b/src/App.css
@@ -1,42 +0,0 @@
-#root {
- max-width: 1280px;
- margin: 0 auto;
- padding: 2rem;
- text-align: center;
-}
-
-.logo {
- height: 6em;
- padding: 1.5em;
- will-change: filter;
- transition: filter 300ms;
-}
-.logo:hover {
- filter: drop-shadow(0 0 2em #646cffaa);
-}
-.logo.react:hover {
- filter: drop-shadow(0 0 2em #61dafbaa);
-}
-
-@keyframes logo-spin {
- from {
- transform: rotate(0deg);
- }
- to {
- transform: rotate(360deg);
- }
-}
-
-@media (prefers-reduced-motion: no-preference) {
- a:nth-of-type(2) .logo {
- animation: logo-spin infinite 20s linear;
- }
-}
-
-.card {
- padding: 2em;
-}
-
-.read-the-docs {
- color: #888;
-}
diff --git a/src/App.jsx b/src/App.jsx
index f67355a..2a7ff79 100644
--- a/src/App.jsx
+++ b/src/App.jsx
@@ -1,35 +1,41 @@
-import { useState } from 'react'
-import reactLogo from './assets/react.svg'
-import viteLogo from '/vite.svg'
-import './App.css'
-
-function App() {
- const [count, setCount] = useState(0)
+import React, { useState } from 'react';
+import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
+import { Provider } from 'react-redux';
+import store from './app/store';
+import LoginPage from './pages/LoginPage';
+import JobDescriptionPage from './pages/JobDescriptionPage';
+import InterviewQuestionsPage from './pages/InterviewQuestionsPage';
+import ResourceInvitePage from './pages/ResourceInvitePage';
+import { ThemeProvider, CssBaseline, Button } from '@mui/material';
+import { darkTheme, lightTheme } from './theme';
+const App = () => {
+ const [darkMode, setDarkMode] = useState(false);
+ const toggleDarkMode = () => setDarkMode(!darkMode);
+
return (
- <>
-
- Vite + React
-
-
-
- Edit src/App.jsx
and save to test HMR
-
-
-
- Click on the Vite and React logos to learn more
-
- >
- )
-}
+
+
+
+
+
+
+ } />
+ } />
+ } />
+ } />
+ } />
+
+
+
+
+ );
+};
-export default App
+export default App;
diff --git a/src/app/store.js b/src/app/store.js
new file mode 100644
index 0000000..3c23ff5
--- /dev/null
+++ b/src/app/store.js
@@ -0,0 +1,12 @@
+import { configureStore } from '@reduxjs/toolkit';
+import authReducer from '../features/auth/authSlice';
+// import jobReducer from '../features/job/jobSlice';
+
+const store = configureStore({
+ reducer: {
+ auth: authReducer,
+ // job: jobReducer,
+ },
+});
+
+export default store;
diff --git a/src/assets/favicon.jpg b/src/assets/favicon.jpg
new file mode 100644
index 0000000..6056ca3
Binary files /dev/null and b/src/assets/favicon.jpg differ
diff --git a/src/features/auth/authSlice.js b/src/features/auth/authSlice.js
new file mode 100644
index 0000000..33ded3a
--- /dev/null
+++ b/src/features/auth/authSlice.js
@@ -0,0 +1,28 @@
+import { createSlice } from '@reduxjs/toolkit';
+
+const initialState = {
+ user: null,
+ isAuthenticated: false,
+ error: null,
+};
+
+const authSlice = createSlice({
+ name: 'auth',
+ initialState,
+ reducers: {
+ loginSuccess: (state, action) => {
+ state.user = action.payload;
+ state.isAuthenticated = true;
+ },
+ logout: (state) => {
+ state.user = null;
+ state.isAuthenticated = false;
+ },
+ setError: (state, action) => {
+ state.error = action.payload;
+ },
+ },
+});
+
+export const { loginSuccess, logout, setError } = authSlice.actions;
+export default authSlice.reducer;
diff --git a/src/helper/helper.js b/src/helper/helper.js
new file mode 100644
index 0000000..995424d
--- /dev/null
+++ b/src/helper/helper.js
@@ -0,0 +1,9 @@
+// src/
+// ├── components/ # Reusable UI components
+// ├── features/ # Redux slices and related logic
+// ├── pages/ # Page components for routes
+// ├── app/ # Redux store setup
+// ├── services/ # API calls and services
+// ├── utils/ # Utility functions
+// ├── App.jsx # Main App component
+// └── main.jsx # Entry point
\ No newline at end of file
diff --git a/src/index.css b/src/index.css
index 6119ad9..e69de29 100644
--- a/src/index.css
+++ b/src/index.css
@@ -1,68 +0,0 @@
-:root {
- font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
- line-height: 1.5;
- font-weight: 400;
-
- color-scheme: light dark;
- color: rgba(255, 255, 255, 0.87);
- background-color: #242424;
-
- font-synthesis: none;
- text-rendering: optimizeLegibility;
- -webkit-font-smoothing: antialiased;
- -moz-osx-font-smoothing: grayscale;
-}
-
-a {
- font-weight: 500;
- color: #646cff;
- text-decoration: inherit;
-}
-a:hover {
- color: #535bf2;
-}
-
-body {
- margin: 0;
- display: flex;
- place-items: center;
- min-width: 320px;
- min-height: 100vh;
-}
-
-h1 {
- font-size: 3.2em;
- line-height: 1.1;
-}
-
-button {
- border-radius: 8px;
- border: 1px solid transparent;
- padding: 0.6em 1.2em;
- font-size: 1em;
- font-weight: 500;
- font-family: inherit;
- background-color: #1a1a1a;
- cursor: pointer;
- transition: border-color 0.25s;
-}
-button:hover {
- border-color: #646cff;
-}
-button:focus,
-button:focus-visible {
- outline: 4px auto -webkit-focus-ring-color;
-}
-
-@media (prefers-color-scheme: light) {
- :root {
- color: #213547;
- background-color: #ffffff;
- }
- a:hover {
- color: #747bff;
- }
- button {
- background-color: #f9f9f9;
- }
-}
diff --git a/src/pages/InterviewQuestionsPage.jsx b/src/pages/InterviewQuestionsPage.jsx
new file mode 100644
index 0000000..6a7c7cc
--- /dev/null
+++ b/src/pages/InterviewQuestionsPage.jsx
@@ -0,0 +1,8 @@
+function InterviewQuestionsPage(params) {
+ return(
+
+ InterviewQuestionsPage
+ )
+}
+
+export default InterviewQuestionsPage
\ No newline at end of file
diff --git a/src/pages/JobDescriptionPage.jsx b/src/pages/JobDescriptionPage.jsx
new file mode 100644
index 0000000..f28fb28
--- /dev/null
+++ b/src/pages/JobDescriptionPage.jsx
@@ -0,0 +1,8 @@
+function JobDescriptionPage(params) {
+ return(
+
+ JobDescriptionPage
+ )
+}
+
+export default JobDescriptionPage
\ No newline at end of file
diff --git a/src/pages/LoginPage.jsx b/src/pages/LoginPage.jsx
new file mode 100644
index 0000000..e565ac8
--- /dev/null
+++ b/src/pages/LoginPage.jsx
@@ -0,0 +1,53 @@
+import React, { useState } from 'react';
+import { useDispatch } from 'react-redux';
+import { loginSuccess, setError } from '../features/auth/authSlice';
+import { Box, Button, TextField, Typography, Alert } from '@mui/material';
+
+const LoginPage = () => {
+ const [email, setEmail] = useState('');
+ const [password, setPassword] = useState('');
+ const [error, setErrorState] = useState(null);
+ const dispatch = useDispatch();
+
+ const handleLogin = () => {
+ if (!email || !password) {
+ setErrorState('Email and Password are required.');
+ return;
+ }
+
+ // Simulate login API call
+ try {
+ dispatch(loginSuccess({ email })); // Replace with actual API response
+ } catch (err) {
+ dispatch(setError(err.message));
+ setErrorState('Invalid credentials.');
+ }
+ };
+
+ return (
+
+ Login
+ {error && {error}}
+ setEmail(e.target.value)}
+ />
+ setPassword(e.target.value)}
+ />
+
+
+ );
+};
+
+export default LoginPage;
\ No newline at end of file
diff --git a/src/pages/ResourceInvitePage.jsx b/src/pages/ResourceInvitePage.jsx
new file mode 100644
index 0000000..1a17144
--- /dev/null
+++ b/src/pages/ResourceInvitePage.jsx
@@ -0,0 +1,8 @@
+function ResourceInvitePage(params) {
+ return(
+
+ ResourceInvitePage
+ )
+}
+
+export default ResourceInvitePage
\ No newline at end of file
diff --git a/src/theme.js b/src/theme.js
new file mode 100644
index 0000000..6219be2
--- /dev/null
+++ b/src/theme.js
@@ -0,0 +1,49 @@
+import { createTheme } from '@mui/material/styles';
+
+const lightTheme = createTheme({
+ palette: {
+ mode: 'light',
+ primary: {
+ main: '#2196f3', // Light Blue
+ },
+ secondary: {
+ main: '#90caf9', // Lighter Blue
+ },
+ background: {
+ default: '#f5f5f5', // Light Gray
+ paper: '#ffffff', // White
+ },
+ text: {
+ primary: '#000000', // Black
+ secondary: '#555555', // Dark Gray
+ },
+ },
+ typography: {
+ fontFamily: `'Roboto', 'Arial', sans-serif`,
+ },
+});
+
+const darkTheme = createTheme({
+ palette: {
+ mode: 'dark',
+ primary: {
+ main: '#2196f3', // Light Blue
+ },
+ secondary: {
+ main: '#64b5f6', // Slightly Lighter Blue
+ },
+ background: {
+ default: '#121212', // Black
+ paper: '#1e1e1e', // Dark Gray
+ },
+ text: {
+ primary: '#ffffff', // White
+ secondary: '#bbbbbb', // Light Gray
+ },
+ },
+ typography: {
+ fontFamily: `'Roboto', 'Arial', sans-serif`,
+ },
+});
+
+export { lightTheme, darkTheme };