/* Парус 8 - Панели мониторинга - Редактор панелей Компоненты: Хуки компонентов */ //--------------------- //Подключение библиотек //--------------------- import { useState, useContext, useEffect, useRef } from "react"; //Классы React import client from "../../../core/client"; //Клиент взаимодействия с сервером приложений import { formatErrorMessage } from "../../../core/utils"; //Общие вспомогательные функции import { BackEndСtx } from "../../../context/backend"; //Контекст взаимодействия с сервером import { DATA_SOURCE_TYPE, ARGUMENT_DATA_TYPE } from "./editors_common"; //Общие объекты редакторов //----------- //Тело модуля //----------- //Загрузка модуля компонента из модуля (можно применять как альтернативу React.lazy) const useComponentModule = ({ path = null, module = "view" } = {}) => { //Собственное состояние - импортированный модуль компонента const [componentModule, setComponentModule] = useState(null); //Собственное состояние - флаг готовности const [init, setInit] = useState(false); //При подмонтировании к странице useEffect(() => { //Динамическая загрузка модуля компонента из библиотеки const importComponentModule = async () => { setInit(false); const moduleContent = await import(`./${path}/${module}`); setComponentModule(moduleContent); setInit(true); }; if (path) importComponentModule(); }, [path, module]); //Возвращаем интерфейс хука return [componentModule, init]; }; //Описание пользовательской процедуры const useUserProcDesc = ({ code, refresh }) => { //Собственное состояние - флаг загрузки const [isLoading, setLoading] = useState(false); //Собственное состояние - данные const [data, setData] = useState(null); //Подключение к контексту взаимодействия с сервером const { executeStored } = useContext(BackEndСtx); //При необходимости обновить данные компонента useEffect(() => { //Загрузка данных с сервера const loadData = async () => { try { setLoading(true); const data = await executeStored({ stored: "PKG_P8PANELS_EDITOR.USERPROCS_DESC", args: { SCODE: code }, respArg: "COUT", isArray: name => name === "arguments", loader: false }); setData(data?.XUSERPROC || null); } finally { setLoading(false); } }; //Если надо обновить и есть для чего получать данные if (refresh > 0) if (code) loadData(); else setData(null); }, [refresh, code, executeStored]); //Возвращаем интерфейс хука return [data, isLoading]; }; //Получение данных компонента из источника const useComponentDataSource = ({ dataSource, values }) => { //Контроллер для прерывания запросов const abortController = useRef(null); //Собственное состояние - параметры исполнения const [state, setState] = useState({ stored: null, storedArgs: [], respArg: null, reqSet: false }); //Собственное состояние - флаг загрузки const [isLoading, setLoading] = useState(false); //Собственное состояние - данные const [data, setData] = useState({ init: false }); //Собственное состояние - ошибка получения данных const [error, setError] = useState(null); //Подключение к контексту взаимодействия с сервером const { executeStored } = useContext(BackEndСtx); //При необходимости обновить данные useEffect(() => { //Загрузка данных с сервера const loadData = async () => { try { setLoading(true); abortController.current?.abort?.(); abortController.current = new AbortController(); const data = await executeStored({ stored: state.stored, args: { ...(state.storedArgs ? state.storedArgs : {}) }, respArg: state.respArg, loader: false, signal: abortController.current.signal, showErrorMessage: false }); setError(null); setData({ ...data, init: true }); } catch (e) { if (e.message !== client.ERR_ABORTED) { setError(formatErrorMessage(e.message).text); setData({ init: false }); } } finally { setLoading(false); } }; if (state.reqSet) { if (state.stored) loadData(); } else setData({ init: false }); return () => abortController.current?.abort?.(); }, [state.stored, state.storedArgs, state.respArg, state.reqSet, executeStored]); //При изменении свойств useEffect(() => { setState(pv => { if (dataSource?.type == DATA_SOURCE_TYPE.USER_PROC) { const { stored, respArg } = dataSource; let reqSet = true; const storedArgs = {}; dataSource.arguments.forEach(argument => { let v = argument.valueSource ? values[argument.valueSource] : argument.value; storedArgs[argument.name] = argument.dataType == ARGUMENT_DATA_TYPE.NUMB ? isNaN(parseFloat(v)) ? null : parseFloat(v) : argument.dataType == ARGUMENT_DATA_TYPE.DATE ? new Date(v) : String(v === undefined ? "" : v); if (argument.req === true && [undefined, null, ""].includes(storedArgs[argument.name])) reqSet = false; }); if (pv.stored != stored || pv.respArg != respArg || JSON.stringify(pv.storedArgs) != JSON.stringify(storedArgs)) { if (!reqSet) { setError("Не заданы обязательные параметры источника данных"); setData({ init: false }); } return { stored, respArg, storedArgs, reqSet }; } else return pv; } else return pv; }); }, [dataSource, values]); //Возвращаем интерфейс хука return [data, error, isLoading]; }; //---------------- //Интерфейс модуля //---------------- export { useComponentModule, useUserProcDesc, useComponentDataSource };