glist #3

Merged
enemy01 merged 3 commits from glist into main 2024-09-27 04:03:58 +07:00
7 changed files with 301 additions and 9 deletions
Showing only changes of commit 519bea1a98 - Show all commits

58
package-lock.json generated
View File

@ -22,6 +22,9 @@
"socket.io": "^4.8.0", "socket.io": "^4.8.0",
"socket.io-client": "^4.8.0", "socket.io-client": "^4.8.0",
"web-vitals": "^2.1.4" "web-vitals": "^2.1.4"
},
"devDependencies": {
"sass": "^1.79.3"
} }
}, },
"node_modules/@adobe/css-tools": { "node_modules/@adobe/css-tools": {
@ -10356,6 +10359,13 @@
"url": "https://opencollective.com/immer" "url": "https://opencollective.com/immer"
} }
}, },
"node_modules/immutable": {
"version": "4.3.7",
"resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.7.tgz",
"integrity": "sha512-1hqclzwYwjRDFLjcFxOM5AYkkG0rpFPpr1RLPMEuGczoS7YA8gLhy8SWXYRAA/XwfEHpfo3cw5JGioS32fnMRw==",
"devOptional": true,
"license": "MIT"
},
"node_modules/import-fresh": { "node_modules/import-fresh": {
"version": "3.3.0", "version": "3.3.0",
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
@ -17053,6 +17063,24 @@
"integrity": "sha512-ZRwKbh/eQ6w9vmTjkuG0Ioi3HBwPFce0O+v//ve+aOq1oeCy7jMV2qzzAlpsNuqpqCBjjriM1lbtZbF/Q8jVyA==", "integrity": "sha512-ZRwKbh/eQ6w9vmTjkuG0Ioi3HBwPFce0O+v//ve+aOq1oeCy7jMV2qzzAlpsNuqpqCBjjriM1lbtZbF/Q8jVyA==",
"license": "CC0-1.0" "license": "CC0-1.0"
}, },
"node_modules/sass": {
"version": "1.79.3",
"resolved": "https://registry.npmjs.org/sass/-/sass-1.79.3.tgz",
"integrity": "sha512-m7dZxh0W9EZ3cw50Me5GOuYm/tVAJAn91SUnohLRo9cXBixGUOdvmryN+dXpwR831bhoY3Zv7rEFt85PUwTmzA==",
"devOptional": true,
"license": "MIT",
"dependencies": {
"chokidar": "^4.0.0",
"immutable": "^4.0.0",
"source-map-js": ">=0.6.2 <2.0.0"
},
"bin": {
"sass": "sass.js"
},
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/sass-loader": { "node_modules/sass-loader": {
"version": "12.6.0", "version": "12.6.0",
"resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-12.6.0.tgz", "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-12.6.0.tgz",
@ -17091,6 +17119,36 @@
} }
} }
}, },
"node_modules/sass/node_modules/chokidar": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.1.tgz",
"integrity": "sha512-n8enUVCED/KVRQlab1hr3MVpcVMvxtZjmEa956u+4YijlmQED223XMSYj2tLuKvr4jcCTzNNMpQDUer72MMmzA==",
"devOptional": true,
"license": "MIT",
"dependencies": {
"readdirp": "^4.0.1"
},
"engines": {
"node": ">= 14.16.0"
},
"funding": {
"url": "https://paulmillr.com/funding/"
}
},
"node_modules/sass/node_modules/readdirp": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.0.1.tgz",
"integrity": "sha512-GkMg9uOTpIWWKbSsgwb5fA4EavTR+SG/PMPoAY8hkhHfEEY0/vqljY+XHqtDf2cr2IJtoNRDbrrEpZUiZCkYRw==",
"devOptional": true,
"license": "MIT",
"engines": {
"node": ">= 14.16.0"
},
"funding": {
"type": "individual",
"url": "https://paulmillr.com/funding/"
}
},
"node_modules/sax": { "node_modules/sax": {
"version": "1.2.4", "version": "1.2.4",
"resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",

View File

@ -41,5 +41,8 @@
"last 1 firefox version", "last 1 firefox version",
"last 1 safari version" "last 1 safari version"
] ]
},
"devDependencies": {
"sass": "^1.79.3"
} }
} }

View File

@ -3,6 +3,7 @@ import DeviceGroups from "./pages/DeviceGroups";
import Devices from "./pages/Devices"; import Devices from "./pages/Devices";
import Sidebar from "./Sidebar"; import Sidebar from "./Sidebar";
import Dashboard from './pages/Dashboard'; import Dashboard from './pages/Dashboard';
import UserAccount from './pages/UserAccount'; // Импортируем страницу аккаунта
const App = () => { const App = () => {
const [activeTab, setActiveTab] = useState('map'); // По умолчанию активная вкладка "Карта" const [activeTab, setActiveTab] = useState('map'); // По умолчанию активная вкладка "Карта"
@ -13,7 +14,7 @@ const App = () => {
<div style={{ padding: '20px', flex: 1 }}> <div style={{ padding: '20px', flex: 1 }}>
{activeTab === 'map' && <Dashboard />} {/* Подключаем компонент Dashboard */} {activeTab === 'map' && <Dashboard />} {/* Подключаем компонент Dashboard */}
{activeTab === 'connection' && <div>Подключение</div>} {activeTab === 'connection' && <div>Подключение</div>}
{activeTab === 'account' && <div>Аккаунт пользователя</div>} {activeTab === 'account' && <UserAccount />} {/* Подключаем компонент аккаунта */}
{activeTab === 'groups' && <DeviceGroups />} {/* Группы устройств */} {activeTab === 'groups' && <DeviceGroups />} {/* Группы устройств */}
{activeTab === 'devices' && <Devices />} {/* Устройства */} {activeTab === 'devices' && <Devices />} {/* Устройства */}
</div> </div>

View File

@ -1,7 +1,13 @@
import React from 'react'; import React, { useState } from 'react';
import './Sidebar.css'; import './Sidebar.css';
const Sidebar = ({ onSelectTab, activeTab }) => { const Sidebar = ({ onSelectTab, activeTab }) => {
const [isDropdownOpen, setIsDropdownOpen] = useState(false);
const toggleDropdown = () => {
setIsDropdownOpen(!isDropdownOpen); // Переключаем состояние выпадающего списка
};
return ( return (
<div className="sidebar"> <div className="sidebar">
<h2>Меню</h2> <h2>Меню</h2>
@ -12,15 +18,26 @@ const Sidebar = ({ onSelectTab, activeTab }) => {
<li className={activeTab === 'connection' ? 'active' : ''} onClick={() => onSelectTab('connection')}> <li className={activeTab === 'connection' ? 'active' : ''} onClick={() => onSelectTab('connection')}>
Подключение Подключение
</li> </li>
<li className={activeTab === 'account' ? 'active' : ''} onClick={() => onSelectTab('account')}> <li
className={activeTab === 'account' ? 'active' : ''}
onClick={() => {
onSelectTab('account');
toggleDropdown();
}}
>
Аккаунт пользователя Аккаунт пользователя
</li> </li>
{/* Выпадающий список для групп и устройств */}
{isDropdownOpen && (
<>
<li className={activeTab === 'groups' ? 'active' : ''} onClick={() => onSelectTab('groups')}> <li className={activeTab === 'groups' ? 'active' : ''} onClick={() => onSelectTab('groups')}>
Группы устройств Группы устройств
</li> </li>
<li className={activeTab === 'devices' ? 'active' : ''} onClick={() => onSelectTab('devices')}> <li className={activeTab === 'devices' ? 'active' : ''} onClick={() => onSelectTab('devices')}>
Устройства Устройства
</li> </li>
</>
)}
</ul> </ul>
</div> </div>
); );

87
src/UserAccount.scss Normal file
View File

@ -0,0 +1,87 @@
.user-account {
padding: 20px;
background-color: #f4f4f4;
border-radius: 10px;
max-width: 400px;
margin: 0 auto;
h1 {
text-align: center;
margin-bottom: 20px;
}
.user-info, .edit-form {
display: flex;
flex-direction: column;
gap: 10px;
label {
display: flex;
justify-content: space-between;
font-size: 16px;
}
input {
padding: 8px;
font-size: 14px;
border: 1px solid #ccc;
border-radius: 5px;
}
p {
font-size: 18px;
margin: 10px 0;
}
.buttons {
display: flex;
justify-content: space-between;
button {
padding: 10px 20px;
font-size: 14px;
cursor: pointer;
border: none;
border-radius: 5px;
background-color: #3498db;
color: white;
transition: background-color 0.3s ease;
&:hover {
background-color: #2980b9;
}
&:last-child {
background-color: #e74c3c;
&:hover {
background-color: #c0392b;
}
}
}
}
}
.edit-button {
margin-top: 20px;
padding: 10px 25px;
font-size: 16px;
font-weight: bold;
cursor: pointer;
background-color: #2ecc71; /* Зелёный цвет */
color: white;
border: none;
border-radius: 5px;
transition: background-color 0.3s ease, transform 0.2s ease;
&:hover {
background-color: #27ae60;
transform: scale(1.05); /* Небольшой зум при наведении */
}
&:active {
background-color: #1e8449;
transform: scale(0.98); /* Легкий уменьшенный эффект при нажатии */
}
}
}

42
src/pages/Login.js Normal file
View File

@ -0,0 +1,42 @@
import React, { useState } from 'react';
import './Login.css';
const Login = ({ onLogin }) => {
const [username, setUsername] = useState('');
const [password, setPassword] = useState('');
const [error, setError] = useState('');
const handleSubmit = (e) => {
e.preventDefault();
// Простейшая проверка логина/пароля
if (username === 'admin' && password === 'admin') {
onLogin(); // Вызываем функцию при успешной авторизации
} else {
setError('Неверный логин или пароль');
}
};
return (
<div className="login-container">
<form onSubmit={handleSubmit}>
<h2>Вход</h2>
{error && <p className="error">{error}</p>}
<input
type="text"
placeholder="Логин"
value={username}
onChange={(e) => setUsername(e.target.value)}
/>
<input
type="password"
placeholder="Пароль"
value={password}
onChange={(e) => setPassword(e.target.value)}
/>
<button type="submit">Войти</button>
</form>
</div>
);
};
export default Login;

84
src/pages/UserAccount.js Normal file
View File

@ -0,0 +1,84 @@
import React, { useState } from 'react';
import '../UserAccount.scss';
const UserAccount = () => {
const [userData, setUserData] = useState({
username: 'Мамут Рахал',
email: 'yatupoidayn@mail.ru',
phone: '+666',
});
const [isEditing, setIsEditing] = useState(false);
const [formData, setFormData] = useState(userData);
const handleChange = (e) => {
const { name, value } = e.target;
setFormData((prevData) => ({
...prevData,
[name]: value,
}));
};
const handleSave = () => {
setUserData(formData);
setIsEditing(false);
};
const handleCancel = () => {
setFormData(userData);
setIsEditing(false);
};
return (
<div className="user-account">
<h1>Данные</h1>
{isEditing ? (
<div className="edit-form">
<label>
Имя:
<input
type="text"
name="username"
value={formData.username}
onChange={handleChange}
/>
</label>
<label>
Email:
<input
type="email"
name="email"
value={formData.email}
onChange={handleChange}
/>
</label>
<label>
Телефон:
<input
type="tel"
name="phone"
value={formData.phone}
onChange={handleChange}
/>
</label>
<div className="buttons">
<button onClick={handleSave}>Сохранить</button>
<button onClick={handleCancel}>Отмена</button>
</div>
</div>
) : (
<div className="user-info">
<p><strong>Имя:</strong> {userData.username}</p>
<p><strong>Email:</strong> {userData.email}</p>
<p><strong>Телефон:</strong> {userData.phone}</p>
<button className="edit-button" onClick={() => setIsEditing(true)}>
Редактировать
</button>
</div>
)}
</div>
);
};
export default UserAccount;