diff --git a/data/nginx/proxy_host/1.conf b/data/nginx/proxy_host/1.conf
index a904151..443b547 100644
--- a/data/nginx/proxy_host/1.conf
+++ b/data/nginx/proxy_host/1.conf
@@ -101,4 +101,3 @@ http2 off;
# Custom
include /data/nginx/custom/server_proxy[.]conf;
}
-
diff --git a/frontend/src/components/Header.js b/frontend/src/components/Header.js
new file mode 100644
index 0000000..1d66f4d
--- /dev/null
+++ b/frontend/src/components/Header.js
@@ -0,0 +1,15 @@
+import React from 'react';
+import styles from './Header.module.css';
+
+const Header = ({ user, onLogout }) => {
+ return (
+
+ );
+};
+
+export default Header;
\ No newline at end of file
diff --git a/frontend/src/components/Header.module.css b/frontend/src/components/Header.module.css
new file mode 100644
index 0000000..95defd8
--- /dev/null
+++ b/frontend/src/components/Header.module.css
@@ -0,0 +1,38 @@
+.header {
+ width: 100%;
+ height: 64px;
+ background: #fff;
+ border-bottom: 1.5px solid #e5e7eb;
+ display: flex;
+ align-items: center;
+ justify-content: flex-end;
+ padding: 0 32px;
+ box-sizing: border-box;
+ position: sticky;
+ top: 0;
+ z-index: 10;
+}
+.right {
+ display: flex;
+ align-items: center;
+ gap: 18px;
+}
+.user {
+ font-size: 16px;
+ color: #6366f1;
+ font-weight: 600;
+}
+.logout {
+ background: linear-gradient(90deg, #6366f1 0%, #06b6d4 100%);
+ color: #fff;
+ border: none;
+ border-radius: 8px;
+ padding: 8px 18px;
+ font-size: 15px;
+ font-weight: 600;
+ cursor: pointer;
+ transition: background 0.2s;
+}
+.logout:hover {
+ background: linear-gradient(90deg, #3730a3 0%, #06b6d4 100%);
+}
\ No newline at end of file
diff --git a/frontend/src/components/SideMenu.js b/frontend/src/components/SideMenu.js
new file mode 100644
index 0000000..82a5247
--- /dev/null
+++ b/frontend/src/components/SideMenu.js
@@ -0,0 +1,23 @@
+import React from 'react';
+import styles from './SideMenu.module.css';
+
+const SideMenu = ({ active, onSelect }) => {
+ return (
+
+ );
+};
+
+export default SideMenu;
\ No newline at end of file
diff --git a/frontend/src/components/SideMenu.module.css b/frontend/src/components/SideMenu.module.css
new file mode 100644
index 0000000..165b80f
--- /dev/null
+++ b/frontend/src/components/SideMenu.module.css
@@ -0,0 +1,53 @@
+.menu {
+ width: 250px;
+ min-height: 100vh;
+ background: #f3f4f6;
+ border-right: 1.5px solid #e5e7eb;
+ display: flex;
+ flex-direction: column;
+ padding: 0 0 24px 0;
+}
+.project {
+ font-size: 22px;
+ font-weight: 700;
+ color: #3730a3;
+ padding: 32px 24px 16px 24px;
+ letter-spacing: 1px;
+ border-bottom: 1px solid #e5e7eb;
+ margin-bottom: 12px;
+}
+.nav {
+ flex: 1;
+ padding: 0 0 0 0;
+}
+.section {
+ font-size: 15px;
+ color: #6366f1;
+ font-weight: 600;
+ padding: 12px 24px 6px 24px;
+ text-transform: uppercase;
+ letter-spacing: 0.5px;
+}
+ul {
+ list-style: none;
+ margin: 0;
+ padding: 0 0 0 0;
+}
+li {
+ padding: 12px 24px;
+ font-size: 16px;
+ color: #374151;
+ cursor: pointer;
+ border-left: 3px solid transparent;
+ transition: background 0.15s, border 0.15s, color 0.15s;
+}
+li:hover {
+ background: #e0e7ff;
+ color: #3730a3;
+}
+.active {
+ background: #e0e7ff;
+ color: #3730a3;
+ border-left: 3px solid #6366f1;
+ font-weight: 600;
+}
\ No newline at end of file
diff --git a/frontend/src/context/UserContext.js b/frontend/src/context/UserContext.js
new file mode 100644
index 0000000..410e6c7
--- /dev/null
+++ b/frontend/src/context/UserContext.js
@@ -0,0 +1,42 @@
+import React, { createContext, useContext, useState, useEffect } from 'react';
+
+const UserContext = createContext();
+
+export function UserProvider({ children }) {
+ const [user, setUser] = useState(null);
+ const [token, setToken] = useState(null);
+
+ useEffect(() => {
+ // Инициализация из localStorage
+ const storedUser = localStorage.getItem('user');
+ const storedToken = localStorage.getItem('token');
+ if (storedUser && storedToken) {
+ setUser(JSON.parse(storedUser));
+ setToken(storedToken);
+ }
+ }, []);
+
+ const login = (user, token) => {
+ setUser(user);
+ setToken(token);
+ localStorage.setItem('user', JSON.stringify(user));
+ localStorage.setItem('token', token);
+ };
+
+ const logout = () => {
+ setUser(null);
+ setToken(null);
+ localStorage.removeItem('user');
+ localStorage.removeItem('token');
+ };
+
+ return (
+
+ {children}
+
+ );
+}
+
+export function useUser() {
+ return useContext(UserContext);
+}
\ No newline at end of file
diff --git a/frontend/src/index.js b/frontend/src/index.js
index 0ebbc88..2b7667e 100644
--- a/frontend/src/index.js
+++ b/frontend/src/index.js
@@ -3,11 +3,14 @@ import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import * as serviceWorkerRegistration from './serviceWorkerRegistration';
+import { UserProvider } from './context/UserContext';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
-
+
+
+
);
diff --git a/frontend/src/pages/Dashboard.js b/frontend/src/pages/Dashboard.js
index 89935ca..4d86f2b 100644
--- a/frontend/src/pages/Dashboard.js
+++ b/frontend/src/pages/Dashboard.js
@@ -1,12 +1,44 @@
-import React from 'react';
+import React, { useState } from 'react';
+import SideMenu from '../components/SideMenu';
+import Header from '../components/Header';
+import { useUser } from '../context/UserContext';
const Dashboard = () => {
+ const [active, setActive] = useState('smtp');
+ const { user, logout } = useUser();
+
+ const handleLogout = () => {
+ logout();
+ window.location.href = '/login';
+ };
+
return (
-
-
Добро пожаловать в Dashboard!
-
Вы успешно вошли в систему.
+
+
+
+
+
+ {/* Здесь будет контент выбранного раздела */}
+
Раздел: {getSectionTitle(active)}
+
+ Здесь будет содержимое для "{getSectionTitle(active)}".
+
+
+
);
};
+function getSectionTitle(key) {
+ switch (key) {
+ case 'smtp': return 'SMTP-сервера';
+ case 'template': return 'Шаблон письма';
+ case 'unsubscribed': return 'Отписались';
+ case 'groups': return 'Подписчики и группы';
+ case 'history': return 'История отправок';
+ case 'campaign': return 'Кампания';
+ default: return '';
+ }
+}
+
export default Dashboard;
\ No newline at end of file
diff --git a/frontend/src/pages/Login.js b/frontend/src/pages/Login.js
index eb452dc..f36a52e 100644
--- a/frontend/src/pages/Login.js
+++ b/frontend/src/pages/Login.js
@@ -1,6 +1,7 @@
import React, { useState } from 'react';
import { useNavigate } from 'react-router-dom';
import styles from './Login.module.css';
+import { useUser } from '../context/UserContext';
const Login = () => {
const [email, setEmail] = useState('');
@@ -8,6 +9,7 @@ const Login = () => {
const [error, setError] = useState('');
const [loading, setLoading] = useState(false);
const navigate = useNavigate();
+ const { login } = useUser();
const handleSubmit = async (e) => {
e.preventDefault();
@@ -23,8 +25,7 @@ const Login = () => {
if (!res.ok) {
setError(data.error || 'Ошибка входа');
} else {
- localStorage.setItem('token', data.token);
- // Можно сохранить и user, если нужно: localStorage.setItem('user', JSON.stringify(data.user));
+ login(data.user, data.token);
navigate('/dashboard');
}
} catch (err) {