Изменение сортировки и оптимизация кода

This commit is contained in:
Vladiysss
2026-02-04 01:14:55 +03:00
parent 488769e5cb
commit 23b536c244
2 changed files with 60 additions and 152 deletions

View File

@@ -1,41 +0,0 @@
{
"name": "client",
"version": "0.1.0",
"private": true,
"dependencies": {
"@testing-library/dom": "^10.4.1",
"@testing-library/jest-dom": "^6.9.1",
"@testing-library/react": "^16.3.1",
"@testing-library/user-event": "^13.5.0",
"axios": "^1.13.2",
"react": "^19.2.3",
"react-dom": "^19.2.3",
"react-router-dom": "^7.11.0",
"react-scripts": "5.0.1",
"web-vitals": "^2.1.4"
},
"scripts": {
"start": "PORT=24452 react-scripts start",
"build": "react-scripts build --port=24452",
"test": "react-scripts test --port=24452",
"eject": "react-scripts eject --port=24452"
},
"eslintConfig": {
"extends": [
"react-app",
"react-app/jest"
]
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
}
}

View File

@@ -1,151 +1,101 @@
import React, { useState, useEffect, useRef } from 'react'; import { useState, useEffect, useRef, useCallback } from 'react';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
import axios from 'axios'; import axios from 'axios';
import Header from './Header'; import Header from './Header';
function ListItem({ item }) {
const navigate = useNavigate();
if (!item) return null;
const openBoard = () => { navigate('/kanban-board/' + item.id); };
return (
<li>
<button onClick={openBoard}>
<div className="sort-row">
<h3>{item.title}</h3>
<p><strong>Владелец:</strong> {item.owner_display_name}</p>
</div>
<div className="sort-row">
<p><strong>Описание:</strong> {item.description}</p>
<p><strong>Обновлено:</strong> {new Date(item.updated_at).toLocaleString()}</p>
</div>
</button>
</li>
);
};
const KBBoardsList = () => { const KBBoardsList = () => {
const navigate = useNavigate();
const debounceRef = useRef(null);
const [error, setError] = useState(''); const [error, setError] = useState('');
const [loading, setLoading] = useState(false);
const [showCreateModal, setShowCreateModal] = useState(false);
const [timer, setTimer] = useState(400)
const [sort_method, setSortMethod] = useState('title'); const [sort_method, setSortMethod] = useState('title');
const [reverse, setReverse] = useState(false); const [reverse, setReverse] = useState(false);
const [search_text, setSearchText] = useState(''); const [search_text, setSearchText] = useState('');
const [page, setPage] = useState(1);
const [list, setList] = useState(20);
const [title, setTitle] = useState(''); const [title, setTitle] = useState('');
const [description, setDescription] = useState(''); const [description, setDescription] = useState('');
const [items, setItems] = useState([]); const [items, setItems] = useState([]);
const [showCreateModal, setShowCreateModal] = useState(false);
const [loading, setLoading] = useState(false);
const [searchQuery, setSearchQuery] = useState('');
const [filteredItems, setFilteredItems] = useState([]);
const [page, setPage] = useState(1);
const [list, setList] = useState(20);
const debounceRef = useRef(null);
useEffect(() => {
const loadBoardList = async () => { function ListItem({ item }) {
try { if (!item) return null;
const openBoard = () => { navigate('/kanban-board/' + item.id); };
return (
<li>
<button onClick={openBoard}>
<div className="sort-row">
<h3>{item.title}</h3>
<p><strong>Владелец:</strong> {item.owner_display_name}</p>
</div>
<div className="sort-row">
<p><strong>Описание:</strong> {item.description}</p>
<p><strong>Обновлено:</strong> {new Date(item.updated_at).toLocaleString()}</p>
</div>
</button>
</li>
);
};
const loadBoardList = useCallback(async () => {
clearTimeout(debounceRef.current);
try {
debounceRef.current = setTimeout(async () => {
var newList = { sort_method, reverse, search_text, page, list }; var newList = { sort_method, reverse, search_text, page, list };
const response = await axios.post('/api/boards/list', newList); const response = await axios.post('/api/boards/list', newList);
if (Array.isArray(response.data)) { if (Array.isArray(response.data)) {
setItems(response.data); setItems(response.data);
} else { } else {
// Если данных нет или они не массив — ставим пустой массив
setItems([]); setItems([]);
if (response.data?.detail === 'Доски отсутствуют.') { if (response.data?.detail === 'Доски отсутствуют.') {
console.log('Доски отсутствуют'); console.log('Доски отсутствуют');
} }
} }
} catch (err) { setTimer(400)
if (err.response.data.message === 'Token Error' || err.response.data.message === 'Invalid Token') { }, timer);
setError('Вы не авторизованы');
setTimeout(() => {
window.location.href = '/login';
}, 1500);
} else {
setError('Ошибка загрузки досок');
console.log(err);
setItems([]); // Гарантируем, что items — массив
}
}
};
loadBoardList()
}, []);
useEffect(() => {
clearTimeout(debounceRef.current);
debounceRef.current = setTimeout(() => {
setFilteredItems(
items.filter(item =>
item.title.toLowerCase().includes(searchQuery.toLowerCase())
)
);
}, 300); // 300 мс задержка
}, [searchQuery, items]);
const sortList = async (method = sort_method, isReverse = reverse) => {
try {
const newList = { sort_method: method, reverse: isReverse, search_text };
const response = await axios.post('/api/boards/list', newList);
if (Array.isArray(response.data)) {
setItems(response.data);
} else {
setItems([]);
if (response.data?.detail === 'Доски отсутствуют.') {
console.log('Доски отсутствуют');
}
}
} catch (err) { } catch (err) {
if (err.response?.data?.message === 'Token Error' || err.response?.data?.message === 'Invalid Token') { if (err.response?.data?.message === 'Token Error' || err.response?.data?.message === 'Invalid Token') {
setError('Вы не авторизованы'); setError('Вы не авторизованы');
setTimeout(() => { setTimeout(() => {
window.location.href = '/login'; navigate('/login');
}, 1500); }, 1000);
} else { } else {
setError('Ошибка загрузки досок'); setError('Ошибка загрузки досок');
console.log(err); console.log(err);
setItems([]); setItems([]);
} }
} }
}; }, [sort_method, reverse, search_text, page, list, timer, setItems, setError, navigate]);
const setFilterTitle = async () => { useEffect(() => {
const newMethod = 'title'; loadBoardList();
const newReverse = sort_method === 'title' ? !reverse : false; }, [loadBoardList]);
const setFilter = (method) => () => {
const newMethod = method;
const newReverse = sort_method === method ? !reverse : false;
setSortMethod(newMethod); setSortMethod(newMethod);
setReverse(newReverse); setReverse(newReverse);
setTimer(100);
await sortList(newMethod, newReverse);
};
const setFilterOwner = async () => {
const newMethod = 'owner';
const newReverse = sort_method === 'owner' ? !reverse : false;
setSortMethod(newMethod);
setReverse(newReverse);
await sortList(newMethod, newReverse);
};
const setFilterUptime = async () => {
const newMethod = 'update_time';
const newReverse = sort_method === 'update_time' ? !reverse : false;
setSortMethod(newMethod);
setReverse(newReverse);
await sortList(newMethod, newReverse);
}; };
const createBoard = async () => { const createBoard = async () => {
try { try {
setLoading(true)
const newBoard = { title, description }; const newBoard = { title, description };
await axios.post('/api/boards/create', newBoard); await axios.post('/api/boards/create', newBoard);
setShowCreateModal(false) setShowCreateModal(false);
await loadBoardList();
} catch (err) { } catch (err) {
setError('Ошибка'); setError('Ошибка');
} finally {
setLoading(false);
} }
}; };
@@ -159,25 +109,24 @@ const KBBoardsList = () => {
{ {
error && <div className="error">{error}</div> error && <div className="error">{error}</div>
} }
<div className="kan-ban-list-sort"> <div className="kan-ban-list-sort">
<h3>Сортировка по:</h3> <h3>Сортировка по:</h3>
<div className="nav-sort"> <div className="nav-sort">
<button onClick={setFilterTitle}> <button onClick={setFilter('title')}>
Названию Названию
</button> </button>
<button onClick={setFilterOwner}> <button onClick={setFilter('owner')}>
Создателю Создателю
</button> </button>
<button onClick={setFilterUptime}> <button onClick={setFilter('update_time')}>
Дате обновления Дате обновления
</button> </button>
</div> </div>
<input <input
type="text" type="text"
placeholder="Поиск по названию..." placeholder="Поиск по названию..."
value={searchQuery} value={search_text}
onChange={(e) => setSearchQuery(e.target.value)} onChange={(e) => setSearchText(e.target.value)}
/> />
</div> </div>
<div className="kan-ban-list"> <div className="kan-ban-list">
@@ -185,9 +134,9 @@ const KBBoardsList = () => {
<h3>Доступные канбан доски:</h3> <h3>Доступные канбан доски:</h3>
<button onClick={openCreateModal}>Создать канбан-доску</button> <button onClick={openCreateModal}>Создать канбан-доску</button>
</div> </div>
{filteredItems.length > 0 ? ( {items.length > 0 ? (
<ul> <ul>
{filteredItems.map((item) => ( {items.map((item) => (
<ListItem key={item.id} item={item} /> <ListItem key={item.id} item={item} />
))} ))}
</ul> </ul>