file-view-refresh-button.tsx 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. import {
  2. type Dispatch,
  3. type SetStateAction,
  4. type ElementType,
  5. useCallback,
  6. useState,
  7. } from 'react'
  8. import { useTranslation } from 'react-i18next'
  9. import { postJSON } from '@/infrastructure/fetch-json'
  10. import { useProjectContext } from '@/shared/context/project-context'
  11. import type { BinaryFile } from '../types/binary-file'
  12. import { Nullable } from '../../../../../types/utils'
  13. import importOverleafModules from '../../../../macros/import-overleaf-module.macro'
  14. import OLButton from '@/features/ui/components/ol/ol-button'
  15. import { sendMB } from '@/infrastructure/event-tracking'
  16. import useIsMounted from '@/shared/hooks/use-is-mounted'
  17. type FileViewRefreshButtonProps = {
  18. setRefreshError: Dispatch<SetStateAction<Nullable<string>>>
  19. file: BinaryFile
  20. }
  21. const tprFileViewRefreshButton = importOverleafModules(
  22. 'tprFileViewRefreshButton'
  23. ) as {
  24. import: { TPRFileViewRefreshButton: ElementType }
  25. path: string
  26. }[]
  27. export default function FileViewRefreshButton({
  28. setRefreshError,
  29. file,
  30. }: FileViewRefreshButtonProps) {
  31. const { projectId } = useProjectContext()
  32. const [refreshing, setRefreshing] = useState(false)
  33. const isMountedRef = useIsMounted()
  34. const refreshFile = useCallback(
  35. (isTPR: Nullable<boolean>) => {
  36. setRefreshing(true)
  37. // Replacement of the file handled by the file tree
  38. window.expectingLinkedFileRefreshedSocketFor = file.name
  39. const body = {
  40. shouldReindexReferences: isTPR || /\.bib$/.test(file.name),
  41. }
  42. postJSON(`/project/${projectId}/linked_file/${file.id}/refresh`, {
  43. body,
  44. })
  45. .then(() => {
  46. if (isMountedRef.current) {
  47. setRefreshing(false)
  48. }
  49. sendMB('refresh-linked-file', {
  50. provider: file.linkedFileData?.provider,
  51. })
  52. })
  53. .catch(err => {
  54. if (isMountedRef.current) {
  55. setRefreshing(false)
  56. setRefreshError(err.data?.message || err.message)
  57. }
  58. })
  59. },
  60. [file, projectId, setRefreshError, isMountedRef]
  61. )
  62. if (tprFileViewRefreshButton.length > 0) {
  63. return tprFileViewRefreshButton.map(
  64. ({ import: { TPRFileViewRefreshButton }, path }) => (
  65. <TPRFileViewRefreshButton
  66. key={path}
  67. file={file}
  68. refreshFile={refreshFile}
  69. refreshing={refreshing}
  70. />
  71. )
  72. )[0]
  73. } else {
  74. return (
  75. <FileViewRefreshButtonDefault
  76. refreshFile={refreshFile}
  77. refreshing={refreshing}
  78. />
  79. )
  80. }
  81. }
  82. type FileViewRefreshButtonDefaultProps = {
  83. refreshFile: (isTPR: Nullable<boolean>) => void
  84. refreshing: boolean
  85. }
  86. function FileViewRefreshButtonDefault({
  87. refreshFile,
  88. refreshing,
  89. }: FileViewRefreshButtonDefaultProps) {
  90. const { t } = useTranslation()
  91. return (
  92. <OLButton
  93. variant="primary"
  94. onClick={() => refreshFile(null)}
  95. disabled={refreshing}
  96. isLoading={refreshing}
  97. loadingLabel={t('refreshing')}
  98. >
  99. {t('refresh')}
  100. </OLButton>
  101. )
  102. }