Merge branch 'feat/duplicate-all-locales' of github.com:payloadcms/payload into feat/duplicate-all-locales
This commit is contained in:
@@ -0,0 +1,22 @@
|
||||
@import '../../../scss/styles.scss';
|
||||
|
||||
.duplicate {
|
||||
|
||||
&__modal {
|
||||
@include blur-bg;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 100%;
|
||||
|
||||
.btn {
|
||||
margin-right: $baseline;
|
||||
}
|
||||
}
|
||||
|
||||
&__modal-template {
|
||||
z-index: 1;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -1,39 +1,143 @@
|
||||
import React, { useCallback } from 'react';
|
||||
import React, { useCallback, useState } from 'react';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
import { toast } from 'react-toastify';
|
||||
import { Modal, useModal } from '@faceless-ui/modal';
|
||||
import { useConfig } from '../../utilities/Config';
|
||||
import { Props } from './types';
|
||||
import Button from '../Button';
|
||||
import { useForm } from '../../forms/Form/context';
|
||||
import { requests } from '../../../api';
|
||||
import { useForm, useFormModified } from '../../forms/Form/context';
|
||||
import MinimalTemplate from '../../templates/Minimal';
|
||||
|
||||
import './index.scss';
|
||||
|
||||
const baseClass = 'duplicate';
|
||||
|
||||
const Duplicate: React.FC<Props> = ({ slug }) => {
|
||||
const Duplicate: React.FC<Props> = ({ slug, collection, id }) => {
|
||||
const { push } = useHistory();
|
||||
const { getData } = useForm();
|
||||
const modified = useFormModified();
|
||||
const { toggle } = useModal();
|
||||
const { setModified } = useForm();
|
||||
const { serverURL, routes: { api }, localization } = useConfig();
|
||||
const { routes: { admin } } = useConfig();
|
||||
const [hasClicked, setHasClicked] = useState<boolean>(false);
|
||||
|
||||
const handleClick = useCallback(() => {
|
||||
const data = getData();
|
||||
const modalSlug = `duplicate-${id}`;
|
||||
|
||||
push({
|
||||
pathname: `${admin}/collections/${slug}/create`,
|
||||
state: {
|
||||
data,
|
||||
},
|
||||
});
|
||||
}, [push, getData, slug, admin]);
|
||||
const handleClick = useCallback(async (override = false) => {
|
||||
setHasClicked(true);
|
||||
|
||||
if (modified && !override) {
|
||||
toggle(modalSlug);
|
||||
return;
|
||||
}
|
||||
|
||||
const create = async (locale?: string): Promise<string | null> => {
|
||||
const localeParam = locale ? `locale=${locale}` : '';
|
||||
const response = await requests.get(`${serverURL}${api}/${slug}/${id}?${localeParam}`);
|
||||
const data = await response.json();
|
||||
const result = await requests.post(`${serverURL}${api}/${slug}`, {
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify(data),
|
||||
});
|
||||
const json = await result.json();
|
||||
|
||||
if (result.status === 201) {
|
||||
return json.doc.id;
|
||||
}
|
||||
json.errors.forEach((error) => toast.error(error.message));
|
||||
return null;
|
||||
};
|
||||
|
||||
let duplicateID;
|
||||
if (localization) {
|
||||
duplicateID = await create(localization.defaultLocale);
|
||||
let abort = false;
|
||||
localization.locales
|
||||
.filter((locale) => locale !== localization.defaultLocale)
|
||||
.forEach(async (locale) => {
|
||||
if (!abort) {
|
||||
const res = await requests.get(`${serverURL}${api}/${slug}/${id}?locale=${locale}`);
|
||||
const localizedDoc = await res.json();
|
||||
const patchResult = await requests.patch(`${serverURL}${api}/${slug}/${duplicateID}?locale=${locale}`, {
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify(localizedDoc),
|
||||
});
|
||||
if (patchResult.status > 400) {
|
||||
abort = true;
|
||||
const json = await patchResult.json();
|
||||
json.errors.forEach((error) => toast.error(error.message));
|
||||
}
|
||||
}
|
||||
});
|
||||
if (abort) {
|
||||
// delete the duplicate doc to prevent incomplete
|
||||
await requests.delete(`${serverURL}${api}/${slug}/${id}`);
|
||||
}
|
||||
} else {
|
||||
duplicateID = await create();
|
||||
}
|
||||
|
||||
toast.success(`${collection.labels.singular} successfully duplicated.`,
|
||||
{ autoClose: 3000 });
|
||||
|
||||
const previousModifiedState = modified;
|
||||
setModified(false);
|
||||
setTimeout(() => {
|
||||
push({
|
||||
pathname: `${admin}/collections/${slug}/${duplicateID}`,
|
||||
});
|
||||
setModified(previousModifiedState);
|
||||
}, 10);
|
||||
}, [modified, localization, collection.labels.singular, setModified, toggle, modalSlug, serverURL, api, slug, id, push, admin]);
|
||||
|
||||
const confirm = useCallback(async () => {
|
||||
setHasClicked(false);
|
||||
await handleClick(true);
|
||||
}, [handleClick]);
|
||||
|
||||
return (
|
||||
<Button
|
||||
id="action-duplicate"
|
||||
buttonStyle="none"
|
||||
className={baseClass}
|
||||
onClick={handleClick}
|
||||
>
|
||||
Duplicate
|
||||
</Button>
|
||||
<React.Fragment>
|
||||
<Button
|
||||
id="action-duplicate"
|
||||
buttonStyle="none"
|
||||
className={baseClass}
|
||||
onClick={() => handleClick(false)}
|
||||
>
|
||||
Duplicate
|
||||
</Button>
|
||||
{ modified && hasClicked && (
|
||||
<Modal
|
||||
slug={modalSlug}
|
||||
className={`${baseClass}__modal`}
|
||||
>
|
||||
<MinimalTemplate className={`${baseClass}__modal-template`}>
|
||||
<h1>Confirm duplicate</h1>
|
||||
<p>
|
||||
You have unsaved changes. Would you like to continue to duplicate?
|
||||
</p>
|
||||
<Button
|
||||
id="confirm-cancel"
|
||||
buttonStyle="secondary"
|
||||
type="button"
|
||||
onClick={() => toggle(modalSlug)}
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
<Button
|
||||
onClick={confirm}
|
||||
id="confirm-duplicate"
|
||||
>
|
||||
Duplicate without saving changes
|
||||
</Button>
|
||||
</MinimalTemplate>
|
||||
</Modal>
|
||||
) }
|
||||
</React.Fragment>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
import { SanitizedCollectionConfig } from '../../../../collections/config/types';
|
||||
|
||||
export type Props = {
|
||||
slug: string,
|
||||
slug: string
|
||||
collection: SanitizedCollectionConfig
|
||||
id: string
|
||||
}
|
||||
|
||||
@@ -142,8 +142,14 @@ const DefaultEditView: React.FC<Props> = (props) => {
|
||||
Create New
|
||||
</Link>
|
||||
</li>
|
||||
{!disableDuplicate && (
|
||||
<li><DuplicateDocument slug={slug} /></li>
|
||||
{!disableDuplicate && isEditing && (
|
||||
<li>
|
||||
<DuplicateDocument
|
||||
collection={collection}
|
||||
id={id}
|
||||
slug={slug}
|
||||
/>
|
||||
</li>
|
||||
)}
|
||||
</React.Fragment>
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user