P8-Panels/app/panels/clnt_task_board/clnt_task_board.js

235 lines
12 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
Парус 8 - Панели мониторинга - УДП - Доски задач
Панель мониторинга: Корневая панель доски задач
*/
//---------------------
//Подключение библиотек
//---------------------
import React, { useState } from "react"; //Классы React
import { DragDropContext, Droppable } from "react-beautiful-dnd"; //Работа с drag&drop
import { Stack, Card, CardHeader, CardContent, Box, Button, IconButton, Icon, Typography } from "@mui/material"; //Интерфейсные компоненты
import { TaskCard } from "./components/task_card"; //Компонент карточки события
import { TaskFormDialog } from "./components/task_form"; //Компонент формы события
import { Filter } from "./filter.js"; //Компонент фильтров
import { FilterDialog } from "./components/filter_dialog"; //Компонент диалогового окна фильтра отбора
import { TaskCardSettings } from "./components/task_card_settings.js"; //Компонент настроек карточки события
import { useTasks, useWindowResize, COLORS } from "./hooks.js"; //Вспомогательные хуки
//---------
//Константы
//---------
//Стили
const STYLES = {
CONTAINER: { width: "100%", padding: 1 },
STATUS_BLOCK: statusColor => {
return {
maxWidth: "300px",
minWidth: "300px",
minHeight: "100px",
backgroundColor: statusColor,
padding: "8px"
};
},
BLOCK_OPACITY: isAvailable => {
return isAvailable ? { opacity: 1 } : { opacity: 0.5 };
},
MARK_INFO: {
textAlign: "left",
textOverflow: "ellipsis",
overflow: "hidden",
whiteSpace: "pre",
maxWidth: "calc(250px)",
width: "-webkit-fill-available"
}
};
//-----------
//Тело модуля
//-----------
//Корневая панель доски задач
const ClntTaskBoard = () => {
//Собственное состояние
const [
tasks,
eventRoutes,
docLinks,
taskFormOpen,
setTaskFormOpen,
cardSettings,
handleFilterOk,
handleFilterCancel,
handleFilterClick,
handleCardSettingsClick,
handleCardSettingsOk,
handleCardSettingsCancel,
handleReload,
onDragEnd,
handleOrderChanged
] = useTasks();
//Состояние доступных маршрутов события
const [availableRoutes, setAvailableRoutes] = useState({ sorce: "", routes: [] });
//Состояние перетаскиваемого события
const [dragItem, setDragItem] = useState({ type: "", status: "" });
const clearDragItem = () => {
setDragItem({ type: "", status: "" });
};
//Очистка состояния
const clearARState = () => {
setAvailableRoutes({ sorce: "", routes: [] });
};
//Проверка доступности карточки события
const isCardAvailable = code => {
return availableRoutes.sorce === code || availableRoutes.routes.find(r => r.dest === code) || !availableRoutes.sorce ? true : false;
};
//Состояние ширины и высоты рабочей области окна
// eslint-disable-next-line no-unused-vars
const [width, height] = useWindowResize();
// useEffect(() => {
// console.log(`w: ${width}, h: ${height}`);
// }, [width, height]);
// useEffect(() => {
// console.log(availableRoutes);
// }, [availableRoutes]);
return (
<Box sx={STYLES.CONTAINER}>
{tasks.filters.isOpen ? (
<FilterDialog initial={tasks.filters.values} docs={docLinks} onOk={handleFilterOk} onCancel={handleFilterCancel} />
) : null}
<Filter
filter={tasks.filters.values}
selectedDoc={tasks.filters.values.docLink ? docLinks.find(d => d.id === tasks.filters.values.docLink) : null}
handleFilterClick={handleFilterClick}
handleReload={handleReload}
orders={tasks.orders}
handleOrderChanged={handleOrderChanged}
/>
{tasks.filters.values.type ? (
<DragDropContext
onDragStart={e => {
let srcCode = tasks.statuses.find(s => s.id == e.source.droppableId).code;
setAvailableRoutes({ sorce: srcCode, routes: [...eventRoutes.filter(r => r.src === srcCode)] });
}}
onDragEnd={e => {
onDragEnd(e);
clearARState();
}}
>
<div>
<Droppable droppableId="Statuses" type="droppableTask">
{provided => (
<div ref={provided.innerRef}>
<Stack direction="row" spacing={2}>
{tasks.statuses.map((status, index) => (
<div key={index}>
<Droppable isDropDisabled={!isCardAvailable(status.code)} droppableId={status.id.toString()}>
{provided => (
<div ref={provided.innerRef}>
<Card
className="category-card"
sx={{
...STYLES.STATUS_BLOCK(status.color),
...STYLES.BLOCK_OPACITY(isCardAvailable(status.code))
}}
>
<CardHeader
action={
<IconButton
aria-label="settings"
onClick={() => handleCardSettingsClick(status)}
>
<Icon>more_vert</Icon>
</IconButton>
}
title={
<Typography sx={STYLES.MARK_INFO} title={status.caption} variant="h5">
{status.caption}
</Typography>
}
subheader={
<Button
onClick={() => {
setDragItem({ type: tasks.filters.values.type, status: status.code });
setTaskFormOpen(true);
}}
>
+ Добавить
</Button>
}
sx={{ padding: 0 }}
/>
<CardContent
sx={{
padding: 0,
overflowY: "auto",
maxHeight: height * 0.749
}}
>
<Stack spacing={1}>
{tasks.rows
.filter(item => item.category === status.id)
.map((item, index) => (
<TaskCard
task={item}
index={index}
handleReload={handleReload}
key={item.id}
/>
))}
{provided.placeholder}
</Stack>
</CardContent>
</Card>
</div>
)}
</Droppable>
</div>
))}
</Stack>
{provided.placeholder}
</div>
)}
</Droppable>
</div>
</DragDropContext>
) : null}
{taskFormOpen ? (
<TaskFormDialog
taskType={dragItem.type}
taskStatus={dragItem.status}
onClose={() => {
setTaskFormOpen(false);
clearDragItem();
}}
/>
) : null}
{cardSettings.isOpen ? (
<TaskCardSettings
initial={cardSettings.settings}
availableClrs={COLORS}
onOk={handleCardSettingsOk}
onCancel={handleCardSettingsCancel}
/>
) : null}
</Box>
);
};
//----------------
//Интерфейс модуля
//----------------
export { ClntTaskBoard };