const { tasks, title, onTaskDragStop, onTaskDragStart, onTaskDragOver, functionLoader, componentOwnerId, handleColumns, projectId, contract, columns, setColumns, addActionStatus, removeColumn, columnIndex, } = props; const ColumnContainer = styled.div` display: flex; flex-direction: column; align-items: center; height: 100%; width: 17.5rem; margin-left: 2em; margin-right: 2em; background-color: transparent; cursor: pointer; :hover { background-color: #11121a; } padding: 1rem; `; const ColumnDetailsIcon = styled.div` color: transparent; `; const ColumnLabel = styled.div` display: flex; justify-content: start; align-items: center; color: #fff; font-family: Helvetica Neue; font-size: 16px; font-style: normal; font-weight: 700; line-height: 150%; padding-top: 4px; padding-bottom: 4px; gap: 0.5rem; cursor: pointer; width: 15rem; :hover { ${ColumnDetailsIcon} { color: #ffffff; } } `; const TasksContainer = styled.div` display: flex; flex-direction: column; gap: 16px; padding-bottom: 16px; `; const AddTaskContainer = styled.div` display: flex; flex-direction: column; align-items: center; `; const AddIcon = styled.div` color: #777583; `; const AddTaskButton = styled.div` display: flex; flex-direction: row; justify-content: center; align-items: center; background-color: #1e1f28; color: #ffffff; width: 240px; padding: 16px; gap: 4px; border-radius: 4px; :hover { ${AddIcon} { color: #ffffff; } } `; const AddTaskText = styled.div` display: flex; justify-content: center; align-items: center; margin-left: 0.25rem; `; const Title = styled.div` padding: 0; margin: 0; max-width: 100%; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; `; const createTaskButton = ( <AddTaskButton> <AddIcon> <i className="bi bi-plus-circle-fill"></i> </AddIcon> <AddTaskText>Add new Card</AddTaskText> </AddTaskButton> ); const columnDetailsButton = ( <ColumnDetailsIcon> <i className="bi bi-pen-fill"></i> </ColumnDetailsIcon> ); const [createStatus, setCreateStatus] = useState([]); const [editTaskId, setEditTaskId] = useState(undefined); const [editedTask, setEditedTask] = useState(undefined); const [editTaskTitle, setEditTaskTitle] = useState(''); const [editTaskDescription, setEditTaskDescription] = useState(''); const [editTaskTitleMissing, setEditTaskTitleMissing] = useState(false); const [editTaskDescriptionMissing, setEditTaskDescriptionMissing] = useState(false); const [editTaskColumn, setEditTaskColumn] = useState(''); const [editTaskDialogTaskId, setEditTaskDialogTaskId] = useState(undefined); const [showDeleteTaskDialog, setShowDeleteTaskDialog] = useState(false); const [deleteTaskId, setDeleteTaskId] = useState(undefined); const [showEditTaskDialog, setShowEditTaskDialog] = useState(false); const [editTaskTitleStatus, setEditTaskTitleStatus] = useState([]); const [editTaskDescriptionStatus, setEditTaskDescriptionStatus] = useState([]); const addCreateTaskStatus = useCallback((newStatus) => { let isNew = true; let newCreateTaskStatuses = createStatus.map((status) => { if (status.title === newStatus.title) { isNew = false; return newStatus; } else { return status; } }); if (isNew) { newCreateTaskStatuses = [...newCreateTaskStatuses, newStatus]; } setCreateStatus(newCreateTaskStatuses); }, []); const onChangeShowDeleteTaskDialog = (open, id) => { setShowDeleteTaskDialog(open); setDeleteTaskId(id); }; const onEditTaskTitle = ({ target }) => { setEditTaskTitleMissing(false); setEditTaskTitle(target.value); }; const onChangeShowEditTaskDialog = (open, id) => { setEditTaskTitleMissing(false); setEditTaskDescriptionMissing(false); setShowEditTaskDialog(open); setEditTaskDialogTaskId(id); }; const onEditTaskDescription = ({ target }) => { setEditTaskDescriptionMissing(false); setEditTaskDescription(target.value); }; const setEditTask = (task, id, title, description, column) => { setEditedTask(task); setEditTaskId(id); setEditTaskTitle(title); setEditTaskDescription(description); setEditTaskColumn(column); }; const deleteTask = useCallback(() => { const oldStatuses = columns; const taskId = deleteTaskId; const actionStatusPrefix = 'Delete task'; const newActionStatus = { id: actionStatusPrefix + taskId, status: `Deleting task: ${taskId}`, seen: false, }; try { addActionStatus(newActionStatus); const newStatuses = columns; for (let status of newStatuses) { status.tasks = status.tasks.filter((task) => task.id !== taskId); } setColumns(newStatuses); Near.fakCalimeroCall(contract, 'delete_task_by_id', { project_id: projectId, task_id: taskId, }).then(() => { newActionStatus.status = `Deleted task: ${taskId}`; addActionStatus(newActionStatus); }); } catch (e) { newActionStatus.status = `Error deleting task: ${taskId}`; addActionStatus(newActionStatus); setColumns(oldStatuses); } onChangeShowDeleteTaskDialog(false, undefined); onChangeShowEditTaskDialog(false, undefined); }, []); const updateTaskTitle = useCallback(() => { if (!editTaskTitle || editTaskTitle.trim() === '') { setEditTaskTitleMissing(true); return; } const oldTask = tasks.find((task) => task.id === editTaskId); if (oldTask.title === editTaskTitle) { return; } const newStatus = { id: editTaskId, status: 'Saving...' }; const newStatuses = [...editTaskTitleStatus, newStatus]; try { setEditTaskTitleStatus(newStatuses); const editedTask = { project_id: projectId, id: editTaskId, title: editTaskTitle, description: editTaskDescription, status: editTaskColumn, }; let newColumnsArray = []; const storageColumns = Storage.privateGet( 'tempColumns' + contract + projectId, ); if (storageColumns && JSON.parse(storageColumns).length > 0) { const columnsArray = JSON.parse(storageColumns); let filteredColumnsArray = []; if (columnsArray.find((task) => task.id === editTaskId)) { filteredColumnsArray = columnsArray.filter( (task) => task.id !== editTaskId, ); } if (columnsArray.find((task) => task.title === oldTask.title)) { filteredColumnsArray = columnsArray.filter( (task) => task.title !== oldTask.title, ); } newColumnsArray = filteredColumnsArray; newColumnsArray.push(editedTask); } else { newColumnsArray.push(editedTask); } const jsonStringArray = JSON.stringify(newColumnsArray); Storage.privateSet('tempColumns' + contract + projectId, jsonStringArray); handleColumns(projectId); Near.fakCalimeroCall(contract, 'change_task_name', { project_id: projectId, task_id: editTaskId, new_title: editTaskTitle, }).then(() => { let foundStatus = newStatuses.find((t) => t.id === editTaskId); foundStatus.status = 'Saved'; const filteredStatuses = newStatuses.filter((t) => t.id !== editTaskId); setEditTaskTitleStatus([...filteredStatuses, foundStatus]); setTimeout(() => { const filteredStatuses = newStatuses.filter((s) => s.id !== editTaskId); setEditTaskTitleStatus(filteredStatuses); }, 3000); }); } catch (e) { let foundStatus = newStatuses.find((t) => t.id === editTaskId); foundStatus.status = 'Error saving'; const filteredStatuses = newStatuses.filter((t) => t.id !== editTaskId); setEditTaskTitleStatus([...filteredStatuses, foundStatus]); setTimeout(() => { const filteredStatuses = newStatuses.filter((s) => s.id !== editTaskId); setEditTaskTitleStatus(filteredStatuses); }, 3000); } }, []); const updateTaskDescription = useCallback(() => { const oldTask = tasks.find((task) => task.id === editTaskId); if (oldTask.description === editTaskDescription) { return; } const newStatus = { id: editTaskId, status: 'Saving...' }; const newStatuses = [...editTaskDescriptionStatus, newStatus]; try { setEditTaskDescriptionStatus(newStatuses); const editedTask = { project_id: projectId, id: editTaskId, title: editTaskTitle, description: editTaskDescription, status: editTaskColumn, }; let newColumnsArray = []; const storageColumns = Storage.privateGet( 'tempColumns' + contract + projectId, ); if (storageColumns && JSON.parse(storageColumns).length > 0) { const columnsArray = JSON.parse(storageColumns); let filteredColumnsArray = []; if (columnsArray.find((task) => task.id === editTaskId)) { filteredColumnsArray = columnsArray.filter( (task) => task.id !== editTaskId, ); } if ( columnsArray.find((task) => task.description === oldTask.description) ) { filteredColumnsArray = columnsArray.filter( (task) => task.description !== oldTask.description, ); } newColumnsArray = filteredColumnsArray; newColumnsArray.push(editedTask); } else { newColumnsArray.push(editedTask); } const jsonStringArray = JSON.stringify(newColumnsArray); Storage.privateSet('tempColumns' + contract + projectId, jsonStringArray); handleColumns(projectId); Near.fakCalimeroCall(contract, 'edit_task_description', { project_id: projectId, task_id: editTaskId, new_description: editTaskDescription, }).then(() => { let foundStatus = newStatuses.find((t) => t.id === editTaskId); foundStatus.status = 'Saved'; const filteredStatuses = newStatuses.filter((t) => t.id !== editTaskId); setEditTaskDescriptionStatus([...filteredStatuses, foundStatus]); setTimeout(() => { const filteredStatuses = editTaskDescriptionStatus.filter( (s) => s.id !== editTaskId, ); setEditTaskDescriptionStatus(filteredStatuses); }, 3000); }); } catch (e) { let foundStatus = newStatuses.find((t) => t.id === editTaskId); foundStatus.status = 'Error saving'; const filteredStatuses = newStatuses.filter((t) => t.id !== editTaskId); setEditTaskDescriptionStatus([...filteredStatuses, foundStatus]); setTimeout(() => { const filteredStatuses = editTaskDescriptionStatus.filter( (s) => s.id !== editTaskId, ); setEditTaskDescriptionStatus(filteredStatuses); }, 3000); } }, []); const cleanCreateTaskStatus = (title) => { const filteredStatuses = createStatus.filter((s) => s.title !== title); setCreateStatus(filteredStatuses); }; return ( <> {showDeleteTaskDialog && ( <Widget src={`${componentOwnerId}/widget/Calimero.TaskChain.ConfirmationPopup`} props={{ onClick: () => deleteTask(), onClose: () => onChangeShowDeleteTaskDialog(false, undefined, title), functionLoader, title: 'Are you sure you want to delete the task?', }} /> )} {showEditTaskDialog && ( <Widget src={`${componentOwnerId}/widget/Calimero.TaskChain.BoardContainer.Task.TaskDetailsDialog`} props={{ onChangeShowEditTaskDialog, editTaskTitle, editTaskDescription, onEditTaskTitle, onEditTaskDescription, updateTaskTitle, updateTaskDescription, editTaskTitleStatus, editTaskId, editedTask, // task, editTaskDialogTaskId, editTaskDescriptionStatus, onChangeShowDeleteTaskDialog, editTaskTitleMissing, editTaskDescriptionMissing, componentOwnerId, contract, projectId, }} /> )} <ColumnContainer droppable onDragOver={(_e) => { onTaskDragOver(); }} onDrop={() => onTaskDragStop(title)} > <ColumnLabel> <Title>{title}</Title> <Widget src={`${componentOwnerId}/widget/Calimero.TaskChain.Popups.ColumnDetailsPopup`} props={{ componentOwnerId, columnIndex, columnName: title, removeColumn, contract, projectId, addActionStatus, containsTasks: tasks.length > 0, columnDetailsButton, columns, setColumns, }} /> </ColumnLabel> <TasksContainer> {tasks.map((task, i) => { return ( <div key={task.id}> <Widget src={`${componentOwnerId}/widget/Calimero.TaskChain.BoardContainer.Task.TaskCard`} props={{ task: task, status: title, index: i, onTaskDragStart: onTaskDragStart, onTaskDragStop: onTaskDragStop, onClick: () => { setEditTask( task, task.id, task.title, task.description, title, ); onChangeShowEditTaskDialog(true, task.id); }, createStatus, }} /> </div> ); })} </TasksContainer> <AddTaskContainer> <Widget src={`${componentOwnerId}/widget/Calimero.TaskChain.Popups.CreateTaskPopup`} props={{ createTaskButton, componentOwnerId, addCreateTaskStatus, cleanCreateTaskStatus, contract, handleColumns, projectId, columnTitle: title, }} /> </AddTaskContainer> </ColumnContainer> </> );