Table.tsx 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. import React from "react";
  2. import styled from "styled-components";
  3. import { Column, Row, useGlobalFilter, useTable } from "react-table";
  4. import InputRow from "./values-form/InputRow";
  5. import Loading from "components/Loading";
  6. const GlobalFilter: React.FunctionComponent<any> = ({ setGlobalFilter }) => {
  7. const [value, setValue] = React.useState("");
  8. const onChange = (value: string) => {
  9. setValue(value);
  10. setGlobalFilter(value || undefined);
  11. };
  12. return (
  13. <SearchRow>
  14. <i className="material-icons">search</i>
  15. <SearchInput
  16. value={value}
  17. onChange={(e: any) => {
  18. onChange(e.target.value);
  19. }}
  20. placeholder="Search"
  21. />
  22. </SearchRow>
  23. );
  24. };
  25. export type TableProps = {
  26. columns: Column<any>[];
  27. data: any[];
  28. onRowClick?: (row: Row) => void;
  29. isLoading: boolean;
  30. disableGlobalFilter?: boolean;
  31. };
  32. const Table: React.FC<TableProps> = ({
  33. columns: columnsData,
  34. data,
  35. onRowClick,
  36. isLoading,
  37. disableGlobalFilter = false,
  38. }) => {
  39. const {
  40. getTableProps,
  41. getTableBodyProps,
  42. rows,
  43. setGlobalFilter,
  44. prepareRow,
  45. headerGroups,
  46. visibleColumns,
  47. } = useTable(
  48. {
  49. columns: columnsData,
  50. data,
  51. },
  52. useGlobalFilter
  53. );
  54. const renderRows = () => {
  55. if (isLoading) {
  56. return (
  57. <StyledTr disableHover={true} selected={false}>
  58. <StyledTd colSpan={visibleColumns.length}>
  59. <Loading />
  60. </StyledTd>
  61. </StyledTr>
  62. );
  63. }
  64. if (!rows.length) {
  65. return (
  66. <StyledTr disableHover={true} selected={false}>
  67. <StyledTd colSpan={visibleColumns.length}>No data available</StyledTd>
  68. </StyledTr>
  69. );
  70. }
  71. return (
  72. <>
  73. {rows.map((row) => {
  74. prepareRow(row);
  75. return (
  76. <StyledTr
  77. {...row.getRowProps()}
  78. enablePointer={!!onRowClick}
  79. onClick={() => onRowClick && onRowClick(row)}
  80. selected={false}
  81. >
  82. {row.cells.map((cell) => (
  83. <StyledTd {...cell.getCellProps()}>
  84. {cell.render("Cell")}
  85. </StyledTd>
  86. ))}
  87. </StyledTr>
  88. );
  89. })}
  90. </>
  91. );
  92. };
  93. return (
  94. <TableWrapper>
  95. {!disableGlobalFilter && (
  96. <GlobalFilter setGlobalFilter={setGlobalFilter} />
  97. )}
  98. <StyledTable {...getTableProps()}>
  99. <StyledTHead>
  100. {headerGroups.map((headerGroup) => (
  101. <StyledTr
  102. {...headerGroup.getHeaderGroupProps()}
  103. disableHover={true}
  104. >
  105. {headerGroup.headers.map((column) => (
  106. <StyledTh {...column.getHeaderProps()}>
  107. {column.render("Header")}
  108. </StyledTh>
  109. ))}
  110. </StyledTr>
  111. ))}
  112. </StyledTHead>
  113. <tbody {...getTableBodyProps()}>{renderRows()}</tbody>
  114. </StyledTable>
  115. </TableWrapper>
  116. );
  117. };
  118. export default Table;
  119. const TableWrapper = styled.div`
  120. padding-bottom: 20px;
  121. `;
  122. type StyledTrProps = {
  123. enablePointer?: boolean;
  124. disableHover?: boolean;
  125. selected?: boolean;
  126. };
  127. export const StyledTr = styled.tr`
  128. line-height: 2.2em;
  129. background: ${(props: StyledTrProps) => (props.selected ? "#ffffff11" : "")};
  130. :hover {
  131. background: ${(props: StyledTrProps) =>
  132. props.disableHover ? "" : "#ffffff22"};
  133. }
  134. cursor: ${(props: StyledTrProps) =>
  135. props.enablePointer ? "pointer" : "unset"};
  136. `;
  137. export const StyledTd = styled.td`
  138. font-size: 13px;
  139. color: #ffffff;
  140. :first-child {
  141. padding-left: 10px;
  142. }
  143. :last-child {
  144. padding-right: 10px;
  145. }
  146. user-select: text;
  147. `;
  148. export const StyledTHead = styled.thead`
  149. width: 100%;
  150. `;
  151. export const StyledTh = styled.th`
  152. text-align: left;
  153. font-size: 13px;
  154. font-weight: 500;
  155. color: #aaaabb;
  156. :first-child {
  157. padding-left: 10px;
  158. }
  159. :last-child {
  160. padding-right: 10px;
  161. }
  162. `;
  163. export const StyledTable = styled.table`
  164. width: 100%;
  165. min-width: 500px;
  166. border-collapse: collapse;
  167. `;
  168. const SearchInput = styled.input`
  169. outline: none;
  170. border: none;
  171. font-size: 13px;
  172. background: none;
  173. width: 100%;
  174. color: white;
  175. padding: 0;
  176. height: 20px;
  177. `;
  178. const SearchRow = styled.div`
  179. display: flex;
  180. width: 100%;
  181. font-size: 13px;
  182. color: #ffffff55;
  183. border-radius: 4px;
  184. user-select: none;
  185. align-items: center;
  186. padding: 10px 0px;
  187. min-width: 300px;
  188. max-width: min-content;
  189. background: #ffffff11;
  190. margin-bottom: 7px;
  191. margin-top: 7px;
  192. i {
  193. width: 18px;
  194. height: 18px;
  195. margin-left: 12px;
  196. margin-right: 12px;
  197. font-size: 20px;
  198. }
  199. `;