fix(ui): client side doc data not updating after save (#9340)

### What?
When a document is saved the data from useDocumentInfo was stale.

### Why?
Previously we would refresh the entire document by calling the
form-state endpoint, we no longer do that.

### How?
Adds a new variable accessible from useDocumentInfo,
`savedDocumentData`, that is updated when the document is successfully
saved and defaults to initialData.
This commit is contained in:
Jarrod Flesch
2024-11-19 13:22:23 -05:00
committed by GitHub
parent 69b7a11a28
commit 661f450c61
4 changed files with 59 additions and 33 deletions

View File

@@ -1,13 +1,13 @@
'use client'
import type { FormState, SanitizedCollectionConfig, UploadEdits } from 'payload'
import { isImage, reduceFieldsToValues } from 'payload/shared'
import { isImage } from 'payload/shared'
import React, { useCallback, useEffect, useRef, useState } from 'react'
import { toast } from 'sonner'
import { FieldError } from '../../fields/FieldError/index.js'
import { fieldBaseClass } from '../../fields/shared/index.js'
import { useForm } from '../../forms/Form/index.js'
import { useForm, useFormProcessing } from '../../forms/Form/index.js'
import { useField } from '../../forms/useField/index.js'
import { useDocumentInfo } from '../../providers/DocumentInfo/index.js'
import { EditDepthProvider } from '../../providers/EditDepth/index.js'
@@ -94,15 +94,15 @@ export const Upload: React.FC<UploadProps> = (props) => {
const { t } = useTranslation()
const { setModified } = useForm()
const { resetUploadEdits, updateUploadEdits, uploadEdits } = useUploadEdits()
const { docPermissions } = useDocumentInfo()
const { docPermissions, savedDocumentData } = useDocumentInfo()
const isFormSubmitting = useFormProcessing()
const { errorMessage, setValue, showError, value } = useField<File>({
path: 'file',
validate,
})
const [doc, setDoc] = useState(reduceFieldsToValues(initialState || {}, true))
const [fileSrc, setFileSrc] = useState<null | string>(null)
const [replacingFile, setReplacingFile] = useState(false)
const [removedFile, setRemovedFile] = useState(false)
const [filename, setFilename] = useState<string>(value?.name || '')
const [showUrlInput, setShowUrlInput] = useState(false)
const [fileUrl, setFileUrl] = useState<string>('')
@@ -156,11 +156,10 @@ export const Upload: React.FC<UploadProps> = (props) => {
)
const handleFileRemoval = useCallback(() => {
setReplacingFile(true)
setRemovedFile(true)
handleFileChange(null)
setFileSrc('')
setFileUrl('')
setDoc({})
resetUploadEdits()
setShowUrlInput(false)
}, [handleFileChange, resetUploadEdits])
@@ -192,11 +191,10 @@ export const Upload: React.FC<UploadProps> = (props) => {
}
useEffect(() => {
setDoc(reduceFieldsToValues(initialState || {}, true))
if (initialState?.file?.value instanceof File) {
setFileSrc(URL.createObjectURL(initialState.file.value))
setRemovedFile(false)
}
setReplacingFile(false)
}, [initialState])
useEffect(() => {
@@ -205,6 +203,12 @@ export const Upload: React.FC<UploadProps> = (props) => {
}
}, [showUrlInput])
useEffect(() => {
if (isFormSubmitting) {
setRemovedFile(false)
}
}, [isFormSubmitting])
const canRemoveUpload =
docPermissions?.update && 'delete' in docPermissions && docPermissions?.delete
@@ -222,19 +226,19 @@ export const Upload: React.FC<UploadProps> = (props) => {
return (
<div className={[fieldBaseClass, baseClass].filter(Boolean).join(' ')}>
<FieldError message={errorMessage} showError={showError} />
{doc.filename && !replacingFile && (
{savedDocumentData && savedDocumentData.filename && !removedFile && (
<FileDetails
collectionSlug={collectionSlug}
customUploadActions={customActions}
doc={doc}
doc={savedDocumentData}
enableAdjustments={showCrop || showFocalPoint}
handleRemove={canRemoveUpload ? handleFileRemoval : undefined}
hasImageSizes={hasImageSizes}
imageCacheTag={doc.updatedAt}
imageCacheTag={savedDocumentData.updatedAt}
uploadConfig={uploadConfig}
/>
)}
{(!doc.filename || replacingFile) && (
{(!savedDocumentData?.filename || removedFile) && (
<div className={`${baseClass}__upload`}>
{!value && !showUrlInput && (
<Dropzone onChange={handleFileSelection}>
@@ -339,7 +343,7 @@ export const Upload: React.FC<UploadProps> = (props) => {
<UploadActions
customActions={customActions}
enableAdjustments={showCrop || showFocalPoint}
enablePreviewSizes={hasImageSizes && doc.filename && !replacingFile}
enablePreviewSizes={hasImageSizes && savedDocumentData?.filename && !removedFile}
mimeType={value.type}
/>
</div>
@@ -356,17 +360,17 @@ export const Upload: React.FC<UploadProps> = (props) => {
)}
</div>
)}
{(value || doc.filename) && (
{(value || savedDocumentData?.filename) && (
<EditDepthProvider>
<Drawer Header={null} slug={editDrawerSlug}>
<EditUpload
fileName={value?.name || doc?.filename}
fileSrc={doc?.url || fileSrc}
imageCacheTag={doc.updatedAt}
fileName={value?.name || savedDocumentData?.filename}
fileSrc={savedDocumentData?.url || fileSrc}
imageCacheTag={savedDocumentData?.updatedAt}
initialCrop={uploadEdits?.crop ?? undefined}
initialFocalPoint={{
x: uploadEdits?.focalPoint?.x || doc.focalX || 50,
y: uploadEdits?.focalPoint?.y || doc.focalY || 50,
x: uploadEdits?.focalPoint?.x || savedDocumentData?.focalX || 50,
y: uploadEdits?.focalPoint?.y || savedDocumentData?.focalY || 50,
}}
onSave={onEditsSave}
showCrop={showCrop}
@@ -375,14 +379,18 @@ export const Upload: React.FC<UploadProps> = (props) => {
</Drawer>
</EditDepthProvider>
)}
{doc && hasImageSizes && (
{savedDocumentData && hasImageSizes && (
<Drawer
className={`${baseClass}__previewDrawer`}
hoverTitle
slug={sizePreviewSlug}
title={t('upload:sizesFor', { label: doc?.filename })}
title={t('upload:sizesFor', { label: savedDocumentData.filename })}
>
<PreviewSizes doc={doc} imageCacheTag={doc.updatedAt} uploadConfig={uploadConfig} />
<PreviewSizes
doc={savedDocumentData}
imageCacheTag={savedDocumentData.updatedAt}
uploadConfig={uploadConfig}
/>
</Drawer>
)}
</div>

View File

@@ -42,7 +42,7 @@ const DocumentInfo: React.FC<
hasPublishedDoc: hasPublishedDocFromProps,
hasPublishPermission: hasPublishPermissionFromProps,
hasSavePermission: hasSavePermissionFromProps,
initialData: data,
initialData,
initialState,
isLocked: isLockedFromProps,
lastUpdateTime: lastUpdateTimeFromProps,
@@ -84,7 +84,7 @@ const DocumentInfo: React.FC<
const [documentTitle, setDocumentTitle] = useState(() =>
formatDocTitle({
collectionConfig,
data: { ...data, id },
data: { ...(initialData || {}), id },
dateFormat,
fallback: id?.toString(),
globalConfig,
@@ -105,8 +105,9 @@ const DocumentInfo: React.FC<
const [documentIsLocked, setDocumentIsLocked] = useState<boolean | undefined>(isLockedFromProps)
const [currentEditor, setCurrentEditor] = useState<ClientUser | null>(currentEditorFromProps)
const [lastUpdateTime, setLastUpdateTime] = useState<number>(lastUpdateTimeFromProps)
const [savedDocumentData, setSavedDocumentData] = useState(initialData)
const isInitializing = initialState === undefined || data === undefined
const isInitializing = initialState === undefined || initialData === undefined
const { getPreference, setPreference } = usePreferences()
const { code: locale } = useLocale()
@@ -251,18 +252,25 @@ const DocumentInfo: React.FC<
}
}, [collectionConfig, globalConfig, versionCount])
const updateSavedDocumentData = React.useCallback<DocumentInfoContext['updateSavedDocumentData']>(
(json) => {
setSavedDocumentData(json)
},
[],
)
useEffect(() => {
setDocumentTitle(
formatDocTitle({
collectionConfig,
data: { ...data, id },
data: { ...savedDocumentData, id },
dateFormat,
fallback: id?.toString(),
globalConfig,
i18n,
}),
)
}, [collectionConfig, globalConfig, data, dateFormat, i18n, id])
}, [collectionConfig, globalConfig, savedDocumentData, dateFormat, i18n, id])
// clean on unmount
useEffect(() => {
@@ -306,12 +314,13 @@ const DocumentInfo: React.FC<
hasPublishPermission,
hasSavePermission,
incrementVersionCount,
initialData: data,
initialData,
initialState,
isInitializing,
lastUpdateTime,
mostRecentVersionIsAutosaved,
preferencesKey,
savedDocumentData,
setCurrentEditor,
setDocFieldPreferences,
setDocumentIsLocked,
@@ -324,6 +333,7 @@ const DocumentInfo: React.FC<
unlockDocument,
unpublishedVersionCount,
updateDocumentEditor,
updateSavedDocumentData,
versionCount,
}

View File

@@ -57,6 +57,7 @@ export type DocumentInfoContext = {
lastUpdateTime?: number
mostRecentVersionIsAutosaved: boolean
preferencesKey?: string
savedDocumentData?: Data
setCurrentEditor?: React.Dispatch<React.SetStateAction<ClientUser>>
setDocFieldPreferences: (
field: string,
@@ -72,5 +73,6 @@ export type DocumentInfoContext = {
unlockDocument: (docId: number | string, slug: string) => Promise<void>
unpublishedVersionCount: number
updateDocumentEditor: (docId: number | string, slug: string, user: ClientUser) => Promise<void>
updateSavedDocumentData: (data: Data) => void
versionCount: number
} & DocumentInfoProps

View File

@@ -71,17 +71,18 @@ export const DefaultEditView: React.FC<ClientSideEditViewProps> = ({
hasPublishPermission,
hasSavePermission,
incrementVersionCount,
initialData: data,
initialState,
isEditing,
isInitializing,
lastUpdateTime,
redirectAfterDelete,
redirectAfterDuplicate,
savedDocumentData,
setCurrentEditor,
setDocumentIsLocked,
unlockDocument,
updateDocumentEditor,
updateSavedDocumentData,
} = useDocumentInfo()
const {
@@ -212,6 +213,10 @@ export const DefaultEditView: React.FC<ClientSideEditViewProps> = ({
incrementVersionCount()
if (typeof updateSavedDocumentData === 'function') {
void updateSavedDocumentData(json?.doc || {})
}
if (typeof onSaveFromContext === 'function') {
void onSaveFromContext({
...json,
@@ -238,6 +243,7 @@ export const DefaultEditView: React.FC<ClientSideEditViewProps> = ({
await getDocPermissions(json)
},
[
updateSavedDocumentData,
reportUpdate,
id,
entitySlug,
@@ -479,7 +485,7 @@ export const DefaultEditView: React.FC<ClientSideEditViewProps> = ({
SaveButton,
SaveDraftButton,
}}
data={data}
data={savedDocumentData}
disableActions={disableActions}
disableCreate={disableCreate}
hasPublishPermission={hasPublishPermission}
@@ -521,7 +527,7 @@ export const DefaultEditView: React.FC<ClientSideEditViewProps> = ({
className={`${baseClass}__auth`}
collectionSlug={collectionConfig.slug}
disableLocalStrategy={collectionConfig.auth?.disableLocalStrategy}
email={data?.email}
email={savedDocumentData?.email}
loginWithUsername={auth?.loginWithUsername}
operation={operation}
readOnly={!hasSavePermission}
@@ -529,7 +535,7 @@ export const DefaultEditView: React.FC<ClientSideEditViewProps> = ({
setSchemaPathSegments={setSchemaPathSegments}
setValidateBeforeSubmit={setValidateBeforeSubmit}
useAPIKey={auth.useAPIKey}
username={data?.username}
username={savedDocumentData?.username}
verify={auth.verify}
/>
)}