index.tsx 2.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. import React, { useEffect, useState, useRef, useCallback } from 'react';
  2. import { useTranslation } from 'react-i18next';
  3. import Typography from '../Typography';
  4. import Item from '../AnnotationItem';
  5. import { watchScroll } from '../../helpers/utility';
  6. import { Body } from '../../global/sidebarStyled';
  7. type Props = {
  8. isActive?: boolean;
  9. annotations: AnnotationType[];
  10. };
  11. const AnnotationList: React.FC<Props> = ({
  12. isActive = false,
  13. annotations,
  14. }: Props) => {
  15. let observer: any = null;
  16. const { t } = useTranslation('sidebar');
  17. const [renderQueue, setQueue] = useState<AnnotationType[]>([]);
  18. const containerRef = useRef<HTMLDivElement>(null);
  19. const innerRef = useRef<HTMLDivElement>(null);
  20. const scrollUpdate = useCallback(
  21. (state: ScrollStateType): void => {
  22. const innerHeight = innerRef.current?.offsetHeight || 0;
  23. const wrapperHeight = containerRef.current?.offsetHeight || 0;
  24. if (
  25. wrapperHeight + state.lastY >= innerHeight &&
  26. renderQueue.length !== annotations.length
  27. ) {
  28. const start = renderQueue.length;
  29. const end = renderQueue.length + 15;
  30. const newQueue = [...renderQueue, ...annotations.slice(start, end)];
  31. setQueue(newQueue);
  32. }
  33. },
  34. [renderQueue, annotations]
  35. );
  36. useEffect(() => {
  37. observer = watchScroll(containerRef.current, scrollUpdate);
  38. return (): void => {
  39. if (observer) {
  40. observer.subscriber.unsubscribe();
  41. }
  42. };
  43. }, [containerRef, scrollUpdate]);
  44. useEffect(() => {
  45. if (isActive) {
  46. setQueue(annotations.slice(0, 15));
  47. }
  48. }, [isActive, annotations]);
  49. return (
  50. <Body ref={containerRef}>
  51. <div ref={innerRef}>
  52. <Typography light align="left">
  53. {`${annotations.length} ${t('annotation')}`}
  54. </Typography>
  55. {isActive &&
  56. renderQueue.map((ele, index) => {
  57. const key = `annot_item_${index}`;
  58. const {
  59. obj_type,
  60. obj_attr: { page, title, date },
  61. } = ele;
  62. const actualPage = page + 1;
  63. const prevAnnot = annotations[index - 1];
  64. const prevPage =
  65. index > 0 && prevAnnot ? prevAnnot.obj_attr.page + 1 : -1;
  66. return (
  67. <Item
  68. key={key}
  69. title={title}
  70. date={date}
  71. type={obj_type}
  72. page={actualPage}
  73. showPageNum={actualPage !== prevPage}
  74. />
  75. );
  76. })}
  77. </div>
  78. </Body>
  79. );
  80. };
  81. export default AnnotationList;