Files
klz-cables.com/.pnpm-store/v10/files/ea/3a5c475e513cc661fc0696b3a3feac7b74cb994d4afeb94d2974b1c4c0a8e6d32fb04a5a0325d99004f899841a16dbea29eb7961e3dc0d6b2230186323bd24
Marc Mintel 5397309103
Some checks failed
Build & Deploy / 🔍 Prepare (push) Successful in 20s
Build & Deploy / 🧪 QA (push) Failing after 34s
Build & Deploy / 🏗️ Build (push) Has started running
Build & Deploy / 🚀 Deploy (push) Has been cancelled
Build & Deploy / 🧪 Smoke Test (push) Has been cancelled
Build & Deploy / ⚡ Lighthouse (push) Has been cancelled
Build & Deploy / 🔔 Notify (push) Has been cancelled
fix(products): fix breadcrumbs and product filtering (backport from main)
2026-02-24 16:04:21 +01:00

529 lines
17 KiB
Plaintext

'use client';
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import { useModal } from '@faceless-ui/modal';
import { formatAdminURL } from 'payload/shared';
import * as qs from 'qs-esm';
import React from 'react';
import { toast } from 'sonner';
import { fieldReducer } from '../../../forms/Form/fieldReducer.js';
import { useEffectEvent } from '../../../hooks/useEffectEvent.js';
import { useConfig } from '../../../providers/Config/index.js';
import { useLocale } from '../../../providers/Locale/index.js';
import { useServerFunctions } from '../../../providers/ServerFunctions/index.js';
import { useTranslation } from '../../../providers/Translation/index.js';
import { useUploadHandlers } from '../../../providers/UploadHandlers/index.js';
import { hasSavePermission as getHasSavePermission } from '../../../utilities/hasSavePermission.js';
import { LoadingOverlay } from '../../Loading/index.js';
import { useLoadingOverlay } from '../../LoadingOverlay/index.js';
import { useBulkUpload } from '../index.js';
import { createFormData } from './createFormData.js';
import { formsManagementReducer } from './reducer.js';
const Context = /*#__PURE__*/React.createContext({
activeIndex: 0,
addFiles: () => Promise.resolve(),
bulkUpdateForm: () => null,
collectionSlug: '',
docPermissions: undefined,
documentSlots: {},
forms: [],
getFormDataRef: {
current: () => ({})
},
hasPublishPermission: false,
hasSavePermission: false,
hasSubmitted: false,
isInitializing: false,
removeFile: () => {},
saveAllDocs: () => Promise.resolve(),
setActiveIndex: () => 0,
setFormTotalErrorCount: () => {},
totalErrorCount: 0,
updateUploadEdits: () => {}
});
const initialState = {
activeIndex: 0,
forms: [],
totalErrorCount: 0
};
export function FormsManagerProvider({
children
}) {
const {
config
} = useConfig();
const {
routes: {
api
}
} = config;
const {
code
} = useLocale();
const {
i18n,
t
} = useTranslation();
const {
getDocumentSlots,
getFormState
} = useServerFunctions();
const {
getUploadHandler
} = useUploadHandlers();
const [documentSlots, setDocumentSlots] = React.useState({});
const [hasSubmitted, setHasSubmitted] = React.useState(false);
const [docPermissions, setDocPermissions] = React.useState();
const [hasSavePermission, setHasSavePermission] = React.useState(false);
const [hasPublishPermission, setHasPublishPermission] = React.useState(false);
const [hasInitializedState, setHasInitializedState] = React.useState(false);
const [hasInitializedDocPermissions, setHasInitializedDocPermissions] = React.useState(false);
const [isInitializing, setIsInitializing] = React.useState(false);
const [state, dispatch] = React.useReducer(formsManagementReducer, initialState);
const {
activeIndex,
forms,
totalErrorCount
} = state;
const formsRef = React.useRef(forms);
formsRef.current = forms;
const {
toggleLoadingOverlay
} = useLoadingOverlay();
const {
closeModal
} = useModal();
const {
collectionSlug,
drawerSlug,
initialFiles,
initialForms,
onSuccess,
setInitialFiles,
setInitialForms,
setSuccessfullyUploaded
} = useBulkUpload();
const [isUploading, setIsUploading] = React.useState(false);
const [loadingText, setLoadingText] = React.useState('');
const hasInitializedWithFiles = React.useRef(false);
const initialStateRef = React.useRef(null);
const getFormDataRef = React.useRef(() => ({}));
const baseAPIPath = formatAdminURL({
apiRoute: api,
path: ''
});
const actionURL = `${baseAPIPath}/${collectionSlug}`;
const initializeSharedDocPermissions = React.useCallback(async () => {
const params = {
locale: code || undefined
};
const docAccessURL = `/${collectionSlug}/access`;
const res = await fetch(`${baseAPIPath}${docAccessURL}?${qs.stringify(params)}`, {
credentials: 'include',
headers: {
'Accept-Language': i18n.language,
'Content-Type': 'application/json'
},
method: 'post'
});
const json = await res.json();
const publishedAccessJSON = await fetch(`${baseAPIPath}${docAccessURL}?${qs.stringify(params)}`, {
body: JSON.stringify({
_status: 'published'
}),
credentials: 'include',
headers: {
'Accept-Language': i18n.language,
'Content-Type': 'application/json'
},
method: 'POST'
}).then(res_0 => res_0.json());
setDocPermissions(json);
setHasSavePermission(getHasSavePermission({
collectionSlug,
docPermissions: json,
isEditing: false
}));
setHasPublishPermission(publishedAccessJSON?.update);
setHasInitializedDocPermissions(true);
}, [baseAPIPath, code, collectionSlug, i18n.language]);
const initializeSharedFormState = React.useCallback(async abortController => {
if (abortController?.signal) {
abortController.abort('aborting previous fetch for initial form state without files');
}
// FETCH AND SET THE DOCUMENT SLOTS HERE!
const documentSlots_0 = await getDocumentSlots({
collectionSlug
});
setDocumentSlots(documentSlots_0);
try {
const {
state: formStateWithoutFiles
} = await getFormState({
collectionSlug,
docPermissions,
docPreferences: {
fields: {}
},
locale: code,
operation: 'create',
renderAllFields: true,
schemaPath: collectionSlug,
skipValidation: true
});
initialStateRef.current = formStateWithoutFiles;
setHasInitializedState(true);
} catch (_err) {
// swallow error
}
}, [getDocumentSlots, collectionSlug, getFormState, docPermissions, code]);
const setActiveIndex = React.useCallback(index => {
const currentFormsData = getFormDataRef.current();
dispatch({
type: 'REPLACE',
state: {
activeIndex: index,
forms: forms.map((form, i) => {
if (i === activeIndex) {
return {
errorCount: form.errorCount,
formID: form.formID,
formState: currentFormsData,
uploadEdits: form.uploadEdits
};
}
return form;
})
}
});
}, [forms, activeIndex]);
const addFiles = React.useCallback(async files => {
if (forms.length) {
// save the state of the current form before adding new files
dispatch({
type: 'UPDATE_FORM',
errorCount: forms[activeIndex].errorCount,
formState: getFormDataRef.current(),
index: activeIndex
});
}
toggleLoadingOverlay({
isLoading: true,
key: 'addingDocs'
});
if (!hasInitializedState) {
await initializeSharedFormState();
}
dispatch({
type: 'ADD_FORMS',
forms: Array.from(files).map(file => ({
file,
initialState: initialStateRef.current
}))
});
toggleLoadingOverlay({
isLoading: false,
key: 'addingDocs'
});
}, [initializeSharedFormState, hasInitializedState, toggleLoadingOverlay, activeIndex, forms]);
const addFilesEffectEvent = useEffectEvent(addFiles);
const addInitialForms = useEffectEvent(async initialForms_0 => {
toggleLoadingOverlay({
isLoading: true,
key: 'addingDocs'
});
if (!hasInitializedState) {
await initializeSharedFormState();
}
dispatch({
type: 'ADD_FORMS',
forms: initialForms_0.map(form_0 => ({
...form_0,
initialState: form_0?.initialState || initialStateRef.current
}))
});
toggleLoadingOverlay({
isLoading: false,
key: 'addingDocs'
});
});
const removeFile = React.useCallback(index_0 => {
dispatch({
type: 'REMOVE_FORM',
index: index_0
});
}, []);
const setFormTotalErrorCount = React.useCallback(({
errorCount,
index: index_1
}) => {
dispatch({
type: 'UPDATE_ERROR_COUNT',
count: errorCount,
index: index_1
});
}, []);
const saveAllDocs = React.useCallback(async ({
overrides
} = {}) => {
const currentFormsData_0 = getFormDataRef.current();
const currentForms = [...forms];
currentForms[activeIndex] = {
errorCount: currentForms[activeIndex].errorCount,
formID: currentForms[activeIndex].formID,
formState: currentFormsData_0,
uploadEdits: currentForms[activeIndex].uploadEdits
};
const activeFormID = currentForms[activeIndex]?.formID;
const newDocs = [];
setIsUploading(true);
for (let i_0 = 0; i_0 < currentForms.length; i_0++) {
try {
const form_1 = currentForms[i_0];
const fileValue = form_1.formState?.file?.value;
setLoadingText(t('general:uploadingBulk', {
current: i_0 + 1,
total: currentForms.length
}));
const actionURLWithParams = `${actionURL}${qs.stringify({
locale: code,
uploadEdits: form_1?.uploadEdits || undefined
}, {
addQueryPrefix: true
})}`;
const req = await fetch(actionURLWithParams, {
body: await createFormData(form_1.formState, overrides, collectionSlug, getUploadHandler({
collectionSlug
})),
credentials: 'include',
method: 'POST'
});
const json_0 = await req.json();
if (req.status === 201 && json_0?.doc) {
newDocs.push({
collectionSlug,
doc: json_0.doc,
formID: form_1.formID
});
}
// should expose some sort of helper for this
const [fieldErrors, nonFieldErrors] = (json_0?.errors || []).reduce(([fieldErrs, nonFieldErrs], err) => {
const newFieldErrs = [];
const newNonFieldErrs = [];
if (err?.message) {
newNonFieldErrs.push(err);
}
if (Array.isArray(err?.data?.errors)) {
err.data?.errors.forEach(dataError => {
if (dataError?.path) {
newFieldErrs.push(dataError);
} else {
newNonFieldErrs.push(dataError);
}
});
}
return [[...fieldErrs, ...newFieldErrs], [...nonFieldErrs, ...newNonFieldErrs]];
}, [[], []]);
const missingFile = !fileValue && req.status === 400;
const exceedsLimit = fileValue && req.status === 413;
const missingFilename = fileValue && typeof fileValue === 'object' && 'name' in fileValue && (!fileValue.name || fileValue.name === '');
if (missingFile || exceedsLimit || missingFilename) {
currentForms[i_0].formState.file.valid = false;
// neeed to get the field state to extract count since field errors
// are not returned when file is missing or exceeds limit
const {
state: newState
} = await getFormState({
collectionSlug,
docPermissions,
docPreferences: null,
formState: currentForms[i_0].formState,
operation: 'update',
schemaPath: collectionSlug
});
currentForms[i_0] = {
errorCount: Object.values(newState).reduce((acc, value) => value?.valid === false ? acc + 1 : acc, 0),
formID: currentForms[i_0].formID,
formState: newState
};
toast.error(nonFieldErrors[0]?.message);
} else {
currentForms[i_0] = {
errorCount: fieldErrors.length,
formID: currentForms[i_0].formID,
formState: fieldReducer(currentForms[i_0].formState, {
type: 'ADD_SERVER_ERRORS',
errors: fieldErrors
})
};
}
} catch (_) {
// swallow
}
}
setHasSubmitted(true);
setLoadingText('');
setIsUploading(false);
const remainingForms = [];
currentForms.forEach(({
errorCount: errorCount_0
}, i_1) => {
if (errorCount_0) {
remainingForms.push(currentForms[i_1]);
}
});
const successCount = Math.max(0, currentForms.length - remainingForms.length);
const errorCount_1 = currentForms.length - successCount;
if (successCount) {
toast.success(`Successfully saved ${successCount} files`);
setSuccessfullyUploaded(true);
if (typeof onSuccess === 'function') {
onSuccess(newDocs, errorCount_1);
}
}
if (errorCount_1) {
toast.error(`Failed to save ${errorCount_1} files`);
} else {
closeModal(drawerSlug);
}
dispatch({
type: 'REPLACE',
state: {
activeIndex: remainingForms.reduce((acc_0, {
formID
}, i_2) => {
if (formID === activeFormID) {
return i_2;
}
return acc_0;
}, 0),
forms: remainingForms,
totalErrorCount: remainingForms.reduce((acc_1, {
errorCount: errorCount_2
}) => acc_1 + errorCount_2, 0)
}
});
if (remainingForms.length === 0) {
setInitialFiles(undefined);
setInitialForms(undefined);
}
}, [forms, activeIndex, t, actionURL, code, collectionSlug, getUploadHandler, getFormState, docPermissions, setSuccessfullyUploaded, onSuccess, closeModal, drawerSlug, setInitialFiles, setInitialForms]);
const bulkUpdateForm = React.useCallback(async (updatedFields, afterStateUpdate) => {
for (let i_3 = 0; i_3 < forms.length; i_3++) {
Object.entries(updatedFields).forEach(([path, value_0]) => {
if (forms[i_3].formState[path]) {
forms[i_3].formState[path].value = value_0;
dispatch({
type: 'UPDATE_FORM',
errorCount: forms[i_3].errorCount,
formState: forms[i_3].formState,
index: i_3
});
}
});
if (typeof afterStateUpdate === 'function') {
afterStateUpdate();
}
if (hasSubmitted) {
const {
state: state_0
} = await getFormState({
collectionSlug,
docPermissions,
docPreferences: null,
formState: forms[i_3].formState,
operation: 'create',
schemaPath: collectionSlug
});
const newFormErrorCount = Object.values(state_0).reduce((acc_2, value_1) => value_1?.valid === false ? acc_2 + 1 : acc_2, 0);
dispatch({
type: 'UPDATE_FORM',
errorCount: newFormErrorCount,
formState: state_0,
index: i_3
});
}
}
}, [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_2 => ({
...form_2,
uploadEdits: {}
}))
}
});
}, [forms]);
React.useEffect(() => {
if (!collectionSlug) {
return;
}
if (!hasInitializedState) {
void initializeSharedFormState();
}
if (!hasInitializedDocPermissions) {
void initializeSharedDocPermissions();
}
if (initialFiles || initialForms) {
if (!hasInitializedState || !hasInitializedDocPermissions) {
setIsInitializing(true);
} else {
setIsInitializing(false);
}
}
if (hasInitializedState && (initialForms?.length || initialFiles?.length) && !hasInitializedWithFiles.current) {
if (initialForms?.length) {
void addInitialForms(initialForms);
}
if (initialFiles?.length) {
void addFilesEffectEvent(initialFiles);
}
hasInitializedWithFiles.current = true;
}
return;
}, [initialFiles, initializeSharedFormState, initializeSharedDocPermissions, collectionSlug, hasInitializedState, hasInitializedDocPermissions, initialForms]);
return /*#__PURE__*/_jsxs(Context, {
value: {
activeIndex: state.activeIndex,
addFiles,
bulkUpdateForm,
collectionSlug,
docPermissions,
documentSlots,
forms,
getFormDataRef,
hasPublishPermission,
hasSavePermission,
hasSubmitted,
isInitializing,
removeFile,
resetUploadEdits,
saveAllDocs,
setActiveIndex,
setFormTotalErrorCount,
totalErrorCount,
updateUploadEdits
},
children: [isUploading && /*#__PURE__*/_jsx(LoadingOverlay, {
animationDuration: "250ms",
loadingText: loadingText,
overlayType: "fullscreen",
show: true
}), children]
});
}
export function useFormsManager() {
return React.use(Context);
}
//# sourceMappingURL=index.js.map