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:
@@ -1,13 +1,13 @@
|
|||||||
'use client'
|
'use client'
|
||||||
import type { FormState, SanitizedCollectionConfig, UploadEdits } from 'payload'
|
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 React, { useCallback, useEffect, useRef, useState } from 'react'
|
||||||
import { toast } from 'sonner'
|
import { toast } from 'sonner'
|
||||||
|
|
||||||
import { FieldError } from '../../fields/FieldError/index.js'
|
import { FieldError } from '../../fields/FieldError/index.js'
|
||||||
import { fieldBaseClass } from '../../fields/shared/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 { useField } from '../../forms/useField/index.js'
|
||||||
import { useDocumentInfo } from '../../providers/DocumentInfo/index.js'
|
import { useDocumentInfo } from '../../providers/DocumentInfo/index.js'
|
||||||
import { EditDepthProvider } from '../../providers/EditDepth/index.js'
|
import { EditDepthProvider } from '../../providers/EditDepth/index.js'
|
||||||
@@ -94,15 +94,15 @@ export const Upload: React.FC<UploadProps> = (props) => {
|
|||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const { setModified } = useForm()
|
const { setModified } = useForm()
|
||||||
const { resetUploadEdits, updateUploadEdits, uploadEdits } = useUploadEdits()
|
const { resetUploadEdits, updateUploadEdits, uploadEdits } = useUploadEdits()
|
||||||
const { docPermissions } = useDocumentInfo()
|
const { docPermissions, savedDocumentData } = useDocumentInfo()
|
||||||
|
const isFormSubmitting = useFormProcessing()
|
||||||
const { errorMessage, setValue, showError, value } = useField<File>({
|
const { errorMessage, setValue, showError, value } = useField<File>({
|
||||||
path: 'file',
|
path: 'file',
|
||||||
validate,
|
validate,
|
||||||
})
|
})
|
||||||
|
|
||||||
const [doc, setDoc] = useState(reduceFieldsToValues(initialState || {}, true))
|
|
||||||
const [fileSrc, setFileSrc] = useState<null | string>(null)
|
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 [filename, setFilename] = useState<string>(value?.name || '')
|
||||||
const [showUrlInput, setShowUrlInput] = useState(false)
|
const [showUrlInput, setShowUrlInput] = useState(false)
|
||||||
const [fileUrl, setFileUrl] = useState<string>('')
|
const [fileUrl, setFileUrl] = useState<string>('')
|
||||||
@@ -156,11 +156,10 @@ export const Upload: React.FC<UploadProps> = (props) => {
|
|||||||
)
|
)
|
||||||
|
|
||||||
const handleFileRemoval = useCallback(() => {
|
const handleFileRemoval = useCallback(() => {
|
||||||
setReplacingFile(true)
|
setRemovedFile(true)
|
||||||
handleFileChange(null)
|
handleFileChange(null)
|
||||||
setFileSrc('')
|
setFileSrc('')
|
||||||
setFileUrl('')
|
setFileUrl('')
|
||||||
setDoc({})
|
|
||||||
resetUploadEdits()
|
resetUploadEdits()
|
||||||
setShowUrlInput(false)
|
setShowUrlInput(false)
|
||||||
}, [handleFileChange, resetUploadEdits])
|
}, [handleFileChange, resetUploadEdits])
|
||||||
@@ -192,11 +191,10 @@ export const Upload: React.FC<UploadProps> = (props) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setDoc(reduceFieldsToValues(initialState || {}, true))
|
|
||||||
if (initialState?.file?.value instanceof File) {
|
if (initialState?.file?.value instanceof File) {
|
||||||
setFileSrc(URL.createObjectURL(initialState.file.value))
|
setFileSrc(URL.createObjectURL(initialState.file.value))
|
||||||
|
setRemovedFile(false)
|
||||||
}
|
}
|
||||||
setReplacingFile(false)
|
|
||||||
}, [initialState])
|
}, [initialState])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -205,6 +203,12 @@ export const Upload: React.FC<UploadProps> = (props) => {
|
|||||||
}
|
}
|
||||||
}, [showUrlInput])
|
}, [showUrlInput])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (isFormSubmitting) {
|
||||||
|
setRemovedFile(false)
|
||||||
|
}
|
||||||
|
}, [isFormSubmitting])
|
||||||
|
|
||||||
const canRemoveUpload =
|
const canRemoveUpload =
|
||||||
docPermissions?.update && 'delete' in docPermissions && docPermissions?.delete
|
docPermissions?.update && 'delete' in docPermissions && docPermissions?.delete
|
||||||
|
|
||||||
@@ -222,19 +226,19 @@ export const Upload: React.FC<UploadProps> = (props) => {
|
|||||||
return (
|
return (
|
||||||
<div className={[fieldBaseClass, baseClass].filter(Boolean).join(' ')}>
|
<div className={[fieldBaseClass, baseClass].filter(Boolean).join(' ')}>
|
||||||
<FieldError message={errorMessage} showError={showError} />
|
<FieldError message={errorMessage} showError={showError} />
|
||||||
{doc.filename && !replacingFile && (
|
{savedDocumentData && savedDocumentData.filename && !removedFile && (
|
||||||
<FileDetails
|
<FileDetails
|
||||||
collectionSlug={collectionSlug}
|
collectionSlug={collectionSlug}
|
||||||
customUploadActions={customActions}
|
customUploadActions={customActions}
|
||||||
doc={doc}
|
doc={savedDocumentData}
|
||||||
enableAdjustments={showCrop || showFocalPoint}
|
enableAdjustments={showCrop || showFocalPoint}
|
||||||
handleRemove={canRemoveUpload ? handleFileRemoval : undefined}
|
handleRemove={canRemoveUpload ? handleFileRemoval : undefined}
|
||||||
hasImageSizes={hasImageSizes}
|
hasImageSizes={hasImageSizes}
|
||||||
imageCacheTag={doc.updatedAt}
|
imageCacheTag={savedDocumentData.updatedAt}
|
||||||
uploadConfig={uploadConfig}
|
uploadConfig={uploadConfig}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{(!doc.filename || replacingFile) && (
|
{(!savedDocumentData?.filename || removedFile) && (
|
||||||
<div className={`${baseClass}__upload`}>
|
<div className={`${baseClass}__upload`}>
|
||||||
{!value && !showUrlInput && (
|
{!value && !showUrlInput && (
|
||||||
<Dropzone onChange={handleFileSelection}>
|
<Dropzone onChange={handleFileSelection}>
|
||||||
@@ -339,7 +343,7 @@ export const Upload: React.FC<UploadProps> = (props) => {
|
|||||||
<UploadActions
|
<UploadActions
|
||||||
customActions={customActions}
|
customActions={customActions}
|
||||||
enableAdjustments={showCrop || showFocalPoint}
|
enableAdjustments={showCrop || showFocalPoint}
|
||||||
enablePreviewSizes={hasImageSizes && doc.filename && !replacingFile}
|
enablePreviewSizes={hasImageSizes && savedDocumentData?.filename && !removedFile}
|
||||||
mimeType={value.type}
|
mimeType={value.type}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@@ -356,17 +360,17 @@ export const Upload: React.FC<UploadProps> = (props) => {
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{(value || doc.filename) && (
|
{(value || savedDocumentData?.filename) && (
|
||||||
<EditDepthProvider>
|
<EditDepthProvider>
|
||||||
<Drawer Header={null} slug={editDrawerSlug}>
|
<Drawer Header={null} slug={editDrawerSlug}>
|
||||||
<EditUpload
|
<EditUpload
|
||||||
fileName={value?.name || doc?.filename}
|
fileName={value?.name || savedDocumentData?.filename}
|
||||||
fileSrc={doc?.url || fileSrc}
|
fileSrc={savedDocumentData?.url || fileSrc}
|
||||||
imageCacheTag={doc.updatedAt}
|
imageCacheTag={savedDocumentData?.updatedAt}
|
||||||
initialCrop={uploadEdits?.crop ?? undefined}
|
initialCrop={uploadEdits?.crop ?? undefined}
|
||||||
initialFocalPoint={{
|
initialFocalPoint={{
|
||||||
x: uploadEdits?.focalPoint?.x || doc.focalX || 50,
|
x: uploadEdits?.focalPoint?.x || savedDocumentData?.focalX || 50,
|
||||||
y: uploadEdits?.focalPoint?.y || doc.focalY || 50,
|
y: uploadEdits?.focalPoint?.y || savedDocumentData?.focalY || 50,
|
||||||
}}
|
}}
|
||||||
onSave={onEditsSave}
|
onSave={onEditsSave}
|
||||||
showCrop={showCrop}
|
showCrop={showCrop}
|
||||||
@@ -375,14 +379,18 @@ export const Upload: React.FC<UploadProps> = (props) => {
|
|||||||
</Drawer>
|
</Drawer>
|
||||||
</EditDepthProvider>
|
</EditDepthProvider>
|
||||||
)}
|
)}
|
||||||
{doc && hasImageSizes && (
|
{savedDocumentData && hasImageSizes && (
|
||||||
<Drawer
|
<Drawer
|
||||||
className={`${baseClass}__previewDrawer`}
|
className={`${baseClass}__previewDrawer`}
|
||||||
hoverTitle
|
hoverTitle
|
||||||
slug={sizePreviewSlug}
|
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>
|
</Drawer>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ const DocumentInfo: React.FC<
|
|||||||
hasPublishedDoc: hasPublishedDocFromProps,
|
hasPublishedDoc: hasPublishedDocFromProps,
|
||||||
hasPublishPermission: hasPublishPermissionFromProps,
|
hasPublishPermission: hasPublishPermissionFromProps,
|
||||||
hasSavePermission: hasSavePermissionFromProps,
|
hasSavePermission: hasSavePermissionFromProps,
|
||||||
initialData: data,
|
initialData,
|
||||||
initialState,
|
initialState,
|
||||||
isLocked: isLockedFromProps,
|
isLocked: isLockedFromProps,
|
||||||
lastUpdateTime: lastUpdateTimeFromProps,
|
lastUpdateTime: lastUpdateTimeFromProps,
|
||||||
@@ -84,7 +84,7 @@ const DocumentInfo: React.FC<
|
|||||||
const [documentTitle, setDocumentTitle] = useState(() =>
|
const [documentTitle, setDocumentTitle] = useState(() =>
|
||||||
formatDocTitle({
|
formatDocTitle({
|
||||||
collectionConfig,
|
collectionConfig,
|
||||||
data: { ...data, id },
|
data: { ...(initialData || {}), id },
|
||||||
dateFormat,
|
dateFormat,
|
||||||
fallback: id?.toString(),
|
fallback: id?.toString(),
|
||||||
globalConfig,
|
globalConfig,
|
||||||
@@ -105,8 +105,9 @@ const DocumentInfo: React.FC<
|
|||||||
const [documentIsLocked, setDocumentIsLocked] = useState<boolean | undefined>(isLockedFromProps)
|
const [documentIsLocked, setDocumentIsLocked] = useState<boolean | undefined>(isLockedFromProps)
|
||||||
const [currentEditor, setCurrentEditor] = useState<ClientUser | null>(currentEditorFromProps)
|
const [currentEditor, setCurrentEditor] = useState<ClientUser | null>(currentEditorFromProps)
|
||||||
const [lastUpdateTime, setLastUpdateTime] = useState<number>(lastUpdateTimeFromProps)
|
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 { getPreference, setPreference } = usePreferences()
|
||||||
const { code: locale } = useLocale()
|
const { code: locale } = useLocale()
|
||||||
@@ -251,18 +252,25 @@ const DocumentInfo: React.FC<
|
|||||||
}
|
}
|
||||||
}, [collectionConfig, globalConfig, versionCount])
|
}, [collectionConfig, globalConfig, versionCount])
|
||||||
|
|
||||||
|
const updateSavedDocumentData = React.useCallback<DocumentInfoContext['updateSavedDocumentData']>(
|
||||||
|
(json) => {
|
||||||
|
setSavedDocumentData(json)
|
||||||
|
},
|
||||||
|
[],
|
||||||
|
)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setDocumentTitle(
|
setDocumentTitle(
|
||||||
formatDocTitle({
|
formatDocTitle({
|
||||||
collectionConfig,
|
collectionConfig,
|
||||||
data: { ...data, id },
|
data: { ...savedDocumentData, id },
|
||||||
dateFormat,
|
dateFormat,
|
||||||
fallback: id?.toString(),
|
fallback: id?.toString(),
|
||||||
globalConfig,
|
globalConfig,
|
||||||
i18n,
|
i18n,
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
}, [collectionConfig, globalConfig, data, dateFormat, i18n, id])
|
}, [collectionConfig, globalConfig, savedDocumentData, dateFormat, i18n, id])
|
||||||
|
|
||||||
// clean on unmount
|
// clean on unmount
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -306,12 +314,13 @@ const DocumentInfo: React.FC<
|
|||||||
hasPublishPermission,
|
hasPublishPermission,
|
||||||
hasSavePermission,
|
hasSavePermission,
|
||||||
incrementVersionCount,
|
incrementVersionCount,
|
||||||
initialData: data,
|
initialData,
|
||||||
initialState,
|
initialState,
|
||||||
isInitializing,
|
isInitializing,
|
||||||
lastUpdateTime,
|
lastUpdateTime,
|
||||||
mostRecentVersionIsAutosaved,
|
mostRecentVersionIsAutosaved,
|
||||||
preferencesKey,
|
preferencesKey,
|
||||||
|
savedDocumentData,
|
||||||
setCurrentEditor,
|
setCurrentEditor,
|
||||||
setDocFieldPreferences,
|
setDocFieldPreferences,
|
||||||
setDocumentIsLocked,
|
setDocumentIsLocked,
|
||||||
@@ -324,6 +333,7 @@ const DocumentInfo: React.FC<
|
|||||||
unlockDocument,
|
unlockDocument,
|
||||||
unpublishedVersionCount,
|
unpublishedVersionCount,
|
||||||
updateDocumentEditor,
|
updateDocumentEditor,
|
||||||
|
updateSavedDocumentData,
|
||||||
versionCount,
|
versionCount,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -57,6 +57,7 @@ export type DocumentInfoContext = {
|
|||||||
lastUpdateTime?: number
|
lastUpdateTime?: number
|
||||||
mostRecentVersionIsAutosaved: boolean
|
mostRecentVersionIsAutosaved: boolean
|
||||||
preferencesKey?: string
|
preferencesKey?: string
|
||||||
|
savedDocumentData?: Data
|
||||||
setCurrentEditor?: React.Dispatch<React.SetStateAction<ClientUser>>
|
setCurrentEditor?: React.Dispatch<React.SetStateAction<ClientUser>>
|
||||||
setDocFieldPreferences: (
|
setDocFieldPreferences: (
|
||||||
field: string,
|
field: string,
|
||||||
@@ -72,5 +73,6 @@ export type DocumentInfoContext = {
|
|||||||
unlockDocument: (docId: number | string, slug: string) => Promise<void>
|
unlockDocument: (docId: number | string, slug: string) => Promise<void>
|
||||||
unpublishedVersionCount: number
|
unpublishedVersionCount: number
|
||||||
updateDocumentEditor: (docId: number | string, slug: string, user: ClientUser) => Promise<void>
|
updateDocumentEditor: (docId: number | string, slug: string, user: ClientUser) => Promise<void>
|
||||||
|
updateSavedDocumentData: (data: Data) => void
|
||||||
versionCount: number
|
versionCount: number
|
||||||
} & DocumentInfoProps
|
} & DocumentInfoProps
|
||||||
|
|||||||
@@ -71,17 +71,18 @@ export const DefaultEditView: React.FC<ClientSideEditViewProps> = ({
|
|||||||
hasPublishPermission,
|
hasPublishPermission,
|
||||||
hasSavePermission,
|
hasSavePermission,
|
||||||
incrementVersionCount,
|
incrementVersionCount,
|
||||||
initialData: data,
|
|
||||||
initialState,
|
initialState,
|
||||||
isEditing,
|
isEditing,
|
||||||
isInitializing,
|
isInitializing,
|
||||||
lastUpdateTime,
|
lastUpdateTime,
|
||||||
redirectAfterDelete,
|
redirectAfterDelete,
|
||||||
redirectAfterDuplicate,
|
redirectAfterDuplicate,
|
||||||
|
savedDocumentData,
|
||||||
setCurrentEditor,
|
setCurrentEditor,
|
||||||
setDocumentIsLocked,
|
setDocumentIsLocked,
|
||||||
unlockDocument,
|
unlockDocument,
|
||||||
updateDocumentEditor,
|
updateDocumentEditor,
|
||||||
|
updateSavedDocumentData,
|
||||||
} = useDocumentInfo()
|
} = useDocumentInfo()
|
||||||
|
|
||||||
const {
|
const {
|
||||||
@@ -212,6 +213,10 @@ export const DefaultEditView: React.FC<ClientSideEditViewProps> = ({
|
|||||||
|
|
||||||
incrementVersionCount()
|
incrementVersionCount()
|
||||||
|
|
||||||
|
if (typeof updateSavedDocumentData === 'function') {
|
||||||
|
void updateSavedDocumentData(json?.doc || {})
|
||||||
|
}
|
||||||
|
|
||||||
if (typeof onSaveFromContext === 'function') {
|
if (typeof onSaveFromContext === 'function') {
|
||||||
void onSaveFromContext({
|
void onSaveFromContext({
|
||||||
...json,
|
...json,
|
||||||
@@ -238,6 +243,7 @@ export const DefaultEditView: React.FC<ClientSideEditViewProps> = ({
|
|||||||
await getDocPermissions(json)
|
await getDocPermissions(json)
|
||||||
},
|
},
|
||||||
[
|
[
|
||||||
|
updateSavedDocumentData,
|
||||||
reportUpdate,
|
reportUpdate,
|
||||||
id,
|
id,
|
||||||
entitySlug,
|
entitySlug,
|
||||||
@@ -479,7 +485,7 @@ export const DefaultEditView: React.FC<ClientSideEditViewProps> = ({
|
|||||||
SaveButton,
|
SaveButton,
|
||||||
SaveDraftButton,
|
SaveDraftButton,
|
||||||
}}
|
}}
|
||||||
data={data}
|
data={savedDocumentData}
|
||||||
disableActions={disableActions}
|
disableActions={disableActions}
|
||||||
disableCreate={disableCreate}
|
disableCreate={disableCreate}
|
||||||
hasPublishPermission={hasPublishPermission}
|
hasPublishPermission={hasPublishPermission}
|
||||||
@@ -521,7 +527,7 @@ export const DefaultEditView: React.FC<ClientSideEditViewProps> = ({
|
|||||||
className={`${baseClass}__auth`}
|
className={`${baseClass}__auth`}
|
||||||
collectionSlug={collectionConfig.slug}
|
collectionSlug={collectionConfig.slug}
|
||||||
disableLocalStrategy={collectionConfig.auth?.disableLocalStrategy}
|
disableLocalStrategy={collectionConfig.auth?.disableLocalStrategy}
|
||||||
email={data?.email}
|
email={savedDocumentData?.email}
|
||||||
loginWithUsername={auth?.loginWithUsername}
|
loginWithUsername={auth?.loginWithUsername}
|
||||||
operation={operation}
|
operation={operation}
|
||||||
readOnly={!hasSavePermission}
|
readOnly={!hasSavePermission}
|
||||||
@@ -529,7 +535,7 @@ export const DefaultEditView: React.FC<ClientSideEditViewProps> = ({
|
|||||||
setSchemaPathSegments={setSchemaPathSegments}
|
setSchemaPathSegments={setSchemaPathSegments}
|
||||||
setValidateBeforeSubmit={setValidateBeforeSubmit}
|
setValidateBeforeSubmit={setValidateBeforeSubmit}
|
||||||
useAPIKey={auth.useAPIKey}
|
useAPIKey={auth.useAPIKey}
|
||||||
username={data?.username}
|
username={savedDocumentData?.username}
|
||||||
verify={auth.verify}
|
verify={auth.verify}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|||||||
Reference in New Issue
Block a user