forked from CITKParus/P8-Panels
165 lines
7.4 KiB
JavaScript
165 lines
7.4 KiB
JavaScript
/*
|
||
Парус 8 - Панели мониторинга
|
||
Компонент: Диалог
|
||
*/
|
||
|
||
//---------------------
|
||
//Подключение библиотек
|
||
//---------------------
|
||
|
||
import React, { useEffect, useState } from "react"; //Классы React
|
||
import PropTypes from "prop-types"; //Контроль свойств компонента
|
||
import { Dialog, DialogTitle, DialogContent, DialogActions, Button, Box, Typography, IconButton, Icon } from "@mui/material"; //Интерфейсные компоненты
|
||
import { BUTTONS } from "../../app.text"; //Общие текстовые ресурсы
|
||
import { P8P_INPUT, P8PInput } from "./p8p_input"; //Поле ввода
|
||
import { P8P_DIALOG_TITLE_VARIANT } from "../theme/variants/p8p_dialog_title_variants"; //Варианты заголовков диалога
|
||
import { P8P_DIALOG_CONTENT_VARIANT } from "../theme/variants/p8p_dialog_content_variants"; //Варианты содержимого диалога
|
||
import { P8P_DIALOG_ACTIONS_VARIANT } from "../theme/variants/p8p_dialog_actions_variants"; //Варианты действий диалога
|
||
import { P8P_BUTTON_VARIANT } from "../theme/variants/p8p_button_variants"; //Варианты кнопок
|
||
import { P8P_TYPOGRAPHY_VARIANT } from "../theme/p8p_typography"; //Варианты шрифтов
|
||
import { P8P_ICON_BUTTON_VARIANT } from "../theme/variants/p8p_icon_button_variants"; //Варианты кнопок-иконок
|
||
import { P8P_BOX_DIALOG_TITLE } from "../theme/styles/box"; //Стили контейнеров
|
||
|
||
//---------
|
||
//Константы
|
||
//---------
|
||
|
||
//Типовая ширина диалога
|
||
const P8P_DIALOG_WIDTH = {
|
||
XS: "xs",
|
||
SM: "sm",
|
||
MD: "md",
|
||
LG: "lg",
|
||
XL: "xl"
|
||
};
|
||
|
||
//-----------------------
|
||
//Вспомогательные функции
|
||
//-----------------------
|
||
|
||
//Формирование объекта вида {ключ: значение} из текущего состояния элементов ввода формы
|
||
const buildFormValues = inputsState =>
|
||
inputsState.reduce((res, input) => ({ ...res, [input.name]: input.value == undefined ? null : input.value }), {});
|
||
|
||
//-----------
|
||
//Тело модуля
|
||
//-----------
|
||
|
||
//Диалог
|
||
const P8PDialog = ({
|
||
title,
|
||
width,
|
||
fullWidth,
|
||
inputs,
|
||
children,
|
||
okDisabled = false,
|
||
paddingDisabled = false,
|
||
actionsDisabled = false,
|
||
scrollContent = true,
|
||
onOk,
|
||
onCancel,
|
||
onClose,
|
||
onInputChange
|
||
}) => {
|
||
//Состояние элементов ввода диалога
|
||
const [inputsState, setInputsState] = useState([]);
|
||
|
||
//При изменении элемента ввода
|
||
const handleInputChange = (name, value) => {
|
||
//Если есть функция пересчета формы - вызовем её
|
||
const doNotChangeInputsState = onInputChange ? onInputChange(name, value, inputsState) : false;
|
||
//И ориентируясь на то, пересчитала ли она элементы ввода обновим собственное состояние.
|
||
//Если функция пересчета вернула "true", значит она пересчитала что-то, тогда новые настройки элементов придут через свойство inputs и будут обработаны в useEffect ниже.
|
||
//Следовательно, и нам здесь не надо состояние выставлять, т.к. всё будет перезаписано useEffectом.
|
||
if (!doNotChangeInputsState)
|
||
setInputsState(pv => pv.reduce((accum, cur) => [...accum, { ...cur, value: cur.name === name ? value : cur.value }], []));
|
||
};
|
||
|
||
//При нажатии на "ОК" диалога
|
||
const handleOk = () => onOk && onOk(buildFormValues(inputsState));
|
||
|
||
//При нажатии на "Отмена" диалога
|
||
const handleCancel = () => onCancel && onCancel();
|
||
|
||
//При нажатии на "Закрыть" диалога
|
||
const handleClose = () => (onClose ? onClose() : onCancel ? onCancel() : null);
|
||
|
||
//При изменении полей для ввода
|
||
useEffect(() => {
|
||
if (inputs && Array.isArray(inputs) && inputs.length > 0) setInputsState(inputs.map(input => ({ ...input })));
|
||
}, [inputs]);
|
||
|
||
//Расчет объектного представления текущих значений формы
|
||
const formValues = buildFormValues(inputsState);
|
||
|
||
//Формирование представления
|
||
return (
|
||
<Dialog onClose={handleClose} open {...{ ...(width ? { maxWidth: width } : {}), ...(fullWidth === true ? { fullWidth: true } : {}) }}>
|
||
<DialogTitle variant={P8P_DIALOG_TITLE_VARIANT.PRIMARY_DIVIDED}>
|
||
<Box sx={P8P_BOX_DIALOG_TITLE}>
|
||
<Box /> {/* Пустая ячейка для баланса */}
|
||
<Typography variant={P8P_TYPOGRAPHY_VARIANT.H6} textAlign="center">
|
||
{title}
|
||
</Typography>
|
||
<Box display="flex" justifyContent="flex-end">
|
||
<IconButton variant={P8P_ICON_BUTTON_VARIANT.DIALOG_CLOSE} onClick={handleClose}>
|
||
<Icon fontSize="small">close</Icon>
|
||
</IconButton>
|
||
</Box>
|
||
</Box>
|
||
</DialogTitle>
|
||
<DialogContent
|
||
variant={scrollContent ? P8P_DIALOG_CONTENT_VARIANT.PRIMARY : P8P_DIALOG_CONTENT_VARIANT.HIDDEN}
|
||
data-variant-props={{ paddingDisabled }}
|
||
>
|
||
{inputsState.map((input, i) => (
|
||
<P8PInput key={i} {...input} formValues={formValues} onChange={handleInputChange} />
|
||
))}
|
||
{children}
|
||
</DialogContent>
|
||
{!actionsDisabled ? (
|
||
<DialogActions variant={P8P_DIALOG_ACTIONS_VARIANT.DIALOG}>
|
||
{onClose && (
|
||
<Button variant={P8P_BUTTON_VARIANT.OUTLINED} onClick={handleClose}>
|
||
{BUTTONS.CLOSE}
|
||
</Button>
|
||
)}
|
||
{onCancel && (
|
||
<Button variant={P8P_BUTTON_VARIANT.SECONDARY} onClick={handleCancel}>
|
||
{BUTTONS.CANCEL}
|
||
</Button>
|
||
)}
|
||
{onOk && (
|
||
<Button variant={P8P_BUTTON_VARIANT.PRIMARY} disabled={okDisabled} onClick={handleOk}>
|
||
{BUTTONS.OK}
|
||
</Button>
|
||
)}
|
||
</DialogActions>
|
||
) : null}
|
||
</Dialog>
|
||
);
|
||
};
|
||
|
||
//Контроль свойств - Диалог
|
||
P8PDialog.propTypes = {
|
||
title: PropTypes.string.isRequired,
|
||
width: PropTypes.oneOf(Object.values(P8P_DIALOG_WIDTH)),
|
||
fullWidth: PropTypes.bool,
|
||
inputs: PropTypes.arrayOf(PropTypes.shape(P8P_INPUT)),
|
||
children: PropTypes.oneOfType([PropTypes.node, PropTypes.arrayOf(PropTypes.node)]),
|
||
okDisabled: PropTypes.bool,
|
||
paddingDisabled: PropTypes.bool,
|
||
actionsDisabled: PropTypes.bool,
|
||
scrollContent: PropTypes.bool,
|
||
onOk: PropTypes.func,
|
||
onCancel: PropTypes.func,
|
||
onClose: PropTypes.func,
|
||
onInputChange: PropTypes.func
|
||
};
|
||
|
||
//----------------
|
||
//Интерфейс модуля
|
||
//----------------
|
||
|
||
export { P8PDialog, P8P_DIALOG_WIDTH };
|