TableOptions.tsx 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. import React, { FC, useState } from "react";
  2. import { bindActionCreators } from "redux";
  3. import { connect } from "react-redux";
  4. import styled, { css } from "styled-components";
  5. import { ifProp } from "styled-tools";
  6. import { Flex } from "reflexbox/styled-components";
  7. import TableNav from "./TableNav";
  8. import TextInput from "./TextInput";
  9. import { getUrlsList } from "../actions";
  10. interface Props {
  11. getUrlsList: any; // TODO: types
  12. nosearch?: boolean;
  13. url: {
  14. page: number;
  15. count: number;
  16. countAll: number;
  17. };
  18. }
  19. const Tr = styled(Flex).attrs({ as: "tr", alignItems: "center" })`
  20. thead & {
  21. border-bottom: 1px solid #ddd !important;
  22. }
  23. `;
  24. const Th = styled(Flex).attrs({ as: "th", alignItems: "center" })``;
  25. const Divider = styled.div`
  26. margin: 0 16px 0 24px;
  27. width: 1px;
  28. height: 20px;
  29. background-color: #ccc;
  30. @media only screen and (max-width: 768px) {
  31. margin: 0 4px 0 12px;
  32. }
  33. @media only screen and (max-width: 510px) {
  34. display: none;
  35. }
  36. `;
  37. const Ul = styled(Flex).attrs({ as: "ul" })`
  38. margin: 0;
  39. padding: 0;
  40. list-style: none;
  41. @media only screen and (max-width: 510px) {
  42. display: none;
  43. }
  44. `;
  45. const Li = styled(Flex).attrs({ as: "li" })`
  46. li {
  47. margin: 0 0 0 12px;
  48. list-style: none;
  49. @media only screen and (max-width: 768px) {
  50. margin-left: 8px;
  51. }
  52. }
  53. `;
  54. const Button = styled.button<{ active: boolean }>`
  55. display: flex;
  56. padding: 4px 8px;
  57. border: none;
  58. font-size: 12px;
  59. border-radius: 4px;
  60. box-shadow: 0 0px 10px rgba(100, 100, 100, 0.1);
  61. background-color: white;
  62. cursor: pointer;
  63. transition: all 0.2s ease-out;
  64. box-sizing: border-box;
  65. ${ifProp(
  66. { active: false },
  67. css`
  68. border: 1px solid #ddd;
  69. background-color: #f5f5f5;
  70. box-shadow: 0 0px 5px rgba(150, 150, 150, 0.1);
  71. :hover {
  72. border-color: 1px solid #ccc;
  73. background-color: white;
  74. }
  75. `
  76. )}
  77. @media only screen and (max-width: 768px) {
  78. font-size: 10px;
  79. }
  80. `;
  81. const TableOptions: FC<Props> = ({ getUrlsList, nosearch, url }) => {
  82. const [search, setSearch] = useState();
  83. const [count, setCount] = useState();
  84. function submitSearch(e) {
  85. e.preventDefault();
  86. getUrlsList({ search });
  87. }
  88. const handleCount = e => setCount(Number(e.target.textContent));
  89. function handleNav(num) {
  90. return e => {
  91. const { active } = e.target.dataset;
  92. if (active === "false") return null;
  93. return getUrlsList({ page: url.page + num });
  94. };
  95. }
  96. return (
  97. <Tr>
  98. <Th>
  99. {!nosearch && (
  100. <form onSubmit={submitSearch}>
  101. <TextInput
  102. as="input"
  103. id="search"
  104. name="search"
  105. value={search}
  106. placeholder="Search..."
  107. onChange={e => setSearch(e.target.value)}
  108. tiny
  109. />
  110. </form>
  111. )}
  112. </Th>
  113. <Th>
  114. <Flex alignItems="center">
  115. <Ul>
  116. {[10, 25, 50].map(c => (
  117. <Li key={c}>
  118. <Button active={count === c} onClick={handleCount}>
  119. {c}
  120. </Button>
  121. </Li>
  122. ))}
  123. </Ul>
  124. </Flex>
  125. <Divider />
  126. <TableNav
  127. handleNav={handleNav}
  128. next={url.page * count < url.countAll}
  129. prev={url.page > 1}
  130. />
  131. </Th>
  132. </Tr>
  133. );
  134. };
  135. TableOptions.defaultProps = {
  136. nosearch: false
  137. };
  138. const mapStateToProps = ({ url }) => ({ url });
  139. const mapDispatchToProps = dispatch => ({
  140. getUrlsList: bindActionCreators(getUrlsList, dispatch)
  141. });
  142. export default connect(
  143. mapStateToProps,
  144. mapDispatchToProps
  145. )(TableOptions);