add select type to table

This commit is contained in:
Alexander Navarro 2023-09-24 11:58:29 -03:00
parent 71cf3d656e
commit 739ee87879
4 changed files with 104 additions and 12 deletions

View file

@ -0,0 +1,47 @@
import React, { useMemo, type ChangeEventHandler } from 'react';
export type DataItem = Record<string, any>;
interface Props {
onChange: (value: string | null) => void;
data: DataItem[];
keyData: string;
}
export default function Select({
data,
keyData,
onChange,
}: Props): JSX.Element {
const options = useMemo(() => {
let options = data.map((item) => item[keyData]);
options = [...new Set(options)];
options = options.map((item, idx) => (
<option key={idx} value={item}>
{item}
</option>
));
options.unshift(
<option key={-1} value="">
Select...
</option>,
);
return options;
}, [data, keyData]);
return (
<select
name="fooe"
id="foo"
onChange={({ target }) =>
{ onChange(target.value !== '' ? target.value : null); }
}
>
{options}
</select>
);
}

View file

@ -1,5 +1,6 @@
import React, { useMemo, useState } from 'react'; import React, { useMemo, useState } from 'react';
import usePagination, { Offset } from 'src/hooks/usePagination'; import usePagination, { Offset } from 'src/hooks/usePagination';
import Select from './Inputs/Select';
export type DataItem = Record<string, any>; export type DataItem = Record<string, any>;
@ -7,6 +8,8 @@ export enum HeaderType {
Index, Index,
String, String,
Number, Number,
Select,
Multiple,
} }
export interface Header { export interface Header {
@ -22,11 +25,10 @@ interface Props {
} }
interface Filter { interface Filter {
type: HeaderType, type: HeaderType;
value: string, value: string;
} }
export default function Table({ data, headers }: Props): JSX.Element { export default function Table({ data, headers }: Props): JSX.Element {
const [filters, setFilters] = useState<Record<string, Filter>>({}); const [filters, setFilters] = useState<Record<string, Filter>>({});
@ -36,15 +38,17 @@ export default function Table({ data, headers }: Props): JSX.Element {
return data.search(filter.value) !== -1; return data.search(filter.value) !== -1;
case HeaderType.Number: case HeaderType.Number:
return data === filter.value; return data === filter.value;
case HeaderType.Select:
return data === filter.value;
} }
return true; return true;
} };
const filteredItems = useMemo(() => { const filteredItems = useMemo(() => {
return data.filter((item) => { return data.filter((item) => {
return Object.entries(filters).every( return Object.entries(filters).every(([key, filter]) =>
([key, filter]) => resolveFilterByType(filter, item[key]), resolveFilterByType(filter, item[key]),
); );
}); });
}, [data, filters]); }, [data, filters]);
@ -53,7 +57,11 @@ export default function Table({ data, headers }: Props): JSX.Element {
items: filteredItems, items: filteredItems,
}); });
const handleUpdateFilters = (name: string, type: HeaderType, value: any): void => { const handleUpdateFilters = (
name: string,
type: HeaderType,
value: any,
): void => {
setFilters((prev) => { setFilters((prev) => {
if (value === null) { if (value === null) {
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete // eslint-disable-next-line @typescript-eslint/no-dynamic-delete
@ -63,7 +71,6 @@ export default function Table({ data, headers }: Props): JSX.Element {
return { ...prev, [name]: { value, type } }; return { ...prev, [name]: { value, type } };
}); });
}; };
function formatCell(data: DataItem, header: Header): JSX.Element { function formatCell(data: DataItem, header: Header): JSX.Element {
@ -77,6 +84,16 @@ export default function Table({ data, headers }: Props): JSX.Element {
); );
} }
if (header.type === HeaderType.Multiple) {
return (
<ul className="text-start">
{data[header.key].map((item: JSX.Element, idx: number) => (
<li key={idx}>{item}</li>
))}
</ul>
);
}
return data[header.key]; return data[header.key];
} }
@ -86,7 +103,11 @@ export default function Table({ data, headers }: Props): JSX.Element {
return ( return (
<input <input
onChange={(e) => { onChange={(e) => {
handleUpdateFilters(header.key, header.type, e.target.value ?? null); handleUpdateFilters(
header.key,
header.type,
e.target.value ?? null,
);
}} }}
/> />
); );
@ -95,7 +116,21 @@ export default function Table({ data, headers }: Props): JSX.Element {
<input <input
type="number" type="number"
onChange={(e) => { onChange={(e) => {
handleUpdateFilters(header.key, header.type, e.target.value !== '' ? parseInt(e.target.value) : null); handleUpdateFilters(
header.key,
header.type,
e.target.value !== '' ? parseInt(e.target.value) : null,
);
}}
/>
);
case HeaderType.Select:
return (
<Select
data={data}
keyData={header.key}
onChange={(value) => {
handleUpdateFilters(header.key, header.type, value);
}} }}
/> />
); );

View file

@ -0,0 +1,5 @@
import Table, { HeaderType, type Header } from './Table';
export default Table;
export { HeaderType, type Header };

View file

@ -1,7 +1,7 @@
--- ---
import { getCollection } from 'astro:content'; import { getCollection } from 'astro:content';
import Layout from '@layouts/Layout.astro'; import Layout from '@layouts/Layout.astro';
import Table, { HeaderType, type Header } from '@components/Table.jsx'; import Table, { HeaderType, type Header } from '@components/Table';
const rawGames = await getCollection('games'); const rawGames = await getCollection('games');
@ -26,7 +26,12 @@ const headers: Header[] = [
{ {
key: 'status', key: 'status',
header: 'Status', header: 'Status',
type: HeaderType.String, type: HeaderType.Select,
},
{
key: 'genres',
header: 'Genres',
type: HeaderType.Multiple,
}, },
{ {
key: 'times_played', key: 'times_played',