pubsweet-component-bookbuilder
Version:
503 lines (480 loc) • 15 kB
JavaScript
/* eslint-disable no-console */
import React from 'react'
import { get, findIndex, map, find, pickBy } from 'lodash'
import { adopt } from 'react-adopt'
import { withRouter } from 'react-router-dom'
import withModal from 'editoria-common/src/withModal'
import BookBuilder from './BookBuilder'
import statefull from './Statefull'
import {
getBookQuery,
getBookBuilderRulesQuery,
getTemplatesQuery,
createBookComponentMutation,
deleteBookComponentMutation,
updateBookComponentPaginationMutation,
updatedBookComponentOrderMutation,
updateBookComponentWorkflowStateMutation,
updateBookComponentUploadingMutation,
unlockBookComponentMutation,
ingestWordFilesMutation,
updateBookComponentTypeMutation,
updateApplicationParametersMutation,
exportBookMutation,
orderChangeSubscription,
bookComponentAddedSubscription,
bookComponentDeletedSubscription,
paginationChangeSubscription,
workflowChangeSubscription,
lockChangeSubscription,
titleChangeSubscription,
productionEditorChangeSubscription,
componentTypeChangeSubscription,
addTeamMemberSubscription,
updateBookMetadataMutation,
bookMetadataSubscription,
updateRunningHeadersMutation,
runningHeadersUpdatedSubscription,
bookRenamedSubscription,
toggleIncludeInTOCMutation,
bookComponentIncludeInTOCSubscription,
uploadingUpdatedSubscription,
} from './queries'
const mapper = {
statefull,
withModal,
getBookQuery,
getTemplatesQuery,
getBookBuilderRulesQuery,
lockChangeSubscription,
orderChangeSubscription,
bookRenamedSubscription,
bookComponentAddedSubscription,
bookComponentDeletedSubscription,
paginationChangeSubscription,
workflowChangeSubscription,
titleChangeSubscription,
productionEditorChangeSubscription,
componentTypeChangeSubscription,
bookComponentIncludeInTOCSubscription,
runningHeadersUpdatedSubscription,
addTeamMemberSubscription,
bookMetadataSubscription,
uploadingUpdatedSubscription,
ingestWordFilesMutation,
updateBookMetadataMutation,
createBookComponentMutation,
unlockBookComponentMutation,
deleteBookComponentMutation,
toggleIncludeInTOCMutation,
updateBookComponentPaginationMutation,
updatedBookComponentOrderMutation,
updateBookComponentWorkflowStateMutation,
updateBookComponentUploadingMutation,
updateApplicationParametersMutation,
updateBookComponentTypeMutation,
updateRunningHeadersMutation,
exportBookMutation,
}
const mapProps = args => ({
state: args.statefull.state,
setState: args.statefull.setState,
book: get(args.getBookQuery, 'data.getBook'),
addBookComponent: args.createBookComponentMutation.addBookComponent,
deleteBookComponent: args.deleteBookComponentMutation.deleteBookComponent,
toggleIncludeInTOC: args.toggleIncludeInTOCMutation.toggleIncludeInTOC,
updateRunningHeaders: args.updateRunningHeadersMutation.updateRunningHeaders,
updateBookComponentPagination:
args.updateBookComponentPaginationMutation.updateBookComponentPagination,
updateBookComponentOrder:
args.updatedBookComponentOrderMutation.updateBookComponentOrder,
updateBookComponentWorkflowState:
args.updateBookComponentWorkflowStateMutation
.updateBookComponentWorkflowState,
updateBookComponentUploading:
args.updateBookComponentUploadingMutation.updateUploading,
updateComponentType: args.updateBookComponentTypeMutation.updateComponentType,
updateApplicationParameters:
args.updateApplicationParametersMutation.updateApplicationParameter,
updateBookMetadata: args.updateBookMetadataMutation.updateMetadata,
uploadBookComponent: args.ingestWordFilesMutation.ingestWordFiles,
unlockBookComponent: args.unlockBookComponentMutation.unlockBookComponent,
ingestWordFiles: args.ingestWordFilesMutation.ingestWordFiles,
exportBook: args.exportBookMutation.exportBook,
onDeleteBookComponent: (bookComponentId, componentType, title) => {
const { deleteBookComponentMutation, withModal } = args
const { deleteBookComponent } = deleteBookComponentMutation
const { showModal, hideModal } = withModal
const onConfirm = () => {
deleteBookComponent({
variables: {
input: {
id: bookComponentId,
deleted: true,
},
},
})
hideModal()
}
showModal('deleteBookComponent', {
onConfirm,
componentType,
title,
})
},
onTeamManager: bookId => {
args.withModal.showModal('bookTeamManager', {
bookId,
})
},
onError: error => {
const { withModal } = args
const { showModal, hideModal } = withModal
showModal('errorModal', {
onConfirm: hideModal,
error,
})
},
onBookSettings: book => {
const { withModal, updateRunningHeadersMutation } = args
const { updateRunningHeaders } = updateRunningHeadersMutation
const { showModal, hideModal } = withModal
const { divisions } = book
const bookComponents = []
for (let i = 0; i < divisions.length; i += 1) {
for (let j = 0; j < divisions[i].bookComponents.length; j += 1) {
bookComponents.push(divisions[i].bookComponents[j])
}
}
const onConfirm = bookComponents => {
updateRunningHeaders({
variables: {
input: bookComponents,
bookId: book.id,
},
})
hideModal()
}
showModal('bookSettingsModal', {
onConfirm,
bookComponents,
})
},
onWarning: warning => {
const { withModal } = args
const { showModal, hideModal } = withModal
showModal('warningModal', {
onConfirm: hideModal,
warning,
})
},
onEndNoteModal: componentType =>
new Promise((resolve, reject) => {
const {
withModal: { showModal, hideModal },
} = args
const onConfirm = () => {
hideModal()
resolve(true)
}
const onHideModal = () => {
hideModal()
resolve(false)
}
showModal('addEndNote', {
onConfirm,
onHideModal,
componentType,
})
}),
onAdminUnlock: (bookComponentId, componentType, title) => {
const { unlockBookComponentMutation, withModal } = args
const { unlockBookComponent } = unlockBookComponentMutation
const { showModal, hideModal } = withModal
const onConfirm = () => {
unlockBookComponent({
variables: {
input: {
id: bookComponentId,
},
},
})
hideModal()
}
showModal('unlockModal', {
onConfirm,
componentType,
title,
})
},
onMetadataAdd: book => {
const { updateBookMetadataMutation, withModal } = args
const { updateMetadata } = updateBookMetadataMutation
const { showModal, hideModal } = withModal
const onConfirm = values => {
if (values.edition === '') {
values.edition = 0
}
if (values.copyrightYear === '') {
values.copyrightYear = 1900
}
const filtered = pickBy(values, v => v !== null && v !== undefined)
updateMetadata({
variables: {
input: {
id: book.id,
...filtered,
},
},
}).then(res => {
hideModal()
})
}
showModal('metadataModal', {
onConfirm,
book,
})
},
onAssetManager: bookId => {
const { withModal } = args
const { showModal } = withModal
showModal('assetManagerModal', {
bookId,
withImport: false,
})
},
onExportBook: (book, bookTitle, history) => {
const { exportBookMutation, withModal } = args
const { exportBook } = exportBookMutation
const { showModal, hideModal } = withModal
const { divisions } = book
let endnotesComponent
const backmatterDivision = find(divisions, { label: 'Backmatter' })
let backmatterBookComponents
if (backmatterDivision) {
backmatterBookComponents = backmatterDivision.bookComponents
}
if (backmatterBookComponents) {
endnotesComponent = find(backmatterBookComponents, {
componentType: 'endnotes',
})
}
const getTemplates = target => {
const {
getTemplatesQuery: { client, query },
} = args
const variables = endnotesComponent
? Object.assign({ target }, { notes: 'endnotes' })
: { target }
return client.query({ query, variables, fetchPolicy: 'no-cache' })
}
const onConfirm = (mode, viewer, templateId, format) => {
const payload = {
mode,
templateId: undefined,
previewer: undefined,
fileExtension: undefined,
icmlNotes: endnotesComponent ? 'endnotes' : 'chapterEnd',
}
if (mode === 'preview') {
payload.templateId = templateId
payload.previewer = viewer
} else {
if (format !== 'icml') {
payload.templateId = templateId
}
payload.fileExtension = format
}
exportBook({
variables: {
input: {
bookId: book.id,
...payload,
},
},
})
.then(res => {
hideModal()
const { data } = res
const { exportBook } = data
const { path } = exportBook
if (mode === 'download') {
if (format === 'pdf') {
window.open(path, '_blank')
} else {
window.location.replace(path)
}
} else if (mode === 'preview') {
if (viewer === 'vivliostyle') {
const viliostylePath =
'/vivliostyle/viewer/vivliostyle-viewer.html'
const url = `${viliostylePath}#b=${path}`
window.open(url, '_blank')
} else {
history.push(`/books/${book.id}/pagedPreviewer/paged/${path}`)
}
}
})
.catch(res => {
hideModal()
showModal('warningModal', {
onConfirm: hideModal,
warning: `${res.message.replace('GraphQL error: Error: ', '')}`,
})
})
}
showModal('exportBookModal', {
onConfirm,
bookTitle,
getTemplates,
})
},
onWorkflowUpdate: (
bookComponentId,
workflowStages,
nextProgressValues,
textKey,
) => {
const { updateBookComponentWorkflowStateMutation, withModal } = args
const {
updateBookComponentWorkflowState,
} = updateBookComponentWorkflowStateMutation
const { showModal, hideModal } = withModal
const onConfirm = () => {
const { title, type, value } = nextProgressValues
const isLast =
workflowStages.length - 1 ===
findIndex(workflowStages, { label: title, type })
const indexOfStage = findIndex(workflowStages, { label: title, type })
if (value === 1) {
workflowStages[indexOfStage].value = value
if (!isLast) {
workflowStages[indexOfStage + 1].value = 0
}
}
if (value === -1) {
workflowStages[indexOfStage].value = value
const next = indexOfStage + 1
if (type !== 'file_prep') {
const previous = indexOfStage - 1
workflowStages[previous].value = 0
}
workflowStages[next].value = -1
}
if (value === 0) {
workflowStages[indexOfStage].value = value
const next = indexOfStage + 1
for (let i = next; i < workflowStages.length; i += 1) {
workflowStages[i].value = -1
}
}
const cleanedWorkflowStages = map(workflowStages, item => ({
label: item.label,
type: item.type,
value: item.value,
}))
updateBookComponentWorkflowState({
variables: {
input: {
id: bookComponentId,
workflowStages: cleanedWorkflowStages,
},
},
})
hideModal()
}
showModal('workflowModal', {
onConfirm,
textKey,
})
},
loading: args.getBookQuery.networkStatus === 1,
loadingRules: args.getBookBuilderRulesQuery.networkStatus === 1,
rules: get(args.getBookBuilderRulesQuery, 'data.getBookBuilderRules'),
refetching:
args.getBookQuery.networkStatus === 4 ||
args.getBookQuery.networkStatus === 2, // possible apollo bug
refetchingBookBuilderRules:
args.getBookBuilderRulesQuery.networkStatus === 4 ||
args.getBookBuilderRulesQuery.networkStatus === 2, // possible apollo bug
})
const Composed = adopt(mapper, mapProps)
const Connected = props => {
const { match, history, currentUser, applicationParameter } = props
const { id: bookId } = match.params
return (
<Composed bookId={bookId}>
{({
book,
state,
setState,
onTeamManager,
onBookSettings,
onExportBook,
addBookComponent,
deleteBookComponent,
toggleIncludeInTOC,
updateBookComponentPagination,
updateBookComponentOrder,
updateComponentType,
updateApplicationParameters,
updateBookComponentWorkflowState,
onError,
onWarning,
onMetadataAdd,
uploadBookComponent,
onAssetManager,
updateBookComponentUploading,
ingestWordFiles,
onDeleteBookComponent,
loading,
refetching,
onAdminUnlock,
onEndNoteModal,
loadingRules,
exportBook,
rules,
refetchingBookBuilderRules,
onWorkflowUpdate,
}) => (
<BookBuilder
addBookComponent={addBookComponent}
applicationParameter={applicationParameter}
book={book}
currentUser={currentUser}
deleteBookComponent={deleteBookComponent}
exportBook={exportBook}
history={history}
ingestWordFiles={ingestWordFiles}
loading={loading}
loadingRules={loadingRules}
onAdminUnlock={onAdminUnlock}
onAssetManager={onAssetManager}
onBookSettings={onBookSettings}
onDeleteBookComponent={onDeleteBookComponent}
onEndNoteModal={onEndNoteModal}
onError={onError}
onExportBook={onExportBook}
onMetadataAdd={onMetadataAdd}
onTeamManager={onTeamManager}
onWarning={onWarning}
onWorkflowUpdate={onWorkflowUpdate}
refetching={refetching}
refetchingBookBuilderRules={refetchingBookBuilderRules}
rules={rules}
setState={setState}
state={state}
toggleIncludeInTOC={toggleIncludeInTOC}
updateApplicationParameters={updateApplicationParameters}
updateBookComponentOrder={updateBookComponentOrder}
updateBookComponentPagination={updateBookComponentPagination}
updateBookComponentUploading={updateBookComponentUploading}
updateBookComponentWorkflowState={updateBookComponentWorkflowState}
updateComponentType={updateComponentType}
uploadBookComponent={uploadBookComponent}
/>
)}
</Composed>
)
}
export default withRouter(Connected)