Skip to content

Commit

Permalink
Merge pull request #1760 from gettakaro/feature/quick-search-tables
Browse files Browse the repository at this point in the history
Feat: add quick search to tables
  • Loading branch information
emielvanseveren authored Nov 2, 2024
2 parents 1318dc8 + 9832d9b commit 6667dad
Show file tree
Hide file tree
Showing 6 changed files with 68 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ export const Default = styled.button<{
span {
font-size: 1.25rem;
font-weight: 600;
white-space: nowrap;
color: ${({ theme, color }) => {
switch (color) {
case 'white':
Expand Down
31 changes: 30 additions & 1 deletion packages/lib-components/src/components/data/Table/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import {
AiOutlinePicRight as TightDensityIcon,
AiOutlineRight as ExpandIcon,
AiOutlineUp as CollapseIcon,
AiOutlineSearch as SearchIcon,
} from 'react-icons/ai';
import { ColumnHeader } from './subcomponents/ColumnHeader';
import { ColumnVisibility } from './subcomponents/ColumnVisibility';
Expand All @@ -37,7 +38,8 @@ import { PageSizeSelect } from './subcomponents/Pagination/PageSizeSelect';

import { ColumnFilter, PageOptions } from '../../../hooks/useTableActions';
import { GenericCheckBox as CheckBox } from '../../inputs/CheckBox/Generic';
import { useLocalStorage } from '../../../hooks';
import { useDebounce, useLocalStorage } from '../../../hooks';
import { UnControlledTextField } from '../../../components';

export interface TableProps<DataType extends object> {
id: string;
Expand All @@ -58,6 +60,10 @@ export interface TableProps<DataType extends object> {
/// Renders actions that are only visible when one or more rows are selected.
renderRowSelectionActions?: () => JSX.Element;

/// When callback is assigned, an input field will appear in the toolbar.
onSearchInputChanged?: (input: string) => void;
searchInputPlaceholder?: string;

title?: string;

rowSelection?: {
Expand Down Expand Up @@ -95,6 +101,8 @@ export function Table<DataType extends object>({
rowSelection,
columnSearch,
renderDetailPanel,
onSearchInputChanged,
searchInputPlaceholder = 'Search...',
renderToolbar,
canExpand = () => false,
renderRowSelectionActions,
Expand Down Expand Up @@ -127,6 +135,15 @@ export function Table<DataType extends object>({

const [columnPinning, setColumnPinning] = useState<ColumnPinningState>({});
const { storedValue: density, setValue: setDensity } = useLocalStorage<Density>(`table-density-${id}`, 'tight');
const [searchInput, setSearchInput] = useState<string>('');
const debouncedValue = useDebounce(searchInput, 350);

useEffect(() => {
if (onSearchInputChanged) {
onSearchInputChanged(debouncedValue);
table.resetPagination();
}
}, [debouncedValue]);

// Might because potentially none fullfil the canExpand condtion.
const rowsMightExpand = renderDetailPanel ? true : false;
Expand Down Expand Up @@ -246,6 +263,18 @@ export function Table<DataType extends object>({
</Flex>
<Flex>
{renderToolbar && renderToolbar()}
{onSearchInputChanged && (
<UnControlledTextField
name="search-input"
value={searchInput}
placeholder={searchInputPlaceholder}
id={id + '-search-input'}
hasDescription={false}
hasError={false}
icon={<SearchIcon />}
onChange={(e) => setSearchInput(e.currentTarget.value)}
/>
)}
{!isLoading && <Filter table={table} />}
<ColumnVisibility
table={table}
Expand Down
8 changes: 7 additions & 1 deletion packages/web-main/src/routes/_auth/_global/players.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ function Component() {
useDocumentTitle('Players');

const { pagination, columnFilters, sorting, columnSearch } = useTableActions<PlayerOutputDTO>({ pageSize: 25 });
const [quickSearchInput, setQuickSearchInput] = useState<string>('');
const { data, isLoading } = useQuery(
playersQueryOptions({
page: pagination.paginationState.pageIndex,
Expand All @@ -73,7 +74,10 @@ function Component() {
xboxLiveId: columnFilters.columnFiltersState.find((filter) => filter.id === 'xboxLiveId')?.value,
},
search: {
name: columnSearch.columnSearchState.find((search) => search.id === 'name')?.value,
name: [
...(columnSearch.columnSearchState.find((search) => search.id === 'name')?.value ?? []),
quickSearchInput,
],
steamId: columnSearch.columnSearchState.find((search) => search.id === 'steamId')?.value,
epicOnlineServicesId: columnSearch.columnSearchState.find((search) => search.id === 'epicOnlineServicesId')
?.value,
Expand Down Expand Up @@ -271,6 +275,8 @@ function Component() {
columnSearch={columnSearch}
sorting={sorting}
isLoading={isLoading}
onSearchInputChanged={setQuickSearchInput}
searchInputPlaceholder="Search player by name..."
/>
</Fragment>
);
Expand Down
12 changes: 9 additions & 3 deletions packages/web-main/src/routes/_auth/_global/users.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import { useUserRemove, useInviteUser, usersQueryOptions, userMeQueryOptions } f
import { UserOutputWithRolesDTO, UserSearchInputDTOSortDirectionEnum, PERMISSIONS } from '@takaro/apiclient';
import { createColumnHelper } from '@tanstack/react-table';
import {
AiOutlinePlus as PlusIcon,
AiOutlineSolution as InviteUserIcon,
AiOutlineDelete as DeleteIcon,
AiOutlineUser as ProfileIcon,
AiOutlineEdit as EditIcon,
Expand All @@ -45,6 +45,7 @@ export const Route = createFileRoute('/_auth/_global/users')({
function Component() {
useDocumentTitle('Users');
const { pagination, columnFilters, sorting, columnSearch } = useTableActions<UserOutputWithRolesDTO>();
const [quickSearchInput, setQuickSearchInput] = useState<string>('');

const { data, isLoading } = useQuery({
...usersQueryOptions({
Expand All @@ -60,7 +61,10 @@ function Component() {
playerId: columnFilters.columnFiltersState.find((filter) => filter.id === 'playerId')?.value,
},
search: {
name: columnSearch.columnSearchState.find((search) => search.id === 'name')?.value,
name: [
...(columnSearch.columnSearchState.find((search) => search.id === 'name')?.value ?? []),
quickSearchInput,
],
discordId: columnSearch.columnSearchState.find((search) => search.id === 'discordId')?.value,
playerId: columnSearch.columnSearchState.find((search) => search.id === 'playerId')?.value,
},
Expand Down Expand Up @@ -152,6 +156,8 @@ function Component() {
columnFiltering={columnFilters}
columnSearch={columnSearch}
sorting={sorting}
onSearchInputChanged={setQuickSearchInput}
searchInputPlaceholder="Search by user name..."
/>
);
}
Expand Down Expand Up @@ -193,7 +199,7 @@ const InviteUser: FC = () => {
<Button
onClick={() => setOpen(true)}
text="Invite user"
icon={<PlusIcon />}
icon={<InviteUserIcon />}
disabled={!hasManageUsersPermission}
/>
<Dialog open={open} onOpenChange={setOpen}>
Expand Down
5 changes: 4 additions & 1 deletion packages/web-main/src/routes/_auth/_global/variables.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ function Component() {
const { pagination, columnFilters, sorting, columnSearch, rowSelection } = useTableActions<VariableOutputDTO>();
const navigate = useNavigate();
const [openVariablesDialog, setOpenVariablesDialog] = useState<boolean>(false);
const [quickSearchInput, setQuickSearchInput] = useState<string>('');

const { data, isLoading } = useQuery({
...variablesQueryOptions({
Expand All @@ -62,7 +63,7 @@ function Component() {
moduleId: columnFilters.columnFiltersState.find((filter) => filter.id === 'moduleId')?.value,
},
search: {
key: columnSearch.columnSearchState.find((search) => search.id === 'key')?.value,
key: [...(columnSearch.columnSearchState.find((search) => search.id === 'key')?.value ?? []), quickSearchInput],
gameServerId: columnSearch.columnSearchState.find((search) => search.id === 'gameServerId')?.value,
playerId: columnSearch.columnSearchState.find((search) => search.id === 'playerId')?.value,
moduleId: columnSearch.columnSearchState.find((search) => search.id === 'moduleId')?.value,
Expand Down Expand Up @@ -191,6 +192,8 @@ function Component() {
<Divider size="large" />
<Table
title="List of variables"
searchInputPlaceholder="Search by variable key..."
onSearchInputChanged={setQuickSearchInput}
renderToolbar={() => {
return (
<Button
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import {
useTableActions,
} from '@takaro/lib-components';
import { useQuery } from '@tanstack/react-query';
import { FC } from 'react';
import { FC, useState } from 'react';
import { createColumnHelper, Row } from '@tanstack/react-table';
import { shopListingsQueryOptions } from 'queries/shopListing';
import { useHasPermission } from 'hooks/useHasPermission';
Expand Down Expand Up @@ -46,6 +46,7 @@ const ShopListingBuyFormContainer = styled.div`

export const ShopTableView: FC<ShopViewProps> = ({ gameServerId, currencyName, gameServerType, currency }) => {
const hasPermission = useHasPermission(['MANAGE_SHOP_LISTINGS']);
const [quickSearchInput, setQuickSearchInput] = useState<string>('');

const { pagination, columnFilters, sorting, columnSearch } = useTableActions<ShopListingOutputDTO>({ pageSize: 25 });
const { data, isLoading } = useQuery(
Expand All @@ -61,7 +62,12 @@ export const ShopTableView: FC<ShopViewProps> = ({ gameServerId, currencyName, g
name: columnFilters.columnFiltersState.find((filter) => filter.id === 'name')?.value,
gameServerId: [gameServerId],
},
search: {},
search: {
name: [
...(columnFilters.columnFiltersState.find((filter) => filter.id === 'name')?.value ?? []),
quickSearchInput,
],
},
}),
);

Expand All @@ -83,6 +89,10 @@ export const ShopTableView: FC<ShopViewProps> = ({ gameServerId, currencyName, g
header: 'Status',
id: 'draft',
cell: (info) => (info.getValue() ? <Chip color="primary" label="Draft" /> : 'Available'),
enableColumnFilter: false,
meta: {
dataType: 'boolean',
},
}),
columnHelper.accessor('items', {
header: 'Amount of items',
Expand All @@ -97,6 +107,9 @@ export const ShopTableView: FC<ShopViewProps> = ({ gameServerId, currencyName, g
{info.getValue()} {currencyName}
</strong>
),
meta: {
dataType: 'number',
},
}),

columnHelper.accessor('createdAt', {
Expand Down Expand Up @@ -197,6 +210,8 @@ export const ShopTableView: FC<ShopViewProps> = ({ gameServerId, currencyName, g
title="Shop"
id="shop-table"
columns={columnDefs}
searchInputPlaceholder="Search shop listing by name"
onSearchInputChanged={setQuickSearchInput}
data={data?.data as ShopListingOutputDTO[]}
pagination={p}
columnFiltering={columnFilters}
Expand Down

0 comments on commit 6667dad

Please sign in to comment.