file-view-refresh-button.tsx 2.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576
  1. import {
  2. type Dispatch,
  3. type SetStateAction,
  4. useCallback,
  5. useState,
  6. } from 'react'
  7. import { useTranslation } from 'react-i18next'
  8. import classNames from 'classnames'
  9. import Icon from '@/shared/components/icon'
  10. import { postJSON } from '@/infrastructure/fetch-json'
  11. import { useProjectContext } from '@/shared/context/project-context'
  12. import useAbortController from '@/shared/hooks/use-abort-controller'
  13. import { useUserContext } from '@/shared/context/user-context'
  14. import { hasProvider, type BinaryFile } from '../types/binary-file'
  15. import { Nullable } from '../../../../../types/utils'
  16. type FileViewRefreshButtonProps = {
  17. setRefreshError: Dispatch<SetStateAction<Nullable<string>>>
  18. file: BinaryFile
  19. }
  20. export default function FileViewRefreshButton({
  21. setRefreshError,
  22. file,
  23. }: FileViewRefreshButtonProps) {
  24. const { signal } = useAbortController()
  25. const { t } = useTranslation()
  26. const [refreshing, setRefreshing] = useState(false)
  27. const { _id: projectId } = useProjectContext()
  28. const { id: userId } = useUserContext()
  29. const isMendeleyOrZotero =
  30. hasProvider(file, 'mendeley') || hasProvider(file, 'zotero')
  31. let isImporter
  32. if (isMendeleyOrZotero) {
  33. isImporter = file.linkedFileData.importer_id === userId
  34. }
  35. const buttonClickable = isMendeleyOrZotero ? isImporter : true
  36. const refreshFile = useCallback(() => {
  37. setRefreshing(true)
  38. // Replacement of the file handled by the file tree
  39. window.expectingLinkedFileRefreshedSocketFor = file.name
  40. const body = {
  41. shouldReindexReferences: isMendeleyOrZotero || /\.bib$/.test(file.name),
  42. }
  43. postJSON(`/project/${projectId}/linked_file/${file.id}/refresh`, {
  44. signal,
  45. body,
  46. })
  47. .then(() => {
  48. setRefreshing(false)
  49. })
  50. .catch(err => {
  51. setRefreshing(false)
  52. setRefreshError(err.data?.message || err.message)
  53. })
  54. }, [file, projectId, signal, setRefreshError, isMendeleyOrZotero])
  55. return (
  56. <button
  57. className={classNames('btn', {
  58. 'btn-primary': buttonClickable,
  59. 'btn-secondary': !buttonClickable,
  60. })}
  61. onClick={refreshFile}
  62. disabled={refreshing || !buttonClickable}
  63. >
  64. <Icon type="refresh" spin={refreshing} fw />
  65. <span>{refreshing ? `${t('refreshing')}…` : t('refresh')}</span>
  66. </button>
  67. )
  68. }