/* Парус 8 - Панели мониторинга Контекст: Взаимодействие с API параметров */ //--------------------- //Подключение библиотек //--------------------- import React, { createContext, useContext, useCallback, useState, useRef } from "react"; //ReactJS import PropTypes from "prop-types"; //Контроль свойств компонента import { MessagingCtx } from "./messaging"; //Контекст сообщений import { P8PSettingsDialog } from "../components/p8p_settings_dialog"; //Диалог отображения параметров import { useSettingsContext } from "./settings_hooks"; //Вспомогательные хуки параметров //--------- //Константы //--------- //Доступные виды параметров const SETTINGS_KINDS = { SYSTEM: 0, PANEL: 1, USER: 2 }; //Доступные действия параметров const SETTINGS_ACTIONS = { INIT: "INIT", GET: "GET", PUT: "PUT" }; //Псевдокод панели для системных параметров const SETTINGS_SYSTEM_PSEUDO = "__P8_SYSTEM"; //---------------- //Интерфейс модуля //---------------- //Контекст взаимодействия с API параметров export const SettingsCtx = createContext(); //Провайдер контекста взаимодействия с API параметров export const SettingsContext = ({ children }) => { //Подключение к контексту сообщений const { showMsgErr } = useContext(MessagingCtx); //Собственное состояние - действия параметров const { putPanelSettings, getPanelSettings, initPanelSettings } = useSettingsContext(showMsgErr); //Собственное состояние - отображаемые параметры const [settings, setSettings] = useState({ isOpen: false, data: {}, panel: null }); //Собственное состояние - колбэки для обработки событий const settingsCallbacks = useRef({ onOk: null, onCancel: null }); //Формирование структуры параметров панели const buildPanelSettings = (kind, panel, settings) => kind === SETTINGS_KINDS.SYSTEM ? { [SETTINGS_SYSTEM_PSEUDO]: { ...settings } } : { [panel]: { ...settings } }; //Извлечение настроек из ответа сервера const extractSettings = (res, kind, panel) => kind === SETTINGS_KINDS.SYSTEM ? { ...(res[SETTINGS_SYSTEM_PSEUDO] || {}) } : { ...(panel ? res[panel] : res) }; //Валидация параметров настройки const validateSettingsParams = useCallback( ({ action, kind, panel }) => { if ([SETTINGS_KINDS.PANEL, SETTINGS_KINDS.USER].includes(kind) && !panel) { //Формируем текст ошибки const errMsg = `Ошибка ${ action === SETTINGS_ACTIONS.INIT ? "инициализации" : action === SETTINGS_ACTIONS.PUT ? "добавления" : "действия" } параметров. Для панельных/пользовательских параметров необходимо указать панель.`; //Отображаем ошибку showMsgErr(errMsg); throw new Error(errMsg); } }, [showMsgErr] ); //Добавление параметров панелей const putSettings = useCallback( async ({ kind, settings, panel = null, loader = true }) => { //Проверка корректности параметров validateSettingsParams({ action: SETTINGS_ACTIONS.PUT, kind, panel }); //Оборачиваем параметры в панель const panelSettings = buildPanelSettings(kind, panel, settings); //Добавляем параметры панели const res = await putPanelSettings({ kind, panelSettings, loader }); //Возвращаем результат return res; }, [putPanelSettings, validateSettingsParams] ); //Считывание параметров const getSettings = useCallback( async ({ kind, code = null, panel = null, full = false, loader = true }) => { //Считываем параметры панели const res = await getPanelSettings({ kind, code, panel, full, loader }); //Возвращаем результат return extractSettings(res, kind, panel); }, [getPanelSettings] ); //Инициализация параметров const initSettings = useCallback( async ({ kind, settings, panel = null, full = false, loader = true }) => { //Проверка корректности параметров validateSettingsParams({ action: SETTINGS_ACTIONS.INIT, kind, panel }); //Оборачиваем параметры в панель const panelSettings = buildPanelSettings(kind, panel, settings); //Добавляем параметры панели const res = await initPanelSettings({ kind, panelSettings, full, loader }); //Возвращаем результат return extractSettings(res, kind, panel); }, [initPanelSettings, validateSettingsParams] ); //При нажатии "ОК" диалога параметров const handleOk = async newSettings => { //Признак наличия изменений параметров const isChanged = JSON.stringify(newSettings) !== JSON.stringify(settings.data); //Если параметры изменились - обновляем на сервере if (isChanged) await putPanelSettings({ kind: SETTINGS_KINDS.USER, panelSettings: newSettings }); //Если есть колбэк на нажатие "ОК" - вызываем его if (settingsCallbacks.current.onOk) settingsCallbacks.current.onOk({ settings: settings.panel ? newSettings[settings.panel] : newSettings, isChanged }); //Сбрасываем отображаемые данные setSettings({ isOpen: false, data: {}, panel: null }); }; //При нажатии "Отменить" диалога параметров const handleClose = () => { //Если есть колбэк на нажатие "Отменить" - вызываем его if (settingsCallbacks.current.onCancel) settingsCallbacks.current.onCancel(); //Сбрасываем отображаемые данные setSettings({ isOpen: false, data: {}, panel: null }); }; //Открытие диалога параметров const showSettingsDialog = async ({ panel = null, onOk = null, onCancel = null } = {}) => { //Загружаем информацию о параметрах const panelSettings = await getPanelSettings({ kind: SETTINGS_KINDS.USER, panel, full: true }); //Устанавливаем отображаемые данные setSettings({ isOpen: true, data: panelSettings, panel }); //Устанавливаем колбэки settingsCallbacks.current = { onOk, onCancel }; }; //Вернём компонент провайдера return ( {settings.isOpen ? : null} {children} ); }; //Контроль свойств - Провайдер контекста взаимодействия с API параметров SettingsContext.propTypes = { children: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.node), PropTypes.node]) };