import React, { useState, useEffect, useRef, useCallback } from 'react' import PropTypes from 'prop-types' import Icon from '../../../shared/components/icon' import { formatTime, relativeDate } from '../../utils/format-date' import { Trans, useTranslation } from 'react-i18next' import importOverleafModules from '../../../../macros/import-overleaf-module.macro' import { postJSON } from '../../../infrastructure/fetch-json' const tprLinkedFileInfo = importOverleafModules('tprLinkedFileInfo') const tprLinkedFileRefreshError = importOverleafModules( 'tprLinkedFileRefreshError' ) const MAX_URL_LENGTH = 60 const FRONT_OF_URL_LENGTH = 35 const FILLER = '...' const TAIL_OF_URL_LENGTH = MAX_URL_LENGTH - FRONT_OF_URL_LENGTH - FILLER.length function shortenedUrl(url) { if (!url) { return } if (url.length > MAX_URL_LENGTH) { const front = url.slice(0, FRONT_OF_URL_LENGTH) const tail = url.slice(url.length - TAIL_OF_URL_LENGTH) return front + FILLER + tail } return url } export default function BinaryFileHeader({ file, storeReferencesKeys }) { const isMounted = useRef(true) const [refreshing, setRefreshing] = useState(false) const [refreshError, setRefreshError] = useState(null) const { t } = useTranslation() useEffect(() => { // set to false on unmount to avoid unmounted component warning when refreshing return () => (isMounted.current = false) }, []) let fileInfo if (file.linkedFileData) { if (file.linkedFileData.provider === 'url') { fileInfo = (
) } else if (file.linkedFileData.provider === 'project_file') { fileInfo = (
) } else if (file.linkedFileData.provider === 'project_output_file') { fileInfo = (
) } } const refreshFile = useCallback(() => { setRefreshing(true) // Replacement of the file handled by the file tree window.expectingLinkedFileRefreshedSocketFor = file.name postJSON(`/project/${window.project_id}/linked_file/${file.id}/refresh`, { disableAutoLoginRedirect: true }) .then(() => { if (isMounted.current) { setRefreshing(false) } }) .catch(err => { if (isMounted.current) { setRefreshing(false) setRefreshError(err.message) } }) .finally(() => { if ( file.linkedFileData.provider === 'mendeley' || file.linkedFileData.provider === 'zotero' || file.name.match(/^.*\.bib$/) ) { reindexReferences() } }) function reindexReferences() { const opts = { body: { shouldBroadcast: true } } postJSON(`/project/${window.project_id}/references/indexAll`, opts) .then(response => { // Later updated by the socket but also updated here for immediate use storeReferencesKeys(response.keys) }) .catch(error => { console.log(error) }) } }, [file, isMounted, storeReferencesKeys]) return (
{file.linkedFileData && fileInfo} {file.linkedFileData && tprLinkedFileInfo.map(({ import: { LinkedFileInfo }, path }) => ( ))} {file.linkedFileData && ( )}   {' ' + t('download')} {refreshError && (

Error: {refreshError} {tprLinkedFileRefreshError.map( ({ import: { LinkedFileRefreshError }, path }) => ( ) )}
)}
) } BinaryFileHeader.propTypes = { file: PropTypes.shape({ id: PropTypes.string, name: PropTypes.string, linkedFileData: PropTypes.object }).isRequired, storeReferencesKeys: PropTypes.func.isRequired } function UrlProvider({ file }) { return (

  ] } values={{ shortenedUrl: shortenedUrl(file.linkedFileData.url), formattedDate: formatTime(file.created), relativeDate: relativeDate(file.created) }} />

) } UrlProvider.propTypes = { file: PropTypes.shape({ linkedFileData: PropTypes.object, created: PropTypes.string }).isRequired } function ProjectFilePathProvider({ file }) { /* eslint-disable jsx-a11y/anchor-has-content, react/jsx-key */ return (

  ] : [ ] } values={{ sourceEntityPath: file.linkedFileData.source_entity_path.slice(1), formattedDate: formatTime(file.created), relativeDate: relativeDate(file.created) }} />

/* esline-enable jsx-a11y/anchor-has-content, react/jsx-key */ ) } ProjectFilePathProvider.propTypes = { file: PropTypes.shape({ linkedFileData: PropTypes.object, created: PropTypes.string }).isRequired } function ProjectOutputFileProvider({ file }) { return (

  ] : [ ] } values={{ sourceOutputFilePath: file.linkedFileData.source_output_file_path, formattedDate: formatTime(file.created), relativeDate: relativeDate(file.created) }} />

) } ProjectOutputFileProvider.propTypes = { file: PropTypes.shape({ linkedFileData: PropTypes.object, created: PropTypes.string }).isRequired }