diff --git a/packages/ui/src/elements/BulkUpload/AddingFilesView/index.tsx b/packages/ui/src/elements/BulkUpload/AddingFilesView/index.tsx index db59591822a..20a1952aca4 100644 --- a/packages/ui/src/elements/BulkUpload/AddingFilesView/index.tsx +++ b/packages/ui/src/elements/BulkUpload/AddingFilesView/index.tsx @@ -29,6 +29,8 @@ export function AddingFilesView() { hasPublishPermission, hasSavePermission, hasSubmitted, + resetUploadEdits, + updateUploadEdits, } = useFormsManager() const activeForm = forms[activeIndex] const { getEntityConfig } = useConfig() @@ -67,7 +69,12 @@ export function AddingFilesView() { versionCount={0} > - + ) : null} diff --git a/packages/ui/src/elements/BulkUpload/EditForm/index.tsx b/packages/ui/src/elements/BulkUpload/EditForm/index.tsx index 7c186d498bf..f1c4da6c28a 100644 --- a/packages/ui/src/elements/BulkUpload/EditForm/index.tsx +++ b/packages/ui/src/elements/BulkUpload/EditForm/index.tsx @@ -16,11 +16,10 @@ import { useEditDepth } from '../../../providers/EditDepth/index.js' import { OperationProvider } from '../../../providers/Operation/index.js' import { useRouteTransition } from '../../../providers/RouteTransition/index.js' import { useServerFunctions } from '../../../providers/ServerFunctions/index.js' -import { useUploadEdits } from '../../../providers/UploadEdits/index.js' import { abortAndIgnore, handleAbortRef } from '../../../utilities/abortAndIgnore.js' import { useDocumentDrawerContext } from '../../DocumentDrawer/Provider.js' import { DocumentFields } from '../../DocumentFields/index.js' -import { Upload } from '../../Upload/index.js' +import { Upload_v4 } from '../../Upload/index.js' import { useFormsManager } from '../FormsManager/index.js' import { BulkUploadProvider } from '../index.js' import './index.scss' @@ -31,7 +30,12 @@ const baseClass = 'collection-edit' // When rendered within a drawer, props are empty // This is solely to support custom edit views which get server-rendered -export function EditForm({ submitted }: EditFormProps) { +export function EditForm({ + resetUploadEdits, + submitted, + updateUploadEdits, + uploadEdits, +}: EditFormProps) { const { action, collectionSlug: docSlug, @@ -62,7 +66,6 @@ export function EditForm({ submitted }: EditFormProps) { const depth = useEditDepth() const params = useSearchParams() const { reportUpdate } = useDocumentEvents() - const { resetUploadEdits } = useUploadEdits() const { startRouteTransition } = useRouteTransition() const locale = params.get('locale') @@ -161,10 +164,13 @@ export function EditForm({ submitted }: EditFormProps) { BeforeFields={ {CustomUpload || ( - )} @@ -185,7 +191,7 @@ function GetFieldProxy() { const { getFields } = useForm() const { getFormDataRef } = useFormsManager() - React.useEffect(() => { + useEffect(() => { getFormDataRef.current = getFields }, [getFields, getFormDataRef]) diff --git a/packages/ui/src/elements/BulkUpload/EditForm/types.ts b/packages/ui/src/elements/BulkUpload/EditForm/types.ts index 19083a07103..d975483a955 100644 --- a/packages/ui/src/elements/BulkUpload/EditForm/types.ts +++ b/packages/ui/src/elements/BulkUpload/EditForm/types.ts @@ -1,3 +1,5 @@ +import type { UploadProps_v4 } from '../../Upload/index.js' + export type EditFormProps = { readonly submitted?: boolean -} +} & Pick diff --git a/packages/ui/src/elements/BulkUpload/FormsManager/index.tsx b/packages/ui/src/elements/BulkUpload/FormsManager/index.tsx index 713e25d98da..21159e87665 100644 --- a/packages/ui/src/elements/BulkUpload/FormsManager/index.tsx +++ b/packages/ui/src/elements/BulkUpload/FormsManager/index.tsx @@ -1,6 +1,12 @@ 'use client' -import type { Data, DocumentSlots, FormState, SanitizedDocumentPermissions } from 'payload' +import type { + Data, + DocumentSlots, + FormState, + SanitizedDocumentPermissions, + UploadEdits, +} from 'payload' import { useModal } from '@faceless-ui/modal' import { isImage } from 'payload/shared' @@ -41,6 +47,7 @@ type FormsManagerContext = { readonly hasSubmitted: boolean readonly isInitializing: boolean readonly removeFile: (index: number) => void + readonly resetUploadEdits?: () => void readonly saveAllDocs: ({ overrides }?: { overrides?: Record }) => Promise readonly setActiveIndex: (index: number) => void readonly setFormTotalErrorCount: ({ @@ -52,6 +59,7 @@ type FormsManagerContext = { }) => void readonly thumbnailUrls: string[] readonly totalErrorCount?: number + readonly updateUploadEdits: (args: UploadEdits) => void } const Context = React.createContext({ @@ -73,6 +81,7 @@ const Context = React.createContext({ setFormTotalErrorCount: () => {}, thumbnailUrls: [], totalErrorCount: 0, + updateUploadEdits: () => {}, }) const initialState: State = { @@ -242,6 +251,7 @@ export function FormsManagerProvider({ children }: FormsManagerProps) { return { errorCount: form.errorCount, formState: currentFormsData, + uploadEdits: form.uploadEdits, } } return form @@ -295,6 +305,7 @@ export function FormsManagerProvider({ children }: FormsManagerProps) { currentForms[activeIndex] = { errorCount: currentForms[activeIndex].errorCount, formState: currentFormsData, + uploadEdits: currentForms[activeIndex].uploadEdits, } const newDocs = [] @@ -306,7 +317,16 @@ export function FormsManagerProvider({ children }: FormsManagerProps) { setLoadingText(t('general:uploadingBulk', { current: i + 1, total: currentForms.length })) - const req = await fetch(actionURL, { + const actionURLWithParams = `${actionURL}${qs.stringify( + { + uploadEdits: form?.uploadEdits || undefined, + }, + { + addQueryPrefix: true, + }, + )}` + + const req = await fetch(actionURLWithParams, { body: await createFormData( form.formState, overrides, @@ -478,6 +498,31 @@ export function FormsManagerProvider({ children }: FormsManagerProps) { [collectionSlug, docPermissions, forms, getFormState, hasSubmitted], ) + const updateUploadEdits = React.useCallback( + (uploadEdits) => { + dispatch({ + type: 'UPDATE_FORM', + errorCount: forms[activeIndex].errorCount, + formState: forms[activeIndex].formState, + index: activeIndex, + uploadEdits, + }) + }, + [activeIndex, forms], + ) + + const resetUploadEdits = React.useCallback(() => { + dispatch({ + type: 'REPLACE', + state: { + forms: forms.map((form) => ({ + ...form, + uploadEdits: {}, + })), + }, + }) + }, [forms]) + React.useEffect(() => { if (!collectionSlug) { return @@ -529,11 +574,13 @@ export function FormsManagerProvider({ children }: FormsManagerProps) { hasSubmitted, isInitializing, removeFile, + resetUploadEdits, saveAllDocs, setActiveIndex, setFormTotalErrorCount, thumbnailUrls: renderedThumbnails, totalErrorCount, + updateUploadEdits, }} > {isUploading && ( diff --git a/packages/ui/src/elements/BulkUpload/FormsManager/reducer.ts b/packages/ui/src/elements/BulkUpload/FormsManager/reducer.ts index 8d2662709f1..cbbe28a9f75 100644 --- a/packages/ui/src/elements/BulkUpload/FormsManager/reducer.ts +++ b/packages/ui/src/elements/BulkUpload/FormsManager/reducer.ts @@ -1,10 +1,11 @@ -import type { FormState } from 'payload' +import type { FormState, UploadEdits } from 'payload' export type State = { activeIndex: number forms: { errorCount: number formState: FormState + uploadEdits?: UploadEdits }[] totalErrorCount: number } @@ -21,6 +22,7 @@ type Action = index: number type: 'UPDATE_FORM' updatedFields?: Record + uploadEdits?: UploadEdits } | { files: FileList @@ -55,6 +57,7 @@ export function formsManagementReducer(state: State, action: Action): State { value: action.files[i], }, }, + uploadEdits: {}, } } @@ -117,6 +120,10 @@ export function formsManagementReducer(state: State, action: Action): State { ...updatedForms[action.index].formState, ...action.formState, }, + uploadEdits: { + ...updatedForms[action.index].uploadEdits, + ...action.uploadEdits, + }, } return { diff --git a/packages/ui/src/elements/Upload/index.tsx b/packages/ui/src/elements/Upload/index.tsx index 9316ff3ba4f..1796d4d3b5c 100644 --- a/packages/ui/src/elements/Upload/index.tsx +++ b/packages/ui/src/elements/Upload/index.tsx @@ -19,9 +19,9 @@ import { Drawer, DrawerToggler } from '../Drawer/index.js' import { Dropzone } from '../Dropzone/index.js' import { EditUpload } from '../EditUpload/index.js' import { FileDetails } from '../FileDetails/index.js' -import './index.scss' import { PreviewSizes } from '../PreviewSizes/index.js' import { Thumbnail } from '../Thumbnail/index.js' +import './index.scss' const baseClass = 'file-field' export const editDrawerSlug = 'edit-upload' @@ -91,7 +91,34 @@ export type UploadProps = { } export const Upload: React.FC = (props) => { - const { collectionSlug, customActions, initialState, onChange, uploadConfig } = props + const { resetUploadEdits, updateUploadEdits, uploadEdits } = useUploadEdits() + return ( + + ) +} + +export type UploadProps_v4 = { + readonly resetUploadEdits?: () => void + readonly updateUploadEdits?: (args: UploadEdits) => void + readonly uploadEdits?: UploadEdits +} & UploadProps + +export const Upload_v4: React.FC = (props) => { + const { + collectionSlug, + customActions, + initialState, + onChange, + resetUploadEdits, + updateUploadEdits, + uploadConfig, + uploadEdits, + } = props const { config: { @@ -102,7 +129,6 @@ export const Upload: React.FC = (props) => { const { t } = useTranslation() const { setModified } = useForm() - const { resetUploadEdits, updateUploadEdits, uploadEdits } = useUploadEdits() const { id, docPermissions, savedDocumentData, setUploadStatus } = useDocumentInfo() const isFormSubmitting = useFormProcessing() const { errorMessage, setValue, showError, value } = useField({ diff --git a/packages/ui/src/providers/UploadEdits/index.tsx b/packages/ui/src/providers/UploadEdits/index.tsx index 3f45a0dc373..610b83223c2 100644 --- a/packages/ui/src/providers/UploadEdits/index.tsx +++ b/packages/ui/src/providers/UploadEdits/index.tsx @@ -3,20 +3,26 @@ import type { UploadEdits } from 'payload' import React from 'react' +export type UploadEditsProviderProps = { + children: React.ReactNode + initialUploadEdits?: UploadEdits +} export type UploadEditsContext = { + getUploadEdits: () => UploadEdits resetUploadEdits: () => void updateUploadEdits: (edits: UploadEdits) => void uploadEdits: UploadEdits } const Context = React.createContext({ + getUploadEdits: () => undefined, resetUploadEdits: undefined, updateUploadEdits: undefined, uploadEdits: undefined, }) -export const UploadEditsProvider = ({ children }) => { - const [uploadEdits, setUploadEdits] = React.useState(undefined) +export const UploadEditsProvider = ({ children, initialUploadEdits }: UploadEditsProviderProps) => { + const [uploadEdits, setUploadEdits] = React.useState(initialUploadEdits || {}) const resetUploadEdits = () => { setUploadEdits({}) @@ -29,7 +35,13 @@ export const UploadEditsProvider = ({ children }) => { })) } - return {children} + const getUploadEdits = () => uploadEdits + + return ( + + {children} + + ) } export const useUploadEdits = (): UploadEditsContext => React.use(Context) diff --git a/packages/ui/src/views/Edit/index.tsx b/packages/ui/src/views/Edit/index.tsx index 78a054cb396..3abe9f8cbfd 100644 --- a/packages/ui/src/views/Edit/index.tsx +++ b/packages/ui/src/views/Edit/index.tsx @@ -325,6 +325,7 @@ export function DefaultEditView({ isLockingEnabled, setDocumentIsLocked, startRouteTransition, + redirectAfterCreate, ], )