Brandon Nicholls
Committed by GitHub

Merge pull request #714 from iambrandonn/RESCOI-1046

RESCOI-1046: Handle new travel logs on the revise screen
......@@ -20,7 +20,12 @@ import styles from './style';
import React from 'react';
import ProjectToReview from '../project-to-review';
export default function DeclarationSection({declarationsToReview, configId, className}) {
export default function DeclarationSection({
declarationsToReview,
configId,
className,
necessaryEntities
}) {
const projects = declarationsToReview;
const projectsJSX = projects.map((project, index) => {
......@@ -30,6 +35,7 @@ export default function DeclarationSection({declarationsToReview, configId, clas
project={project}
last={index === projects.length - 1}
configId={configId}
necessaryEntities={necessaryEntities}
/>
);
});
......@@ -45,3 +51,14 @@ export default function DeclarationSection({declarationsToReview, configId, clas
</div>
);
}
DeclarationSection.propTypes = {
declarationsToReview: React.PropTypes.arrayOf(React.PropTypes.object),
configId: React.PropTypes.number.isRequired,
className: React.PropTypes.string,
necessaryEntities: React.PropTypes.array.isRequired
};
DeclarationSection.defaultProps = {
declarationsToReview: []
};
......
......@@ -178,6 +178,11 @@ export default class EntityToReview extends React.Component {
);
}
}
else if (!entity.answers) {
icon = (
<i className={`fa fa-exclamation-circle ${styles.incomplete}`} />
);
}
let actions;
if (this.state.revising || this.state.responding) {
......
......@@ -20,7 +20,13 @@ import styles from './style';
import React from 'react';
import EntityDeclaration from '../entity-declaration';
export default function ProjectToReview({project, last, configId, className}) {
export default function ProjectToReview({
project,
last,
configId,
className,
necessaryEntities
}) {
let entityDeclarations;
if (project.entities) {
entityDeclarations = project.entities.map(entityDeclaration => {
......@@ -46,6 +52,27 @@ export default function ProjectToReview({project, last, configId, className}) {
);
}
let undeclaredEntities;
if (necessaryEntities.length !== project.entities.length) {
undeclaredEntities = necessaryEntities.filter(necessaryEntity => {
return !project.entities.some(projectEntity => {
return projectEntity.id === necessaryEntity.id;
});
}).map(entity => {
entity.adminComments = [];
entity.projectId = project.id;
return (
<EntityDeclaration
key={entity.id}
entity={entity}
revised={false}
respondedTo={false}
configId={configId}
/>
);
});
}
return (
<div className={`${styles.container} ${className}`}>
<div className={styles.projectTitle}>
......@@ -63,8 +90,20 @@ export default function ProjectToReview({project, last, configId, className}) {
<span className={styles.commentFiller} />
</div>
{entityDeclarations}
{undeclaredEntities}
{bottomBorder}
</div>
);
}
ProjectToReview.propTypes = {
project: React.PropTypes.object.isRequired,
last: React.PropTypes.bool,
configId: React.PropTypes.number.isRequired,
className: React.PropTypes.string,
necessaryEntities: React.PropTypes.arrayOf(React.PropTypes.object).isRequired
};
ProjectToReview.defaultProps = {
last: false
};
......
......@@ -18,6 +18,7 @@
import styles from './style';
import React from 'react';
import {isEmpty} from 'lodash';
import {AppHeader} from '../../../app-header';
import {PIReviewStore} from '../../../../stores/pi-review-store';
import RevisionHeader from '../revision-header';
......@@ -70,62 +71,74 @@ export class Revise extends React.Component {
render() {
const {configState} = this.context;
let questionnaire, entities, declarations, submittedDate, lastReviewDate;
let disclosureType, disclosureFiles;
let questionnaireJsx;
let entitiesJsx;
let declarationsJsx;
let submittedDate;
let lastReviewDate;
let disclosureType;
let disclosureFilesJsx;
if (this.state.disclosure) {
if (this.state.disclosure.questions) {
const questionsToDisplay = this.state.disclosure.questions;
if (questionsToDisplay.length > 0) {
questionnaire = (
<QuestionnaireSection
questions={questionsToDisplay}
/>
);
}
lastReviewDate = this.state.disclosure.lastReviewDate;
submittedDate = this.state.disclosure.submittedDate;
disclosureType = this.state.disclosure.typeCd;
const {
questions,
entities,
declarations,
id: disclosureId,
configId
} = this.state.disclosure;
if (!isEmpty(questions)) {
questionnaireJsx = (
<QuestionnaireSection
questions={questions}
/>
);
}
if (this.state.disclosure.entities) {
const entitiesToReview = this.state.disclosure.entities;
if (entitiesToReview.length > 0) {
entities = (
<EntitySection
entitiesToReview={entitiesToReview}
disclosureId={parseInt(this.state.disclosure.id)}
/>
);
}
if (!isEmpty(entities)) {
entitiesJsx = (
<EntitySection
entitiesToReview={entities}
disclosureId={parseInt(disclosureId)}
/>
);
}
if (this.state.disclosure.declarations) {
const declarationsToReview = this.state.disclosure.declarations;
if (declarationsToReview.length > 0) {
declarations = (
<DeclarationSection
declarationsToReview={declarationsToReview}
configId={this.state.disclosure.configId}
/>
);
}
if (!isEmpty(declarations)) {
declarationsJsx = (
<DeclarationSection
declarationsToReview={declarations}
configId={configId}
necessaryEntities={entities}
/>
);
}
if (this.state.files) {
disclosureFiles = (
disclosureFilesJsx = (
<FileSection
files={this.state.files}
disclosureId={this.state.disclosure.id}
disclosureId={disclosureId}
/>
);
}
lastReviewDate = this.state.disclosure.lastReviewDate;
submittedDate = this.state.disclosure.submittedDate;
disclosureType = this.state.disclosure.typeCd;
}
return (
<div className={'flexbox column'} style={{height: '100%'}}>
<AppHeader className={`${styles.override} ${styles.header}`} moduleName={'Conflict Of Interest'} />
<div className={`fill flexbox column ${styles.container} ${this.props.className}`}>
<AppHeader
className={`${styles.override} ${styles.header}`}
moduleName={'Conflict Of Interest'}
/>
<div
className={
`fill flexbox column ${styles.container} ${this.props.className}`
}
>
<RevisionHeader
disclosureType={disclosureType}
submittedDate={submittedDate}
......@@ -133,10 +146,10 @@ export class Revise extends React.Component {
/>
<div className={'flexbox row fill'}>
<span className={`fill ${styles.disclosure}`}>
{questionnaire}
{entities}
{declarations}
{disclosureFiles}
{questionnaireJsx}
{entitiesJsx}
{declarationsJsx}
{disclosureFilesJsx}
</span>
<SidePanel
......
......@@ -79,7 +79,7 @@ class _PIReviewStore {
}
updateCanSubmit() {
const {questions, entities, declarations} = this.disclosure;
const {questions, entities, declarations, projects} = this.disclosure;
if (questions) {
const allQuestionsDone = questions.every(question => {
......@@ -110,32 +110,29 @@ class _PIReviewStore {
}
}
if (declarations) {
const allDeclarationsDone = declarations.every(declaration => {
const allEntitiesDone = declaration.entities.every(
entity => {
if (entity.relationshipCd == null) {
return false;
}
const hasAdminComment = (
entity.adminComments &&
entity.adminComments.length > 0
);
if (!hasAdminComment) {
return true;
}
if (entity.reviewedOn == null) {
return false;
}
if (projects) {
const allDeclarationsDone = projects.every(project => {
return entities.every(entity => {
return declarations.some(declaration => {
return declaration.entities.some(d => {
if (
d.adminComments &&
d.adminComments.length > 0 &&
d.reviewedOn == null
) {
return false;
}
return true;
}
);
return allEntitiesDone;
return (
d.projectId === project.id &&
d.id === entity.id &&
d.relationshipCd != null
);
});
});
});
});
if (!allDeclarationsDone) {
this.applicationState.canSubmit = false;
return;
......@@ -506,16 +503,23 @@ class _PIReviewStore {
}
reviseDeclaration([entityId, projectId, disposition, comment]) {
this.disclosure.declarations.forEach(project => {
project.entities.forEach(entity => {
if (entity.id === entityId && entity.projectId === projectId) {
entity.reviewedOn = new Date();
entity.revised = true;
entity.comments = comment;
entity.relationshipCd = parseInt(disposition);
}
const project = this.disclosure.declarations.find(p => p.id === projectId);
const entity = project.entities.find(e => e.id === entityId);
if (entity) {
entity.reviewedOn = new Date();
entity.revised = true;
entity.comments = comment;
entity.relationshipCd = parseInt(disposition);
} else {
project.entities.push({
adminComments: [],
comments: comment,
id: entityId,
projectId,
relationshipCd: parseInt(disposition)
});
});
}
this.updateCanSubmit();
createRequest()
......
......@@ -952,7 +952,13 @@ export async function getPIReviewItems(
'd.user_id': userInfo.schoolId
});
const [questions, entities, declarations, disclosure] = await Promise.all([
const [
questions,
entities,
declarations,
disclosure,
projects
] = await Promise.all([
getQuestionsToReview(
knex,
disclosureId,
......@@ -980,12 +986,14 @@ export async function getPIReviewItems(
'last_review_date as lastReviewDate',
'type_cd as typeCd'
)
.where('id', disclosureId)
.where('id', disclosureId),
getAllProjects(knex, userInfo.schoolId, authHeader, dbInfo)
]);
return {
questions,
entities,
projects,
declarations,
configId: disclosure.configId,
submittedDate: disclosure.submittedDate,
......@@ -1172,21 +1180,41 @@ export async function reviseDeclarationById(
})
]);
return await Promise.all([
knex('declaration')
.update({
comments: declaration.comment,
type_cd: declaration.disposition
})
.where('id', declarationRow.id),
upsertReviewRecord(
if (!declarationRow) {
const declarationId = await knex('declaration')
.insert({
disclosure_id: disclosureId,
fin_entity_id: entityId,
project_id: projectId,
type_cd: declaration.disposition,
comments: declaration.comment
}, 'id');
await upsertReviewRecord(
knex,
disclosureId,
DISCLOSURE_STEP.PROJECTS,
declarationRow.id,
declarationId,
{revised: true}
)
]);
);
}
else {
await Promise.all([
knex('declaration')
.update({
comments: declaration.comment,
type_cd: declaration.disposition
})
.where('id', declarationRow.id),
upsertReviewRecord(
knex,
disclosureId,
DISCLOSURE_STEP.PROJECTS,
declarationRow.id,
{revised: true}
)
]);
}
}
export async function reviseSubQuestion(
......