/* eslint-disable no-unused-vars */ /* eslint-disable react-hooks/exhaustive-deps */ import React, { useMemo, useState, useEffect, useCallback } from 'react'; import { useTable, useFilters, useSortBy, useGlobalFilter, useAsyncDebounce, usePagination, useBlockLayout, useResizeColumns, useRowSelect, } from 'react-table'; import cx from 'classnames'; import { resolveReferences, resolveWidgetFieldValue, validateWidget } from '@/_helpers/utils'; import SelectSearch, { fuzzySearch } from 'react-select-search'; import { useExportData } from 'react-table-plugins'; import Papa from 'papaparse'; import { Pagination } from './Pagination'; import { CustomSelect } from './CustomSelect'; import { Tags } from './Tags'; import { Radio } from './Radio'; import { Toggle } from './Toggle'; import { Datepicker } from './Datepicker'; import { GlobalFilter } from './GlobalFilter'; var _ = require('lodash'); export function Table({ id, width, height, component, onComponentClick, currentState = { components: {} }, onEvent, paramUpdated, changeCanDrag, onComponentOptionChanged, onComponentOptionsChanged, darkMode, fireEvent, setExposedVariable, registerAction, }) { const color = component.definition.styles.textColor.value !== '#000' ? component.definition.styles.textColor.value : darkMode && '#fff'; const actions = component.definition.properties.actions || { value: [] }; const serverSidePaginationProperty = component.definition.properties.serverSidePagination; const serverSidePagination = serverSidePaginationProperty ? resolveWidgetFieldValue(serverSidePaginationProperty.value, currentState) : false; const serverSideSearchProperty = component.definition.properties.serverSideSearch; const serverSideSearch = serverSideSearchProperty ? resolveWidgetFieldValue(serverSideSearchProperty.value, currentState) : false; const displaySearchBoxProperty = component.definition.properties.displaySearchBox; const displaySearchBox = displaySearchBoxProperty ? resolveWidgetFieldValue(displaySearchBoxProperty.value, currentState) : true; const showDownloadButtonProperty = component.definition.properties.showDownloadButton?.value; const showDownloadButton = resolveWidgetFieldValue(showDownloadButtonProperty, currentState) ?? true; // default is true for backward compatibility const showFilterButtonProperty = component.definition.properties.showFilterButton?.value; const showFilterButton = resolveWidgetFieldValue(showFilterButtonProperty, currentState) ?? true; // default is true for backward compatibility const showBulkUpdateActionsProperty = component.definition.properties.showBulkUpdateActions?.value; const showBulkUpdateActions = resolveWidgetFieldValue(showBulkUpdateActionsProperty, currentState) ?? true; // default is true for backward compatibility const showBulkSelectorProperty = component.definition.properties.showBulkSelector?.value; const showBulkSelector = resolveWidgetFieldValue(showBulkSelectorProperty, currentState) ?? false; // default is false for backward compatibility const highlightSelectedRowProperty = component.definition.properties.highlightSelectedRow?.value; const highlightSelectedRow = resolveWidgetFieldValue(highlightSelectedRowProperty, currentState) ?? false; // default is false for backward compatibility const clientSidePaginationProperty = component.definition.properties.clientSidePagination?.value; const clientSidePagination = resolveWidgetFieldValue(clientSidePaginationProperty, currentState) ?? !serverSidePagination; // default is true for backward compatibility const tableTypeProperty = component.definition.styles.tableType; let tableType = tableTypeProperty ? tableTypeProperty.value : 'table-bordered'; tableType = tableType === '' ? 'table-bordered' : tableType; const cellSizeType = component.definition.styles.cellSize?.value; const borderRadius = component.definition.styles.borderRadius?.value; const widgetVisibility = component.definition.styles?.visibility?.value ?? true; const disabledState = component.definition.styles?.disabledState?.value ?? false; const parsedDisabledState = typeof disabledState !== 'boolean' ? resolveWidgetFieldValue(disabledState, currentState) : disabledState; let parsedWidgetVisibility = widgetVisibility; try { parsedWidgetVisibility = resolveReferences(parsedWidgetVisibility, currentState, []); } catch (err) { console.log(err); } const [loadingState, setLoadingState] = useState(false); useEffect(() => { const loadingStateProperty = component.definition.properties.loadingState; if (loadingStateProperty && currentState) { const newState = resolveReferences(loadingStateProperty.value, currentState, false); setLoadingState(newState); } }, [currentState]); const [componentState, setcomponentState] = useState(currentState.components[component.component] || {}); useEffect(() => { setcomponentState(currentState.components[component.name] || {}); }, [currentState.components[component.name]]); const [isFiltersVisible, setFiltersVisibility] = useState(false); const [filters, setFilters] = useState([]); function showFilters() { setFiltersVisibility(true); } function hideFilters() { setFiltersVisibility(false); } function filterColumnChanged(index, value) { const newFilters = filters; newFilters[index].id = value; setFilters(newFilters); setAllFilters(newFilters.filter((filter) => filter.id !== '')); } function filterOperationChanged(index, value) { const newFilters = filters; newFilters[index].value = { ...newFilters[index].value, operation: value, }; setFilters(newFilters); setAllFilters(newFilters.filter((filter) => filter.id !== '')); } function filterValueChanged(index, value) { const newFilters = filters; newFilters[index].value = { ...newFilters[index].value, value: value, }; setFilters(newFilters); setAllFilters(newFilters.filter((filter) => filter.id !== '')); } function addFilter() { setFilters([...filters, { id: '', value: { operation: 'contains', value: '' } }]); } function removeFilter(index) { let newFilters = filters; newFilters.splice(index, 1); setFilters(newFilters); setAllFilters(newFilters.filter((filter) => filter.id !== '')); } function clearFilters() { setFilters([]); setAllFilters([]); } const defaultColumn = React.useMemo( () => ({ minWidth: 60, width: 268, }), [] ); const columnSizes = component.definition.properties.columnSizes || {}; function handleCellValueChange(index, key, value, rowData) { const changeSet = componentState.changeSet; const dataUpdates = componentState.dataUpdates || []; let obj = changeSet ? changeSet[index] || {} : {}; obj = _.set(obj, key, value); let newChangeset = { ...changeSet, [index]: { ...obj, }, }; obj = _.set(rowData, key, value); let newDataUpdates = { ...dataUpdates, [index]: { ...obj }, }; return onComponentOptionsChanged(component, [ ['dataUpdates', newDataUpdates], ['changeSet', newChangeset], ]); } function getExportFileBlob({ columns, data }) { const headerNames = columns.map((col) => col.exportValue); const csvString = Papa.unparse({ fields: headerNames, data }); return new Blob([csvString], { type: 'text/csv' }); } function onPageIndexChanged(page) { onComponentOptionChanged(component, 'pageIndex', page).then(() => { onEvent('onPageChanged', { component, data: {} }); }); } function handleChangesSaved() { Object.keys(changeSet).forEach((key) => { tableData[key] = { ..._.merge(tableData[key], changeSet[key]), }; }); onComponentOptionChanged(component, 'changeSet', {}); onComponentOptionChanged(component, 'dataUpdates', []); } function handleChangesDiscarded() { onComponentOptionChanged(component, 'changeSet', {}); onComponentOptionChanged(component, 'dataUpdates', []); } function customFilter(rows, columnIds, filterValue) { try { if (filterValue.operation === 'equals') { return rows.filter((row) => row.values[columnIds[0]] === filterValue.value); } if (filterValue.operation === 'ne') { return rows.filter((row) => row.values[columnIds[0]] !== filterValue.value); } if (filterValue.operation === 'matches') { return rows.filter((row) => row.values[columnIds[0]].toString().toLowerCase().includes(filterValue.value.toLowerCase()) ); } if (filterValue.operation === 'nl') { return rows.filter((row) => !row.values[columnIds[0]].toString().toLowerCase().includes(filterValue.value.toLowerCase()) ); } if (filterValue.operation === 'gt') { return rows.filter((row) => row.values[columnIds[0]] > filterValue.value); } if (filterValue.operation === 'lt') { return rows.filter((row) => row.values[columnIds[0]] < filterValue.value); } if (filterValue.operation === 'gte') { return rows.filter((row) => row.values[columnIds[0]] >= filterValue.value); } if (filterValue.operation === 'lte') { return rows.filter((row) => row.values[columnIds[0]] <= filterValue.value); } let value = filterValue.value; if (typeof value === 'string') { value = value.toLowerCase(); } return rows.filter((row) => { let rowValue = row.values[columnIds[0]]; if (typeof rowValue === 'string') { rowValue = rowValue.toLowerCase(); } return rowValue.includes(value); }); } catch { return rows; } } const changeSet = componentState ? componentState.changeSet : {}; const computeFontColor = useCallback(() => { if (color !== undefined) { return color; } else { return darkMode ? '#ffffff' : '#000000'; } }, [color, darkMode]); const columnData = component.definition.properties.columns.value.map((column) => { const columnSize = columnSizes[column.id] || columnSizes[column.name]; const columnType = column.columnType; const columnOptions = {}; if ( columnType === 'dropdown' || columnType === 'multiselect' || columnType === 'badge' || columnType === 'badges' || columnType === 'radio' ) { const values = resolveReferences(column.values, currentState) || []; const labels = resolveReferences(column.labels, currentState, []) || []; if (Array.isArray(labels)) { columnOptions.selectOptions = labels.map((label, index) => { return { name: label, value: values[index] }; }); } } if (columnType === 'datepicker') { column.isTimeChecked = column.isTimeChecked ? column.isTimeChecked : false; column.dateFormat = column.dateFormat ? column.dateFormat : 'DD/MM/YYYY'; column.parseDateFormat = column.parseDateFormat ?? column.dateFormat; //backwards compatibility } const width = columnSize || defaultColumn.width; return { id: column.id, Header: column.name, accessor: column.key || column.name, filter: customFilter, width: width, columnOptions, columnType, isEditable: column.isEditable, Cell: function (cell) { const rowChangeSet = changeSet ? changeSet[cell.row.index] : null; const cellValue = rowChangeSet ? rowChangeSet[column.name] || cell.value : cell.value; switch (columnType) { case 'string': case undefined: case 'default': { const textColor = resolveReferences(column.textColor, currentState, '', { cellValue }); const cellStyles = { color: textColor ?? '', }; if (column.isEditable) { const validationData = validateWidget({ validationObject: { regex: { value: column.regex, }, minLength: { value: column.minLength, }, maxLength: { value: column.maxLength, }, customRule: { value: column.customRule, }, }, widgetValue: cellValue, currentState, customResolveObjects: { cellValue }, }); const { isValid, validationError } = validationData; const cellStyles = { color: textColor ?? '', }; return (
| {column.render('Header')} | ))}
|---|
|
{cell.render('Cell')}
|
);
})}