mirror of
https://github.com/yu-i-i/overleaf-cep.git
synced 2026-11-12 21:23:45 +01:00
[WEB] Adding error message in the unable to sync modal GitOrigin-RevId: b9d2cdc0db8c87e8f90b77d812dbb6d0c6695622
151 lines
4.3 KiB
TypeScript
151 lines
4.3 KiB
TypeScript
import { Trans, useTranslation } from 'react-i18next'
|
|
import { memo, useCallback, useState } from 'react'
|
|
import OLButton from '@/shared/components/ol/ol-button'
|
|
import {
|
|
OLModal,
|
|
OLModalBody,
|
|
OLModalFooter,
|
|
OLModalHeader,
|
|
OLModalTitle,
|
|
} from '@/shared/components/ol/ol-modal'
|
|
import DiffViewer from './diff-viewer'
|
|
import getMeta from '@/utils/meta'
|
|
import { uploadBatch } from '@/infrastructure/batch-file-uploader'
|
|
import { debugConsole } from '@/utils/debugging'
|
|
import Notification from '@/shared/components/notification'
|
|
import { downloadFileContent } from '@/utils/download-file'
|
|
|
|
export type UnableToSyncModalProps = {
|
|
baseContent: string
|
|
targetContent: string
|
|
docName: string | null
|
|
rootFolderId: string | undefined
|
|
show: boolean
|
|
onHide: () => void
|
|
}
|
|
|
|
// Generates the offline copy filename with a timestamp to avoid duplicates.
|
|
// e.g. main.tex -> main(offline-2026-07-27-14-07).tex
|
|
function buildOfflineFilename(docName: string | null): string {
|
|
const now = new Date()
|
|
const stamp = [
|
|
now.getFullYear(),
|
|
String(now.getMonth() + 1).padStart(2, '0'),
|
|
String(now.getDate()).padStart(2, '0'),
|
|
String(now.getHours()).padStart(2, '0'),
|
|
String(now.getMinutes()).padStart(2, '0'),
|
|
].join('-')
|
|
const suffix = `(offline-${stamp})`
|
|
if (!docName) {
|
|
return `main${suffix}.tex`
|
|
}
|
|
const lastDot = docName.lastIndexOf('.')
|
|
if (lastDot === -1) {
|
|
return `${docName}${suffix}`
|
|
}
|
|
return `${docName.slice(0, lastDot)}${suffix}${docName.slice(lastDot)}`
|
|
}
|
|
|
|
function UnableToSyncModal({
|
|
baseContent,
|
|
targetContent,
|
|
docName,
|
|
rootFolderId,
|
|
show,
|
|
onHide,
|
|
}: UnableToSyncModalProps) {
|
|
const { t } = useTranslation()
|
|
const [saving, setSaving] = useState(false)
|
|
const [saveError, setSaveError] = useState(false)
|
|
|
|
const handleDownload = useCallback(() => {
|
|
downloadFileContent(targetContent, docName ?? 'document.txt')
|
|
}, [targetContent, docName])
|
|
|
|
const handleSaveAsNewFile = useCallback(async () => {
|
|
const projectId = getMeta('ol-project_id')
|
|
const filename = buildOfflineFilename(docName)
|
|
|
|
setSaving(true)
|
|
setSaveError(false)
|
|
try {
|
|
if (!rootFolderId) {
|
|
throw new Error('rootFolderId not available')
|
|
}
|
|
const [result] = await uploadBatch(
|
|
[
|
|
{
|
|
file: new Blob([targetContent], { type: 'text/plain' }),
|
|
name: filename,
|
|
},
|
|
],
|
|
{ projectId, folderId: rootFolderId }
|
|
)
|
|
if (result.status === 'error') {
|
|
throw new Error(result.error)
|
|
}
|
|
onHide()
|
|
} catch (error) {
|
|
debugConsole.error('Failed to save offline changes as new file', error)
|
|
setSaveError(true)
|
|
} finally {
|
|
setSaving(false)
|
|
}
|
|
}, [docName, targetContent, rootFolderId, onHide])
|
|
|
|
return (
|
|
<OLModal
|
|
show={show}
|
|
onHide={onHide}
|
|
className="unable-to-sync-modal"
|
|
backdrop="static"
|
|
keyboard={false}
|
|
centered
|
|
>
|
|
<OLModalHeader closeButton={false}>
|
|
<OLModalTitle>{t('your_offline_edits_couldnt_be_synced')}</OLModalTitle>
|
|
</OLModalHeader>
|
|
<OLModalBody>
|
|
<p>{t('offline_edits_couldnt_combine')}</p>
|
|
<DiffViewer baseContent={baseContent} targetContent={targetContent} />
|
|
<p className="mt-2">{t('offline_save_explanation')}</p>
|
|
{saveError && (
|
|
<Notification
|
|
type="error"
|
|
content={
|
|
<Trans
|
|
i18nKey="unable_to_save_check_connection_or_download"
|
|
components={[
|
|
// eslint-disable-next-line jsx-a11y/anchor-has-content,jsx-a11y/anchor-is-valid,react/jsx-key
|
|
<a
|
|
href="#"
|
|
onClick={e => {
|
|
e.preventDefault()
|
|
handleDownload()
|
|
}}
|
|
/>,
|
|
]}
|
|
/>
|
|
}
|
|
/>
|
|
)}
|
|
</OLModalBody>
|
|
<OLModalFooter>
|
|
<OLButton variant="danger-ghost" onClick={onHide}>
|
|
{t('discard_changes')}
|
|
</OLButton>
|
|
<OLButton
|
|
variant="primary"
|
|
onClick={handleSaveAsNewFile}
|
|
isLoading={saving}
|
|
loadingLabel={t('saving')}
|
|
>
|
|
{t('save_as_new_file')}
|
|
</OLButton>
|
|
</OLModalFooter>
|
|
</OLModal>
|
|
)
|
|
}
|
|
|
|
export default memo(UnableToSyncModal)
|