TBody.tsx 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. import React, { FC } from 'react';
  2. import { connect } from 'react-redux';
  3. import styled, { css } from 'styled-components';
  4. import distanceInWordsToNow from 'date-fns/formatDistanceToNow';
  5. import { ifProp } from 'styled-tools';
  6. import { Flex } from 'reflexbox/styled-components';
  7. import TBodyShortUrl from './TBodyShortUrl';
  8. import TBodyCount from './TBodyCount';
  9. interface Props {
  10. urls: Array<{
  11. id: string;
  12. count: number;
  13. created_at: string;
  14. password: boolean;
  15. target: string;
  16. }>;
  17. copiedIndex: number;
  18. showModal: any; // TODO: types
  19. tableLoading: boolean;
  20. handleCopy: any;
  21. }
  22. const TBody = styled(Flex).attrs({
  23. as: 'tbody',
  24. flex: '1 1 auto',
  25. flexDirection: 'column',
  26. })<{ loading: boolean }>`
  27. ${ifProp(
  28. 'loading',
  29. css`
  30. opacity: 0.2;
  31. `
  32. )}
  33. tr:hover {
  34. background-color: #f8f8f8;
  35. td:after {
  36. background: linear-gradient(to left, #f8f8f8, #f8f8f8, transparent);
  37. }
  38. }
  39. `;
  40. const Td = styled(Flex).attrs({
  41. as: 'td',
  42. flexBasis: 0,
  43. })<{ flex?: string; withFade?: boolean; date?: boolean }>`
  44. white-space: nowrap;
  45. overflow: hidden;
  46. ${ifProp(
  47. 'withFade',
  48. css`
  49. :after {
  50. content: '';
  51. position: absolute;
  52. right: 0;
  53. top: 0;
  54. height: 100%;
  55. width: 56px;
  56. background: linear-gradient(to left, white, white, transparent);
  57. `
  58. )}
  59. :last-child {
  60. justify-content: space-between;
  61. }
  62. a {
  63. color: #2196f3;
  64. text-decoration: none;
  65. box-sizing: border-box;
  66. border-bottom: 1px dotted transparent;
  67. transition: all 0.2s ease-out;
  68. :hover {
  69. border-bottom-color: #2196f3;
  70. }
  71. }
  72. ${ifProp(
  73. 'date',
  74. css`
  75. font-size: 15px;
  76. `
  77. )}
  78. @media only screen and (max-width: 768px) {
  79. flex: 1;
  80. :nth-child(2) {
  81. display: none;
  82. }
  83. }
  84. @media only screen and (max-width: 510px) {
  85. :nth-child(1) {
  86. display: none;
  87. }
  88. }
  89. `;
  90. const TableBody: FC<Props> = ({
  91. copiedIndex,
  92. handleCopy,
  93. tableLoading,
  94. showModal,
  95. urls,
  96. }) => {
  97. const showList = (url, index) => (
  98. <tr key={`tbody-${index}`}>
  99. <Td flex="2 2 0" withFade>
  100. <a href={url.target}>{url.target}</a>
  101. </Td>
  102. <Td flex="1 1 0" date>
  103. {`${distanceInWordsToNow(new Date(url.created_at))} ago`}
  104. </Td>
  105. <Td flex="1 1 0" withFade>
  106. <TBodyShortUrl
  107. index={index}
  108. copiedIndex={copiedIndex}
  109. handleCopy={handleCopy}
  110. url={url}
  111. />
  112. </Td>
  113. <Td flex="1 1 0">
  114. <TBodyCount url={url} showModal={showModal(url)} />
  115. </Td>
  116. </tr>
  117. );
  118. return (
  119. <TBody loading={tableLoading}>
  120. {urls.length ? (
  121. urls.map(showList)
  122. ) : (
  123. <tr>
  124. <Td>Nothing to show.</Td>
  125. </tr>
  126. )}
  127. </TBody>
  128. );
  129. };
  130. const mapStateToProps = ({ loading: { table: tableLoading } }) => ({
  131. tableLoading,
  132. });
  133. export default connect(mapStateToProps)(TableBody);