@manuscripts/body-editor 2.7.7 → 2.7.8-LEAN-4213.0
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/components/affiliations/AffiliationForm.js +106 -0
- package/dist/cjs/components/affiliations/AffiliationItem.js +112 -0
- package/dist/cjs/components/affiliations/AffiliationList.js +47 -0
- package/dist/cjs/components/affiliations/AffiliationsModal.js +418 -0
- package/dist/cjs/components/authors/AuthorDetailsForm.js +10 -2
- package/dist/cjs/components/authors/AuthorList.js +1 -1
- package/dist/cjs/components/authors/AuthorsModal.js +184 -80
- package/dist/cjs/components/authors/DraggableAuthor.js +0 -3
- package/dist/cjs/components/dialog/ConfirmationDialog.js +86 -0
- package/dist/cjs/components/form/FormFooter.js +32 -0
- package/dist/cjs/components/form/FormPlaceholder.js +43 -0
- package/dist/cjs/components/{authors/AuthorActions.js → form/ModalFormActions.js} +12 -11
- package/dist/cjs/plugins/affiliations.js +5 -38
- package/dist/cjs/useEditor.js +0 -1
- package/dist/cjs/versions.js +1 -1
- package/dist/cjs/views/affiliations.js +82 -14
- package/dist/cjs/views/contributors.js +1 -9
- package/dist/es/components/affiliations/AffiliationForm.js +76 -0
- package/dist/es/components/affiliations/AffiliationItem.js +82 -0
- package/dist/es/components/affiliations/AffiliationList.js +40 -0
- package/dist/es/components/affiliations/AffiliationsModal.js +388 -0
- package/dist/es/components/authors/AuthorDetailsForm.js +11 -3
- package/dist/es/components/authors/AuthorList.js +1 -1
- package/dist/es/components/authors/AuthorsModal.js +183 -79
- package/dist/es/components/authors/DraggableAuthor.js +0 -3
- package/dist/es/components/dialog/ConfirmationDialog.js +79 -0
- package/dist/es/components/form/FormFooter.js +27 -0
- package/dist/es/components/form/FormPlaceholder.js +36 -0
- package/dist/es/components/{authors/AuthorActions.js → form/ModalFormActions.js} +10 -9
- package/dist/es/plugins/affiliations.js +6 -39
- package/dist/es/useEditor.js +0 -1
- package/dist/es/versions.js +1 -1
- package/dist/es/views/affiliations.js +85 -17
- package/dist/es/views/contributors.js +1 -9
- package/dist/types/components/{authors → affiliations}/AffiliationForm.d.ts +5 -0
- package/dist/types/components/affiliations/AffiliationItem.d.ts +10 -0
- package/dist/types/components/affiliations/AffiliationList.d.ts +26 -0
- package/dist/types/components/affiliations/AffiliationsModal.d.ts +11 -0
- package/dist/types/components/authors/AuthorDetailsForm.d.ts +1 -0
- package/dist/types/components/authors/AuthorsModal.d.ts +2 -1
- package/dist/types/components/dialog/ConfirmationDialog.d.ts +15 -0
- package/dist/types/components/form/FormFooter.d.ts +5 -0
- package/dist/types/components/form/FormPlaceholder.d.ts +9 -0
- package/dist/types/components/{authors/AuthorActions.d.ts → form/ModalFormActions.d.ts} +4 -3
- package/dist/types/lib/dnd.d.ts +1 -1
- package/dist/types/selection.d.ts +7 -1
- package/dist/types/versions.d.ts +1 -1
- package/dist/types/views/affiliations.d.ts +11 -0
- package/dist/types/views/contributors.d.ts +0 -1
- package/package.json +2 -2
- package/styles/AdvancedEditor.css +8 -4
- package/styles/Editor.css +7 -0
- package/dist/cjs/components/authors/AffiliationButton.js +0 -104
- package/dist/cjs/components/authors/AffiliationForm.js +0 -50
- package/dist/cjs/components/authors/AuthorAffiliations.js +0 -120
- package/dist/cjs/components/authors/AuthorFormPlaceholder.js +0 -71
- package/dist/cjs/components/authors/DeleteAuthorConfirmationDialog.js +0 -36
- package/dist/cjs/components/authors/RequiredFieldConfirmationDialog.js +0 -39
- package/dist/cjs/components/authors/SaveAuthorConfirmationDialog.js +0 -39
- package/dist/es/components/authors/AffiliationButton.js +0 -74
- package/dist/es/components/authors/AffiliationForm.js +0 -43
- package/dist/es/components/authors/AuthorAffiliations.js +0 -89
- package/dist/es/components/authors/AuthorFormPlaceholder.js +0 -64
- package/dist/es/components/authors/DeleteAuthorConfirmationDialog.js +0 -29
- package/dist/es/components/authors/RequiredFieldConfirmationDialog.js +0 -32
- package/dist/es/components/authors/SaveAuthorConfirmationDialog.js +0 -32
- package/dist/types/components/authors/AffiliationButton.d.ts +0 -8
- package/dist/types/components/authors/AuthorAffiliations.d.ts +0 -11
- package/dist/types/components/authors/AuthorFormPlaceholder.d.ts +0 -2
- package/dist/types/components/authors/DeleteAuthorConfirmationDialog.d.ts +0 -7
- package/dist/types/components/authors/RequiredFieldConfirmationDialog.d.ts +0 -7
- package/dist/types/components/authors/SaveAuthorConfirmationDialog.d.ts +0 -7
|
@@ -14,31 +14,34 @@
|
|
|
14
14
|
* limitations under the License.
|
|
15
15
|
*/
|
|
16
16
|
import { buildBibliographicName, generateID, ObjectTypes, } from '@manuscripts/json-schema';
|
|
17
|
-
import { AddIcon, CloseButton, ModalBody, ModalContainer, ModalHeader, ModalSidebar, ModalSidebarHeader, ModalSidebarTitle, ScrollableModalContent, SidebarContent, StyledModal, } from '@manuscripts/style-guide';
|
|
17
|
+
import { AddIcon, AddInstitutionIcon, AuthorPlaceholderIcon, CloseButton, Drawer, ModalBody, ModalContainer, ModalHeader, ModalSidebar, ModalSidebarHeader, ModalSidebarTitle, ScrollableModalContent, SelectedItemsBox, SidebarContent, StyledModal, } from '@manuscripts/style-guide';
|
|
18
18
|
import { isEqual, omit } from 'lodash';
|
|
19
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';
|
|
23
|
-
import {
|
|
24
|
-
import
|
|
23
|
+
import { ConfirmationDialog, DialogType } from '../dialog/ConfirmationDialog';
|
|
24
|
+
import FormFooter from '../form/FormFooter';
|
|
25
|
+
import { FormPlaceholder } from '../form/FormPlaceholder';
|
|
26
|
+
import { ModalFormActions } from '../form/ModalFormActions';
|
|
25
27
|
import { AuthorDetailsForm } from './AuthorDetailsForm';
|
|
26
|
-
import { AuthorFormPlaceholder } from './AuthorFormPlaceholder';
|
|
27
28
|
import { AuthorList } from './AuthorList';
|
|
28
|
-
import { RequiredFieldConfirmationDialog } from './RequiredFieldConfirmationDialog';
|
|
29
|
-
import { SaveAuthorConfirmationDialog } from './SaveAuthorConfirmationDialog';
|
|
30
29
|
const AddAuthorButton = styled.div `
|
|
31
30
|
display: flex;
|
|
32
31
|
align-items: center;
|
|
33
|
-
|
|
34
|
-
margin-left: ${(props) => props.theme.grid.unit * 4}px;
|
|
32
|
+
padding: 12px 8px 12px 12px;
|
|
35
33
|
cursor: pointer;
|
|
34
|
+
&[data-active='true'] {
|
|
35
|
+
background: ${(props) => props.theme.colors.background.fifth};
|
|
36
|
+
border: 1px solid ${(props) => props.theme.colors.border.primary};
|
|
37
|
+
border-left: 0;
|
|
38
|
+
border-right: 0;
|
|
39
|
+
}
|
|
36
40
|
`;
|
|
37
41
|
const ActionTitle = styled.div `
|
|
38
42
|
padding-left: ${(props) => props.theme.grid.unit * 2}px;
|
|
39
43
|
`;
|
|
40
44
|
const FormLabel = styled.legend `
|
|
41
|
-
margin-top: 12px;
|
|
42
45
|
margin-bottom: 12px;
|
|
43
46
|
font: ${(props) => props.theme.font.weight.normal}
|
|
44
47
|
${(props) => props.theme.font.size.xlarge} /
|
|
@@ -50,28 +53,73 @@ const FormLabel = styled.legend `
|
|
|
50
53
|
const AuthorForms = styled.div `
|
|
51
54
|
padding-left: ${(props) => props.theme.grid.unit * 3}px;
|
|
52
55
|
padding-right: ${(props) => props.theme.grid.unit * 3}px;
|
|
56
|
+
position: relative;
|
|
57
|
+
margin-top: 20px;
|
|
53
58
|
`;
|
|
54
59
|
const StyledSidebarContent = styled(SidebarContent) `
|
|
55
60
|
padding: 0;
|
|
56
61
|
`;
|
|
57
|
-
const
|
|
58
|
-
|
|
62
|
+
const AuthorsSection = styled.div `
|
|
63
|
+
margin-top: ${(props) => props.theme.grid.unit * 4}px;
|
|
64
|
+
padding-top: ${(props) => props.theme.grid.unit * 4}px;
|
|
65
|
+
border-top: 1px solid ${(props) => props.theme.colors.border.tertiary};
|
|
66
|
+
`;
|
|
67
|
+
const AuthorsHeader = styled.div `
|
|
68
|
+
display: flex;
|
|
69
|
+
justify-content: space-between;
|
|
70
|
+
align-items: flex-start;
|
|
71
|
+
flex-direction: column;
|
|
72
|
+
margin-bottom: ${(props) => props.theme.grid.unit * 2}px;
|
|
73
|
+
`;
|
|
74
|
+
const AuthorsTitle = styled.h3 `
|
|
75
|
+
margin: 0;
|
|
76
|
+
font-weight: ${(props) => props.theme.font.weight.normal};
|
|
77
|
+
font-size: ${(props) => props.theme.font.size.large};
|
|
78
|
+
font-family: ${(props) => props.theme.font.family.sans};
|
|
79
|
+
color: ${(props) => props.theme.colors.text.secondary};
|
|
80
|
+
`;
|
|
81
|
+
const AffiliateButton = styled.button `
|
|
82
|
+
color: ${(props) => props.theme.colors.brand.default};
|
|
83
|
+
background: none;
|
|
84
|
+
border: none;
|
|
85
|
+
cursor: pointer;
|
|
86
|
+
padding: 0;
|
|
87
|
+
font: ${(props) => props.theme.font.weight.normal}
|
|
88
|
+
${(props) => props.theme.font.size.normal}
|
|
89
|
+
${(props) => props.theme.font.family.sans};
|
|
90
|
+
display: flex;
|
|
91
|
+
align-items: center;
|
|
92
|
+
gap: 4px;
|
|
93
|
+
margin-top: ${(props) => props.theme.grid.unit * 2}px;
|
|
94
|
+
&:hover {
|
|
95
|
+
opacity: 0.8;
|
|
96
|
+
}
|
|
97
|
+
`;
|
|
98
|
+
const StyledModalBody = styled(ModalBody) `
|
|
99
|
+
position: relative;
|
|
100
|
+
height: calc(90vh - 40px);
|
|
101
|
+
`;
|
|
102
|
+
const StyledModalSidebarHeader = styled(ModalSidebarHeader) `
|
|
103
|
+
margin-bottom: 16px;
|
|
104
|
+
`;
|
|
105
|
+
export const authorsReducer = arrayReducer((a, b) => a.id === b.id);
|
|
106
|
+
export const affiliationsReducer = arrayReducer((a, b) => a.id === b.id);
|
|
59
107
|
const normalize = (author) => ({
|
|
60
108
|
id: author.id,
|
|
61
|
-
role: author.role,
|
|
62
|
-
affiliations: author.affiliations || [],
|
|
109
|
+
role: author.role || 'author',
|
|
110
|
+
affiliations: (author.affiliations || []).sort(),
|
|
63
111
|
bibliographicName: author.bibliographicName,
|
|
64
112
|
email: author.email || '',
|
|
65
113
|
isCorresponding: author.isCorresponding || false,
|
|
66
114
|
ORCIDIdentifier: author.ORCIDIdentifier || '',
|
|
67
|
-
priority: author.priority,
|
|
115
|
+
priority: author.priority || 0,
|
|
68
116
|
isJointContributor: author.isJointContributor || false,
|
|
69
|
-
userID: '',
|
|
70
|
-
invitationID: '',
|
|
117
|
+
userID: author.userID || '',
|
|
118
|
+
invitationID: author.invitationID || '',
|
|
71
119
|
footnote: author.footnote || [],
|
|
72
120
|
corresp: author.corresp || [],
|
|
73
121
|
});
|
|
74
|
-
export const AuthorsModal = ({ authors: $authors, affiliations: $affiliations, author, onSaveAuthor, onDeleteAuthor,
|
|
122
|
+
export const AuthorsModal = ({ authors: $authors, affiliations: $affiliations, author, onSaveAuthor, onDeleteAuthor, addNewAuthor = false, }) => {
|
|
75
123
|
const [isOpen, setOpen] = useState(true);
|
|
76
124
|
const [isDisableSave, setDisableSave] = useState(true);
|
|
77
125
|
const [isEmailRequired, setEmailRequired] = useState(false);
|
|
@@ -84,38 +132,74 @@ export const AuthorsModal = ({ authors: $authors, affiliations: $affiliations, a
|
|
|
84
132
|
const [nextAuthor, setNextAuthor] = useState(null);
|
|
85
133
|
const [isSwitchingAuthor, setIsSwitchingAuthor] = useState(false);
|
|
86
134
|
const [isCreatingNewAuthor, setIsCreatingNewAuthor] = useState(false);
|
|
135
|
+
const [showAffiliationDrawer, setShowAffiliationDrawer] = useState(false);
|
|
136
|
+
const [selectedAffiliations, setSelectedAffiliations] = useState([]);
|
|
87
137
|
const valuesRef = useRef();
|
|
88
138
|
const actionsRef = useRef();
|
|
89
139
|
const [authors, dispatchAuthors] = useReducer(authorsReducer, $authors.sort(authorComparator));
|
|
90
|
-
const [affiliations
|
|
140
|
+
const [affiliations] = useReducer(affiliationsReducer, $affiliations);
|
|
141
|
+
const affiliationItems = affiliations.map((affiliation) => ({
|
|
142
|
+
id: affiliation.id,
|
|
143
|
+
label: affiliation.institution,
|
|
144
|
+
country: affiliation.country,
|
|
145
|
+
city: affiliation.city,
|
|
146
|
+
state: affiliation.county,
|
|
147
|
+
}));
|
|
148
|
+
const [selectedAffiliationIds, setSelectedAffiliationIds] = useState([]);
|
|
91
149
|
useEffect(() => {
|
|
92
150
|
if (addNewAuthor) {
|
|
93
151
|
handleAddAuthor();
|
|
94
152
|
}
|
|
95
153
|
}, [addNewAuthor]);
|
|
96
154
|
const [selection, setSelection] = useState(author);
|
|
155
|
+
useEffect(() => {
|
|
156
|
+
const currentAuthor = selection;
|
|
157
|
+
const relevantAffiliations = affiliationItems.filter((item) => { var _a; return (_a = currentAuthor === null || currentAuthor === void 0 ? void 0 : currentAuthor.affiliations) === null || _a === void 0 ? void 0 : _a.includes(item.id); });
|
|
158
|
+
setSelectedAffiliations(relevantAffiliations);
|
|
159
|
+
setSelectedAffiliationIds(relevantAffiliations.map((item) => item.id));
|
|
160
|
+
}, []);
|
|
97
161
|
const handleSelect = (author) => {
|
|
98
162
|
const values = valuesRef.current;
|
|
99
163
|
setIsCreatingNewAuthor(false);
|
|
100
|
-
if (values && selection
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
164
|
+
if (values && selection) {
|
|
165
|
+
const normalizedSelection = normalize(selection);
|
|
166
|
+
const normalizedValues = normalize(values);
|
|
167
|
+
const hasChanges = !isEqual(normalizedSelection, normalizedValues);
|
|
168
|
+
if (hasChanges && !isDisableSave) {
|
|
169
|
+
setShowConfirmationDialog(true);
|
|
170
|
+
setNextAuthor(author);
|
|
171
|
+
}
|
|
172
|
+
else if (hasChanges && isDisableSave) {
|
|
173
|
+
setShowRequiredFieldConfirmationDialog(true);
|
|
174
|
+
setNextAuthor(author);
|
|
175
|
+
}
|
|
176
|
+
else {
|
|
177
|
+
updateAffiliationSelection(author);
|
|
178
|
+
setSelection(author);
|
|
179
|
+
setShowAffiliationDrawer(false);
|
|
180
|
+
setNewAuthor(false);
|
|
181
|
+
}
|
|
107
182
|
}
|
|
108
183
|
else {
|
|
184
|
+
setShowAffiliationDrawer(false);
|
|
185
|
+
updateAffiliationSelection(author);
|
|
109
186
|
setSelection(author);
|
|
110
187
|
setNewAuthor(false);
|
|
111
188
|
}
|
|
112
189
|
};
|
|
190
|
+
const updateAffiliationSelection = (author) => {
|
|
191
|
+
const relevantAffiliations = affiliationItems.filter((item) => { var _a; return (_a = author.affiliations) === null || _a === void 0 ? void 0 : _a.includes(item.id); });
|
|
192
|
+
setSelectedAffiliations(relevantAffiliations);
|
|
193
|
+
setSelectedAffiliationIds(relevantAffiliations.map((item) => item.id));
|
|
194
|
+
};
|
|
113
195
|
const handleClose = () => {
|
|
114
|
-
if (
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
196
|
+
if (unSavedChanges) {
|
|
197
|
+
if (isDisableSave) {
|
|
198
|
+
setShowRequiredFieldConfirmationDialog(true);
|
|
199
|
+
}
|
|
200
|
+
else {
|
|
201
|
+
setShowConfirmationDialog(true);
|
|
202
|
+
}
|
|
119
203
|
}
|
|
120
204
|
else {
|
|
121
205
|
setShowRequiredFieldConfirmationDialog(false);
|
|
@@ -131,6 +215,7 @@ export const AuthorsModal = ({ authors: $authors, affiliations: $affiliations, a
|
|
|
131
215
|
setSelection(nextAuthor);
|
|
132
216
|
setNextAuthor(null);
|
|
133
217
|
setNewAuthor(false);
|
|
218
|
+
setShowAffiliationDrawer(false);
|
|
134
219
|
setIsCreatingNewAuthor(false);
|
|
135
220
|
}
|
|
136
221
|
else if (isCreatingNewAuthor) {
|
|
@@ -142,10 +227,14 @@ export const AuthorsModal = ({ authors: $authors, affiliations: $affiliations, a
|
|
|
142
227
|
const handleCancel = () => {
|
|
143
228
|
handleResetAuthor();
|
|
144
229
|
if (nextAuthor) {
|
|
230
|
+
const affiliations = nextAuthor.affiliations || [];
|
|
231
|
+
setSelectedAffiliationIds(affiliations);
|
|
232
|
+
setSelectedAffiliations(affiliationItems.filter((item) => affiliations.includes(item.id)));
|
|
145
233
|
setSelection(nextAuthor);
|
|
146
234
|
setNextAuthor(null);
|
|
147
235
|
setNewAuthor(false);
|
|
148
236
|
setIsCreatingNewAuthor(false);
|
|
237
|
+
setUnSavedChanges(false);
|
|
149
238
|
}
|
|
150
239
|
else if (newAuthor && unSavedChanges && !isSwitchingAuthor) {
|
|
151
240
|
setNewAuthor(false);
|
|
@@ -157,6 +246,8 @@ export const AuthorsModal = ({ authors: $authors, affiliations: $affiliations, a
|
|
|
157
246
|
setIsCreatingNewAuthor(false);
|
|
158
247
|
}
|
|
159
248
|
setShowConfirmationDialog(false);
|
|
249
|
+
setShowRequiredFieldConfirmationDialog(false);
|
|
250
|
+
setShowAffiliationDrawer(false);
|
|
160
251
|
};
|
|
161
252
|
const handleSaveAuthor = (values) => {
|
|
162
253
|
if (!values || !selection) {
|
|
@@ -172,6 +263,9 @@ export const AuthorsModal = ({ authors: $authors, affiliations: $affiliations, a
|
|
|
172
263
|
setSelection(author);
|
|
173
264
|
setShowConfirmationDialog(false);
|
|
174
265
|
setNewAuthor(false);
|
|
266
|
+
setSelectedAffiliationIds([]);
|
|
267
|
+
setSelectedAffiliations([]);
|
|
268
|
+
setShowAffiliationDrawer(false);
|
|
175
269
|
setIsCreatingNewAuthor(false);
|
|
176
270
|
dispatchAuthors({
|
|
177
271
|
type: 'update',
|
|
@@ -211,6 +305,8 @@ export const AuthorsModal = ({ authors: $authors, affiliations: $affiliations, a
|
|
|
211
305
|
footnote: [],
|
|
212
306
|
};
|
|
213
307
|
setIsSwitchingAuthor(!!selection);
|
|
308
|
+
setSelectedAffiliations([]);
|
|
309
|
+
setSelectedAffiliationIds([]);
|
|
214
310
|
setSelection(author);
|
|
215
311
|
setNewAuthor(true);
|
|
216
312
|
};
|
|
@@ -218,7 +314,9 @@ export const AuthorsModal = ({ authors: $authors, affiliations: $affiliations, a
|
|
|
218
314
|
const values = valuesRef.current;
|
|
219
315
|
setIsSwitchingAuthor(!!selection);
|
|
220
316
|
setIsCreatingNewAuthor(true);
|
|
221
|
-
if (values &&
|
|
317
|
+
if (values &&
|
|
318
|
+
selection &&
|
|
319
|
+
!isEqual(normalize(values), normalize(selection))) {
|
|
222
320
|
if (isDisableSave) {
|
|
223
321
|
setShowRequiredFieldConfirmationDialog(true);
|
|
224
322
|
}
|
|
@@ -229,6 +327,7 @@ export const AuthorsModal = ({ authors: $authors, affiliations: $affiliations, a
|
|
|
229
327
|
}
|
|
230
328
|
else {
|
|
231
329
|
createNewAuthor();
|
|
330
|
+
setShowAffiliationDrawer(false);
|
|
232
331
|
}
|
|
233
332
|
};
|
|
234
333
|
const handleDeleteAuthor = () => {
|
|
@@ -237,37 +336,26 @@ export const AuthorsModal = ({ authors: $authors, affiliations: $affiliations, a
|
|
|
237
336
|
}
|
|
238
337
|
onDeleteAuthor(selection);
|
|
239
338
|
setSelection(undefined);
|
|
339
|
+
setUnSavedChanges(false);
|
|
240
340
|
dispatchAuthors({
|
|
241
341
|
type: 'delete',
|
|
242
342
|
item: selection,
|
|
243
343
|
});
|
|
244
344
|
};
|
|
245
|
-
const
|
|
246
|
-
|
|
247
|
-
dispatchAffiliations({
|
|
248
|
-
type: 'update',
|
|
249
|
-
items: [affiliation],
|
|
250
|
-
});
|
|
251
|
-
};
|
|
252
|
-
const handleAddAffiliation = (affiliation) => {
|
|
253
|
-
if (!valuesRef.current) {
|
|
254
|
-
return;
|
|
255
|
-
}
|
|
256
|
-
const values = valuesRef.current;
|
|
257
|
-
const affiliations = values.affiliations || [];
|
|
258
|
-
handleSaveAuthor(Object.assign(Object.assign({}, values), { affiliations: [...affiliations, affiliation.id] }));
|
|
259
|
-
};
|
|
260
|
-
const handleRemoveAffiliation = (affiliation) => {
|
|
261
|
-
var _a;
|
|
262
|
-
if (!valuesRef.current) {
|
|
345
|
+
const handleRemoveAffiliation = (affId) => {
|
|
346
|
+
if (!selection) {
|
|
263
347
|
return;
|
|
264
348
|
}
|
|
265
|
-
const
|
|
266
|
-
|
|
349
|
+
const newAffiliations = selectedAffiliationIds.filter((id) => id !== affId);
|
|
350
|
+
setSelectedAffiliationIds(newAffiliations);
|
|
351
|
+
setSelectedAffiliations(affiliationItems.filter((item) => newAffiliations.includes(item.id)));
|
|
267
352
|
};
|
|
268
353
|
const handleResetAuthor = () => {
|
|
269
354
|
var _a;
|
|
270
355
|
(_a = actionsRef.current) === null || _a === void 0 ? void 0 : _a.reset();
|
|
356
|
+
const affiliations = (selection === null || selection === void 0 ? void 0 : selection.affiliations) || [];
|
|
357
|
+
setSelectedAffiliationIds(affiliations);
|
|
358
|
+
setSelectedAffiliations(affiliationItems.filter((item) => affiliations.includes(item.id)));
|
|
271
359
|
setShowConfirmationDialog(false);
|
|
272
360
|
setShowRequiredFieldConfirmationDialog(false);
|
|
273
361
|
setUnSavedChanges(false);
|
|
@@ -282,60 +370,76 @@ export const AuthorsModal = ({ authors: $authors, affiliations: $affiliations, a
|
|
|
282
370
|
};
|
|
283
371
|
const handleChangeAuthor = (values) => {
|
|
284
372
|
const normalized = omit(normalize(selection), 'priority');
|
|
285
|
-
const updatedValues = omit(values, 'priority');
|
|
286
|
-
|
|
287
|
-
|
|
373
|
+
const updatedValues = omit(normalize(values), 'priority');
|
|
374
|
+
const isSameAuthor = updatedValues.id === normalized.id;
|
|
375
|
+
const hasChanges = !isEqual(updatedValues, normalized);
|
|
376
|
+
if (isSameAuthor && hasChanges) {
|
|
288
377
|
setUnSavedChanges(true);
|
|
289
378
|
}
|
|
290
|
-
|
|
291
|
-
|
|
379
|
+
else {
|
|
380
|
+
setUnSavedChanges(false);
|
|
381
|
+
}
|
|
382
|
+
valuesRef.current = Object.assign(Object.assign({}, updatedValues), { priority: values.priority });
|
|
292
383
|
const { given, family } = values.bibliographicName;
|
|
293
384
|
const { email, isCorresponding } = values;
|
|
294
385
|
const isNameFilled = (given === null || given === void 0 ? void 0 : given.length) && (family === null || family === void 0 ? void 0 : family.length);
|
|
295
|
-
if (
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
setDisableSave(false);
|
|
386
|
+
if (hasChanges && isNameFilled) {
|
|
387
|
+
if (isCorresponding) {
|
|
388
|
+
setDisableSave(!(email === null || email === void 0 ? void 0 : email.length));
|
|
389
|
+
}
|
|
390
|
+
else {
|
|
391
|
+
setDisableSave(false);
|
|
392
|
+
}
|
|
303
393
|
}
|
|
304
394
|
else {
|
|
305
395
|
setDisableSave(true);
|
|
306
396
|
}
|
|
307
|
-
|
|
308
|
-
setEmailRequired(true);
|
|
309
|
-
}
|
|
310
|
-
else {
|
|
311
|
-
setEmailRequired(false);
|
|
312
|
-
}
|
|
397
|
+
setEmailRequired(isCorresponding);
|
|
313
398
|
};
|
|
314
399
|
const handleShowDeleteDialog = () => {
|
|
315
400
|
setShowDeleteDialog((prev) => !prev);
|
|
316
401
|
};
|
|
402
|
+
const handleAffiliationSelect = (affiliationId) => {
|
|
403
|
+
if (!selection) {
|
|
404
|
+
return;
|
|
405
|
+
}
|
|
406
|
+
const currentAffiliations = selectedAffiliationIds || [];
|
|
407
|
+
const isAlreadySelected = currentAffiliations.includes(affiliationId);
|
|
408
|
+
const newAffiliations = isAlreadySelected
|
|
409
|
+
? currentAffiliations.filter((id) => id !== affiliationId)
|
|
410
|
+
: [...currentAffiliations, affiliationId];
|
|
411
|
+
setSelectedAffiliationIds(newAffiliations);
|
|
412
|
+
setSelectedAffiliations(affiliationItems.filter((item) => newAffiliations.includes(item.id)));
|
|
413
|
+
};
|
|
317
414
|
return (React.createElement(StyledModal, { isOpen: isOpen, onRequestClose: () => handleClose(), shouldCloseOnOverlayClick: true },
|
|
318
415
|
React.createElement(ModalContainer, null,
|
|
319
416
|
React.createElement(ModalHeader, null,
|
|
320
417
|
React.createElement(CloseButton, { onClick: () => handleClose(), "data-cy": "modal-close-button" })),
|
|
321
|
-
React.createElement(
|
|
418
|
+
React.createElement(StyledModalBody, null,
|
|
322
419
|
React.createElement(ModalSidebar, { "data-cy": "authors-sidebar" },
|
|
323
|
-
React.createElement(
|
|
420
|
+
React.createElement(StyledModalSidebarHeader, null,
|
|
324
421
|
React.createElement(ModalSidebarTitle, null, "Authors")),
|
|
325
422
|
React.createElement(StyledSidebarContent, null,
|
|
326
|
-
React.createElement(AddAuthorButton, { "data-cy": "add-author-button", onClick: handleAddAuthor },
|
|
423
|
+
React.createElement(AddAuthorButton, { "data-cy": "add-author-button", onClick: handleAddAuthor, "data-active": isCreatingNewAuthor },
|
|
327
424
|
React.createElement(AddIcon, { width: 18, height: 18 }),
|
|
328
425
|
React.createElement(ActionTitle, null, "New Author")),
|
|
329
426
|
React.createElement(AuthorList, { author: selection, authors: authors, onSelect: handleSelect, onDelete: handleShowDeleteDialog, moveAuthor: handleMoveAuthor, lastSavedAuthor: lastSavedAuthor }))),
|
|
330
427
|
React.createElement(ScrollableModalContent, { "data-cy": "author-modal-content" }, selection ? (React.createElement(AuthorForms, null,
|
|
331
|
-
React.createElement(
|
|
332
|
-
React.createElement(
|
|
333
|
-
React.createElement(
|
|
428
|
+
React.createElement(ConfirmationDialog, { isOpen: showRequiredFieldConfirmationDialog, onPrimary: () => setShowRequiredFieldConfirmationDialog(false), onSecondary: handleCancel, type: DialogType.REQUIRED, entityType: "author" }),
|
|
429
|
+
React.createElement(ConfirmationDialog, { isOpen: showConfirmationDialog, onPrimary: handleSave, onSecondary: handleCancel, type: DialogType.SAVE, entityType: "author" }),
|
|
430
|
+
React.createElement(ModalFormActions, { type: "author", onSave: () => handleSaveAuthor(valuesRef.current), onDelete: handleDeleteAuthor, showDeleteDialog: showDeleteDialog, handleShowDeleteDialog: handleShowDeleteDialog, newEntity: newAuthor ||
|
|
334
431
|
(isCreatingNewAuthor &&
|
|
335
432
|
!showConfirmationDialog &&
|
|
336
433
|
!showRequiredFieldConfirmationDialog), isDisableSave: isDisableSave }),
|
|
337
434
|
React.createElement(FormLabel, null, "Details"),
|
|
338
|
-
React.createElement(AuthorDetailsForm, { values: normalize(selection), onChange: handleChangeAuthor, onSave: handleSaveAuthor, actionsRef: actionsRef, isEmailRequired: isEmailRequired }),
|
|
339
|
-
React.createElement(
|
|
340
|
-
|
|
435
|
+
React.createElement(AuthorDetailsForm, { values: normalize(selection), onChange: handleChangeAuthor, onSave: handleSaveAuthor, actionsRef: actionsRef, isEmailRequired: isEmailRequired, selectedAffiliations: selectedAffiliationIds }),
|
|
436
|
+
React.createElement(AuthorsSection, null,
|
|
437
|
+
React.createElement(AuthorsHeader, null,
|
|
438
|
+
React.createElement(AuthorsTitle, null, "Authors"),
|
|
439
|
+
React.createElement(AffiliateButton, { onClick: () => setShowAffiliationDrawer(true), "data-cy": "affiliate-authors-button" },
|
|
440
|
+
React.createElement(AddInstitutionIcon, { width: 16, height: 16 }),
|
|
441
|
+
"Assign Institutions")),
|
|
442
|
+
React.createElement(SelectedItemsBox, { items: selectedAffiliations, onRemove: handleRemoveAffiliation, placeholder: "No institutions assigned" })),
|
|
443
|
+
showAffiliationDrawer && (React.createElement(Drawer, { items: affiliationItems, selectedIds: selectedAffiliationIds, title: "Authors", onSelect: handleAffiliationSelect, onBack: () => setShowAffiliationDrawer(false), width: "100%" })))) : (React.createElement(FormPlaceholder, { type: "author", title: 'Author Details', message: 'Select an author from the list to display their details here.', placeholderIcon: React.createElement(AuthorPlaceholderIcon, null) })))),
|
|
444
|
+
React.createElement(FormFooter, { onCancel: handleClose }))));
|
|
341
445
|
};
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { AttentionOrangeIcon, Category, Dialog } from '@manuscripts/style-guide';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import styled from 'styled-components';
|
|
4
|
+
const StyledIcon = styled(AttentionOrangeIcon) `
|
|
5
|
+
margin-right: 8px;
|
|
6
|
+
`;
|
|
7
|
+
const MessageBox = styled.div `
|
|
8
|
+
display: flex;
|
|
9
|
+
flex-direction: column;
|
|
10
|
+
justify-content: space-between;
|
|
11
|
+
min-height: 90px;
|
|
12
|
+
`;
|
|
13
|
+
export var DialogType;
|
|
14
|
+
(function (DialogType) {
|
|
15
|
+
DialogType["SAVE"] = "save";
|
|
16
|
+
DialogType["DELETE"] = "delete";
|
|
17
|
+
DialogType["REQUIRED"] = "required";
|
|
18
|
+
})(DialogType || (DialogType = {}));
|
|
19
|
+
const getDialogConfig = (dialogType, entityType) => {
|
|
20
|
+
const configs = {
|
|
21
|
+
[DialogType.SAVE]: {
|
|
22
|
+
title: 'Unsaved changes',
|
|
23
|
+
message: {
|
|
24
|
+
primary: "You've made changes but not saved them!",
|
|
25
|
+
secondary: 'Would you like to save or discard your changes?',
|
|
26
|
+
},
|
|
27
|
+
buttons: {
|
|
28
|
+
primary: 'Save',
|
|
29
|
+
secondary: 'Discard',
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
[DialogType.DELETE]: {
|
|
33
|
+
title: `Delete ${entityType}`,
|
|
34
|
+
message: {
|
|
35
|
+
primary: entityType === 'affiliation'
|
|
36
|
+
? 'This action will delete the institution and any links to authors affiliated to it.'
|
|
37
|
+
: `Are you sure you want to remove this ${entityType} from the list?`,
|
|
38
|
+
secondary: 'Do you want to continue?',
|
|
39
|
+
},
|
|
40
|
+
buttons: {
|
|
41
|
+
primary: 'Delete',
|
|
42
|
+
secondary: 'Cancel',
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
[DialogType.REQUIRED]: {
|
|
46
|
+
title: 'Empty required field',
|
|
47
|
+
message: {
|
|
48
|
+
primary: 'A required field has been left empty. If you discard, any updates will not be saved!',
|
|
49
|
+
secondary: 'Would you like to discard or continue editing?',
|
|
50
|
+
},
|
|
51
|
+
buttons: {
|
|
52
|
+
primary: 'Continue editing',
|
|
53
|
+
secondary: 'Discard',
|
|
54
|
+
},
|
|
55
|
+
minHeight: '90px',
|
|
56
|
+
},
|
|
57
|
+
};
|
|
58
|
+
return configs[dialogType];
|
|
59
|
+
};
|
|
60
|
+
export const ConfirmationDialog = ({ isOpen, type, entityType, onPrimary, onSecondary, }) => {
|
|
61
|
+
const config = getDialogConfig(type, entityType);
|
|
62
|
+
const Header = () => (React.createElement(React.Fragment, null,
|
|
63
|
+
React.createElement(StyledIcon, null),
|
|
64
|
+
" ",
|
|
65
|
+
config.title));
|
|
66
|
+
const Message = () => (React.createElement(MessageBox, null,
|
|
67
|
+
React.createElement("div", null, config.message.primary),
|
|
68
|
+
config.message.secondary && React.createElement("div", null, config.message.secondary)));
|
|
69
|
+
return (React.createElement(Dialog, { isOpen: isOpen, category: Category.confirmation, header: React.createElement(Header, null), message: React.createElement(Message, null), actions: {
|
|
70
|
+
primary: {
|
|
71
|
+
action: onPrimary,
|
|
72
|
+
title: config.buttons.primary,
|
|
73
|
+
},
|
|
74
|
+
secondary: {
|
|
75
|
+
action: onSecondary,
|
|
76
|
+
title: config.buttons.secondary,
|
|
77
|
+
},
|
|
78
|
+
} }));
|
|
79
|
+
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import styled from 'styled-components';
|
|
3
|
+
const Footer = styled.div `
|
|
4
|
+
display: flex;
|
|
5
|
+
justify-content: flex-end;
|
|
6
|
+
align-items: center;
|
|
7
|
+
padding: 16px 32px;
|
|
8
|
+
height: 40px;
|
|
9
|
+
box-shadow: 0px -2px 12px 0px rgba(216, 216, 216, 0.26);
|
|
10
|
+
border-radius: 0px 0px 8px 8px;
|
|
11
|
+
`;
|
|
12
|
+
const RemoveButton = styled.button `
|
|
13
|
+
background-color: #0d79d0;
|
|
14
|
+
color: ${(props) => props.theme.colors.text.onDark};
|
|
15
|
+
padding: 8px 32px;
|
|
16
|
+
border-radius: 4px;
|
|
17
|
+
border: 1px solid #0d79d0;
|
|
18
|
+
&:hover {
|
|
19
|
+
background-color: ${(props) => props.theme.colors.background.hover};
|
|
20
|
+
}
|
|
21
|
+
cursor: pointer;
|
|
22
|
+
`;
|
|
23
|
+
const FormFooter = ({ onCancel }) => {
|
|
24
|
+
return (React.createElement(Footer, null,
|
|
25
|
+
React.createElement(RemoveButton, { onClick: onCancel }, "Close")));
|
|
26
|
+
};
|
|
27
|
+
export default FormFooter;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import styled from 'styled-components';
|
|
3
|
+
const Container = styled.div `
|
|
4
|
+
display: flex;
|
|
5
|
+
flex-direction: column;
|
|
6
|
+
align-items: center;
|
|
7
|
+
justify-content: center;
|
|
8
|
+
height: 100%;
|
|
9
|
+
overflow-y: auto;
|
|
10
|
+
`;
|
|
11
|
+
const Placeholder = styled.div `
|
|
12
|
+
margin-bottom: ${(props) => props.theme.grid.unit * 5}px;
|
|
13
|
+
`;
|
|
14
|
+
const Action = styled.div `
|
|
15
|
+
font-size: ${(props) => props.theme.font.size.xlarge};
|
|
16
|
+
font-weight: ${(props) => props.theme.font.weight.medium};
|
|
17
|
+
letter-spacing: -0.5px;
|
|
18
|
+
`;
|
|
19
|
+
const Message = styled.div `
|
|
20
|
+
max-width: 400px;
|
|
21
|
+
font-size: ${(props) => props.theme.font.size.xlarge};
|
|
22
|
+
margin-top: ${(props) => props.theme.grid.unit * 6}px;
|
|
23
|
+
font-weight: ${(props) => props.theme.font.weight.light};
|
|
24
|
+
color: ${(props) => props.theme.colors.text.secondary};
|
|
25
|
+
text-align: center;
|
|
26
|
+
|
|
27
|
+
@media (max-width: 850px) {
|
|
28
|
+
margin-right: ${(props) => props.theme.grid.unit * 5}px;
|
|
29
|
+
margin-left: ${(props) => props.theme.grid.unit * 5}px;
|
|
30
|
+
max-width: 350px;
|
|
31
|
+
}
|
|
32
|
+
`;
|
|
33
|
+
export const FormPlaceholder = ({ type, title, message, placeholderIcon, }) => (React.createElement(Container, { "data-cy": `${type}-details` },
|
|
34
|
+
React.createElement(Placeholder, null, placeholderIcon),
|
|
35
|
+
React.createElement(Action, null, title),
|
|
36
|
+
React.createElement(Message, null, message)));
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { ButtonGroup, IconButton, PlusIcon } from '@manuscripts/style-guide';
|
|
2
2
|
import React from 'react';
|
|
3
3
|
import styled from 'styled-components';
|
|
4
|
-
import {
|
|
5
|
-
const
|
|
4
|
+
import { ConfirmationDialog, DialogType } from '../dialog/ConfirmationDialog';
|
|
5
|
+
const ActionsContainer = styled.div `
|
|
6
6
|
display: flex;
|
|
7
7
|
`;
|
|
8
8
|
const StyledButtonGroup = styled(ButtonGroup) `
|
|
@@ -14,8 +14,9 @@ const StyledIconButton = styled(IconButton) `
|
|
|
14
14
|
font-size: 14px;
|
|
15
15
|
font-style: normal;
|
|
16
16
|
font-weight: 400;
|
|
17
|
-
line-height:
|
|
17
|
+
line-height: 1;
|
|
18
18
|
width: auto;
|
|
19
|
+
height: 24px;
|
|
19
20
|
&:disabled {
|
|
20
21
|
color: #c9c9c9 !important;
|
|
21
22
|
background-color: unset !important;
|
|
@@ -25,14 +26,14 @@ const StyledIconButton = styled(IconButton) `
|
|
|
25
26
|
margin-right: 4px;
|
|
26
27
|
}
|
|
27
28
|
`;
|
|
28
|
-
export const
|
|
29
|
-
return (React.createElement(
|
|
30
|
-
React.createElement(
|
|
31
|
-
handleShowDeleteDialog();
|
|
29
|
+
export const ModalFormActions = ({ type, onSave, onDelete, showDeleteDialog, handleShowDeleteDialog, newEntity, isDisableSave, }) => {
|
|
30
|
+
return (React.createElement(ActionsContainer, { "data-cy": `${type}-action` },
|
|
31
|
+
React.createElement(ConfirmationDialog, { isOpen: showDeleteDialog, onPrimary: () => {
|
|
32
32
|
onDelete();
|
|
33
|
-
|
|
33
|
+
handleShowDeleteDialog();
|
|
34
|
+
}, onSecondary: handleShowDeleteDialog, type: DialogType.DELETE, entityType: type }),
|
|
34
35
|
React.createElement(StyledButtonGroup, null,
|
|
35
36
|
React.createElement(StyledIconButton, { onClick: onSave, disabled: isDisableSave, type: "submit" },
|
|
36
37
|
React.createElement(PlusIcon, null),
|
|
37
|
-
|
|
38
|
+
newEntity ? 'Save Details' : 'Update Details'))));
|
|
38
39
|
};
|