/* Парус 8 - Панели мониторинга Хуки для таблиц данных */ //--------------------- //Подключение библиотек //--------------------- import { useReducer, useCallback, useEffect, useContext, useRef, useMemo } from "react"; //Классы React import { BackEndCtx } from "../context/backend"; //Контекст взаимодействия с сервером import { object2Base64XML } from "../core/utils"; //Вспомогательные функции import { DG_AT, INITIAL_STATE, dataGridReducer } from "./p8p_data_grid_reducer"; //Редьюсер состояния //--------- //Константы //--------- //Константы - значения по умолчанию const DG_PAGE_SIZE_DEF = 10; //Размер страницы const DG_NODE_NAME_DEF = "XDATA_GRID"; //Наименование узла, содержащего информацию о таблице const FILTERS_NODE_NAME_DEF = "filters"; //Наименование узла отборов const ORDERS_NODE_NAME_DEF = "orders"; //Наименование узла сортировок const RESP_ARG_DEF = "COUT"; //Имя параметра, содержащего информацию о таблице //----------- //Тело модуля //----------- //Хук для P8PDataGrid const useP8PDataGrid = ({ stored, respArg = RESP_ARG_DEF, contentNodeName = DG_NODE_NAME_DEF, filtersNodeName = FILTERS_NODE_NAME_DEF, ordersNodeName = ORDERS_NODE_NAME_DEF, pageSize = DG_PAGE_SIZE_DEF, reloadDef = false, initFilters = [], initOrders = [], storedArgs = {}, resetPageNumberOnStoredArgsChange = true, executeStoredArgs = {}, resetPageNumberOnExecuteStoredArgsChange = true, allowDataLoad = () => true }) => { //Подключим редьюсер состояния const [state, dispatch] = useReducer(dataGridReducer, INITIAL_STATE({ initFilters, initOrders })); //Установка даных таблицы const setDataGrid = (dataGridData, pageSize, isError) => dispatch({ type: DG_AT.SET_DATA_GRID, payload: { dataGridData, pageSize, isError } }); //Установка фильтра таблицы const setDataGridFilter = filters => dispatch({ type: DG_AT.SET_DATA_GRID_FILTER, payload: filters }); //Установка сортировок таблицы const setDataGridOrder = orders => dispatch({ type: DG_AT.SET_DATA_GRID_ORDER, payload: orders }); //Установка страницы таблицы const setDataGridPageNumber = pageNumber => dispatch({ type: DG_AT.SET_DATA_GRID_PAGE_NUMBER, payload: pageNumber }); //Установка флага загруженности данных const setIsDataLoaded = isDataLoaded => dispatch({ type: DG_AT.SET_IS_DATA_LOADED, payload: isDataLoaded }); //Установка флага активности процесса загрузки данных const setIsLoading = isLoading => dispatch({ type: DG_AT.SET_IS_LOADING, payload: isLoading }); //Установка флага необходимости обновления данных const setReload = (reload, resetPageNumber = false) => dispatch({ type: DG_AT.SET_RELOAD, payload: { reload, resetPageNumber } }); //Ссылка на актуальные параметры хранимой процедуры const refStoredArgs = useRef(storedArgs); //Ссылка на актуальные параметры исполнения хранимой процедуры const refExecuteStoredArgs = useRef(executeStoredArgs); //Признак допустимости обновления данных const isAllowDataLoad = useMemo(() => { return allowDataLoad(); }, [allowDataLoad]); //Подключение к контексту взаимодействия с сервером const { executeStored, SERV_DATA_TYPE_CLOB, isRespErr } = useContext(BackEndCtx); //Загрузка данных таблицы с сервера const loadData = useCallback(async () => { try { //Начинаем загрузку setIsLoading(true); const data = await executeStored({ stored, args: { CFILTERS: { VALUE: object2Base64XML(state.dataGrid.filters, { arrayNodeName: filtersNodeName }), SDATA_TYPE: SERV_DATA_TYPE_CLOB }, CORDERS: { VALUE: object2Base64XML(state.dataGrid.orders, { arrayNodeName: ordersNodeName }), SDATA_TYPE: SERV_DATA_TYPE_CLOB }, NPAGE_NUMBER: state.dataGrid.pageNumber, NPAGE_SIZE: pageSize, NINCLUDE_DEF: reloadDef ? 1 : state.isDataLoaded ? 0 : 1, ...refStoredArgs.current }, respArg, ...refExecuteStoredArgs.current }); //Устанавливаем полученные данные и признак загрузки данных с учетом возможных ошибок setDataGrid(data[contentNodeName], pageSize, isRespErr(data)); } catch (e) { //Если произошла ошибка - данные не загружены setIsDataLoaded(false); } finally { //Сбрасываем признаки загрузки и перезагрузки данных setIsLoading(false); } }, [ SERV_DATA_TYPE_CLOB, contentNodeName, state.isDataLoaded, state.dataGrid.filters, state.dataGrid.orders, state.dataGrid.pageNumber, executeStored, filtersNodeName, isRespErr, ordersNodeName, pageSize, reloadDef, respArg, stored ]); //При изменении состояния фильтра const handleFilterChanged = useCallback(({ filters }) => setDataGridFilter(filters), []); //При изменении состояния сортировки const handleOrderChanged = useCallback(({ orders }) => setDataGridOrder(orders), []); //При изменении количества отображаемых страниц const handlePagesCountChanged = useCallback(() => setDataGridPageNumber(state.dataGrid.pageNumber + 1), [state.dataGrid.pageNumber]); //При изменении страницы отображения const handlePageChange = useCallback(({ page }) => setDataGridPageNumber(page), []); //При необходимости обновления таблицы const doReload = useCallback( ({ returnOnFirstPage = false }) => setReload(true, state.dataGrid.pagesCount <= 0 || returnOnFirstPage), [state.dataGrid.pagesCount] ); //Проверка изменений параметров const isArgsChanged = useCallback( (currentArgs, args) => { //Если дополнительные параметры изменились (и сейчас не происходит загрузка данных с сервера) return !state.isLoading && JSON.stringify(currentArgs) != JSON.stringify(args); }, [state.isLoading] ); //При изменение дополнительных параметров процедуры useEffect(() => { //Если параметры изменились if (isArgsChanged(refStoredArgs.current, storedArgs)) { //Устанавливаем новые дополнительные параметры refStoredArgs.current = storedArgs; //При изменении дополнительных параметров необходимо перезагрузить данные setReload(true, resetPageNumberOnStoredArgsChange); } }, [storedArgs, resetPageNumberOnStoredArgsChange, isArgsChanged]); //При изменение дополнительных параметров вызова процедуры useEffect(() => { //Если параметры изменились if (isArgsChanged(refExecuteStoredArgs.current, executeStoredArgs)) { //Устанавливаем новые дополнительные параметры refExecuteStoredArgs.current = executeStoredArgs; //При изменении дополнительных параметров необходимо перезагрузить данные setReload(true, resetPageNumberOnExecuteStoredArgsChange); } }, [executeStoredArgs, resetPageNumberOnExecuteStoredArgsChange, isArgsChanged]); //При необходимости обновить данные таблицы useEffect(() => { if (isAllowDataLoad && state.reload) { loadData(); } }, [isAllowDataLoad, state.reload, loadData]); //Возвращаем данные таблицы return { dataGrid: state.dataGrid, isDataLoaded: state.isDataLoaded, isLoading: state.isLoading, handleFilterChanged, handleOrderChanged, handlePagesCountChanged, handlePageChange, doReload }; }; //---------------- //Интерфейс модуля //---------------- export { useP8PDataGrid };