Refactor types organization for table component

This commit is contained in:
Alexander Navarro 2023-11-11 11:24:51 -03:00
parent deb95b355f
commit c0683dafb3
12 changed files with 1490 additions and 1195 deletions

View file

@ -20,17 +20,17 @@
"react-dom": "^18.0.0"
},
"devDependencies": {
"@typescript-eslint/eslint-plugin": "^5.50.0",
"eslint": "^8.0.1",
"eslint-config-prettier": "^8.8.0",
"@typescript-eslint/eslint-plugin": "^5.62.0",
"eslint": "^8.53.0",
"eslint-config-prettier": "^8.10.0",
"eslint-config-standard-with-typescript": "^35.0.0",
"eslint-plugin-import": "^2.25.2",
"eslint-plugin-n": "^15.0.0",
"eslint-plugin-promise": "^6.0.0",
"eslint-plugin-react": "^7.32.2",
"eslint-plugin-import": "^2.29.0",
"eslint-plugin-n": "^15.7.0",
"eslint-plugin-promise": "^6.1.1",
"eslint-plugin-react": "^7.33.2",
"gh-pages": "^5.0.0",
"prettier": "^2.8.8",
"prettier-plugin-astro": "^0.10.0",
"typescript": "*"
"typescript": "^5.2.2"
}
}

2529
pnpm-lock.yaml generated

File diff suppressed because it is too large Load diff

View file

@ -1,15 +1,14 @@
import React, {
useState,
type ChangeEventHandler,
useRef,
useEffect,
} from 'react';
import React, { useState, useRef, useEffect } from 'react';
import styles from './SelectInput.module.css';
interface Option {
label: string;
value: any;
}
interface Props {
onChange: (value: string | string[] | null) => void;
options: [{ label: string; value: any }];
keyData: string;
options: Option[];
isMultiple?: boolean;
value?: string | string[];
}

View file

View file

@ -1,7 +1,7 @@
import React, { useState, type ChangeEventHandler, useEffect } from 'react';
import React, { useState, useEffect } from 'react';
interface Props {
onChange: (value: string | string[] | number | number[] | null) => void;
onChange: (value: [string, number | null]) => void;
keyData: string;
}

View file

@ -1,9 +1,9 @@
import React, { useMemo, type ChangeEventHandler } from 'react';
import type { DataItem } from '.';
import React, { useMemo } from 'react';
import type { DataItem, Value } from '../types';
import SelectInput from '@components/Inputs/SelectInput';
interface Props {
onChange: (value: string | string[] | null) => void;
onChange: (value: Value) => void;
data: DataItem[];
keyData: string;
isMultiple?: boolean;
@ -31,28 +31,6 @@ export default function SelectFilter({
return options;
}, [data, keyData]);
const onSelectChange: ChangeEventHandler<HTMLSelectElement> = ({
target,
}): void => {
if (!isMultiple) {
const value = target.value !== '' ? target.value : null;
onChange(value);
return;
}
const values = [];
// FIXME: This looks awfull, when updating the input use something better.
for (let index = 0; index < target.options.length; index++) {
const option = target.options[index];
if (!option.selected || option.value === '') continue;
values.push(option.value);
}
onChange(values);
};
return (
<SelectInput
options={options}

View file

@ -1,19 +1,18 @@
import { HeaderType } from '../Table.tsx';
import { HeaderType, type Filter, type Value } from '../types.ts';
export { default as SelectFilter } from './SelectFilter.tsx';
export { default as NumberInput } from './NumberInput.tsx';
export type DataItem = Record<string, any>;
export interface Filter {
type: HeaderType;
value: string | string[] | number | number[];
}
const filterString = (value: Filter['value'], data: any): boolean => {
const filterString = (value: Value, data: any): boolean => {
return data.search(value) !== -1;
};
const filterNumber = (value: Filter['value'], data: any): boolean => {
const filterNumber = (value: Value, data: any): boolean => {
if (!Array.isArray(value)) {
return true;
}
const [operator, numberValue] = value;
if (numberValue === null) return true;
@ -34,14 +33,19 @@ const filterNumber = (value: Filter['value'], data: any): boolean => {
return data === numberValue;
}
};
const filterSelect = (value: Filter['value'], data: any): boolean => {
const filterSelect = (value: Value, data: any): boolean => {
return data === value;
};
const filterMultiple = (value: Filter['value'], data: any): boolean => {
if (typeof value === 'string') {
const filterMultiple = (value: Value, data: any): boolean => {
if (value === null) {
return true;
}
if (typeof value === 'string' || typeof value === 'number') {
return data.includes(value);
}
return value.every((filter: string) => data.includes(filter));
return value.every((filter: string | number) => data.includes(filter));
};
export const resolveFilterByType = (filter: Filter, data: any): boolean => {

View file

@ -6,34 +6,17 @@ import {
resolveFilterByType,
type Filter,
} from './Filters';
export type DataItem = Record<string, any>;
export enum HeaderType {
Index,
String,
Number,
Select,
Multiple,
}
export interface Header {
key: string;
header: string;
formatter?: (data: DataItem) => string;
type: HeaderType;
}
import type { DataItem, Header, Value } from './types';
import { HeaderType } from './types';
interface Props {
data: DataItem[];
headers: Header[];
}
type Value = string | string[] | number | number[] | null;
export default function Table({ data, headers }: Props): JSX.Element {
const [filters, setFilters] = useState<Record<string, Filter>>({});
const filtersKey = useRef(crypto.randomUUID());
const filtersId = useRef(crypto.randomUUID());
const filteredItems = useMemo(() => {
return data.filter((item) => {
@ -51,9 +34,8 @@ export default function Table({ data, headers }: Props): JSX.Element {
const handleUpdateFilters = (
name: string,
type: HeaderType,
value: any,
value: Value,
): void => {
console.log(value);
setFilters((prev) => {
if (value === null) {
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
@ -91,7 +73,7 @@ export default function Table({ data, headers }: Props): JSX.Element {
function formatFilter(header: Header): JSX.Element {
const baseProps = {
key: header.key + filtersKey.current,
key: header.key + filtersId.current,
keyData: header.key,
value: filters[header.key]?.value,
onChange: (value: Value) => {
@ -129,9 +111,8 @@ export default function Table({ data, headers }: Props): JSX.Element {
<button
className="ml-auto"
onClick={() => {
// FIXME: this clear the filters but not the value of the inputs
setFilters({});
filtersKey.current = crypto.randomUUID();
filtersId.current = crypto.randomUUID();
}}
>
Clear Filters

View file

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

View file

@ -0,0 +1,23 @@
export type DataItem = Record<string, any>;
export type Value = string | string[] | number | number[] | null;
export enum HeaderType {
Index,
String,
Number,
Select,
Multiple,
}
export interface Header {
key: string;
header: string;
formatter?: (data: DataItem) => string;
type: HeaderType;
}
export interface Filter {
type: HeaderType;
value: Value;
}

View file

@ -5,7 +5,7 @@ interface Page {
current: boolean;
}
export interface IUsePagination<T> {
interface IUsePagination<T> {
items: T[];
changeOffset: (offset: Offset, newValue?: number) => void;
/**

View file

@ -1,7 +1,8 @@
---
import { getCollection } from 'astro:content';
import Layout from '@layouts/Layout.astro';
import Table, { HeaderType, type Header } from '@components/Table';
import Table from '@components/Table';
import { HeaderType, type Header } from '@components/Table/types';
const rawGames = await getCollection('games');