diff --git a/client/scripts/actions/TravelLogActions.js b/client/scripts/actions/TravelLogActions.js
index af196d7f..1de2cfcb 100644
--- a/client/scripts/actions/TravelLogActions.js
+++ b/client/scripts/actions/TravelLogActions.js
@@ -43,5 +43,13 @@ class _TravelLogActions {
deleteEntry(relationshipId) { this.dispatch(relationshipId); }
archiveEntry(relationshipId) { this.dispatch(relationshipId); }
+
+ editEntry(relationshipId) { this.dispatch(relationshipId); }
+
+ saveEntry(relationshipId) { this.dispatch(relationshipId); }
+
+ cancelEntry(relationshipId) { this.dispatch(relationshipId); }
+
+ updateEntry(field, value, relationshipId) { this.dispatch({field: field, value: value, relationshipId: relationshipId}); }
}
export let TravelLogActions = alt.createActions(_TravelLogActions);
diff --git a/client/scripts/components/User/TravelLog/Entry.jsx b/client/scripts/components/User/TravelLog/Entry.jsx
index 8a5416f0..68c1e8c6 100644
--- a/client/scripts/components/User/TravelLog/Entry.jsx
+++ b/client/scripts/components/User/TravelLog/Entry.jsx
@@ -21,6 +21,9 @@ import {ProminentButton} from '../../ProminentButton';
import {formatDate} from '../../../formatDate';
import {COIConstants} from '../../../../../COIConstants';
import {TravelLogActions} from '../../../actions/TravelLogActions';
+import TextField from '../TextField';
+import CurrencyField from '../CurrencyField';
+import DateRangeField from '../DateRangeField';
export class Entry extends React.Component {
constructor() {
@@ -28,6 +31,12 @@ export class Entry extends React.Component {
this.deleteEntry = this.deleteEntry.bind(this);
this.archiveEntry = this.archiveEntry.bind(this);
+ this.editEntry = this.editEntry.bind(this);
+ this.saveEntry = this.saveEntry.bind(this);
+ this.cancelEntry = this.cancelEntry.bind(this);
+ this.updateField = this.updateField.bind(this);
+ this.updateStartDate = this.updateStartDate.bind(this);
+ this.updateEndDate = this.updateEndDate.bind(this);
}
deleteEntry() {
@@ -38,6 +47,30 @@ export class Entry extends React.Component {
TravelLogActions.archiveEntry(this.props.travelLog.relationshipId);
}
+ editEntry() {
+ TravelLogActions.editEntry(this.props.travelLog.relationshipId);
+ }
+
+ saveEntry() {
+ TravelLogActions.saveEntry(this.props.travelLog.relationshipId);
+ }
+
+ cancelEntry() {
+ TravelLogActions.cancelEntry(this.props.travelLog.relationshipId);
+ }
+
+ updateField(evt) {
+ TravelLogActions.updateEntry(evt.target.id, evt.target.value, this.props.travelLog.relationshipId);
+ }
+
+ updateStartDate(newValue) {
+ TravelLogActions.updateEntry('startDate', newValue, this.props.travelLog.relationshipId);
+ }
+
+ updateEndDate(newValue) {
+ TravelLogActions.updateEntry('endDate', newValue, this.props.travelLog.relationshipId);
+ }
+
render() {
let styles = {
container: {
@@ -92,6 +125,24 @@ export class Entry extends React.Component {
},
middle: {
marginTop: 10
+ },
+ textField: {
+ container: {
+ display: 'inline-block',
+ width: '33%'
+ },
+ input: {
+ padding: '2px 8px',
+ fontSize: 16,
+ borderRadius: 5,
+ border: '1px solid #ccc',
+ height: 30,
+ width: '95%'
+ },
+ label: {
+ marginBottom: 5,
+ fontWeight: '500'
+ }
}
};
@@ -115,7 +166,14 @@ export class Entry extends React.Component {
);
}
- if (this.props.travelLog.status === COIConstants.RELATIONSHIP_STATUS.DISCLOSED) {
+ if (this.props.editing === true) {
+ actionButtons = (
+
+ );
+ } else if (this.props.travelLog.status === COIConstants.RELATIONSHIP_STATUS.DISCLOSED) {
actionButtons = (
{disclosedDate}
@@ -125,14 +183,62 @@ export class Entry extends React.Component {
} else {
actionButtons = (
);
}
- return (
-
+ let jsx;
+ if (this.props.editing) {
+ jsx = (
+
+
+
+
+
+
+ {actionButtons}
+
+ );
+ } else {
+ jsx = (
@@ -162,6 +268,12 @@ export class Entry extends React.Component {
{actionButtons}
+ );
+ }
+
+ return (
+
+ {jsx}
);
}
diff --git a/client/scripts/components/User/TravelLog/TravelLog.jsx b/client/scripts/components/User/TravelLog/TravelLog.jsx
index e07ec04f..b1a8209a 100644
--- a/client/scripts/components/User/TravelLog/TravelLog.jsx
+++ b/client/scripts/components/User/TravelLog/TravelLog.jsx
@@ -36,7 +36,8 @@ export class TravelLog extends React.Component {
this.state = {
entries: storeState.entries,
potentialEntry: storeState.potentialEntry,
- validating: storeState.validating
+ validating: storeState.validating,
+ entryStates: storeState.entryStates
};
this.onChange = this.onChange.bind(this);
@@ -56,7 +57,8 @@ export class TravelLog extends React.Component {
this.setState({
entries: storeState.entries,
potentialEntry: storeState.potentialEntry,
- validating: storeState.validating
+ validating: storeState.validating,
+ entryStates: storeState.entryStates
});
}
@@ -94,7 +96,10 @@ export class TravelLog extends React.Component {
if (this.state.entries.length > 0) {
travelLogs = this.state.entries.map(travelLog => {
return (
-
+
);
});
}
diff --git a/client/scripts/stores/TravelLogStore.js b/client/scripts/stores/TravelLogStore.js
index ac816362..92282ec3 100644
--- a/client/scripts/stores/TravelLogStore.js
+++ b/client/scripts/stores/TravelLogStore.js
@@ -21,6 +21,10 @@ import {TravelLogActions} from '../actions/TravelLogActions.js';
import alt from '../alt';
import {processResponse, createRequest} from '../HttpUtils';
+let cloneObject = original => {
+ return JSON.parse(JSON.stringify(original));
+};
+
class _TravelLogStore extends AutoBindingStore {
constructor() {
super(TravelLogActions);
@@ -36,6 +40,7 @@ class _TravelLogStore extends AutoBindingStore {
this.sortDirection = 'ASCENDING';
this.filter = 'all';
this.validating = false;
+ this.entryStates = {};
}
refreshTravelLogEntries() {
@@ -88,6 +93,54 @@ class _TravelLogStore extends AutoBindingStore {
}));
}
+ getEntry(relationshipId) {
+ return this.entries.find(entry => {
+ return entry.relationshipId === relationshipId;
+ });
+ }
+
+ editEntry(relationshipId) {
+ if (!this.entryStates[relationshipId]) {
+ this.entryStates[relationshipId] = {};
+ }
+ this.entryStates[relationshipId].editing = true;
+ this.entryStates[relationshipId].snapshot = cloneObject(this.getEntry(relationshipId));
+ }
+
+ saveEntry(relationshipId) {
+ let entryToSave = this.entries.find(entry => {
+ return entry.relationshipId === relationshipId;
+ });
+
+ this.entryStates[relationshipId].editing = false;
+ this.entryStates[relationshipId].snapshot = undefined;
+
+ createRequest().put('/api/coi/travel-log-entries/' + relationshipId)
+ .send(entryToSave)
+ .end(processResponse(() => {}));
+ }
+
+ cancelEntry(relationshipId) {
+ let index = this.entries.findIndex(entry => {
+ return entry.relationshipId === relationshipId;
+ });
+
+ if (index >= 0) {
+ this.entries[index] = this.entryStates[relationshipId].snapshot;
+ }
+
+ this.entryStates[relationshipId].editing = false;
+ this.entryStates[relationshipId].snapshot = undefined;
+ }
+
+ updateEntry(data) {
+ let entryToSave = this.entries.find(entry => {
+ return entry.relationshipId === data.relationshipId;
+ });
+
+ entryToSave[data.field] = data.value;
+ }
+
turnOnValidations() {
this.validating = true;
}
diff --git a/server/db/TravelLogDB.js b/server/db/TravelLogDB.js
index 6062651e..c52775f4 100644
--- a/server/db/TravelLogDB.js
+++ b/server/db/TravelLogDB.js
@@ -19,6 +19,7 @@
/*eslint camelcase:0 */
import {COIConstants} from '../../COIConstants';
import {verifyRelationshipIsUsers} from './CommonDB';
+import * as FileService from '../services/fileService/FileService';
let getKnex;
try {
@@ -149,13 +150,18 @@ let handleTravelLogEntry = (trx, disclosureId, entry, status) => {
});
};
+let getAnnualDisclosureForUser = (trx, schoolId) => {
+ return trx('disclosure').select('status_cd', 'id').where({
+ user_id: schoolId,
+ type_cd: COIConstants.DISCLOSURE_TYPE.ANNUAL
+ });
+};
+
export let createTravelLogEntry = (dbInfo, entry, userInfo) => {
let knex = getKnex(dbInfo);
return knex.transaction(trx => {
- return trx('disclosure').select('status_cd', 'id').where({
- user_id: userInfo.schoolId,
- type_cd: COIConstants.DISCLOSURE_TYPE.ANNUAL
- }).then(disclosure => {
+ return getAnnualDisclosureForUser(trx, userInfo.schoolId)
+ .then(disclosure => {
if (disclosure[0]) {
if (isSubmitted(disclosure[0].status_cd) === true) {
return handleTravelLogEntry(trx, disclosure[0].id, entry, COIConstants.RELATIONSHIP_STATUS.PENDING);
@@ -194,13 +200,96 @@ let deleteRelationship = (trx, id) => {
.where('id', id);
};
+let getQuestionnaireAnswerIds = (trx, id) => {
+ return trx('fin_entity_answer')
+ .select('questionnaire_answer_id')
+ .where('fin_entity_id', id)
+ .then(answers => {
+ return answers.map(answer => {
+ return answer.questionnaire_answer_id;
+ });
+ });
+};
+
+let deleteFinEntityAnswers = (trx, id) => {
+ return trx('fin_entity_answer')
+ .del()
+ .where('fin_entity_id', id);
+};
+
+let deleteQuestionnaireAnswers = (trx, answerIds) => {
+ return trx('questionnaire_answer')
+ .del()
+ .whereIn('id', answerIds);
+};
+
+let deleteEntityAnswers = (trx, id) => {
+ return getQuestionnaireAnswerIds(trx, id).then(answerIds => {
+ return deleteFinEntityAnswers(trx, id).then(() => {
+ return deleteQuestionnaireAnswers(trx, answerIds);
+ });
+ });
+};
+
+let getEntityFiles = (trx, id) => {
+ return trx('file')
+ .select('id', 'key')
+ .where({
+ ref_id: id,
+ file_type: COIConstants.FILE_TYPE.FINANCIAL_ENTITY
+ });
+};
+
+let deleteDbFiles = (trx, id) => {
+ return trx('file')
+ .del()
+ .where({
+ ref_id: id,
+ file_type: COIConstants.FILE_TYPE.FINANCIAL_ENTITY
+ });
+};
+
+let deleteFileData = (files) =>{
+ return Promise.all(
+ files.map(file => {
+ return new Promise((resolve, reject) => {
+ FileService.deleteFile(file.key, err => {
+ if (err) {
+ reject(err);
+ } else {
+ resolve();
+ }
+ });
+ });
+ })
+ );
+};
+
+let deleteEntityFiles = (trx, id) => {
+ return getEntityFiles(trx, id).then(files=> {
+ return deleteDbFiles(trx, id).then(() => {
+ return deleteFileData(files);
+ });
+ });
+};
+
+let deleteEntity = (trx, id) => {
+ return trx('fin_entity')
+ .del()
+ .where('id', id);
+};
+
let deleteEntityIfAllRelationshipsAreDelete = (trx, entityId) => {
return trx('relationship')
- .select('')
+ .select('id')
.where('fin_entity_id', entityId)
.then(rows => {
if (!rows.length) {
- return trx('fin_entity').del().where('id', entityId);
+ return deleteEntityAnswers(trx, entityId).then(() => {
+ return deleteEntityFiles(trx, entityId).then(() => {
+ return deleteEntity(trx, entityId);
+ });
+ });
}
});
};
@@ -280,6 +369,72 @@ let updateRelationship = (trx, entry, id) => {
}
};
+let handleOldEntity = (trx, entityId) => {
+ return deleteEntityIfAllRelationshipsAreDelete(trx, entityId);
+};
+
+let getEntityNameFromId = (trx, id) => {
+ return trx('fin_entity')
+ .select('name')
+ .where('id', id)
+ .then(entity => {
+ return entity[0].name;
+ });
+};
+
+let getEntityIdFromName = (trx, name, disclosureId) => {
+ return trx('fin_entity')
+ .select('id')
+ .where({
+ name: name,
+ disclosure_id: disclosureId
+ })
+ .then(entity => {
+ if (entity[0]) {
+ return entity[0].id;
+ } else {
+ return undefined;
+ }
+ });
+};
+
+let getRelationship = (trx, id) => {
+ return trx('relationship')
+ .select('fin_entity_id')
+ .where('id', id);
+};
+
+let updateRelationshipEntityId = (trx, id, entityId) => {
+ return trx('relationship')
+ .update({fin_entity_id: entityId})
+ .where('id', id);
+};
+
+let updateEntity = (trx, entry, id, schoolId) => {
+ return getRelationship(trx, id).then(relationship => {
+ return getEntityNameFromId(trx, relationship[0].fin_entity_id).then(entityName => {
+ if (entry.entityName === entityName) {
+ return undefined;
+ } else {
+ return getAnnualDisclosureForUser(trx, schoolId).then(disclosure => {
+ return getEntityIdFromName(trx, entry.entityName, disclosure[0].id).then(entityId => {
+ if (entityId) {
+ return updateRelationshipEntityId(trx, id, entityId).then(()=> {
+ return handleOldEntity(trx, relationship[0].fin_entity_id);
+ });
+ } else {
+ return createNewEntity(trx, disclosure[0].id, entry, COIConstants.RELATIONSHIP_STATUS.IN_PROGRESS).then(newEntityId => {
+ return updateRelationshipEntityId(trx, id, newEntityId).then(()=> {
+ return handleOldEntity(trx, relationship[0].fin_entity_id);
+ });
+ });
+ }
+ });
+ });
+ }
+ });
+ });
+};
export let updateTravelLogEntry = (dbInfo, entry, id, userInfo) => {
let knex = getKnex(dbInfo);
@@ -289,7 +444,8 @@ export let updateTravelLogEntry = (dbInfo, entry, id, userInfo) => {
return knex.transaction(trx=>{
return Promise.all([
updateTravelRelationship(trx, entry, id),
- updateRelationship(trx, entry, id)
+ updateRelationship(trx, entry, id),
+ updateEntity(trx, entry, id, userInfo.schoolId)
]).then(() => {
return entry;
});