index.tsx 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. import React, { useEffect, useState, useRef } from 'react';
  2. import _ from 'lodash';
  3. import Icon from '../Icon';
  4. import Drawer from '../Drawer';
  5. import Thumbnail from '../Thumbnail';
  6. import { ScrollStateType } from '../../constants/type';
  7. import { watchScroll, scrollIntoView } from '../../helpers/utility';
  8. import { Container, Head, IconWrapper } from '../../global/sidebarStyled';
  9. import { ThumbnailsWrapper, Body } from './styled';
  10. type Props = {
  11. isActive?: boolean;
  12. close: () => void;
  13. currentPage: number;
  14. totalPage: number;
  15. getPdfImage: (page: number) => Promise<string>;
  16. };
  17. const Thumbnails: React.FC<Props> = ({
  18. isActive = false,
  19. close,
  20. currentPage,
  21. totalPage,
  22. getPdfImage,
  23. }: Props) => {
  24. const containerRef = useRef<HTMLDivElement>(null);
  25. const [scrollIndex, setScrollIndex] = useState(currentPage);
  26. const [elements, setElement] = useState<React.ReactNode[]>([]);
  27. const scrollUpdate = (state: ScrollStateType): void => {
  28. const height = 220;
  29. const index = Math.round((state.lastY + height) / height);
  30. setScrollIndex(index);
  31. };
  32. const createThumbnails = (): void => {
  33. const eleContent: React.ReactNode[] = [];
  34. for (let i = 1; i <= totalPage; i += 1) {
  35. const component = (
  36. <Thumbnail
  37. key={`thumbnail_${i}`}
  38. pageNum={i}
  39. getPdfImage={getPdfImage}
  40. renderingState={_.range(1, 6).includes(i) ? 'RENDERING' : 'LOADING'}
  41. />
  42. );
  43. eleContent.push(component);
  44. }
  45. setElement(eleContent);
  46. };
  47. const updateThumbnails = (): void => {
  48. const renderingIndexQueue = _.range(scrollIndex - 2, scrollIndex + 4);
  49. let index = scrollIndex - 6;
  50. const end = scrollIndex + 6;
  51. while (scrollIndex) {
  52. if (elements[index]) {
  53. const pageNum = index + 1;
  54. elements[index] = (
  55. <Thumbnail
  56. key={`thumbnail_${pageNum}`}
  57. pageNum={pageNum}
  58. getPdfImage={getPdfImage}
  59. renderingState={
  60. renderingIndexQueue.includes(pageNum) ? 'RENDERING' : 'LOADING'
  61. }
  62. />
  63. );
  64. }
  65. index += 1;
  66. if (index >= end) break;
  67. }
  68. if (elements.length) {
  69. setElement([...elements]);
  70. }
  71. };
  72. useEffect(() => {
  73. if (containerRef.current) {
  74. watchScroll(containerRef.current, scrollUpdate);
  75. }
  76. }, [containerRef]);
  77. useEffect(() => {
  78. if (isActive && !elements.length) {
  79. createThumbnails();
  80. }
  81. }, [isActive]);
  82. useEffect(() => {
  83. updateThumbnails();
  84. }, [scrollIndex]);
  85. useEffect(() => {
  86. if (isActive && elements.length) {
  87. const ele: HTMLElement = document.getElementById(
  88. `thumbnail_${currentPage}`
  89. ) as HTMLElement;
  90. scrollIntoView(ele);
  91. }
  92. }, [currentPage, isActive]);
  93. return (
  94. <Drawer anchor="right" open={isActive}>
  95. <Container>
  96. <Head>
  97. <IconWrapper>
  98. <Icon glyph="right-back" onClick={close} />
  99. </IconWrapper>
  100. </Head>
  101. <Body ref={containerRef}>
  102. <ThumbnailsWrapper>{elements}</ThumbnailsWrapper>
  103. </Body>
  104. </Container>
  105. </Drawer>
  106. );
  107. };
  108. export default Thumbnails;