Merge branch 'feat/duplicate-all-locales' of github.com:payloadcms/payload into feat/duplicate-all-locales

This commit is contained in:
James
2022-08-30 14:52:51 -07:00
5 changed files with 196 additions and 24 deletions

View File

@@ -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;
}
}

View File

@@ -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>
);
};

View File

@@ -1,3 +1,7 @@
import { SanitizedCollectionConfig } from '../../../../collections/config/types';
export type Props = {
slug: string,
slug: string
collection: SanitizedCollectionConfig
id: string
}

View File

@@ -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>
)}