diff --git a/client/src/App.jsx b/client/src/App.jsx
index f67355a..ed66208 100644
--- a/client/src/App.jsx
+++ b/client/src/App.jsx
@@ -1,35 +1,52 @@
-import { useState } from 'react'
-import reactLogo from './assets/react.svg'
-import viteLogo from '/vite.svg'
-import './App.css'
+// src/App.jsx
+import { BrowserRouter as Router, Routes, Route, Navigate } from 'react-router-dom';
+import { AuthProvider, useAuth } from './contexts/AuthContext';
+import Login from './components/Login';
+import Dashboard from './components/Dashboard';
+import Editor from './components/Editor';
-function App() {
- const [count, setCount] = useState(0)
-
- return (
- <>
-
- Vite + React
-
-
-
- Edit src/App.jsx and save to test HMR
-
-
-
- Click on the Vite and React logos to learn more
-
- >
- )
+function PrivateRoute({ children }) {
+ const { isAuthenticated } = useAuth();
+ return isAuthenticated ? children : ;
}
-export default App
+function App() {
+ return (
+
+
+
+
+ } />
+
+
+
+ }
+ />
+
+
+
+ }
+ />
+
+
+
+ }
+ />
+ } />
+
+
+
+
+ );
+}
+
+export default App;
\ No newline at end of file
diff --git a/client/src/components/Login.jsx b/client/src/components/Login.jsx
new file mode 100644
index 0000000..69c0cb4
--- /dev/null
+++ b/client/src/components/Login.jsx
@@ -0,0 +1,52 @@
+// src/components/Login.jsx
+import { useState } from 'react';
+import { useNavigate } from 'react-router-dom';
+import { useAuth } from '../contexts/AuthContext';
+
+export default function Login() {
+ const [username, setUsername] = useState('');
+ const [password, setPassword] = useState('');
+ const [error, setError] = useState('');
+ const { login } = useAuth();
+ const navigate = useNavigate();
+
+ const handleSubmit = async (e) => {
+ e.preventDefault();
+ setError('');
+
+ const success = await login(username, password);
+ if (success) {
+ navigate('/dashboard');
+ } else {
+ setError('Invalid credentials');
+ }
+ };
+
+ return (
+
+ );
+}
\ No newline at end of file
diff --git a/client/src/contexts/AuthContext.jsx b/client/src/contexts/AuthContext.jsx
new file mode 100644
index 0000000..45617e5
--- /dev/null
+++ b/client/src/contexts/AuthContext.jsx
@@ -0,0 +1,46 @@
+// src/contexts/AuthContext.jsx
+import { createContext, useContext, useState, useEffect } from 'react';
+import axios from 'axios';
+
+const AuthContext = createContext();
+
+export function AuthProvider({ children }) {
+ const [isAuthenticated, setIsAuthenticated] = useState(false);
+ const [isLoading, setIsLoading] = useState(true);
+
+ useEffect(() => {
+ const token = localStorage.getItem('token');
+ setIsAuthenticated(!!token);
+ setIsLoading(false);
+ }, []);
+
+ const login = async (username, password) => {
+ try {
+ const response = await axios.post(`${import.meta.env.VITE_API_URL}/api/auth/login`, {
+ username,
+ password
+ });
+ localStorage.setItem('token', response.data.token);
+ setIsAuthenticated(true);
+ return true;
+ } catch (error) {
+ console.error('Login error:', error);
+ return false;
+ }
+ };
+
+ const logout = () => {
+ localStorage.removeItem('token');
+ setIsAuthenticated(false);
+ };
+
+ return (
+
+ {!isLoading && children}
+
+ );
+}
+
+export function useAuth() {
+ return useContext(AuthContext);
+}
\ No newline at end of file
diff --git a/client/src/main.jsx b/client/src/main.jsx
index b9a1a6d..dca82ab 100644
--- a/client/src/main.jsx
+++ b/client/src/main.jsx
@@ -1,10 +1,11 @@
-import { StrictMode } from 'react'
-import { createRoot } from 'react-dom/client'
-import './index.css'
+// src/main.jsx
+import React from 'react'
+import ReactDOM from 'react-dom/client'
import App from './App.jsx'
+import './styles/main.scss'
-createRoot(document.getElementById('root')).render(
-
+ReactDOM.createRoot(document.getElementById('root')).render(
+
- ,
-)
+ ,
+)
\ No newline at end of file
diff --git a/client/src/styles/main.scss b/client/src/styles/main.scss
new file mode 100644
index 0000000..8919b99
--- /dev/null
+++ b/client/src/styles/main.scss
@@ -0,0 +1,92 @@
+// src/styles/main.scss
+$primary-color: #2c3e50;
+$secondary-color: #3498db;
+$background-color: #f5f6fa;
+$text-color: #2c3e50;
+$border-color: #dcdde1;
+$error-color: #e74c3c;
+
+body {
+ margin: 0;
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
+ background-color: $background-color;
+ color: $text-color;
+ line-height: 1.5;
+}
+
+.container {
+ max-width: 1200px;
+ margin: 0 auto;
+ padding: 20px;
+}
+
+.login-container {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ min-height: 100vh;
+ padding: 20px;
+}
+
+.login-form {
+ background: white;
+ padding: 30px;
+ border-radius: 8px;
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+ width: 100%;
+ max-width: 400px;
+
+ h2 {
+ margin: 0 0 20px;
+ color: $primary-color;
+ text-align: center;
+ }
+
+ .error {
+ background: lighten($error-color, 35%);
+ color: $error-color;
+ padding: 10px;
+ border-radius: 4px;
+ margin-bottom: 20px;
+ text-align: center;
+ }
+}
+
+.form-group {
+ margin-bottom: 20px;
+
+ label {
+ display: block;
+ margin-bottom: 5px;
+ color: $primary-color;
+ }
+
+ input {
+ width: 100%;
+ padding: 8px;
+ border: 1px solid $border-color;
+ border-radius: 4px;
+ font-size: 16px;
+
+ &:focus {
+ outline: none;
+ border-color: $secondary-color;
+ }
+ }
+}
+
+.button {
+ width: 100%;
+ padding: 10px;
+ background: $primary-color;
+ color: white;
+ border: none;
+ border-radius: 4px;
+ font-size: 16px;
+ cursor: pointer;
+ transition: background-color 0.2s;
+
+ &:hover {
+ background: darken($primary-color, 10%);
+ }
+}
\ No newline at end of file