From 12ca6d8762901f95ee3f890a71abc90d45ff32c5 Mon Sep 17 00:00:00 2001 From: Hector Rodrigues da Silva Date: Tue, 29 Nov 2022 15:50:28 -0300 Subject: [PATCH] add: Theme in table, loader and custom messages --- public/App.tsx | 80 ++++++++++++++- public/index.html | 2 +- src/index.tsx | 244 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 323 insertions(+), 3 deletions(-) create mode 100644 src/index.tsx diff --git a/public/App.tsx b/public/App.tsx index 1c586d3..0450f1b 100644 --- a/public/App.tsx +++ b/public/App.tsx @@ -1,7 +1,83 @@ +import React, {useEffect, useState} from 'react'; +import {DuckTable} from '../src'; + +type Item = { + id: number, + description: string, + value: number, + store: string, + date: string +} + +type Results = { + start: number, + end: number, + total: number +} export const App = (): JSX.Element => { + + const [data, setData] = useState([]); + const [loading, setLoading] = useState(true); + + const actions = () => { + return Custom; + }; + + const columns = [{ + header: 'ID', + value: 'id', + hide: true + }, { + header: 'Description', + value: 'description', + }, { + header: 'Value', + value: 'value', + }, { + header: 'Store', + value: 'store', + }, { + header: 'Date', + value: 'date', + }, { + header: 'Actions', + value: '', + formatter: actions, + style: { width: 200 }, + }]; + + useEffect(() => { + let item: Item = { + id: 0, + value: 0, + store: 'Apple', + date: '12/11/2002', + description: 'Iphone' + }; + let arr: Item[] = [] + const rows: number = 10000; + for(let i = 1; i <= rows; i++) { + arr.push({ ...item, id: i, value: i }); + if(i === rows) setLoading(false); + } + setData(arr); + },[]); + return ( -
Hello
- ) + My message.} + showResultsMessage={({ start, end, total }: Results) => ( + My results + )} + /> + ); } diff --git a/public/index.html b/public/index.html index 40d8124..c27537d 100644 --- a/public/index.html +++ b/public/index.html @@ -6,7 +6,7 @@ content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"> - React Block Duck + React Table diff --git a/src/index.tsx b/src/index.tsx new file mode 100644 index 0000000..94755a9 --- /dev/null +++ b/src/index.tsx @@ -0,0 +1,244 @@ +import 'bootstrap/dist/css/bootstrap.min.css'; +import React, {Fragment, memo, useCallback, useEffect, useState} from 'react'; + +type Results = { + start: number, + end: number, + total: number +} + +interface Props { + data: object[], + maxRows?: number, + loading?: boolean, + columns: object[], + themeTable?: string, + themeLoader?: string, + maxPagination?: number, + emptyDataMessage?: () => JSX.Element | string, + showResultsMessage?: (object: Results) => JSX.Element | string +} + +interface Column { + value: string, + header: string, + hide?: boolean, + style?: object, + formatter?: (cell: any, item: object, index: number) => JSX.Element +} + +export const DuckTable = memo((props: Props): JSX.Element => { + + const { + data = [], + columns = [], + maxRows = 10, + loading = false, + emptyDataMessage, + showResultsMessage, + maxPagination = 10, + themeLoader = 'dark', + themeTable = 'default' + } = props; + + const [rows, setRows] = useState([]); + + const [initialPagination, setInitialPagination] = useState(0); + const [endPagination, setEndPagination] = useState(maxPagination); + + const [countPagination, setCountPagination] = useState(0); + const [currentPagination, setCurrentPagination] = useState(1); + + const renderPagination: number[] = Array.from(Array(countPagination).keys()).slice(initialPagination, endPagination); + + const isDecimal = (n: number) => { + return n % 1 === 0; + }; + + const renderEmptyMessage = (): JSX.Element | string => { + if(typeof emptyDataMessage === 'function') { + return emptyDataMessage(); + } + return !emptyDataMessage ? 'Results not found.' : emptyDataMessage; + }; + + const renderResultsMessage = (): JSX.Element | string => { + const results: Results = { start: startTable, end: endTable, total: data.length }; + if(typeof showResultsMessage === 'function') { + return showResultsMessage(results); + } + return ( + + {!showResultsMessage + ? `Showing from ${results.start} to ${results.end} of ${results.total} results` + : showResultsMessage // string custom + } + + ); + }; + + const renderCell = useCallback((index: number, value: any) => { + if(index < 1) { + return {value} + } else { + return {value} + } + },[]); + + const fullPrevious = () => { + setCurrentPagination(1); + setInitialPagination(0); + setEndPagination(maxPagination); + } + + const fullNext = () => { + setCurrentPagination(countPagination); + setInitialPagination(countPagination - (maxPagination - 1)); + setEndPagination(countPagination); + } + + const previous = () => { + if(currentPagination > 1) { + setPagination(currentPagination - 1); + } + } + + const next = () => { + if(currentPagination !== countPagination) { + setPagination(currentPagination + 1); + } + } + + const setPagination = (pagination: number): void => { + setCurrentPagination(pagination); + const index: number = pagination - 1; + if(index < renderPagination[0]) { + setInitialPagination(index - (maxPagination - 1)); + return setEndPagination(index + 1); + } + if(index > renderPagination.pop()) { + setInitialPagination(index); + return setEndPagination(index + maxPagination); + } + }; + + useEffect(() => { + if(data.length) { + const length: number = data.length; + const pagination: number = length / maxRows; + if(isDecimal(pagination)) { + setCountPagination(pagination); + } else { + const count: number = parseInt(String(pagination)) + 1; + setCountPagination(count); + } + if(pagination < countPagination) { + previous(); + } + } + },[data]); + + useEffect(() => { + if(data.length) { + let dataRows: object[] | undefined; + let arr: object[] = data.slice(); + if(currentPagination > 1) { + const min = (maxRows * currentPagination) - maxRows; + const max = min + maxRows; + dataRows = arr.slice(min, max); + } else { + dataRows = arr.slice(0, maxRows); + } + setRows(dataRows); + } + },[currentPagination, data]); + + const startTable: number = (maxRows * currentPagination + 1) - maxRows; + const endTable: number = (currentPagination * maxRows) - (maxRows - rows.length); + return ( + + + + + {columns.map((column: Column, index) => { + if(!column.hide) { + return ; + } else { + return null; + } + })} + + + {(data.length && !loading) ? + + {rows.map((item: any, index: number) => + + {columns.map((column: Column, index) => { + if(!column.hide) { + const cell = item[column.value]; + if (column.formatter) { + const formatterCell = column.formatter(cell, item, index); + return renderCell(index, formatterCell); + } else { + return renderCell(index, cell); + } + } else { + return null; + } + })} + + )} + + : + + } +
{column.header}
+ {loading ? +
+
+ Loading... +
+
+ : + Boolean(!data.length) && +
+ {renderEmptyMessage()} +
+ } + {countPagination > 1 && + + } +
+ ); +});