@manuscripts/body-editor 2.6.37 → 2.6.38-LEAN-4186.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/commands.js +26 -4
- package/dist/cjs/components/authors/AuthorActions.js +25 -41
- package/dist/cjs/components/authors/AuthorDetailsForm.js +30 -11
- package/dist/cjs/components/authors/AuthorList.js +11 -2
- package/dist/cjs/components/authors/AuthorsModal.js +122 -17
- package/dist/cjs/components/authors/DeleteAuthorConfirmationDialog.js +17 -4
- package/dist/cjs/components/authors/DraggableAuthor.js +62 -15
- package/dist/cjs/components/authors/RequiredFieldConfirmationDialog.js +39 -0
- package/dist/cjs/components/authors/SaveAuthorConfirmationDialog.js +19 -1
- package/dist/cjs/menus.js +7 -1
- package/dist/cjs/plugins/cross-references.js +1 -1
- package/dist/cjs/versions.js +1 -1
- package/dist/cjs/views/contributors.js +42 -15
- package/dist/es/commands.js +24 -3
- package/dist/es/components/authors/AuthorActions.js +26 -19
- package/dist/es/components/authors/AuthorDetailsForm.js +30 -11
- package/dist/es/components/authors/AuthorList.js +11 -2
- package/dist/es/components/authors/AuthorsModal.js +123 -18
- package/dist/es/components/authors/DeleteAuthorConfirmationDialog.js +18 -5
- package/dist/es/components/authors/DraggableAuthor.js +64 -16
- package/dist/es/components/authors/RequiredFieldConfirmationDialog.js +32 -0
- package/dist/es/components/authors/SaveAuthorConfirmationDialog.js +20 -2
- package/dist/es/menus.js +8 -2
- package/dist/es/plugins/cross-references.js +1 -1
- package/dist/es/versions.js +1 -1
- package/dist/es/views/contributors.js +43 -16
- package/dist/types/commands.d.ts +1 -0
- package/dist/types/components/authors/AuthorActions.d.ts +4 -3
- package/dist/types/components/authors/AuthorDetailsForm.d.ts +1 -0
- package/dist/types/components/authors/AuthorList.d.ts +2 -0
- package/dist/types/components/authors/AuthorsModal.d.ts +1 -0
- package/dist/types/components/authors/DeleteAuthorConfirmationDialog.d.ts +0 -2
- package/dist/types/components/authors/DraggableAuthor.d.ts +2 -0
- package/dist/types/components/authors/RequiredFieldConfirmationDialog.d.ts +7 -0
- package/dist/types/versions.d.ts +1 -1
- package/dist/types/views/contributors.d.ts +3 -2
- package/package.json +2 -2
- package/styles/AdvancedEditor.css +31 -2
- package/styles/Editor.css +15 -0
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.RequiredFieldConfirmationDialog = void 0;
|
|
7
|
+
const style_guide_1 = require("@manuscripts/style-guide");
|
|
8
|
+
const react_1 = __importDefault(require("react"));
|
|
9
|
+
const styled_components_1 = __importDefault(require("styled-components"));
|
|
10
|
+
const StyledIcon = (0, styled_components_1.default)(style_guide_1.AttentionOrangeIcon) `
|
|
11
|
+
margin-right: 8px;
|
|
12
|
+
`;
|
|
13
|
+
const MessageBox = styled_components_1.default.div `
|
|
14
|
+
display: flex;
|
|
15
|
+
flex-direction: column;
|
|
16
|
+
justify-content: space-between;
|
|
17
|
+
min-height: 90px;
|
|
18
|
+
`;
|
|
19
|
+
const Header = () => (react_1.default.createElement(react_1.default.Fragment, null,
|
|
20
|
+
react_1.default.createElement(StyledIcon, null),
|
|
21
|
+
" Empty required field"));
|
|
22
|
+
const Message = () => {
|
|
23
|
+
return (react_1.default.createElement(MessageBox, null,
|
|
24
|
+
react_1.default.createElement("div", null, "A required filed has been left empty. If you discard, any updates will not be saved!"),
|
|
25
|
+
react_1.default.createElement("div", null, "Would you like to discard or continue editing?")));
|
|
26
|
+
};
|
|
27
|
+
const RequiredFieldConfirmationDialog = ({ isOpen, onSave, onCancel }) => {
|
|
28
|
+
return (react_1.default.createElement(style_guide_1.Dialog, { isOpen: isOpen, category: style_guide_1.Category.confirmation, header: react_1.default.createElement(Header, null), message: react_1.default.createElement(Message, null), actions: {
|
|
29
|
+
secondary: {
|
|
30
|
+
action: onCancel,
|
|
31
|
+
title: 'Discard',
|
|
32
|
+
},
|
|
33
|
+
primary: {
|
|
34
|
+
action: onSave,
|
|
35
|
+
title: 'Continue editing',
|
|
36
|
+
},
|
|
37
|
+
} }));
|
|
38
|
+
};
|
|
39
|
+
exports.RequiredFieldConfirmationDialog = RequiredFieldConfirmationDialog;
|
|
@@ -6,8 +6,26 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
exports.SaveAuthorConfirmationDialog = void 0;
|
|
7
7
|
const style_guide_1 = require("@manuscripts/style-guide");
|
|
8
8
|
const react_1 = __importDefault(require("react"));
|
|
9
|
+
const styled_components_1 = __importDefault(require("styled-components"));
|
|
10
|
+
const StyledIcon = (0, styled_components_1.default)(style_guide_1.AttentionOrangeIcon) `
|
|
11
|
+
margin-right: 8px;
|
|
12
|
+
`;
|
|
13
|
+
const MessageBox = styled_components_1.default.div `
|
|
14
|
+
display: flex;
|
|
15
|
+
flex-direction: column;
|
|
16
|
+
justify-content: space-between;
|
|
17
|
+
min-height: 72px;
|
|
18
|
+
`;
|
|
19
|
+
const Header = () => (react_1.default.createElement(react_1.default.Fragment, null,
|
|
20
|
+
react_1.default.createElement(StyledIcon, null),
|
|
21
|
+
" Unsaved changes"));
|
|
22
|
+
const Message = () => {
|
|
23
|
+
return (react_1.default.createElement(MessageBox, null,
|
|
24
|
+
react_1.default.createElement("div", null, "You've made changes but not saved them!"),
|
|
25
|
+
react_1.default.createElement("div", null, "Would you like to save or discard your changes?")));
|
|
26
|
+
};
|
|
9
27
|
const SaveAuthorConfirmationDialog = ({ isOpen, onSave, onCancel }) => {
|
|
10
|
-
return (react_1.default.createElement(style_guide_1.Dialog, { isOpen: isOpen, category: style_guide_1.Category.confirmation, header:
|
|
28
|
+
return (react_1.default.createElement(style_guide_1.Dialog, { isOpen: isOpen, category: style_guide_1.Category.confirmation, header: react_1.default.createElement(Header, null), message: react_1.default.createElement(Message, null), actions: {
|
|
11
29
|
secondary: {
|
|
12
30
|
action: onCancel,
|
|
13
31
|
title: 'Discard',
|
package/dist/cjs/menus.js
CHANGED
|
@@ -104,10 +104,16 @@ const getEditorMenus = (editor) => {
|
|
|
104
104
|
},
|
|
105
105
|
{
|
|
106
106
|
id: 'insert-contributors',
|
|
107
|
-
label: 'Authors
|
|
107
|
+
label: 'Authors',
|
|
108
108
|
isEnabled: isCommandValid(commands_1.insertContributors),
|
|
109
109
|
run: doCommand(commands_1.insertContributors),
|
|
110
110
|
},
|
|
111
|
+
{
|
|
112
|
+
id: 'insert-contributors',
|
|
113
|
+
label: 'Affiliations',
|
|
114
|
+
isEnabled: isCommandValid(commands_1.insertAffiliation),
|
|
115
|
+
run: doCommand(commands_1.insertAffiliation),
|
|
116
|
+
},
|
|
111
117
|
{
|
|
112
118
|
id: 'insert-keywords',
|
|
113
119
|
label: 'Keywords',
|
|
@@ -23,7 +23,7 @@ const objects_1 = require("./objects");
|
|
|
23
23
|
exports.default = () => {
|
|
24
24
|
return new prosemirror_state_1.Plugin({
|
|
25
25
|
state: {
|
|
26
|
-
init(
|
|
26
|
+
init() {
|
|
27
27
|
return prosemirror_view_1.DecorationSet.empty;
|
|
28
28
|
},
|
|
29
29
|
apply(tr, oldDecorationSet, oldState, newState) {
|
package/dist/cjs/versions.js
CHANGED
|
@@ -115,16 +115,25 @@ class ContributorsView extends block_view_1.default {
|
|
|
115
115
|
this.dom = document.createElement('div');
|
|
116
116
|
this.dom.classList.add('block-container', `block-${this.node.type.name}`);
|
|
117
117
|
};
|
|
118
|
-
this.
|
|
118
|
+
this.authorContextMenu = () => {
|
|
119
119
|
const can = this.props.getCapabilities();
|
|
120
|
-
const
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
120
|
+
const componentProps = {
|
|
121
|
+
actions: [],
|
|
122
|
+
};
|
|
123
|
+
if (can.editArticle) {
|
|
124
|
+
componentProps.actions.push({
|
|
125
|
+
label: 'New Author',
|
|
126
|
+
action: () => this.handleEdit('', true),
|
|
127
|
+
icon: 'AddOutline',
|
|
128
|
+
});
|
|
129
|
+
componentProps.actions.push({
|
|
130
|
+
label: 'Edit',
|
|
131
|
+
action: () => this.handleEdit(''),
|
|
132
|
+
icon: 'Edit',
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
this.contextMenu = (0, ReactSubView_1.default)(this.props, style_guide_1.ContextMenu, componentProps, this.node, this.getPos, this.view, 'context-menu');
|
|
136
|
+
return this.contextMenu;
|
|
128
137
|
};
|
|
129
138
|
this.createLegend = () => {
|
|
130
139
|
const state = affiliations_1.affiliationsKey.getState(this.view.state);
|
|
@@ -184,7 +193,7 @@ class ContributorsView extends block_view_1.default {
|
|
|
184
193
|
this.contextMenu = (0, ReactSubView_1.default)(this.props, style_guide_1.ContextMenu, componentProps, this.node, this.getPos, this.view, 'context-menu');
|
|
185
194
|
this.props.popper.show(element, this.contextMenu, 'right-start');
|
|
186
195
|
};
|
|
187
|
-
this.handleEdit = (id) => {
|
|
196
|
+
this.handleEdit = (id, addNew) => {
|
|
188
197
|
var _a;
|
|
189
198
|
this.props.popper.destroy();
|
|
190
199
|
const contributors = (0, view_1.findChildrenAttrsByType)(this.view, transform_1.schema.nodes.contributor);
|
|
@@ -197,6 +206,7 @@ class ContributorsView extends block_view_1.default {
|
|
|
197
206
|
onSaveAuthor: this.handleSaveAuthor,
|
|
198
207
|
onDeleteAuthor: this.handleDeleteAuthor,
|
|
199
208
|
onSaveAffiliation: this.handleSaveAffiliation,
|
|
209
|
+
addNewAuthor: addNew,
|
|
200
210
|
};
|
|
201
211
|
(_a = this.popper) === null || _a === void 0 ? void 0 : _a.remove();
|
|
202
212
|
this.popper = (0, ReactSubView_1.default)(this.props, AuthorsModal_1.AuthorsModal, componentProps, this.node, this.getPos, this.view);
|
|
@@ -226,11 +236,29 @@ class ContributorsView extends block_view_1.default {
|
|
|
226
236
|
this.view.dispatch(tr.insert(parent.pos + 1, node));
|
|
227
237
|
};
|
|
228
238
|
this.insertAffiliationNode = (attrs) => {
|
|
229
|
-
const
|
|
230
|
-
const
|
|
231
|
-
const
|
|
232
|
-
|
|
239
|
+
const { view } = this;
|
|
240
|
+
const { dispatch } = view;
|
|
241
|
+
const affiliationsNodeType = transform_1.schema.nodes.affiliations;
|
|
242
|
+
const contributorsNodeType = transform_1.schema.nodes.contributors;
|
|
243
|
+
const affiliationNodeType = transform_1.schema.nodes.affiliation;
|
|
244
|
+
let affiliations = (0, view_1.findChildByType)(view, affiliationsNodeType);
|
|
245
|
+
if (!affiliations) {
|
|
246
|
+
const contributors = (0, view_1.findChildByType)(view, contributorsNodeType);
|
|
247
|
+
if (contributors) {
|
|
248
|
+
const { tr } = this.view.state;
|
|
249
|
+
const affiliationsNode = affiliationsNodeType.create();
|
|
250
|
+
const insertPos = contributors.pos + contributors.node.nodeSize;
|
|
251
|
+
dispatch(tr.insert(insertPos, affiliationsNode));
|
|
252
|
+
affiliations = (0, view_1.findChildByType)(view, affiliationsNodeType);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
if (affiliations) {
|
|
256
|
+
const { tr } = this.view.state;
|
|
257
|
+
const affiliationNode = affiliationNodeType.create(attrs);
|
|
258
|
+
dispatch(tr.insert(affiliations.pos + 1, affiliationNode));
|
|
259
|
+
}
|
|
233
260
|
};
|
|
261
|
+
this.actionGutterButtons = () => [this.authorContextMenu()];
|
|
234
262
|
}
|
|
235
263
|
updateContents() {
|
|
236
264
|
const affs = affiliations_1.affiliationsKey.getState(this.view.state);
|
|
@@ -244,7 +272,6 @@ class ContributorsView extends block_view_1.default {
|
|
|
244
272
|
this.version = affs.version;
|
|
245
273
|
this.container.innerHTML = '';
|
|
246
274
|
this.buildAuthors(affs);
|
|
247
|
-
this.createEditButton();
|
|
248
275
|
this.createLegend();
|
|
249
276
|
this.updateSelection();
|
|
250
277
|
}
|
package/dist/es/commands.js
CHANGED
|
@@ -587,9 +587,30 @@ export const insertContributors = (state, dispatch, view) => {
|
|
|
587
587
|
const contributors = state.schema.nodes.contributors.create({
|
|
588
588
|
id: '',
|
|
589
589
|
});
|
|
590
|
-
const
|
|
591
|
-
|
|
592
|
-
|
|
590
|
+
const tr = state.tr.insert(pos, contributors);
|
|
591
|
+
if (dispatch) {
|
|
592
|
+
const selection = NodeSelection.create(tr.doc, pos);
|
|
593
|
+
if (view) {
|
|
594
|
+
view.focus();
|
|
595
|
+
}
|
|
596
|
+
dispatch(tr.setSelection(selection).scrollIntoView());
|
|
597
|
+
}
|
|
598
|
+
return true;
|
|
599
|
+
};
|
|
600
|
+
export const insertAffiliation = (state, dispatch, view) => {
|
|
601
|
+
if (getChildOfType(state.doc, schema.nodes.affiliations, true)) {
|
|
602
|
+
return false;
|
|
603
|
+
}
|
|
604
|
+
const title = findChildrenByType(state.doc, state.schema.nodes.title)[0];
|
|
605
|
+
let pos = title.pos + title.node.nodeSize;
|
|
606
|
+
const contributors = findChildrenByType(state.doc, state.schema.nodes.contributors)[0];
|
|
607
|
+
if (contributors) {
|
|
608
|
+
pos = contributors.pos + contributors.node.nodeSize;
|
|
609
|
+
}
|
|
610
|
+
const affiliations = state.schema.nodes.affiliations.create({
|
|
611
|
+
id: '',
|
|
612
|
+
});
|
|
613
|
+
const tr = state.tr.insert(pos, affiliations);
|
|
593
614
|
if (dispatch) {
|
|
594
615
|
const selection = NodeSelection.create(tr.doc, pos);
|
|
595
616
|
if (view) {
|
|
@@ -1,31 +1,38 @@
|
|
|
1
|
-
import { ButtonGroup,
|
|
2
|
-
import React
|
|
1
|
+
import { ButtonGroup, IconButton, PlusIcon } from '@manuscripts/style-guide';
|
|
2
|
+
import React from 'react';
|
|
3
3
|
import styled from 'styled-components';
|
|
4
4
|
import { DeleteAuthorConfirmationDialog } from './DeleteAuthorConfirmationDialog';
|
|
5
5
|
const AuthorActionsContainer = styled.div `
|
|
6
6
|
display: flex;
|
|
7
7
|
`;
|
|
8
|
-
const RemoveButton = styled.div `
|
|
9
|
-
display: flex;
|
|
10
|
-
align-items: center;
|
|
11
|
-
|
|
12
|
-
svg {
|
|
13
|
-
cursor: pointer;
|
|
14
|
-
}
|
|
15
|
-
`;
|
|
16
8
|
const StyledButtonGroup = styled(ButtonGroup) `
|
|
17
9
|
flex: 1;
|
|
18
10
|
`;
|
|
19
|
-
|
|
20
|
-
|
|
11
|
+
const StyledIconButton = styled(IconButton) `
|
|
12
|
+
color: #0d79d0;
|
|
13
|
+
text-align: center;
|
|
14
|
+
font-size: 14px;
|
|
15
|
+
font-style: normal;
|
|
16
|
+
font-weight: 400;
|
|
17
|
+
line-height: 24px;
|
|
18
|
+
width: auto;
|
|
19
|
+
&:disabled {
|
|
20
|
+
color: #c9c9c9 !important;
|
|
21
|
+
background-color: unset !important;
|
|
22
|
+
border: unset;
|
|
23
|
+
}
|
|
24
|
+
svg {
|
|
25
|
+
margin-right: 4px;
|
|
26
|
+
}
|
|
27
|
+
`;
|
|
28
|
+
export const AuthorActions = ({ onSave, onDelete, showDeleteDialog, handleShowDeleteDialog, newAuthor, isDisableSave, }) => {
|
|
21
29
|
return (React.createElement(AuthorActionsContainer, { "data-cy": "author-action" },
|
|
22
|
-
React.createElement(DeleteAuthorConfirmationDialog, {
|
|
23
|
-
|
|
30
|
+
React.createElement(DeleteAuthorConfirmationDialog, { isOpen: showDeleteDialog, onDelete: () => {
|
|
31
|
+
handleShowDeleteDialog();
|
|
24
32
|
onDelete();
|
|
25
|
-
}, onCancel: () =>
|
|
26
|
-
React.createElement(RemoveButton, { onClick: () => setShowDeleteDialog(true) },
|
|
27
|
-
React.createElement(DeleteIcon, null)),
|
|
33
|
+
}, onCancel: () => handleShowDeleteDialog() }),
|
|
28
34
|
React.createElement(StyledButtonGroup, null,
|
|
29
|
-
React.createElement(
|
|
30
|
-
|
|
35
|
+
React.createElement(StyledIconButton, { onClick: onSave, disabled: isDisableSave, type: "submit" },
|
|
36
|
+
React.createElement(PlusIcon, null),
|
|
37
|
+
newAuthor ? 'Save Details' : 'Update Details'))));
|
|
31
38
|
};
|
|
@@ -24,6 +24,9 @@ export const LabelText = styled.div `
|
|
|
24
24
|
${(props) => props.theme.font.family.sans};
|
|
25
25
|
letter-spacing: -0.2px;
|
|
26
26
|
color: ${(props) => props.theme.colors.text.primary};
|
|
27
|
+
&::before {
|
|
28
|
+
margin-right: 8px !important;
|
|
29
|
+
}
|
|
27
30
|
`;
|
|
28
31
|
export const Fieldset = styled.fieldset `
|
|
29
32
|
padding: 0;
|
|
@@ -33,7 +36,17 @@ export const Fieldset = styled.fieldset `
|
|
|
33
36
|
const OrcidContainer = styled.div `
|
|
34
37
|
margin: 16px 0 0;
|
|
35
38
|
`;
|
|
36
|
-
|
|
39
|
+
const TextFieldWithError = styled(TextField) `
|
|
40
|
+
&:required::placeholder {
|
|
41
|
+
color: ${(props) => props.theme.colors.text.error};
|
|
42
|
+
}
|
|
43
|
+
`;
|
|
44
|
+
const CheckboxContainer = styled.div `
|
|
45
|
+
display: flex;
|
|
46
|
+
align-items: center;
|
|
47
|
+
gap: 32px;
|
|
48
|
+
`;
|
|
49
|
+
export const AuthorDetailsForm = ({ values, onChange, onSave, actionsRef, isEmailRequired, }) => {
|
|
37
50
|
const formRef = useRef(null);
|
|
38
51
|
if (actionsRef && !actionsRef.current) {
|
|
39
52
|
actionsRef.current = {
|
|
@@ -43,22 +56,28 @@ export const AuthorDetailsForm = ({ values, onChange, onSave, actionsRef, }) =>
|
|
|
43
56
|
},
|
|
44
57
|
};
|
|
45
58
|
}
|
|
46
|
-
return (React.createElement(Formik, { initialValues: values, onSubmit: onSave, enableReinitialize: true, validateOnChange:
|
|
59
|
+
return (React.createElement(Formik, { initialValues: values, onSubmit: onSave, enableReinitialize: true, validateOnChange: true, innerRef: formRef }, (formik) => {
|
|
47
60
|
const isAuthor = formik.values.role === 'author';
|
|
48
61
|
return (React.createElement(ChangeHandlingForm, { onChange: onChange },
|
|
49
62
|
React.createElement(Fieldset, null,
|
|
50
63
|
React.createElement(TextFieldGroupContainer, null,
|
|
51
64
|
React.createElement(Field, { name: 'bibliographicName.given' }, (props) => (React.createElement(TextField, Object.assign({ id: 'given-name', placeholder: 'Given name' }, props.field)))),
|
|
52
65
|
React.createElement(Field, { name: 'bibliographicName.family' }, (props) => (React.createElement(TextField, Object.assign({ id: 'family-name', placeholder: 'Family name' }, props.field))))),
|
|
53
|
-
React.createElement(Field, { name: 'email', type: 'email' }, (props) =>
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
66
|
+
React.createElement(Field, { name: 'email', type: 'email' }, (props) => {
|
|
67
|
+
const placeholder = isEmailRequired
|
|
68
|
+
? '*Email address (required)'
|
|
69
|
+
: 'Email address';
|
|
70
|
+
return (React.createElement(TextFieldWithError, Object.assign({ required: isEmailRequired, id: 'email', placeholder: placeholder }, props.field)));
|
|
71
|
+
}),
|
|
72
|
+
React.createElement(CheckboxContainer, null,
|
|
73
|
+
React.createElement(CheckboxLabel, { disabled: !isAuthor },
|
|
74
|
+
React.createElement(Field, { name: 'isCorresponding' }, (props) => (React.createElement(CheckboxField, Object.assign({ id: 'isCorresponding', checked: props.field.value, disabled: !isAuthor }, props.field)))),
|
|
75
|
+
React.createElement(LabelText, null, "Corresponding Author")),
|
|
76
|
+
React.createElement(CheckboxLabel, null,
|
|
77
|
+
React.createElement(Field, { name: 'role', type: 'checkbox' }, (props) => (React.createElement(CheckboxField, { name: 'role', checked: isAuthor, onChange: (e) => {
|
|
78
|
+
formik.setFieldValue(props.field.name, e.target.checked ? 'author' : 'other', false);
|
|
79
|
+
} }))),
|
|
80
|
+
React.createElement(LabelText, null, "Include in Authors List"))),
|
|
62
81
|
React.createElement(OrcidContainer, null,
|
|
63
82
|
React.createElement(TextFieldLabel, null,
|
|
64
83
|
React.createElement(LabelText, null, "ORCID"),
|
|
@@ -22,9 +22,18 @@ const AuthorListContainer = styled.div `
|
|
|
22
22
|
flex: 1;
|
|
23
23
|
overflow-y: visible;
|
|
24
24
|
`;
|
|
25
|
-
|
|
25
|
+
const AuthorListTitle = styled.h2 `
|
|
26
|
+
color: #6e6e6e;
|
|
27
|
+
font-size: 18px;
|
|
28
|
+
font-weight: 400;
|
|
29
|
+
line-height: 24px;
|
|
30
|
+
margin-left: 14px;
|
|
31
|
+
margin-top: 28px;
|
|
32
|
+
`;
|
|
33
|
+
export const AuthorList = ({ author, authors, onSelect, onDelete, moveAuthor, lastSavedAuthor, }) => {
|
|
26
34
|
return (React.createElement(DndProvider, { backend: HTML5Backend },
|
|
35
|
+
React.createElement(AuthorListTitle, null, "Existing Authors"),
|
|
27
36
|
React.createElement(AuthorListContainer, { "data-cy": "authors-list" }, authors.map((a) => {
|
|
28
|
-
return (React.createElement(DraggableAuthor, { key: a.id, author: a, isSelected: a.id === (author === null || author === void 0 ? void 0 : author.id), onClick: () => onSelect(a), moveAuthor: moveAuthor }));
|
|
37
|
+
return (React.createElement(DraggableAuthor, { key: a.id, author: a, isSelected: a.id === (author === null || author === void 0 ? void 0 : author.id), onClick: () => onSelect(a), onDelete: () => onDelete(), moveAuthor: moveAuthor, showSuccessIcon: lastSavedAuthor === a.id }));
|
|
29
38
|
}))));
|
|
30
39
|
};
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
import { buildBibliographicName, generateID, ObjectTypes, } from '@manuscripts/json-schema';
|
|
17
17
|
import { AddIcon, CloseButton, ModalBody, ModalContainer, ModalHeader, ModalSidebar, ModalSidebarHeader, ModalSidebarTitle, ScrollableModalContent, SidebarContent, StyledModal, } from '@manuscripts/style-guide';
|
|
18
18
|
import { isEqual } from 'lodash';
|
|
19
|
-
import React, { useReducer, useRef, useState } from 'react';
|
|
19
|
+
import React, { useEffect, useReducer, useRef, useState } from 'react';
|
|
20
20
|
import styled from 'styled-components';
|
|
21
21
|
import { arrayReducer } from '../../lib/array-reducer';
|
|
22
22
|
import { authorComparator, } from '../../lib/authors';
|
|
@@ -25,12 +25,13 @@ import { AuthorAffiliations } from './AuthorAffiliations';
|
|
|
25
25
|
import { AuthorDetailsForm } from './AuthorDetailsForm';
|
|
26
26
|
import { AuthorFormPlaceholder } from './AuthorFormPlaceholder';
|
|
27
27
|
import { AuthorList } from './AuthorList';
|
|
28
|
+
import { RequiredFieldConfirmationDialog } from './RequiredFieldConfirmationDialog';
|
|
28
29
|
import { SaveAuthorConfirmationDialog } from './SaveAuthorConfirmationDialog';
|
|
29
30
|
const AddAuthorButton = styled.div `
|
|
30
31
|
display: flex;
|
|
31
32
|
align-items: center;
|
|
32
33
|
margin-bottom: ${(props) => props.theme.grid.unit * 4}px;
|
|
33
|
-
margin-left: ${(props) => props.theme.grid.unit *
|
|
34
|
+
margin-left: ${(props) => props.theme.grid.unit * 4}px;
|
|
34
35
|
cursor: pointer;
|
|
35
36
|
`;
|
|
36
37
|
const ActionTitle = styled.div `
|
|
@@ -50,6 +51,9 @@ const AuthorForms = styled.div `
|
|
|
50
51
|
padding-left: ${(props) => props.theme.grid.unit * 3}px;
|
|
51
52
|
padding-right: ${(props) => props.theme.grid.unit * 3}px;
|
|
52
53
|
`;
|
|
54
|
+
const StyledSidebarContent = styled(SidebarContent) `
|
|
55
|
+
padding: 0;
|
|
56
|
+
`;
|
|
53
57
|
const authorsReducer = arrayReducer((a, b) => a.id === b.id);
|
|
54
58
|
const affiliationsReducer = arrayReducer((a, b) => a.id === b.id);
|
|
55
59
|
const normalize = (author) => ({
|
|
@@ -67,38 +71,97 @@ const normalize = (author) => ({
|
|
|
67
71
|
footnote: author.footnote || [],
|
|
68
72
|
corresp: author.corresp || [],
|
|
69
73
|
});
|
|
70
|
-
export const AuthorsModal = ({ authors: $authors, affiliations: $affiliations, author, onSaveAuthor, onDeleteAuthor, onSaveAffiliation, }) => {
|
|
74
|
+
export const AuthorsModal = ({ authors: $authors, affiliations: $affiliations, author, onSaveAuthor, onDeleteAuthor, onSaveAffiliation, addNewAuthor = false, }) => {
|
|
71
75
|
const [isOpen, setOpen] = useState(true);
|
|
76
|
+
const [isDisableSave, setDisableSave] = useState(false);
|
|
77
|
+
const [isEmailRequired, setEmailRequired] = useState(false);
|
|
72
78
|
const [showConfirmationDialog, setShowConfirmationDialog] = useState(false);
|
|
79
|
+
const [showRequiredFieldConfirmationDialog, setShowRequiredFieldConfirmationDialog,] = useState(false);
|
|
80
|
+
const [lastSavedAuthor, setLastSavedAuthor] = useState(null);
|
|
81
|
+
const [showDeleteDialog, setShowDeleteDialog] = useState(false);
|
|
82
|
+
const [newAuthor, setNewAuthor] = useState(false);
|
|
83
|
+
const [unSavedChanges, setUnSavedChanges] = useState(false);
|
|
84
|
+
const [nextAuthor, setNextAuthor] = useState(null);
|
|
73
85
|
const valuesRef = useRef();
|
|
74
86
|
const actionsRef = useRef();
|
|
75
87
|
const [authors, dispatchAuthors] = useReducer(authorsReducer, $authors.sort(authorComparator));
|
|
76
88
|
const [affiliations, dispatchAffiliations] = useReducer(affiliationsReducer, $affiliations);
|
|
89
|
+
useEffect(() => {
|
|
90
|
+
if (addNewAuthor) {
|
|
91
|
+
handleAddAuthor();
|
|
92
|
+
}
|
|
93
|
+
}, [addNewAuthor]);
|
|
77
94
|
const [selection, setSelection] = useState(author);
|
|
78
95
|
const handleSelect = (author) => {
|
|
79
96
|
const values = valuesRef.current;
|
|
80
|
-
if (values &&
|
|
97
|
+
if (values &&
|
|
98
|
+
selection &&
|
|
99
|
+
!isEqual(values, normalize(selection)) &&
|
|
100
|
+
!isDisableSave) {
|
|
81
101
|
setShowConfirmationDialog(true);
|
|
102
|
+
setNextAuthor(author);
|
|
103
|
+
}
|
|
104
|
+
else if (isDisableSave && unSavedChanges) {
|
|
105
|
+
setShowRequiredFieldConfirmationDialog(true);
|
|
106
|
+
setNextAuthor(author);
|
|
82
107
|
}
|
|
83
108
|
else {
|
|
84
109
|
setSelection(author);
|
|
85
110
|
}
|
|
86
111
|
};
|
|
87
|
-
|
|
112
|
+
useEffect(() => {
|
|
88
113
|
const values = valuesRef.current;
|
|
89
114
|
if (values && selection && !isEqual(values, normalize(selection))) {
|
|
115
|
+
setUnSavedChanges(true);
|
|
116
|
+
}
|
|
117
|
+
}, [valuesRef.current]);
|
|
118
|
+
const handleClose = () => {
|
|
119
|
+
if (isDisableSave && unSavedChanges) {
|
|
120
|
+
setShowRequiredFieldConfirmationDialog(true);
|
|
121
|
+
}
|
|
122
|
+
else if (unSavedChanges) {
|
|
90
123
|
setShowConfirmationDialog(true);
|
|
91
124
|
}
|
|
92
125
|
else {
|
|
126
|
+
setShowRequiredFieldConfirmationDialog(false);
|
|
127
|
+
setLastSavedAuthor(null);
|
|
93
128
|
setOpen(false);
|
|
94
129
|
}
|
|
95
130
|
};
|
|
131
|
+
const handleSave = () => {
|
|
132
|
+
if (valuesRef.current && selection) {
|
|
133
|
+
handleSaveAuthor(valuesRef.current);
|
|
134
|
+
}
|
|
135
|
+
if (nextAuthor) {
|
|
136
|
+
setSelection(nextAuthor);
|
|
137
|
+
setNextAuthor(null);
|
|
138
|
+
}
|
|
139
|
+
else if (newAuthor) {
|
|
140
|
+
createNewAuthor();
|
|
141
|
+
setNewAuthor(false);
|
|
142
|
+
}
|
|
143
|
+
setShowConfirmationDialog(false);
|
|
144
|
+
};
|
|
145
|
+
const handleCancel = () => {
|
|
146
|
+
handleResetAuthor();
|
|
147
|
+
if (nextAuthor) {
|
|
148
|
+
setSelection(nextAuthor);
|
|
149
|
+
setNextAuthor(null);
|
|
150
|
+
}
|
|
151
|
+
else if (newAuthor) {
|
|
152
|
+
createNewAuthor();
|
|
153
|
+
setNewAuthor(false);
|
|
154
|
+
}
|
|
155
|
+
setShowConfirmationDialog(false);
|
|
156
|
+
};
|
|
96
157
|
const handleSaveAuthor = (values) => {
|
|
97
158
|
if (!values || !selection) {
|
|
98
159
|
return;
|
|
99
160
|
}
|
|
100
161
|
const author = Object.assign(Object.assign({}, selection), values);
|
|
101
162
|
onSaveAuthor(author);
|
|
163
|
+
setLastSavedAuthor(author.id);
|
|
164
|
+
setUnSavedChanges(false);
|
|
102
165
|
setSelection(author);
|
|
103
166
|
setShowConfirmationDialog(false);
|
|
104
167
|
dispatchAuthors({
|
|
@@ -121,7 +184,7 @@ export const AuthorsModal = ({ authors: $authors, affiliations: $affiliations, a
|
|
|
121
184
|
state: copy,
|
|
122
185
|
});
|
|
123
186
|
};
|
|
124
|
-
const
|
|
187
|
+
const createNewAuthor = () => {
|
|
125
188
|
const name = buildBibliographicName({ given: '', family: '' });
|
|
126
189
|
const author = {
|
|
127
190
|
id: generateID(ObjectTypes.Contributor),
|
|
@@ -138,12 +201,18 @@ export const AuthorsModal = ({ authors: $authors, affiliations: $affiliations, a
|
|
|
138
201
|
corresp: [],
|
|
139
202
|
footnote: [],
|
|
140
203
|
};
|
|
141
|
-
onSaveAuthor(author);
|
|
142
204
|
setSelection(author);
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
205
|
+
};
|
|
206
|
+
const handleAddAuthor = () => {
|
|
207
|
+
const values = valuesRef.current;
|
|
208
|
+
if (values && selection && !isEqual(values, normalize(selection))) {
|
|
209
|
+
setShowConfirmationDialog(true);
|
|
210
|
+
setNextAuthor(null);
|
|
211
|
+
setNewAuthor(true);
|
|
212
|
+
}
|
|
213
|
+
else {
|
|
214
|
+
createNewAuthor();
|
|
215
|
+
}
|
|
147
216
|
};
|
|
148
217
|
const handleDeleteAuthor = () => {
|
|
149
218
|
if (!selection) {
|
|
@@ -183,9 +252,44 @@ export const AuthorsModal = ({ authors: $authors, affiliations: $affiliations, a
|
|
|
183
252
|
var _a;
|
|
184
253
|
(_a = actionsRef.current) === null || _a === void 0 ? void 0 : _a.reset();
|
|
185
254
|
setShowConfirmationDialog(false);
|
|
255
|
+
setShowRequiredFieldConfirmationDialog(false);
|
|
256
|
+
setUnSavedChanges(false);
|
|
257
|
+
if (!newAuthor && !nextAuthor) {
|
|
258
|
+
setLastSavedAuthor(null);
|
|
259
|
+
setOpen(false);
|
|
260
|
+
}
|
|
261
|
+
else {
|
|
262
|
+
setNewAuthor(false);
|
|
263
|
+
createNewAuthor();
|
|
264
|
+
}
|
|
186
265
|
};
|
|
187
266
|
const handleChangeAuthor = (values) => {
|
|
267
|
+
const isUnchanged = isEqual(normalize(selection), values);
|
|
188
268
|
valuesRef.current = values;
|
|
269
|
+
const { given, family } = values.bibliographicName;
|
|
270
|
+
const { email, isCorresponding } = values;
|
|
271
|
+
const isNameFilled = (given === null || given === void 0 ? void 0 : given.length) && (family === null || family === void 0 ? void 0 : family.length);
|
|
272
|
+
if (isNameFilled && !isCorresponding && !isUnchanged) {
|
|
273
|
+
setDisableSave(false);
|
|
274
|
+
}
|
|
275
|
+
else if (isCorresponding &&
|
|
276
|
+
(email === null || email === void 0 ? void 0 : email.length) &&
|
|
277
|
+
isNameFilled &&
|
|
278
|
+
!isUnchanged) {
|
|
279
|
+
setDisableSave(false);
|
|
280
|
+
}
|
|
281
|
+
else {
|
|
282
|
+
setDisableSave(true);
|
|
283
|
+
}
|
|
284
|
+
if (isCorresponding && !(email === null || email === void 0 ? void 0 : email.length)) {
|
|
285
|
+
setEmailRequired(true);
|
|
286
|
+
}
|
|
287
|
+
else {
|
|
288
|
+
setEmailRequired(false);
|
|
289
|
+
}
|
|
290
|
+
};
|
|
291
|
+
const handleShowDeleteDialog = () => {
|
|
292
|
+
setShowDeleteDialog((prev) => !prev);
|
|
189
293
|
};
|
|
190
294
|
return (React.createElement(StyledModal, { isOpen: isOpen, onRequestClose: () => handleClose(), shouldCloseOnOverlayClick: true },
|
|
191
295
|
React.createElement(ModalContainer, null,
|
|
@@ -195,16 +299,17 @@ export const AuthorsModal = ({ authors: $authors, affiliations: $affiliations, a
|
|
|
195
299
|
React.createElement(ModalSidebar, { "data-cy": "authors-sidebar" },
|
|
196
300
|
React.createElement(ModalSidebarHeader, null,
|
|
197
301
|
React.createElement(ModalSidebarTitle, null, "Authors")),
|
|
198
|
-
React.createElement(
|
|
302
|
+
React.createElement(StyledSidebarContent, null,
|
|
199
303
|
React.createElement(AddAuthorButton, { "data-cy": "add-author-button", onClick: handleAddAuthor },
|
|
200
|
-
React.createElement(AddIcon, { width:
|
|
201
|
-
React.createElement(ActionTitle, null, "
|
|
202
|
-
React.createElement(AuthorList, { author: selection, authors: authors, onSelect: handleSelect, moveAuthor: handleMoveAuthor }))),
|
|
304
|
+
React.createElement(AddIcon, { width: 18, height: 18 }),
|
|
305
|
+
React.createElement(ActionTitle, null, "New Author")),
|
|
306
|
+
React.createElement(AuthorList, { author: selection, authors: authors, onSelect: handleSelect, onDelete: handleShowDeleteDialog, moveAuthor: handleMoveAuthor, lastSavedAuthor: lastSavedAuthor }))),
|
|
203
307
|
React.createElement(ScrollableModalContent, { "data-cy": "author-modal-content" }, selection ? (React.createElement(AuthorForms, null,
|
|
204
|
-
React.createElement(
|
|
205
|
-
React.createElement(
|
|
308
|
+
React.createElement(RequiredFieldConfirmationDialog, { isOpen: showRequiredFieldConfirmationDialog, onSave: () => setShowRequiredFieldConfirmationDialog(false), onCancel: handleCancel }),
|
|
309
|
+
React.createElement(SaveAuthorConfirmationDialog, { isOpen: showConfirmationDialog, onSave: handleSave, onCancel: handleCancel }),
|
|
310
|
+
React.createElement(AuthorActions, { onSave: () => handleSaveAuthor(valuesRef.current), onDelete: handleDeleteAuthor, showDeleteDialog: showDeleteDialog, handleShowDeleteDialog: handleShowDeleteDialog, newAuthor: newAuthor, isDisableSave: isDisableSave }),
|
|
206
311
|
React.createElement(FormLabel, null, "Details"),
|
|
207
|
-
React.createElement(AuthorDetailsForm, { values: normalize(selection), onChange: handleChangeAuthor, onSave: handleSaveAuthor, actionsRef: actionsRef }),
|
|
312
|
+
React.createElement(AuthorDetailsForm, { values: normalize(selection), onChange: handleChangeAuthor, onSave: handleSaveAuthor, actionsRef: actionsRef, isEmailRequired: isEmailRequired }),
|
|
208
313
|
React.createElement(FormLabel, null, "Affiliations"),
|
|
209
314
|
React.createElement(AuthorAffiliations, { author: selection, affiliations: affiliations, onSave: handleSaveAffiliation, onAdd: handleAddAffiliation, onRemove: handleRemoveAffiliation }))) : (React.createElement(AuthorFormPlaceholder, null)))))));
|
|
210
315
|
};
|
|
@@ -1,9 +1,22 @@
|
|
|
1
|
-
import { Category, Dialog } from '@manuscripts/style-guide';
|
|
1
|
+
import { AttentionOrangeIcon, Category, Dialog } from '@manuscripts/style-guide';
|
|
2
2
|
import React from 'react';
|
|
3
|
-
import
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
import styled from 'styled-components';
|
|
4
|
+
const StyledIcon = styled(AttentionOrangeIcon) `
|
|
5
|
+
margin-right: 8px;
|
|
6
|
+
`;
|
|
7
|
+
const P = styled.p `
|
|
8
|
+
margin-bottom: 4px;
|
|
9
|
+
`;
|
|
10
|
+
const Header = () => (React.createElement(React.Fragment, null,
|
|
11
|
+
React.createElement(StyledIcon, null),
|
|
12
|
+
" Delete author"));
|
|
13
|
+
const Message = () => {
|
|
14
|
+
return (React.createElement(React.Fragment, null,
|
|
15
|
+
React.createElement("p", null, "Are you sure you want to remove this author from the authors list?"),
|
|
16
|
+
React.createElement(P, null, "Do you want to continue?")));
|
|
17
|
+
};
|
|
18
|
+
export const DeleteAuthorConfirmationDialog = ({ isOpen, onDelete, onCancel }) => {
|
|
19
|
+
return (React.createElement(Dialog, { isOpen: isOpen, category: Category.confirmation, header: React.createElement(Header, null), message: React.createElement(Message, null), actions: {
|
|
7
20
|
secondary: {
|
|
8
21
|
action: onDelete,
|
|
9
22
|
title: 'Delete',
|