feat: retrofits DocumentDrawer into relationship AddNew

This commit is contained in:
Jacob Fletcher
2022-12-01 16:34:05 -05:00
parent 670e5243a9
commit 475f147f2c
5 changed files with 82 additions and 312 deletions

View File

@@ -1,117 +0,0 @@
@import '../../../../../../scss/styles.scss';
.relationship-add-new-modal {
display: flex;
overflow: hidden;
position: fixed;
height: 100vh;
&__blur-bg {
@include blur-bg();
position: absolute;
z-index: 1;
top: 0;
right: 0;
bottom: 0;
left: 0;
opacity: 0;
transition: all 300ms ease-out;
}
.collection-edit {
@include blur-bg();
transform: translateX(#{base(4)});
opacity: 0;
transition: all 300ms ease-out;
position: relative;
z-index: 2;
}
.collection-edit__form {
overflow: auto;
position: relative;
z-index: 1;
}
.collection-edit__document-actions {
&:before,
&:after {
content: none;
}
}
&--animated {
.collection-edit,
.relationship-add-new-modal__blur-bg,
.relationship-add-new-modal__close {
opacity: 1;
}
.collection-edit {
transform: translateX(0);
}
}
.collection-edit__document-actions {
margin-top: base(2.75);
}
&__close {
@extend %btn-reset;
position: relative;
z-index: 2;
flex-shrink: 0;
text-indent: -9999px;
background: rgba(0, 0, 0, 0.08);
cursor: pointer;
opacity: 0;
transition: all 300ms ease-in-out;
transition-delay: 100ms;
&:active,
&:focus {
outline: 0;
}
}
&__header {
display: flex;
justify-content: space-between;
align-items: flex-start;
margin-top: base(2.5);
}
&__header-close {
svg {
width: base(2.5);
height: base(2.5);
position: relative;
top: base(-.5);
right: base(-.75);
.stroke {
stroke-width: .5px;
}
}
}
@include mid-break {
&__header-close {
svg {
top: base(-.75);
}
}
&__close {
width: base(1);
}
}
}
html[data-theme=dark] {
.relationship-add-new-modal__close {
background: rgba(0, 0, 0, 0.2);
}
}

View File

@@ -1,110 +0,0 @@
import React, { useEffect, useState } from 'react';
import { Modal, useModal } from '@faceless-ui/modal';
import { useWindowInfo } from '@faceless-ui/window-info';
import { useTranslation } from 'react-i18next';
import Button from '../../../../../elements/Button';
import { Props } from './types';
import { useAuth } from '../../../../../utilities/Auth';
import RenderCustomComponent from '../../../../../utilities/RenderCustomComponent';
import { useLocale } from '../../../../../utilities/Locale';
import { useConfig } from '../../../../../utilities/Config';
import DefaultEdit from '../../../../../views/collections/Edit/Default';
import X from '../../../../../icons/X';
import { Fields } from '../../../../Form/types';
import buildStateFromSchema from '../../../../Form/buildStateFromSchema';
import { EditDepthContext, useEditDepth } from '../../../../../utilities/EditDepth';
import { getTranslation } from '../../../../../../../utilities/getTranslation';
import { DocumentInfoProvider } from '../../../../../utilities/DocumentInfo';
import './index.scss';
const baseClass = 'relationship-add-new-modal';
export const AddNewRelationModal: React.FC<Props> = ({ modalCollection, onSave, modalSlug }) => {
const { serverURL, routes: { api } } = useConfig();
const { toggleModal } = useModal();
const { breakpoints: { m: midBreak } } = useWindowInfo();
const locale = useLocale();
const { permissions, user } = useAuth();
const [initialState, setInitialState] = useState<Fields>();
const [isAnimated, setIsAnimated] = useState(false);
const editDepth = useEditDepth();
const { t, i18n } = useTranslation('fields');
const modalAction = `${serverURL}${api}/${modalCollection.slug}?locale=${locale}&depth=0&fallback-locale=null`;
useEffect(() => {
const buildState = async () => {
const state = await buildStateFromSchema({ fieldSchema: modalCollection.fields, data: {}, user, operation: 'create', locale, t });
setInitialState(state);
};
buildState();
}, [modalCollection, locale, user, t]);
useEffect(() => {
setIsAnimated(true);
}, []);
return (
<Modal
slug={modalSlug}
className={[
baseClass,
isAnimated && `${baseClass}--animated`,
].filter(Boolean).join(' ')}
>
{editDepth === 1 && (
<div className={`${baseClass}__blur-bg`} />
)}
<DocumentInfoProvider collection={modalCollection}>
<EditDepthContext.Provider value={editDepth + 1}>
<button
className={`${baseClass}__close`}
type="button"
onClick={() => toggleModal(modalSlug)}
style={{
width: `calc(${midBreak ? 'var(--gutter-h)' : 'var(--nav-width)'} + ${editDepth - 1} * 25px)`,
}}
>
<span>
Close
</span>
</button>
<RenderCustomComponent
DefaultComponent={DefaultEdit}
CustomComponent={modalCollection.admin?.components?.views?.Edit}
componentProps={{
isLoading: !initialState,
data: {},
collection: modalCollection,
permissions: permissions.collections[modalCollection.slug],
isEditing: false,
onSave,
initialState,
hasSavePermission: true,
action: modalAction,
disableEyebrow: true,
disableActions: true,
disableLeaveWithoutSaving: true,
customHeader: (
<div className={`${baseClass}__header`}>
<h2>
{t('addNewLabel', { label: getTranslation(modalCollection.labels.singular, i18n) })}
</h2>
<Button
buttonStyle="none"
className={`${baseClass}__header-close`}
onClick={() => toggleModal(modalSlug)}
>
<X />
</Button>
</div>
),
}}
/>
</EditDepthContext.Provider>
</DocumentInfoProvider>
</Modal>
);
};

View File

@@ -1,7 +0,0 @@
import { SanitizedCollectionConfig } from '../../../../../../../collections/config/types';
export type Props = {
modalSlug: string
modalCollection: SanitizedCollectionConfig
onSave: (json: Record<string, unknown>) => void
}

View File

@@ -12,28 +12,16 @@
&__add-button {
@include formInput;
position: relative;
height: 100%;
margin-left: -1px;
display: flex;
padding: 0;
.btn__content,
.btn__label {
display: flex;
}
.btn__content,
.btn__label {
height: 100%;
}
.btn__label {
padding: 0 base(.5);
align-items: center;
}
padding: 0 base(0.5);
align-items: center;
display: flex;
cursor: pointer;
}
&__relations {
list-style: none;
margin: 0;
@@ -57,4 +45,4 @@
opacity: .7;
}
}
}
}

View File

@@ -1,4 +1,4 @@
import React, { useCallback, useEffect, useState } from 'react';
import React, { Fragment, useCallback, useEffect, useState } from 'react';
import { useModal } from '@faceless-ui/modal';
import { useTranslation } from 'react-i18next';
import Button from '../../../../elements/Button';
@@ -7,10 +7,11 @@ import { SanitizedCollectionConfig } from '../../../../../../collections/config/
import Popup from '../../../../elements/Popup';
import { useRelatedCollections } from './useRelatedCollections';
import { useAuth } from '../../../../utilities/Auth';
import { AddNewRelationModal } from './Modal';
import { useEditDepth } from '../../../../utilities/EditDepth';
import Plus from '../../../../icons/Plus';
import { getTranslation } from '../../../../../../utilities/getTranslation';
import { DocumentDrawer, DocumentDrawerToggler } from '../../../../elements/DocumentDrawer';
import Tooltip from '../../../../elements/Tooltip';
import './index.scss';
@@ -18,30 +19,26 @@ const baseClass = 'relationship-add-new';
export const AddNewRelation: React.FC<Props> = ({ path, hasMany, relationTo, value, setValue, dispatchOptions }) => {
const relatedCollections = useRelatedCollections(relationTo);
const { toggleModal, isModalOpen } = useModal();
const { isModalOpen } = useModal();
const { permissions } = useAuth();
const [hasPermission, setHasPermission] = useState(false);
const [modalCollection, setModalCollection] = useState<SanitizedCollectionConfig>();
const [selectedCollection, setSelectedCollection] = useState<SanitizedCollectionConfig>();
const [popupOpen, setPopupOpen] = useState(false);
const editDepth = useEditDepth();
const { t, i18n } = useTranslation('fields');
const [showTooltip, setShowTooltip] = useState(false);
const modalSlug = `${path}-add-modal-depth-${editDepth}`;
const openModal = useCallback(async (collection: SanitizedCollectionConfig) => {
setModalCollection(collection);
toggleModal(modalSlug);
}, [toggleModal, modalSlug]);
const onSave = useCallback((json) => {
const newValue = Array.isArray(relationTo) ? {
relationTo: modalCollection.slug,
relationTo: selectedCollection.slug,
value: json.doc.id,
} : json.doc.id;
dispatchOptions({
type: 'ADD',
collection: modalCollection,
collection: selectedCollection,
docs: [
json.doc,
],
@@ -55,9 +52,9 @@ export const AddNewRelation: React.FC<Props> = ({ path, hasMany, relationTo, val
setValue(newValue);
}
setModalCollection(undefined);
toggleModal(modalSlug);
}, [relationTo, modalCollection, dispatchOptions, i18n, hasMany, toggleModal, modalSlug, setValue, value]);
setSelectedCollection(undefined);
// toggleModal(modalSlug);
}, [relationTo, selectedCollection, dispatchOptions, i18n, hasMany, setValue, value]);
const onPopopToggle = useCallback((state) => {
setPopupOpen(state);
@@ -75,7 +72,7 @@ export const AddNewRelation: React.FC<Props> = ({ path, hasMany, relationTo, val
useEffect(() => {
if (!isModalOpen(modalSlug)) {
setModalCollection(undefined);
setSelectedCollection(undefined);
}
}, [isModalOpen, modalSlug]);
@@ -85,56 +82,75 @@ export const AddNewRelation: React.FC<Props> = ({ path, hasMany, relationTo, val
id={`${path}-add-new`}
>
{relatedCollections.length === 1 && (
<Button
className={`${baseClass}__add-button`}
onClick={() => openModal(relatedCollections[0])}
buttonStyle="none"
tooltip={t('addNewLabel', { label: relatedCollections[0].labels.singular })}
>
<Plus />
</Button>
<Fragment>
<DocumentDrawerToggler
className={`${baseClass}__add-button`}
collection={relatedCollections[0].slug}
onMouseEnter={() => setShowTooltip(true)}
onMouseLeave={() => setShowTooltip(false)}
>
{showTooltip && (
<Tooltip className={`${baseClass}__tooltip`}>
{t('addNewLabel', { label: relatedCollections[0].labels.singular })}
</Tooltip>
)}
<Plus />
</DocumentDrawerToggler>
{relatedCollections[0] && (
<DocumentDrawer
collection={relatedCollections[0].slug}
onSave={onSave}
/>
)}
</Fragment>
)}
{relatedCollections.length > 1 && (
<Popup
buttonType="custom"
horizontalAlign="center"
onToggleOpen={onPopopToggle}
button={(
<Button
className={`${baseClass}__add-button`}
buttonStyle="none"
tooltip={popupOpen ? undefined : t('addNew')}
>
<Plus />
</Button>
<Fragment>
<Popup
buttonType="custom"
horizontalAlign="center"
onToggleOpen={onPopopToggle}
button={(
<Button
className={`${baseClass}__add-button`}
buttonStyle="none"
tooltip={popupOpen ? undefined : t('addNew')}
>
<Plus />
</Button>
)}
render={({ close: closePopup }) => (
<ul className={`${baseClass}__relations`}>
{relatedCollections.map((relatedCollection) => {
if (permissions.collections[relatedCollection.slug].create.permission) {
return (
<li key={relatedCollection.slug}>
<button
className={`${baseClass}__relation-button ${baseClass}__relation-button--${relatedCollection.slug}`}
type="button"
onClick={() => { closePopup(); openModal(relatedCollection); }}
>
{getTranslation(relatedCollection.labels.singular, i18n)}
</button>
</li>
);
}
render={({ close: closePopup }) => (
<ul className={`${baseClass}__relations`}>
{relatedCollections.map((relatedCollection) => {
if (permissions.collections[relatedCollection.slug].create.permission) {
return (
<li key={relatedCollection.slug}>
<DocumentDrawerToggler
collection={relatedCollection.slug}
className={`${baseClass}__relation-button ${baseClass}__relation-button--${relatedCollection.slug}`}
onClick={() => {
closePopup();
setSelectedCollection(relatedCollection);
}}
>
{getTranslation(relatedCollection.labels.singular, i18n)}
</DocumentDrawerToggler>
</li>
);
}
return null;
})}
</ul>
return null;
})}
</ul>
)}
/>
{selectedCollection && (
<DocumentDrawer
collection={selectedCollection.slug}
onSave={onSave}
/>
)}
/>
)}
{modalCollection && (
<AddNewRelationModal
{...{ onSave, modalSlug, modalCollection }}
/>
</Fragment>
)}
</div>
) : null;