fix: изменение структуры кода страницы канбан доски
разделение на 3 файла: - UI - Бизнес логика - Обращение к бэку
This commit is contained in:
33
src/KBBoard/BoardAPI.js
Normal file
33
src/KBBoard/BoardAPI.js
Normal file
@@ -0,0 +1,33 @@
|
||||
import axios from 'axios';
|
||||
|
||||
export const loadBoardDataAPI = async (boardId) => {
|
||||
return axios.post('/api/boards/load', { id: boardId });
|
||||
};
|
||||
|
||||
export const createTaskAPI = async (taskData) => {
|
||||
return axios.post('/api/boards/categories/tasks/create', taskData);
|
||||
};
|
||||
|
||||
export const createCategoryAPI = async (categoryData) => {
|
||||
return axios.post('/api/boards/categories/create', categoryData);
|
||||
};
|
||||
|
||||
export const updateTaskAPI = async (updateData) => {
|
||||
return axios.put('/api/boards/categories/tasks/update', updateData);
|
||||
};
|
||||
|
||||
export const updateCategoryAPI = async (updateData) => {
|
||||
return axios.put('/api/boards/categories/update', updateData);
|
||||
};
|
||||
|
||||
export const deleteCategoryAPI = async (categoryId) => {
|
||||
return axios.delete('/api/boards/categories/delete', {
|
||||
data: { id: categoryId }
|
||||
});
|
||||
};
|
||||
|
||||
export const deleteTaskAPI = async (taskId) => {
|
||||
return axios.delete('/api/boards/categories/tasks/delete', {
|
||||
data: { id: taskId }
|
||||
});
|
||||
};
|
||||
159
src/KBBoard/BoardLogic.js
Normal file
159
src/KBBoard/BoardLogic.js
Normal file
@@ -0,0 +1,159 @@
|
||||
import { useCallback } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import {
|
||||
loadBoardDataAPI,
|
||||
createTaskAPI,
|
||||
createCategoryAPI,
|
||||
updateTaskAPI,
|
||||
updateCategoryAPI,
|
||||
deleteCategoryAPI,
|
||||
deleteTaskAPI
|
||||
} from './BoardAPI';
|
||||
|
||||
export const useBoardLogic = (id, setError, setInfo, setCategories, setLoading) => {
|
||||
const navigate = useNavigate();
|
||||
|
||||
const loadBoardData = useCallback(async () => {
|
||||
setLoading(true);
|
||||
try {
|
||||
setError('');
|
||||
const response = await loadBoardDataAPI(id);
|
||||
setInfo(response.data);
|
||||
setCategories(response.data.categories || []);
|
||||
} catch (err) {
|
||||
if (err.response?.data?.message === 'Token Error' ||
|
||||
err.response?.data?.message === 'Invalid Token') {
|
||||
setError('Вы не авторизованы');
|
||||
setTimeout(() => navigate('/login'), 1000);
|
||||
} else {
|
||||
setError('Ошибка загрузки доски');
|
||||
}
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}, [id, setError, setInfo, setCategories, setLoading, navigate]);
|
||||
|
||||
const createTask = useCallback(async (taskCategori, taskTitle, taskDescription, modalCrTask) => {
|
||||
setLoading(true);
|
||||
try {
|
||||
const newTask = {
|
||||
category_id: taskCategori,
|
||||
title: taskTitle,
|
||||
description: taskDescription
|
||||
};
|
||||
await createTaskAPI(newTask);
|
||||
await loadBoardData();
|
||||
modalCrTask(null)();
|
||||
} catch (err) {
|
||||
console.error('Ошибка создания задачи:', err);
|
||||
setError('Ошибка создания задачи');
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}, [loadBoardData, setLoading, setError]);
|
||||
|
||||
const createCategory = useCallback(async (categoryTitle, modalCrCateg) => {
|
||||
setLoading(true);
|
||||
try {
|
||||
const newCategory = {
|
||||
board_id: id,
|
||||
title: categoryTitle
|
||||
};
|
||||
await createCategoryAPI(newCategory);
|
||||
await loadBoardData();
|
||||
} catch (err) {
|
||||
console.error('Ошибка создания категории:', err);
|
||||
setError(err.response?.data?.message || 'Ошибка создания категории');
|
||||
} finally {
|
||||
modalCrCateg();
|
||||
setLoading(false);
|
||||
}
|
||||
}, [id, loadBoardData, setLoading, setError]);
|
||||
|
||||
const editTask = useCallback(async (editedTaskId, taskTitle, taskDescription, taskCategory, modalEditTask) => {
|
||||
setLoading(true);
|
||||
try {
|
||||
await updateTaskAPI({
|
||||
id: editedTaskId,
|
||||
update_method: 'title',
|
||||
value: taskTitle
|
||||
});
|
||||
await updateTaskAPI({
|
||||
id: editedTaskId,
|
||||
update_method: 'description',
|
||||
value: taskDescription
|
||||
});
|
||||
await updateTaskAPI({
|
||||
id: editedTaskId,
|
||||
update_method: 'category',
|
||||
value: Number(taskCategory)
|
||||
});
|
||||
await loadBoardData();
|
||||
modalEditTask({}, null)();
|
||||
} catch (err) {
|
||||
console.error('Ошибка редактирования задачи:', err);
|
||||
setError('Ошибка редактирования задачи');
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}, [loadBoardData, setLoading, setError]);
|
||||
|
||||
const editCategory = useCallback(async (editedCategId, categoryTitle, modalEditCateg) => {
|
||||
setLoading(true);
|
||||
try {
|
||||
const updateData = {
|
||||
id: editedCategId,
|
||||
update_method: 'title',
|
||||
value: categoryTitle
|
||||
};
|
||||
await updateCategoryAPI(updateData);
|
||||
await loadBoardData();
|
||||
} catch (err) {
|
||||
console.error('Ошибка редактирования категории:', err);
|
||||
setError(err.response?.data?.message || 'Ошибка редактирования категории');
|
||||
} finally {
|
||||
modalEditCateg({})();
|
||||
setLoading(false);
|
||||
}
|
||||
}, [loadBoardData, setLoading, setError]);
|
||||
|
||||
const deleteCategory = useCallback(async (categoryId, modalDelCateg, modalEditCateg) => {
|
||||
setLoading(true);
|
||||
try {
|
||||
await deleteCategoryAPI(categoryId);
|
||||
await loadBoardData();
|
||||
modalDelCateg();
|
||||
modalEditCateg({})();
|
||||
} catch (err) {
|
||||
console.error('Ошибка удаления категории:', err);
|
||||
setError('Ошибка удаления категории');
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}, [loadBoardData, setLoading, setError]);
|
||||
|
||||
const deleteTask = useCallback(async (taskId, modalDelTask, modalEditTask) => {
|
||||
setLoading(true);
|
||||
try {
|
||||
await deleteTaskAPI(taskId);
|
||||
await loadBoardData();
|
||||
modalDelTask();
|
||||
modalEditTask({}, null)();
|
||||
} catch (err) {
|
||||
console.error('Ошибка удаления задачи:', err);
|
||||
setError('Ошибка удаления задачи');
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}, [loadBoardData, setLoading, setError]);
|
||||
|
||||
return {
|
||||
loadBoardData,
|
||||
createTask,
|
||||
createCategory,
|
||||
editTask,
|
||||
editCategory,
|
||||
deleteCategory,
|
||||
deleteTask
|
||||
};
|
||||
};
|
||||
315
src/KBBoard/KBBoard.js
Normal file
315
src/KBBoard/KBBoard.js
Normal file
@@ -0,0 +1,315 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
import { useParams } from 'react-router-dom';
|
||||
import { useBoardLogic } from './BoardLogic';
|
||||
import Header from './../Header';
|
||||
import './../css/Board.css';
|
||||
|
||||
const KBBoard = () => {
|
||||
const { id } = useParams();
|
||||
const [error, setError] = useState('');
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [info, setInfo] = useState({});
|
||||
const [categories, setCategories] = useState([]);
|
||||
|
||||
const [crTask, setCrTask] = useState(false);
|
||||
const [crCateg, setCrCateg] = useState(false);
|
||||
const [edTask, setEdTask] = useState(false);
|
||||
const [edCateg, setEdCateg] = useState(false);
|
||||
const [delTask, setDelTask] = useState(false);
|
||||
const [delCateg, setDelCateg] = useState(false);
|
||||
|
||||
const [categoryTitle, setCategoryTitle] = useState('');
|
||||
const [taskTitle, setTaskTitle] = useState('');
|
||||
const [taskDescription, setTaskDescription] = useState('');
|
||||
const [taskCategory, setTaskCategory] = useState(null);
|
||||
const [taskCategori, setTaskCategori] = useState(null);
|
||||
const [editedTask, setEditedTask] = useState({});
|
||||
const [editedCateg, setEditedCateg] = useState({});
|
||||
const [taskPosition, setTaskPosition] = useState(null);
|
||||
const [categoryPosition, setCategoryPosition] = useState(null);
|
||||
|
||||
const {
|
||||
loadBoardData,
|
||||
createTask,
|
||||
createCategory,
|
||||
editTask,
|
||||
editCategory,
|
||||
deleteCategory,
|
||||
deleteTask
|
||||
} = useBoardLogic(id, setError, setInfo, setCategories, setLoading);
|
||||
|
||||
useEffect(() => {
|
||||
if (id) loadBoardData();
|
||||
}, [id, loadBoardData]);
|
||||
|
||||
const modalCrTask = (categori) => () => {
|
||||
setCrTask(!crTask);
|
||||
setTaskCategori(categori);
|
||||
setTaskTitle('');
|
||||
setTaskDescription('');
|
||||
}
|
||||
const modalCrCateg = () => {
|
||||
setCrCateg(!crCateg);
|
||||
setCategoryTitle('');
|
||||
}
|
||||
const modalEditTask = (task, id_categ) => () => {
|
||||
setEdTask(!edTask);
|
||||
setTaskCategori(id_categ);
|
||||
setEditedTask(task);
|
||||
setTaskTitle(task.title);
|
||||
setTaskDescription(task.description);
|
||||
setTaskPosition(task.position);
|
||||
setTaskCategory(task.category_id);
|
||||
}
|
||||
const modalEditCateg = (categ) => () => {
|
||||
setEdCateg(!edCateg);
|
||||
setEditedCateg(categ);
|
||||
setCategoryTitle(categ.title);
|
||||
setCategoryPosition(categ.position);
|
||||
}
|
||||
const modalDelTask = () => {
|
||||
setDelTask(!delTask);
|
||||
}
|
||||
const modalDelCateg = () => {
|
||||
setDelCateg(!delCateg);
|
||||
}
|
||||
|
||||
const handleCreateCategory = async (e) => {
|
||||
e.preventDefault();
|
||||
await createCategory(categoryTitle, modalCrCateg);
|
||||
};
|
||||
const handleCreateTask = async (e) => {
|
||||
e.preventDefault();
|
||||
await createTask(taskCategori, taskTitle, taskDescription, modalCrTask);
|
||||
};
|
||||
const handleEditCategory = async (e) => {
|
||||
e.preventDefault();
|
||||
await editCategory(editedCateg.id, categoryTitle, modalEditCateg);
|
||||
};
|
||||
const handleEditTask = async (e) => {
|
||||
e.preventDefault();
|
||||
await editTask(editedTask.id, taskTitle, taskDescription, taskCategory, modalEditTask);
|
||||
};
|
||||
const handleDeleteTask = async (e) => {
|
||||
e.preventDefault();
|
||||
await deleteTask(editedTask.id, modalDelTask, modalEditTask);
|
||||
};
|
||||
const handleDeleteCategory = async (e) => {
|
||||
e.preventDefault();
|
||||
await deleteCategory(editedCateg.id, modalDelCateg, modalEditCateg);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="app-container">
|
||||
<Header />
|
||||
<div className="page-container">
|
||||
{
|
||||
error && <div className="error">{error}</div>
|
||||
}
|
||||
<div className="inf-panel" >
|
||||
<div className="row">
|
||||
<h3>{info.title}</h3>
|
||||
<p>
|
||||
<strong>Участники: </strong> В разработке
|
||||
</p>
|
||||
<p>
|
||||
<strong>Владелец: </strong> {" "+info.owner?.display_name}
|
||||
<img className="nav-avatar" src={info.owner?.avatar_url} alt=''></img>
|
||||
</p>
|
||||
</div>
|
||||
<div className="row">
|
||||
<p><strong>Описание: </strong> {info.description ? info.description : 'Отсутствует'}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="set-panel" >
|
||||
<p>SetingPanel:В разработке</p>
|
||||
</div>
|
||||
<div className="board-panel" >
|
||||
{categories.map((category) => (
|
||||
<div className="categori" key={category.position}>
|
||||
<button onClick={modalEditCateg(category)}><h3>{category.title}</h3></button>
|
||||
<div className="categ-h">
|
||||
<p>Позиция: {category.position}</p>
|
||||
<p>Задач: {category.tasks.length}</p>
|
||||
</div>
|
||||
<div className='task create'>
|
||||
<button onClick={modalCrTask(category.id)}>
|
||||
Новая задача
|
||||
</button>
|
||||
</div>
|
||||
<div className='task-list'>
|
||||
{category.tasks.length > 0 ? (
|
||||
category.tasks.map((task) => (
|
||||
<button className='task' onClick={modalEditTask(task, category.id)} key={task.id}>
|
||||
<div>{task.title}</div>
|
||||
<div>{task.description}</div>
|
||||
</button>
|
||||
))
|
||||
) : (
|
||||
<p>Нет задач</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
{categories.length < 10 ? (
|
||||
<div className="categori create">
|
||||
<div className="bib">
|
||||
<button onClick={modalCrCateg}>
|
||||
<div>
|
||||
+
|
||||
</div>
|
||||
Новая категория
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{crCateg && (
|
||||
<div className="confirm-modal">
|
||||
<div className="modal-content">
|
||||
<div><h3>Новая категория</h3></div>
|
||||
<form onSubmit={handleCreateCategory}>
|
||||
<div>
|
||||
<input
|
||||
type="text"
|
||||
value={categoryTitle}
|
||||
onChange={(e) => setCategoryTitle(e.target.value)}
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<button type="submit" disabled={loading}>
|
||||
{loading ? 'Создание...' : 'Создать'}
|
||||
</button>
|
||||
</form>
|
||||
<button onClick={modalCrCateg}>Отменить</button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{crTask && (
|
||||
<div className="confirm-modal">
|
||||
<div className="modal-content">
|
||||
<div><h3>Новая задача</h3></div>
|
||||
<form onSubmit={handleCreateTask}>
|
||||
<div>
|
||||
<input
|
||||
type="text"
|
||||
value={taskTitle}
|
||||
onChange={(e) => setTaskTitle(e.target.value)}
|
||||
required
|
||||
/>
|
||||
<input
|
||||
type="text"
|
||||
value={taskDescription}
|
||||
onChange={(e) => setTaskDescription(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
<button type="submit" disabled={loading}>
|
||||
{loading ? 'Создание...' : 'Создать'}
|
||||
</button>
|
||||
</form>
|
||||
<button onClick={modalCrTask(null)}>Отменить</button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{edCateg && (
|
||||
<div className="confirm-modal">
|
||||
<div className="modal-content">
|
||||
<div><h3>Изменение категории</h3></div>
|
||||
<form onSubmit={handleEditCategory}>
|
||||
<div>
|
||||
<input
|
||||
type="text"
|
||||
value={categoryTitle}
|
||||
onChange={(e) => setCategoryTitle(e.target.value)}
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<button type="submit" disabled={loading}>
|
||||
{loading ? 'Изменение...' : 'Изменить'}
|
||||
</button>
|
||||
</form>
|
||||
<button onClick={modalEditCateg({})}>Отменить</button>
|
||||
<button className="Important-button" onClick={modalDelCateg}>Удалить</button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{edTask && (
|
||||
<div className="confirm-modal">
|
||||
<div className="modal-content">
|
||||
<div><h3>Изменение задачи</h3></div>
|
||||
<form onSubmit={handleEditTask}>
|
||||
<div>
|
||||
<input
|
||||
type="text"
|
||||
value={taskTitle}
|
||||
onChange={(e) => setTaskTitle(e.target.value)}
|
||||
required
|
||||
/>
|
||||
<input
|
||||
type="text"
|
||||
value={taskDescription}
|
||||
onChange={(e) => setTaskDescription(e.target.value)}
|
||||
required
|
||||
/>
|
||||
<div>
|
||||
<label >Категория:</label>
|
||||
<select value={taskCategory} onChange={(e) => setTaskCategory(e.target.value)}>
|
||||
{categories.map((category) => (
|
||||
<option key={category.position} value={category.id}>
|
||||
{category.title}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<button type="submit" disabled={loading}>
|
||||
{loading ? 'Изменение...' : 'Изменить'}
|
||||
</button>
|
||||
</form>
|
||||
<button onClick={modalEditTask({},null)}>Отменить</button>
|
||||
<button className="Important-button" onClick={modalDelTask}>Удалить</button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{delTask && (
|
||||
<div className="confirm-modal">
|
||||
<div className="modal-content">
|
||||
<div><h3>Удаление задачи</h3></div>
|
||||
<form onSubmit={handleDeleteTask}>
|
||||
<label >Вы точно хотите удалить задачу {editedTask.title}</label>
|
||||
<button onClick={modalDelTask}>Отменить</button>
|
||||
<button className="Important-button" type="submit" disabled={loading}>
|
||||
{loading ? 'Удаление...' : 'Удалить'}
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{delCateg && (
|
||||
<div className="confirm-modal">
|
||||
<div className="modal-content">
|
||||
<div><h3>Удаление категории</h3></div>
|
||||
<form onSubmit={handleDeleteCategory}>
|
||||
<label >Вы точно хотите удалить эту категорию</label>
|
||||
<button onClick={modalDelCateg}>Отменить</button>
|
||||
<button className="Important-button" type="submit" disabled={loading}>
|
||||
{loading ? 'Удаление...' : 'Удалить'}
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default KBBoard;
|
||||
Reference in New Issue
Block a user