Skip to content

Commit

Permalink
Merge pull request #4410 from webkom/refactor-table
Browse files Browse the repository at this point in the history
Refactor table component to functional
  • Loading branch information
norbye committed Jan 27, 2024
2 parents 00a2861 + 3a6e831 commit 7117e5c
Show file tree
Hide file tree
Showing 4 changed files with 398 additions and 363 deletions.
44 changes: 44 additions & 0 deletions app/components/Table/BodyCell.tsx
@@ -0,0 +1,44 @@
import { get } from 'lodash';
import type { ColumnProps, ShowColumn } from '.';

type CellProps = {
column: ColumnProps;
data: Record<string, any>;
index: number;
showColumn?: ShowColumn;
};

const BodyCell: React.FC<CellProps> = ({ column, data, index, showColumn }) => {
if (column.columnChoices) {
if (!showColumn) {
return null;
}
const columnIndex: number = showColumn[column.dataIndex];
column = column.columnChoices[columnIndex];
}

const cellData = get(data, column.dataIndex);

const {
render = (cellData) => cellData,
dataIndex,
centered = true,
} = column;

return (
<td
key={`${dataIndex}-${index}-${data.id}`}
style={
centered
? {
textAlign: 'center',
}
: {}
}
>
{render(cellData, data)}
</td>
);
};

export default BodyCell;
226 changes: 226 additions & 0 deletions app/components/Table/HeadCell.tsx
@@ -0,0 +1,226 @@
import { Button, Flex, Icon } from '@webkom/lego-bricks';
import cx from 'classnames';
import { useEffect, useRef } from 'react';
import Dropdown from 'app/components/Dropdown';
import { TextInput, RadioButton } from 'app/components/Form';
import styles from './Table.css';
import type { ColumnProps, Filters, IsShown, ShowColumn, Sort } from '.';

type HeadCellProps = {
column: ColumnProps;
index: number;
sort: Sort;
filters: Filters;
isShown: IsShown;
showColumn?: ShowColumn;
setSort: React.Dispatch<React.SetStateAction<Sort>>;
setFilters: React.Dispatch<React.SetStateAction<Filters>>;
setIsShown: React.Dispatch<React.SetStateAction<IsShown>>;
setShowColumn: React.Dispatch<React.SetStateAction<ShowColumn>>;
};

const HeadCell: React.FC<HeadCellProps> = ({
column,
index,
sort,
filters,
isShown,
showColumn,
setSort,
setFilters,
setIsShown,
setShowColumn,
}) => {
const searchInputRef = useRef<HTMLInputElement>(null);

const onSortInput = (dataIndex: any, sorter: any) => {
const direction =
sort.dataIndex === dataIndex && sort.direction === 'asc' ? 'desc' : 'asc';
setSort({
direction,
dataIndex,
sorter,
});
};

const changeFilter = (filterIndex: string, value: string) =>
setFilters({ ...filters, [filterIndex]: value });

const toggleIsShown = (filterIndex: string) =>
setIsShown({
[filterIndex]: !isShown[filterIndex],
});

const onChooseColumnInput = (columnIndex: any, dataIndex: any) => {
setShowColumn({
[dataIndex]: columnIndex,
});
};

let chosenProps = column;
const columnChoices = column.columnChoices;
const dataIndexColumnChoices = column.dataIndex;

if (column.columnChoices) {
const columnIndex = showColumn ? showColumn[dataIndexColumnChoices] : 0;
chosenProps = { ...column, ...column.columnChoices[columnIndex] };
}

const {
dataIndex,
filterIndex = dataIndex,
title,
sorter,
filter,
search,
filterMessage,
} = chosenProps;

useEffect(() => {
search &&
isShown[filterIndex] &&
searchInputRef.current?.focus({ preventScroll: true });
}, [search, isShown, filterIndex]);

const sortIconName =
sort.dataIndex === dataIndex
? sort.direction === 'asc'
? 'sort-asc'
: 'sort-desc'
: 'sort';

return (
<th key={`${dataIndex}-${index}`}>
<Flex alignItems="center" justifyContent="center" gap={4.5}>
{sorter && (
<i
onClick={() => onSortInput(dataIndex, sorter)}
className={`fa fa-${sortIconName}`}
/>
)}
{title}
{search && (
<Dropdown
show={isShown[filterIndex]}
toggle={() => toggleIsShown(filterIndex)}
triggerComponent={
<Icon
name="search"
size={16}
className={cx(
(filters[filterIndex] && filters[filterIndex].length) ||
isShown[filterIndex]
? styles.iconActive
: styles.icon
)}
/>
}
contentClassName={styles.overlay}
rootClose
>
<TextInput
inputRef={searchInputRef}
removeBorder
placeholder={filterMessage}
value={filters[filterIndex]}
onChange={(e) => changeFilter(filterIndex, e.target.value)}
onKeyDown={({ keyCode }) => {
if (keyCode === 13) {
toggleIsShown(filterIndex);
}
}}
/>
</Dropdown>
)}
{filter && (
<Dropdown
show={isShown[filterIndex]}
toggle={() => toggleIsShown(filterIndex)}
triggerComponent={
<Icon
name="funnel"
size={16}
className={cx(
filters[filterIndex] !== undefined || isShown[filterIndex]
? styles.iconActive
: styles.icon
)}
/>
}
contentClassName={styles.checkbox}
rootClose
>
{filter.map(({ label, value }) => (
<div key={label}>
<RadioButton
id={filterIndex + value}
name={filterIndex}
label={label}
checked={value === filters[filterIndex]}
onChange={() =>
changeFilter(
filterIndex,
filters[filterIndex] === value ? undefined : value
)
}
/>
</div>
))}
<Button
flat
onClick={() => {
setFilters((prevFilters) => {
const updatedFilters = { ...prevFilters };
delete updatedFilters[filterIndex];
return updatedFilters;
});
toggleIsShown(filterIndex);
}}
>
Nullstill
</Button>
</Dropdown>
)}
{columnChoices && (
<Dropdown
show={isShown[filterIndex]}
toggle={() => toggleIsShown(filterIndex)}
triggerComponent={
<Icon
name="options"
size={16}
className={cx(
filters[filterIndex] !== undefined || isShown[filterIndex]
? styles.iconActive
: styles.icon
)}
/>
}
contentClassName={styles.overlay}
rootClose
>
{showColumn &&
columnChoices.map(({ title }, index) => (
<div key={title}>
<RadioButton
id={dataIndexColumnChoices + index}
name={dataIndexColumnChoices}
inputValue={showColumn[dataIndexColumnChoices]}
value={index}
label={title}
checked={showColumn[dataIndexColumnChoices] === index}
onChange={() => null}
onClick={() => {
onChooseColumnInput(index, dataIndexColumnChoices);
}}
/>
</div>
))}
</Dropdown>
)}
</Flex>
</th>
);
};

export default HeadCell;

0 comments on commit 7117e5c

Please sign in to comment.