Skip to content

Commit

Permalink
feat: Warn the user when the OnlyOffice file has been deleted during …
Browse files Browse the repository at this point in the history
…editing
  • Loading branch information
cballevre committed Oct 10, 2023
1 parent 31023d7 commit 0bdd7db
Show file tree
Hide file tree
Showing 7 changed files with 175 additions and 60 deletions.
1 change: 1 addition & 0 deletions src/drive/hooks/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ export { default as useCurrentFileId } from './useCurrentFileId'
export { default as useCurrentFolderId } from './useCurrentFolderId'
export { default as useDisplayedFolder } from './useDisplayedFolder'
export { default as useParentFolder } from './useParentFolder'
export { useRedirectLink } from './useRedirectLink'
67 changes: 67 additions & 0 deletions src/drive/hooks/useRedirectLink.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import { useMemo, useState, useEffect } from 'react'
import { useSearchParams } from 'react-router-dom'

import {
useClient,
generateWebLink,
deconstructRedirectLink
} from 'cozy-client'

const useRedirectLink = () => {
const [searchParams] = useSearchParams()
const params = new URLSearchParams(location.search)
const client = useClient()

const [fetchStatus, setFetchStatus] = useState('pending')
const [instance, setInstance] = useState(client.getStackClient().uri)

useEffect(() => {
const fetch = async () => {
try {
setFetchStatus('loading')
const permissions = await client
.collection('io.cozy.permissions')
.fetchOwnPermissions()
if (permissions.included.length > 0) {
setInstance(permissions.included[0].attributes.instance)
}
setFetchStatus('loaded')
} catch {
setFetchStatus('error')
}
}
fetch()
}, [client])

/**
* We search for redirectLink using two methods because
* the searchParam differs depending on the position in the url :
* - for /#hash?searchParam, you need useSearchParams
* - for /?searchParam#hash, you need location.search
*/
const redirectLink =
searchParams.get('redirectLink') || params.get('redirectLink')

const redirectWebLink = useMemo(() => {
if (redirectLink === null && fetchStatus !== 'loaded') return null

const { slug, pathname, hash } = deconstructRedirectLink(redirectLink)
const { subdomain: subDomainType } = client.getInstanceOptions()

return generateWebLink({
cozyUrl: instance,
subDomainType,
slug,
pathname,
hash,
searchParams: []
})
}, [client, instance, redirectLink, fetchStatus])

return {
redirectWebLink,
redirectLink
}
}

export { useRedirectLink }
7 changes: 7 additions & 0 deletions src/drive/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -746,5 +746,12 @@
"cancel": "Cancel",
"confirm": "Ok, I get it"
}
},
"FileDeletedModal": {
"title": "Someone has deleted this file",
"content": "Someone has deleted this file while you were editing it. You can stop editing or restore the file to continue editing.",
"confirm": "Restore file",
"cancel": "Undo changes",
"error": "An error occurred, please try again."
}
}
5 changes: 4 additions & 1 deletion src/drive/web/modules/views/OnlyOffice/Editor.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
DEFAULT_EDITOR_TOOLBAR_HEIGHT
} from 'drive/web/modules/views/OnlyOffice/config'
import { FileDivergedModal } from 'drive/web/modules/views/OnlyOffice/components/FileDivergedModal'
import { FileDeletedModal } from 'drive/web/modules/views/OnlyOffice/components/FileDeletedModal'

const getEditorToolbarHeight = editorToolbarHeightFlag => {
if (Number.isInteger(editorToolbarHeightFlag)) {
Expand All @@ -28,7 +29,8 @@ const getEditorToolbarHeight = editorToolbarHeightFlag => {

export const Editor = () => {
const { config, status } = useConfig()
const { isEditorModeView, hasFileDiverged } = useOnlyOfficeContext()
const { isEditorModeView, hasFileDiverged, hasFileDeleted } =
useOnlyOfficeContext()

if (status === 'error') return <Error />
if (status !== 'loaded' || !config) return <Loading />
Expand Down Expand Up @@ -57,6 +59,7 @@ export const Editor = () => {
docEditorConfig={docEditorConfig}
/>
{hasFileDiverged ? <FileDivergedModal /> : null}
{hasFileDeleted ? <FileDeletedModal /> : null}
</DialogContent>
</>
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,12 @@ const OnlyOfficeProvider = ({
const { isDesktop, isMobile } = useBreakpoints()
const [searchParam] = useSearchParams()
const [isEditorReady, setIsEditorReady] = useState(false)

const [editorMode, setEditorMode] = useState(
officeDefaultMode(isDesktop, isMobile)
)

const [hasFileDiverged, setFileDiverged] = useState(false)
const [hasFileDeleted, setFileDeleted] = useState(false)
const [officeKey, setOfficeKey] = useState(null)

const isEditorModeView = useMemo(() => editorMode === 'view', [editorMode])
Expand All @@ -55,6 +55,9 @@ const OnlyOfficeProvider = ({
) {
setFileDiverged(true)
}
if (data.trashed) {
setFileDeleted(true)
}
},
[fileResult?.data?.md5sum]
)
Expand Down Expand Up @@ -87,6 +90,8 @@ const OnlyOfficeProvider = ({
fileId,
hasFileDiverged,
setFileDiverged,
hasFileDeleted,
setFileDeleted,
isPublic,
isReadOnly,
isFromSharing,
Expand Down
64 changes: 6 additions & 58 deletions src/drive/web/modules/views/OnlyOffice/Toolbar/index.jsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,6 @@
import React, { useState, useEffect } from 'react'
import { useSearchParams } from 'react-router-dom'
import React from 'react'

import {
RealTimeQueries,
useClient,
generateWebLink,
deconstructRedirectLink
} from 'cozy-client'
import { RealTimeQueries } from 'cozy-client'
import useBreakpoints from 'cozy-ui/transpiled/react/providers/Breakpoints'

import { DOCTYPE_FILES } from 'drive/lib/doctypes'
Expand All @@ -20,65 +14,19 @@ import FileIcon from 'drive/web/modules/views/OnlyOffice/Toolbar/FileIcon'
import FileName from 'drive/web/modules/views/OnlyOffice/Toolbar/FileName'
import ReadOnly from 'drive/web/modules/views/OnlyOffice/Toolbar/ReadOnly'
import Sharing from 'drive/web/modules/views/OnlyOffice/Toolbar/Sharing'
import { useRedirectLink } from 'drive/hooks/useRedirectLink'

const Toolbar = () => {
const { isMobile } = useBreakpoints()
const { fileId, isPublic, isReadOnly, isEditorReady } = useOnlyOfficeContext()
const client = useClient()
const [fetchStatus, setFetchStatus] = useState('pending')
const [instance, setInstance] = useState(client.getStackClient().uri)

useEffect(() => {
const fetch = async () => {
try {
setFetchStatus('loading')
const permissions = await client
.collection('io.cozy.permissions')
.fetchOwnPermissions()
if (permissions.included.length > 0) {
setInstance(permissions.included[0].attributes.instance)
}
setFetchStatus('loaded')
} catch {
setFetchStatus('error')
}
}
fetch()
}, [client])

const [searchParams] = useSearchParams()
const params = new URLSearchParams(location.search)

/**
* We search for redirectLink using two methods because
* the searchParam differs depending on the position in the url :
* - for /#hash?searchParam, you need useSearchParams
* - for /?searchParam#hash, you need location.search
*/
const redirectLink =
searchParams.get('redirectLink') || params.get('redirectLink')

const { data: fileWithPath } = useFileWithPath(fileId)
const { redirectWebLink } = useRedirectLink()

let link
if (redirectLink) {
const { slug, pathname, hash } = deconstructRedirectLink(redirectLink)
const { subdomain: subDomainType } = client.getInstanceOptions()

link = generateWebLink({
cozyUrl: instance,
subDomainType,
slug,
pathname,
hash,
searchParams: []
})
}

const showBackButton = redirectLink !== null && fetchStatus === 'loaded'
const showBackButton = redirectWebLink !== null

const handleOnClick = () => {
window.location = link
window.location = redirectWebLink
}

return (
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import React, { useState } from 'react'
import { useNavigate } from 'react-router-dom'

import { useClient } from 'cozy-client'
import { ConfirmDialog } from 'cozy-ui/transpiled/react/CozyDialogs'
import Buttons from 'cozy-ui/transpiled/react/Buttons'
import { useI18n } from 'cozy-ui/transpiled/react/providers/I18n'
import Typography from 'cozy-ui/transpiled/react/Typography'
import Alert from 'cozy-ui/transpiled/react/Alert'

import { DOCTYPE_FILES } from 'drive/lib/doctypes'
import { useOnlyOfficeContext } from 'drive/web/modules/views/OnlyOffice/OnlyOfficeProvider'
import { makeOnlyOfficeFileRoute } from 'drive/web/modules/views/OnlyOffice/helpers'
import { useRedirectLink } from 'drive/hooks/useRedirectLink'

const FileDeletedModal = () => {
const { fileId, setFileDeleted, editorMode } = useOnlyOfficeContext()
const navigate = useNavigate()
const client = useClient()
const { t } = useI18n()

const [isErrorAlertDisplayed, setErrorAlertDisplayed] = useState(false)
const [isBusy, setBusy] = useState(false)

const { redirectLink, redirectWebLink } = useRedirectLink()

const restore = async () => {
setErrorAlertDisplayed(false)
setBusy(isBusy)
try {
const resp = await client.collection(DOCTYPE_FILES).restore(fileId)
const route = makeOnlyOfficeFileRoute(resp.data.id, {
fromRedirect: redirectLink,
fromEdit: editorMode === 'edit'
})
navigate(route)
setFileDeleted(false)
} catch {
setErrorAlertDisplayed(true)
} finally {
setBusy(false)
}
}

const goBack = () => {
window.location = redirectWebLink
}

return (
<ConfirmDialog
open
title={t('FileDeletedModal.title')}
content={
<>
{isErrorAlertDisplayed ? (
<Alert severity="error" className="u-mb-1">
{t('FileDeletedModal.error')}
</Alert>
) : null}
<Typography>{t('FileDeletedModal.content')}</Typography>
</>
}
actions={
<>
<Buttons
disabled={isBusy}
variant="secondary"
color="error"
label={t('FileDeletedModal.cancel')}
onClick={goBack}
/>
<Buttons
busy={isBusy}
disabled={isBusy}
label={t('FileDeletedModal.confirm')}
onClick={restore}
/>
</>
}
/>
)
}

export { FileDeletedModal }

0 comments on commit 0bdd7db

Please sign in to comment.