@sinchsmb/ui-kit
Version:
UI kit for SinchSMB frontend
141 lines (125 loc) • 4.39 kB
text/typescript
import { useCallback, useMemo } from 'react';
import { useTranslation } from '../../../core/hooks/useTranslation';
import { useToast } from '../../../core/managers/ToastManager/hooks/useToast';
import { assertUnreachable } from '../../../utils/assertUnreachable';
import { ToastAppearance } from '../../Toast/constants';
import { TableSelectionType } from '../constants';
import { useTablePropsContext } from '../contexts/TablePropsContext';
import { useTableSelectionContext } from '../contexts/TableSelectionContext';
/** Result of {@link useAllPageRowsSelection} hook. */
export interface UseAllPageRowsSelectionResult {
/** Flag indicating whether all page rows are selected. */
isAllPageRowsSelected: boolean | null;
/** Function that will toggle all page rows selection. */
onAllPageRowsSelectionChange: (selected: boolean) => void;
}
/** Hook that returns information about all page rows selection. */
export function useAllPageRowsSelection(): UseAllPageRowsSelectionResult {
const { t } = useTranslation();
const showToast = useToast();
const { selection, onSelectionChanged } = useTableSelectionContext();
const { rowSelectionName, rows, rowIdProvider, rowSelectionIncludeLimit } = useTablePropsContext();
const onAllPageRowsSelectionChange = useCallback(
(selected: boolean) => {
if (!onSelectionChanged) {
return;
}
if (selection?.type === TableSelectionType.Exclude) {
const unselectedIds = new Set(selection.unselectedIds);
if (selected) {
rows.forEach((row) => {
const rowId = rowIdProvider(row);
unselectedIds.delete(rowId);
});
} else {
rows.forEach((row) => {
const rowId = rowIdProvider(row);
unselectedIds.add(rowId);
});
}
onSelectionChanged({
type: TableSelectionType.Exclude,
unselectedIds: Array.from(unselectedIds),
});
} else {
const selectedIds = new Set(selection?.selectedIds);
if (selected) {
rows.forEach((row) => {
const rowId = rowIdProvider(row);
selectedIds.add(rowId);
});
} else {
rows.forEach((row) => {
const rowId = rowIdProvider(row);
selectedIds.delete(rowId);
});
}
if (rowSelectionIncludeLimit && selectedIds.size > rowSelectionIncludeLimit) {
const message = t('ui.table.selectionIncludeLimit', {
count: rowSelectionIncludeLimit,
actionText: t('ui.table.selectAll'),
name: rowSelectionName,
});
showToast(message, { appearance: ToastAppearance.Warning });
}
onSelectionChanged({
type: TableSelectionType.Include,
selectedIds: Array.from(selectedIds).slice(0, rowSelectionIncludeLimit),
});
}
},
[
onSelectionChanged,
rowIdProvider,
rowSelectionIncludeLimit,
rowSelectionName,
rows,
selection,
showToast,
t,
],
);
const isAllPageRowsSelected = useMemo(() => {
if (!selection) {
return false;
}
let allRowsSelected = false;
let someRowSelected = false;
let countIncluded = 0;
let countExcluded = 0;
rows.forEach((row) => {
const rowId = rowIdProvider(row);
switch (selection.type) {
case TableSelectionType.Include:
if (selection.selectedIds.has(rowId)) {
someRowSelected = true;
countIncluded++;
if (rows.length === countIncluded || selection.selectedIds.size === rowSelectionIncludeLimit) {
allRowsSelected = true;
}
}
break;
case TableSelectionType.Exclude:
if (!selection.unselectedIds.has(rowId)) {
someRowSelected = true;
countExcluded++;
if (rows.length === countExcluded) {
allRowsSelected = true;
}
}
break;
/* istanbul ignore next */
default:
assertUnreachable(selection);
}
});
if (allRowsSelected) {
return true;
}
return someRowSelected ? null : false;
}, [rowIdProvider, rowSelectionIncludeLimit, rows, selection]);
return {
onAllPageRowsSelectionChange,
isAllPageRowsSelected,
};
}