,
languageCode: string,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
data: any[],
// eslint-disable-next-line @typescript-eslint/no-explicit-any
highlightedRowsId: any[],
isScrolling: boolean,
displayColumnsFilters: boolean,
labelEmptyState: string,
theme
) {
const highlightedRows = data.filter((item) =>
highlightedRowsId.includes(item.id)
);
return (
{columns.map((column) => {
const isColumnSelected = column.id === orderBy;
const isFilterActive = !!activeFilters.find(
(activeFilter) => activeFilter.propertyKey === column.propertyKey
);
return (
-
setOrderColumn(column.id)}
grey={!isColumnSelected}
darkBlue={isColumnSelected || isFilterActive}
interactive
>
{column.name}
{column.id !== orderBy && (
setOrderColumn(column.id)}
width="16"
height="16"
src={icons[theme.pagination?.icon].sort?.default}
alt="icon-order"
marginLeft="5px"
interactive
/>
)}
{column.id === orderBy && (
setOrderColumn(column.id)}
width="16"
height="16"
src={
orderType === ORDER_TYPE.DESCENDING
? icons[theme.pagination?.icon].sort?.desc
: icons[theme.pagination?.icon].sort?.asc
}
alt="icon-order"
marginLeft="5px"
interactive
/>
)}
{column.tooltipText && }
{column.filterType && displayColumnsFilters && (
<>
updateFilters(
filterId,
column.propertyKey,
doFilter,
value
)
}
languageCode={languageCode}
/>
{renderActiveFilterIndex(activeFilters, column)}
>
)}
);
})}
{highlightedRows &&
highlightedRows.length > 0 &&
renderContent(
columns,
highlightedRows,
highlightedRowsId,
labelEmptyState,
false,
false
)}
);
}
function renderPagination(
currentPage: number,
totalPage: number,
pageLimit: number,
isDropDownPageLimitOpened: boolean,
nbTotalElements: number,
isLoading: boolean,
previousPage,
nextPage,
setPageLimit,
setIsDropDownPageLimitOpened,
theme,
getFirstElementOfPage,
getLastElementOfPage
) {
return (
!isLoading &&
setIsDropDownPageLimitOpened(!isDropDownPageLimitOpened)
}
onKeyDown={() =>
!isLoading &&
setIsDropDownPageLimitOpened(!isDropDownPageLimitOpened)
}
style={{
color: theme.pagination?.dropdown?.color,
border: theme.pagination?.dropdown?.border,
boxShadow: theme.pagination?.dropdown?.boxShadow,
background: theme.pagination?.dropdown?.backgroundColor,
borderRadius: theme.pagination?.dropdown?.borderRadius,
}}
interactive
>
{isDropDownPageLimitOpened && (
{getPageLimitOptions(nbTotalElements).map((option) => (
// eslint-disable-next-line jsx-a11y/no-static-element-interactions
option.callback(setPageLimit, nbTotalElements)}
onKeyDown={() =>
option.callback(setPageLimit, nbTotalElements)
}
>
{option.text}
{option.value === pageLimit && (
)}
))}
)}
{pageLimit === nbTotalElements
? i18next.t('GENERAL_ALL')
: `${pageLimit} ${i18next.t(
'COMPONENT_LIST_PAGINATION_PER_PAGE'
)}`}
{getFirstElementOfPage()} - {getLastElementOfPage()}{' '}
{i18next.t('COMPONENT_LIST_VIEW_PAGINATOR_ON')} {nbTotalElements}
{`${currentPage} / ${totalPage}`}
= totalPage ? 'disabled' : undefined}
onClick={nextPage}
onKeyDown={nextPage}
interactive
>
);
}
function renderLoadingState(columns: Column[], theme) {
return (
<>
{_.times(NB_EMPTY_ROWS_LOADING_STATE, (index) => (
{columns.map(({ name }) => (
-
))}
{index > 0 && }
))}
>
);
}
const TableView = (props: Props): JSX.Element | null => {
const {
data,
columns,
minWidth,
maxPerPage,
positionTop,
positionBottom,
languageCode,
defaultOrderBy,
defaultOrderType,
highligthedRowsId,
isLoading,
displayColumnsFilters,
labelEmptyState,
theme,
} = props;
const tableContentRef = useRef(null);
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const [activeData, setActiveData] = useState([]);
const [orderBy, setOrderBy] = useState(defaultOrderBy);
const [orderType, setOrdertType] = useState(defaultOrderType);
const [totalPage, setTotalPage] = useState(1);
const [pageLimit, setPageLimit] = useState(maxPerPage);
const [currentPage, setCurrentPage] = useState(1);
const [selectedFilterId, setSelectedFilterId] = useState<
string | number | object | null
>(null);
const [activeFilters, setActiveFilters] = useState([]);
const [isDropDownPageLimitOpened, setIsDropDownPageLimitOpened] =
useState(false);
const [isScrollingContent, setIsScrollingContent] = useState(false);
useScrollListener(tableContentRef, (event) => {
setIsScrollingContent(event.target.scrollTop !== 0);
});
useEffect(() => {
i18next.changeLanguage(languageCode);
}, [languageCode]);
useEffect(() => {
if (!data) {
return;
}
setActiveData(data);
}, [data]);
useEffect(() => {
if (!activeData) {
return;
}
const totalPerPage = pageLimit;
setTotalPage(
Math.max(
Math.ceil(
activeData.filter((item) => !highligthedRowsId.includes(item.id))
.length / totalPerPage
),
1
)
);
setCurrentPage(1);
}, [pageLimit, activeData, highligthedRowsId]);
const previousPage = () => {
if (currentPage <= 1) {
return;
}
setCurrentPage(currentPage - 1);
};
const nextPage = () => {
if (currentPage >= totalPage) {
return;
}
setCurrentPage(currentPage + 1);
};
const setOrderColumn = (columnId) => {
if (orderBy === columnId) {
setOrdertType(
orderType === ORDER_TYPE.ASCENDING
? ORDER_TYPE.DESCENDING
: ORDER_TYPE.ASCENDING
);
return;
}
setOrderBy(columnId);
setOrdertType(ORDER_TYPE.ASCENDING);
};
if (!columns || !columns.length) {
return null;
}
const references = {};
// create ref to attach to selector Filter using useOnClickOutside hook
const GetOrCreateRef = (id) => {
if (!Object.prototype.hasOwnProperty.call(references, id)) {
references[id] = useOnClickOutside(() => {
if (selectedFilterId === id) {
setSelectedFilterId(null);
}
});
}
return references[id];
};
/** *************** */
/* Handle Filters */
/** *************** */
const handleFilterSelection = (filterId) =>
setSelectedFilterId(selectedFilterId === filterId ? null : filterId);
const updateFilters = (filterId, propertyKey, doFilter, value) => {
// deactivate filter when deselected or submitted incomplete or empty
if (
!doFilter ||
value === null ||
value.minValue === null ||
value.maxValue === null ||
(filterId.toString().startsWith('string-selector-filter') &&
value.length === 0)
) {
setActiveFilters(
activeFilters.filter(
(activeFilter) => activeFilter.filterId !== filterId
)
);
return;
}
// remove overwritten filter
const updatedActiveFilters = activeFilters.filter(
(activeFilter) => activeFilter.propertyKey !== propertyKey
);
// activate new filter
setActiveFilters([
...updatedActiveFilters,
{ filterId, propertyKey, doFilter, value },
]);
};
useEffect(() => {
if (!activeFilters.length) {
setActiveData(data);
return;
}
let filteredData = data;
activeFilters.forEach(({ propertyKey, doFilter, value }) => {
filteredData = doFilter(filteredData, propertyKey, value);
});
setActiveData(filteredData);
}, [activeFilters, data]);
const sortedData = sortListBy(
activeData,
columns,
orderBy,
orderType,
highligthedRowsId
);
const updatedTheme = getTheme(theme, 'tableView');
const getFirstElementOfPage = () => {
return (currentPage - 1) * maxPerPage + 1;
};
const getLastElementOfPage = () => {
const itemsCount = activeData.filter(
(item) => !highligthedRowsId.includes(item.id)
).length;
if (currentPage * maxPerPage > itemsCount) {
return itemsCount;
}
return currentPage * maxPerPage;
};
return (
{activeFilters.length !== 0 && (
setActiveFilters([])}>
{i18next.t('GENERAL_CLEAR_FILTER')}
)}
{renderHeader(
columns,
orderBy,
orderType,
setOrderColumn,
selectedFilterId,
handleFilterSelection,
updateFilters,
activeFilters,
GetOrCreateRef,
languageCode,
activeData,
isLoading ? [] : highligthedRowsId, // no need to display highlighted rows if data are being fetched
isScrollingContent,
displayColumnsFilters,
labelEmptyState,
updatedTheme
)}
{isLoading && renderLoadingState(columns, updatedTheme)}
{!isLoading &&
renderContent(
columns,
getPaginatedData(
sortedData,
currentPage,
pageLimit,
highligthedRowsId
),
highligthedRowsId,
labelEmptyState,
true,
true
)}
{renderPagination(
currentPage,
totalPage,
pageLimit,
isDropDownPageLimitOpened,
activeData.filter((item) => !highligthedRowsId.includes(item.id))
.length,
isLoading,
previousPage,
nextPage,
setPageLimit,
setIsDropDownPageLimitOpened,
updatedTheme,
getFirstElementOfPage,
getLastElementOfPage
)}
);
};
TableView.propTypes = {
// eslint-disable-next-line react/forbid-prop-types
theme: PropTypes.objectOf(PropTypes.any),
isLoading: PropTypes.bool,
minWidth: PropTypes.number,
maxPerPage: PropTypes.number,
positionTop: PropTypes.number,
positionBottom: PropTypes.number,
defaultOrderBy: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
defaultOrderType: PropTypes.string,
columns: PropTypes.arrayOf(
PropTypes.shape({
render: PropTypes.func,
decimals: PropTypes.number,
tooltipText: PropTypes.string,
name: PropTypes.string.isRequired,
type: PropTypes.oneOf(Object.keys(TYPE_FIELD)),
propertyKey: PropTypes.string.isRequired,
})
).isRequired,
// eslint-disable-next-line react/forbid-prop-types
data: PropTypes.arrayOf(PropTypes.object).isRequired,
// eslint-disable-next-line react/forbid-prop-types
highligthedRowsId: PropTypes.arrayOf(PropTypes.any),
displayColumnsFilters: PropTypes.bool,
languageCode: PropTypes.string,
labelEmptyState: PropTypes.string,
};
TableView.defaultProps = {
isLoading: false,
minWidth: 600,
maxPerPage: 20,
positionTop: 0,
positionBottom: 0,
defaultOrderBy: null,
defaultOrderType: ORDER_TYPE.ASCENDING,
highligthedRowsId: [],
displayColumnsFilters: true,
languageCode: 'fr',
labelEmptyState: 'Aucun résultat ne correspond à votre recherche',
theme: null,
};
export default TableView;