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 {
  9. Container, Head, Body, IconWrapper,
  10. } from '../../global/sidebarStyled';
  11. import { ThumbnailsWrapper } from './styled';
  12. type Props = {
  13. isActive?: boolean;
  14. close: () => void;
  15. currentPage: number;
  16. totalPage: number;
  17. getPdfImage: (page: number) => Promise<string>;
  18. };
  19. const Thumbnails: React.FC<Props> = ({
  20. isActive = false,
  21. close,
  22. currentPage,
  23. totalPage,
  24. getPdfImage,
  25. }: Props) => {
  26. const containerRef = useRef<HTMLDivElement>(null);
  27. const [scrollIndex, setScrollIndex] = useState(currentPage);
  28. const [elements, setElement] = useState<React.ReactNode[]>([]);
  29. const scrollUpdate = (state: ScrollStateType): void => {
  30. const height = 220;
  31. const index = Math.round((state.lastY + height) / height);
  32. setScrollIndex(index);
  33. };
  34. const createThumbnails = (): void => {
  35. const eleContent: React.ReactNode[] = [];
  36. for (let i = 1; i <= totalPage; i += 1) {
  37. const component = (
  38. <Thumbnail
  39. key={`thumbnail_${i}`}
  40. pageNum={i}
  41. getPdfImage={getPdfImage}
  42. renderingState={_.range(1, 6).includes(i) ? 'RENDERING' : 'LOADING'}
  43. />
  44. );
  45. eleContent.push(component);
  46. }
  47. setElement(eleContent);
  48. };
  49. const updateThumbnails = (): void => {
  50. const renderingIndexQueue = _.range(scrollIndex - 2, scrollIndex + 4);
  51. let index = scrollIndex - 5;
  52. const end = scrollIndex + 5;
  53. while (scrollIndex) {
  54. if (elements[index]) {
  55. const pageNum = index + 1;
  56. elements[index] = (
  57. <Thumbnail
  58. key={`thumbnail_${pageNum}`}
  59. pageNum={pageNum}
  60. getPdfImage={getPdfImage}
  61. renderingState={renderingIndexQueue.includes(pageNum) ? 'RENDERING' : 'LOADING'}
  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(`thumbnail_${currentPage}`) as HTMLElement;
  88. scrollIntoView(ele);
  89. }
  90. }, [currentPage, isActive]);
  91. return (
  92. <Drawer anchor="right" open={isActive}>
  93. <Container>
  94. <Head>
  95. <IconWrapper>
  96. <Icon glyph="right-back" onClick={close} />
  97. </IconWrapper>
  98. </Head>
  99. <Body ref={containerRef}>
  100. <ThumbnailsWrapper>
  101. {elements}
  102. </ThumbnailsWrapper>
  103. </Body>
  104. </Container>
  105. </Drawer>
  106. );
  107. };
  108. export default Thumbnails;