file-view-refresh-button.tsx 3.0 KB

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