Table.tsx 4.7 KB

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