index.tsx 2.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. import {Component, ReactElement} from 'react';
  2. import {browserHistory} from 'react-router';
  3. import styled from '@emotion/styled';
  4. import {Query} from 'history';
  5. import PropTypes from 'prop-types';
  6. import Button from 'app/components/button';
  7. import ButtonBar from 'app/components/buttonBar';
  8. import {IconChevron} from 'app/icons';
  9. import {t} from 'app/locale';
  10. import space from 'app/styles/space';
  11. import {callIfFunction} from 'app/utils/callIfFunction';
  12. import parseLinkHeader from 'app/utils/parseLinkHeader';
  13. const defaultProps: DefaultProps = {
  14. size: 'small',
  15. disabled: false,
  16. onCursor: (cursor: string, path: string, query: Query, _direction: number) => {
  17. browserHistory.push({
  18. pathname: path,
  19. query: {...query, cursor},
  20. });
  21. },
  22. };
  23. type DefaultProps = {
  24. size?: 'zero' | 'xsmall' | 'small';
  25. onCursor?: (cursor: string, path: string, query: Query, _direction: number) => void;
  26. disabled?: boolean;
  27. };
  28. type Props = DefaultProps & {
  29. pageLinks?: string | null;
  30. to?: string;
  31. /**
  32. * The caption must be the PaginationCaption component
  33. */
  34. caption?: ReactElement;
  35. className?: string;
  36. };
  37. class Pagination extends Component<Props> {
  38. static contextTypes = {
  39. location: PropTypes.object,
  40. };
  41. static defaultProps = defaultProps;
  42. render() {
  43. const {className, onCursor, pageLinks, size, caption, disabled} = this.props;
  44. if (!pageLinks) {
  45. return null;
  46. }
  47. const location = this.context.location;
  48. const path = this.props.to || location.pathname;
  49. const query = location.query;
  50. const links = parseLinkHeader(pageLinks);
  51. const previousDisabled = disabled || links.previous.results === false;
  52. const nextDisabled = disabled || links.next.results === false;
  53. return (
  54. <Wrapper className={className}>
  55. {caption}
  56. <ButtonBar merged>
  57. <Button
  58. icon={<IconChevron direction="left" size="sm" />}
  59. aria-label={t('Previous')}
  60. size={size}
  61. disabled={previousDisabled}
  62. onClick={() => {
  63. callIfFunction(onCursor, links.previous.cursor, path, query, -1);
  64. }}
  65. />
  66. <Button
  67. icon={<IconChevron direction="right" size="sm" />}
  68. aria-label={t('Next')}
  69. size={size}
  70. disabled={nextDisabled}
  71. onClick={() => {
  72. callIfFunction(onCursor, links.next.cursor, path, query, 1);
  73. }}
  74. />
  75. </ButtonBar>
  76. </Wrapper>
  77. );
  78. }
  79. }
  80. const Wrapper = styled('div')`
  81. display: flex;
  82. align-items: center;
  83. justify-content: flex-end;
  84. margin: ${space(3)} 0 0 0;
  85. `;
  86. export default Pagination;