import moment from 'moment' import { has, get, find, omit, isEmpty, debounce, mergeWith, capitalize, } from 'lodash' import { change as changeForm } from 'redux-form' import { actions } from 'pubsweet-client/src' import { handleError } from 'pubsweet-component-faraday-ui' import { autosaveRequest, autosaveFailure, autosaveSuccess, } from 'pubsweet-component-wizard/src/redux/autosave' import { createRecommendation, updateRecommendation, } from '../redux/recommendations' export const parseTitle = version => { const title = get(version, 'metadata.title') if (title) { return title.replace(/<p[^>]*>/g, '').replace(/<\/p>/g, '') } return 'Untitled' } export const parseAuthor = version => { const author = find(get(version, 'authors'), a => a.isSubmitting) return author ? `${author.firstName} ${author.lastName}` : 'N/A' } export const parseType = version => { const type = get(version, 'metadata.type') return type ? type.replace('-', ' ') : 'N/A' } export const parseSubmissionDate = version => { const submitted = get(version, 'submitted') const submittedDate = moment(submitted) const today = moment() const daysAgo = moment.duration(today - moment(submitted)).days() return submitted ? `${submittedDate.format('DD.MM.YYYY')} ${ daysAgo > 0 ? `(${daysAgo} days)` : '' }` : 'N/A' } export const mapStatusToLabel = ({ visibleStatus, status }) => { if (visibleStatus) { return visibleStatus } else if (status) { return capitalize(status) } return 'Draft' } export const parseVersion = version => ({ type: parseType(version), title: parseTitle(version), author: parseAuthor(version), version: get(version, 'version'), submitted: parseSubmissionDate(version), abstract: get(version, 'metadata.abstract'), }) export const parseJournalIssue = (journal, metadata) => journal.issueTypes.find(t => t.value === get(metadata, 'issue')) export const parseSearchParams = url => { const params = new URLSearchParams(url) const parsedObject = {} /* eslint-disable */ for ([key, value] of params) { parsedObject[key] = value } /* eslint-enable */ return parsedObject } export const parseVersionOptions = (fragments = []) => fragments .map((f, index) => ({ value: f, label: `Version ${index + 1}`, })) .reverse() const alreadyAnswered = `You have already answered this invitation.` export const redirectToError = redirectFn => err => { const errorText = get(JSON.parse(err.response), 'error') if (errorText.includes('has already been answered')) { redirectFn('/error-page', alreadyAnswered) } else { redirectFn('/error-page', 'Something went wrong. Please try again.') } } export const parseReviewResponseToForm = (review = {}) => { if (isEmpty(review)) return {} const comments = get(review, 'comments', []) const publicComment = comments.find(c => c.public) const privateComment = comments.find(c => !c.public) return { ...review, public: get(publicComment, 'content'), file: get(publicComment, 'files.0', null), confidential: get(privateComment, 'content'), } } export const parseReviewRequest = (review = {}) => { if (isEmpty(review)) return {} const comments = [ { public: true, files: has(review, 'file') ? [get(review, 'file')] : [], content: get(review, 'public'), }, ] if (get(review, 'confidential', '')) { comments.push({ public: false, content: get(review, 'confidential'), files: [], }) } return { id: get(review, 'id', null), comments, recommendationType: 'review', recommendation: get(review, 'recommendation', 'publish'), } } export const reviewerReportValidate = values => { const errors = {} if (!values.public && !values.file) { errors.public = 'A file or a public report is required.' } return errors } const onChange = (values, dispatch, { project, version }) => { const newValues = parseReviewRequest(values) dispatch(autosaveRequest()) if (newValues.id) { updateRecommendation({ fragmentId: version.id, collectionId: project.id, recommendation: newValues, }).then( r => { dispatch(autosaveSuccess(Date.now())) return r }, err => { dispatch(autosaveFailure()) throw err }, ) } else { createRecommendation({ fragmentId: version.id, collectionId: project.id, recommendation: omit(newValues, 'id'), }).then( r => { dispatch(changeForm('reviewerReport', 'id', r.id)) dispatch(autosaveSuccess(Date.now())) return r }, err => { dispatch(autosaveFailure()) throw err }, ) } } export const onReviewChange = debounce(onChange, 1000, { maxWait: 5000 }) export const onReviewSubmit = ( values, dispatch, { project, version, showModal, setFetching, isSubmitting }, ) => { showModal({ title: 'Are you done?', subtitle: 'Once submitted, the report cannot be modified.', confirmText: 'Submit report', onConfirm: ({ hideModal, setModalError }) => { setFetching(true) const newValues = parseReviewRequest(values) newValues.submittedOn = Date.now() updateRecommendation({ fragmentId: version.id, collectionId: project.id, recommendation: newValues, }) .then(() => dispatch(actions.getCollection({ id: project.id }))) .then(() => { dispatch(actions.getFragments({ id: project.id })) hideModal() }) .catch(err => { setFetching(false) handleError(setModalError)(err) }) }, }) } const parseRevision = (values, fragment) => { const v = omit(values, 'authorForm') return { ...fragment, revision: { ...v, metadata: mergeWith( {}, fragment.metadata, v.metadata, (obj, src) => (src === '' ? obj : src), ), }, } } const _onRevisionChange = (values, dispatch, { project, version }) => { dispatch(actions.updateFragment(project, parseRevision(values, version))) } export const onRevisionChange = debounce(_onRevisionChange, 1000, { maxWait: 5000, }) export const onRevisionSubmit = ( values, dispatch, { history, version, project, showModal, hideModal, setModalError, submitRevision, }, ) => { showModal({ title: 'Ready to submit your revision?', subtitle: `Once submitted, the submission can't be modified.`, onConfirm: () => { submitRevision(project.id, version.id) .then(r => { dispatch(actions.getFragments({ id: project.id })).then(() => { history.push(`/projects/${r.collectionId}/versions/${r.id}/details`) hideModal() }) }) .catch(e => setModalError('Something went wrong.')) }, onCancel: hideModal, }) } // revision validators export const requiredHTML = value => { if (value && value.replace('<p></p>', '').replace('<h1></h1>', '')) { return undefined } return 'Required' } export const requiredFiles = (values, formValues) => { const manuscripts = get(formValues, 'files.manuscripts') if (!manuscripts || manuscripts.length === 0) { return 'At least one main manuscript file is needed.' } return undefined } // new stuff export const parseEicDecision = ({ decision, message }) => ({ recommendation: decision, recommendationType: 'editorRecommendation', comments: [ { public: decision !== 'return-to-handling-editor', content: message, }, ], })