@@ -13,6 +13,8 @@ const KBBoard = () => {
const [ categories , setCategories ] = useState ( [ ] ) ;
const [ isOwner , setIsOwner ] = useState ( null ) ;
const [ items , setItems ] = useState ( [ ] ) ;
const [ draggedItem , setDraggedItem ] = useState ( null ) ;
const [ draggedType , setDraggedType ] = useState ( null ) ;
const [ memList , setMemList ] = useState ( false ) ;
const [ crTask , setCrTask ] = useState ( false ) ;
@@ -36,12 +38,11 @@ const KBBoard = () => {
const [ taskDescription , setTaskDescription ] = useState ( '' ) ;
const [ taskCategory , setTaskCategory ] = useState ( null ) ;
const [ taskCategori , setTaskCategori ] = useState ( null ) ;
const [ taskDeadline , setTaskDeadline ] = useState ( '' ) ;
const [ taskDeadline , setTaskDeadline ] = useState ( null ) ;
const [ assignedMembers , setAssignedMembers ] = useState ( null ) ;
const [ editedTask , setEditedTask ] = useState ( { } ) ;
const [ editedCateg , setEditedCateg ] = useState ( { } ) ;
const [ taskPosition , setTaskPosition ] = useState ( null ) ;
const [ categoryPosition , setCategoryPosition ] = useState ( null ) ;
const [ assignedMember , setAssignedMember ] = useState ( 0 ) ;
const [ addedUsername , setAddedUsername ] = useState ( '' ) ;
const [ deletedMember , setDeletedMember ] = useState ( '' ) ;
@@ -78,6 +79,24 @@ const KBBoard = () => {
) ;
} ;
const [ socket , setSocket ] = useState ( null ) ;
useEffect ( ( ) => {
const protocol = window . location . protocol === 'https:' ? 'wss:' : 'ws:' ;
const ws = new WebSocket ( ` ${ protocol } //https://back.fool-stack.ru/api/boards/ws/ ` + id ) ;
ws . onopen = ( ) => {
console . log ( 'WebSocket соединение установлено' ) ;
setSocket ( ws ) ;
} ;
ws . onmessage = ( event ) => {
const message = JSON . parse ( event . data ) ;
loadBoardData ( ) ;
} ;
ws . onclose = ( ) => console . log ( 'WebSocket соединение закрыто' ) ;
ws . onerror = ( error ) => console . error ( 'Ошибка WebSocket:' , error ) ;
return ( ) => ws . close ( ) ;
} , [ id , loadBoardData ] ) ;
useEffect ( ( ) => {
if ( id ) loadBoardData ( ) ;
} , [ id , loadBoardData ] ) ;
@@ -94,7 +113,7 @@ const KBBoard = () => {
setTaskCategori ( categori ) ;
setTaskTitle ( '' ) ;
setTaskDescription ( '' ) ;
setTaskDeadline ( '' )
setTaskDeadline ( null )
}
const modalCrCateg = ( ) => {
setCrCateg ( ! crCateg ) ;
@@ -119,7 +138,6 @@ const KBBoard = () => {
setEdCateg ( ! edCateg ) ;
setEditedCateg ( categ ) ;
setCategoryTitle ( categ . title ) ;
setCategoryPosition ( categ . position ) ;
}
const modalDelTask = ( ) => {
setDelTask ( ! delTask ) ;
@@ -194,6 +212,137 @@ const KBBoard = () => {
await deleteMember ( id , deletedMember , modalDeleteMember ) ;
} ;
const handleCategoryDragStart = ( e , category ) => {
e . stopPropagation ( ) ;
setDraggedType ( 'c' ) ;
setDraggedItem ( category ) ;
e . dataTransfer . setData ( 'text/plain' , JSON . stringify ( {
id : category . id ,
type : 'c' ,
position : category . position
} ) ) ;
e . currentTarget . style . opacity = '0.5' ;
} ;
const handleTaskDragStart = ( e , task , categoryId ) => {
e . stopPropagation ( ) ;
setDraggedType ( 't' ) ;
setDraggedItem ( { ... task , categoryId } ) ;
e . dataTransfer . setData ( 'text/plain' , JSON . stringify ( {
id : task . id ,
type : 't' ,
position : task . position ,
categoryId : categoryId
} ) ) ;
e . currentTarget . style . opacity = '0.5' ;
e . currentTarget . style . transform = 'scale(0.95)' ;
} ;
const handleDragEnd = ( e ) => {
setDraggedType ( null ) ;
setDraggedItem ( null ) ;
e . currentTarget . style . opacity = '1' ;
e . currentTarget . style . transform = 'scale(1)' ;
} ;
const handleDragOver = ( e ) => {
e . preventDefault ( ) ;
const data = e . dataTransfer . getData ( 'text/plain' ) ;
if ( ! data ) return ;
try {
const draggedData = JSON . parse ( data ) ;
if ( draggedData . type === 't' ) {
e . currentTarget . style . boxShadow = '0 0 10px rgba(0, 0, 255, 0.3)' ;
e . currentTarget . style . border = '2px dashed #007bff' ;
} else if ( draggedData . type === 'c' ) {
e . currentTarget . style . backgroundColor = '#f0f0f0' ;
}
} catch ( err ) {
console . error ( 'Ошибка парсинга данных drag:' , err ) ;
}
} ;
const handleDragLeave = ( e ) => {
e . currentTarget . style . backgroundColor = '' ;
e . currentTarget . style . boxShadow = '' ;
e . currentTarget . style . border = '' ;
} ;
const handleCategoryReorder = async ( e , targetPosition ) => {
e . preventDefault ( ) ;
e . currentTarget . style . boxShadow = '' ;
e . currentTarget . style . border = '' ;
e . currentTarget . style . backgroundColor = '' ;
e . currentTarget . style . transform = '' ;
const data = e . dataTransfer . getData ( 'text/plain' ) ;
if ( ! data ) return ;
try {
const draggedData = JSON . parse ( data ) ;
if ( draggedData . type !== 'c' ) return ;
if ( draggedType === 'c' && draggedItem . position !== targetPosition ) {
setCategories ( ( prevItems ) => {
const draggedIndex = prevItems . findIndex ( item => item . position === draggedItem . position ) ;
const targetIndex = prevItems . findIndex ( item => item . position === targetPosition ) ;
const newItems = [ ... prevItems ] ;
newItems . splice ( draggedIndex , 1 ) ;
newItems . splice ( targetIndex , 0 , draggedItem ) ;
const updatedItems = newItems . map ( ( item , index ) => ( {
... item ,
position : index
} ) ) ;
return updatedItems ;
} ) ;
await editCategoryPosition ( draggedItem . id , targetPosition ) ;
}
} catch ( err ) {
console . error ( 'Ошибка при переупорядочивании категорий:' , err ) ;
setError ( 'Н е удалось переупорядочить категории' ) ;
}
} ;
const handleTaskReorder = async ( e , targetPosition , targetCategoryPos ) => {
e . stopPropagation ( ) ;
e . preventDefault ( ) ;
e . currentTarget . style . boxShadow = '' ;
e . currentTarget . style . border = '' ;
e . currentTarget . style . backgroundColor = '' ;
e . currentTarget . style . transform = '' ;
const data = e . dataTransfer . getData ( 'text/plain' ) ;
if ( ! data ) return ;
if ( ! draggedItem || draggedType !== 't' ) return ;
try {
const draggedData = JSON . parse ( data ) ;
// Обрабатываем только задачи
if ( draggedData . type !== 't' || ! draggedItem ) return ;
// Находим целевую категорию по позиции
const targetCat = categories . find ( cat => cat . position === targetCategoryPos ) ;
if ( ! targetCat ) return ;
// Проверяем, что задача не перемещается в ту же позицию той же категории
if ( ( draggedItem . position === targetPosition ||
( draggedItem . position === targetCat . length - 1 && targetPosition === targetCat . length ) ) &&
draggedItem . category _id === targetCat . id ) return ;
await editTask ( draggedItem . id , draggedItem . title ,
draggedItem . description , targetPosition ,
draggedItem . deadline , targetCat . id , null ) ;
} catch ( err ) {
console . error ( 'Ошибка при переупорядочивании задач:' , err ) ;
setError ( 'Н е удалось переупорядочить задачи' ) ;
}
} ;
return (
< div className = "app-container" >
@@ -260,12 +409,16 @@ const KBBoard = () => {
< / d i v >
< div className = "board-panel" >
{ categories . map ( ( category ) => (
< div className = "categori" key = { category . position } >
< div className = "categori" key = { category . position }
draggable = "true"
onDragStart = { ( e ) => handleCategoryDragStart ( e , category ) }
onDragLeave = { handleDragLeave }
onDragEnd = { handleDragEnd }
onDragOver = { handleDragOver }
onDrop = { ( e ) => handleCategoryReorder ( e , category . position ) }
>
< button onClick = { modalEditCateg ( category ) } > < h3 > { category . title } < / h 3 > < / b u t t o n >
< div className = "categ-h" >
< p > Позиция : { category . position } < / p >
< p > Задач : { category . tasks . length } < / p >
< / d i v >
< div className = 'task create' >
< button onClick = { modalCrTask ( category . id ) } >
Новая задача
@@ -274,9 +427,17 @@ const KBBoard = () => {
< div className = 'task-list' >
{ category . tasks . length > 0 ? (
category . tasks . map ( ( task ) => (
< button className = 'task' onClick = { modalEditTask ( task , category . id ) } key = { task . id } >
< button className = 'task' onClick = { modalEditTask ( task , category . id ) } key = { task . position }
draggable = "true"
onDragStart = { ( e ) => handleTaskDragStart ( e , task , category . position ) }
onDragLeave = { handleDragLeave }
onDragEnd = { handleDragEnd }
onDragOver = { handleDragOver }
onDrop = { ( e ) => handleTaskReorder ( e , task . position , category . position ) }
>
< div > { task . title } < / d i v >
< div > { task . description } < / d i v >
< div > { task . description } < / d i v >
{ task . deadline && (
< div > Дедлайн : { new Date ( task . deadline ) . toLocaleString ( 'ru-RU' , {
day : '2-digit' ,
@@ -299,6 +460,12 @@ const KBBoard = () => {
) : (
< p > Нет задач < / p >
) }
< div className = 'task move'
onDrop = { ( e ) => handleTaskReorder ( e , category . tasks . length , category . position ) }
onDragLeave = { handleDragLeave }
onDragEnd = { handleDragEnd }
onDragOver = { handleDragOver }
> < / d i v >
< / d i v >
< / d i v >
) ) }