From f1c5624fc48788fb0f6eb52a0e739b84ef19ea9c Mon Sep 17 00:00:00 2001 From: Conrad S Date: Mon, 20 Feb 2017 12:09:25 -0500 Subject: [PATCH 01/15] Update getDocuments to take in a list of paths --- src/components/DocumentCardViewer/index.js | 2 +- src/containers/Documents/actions.js | 4 ++-- src/containers/Documents/sagas.js | 7 +++++-- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/components/DocumentCardViewer/index.js b/src/components/DocumentCardViewer/index.js index 73a605e5..be850c0a 100644 --- a/src/components/DocumentCardViewer/index.js +++ b/src/components/DocumentCardViewer/index.js @@ -16,7 +16,7 @@ export default class DocumentCardViewer extends Component { } componentDidMount() { - this.props.getDocuments(this.props.documentPath, this.props.fileKey); + this.props.getDocuments([this.props.documentPath], this.props.fileKey); } uploadHandler = (event) => { diff --git a/src/containers/Documents/actions.js b/src/containers/Documents/actions.js index 3c8c901d..0af0a2a8 100644 --- a/src/containers/Documents/actions.js +++ b/src/containers/Documents/actions.js @@ -7,10 +7,10 @@ import { UPLOAD_DOCUMENT_ERROR, } from './constants'; -export function loadDocuments(documentPath, fileKey) { +export function loadDocuments(documentPaths, fileKey) { return { type: LOAD_DOCUMENTS, - documentPath, + documentPaths, fileKey, }; } diff --git a/src/containers/Documents/sagas.js b/src/containers/Documents/sagas.js index d6f28455..d984e9f3 100644 --- a/src/containers/Documents/sagas.js +++ b/src/containers/Documents/sagas.js @@ -16,11 +16,14 @@ import { function* getDocuments(action) { - const { documentPath, fileKey } = action; + const { documentPaths, fileKey } = action; + const pathsString = documentPaths.reduce((acc, val) => ( + `${acc}paths[]=${val}&` + ), ''); const res = yield call( request, - `${documentURL}?paths[]=${documentPath}`, { + `${documentURL}?${pathsString}`, { method: 'GET', headers: getHeaders(), } -- GitLab From 11befc25284e67f305cb6347380f1a2a5c302776 Mon Sep 17 00:00:00 2001 From: Conrad S Date: Tue, 21 Feb 2017 11:03:02 -0500 Subject: [PATCH 02/15] Add vertical tree of states and slots --- src/components/Project/defaultSlots.js | 414 +++++++++++++++++++++++++ src/components/Project/index.js | 170 +++++++++- src/containers/Building/sagas.js | 27 +- 3 files changed, 597 insertions(+), 14 deletions(-) create mode 100644 src/components/Project/defaultSlots.js diff --git a/src/components/Project/defaultSlots.js b/src/components/Project/defaultSlots.js new file mode 100644 index 00000000..0aaf5408 --- /dev/null +++ b/src/components/Project/defaultSlots.js @@ -0,0 +1,414 @@ +const defaultSlots = { + 3: { + name: 'Collect Forms', + id: 3, + description: 'Collect 12 Months of Utility Bills and 3 years of Income. Fill out business section of PNS form.', + slots: [ + { name: 'income-statements', title: 'Income Statements', folder_name: 'Income Statements', state_id: 3 }, + { name: 'sceep-forms', title: 'SCEEP Forms', folder_name: 'SCEEP Forms', state_id: 3 }, + { name: 'pea-reports', title: 'PEA Reports', folder_name: 'PEA Reports', state_id: 3 }, + { name: 'taxes', title: 'Taxes', folder_name: 'Taxes', state_id: 3 }, + { name: 'credit-reports', title: 'Credit Reports', folder_name: 'Credit Reports', state_id: 3 }, + { name: 'certificate-of-incorporation', title: 'Certificate of Incorporation', folder_name: 'Certificate of Incorporation', state_id: 3 }, + { name: 'bank-statements', title: 'Bank Statements', folder_name: 'Bank Statements', state_id: 3 }, + { name: '501(c)3-confirmation', title: '501(c)3 Confirmation', folder_name: '501(c)3 Confirmation', state_id: 3 }, + { name: 'proof-of-insurance', title: 'Proof of Property and Liability Insurance', folder_name: 'Proof of Property and Liability Insurance', state_id: 3 }, + { name: 'property-appraisal', title: 'Property Appraisal', folder_name: 'Property Appraisal', state_id: 3 }, + { name: 'title-of-location', title: 'Title of Location', folder_name: 'Title of Location', state_id: 3 }, + { name: 'misc', title: 'Miscellaneous', folder_name: 'Miscellaneous', state_id: 3 }, + ], + }, + + 4: { + name: 'Create Opportunity', + id: 4, + description: 'Create object on project dashboard with pending state. Create opportunity on salesforce.', + slots: [], + }, + + 5: { + name: 'Confirm Bill Validity', + id: 5, + description: 'Quality Assurance checks bills on dashboard are correct.', + slots: [], + }, + + 6: { + name: 'Confirm Validity of 3 Years of Income Statements ', + id: 6, + description: 'Finance does quality check on 3 Years of Income Statements on dashboard.', + slots: [ + { name: 'financial-reports', title: 'Financial Reports', folder_name: 'Financial Reports', state_id: 6 }, + { name: 'balance-sheets', title: 'Balance Sheets', folder_name: 'Balance Sheets', state_id: 6 }, + ], + }, + + + 7: { + name: 'Schedule Site Visit', + id: 7, + description: 'Schedule site visit with client and project engineer.', + slots: [], + }, + + + 8: { + name: 'Complete Business Development PNS', + id: 8, + description: 'Complete Business Development section of PNS form', + slots: [], + }, + + + 9: { + name: 'Business Development PNS Approval', + id: 9, + description: 'Business Development section of PNS form will go through approval.', + slots: [], + }, + + 10: { + name: 'Perform Remote Assessment', + id: 10, + description: 'Project Engineers perform remote assessment (Energy Watch, Code Violations, Google Earth, Heat Load Calculations).', + slots: [ + { name: 'breakdown-of-bills', title: 'Breakdown of Bills', folder_name: 'Breakdown of Bills', state_id: 10 }, + { name: 'heat-load', title: 'Engineering Models', folder_name: 'Engineering Models', state_id: 10 }, + ], + }, + + + 11: { + name: 'Complete Engineer PNS', + id: 11, + description: 'Complete Engineer section of PNS Form.', + slots: [], + }, + + + 12: { + name: 'Engineer PNS Approval', + id: 12, + description: 'Engineer section of the PNS form will go through approval.', + slots: [], + }, + + 13: { + name: 'Conduct Site Visit', + id: 13, + description: 'Project Engineer conducts site visit audit. All data entry is complete. Sensors are installed.', + slots: [ + { name: 'canvas', title: 'Canvas', folder_name: 'Canvas', state_id: 13 }, + { name: 'pictures', title: 'Pictures', folder_name: 'Pictures', state_id: 13 }, + { name: 'sketches', title: 'Sketches', folder_name: 'Sketches', state_id: 13 }, + { name: 'marketplace-photos', title: 'Marketplace Photos', folder_name: 'Marketplace Photos', state_id: 13 }, + ], + }, + + 14: { + name: 'Perform Initial Engineering Analysis', + id: 14, + description: 'Project Engineer performs energy efficiency calculations for annual savings.', + slots: [ + { name: 'pns', title: 'PNS Form', folder_name: 'PNS Form', state_id: 14 }, + { name: 'cooling-load', title: 'Engineering Models', folder_name: 'Engineering Models', state_id: 14 }, + ], + }, + + 15: { + name: 'Send Diagnostic Report', + id: 15, + description: 'Project Engineer creates diagnostic report.', + slots: [ + { name: 'diagnostic-report', title: 'Diagnostic Report', folder_name: 'Diagnostic Report', state_id: 15 }, + ], + }, + + + 16: { + name: 'Complete Finance PNS', + id: 16, + description: 'Complete Finance section of the PNS Form. This step does not have any dependencies. Must only be complete one month post site visit.', + slots: [], + }, + + + 17: { + name: 'Finance PNS Approval', + id: 17, + description: 'Finance section of the PNS form will go through approval.', + slots: [], + }, + + + 18: { + name: 'Send PNS Form', + id: 18, + description: 'Project Engineer sends client PNS Form.', + slots: [], + }, + + + 19: { + name: 'Follow Up Post Project Update', + id: 19, + description: 'Project Engineer contacts client to discover if client is interested in moving forward.', + slots: [], + }, + + 20: { + name: 'Outsource Retrofit', + id: 20, + description: 'Project Manager assesses potential outsourced retrofits (e.g. lighting and windows).', + slots: [ + { name: 'signed-quotes', title: 'Quotes', folder_name: 'Quotes', state_id: 20 }, + ], + }, + + + 21: { + name: 'HPD Finance', + id: 21, + description: 'Finance discovers if HPD will finance the project.', + slots: [], + }, + + + 22: { + name: 'Confirm Client wants HPD', + id: 22, + description: 'Finance confirms client wants to proceed with HPD program.', + slots: [], + }, + + 23: { + name: 'Preliminary Financial Analysis', + id: 23, + description: 'Run preliminary financial model and suggest budget range for Project Engineer.', + slots: [ + { name: 'financial-model', title: 'Financial Model', folder_name: 'Financial Model', state_id: 23 }, + { name: 'budget', title: 'Budget', folder_name: 'Budget', state_id: 23 }, + ], + }, + + + 24: { + name: 'Confirm Project Financing', + id: 24, + description: 'Finance decides if project is feasible.', + slots: [], + }, + + 25: { + name: 'Perform Detailed Calculations and Analysis', + id: 25, + description: 'Project Engineer runs models (hydronic, steam, cooling, heating, controls).', + slots: [ + { name: 'engineering-models', title: 'Engineering Models', folder_name: 'Engineering Models', state_id: 25 }, + ], + }, + + 26: { + name: 'Write Scope of Work Report', + id: 26, + description: 'Project Engineer selects desired equipment for retrofits.', + slots: [ + { name: 'scope-of-work', title: 'Scope of Work', folder_name: 'Scope of Work', state_id: 26 }, + ], + }, + + 27: { + name: 'Obtain Quotes', + id: 27, + description: 'Project Manager bundles nearby projects together and sends equipment lists to contractor to collect quotes and look for violations.', + slots: [ + { name: 'quotes', title: 'Quotes', folder_name: 'Quotes', state_id: 27 }, + ], + }, + + 28: { + name: 'Create Engineering Energy Output Model', + id: 28, + description: 'Project Engineer generates Engineering Output Model for suggested scenario.', + slots: [ + { name: 'engineering-output-model', title: 'Engineering Output Model', folder_name: 'Engineering Output Model', state_id: 28 }, + ], + }, + + 29: { + name: 'Create Financial Model', + id: 29, + description: 'Finance uses quotes and Engineering Output Model to run financial model for suggested scenario.', + slots: [ + { name: 'financial-model', title: 'Financial Model', folder_name: 'Financial Model', state_id: 29 }, + ], + }, + + 30: { + name: 'Create Client Presentation', + id: 30, + description: 'Project Engineer creates final presentation for various retrofit scenarios with upfront cost estimates and annual savings.', + slots: [ + { name: 'final-presentation', title: 'Final Presentation', folder_name: 'Final Presentation', state_id: 30 }, + ], + }, + + + 31: { + name: 'Schedule Client Presentation', + id: 31, + description: 'Project Manager coordinates with client, engineer, and finance/business to set up presentation date.', + slots: [], + }, + + + 32: { + name: 'Present to Client', + id: 32, + description: 'Project Engineer presents retrofit scenarios and financing options to client.', + slots: [], + }, + + + 33: { + name: 'Client Chooses Retrofits', + id: 33, + description: 'Project Engineer contacts Client to determine actionable retrofits. ', + slots: [], + }, + + 34: { + name: 'Redesign Scope of Work', + id: 34, + description: 'Project Engineer redesigns and finalizes scope of work.', + slots: [ + { name: 'redesigned-scope-of-work', title: 'Redesigned Scope of Work', folder_name: 'Redesigned Scope of Work', state_id: 34 }, + ], + }, + + + 35: { + name: 'Send Client Scope of Work and List of Contractors', + id: 35, + description: 'Client will be sent the scope of work and a list of contractors.', + slots: [], + }, + + 36: { + name: 'Finalize Quotes', + id: 36, + description: 'Project Engineer sends contractor Final Scope of Work and finalizes quotes. Contractor signs contract.', + slots: [ + { name: 'contractor-quotes', title: 'Contractor Quotes', folder_name: 'Contractor Quotes', state_id: 36 }, + ], + }, + + 37: { + name: 'Final Financial Model', + id: 37, + description: 'Finance runs the financial model to obtain actual costs including payback years.', + slots: [ + { name: 'final-financial-model', title: 'Final Financial Model', folder_name: 'Final Financial Model', state_id: 37 }, + ], + }, + + + 38: { + name: 'Update Client with Project Financing', + id: 38, + description: 'Finance contacts client to discuss financing options such as loans and marketplace.', + slots: [], + + }, + + + 39: { + name: 'Client Decides on Marketplace', + id: 39, + description: 'Client decides if they want to use Marketplace.', + slots: [], + }, + + + 40: { + name: 'Marketplace Content', + id: 40, + description: 'The Project content gets collected to prepare it for a Marketplace Launch.', + slots: [], + }, + + + 41: { + name: 'Marketplace', + id: 41, + description: 'The Project is launched on the Marketplace and is being funded.', + slots: [], + }, + + + 42: { + name: 'Contractor Downpayment', + id: 42, + description: 'A downpayment is payed to contractor.', + slots: [], + }, + + 43: { + name: 'Apply for Loan', + id: 43, + description: 'Finance appplies for loan.', + slots: [ + { name: 'nyserda', title: 'NYSERDA Request for Financing Form', folder_name: 'NYSERDA Request for Financing Form', state_id: 43 }, + { name: 'loan-application', title: 'Loan Application', folder_name: 'Loan Application', state_id: 43 }, + ], + }, + + 44: { + name: 'Approval of Underwriter', + id: 44, + description: 'Finance is notified that the loan was approved by the Underwriter (banks).', + slots: [], + }, + + 45: { + name: 'Confirm Funding', + id: 45, + description: 'Finance confirms project is funded.', + slots: [], + }, + + + 46: { + name: 'Commence Construction', + id: 46, + description: 'Construction Manager coordinates with client contractor, and engineers to schedule retrofit construction.', + slots: [], + }, + + + 47: { + name: 'Measurement and Verification', + id: 47, + description: 'Project Engineer collects sensor data during site visit, recalibrates sensors, and reinstalls sensors for "post retrofit" measurement and verification.', + slots: [], + }, + + + 48: { + name: 'Loan Payback', + id: 48, + description: 'Loan is in the process of being paid back.', + slots: [], + }, + + + 49: { + name: 'Completed', + id: 49, + description: 'Project is complete!', + slots: [], + }, + +}; + +export { defaultSlots as default }; diff --git a/src/components/Project/index.js b/src/components/Project/index.js index 6cad3ff3..4fae8cd1 100644 --- a/src/components/Project/index.js +++ b/src/components/Project/index.js @@ -1,18 +1,162 @@ -import React, { PropTypes } from 'react'; - /* eslint-disable */ -const Project = ({ buildingId }) => { - return ( -
- Coming Soon! -
- {buildingId} -
- ); -}; +import React, { Component, PropTypes } from 'react'; +import defaultSlots from './defaultSlots'; +import documentsPropType from '../../containers/Documents/propTypes'; +import { +// completeProjectPropTypes, + completeOverviewPropTypes, +} from '../../containers/Building/propTypes'; +import DocumentCard from '../DocumentCard/'; +import { uploadSVG } from '../bpl'; + +export default class Project extends Component { + constructor(props) { + super(props); + + const { building, buildingId } = this.props; + this.state = { + documentPath: `/Buildings/${buildingId}_${building.address}/`, + projectId: this.props.params.projectId, + fileKey: 'project', + convertingFile: false, + }; + } + + componentDidMount() { + // Get all of the files for thsi project + const pathList = Object.keys(defaultSlots).reduce((acc, state) => { + const paths = defaultSlots[state]["slots"].map(val => ( + `${this.state.documentPath}Project-${this.state.projectId}/${val.folder_name}` + )); + return acc.concat(paths); + }, []); + this.props.getDocuments(pathList, this.state.fileKey); + } + + uploadHandler = (event) => { + const file = event.target.files[0]; + const { buildingId } = this.props; + const fileKey = this.state.fileKey; + const documentPath = event.target.name; + this.setState({ convertingFile: true }); + const fileReader = new FileReader(); + + fileReader.onload = function fileResults() { + this.setState({ convertingFile: false }); + this.props.uploadDocument(buildingId, documentPath, fileReader.result, '', + file.name, fileKey); + }.bind(this); + fileReader.readAsDataURL(file); + } + + renderUploadButton = (uploadPath) => { + let disabled = false; + let img = ( +
+ + Choose a file +
+ ); + if (this.state.convertingFile || this.props.documents.uploading) { + disabled = true; + img = ( +
+
+
+
+
+
+ ); + } + + return ( +
+ + +
+ ); + } + + renderDocuments = (documentList) => { + let docs =
+ if (documentList != null && documentList.length > 0) { + docs = documentList.map(item => ( +
+ +
+ )); + } + return docs; + } + + // Generate the HTML to show all of the files for a state + generateStateHTML = (stateId, slotToDocuments) => ( + defaultSlots[stateId]["slots"].map(val => { + const slotPath = `${this.state.documentPath}Project-${this.state.projectId}/${val.folder_name}`; + return ( +
+

{val.title}

+ {/* Pass the download path into the render upload button function */} + {this.renderUploadButton(slotPath)} + {/* Render the documents for this slot */} + {this.renderDocuments(slotToDocuments[slotPath])} +
+
+ ); + }) + ) + + generateDocumentHTML = () => { + // An object that given a slot path name, returns a list of documents + const slotToDocuments = this.props.documents.files.project.reduce((acc, val) => { + if (acc[val.path]) { + acc[val.path].push(val); + } else { + acc[val.path] = [val]; + } + return acc; + }, {}); + return Object.keys(defaultSlots).map(val => ( +
+

{`${val}. ${defaultSlots[val]['name']}`}

+
{defaultSlots[val]['description']}
+
+ {this.generateStateHTML(val, slotToDocuments)} +
+
+ )); + } + + render() { + return ( +
+
+
+ {this.generateDocumentHTML()} +
+
+
+ ); + } +} Project.propTypes = { buildingId: PropTypes.string, + building: completeOverviewPropTypes, + params: PropTypes.shape({ + projectId: PropTypes.string, + }), + // projects: completeProjectPropTypes, + documents: documentsPropType, + getDocuments: PropTypes.func, + uploadDocument: PropTypes.func, }; - -export default Project; diff --git a/src/containers/Building/sagas.js b/src/containers/Building/sagas.js index 5e5852a9..bab5c4c5 100644 --- a/src/containers/Building/sagas.js +++ b/src/containers/Building/sagas.js @@ -39,7 +39,32 @@ function* getProjects(action) { const buildingId = action.buildingId; const res = { buildingId, - data: [], + data: [ + { + client_id: 5, + created: '2016-04-29T19:25:08.509790+00:00', + id: 6, + name: '2324 Pitkin Avenue', + sales_force_id: '00661000009yx9lAAA', + slug: '2324-pitkin-avenue-6', + state: 'pending', + updated: null, + program_type: 'CBRA', + building_id: buildingId, + }, + { + client_id: 10, + created: '2016-04-29T19:25:08.509790+00:00', + id: 7, + name: '2324 Pitkin Avenue', + sales_force_id: '00661000009yx9lAAA', + slug: '2324-pitkin-avenue-6', + state: 'pending', + updated: null, + program_type: 'BUILD HEALTH', + building_id: buildingId, + }, + ], }; yield put(projectsLoaded(res)); -- GitLab From 21bbfc120832f85ca7f8c7b729dc5d21d954a82e Mon Sep 17 00:00:00 2001 From: Conrad S Date: Tue, 21 Feb 2017 11:26:04 -0500 Subject: [PATCH 03/15] Add validation for project exists --- src/components/Project/index.js | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/src/components/Project/index.js b/src/components/Project/index.js index 038805bb..82dedbe1 100644 --- a/src/components/Project/index.js +++ b/src/components/Project/index.js @@ -3,7 +3,7 @@ import React, { Component, PropTypes } from 'react'; import defaultSlots from './defaultSlots'; import documentsPropType from '../../containers/Documents/propTypes'; import { -// completeProjectPropTypes, + completeProjectPropTypes, completeOverviewPropTypes, } from '../../containers/Building/propTypes'; import DocumentCard from '../DocumentCard/'; @@ -138,10 +138,34 @@ export default class Project extends Component { } render() { + const projectExists = this.props.projects["list"].reduce((acc, val) => ( + acc || val.id == this.props.params.projectId + ), false); + if (!projectExists) { + return ( +
+ +
+
+
+ This project does not exist +
+
+
+
+ ) + } return (
Date: Tue, 21 Feb 2017 11:26:34 -0500 Subject: [PATCH 04/15] Add semicolon --- src/components/Project/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/Project/index.js b/src/components/Project/index.js index 82dedbe1..0280c4ab 100644 --- a/src/components/Project/index.js +++ b/src/components/Project/index.js @@ -160,7 +160,7 @@ export default class Project extends Component {
- ) + ); } return (
-- GitLab From b4b5fdeebb55bbf37a56d5d78ef42240d7e035f8 Mon Sep 17 00:00:00 2001 From: Conrad S Date: Tue, 21 Feb 2017 11:28:37 -0500 Subject: [PATCH 05/15] Add project id to breadcrumb title --- src/components/Project/index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/Project/index.js b/src/components/Project/index.js index 0280c4ab..fd57546a 100644 --- a/src/components/Project/index.js +++ b/src/components/Project/index.js @@ -148,7 +148,7 @@ export default class Project extends Component { building={this.props.building} breadcrumbs={[ { name: 'Overview', url: '' }, - { name: 'Project', url: 'null' }, + { name: `Project ${this.props.params.projectId}`, url: 'null' }, ]} links={[]} /> @@ -168,7 +168,7 @@ export default class Project extends Component { building={this.props.building} breadcrumbs={[ { name: 'Overview', url: '' }, - { name: 'Project', url: 'null' }, + { name: `Project ${this.props.params.projectId}`, url: 'null' }, ]} links={[]} /> -- GitLab From 4cf087778cdd23f3e85f05d3ccaa7c95b530704c Mon Sep 17 00:00:00 2001 From: Conrad S Date: Wed, 22 Feb 2017 10:21:01 -0500 Subject: [PATCH 06/15] Update to reflect es-lint and PR --- src/components/Project/defaultSlots.js | 2 +- src/components/Project/index.js | 113 ++++++++++--------------- 2 files changed, 48 insertions(+), 67 deletions(-) diff --git a/src/components/Project/defaultSlots.js b/src/components/Project/defaultSlots.js index 0aaf5408..d2af4ccc 100644 --- a/src/components/Project/defaultSlots.js +++ b/src/components/Project/defaultSlots.js @@ -411,4 +411,4 @@ const defaultSlots = { }; -export { defaultSlots as default }; +export default defaultSlots; diff --git a/src/components/Project/index.js b/src/components/Project/index.js index fd57546a..a7cceffe 100644 --- a/src/components/Project/index.js +++ b/src/components/Project/index.js @@ -1,4 +1,3 @@ -/* eslint-disable */ import React, { Component, PropTypes } from 'react'; import defaultSlots from './defaultSlots'; import documentsPropType from '../../containers/Documents/propTypes'; @@ -26,7 +25,7 @@ export default class Project extends Component { componentDidMount() { // Get all of the files for thsi project const pathList = Object.keys(defaultSlots).reduce((acc, state) => { - const paths = defaultSlots[state]["slots"].map(val => ( + const paths = defaultSlots[state].slots.map(val => ( `${this.state.documentPath}Project-${this.state.projectId}/${val.folder_name}` )); return acc.concat(paths); @@ -50,6 +49,46 @@ export default class Project extends Component { fileReader.readAsDataURL(file); } + + // Generate the HTML to show all of the files for a state + generateStateHTML = (stateId, slotToDocuments) => ( + defaultSlots[stateId].slots.map((val) => { + const slotPath = `${this.state.documentPath}Project-${this.state.projectId}/${val.folder_name}`; + return ( +
+

{val.title}

+ {/* Pass the download path into the render upload button function */} + {this.renderUploadButton(slotPath)} + {/* Render the documents for this slot */} + {this.renderDocuments(slotToDocuments[slotPath])} +
+
+ ); + }) + ) + + generateDocumentHTML = () => { + // An object that given a slot path name, returns a list of documents + const slotToDocuments = this.props.documents.files.project.reduce((acc, val) => { + const newAcc = acc; + if (acc[val.path]) { + newAcc[val.path].push(val); + } else { + newAcc[val.path] = [val]; + } + return acc; + }, {}); + return Object.keys(defaultSlots).map(val => ( +
+

{`${val}. ${defaultSlots[val].name}`}

+
{defaultSlots[val].description}
+
+ {this.generateStateHTML(val, slotToDocuments)} +
+
+ )); + } + renderUploadButton = (uploadPath) => { let disabled = false; let img = ( @@ -88,8 +127,8 @@ export default class Project extends Component { } renderDocuments = (documentList) => { - let docs =
- if (documentList != null && documentList.length > 0) { + let docs =
; + if (documentList != null && documentList.length > 0) { docs = documentList.map(item => (
@@ -99,69 +138,11 @@ export default class Project extends Component { return docs; } - // Generate the HTML to show all of the files for a state - generateStateHTML = (stateId, slotToDocuments) => ( - defaultSlots[stateId]["slots"].map(val => { - const slotPath = `${this.state.documentPath}Project-${this.state.projectId}/${val.folder_name}`; - return ( -
-

{val.title}

- {/* Pass the download path into the render upload button function */} - {this.renderUploadButton(slotPath)} - {/* Render the documents for this slot */} - {this.renderDocuments(slotToDocuments[slotPath])} -
-
- ); - }) - ) - - generateDocumentHTML = () => { - // An object that given a slot path name, returns a list of documents - const slotToDocuments = this.props.documents.files.project.reduce((acc, val) => { - if (acc[val.path]) { - acc[val.path].push(val); - } else { - acc[val.path] = [val]; - } - return acc; - }, {}); - return Object.keys(defaultSlots).map(val => ( -
-

{`${val}. ${defaultSlots[val]['name']}`}

-
{defaultSlots[val]['description']}
-
- {this.generateStateHTML(val, slotToDocuments)} -
-
- )); - } - render() { - const projectExists = this.props.projects["list"].reduce((acc, val) => ( - acc || val.id == this.props.params.projectId + /* eslint-disable eqeqeq */ + const projectExists = this.props.projects.list.reduce((acc, val) => ( + acc || (val.id == this.props.params.projectId) ), false); - if (!projectExists) { - return ( -
- -
-
-
- This project does not exist -
-
-
-
- ); - } return (
- {this.generateDocumentHTML()} + {projectExists ? this.generateDocumentHTML() : 'This project does not exist'}
-- GitLab From a00ed5589ab52c25d7ea7ba130b0df9cfbde13c5 Mon Sep 17 00:00:00 2001 From: Conrad S Date: Wed, 22 Feb 2017 10:53:35 -0500 Subject: [PATCH 07/15] Add real call to project service --- src/containers/Building/sagas.js | 45 ++++++++++---------------------- src/utils/restServices.js | 2 ++ 2 files changed, 16 insertions(+), 31 deletions(-) diff --git a/src/containers/Building/sagas.js b/src/containers/Building/sagas.js index bab5c4c5..3f90aacc 100644 --- a/src/containers/Building/sagas.js +++ b/src/containers/Building/sagas.js @@ -1,6 +1,6 @@ import { call, put, takeEvery, takeLatest } from 'redux-saga/effects'; import request from '../../utils/request'; -import { getHeaders, buildingsURL } from '../../utils/restServices'; +import { getHeaders, buildingsURL, projectURL } from '../../utils/restServices'; import { LOAD_BUILDING_DETAIL, @@ -11,6 +11,7 @@ import { buildingDetailLoaded, buildingDetailLoadingError, projectsLoaded, + projectsLoadingError, } from './actions'; /** @@ -37,37 +38,19 @@ function* getBuildingDetail(action) { function* getProjects(action) { const buildingId = action.buildingId; - const res = { - buildingId, - data: [ - { - client_id: 5, - created: '2016-04-29T19:25:08.509790+00:00', - id: 6, - name: '2324 Pitkin Avenue', - sales_force_id: '00661000009yx9lAAA', - slug: '2324-pitkin-avenue-6', - state: 'pending', - updated: null, - program_type: 'CBRA', - building_id: buildingId, - }, - { - client_id: 10, - created: '2016-04-29T19:25:08.509790+00:00', - id: 7, - name: '2324 Pitkin Avenue', - sales_force_id: '00661000009yx9lAAA', - slug: '2324-pitkin-avenue-6', - state: 'pending', - updated: null, - program_type: 'BUILD HEALTH', - building_id: buildingId, - }, - ], - }; + const res = yield call( + request, + `${projectURL}?building_id=${buildingId}`, { + method: 'GET', + headers: getHeaders(), + } + ); - yield put(projectsLoaded(res)); + if (!res.err) { + yield put(projectsLoaded(res)); + } else { + yield put(projectsLoadingError(res.err)); + } } /** diff --git a/src/utils/restServices.js b/src/utils/restServices.js index 40a39a0a..b77a127f 100644 --- a/src/utils/restServices.js +++ b/src/utils/restServices.js @@ -15,3 +15,5 @@ export const turkURL = `${buildingService}/turkhit/`; export const documentURL = `${documentService}/document/`; export const accountURL = `${utilityService}/account/`; export const billsURL = `${utilityService}/bills/`; +export const projectURL = `${projectService}/project/`; +export const projectDocumentURL = `${projectService}/document/`; -- GitLab From c304793bd7d4749ce865ed597ab89712802bb316 Mon Sep 17 00:00:00 2001 From: Conrad S Date: Wed, 22 Feb 2017 15:41:51 -0500 Subject: [PATCH 08/15] Update Project frontend to use projectservice database --- src/components/DocumentCardViewer/index.js | 2 +- src/components/Project/index.js | 128 ++++++++++++++------- src/containers/Documents/actions.js | 18 ++- src/containers/Documents/constants.js | 1 + src/containers/Documents/sagas.js | 35 +++++- src/utils/restServices.js | 2 +- 6 files changed, 135 insertions(+), 51 deletions(-) diff --git a/src/components/DocumentCardViewer/index.js b/src/components/DocumentCardViewer/index.js index 77dbea32..544b6418 100644 --- a/src/components/DocumentCardViewer/index.js +++ b/src/components/DocumentCardViewer/index.js @@ -16,7 +16,7 @@ export default class DocumentCardViewer extends Component { } componentDidMount() { - this.props.getDocuments([this.props.documentPath], this.props.fileKey); + this.props.getDocuments([this.props.documentPath], [], this.props.fileKey); this.props.getFolderUrl(this.props.documentPath); } diff --git a/src/components/Project/index.js b/src/components/Project/index.js index a7cceffe..23845077 100644 --- a/src/components/Project/index.js +++ b/src/components/Project/index.js @@ -8,6 +8,8 @@ import { import DocumentCard from '../DocumentCard/'; import LinkBarDetail from '../../components/LinkBarDetail'; import { uploadSVG } from '../bpl'; +import { getHeaders, projectDocumentURL } from '../../utils/restServices'; +import request from '../../utils/request'; export default class Project extends Component { constructor(props) { @@ -15,57 +17,54 @@ export default class Project extends Component { const { building, buildingId } = this.props; this.state = { - documentPath: `/Buildings/${buildingId}_${building.address}/`, + projectDocumentsPath: `/Buildings/${buildingId}_${building.address}/Project-${this.props.params.projectId}/`, projectId: this.props.params.projectId, fileKey: 'project', convertingFile: false, + error: '', }; } componentDidMount() { - // Get all of the files for thsi project - const pathList = Object.keys(defaultSlots).reduce((acc, state) => { - const paths = defaultSlots[state].slots.map(val => ( - `${this.state.documentPath}Project-${this.state.projectId}/${val.folder_name}` - )); - return acc.concat(paths); - }, []); - this.props.getDocuments(pathList, this.state.fileKey); + // Get all of the files for this project + this.getProjectDocuments(); } - uploadHandler = (event) => { - const file = event.target.files[0]; - const { buildingId } = this.props; - const fileKey = this.state.fileKey; - const documentPath = event.target.name; - this.setState({ convertingFile: true }); - const fileReader = new FileReader(); - - fileReader.onload = function fileResults() { - this.setState({ convertingFile: false }); - this.props.uploadDocument(buildingId, documentPath, fileReader.result, '', - file.name, fileKey); - }.bind(this); - fileReader.readAsDataURL(file); + // Make a call to project service to get a list of documents associated with this project + // Then call document service with those keys to get those files + getProjectDocuments = () => { + request(`${projectDocumentURL}?project_id=${this.props.params.projectId}`, { + method: 'GET', + headers: getHeaders(), + }).then((res) => { + if (!res.err) { + const documentKeys = res.data.map(val => ( + val.document_key + )); + // Call document service with the keys + this.props.getDocuments([], documentKeys, this.state.fileKey); + } else { + this.setState({ error: `Failed to retrieve project documents. | ${res.err.message}` }); + } + }); } - - // Generate the HTML to show all of the files for a state - generateStateHTML = (stateId, slotToDocuments) => ( - defaultSlots[stateId].slots.map((val) => { - const slotPath = `${this.state.documentPath}Project-${this.state.projectId}/${val.folder_name}`; - return ( -
-

{val.title}

- {/* Pass the download path into the render upload button function */} - {this.renderUploadButton(slotPath)} - {/* Render the documents for this slot */} - {this.renderDocuments(slotToDocuments[slotPath])} -
-
- ); - }) - ) + // Post a project document to the projectservice + postProjectDocument = (documentKey, slot) => { + request(`${projectDocumentURL}`, { + method: 'POST', + headers: getHeaders(), + body: JSON.stringify({ + document_key: documentKey, + project_id: this.state.projectId, + role: slot, + }), + }).then((res) => { + if (res.err) { + this.setState({ error: `Failed to save the document to project service. | ${res.err.message}` }); + } + }); + } generateDocumentHTML = () => { // An object that given a slot path name, returns a list of documents @@ -89,7 +88,42 @@ export default class Project extends Component { )); } - renderUploadButton = (uploadPath) => { + // Generate the HTML to show all of the files for a state + generateStateHTML = (stateId, slotToDocuments) => ( + defaultSlots[stateId].slots.map((val) => { + const slot = `${val.folder_name}`; + return ( +
+

{val.title}

+ {/* Pass the download path into the render upload button function */} + {this.renderUploadButton(slot)} + {/* Render the documents for this slot */} + {this.renderDocuments(slotToDocuments[`${this.state.projectDocumentsPath}${slot}`])} +
+
+ ); + }) + ) + + uploadHandler = (event) => { + const file = event.target.files[0]; + const { buildingId } = this.props; + const fileKey = this.state.fileKey; + const documentSlot = event.target.name; + const documentPath = `${this.state.projectDocumentsPath}${documentSlot}`; + this.setState({ convertingFile: true }); + const fileReader = new FileReader(); + + fileReader.onload = function fileResults() { + this.setState({ convertingFile: false }); + this.props.uploadDocument(buildingId, documentPath, fileReader.result, '', + file.name, fileKey, + projectDocumentURL, { project_id: this.state.projectId, role: documentSlot }); + }.bind(this); + fileReader.readAsDataURL(file); + } + + renderUploadButton = (slot) => { let disabled = false; let img = (
@@ -113,13 +147,13 @@ export default class Project extends Component {
-
@@ -156,6 +190,12 @@ export default class Project extends Component {
+
+ {this.state.error} +
{projectExists ? this.generateDocumentHTML() : 'This project does not exist'}
diff --git a/src/containers/Documents/actions.js b/src/containers/Documents/actions.js index 531d61af..b7eb9320 100644 --- a/src/containers/Documents/actions.js +++ b/src/containers/Documents/actions.js @@ -7,12 +7,14 @@ import { UPLOAD_DOCUMENT_ERROR, LOAD_FOLDER_URL, LOAD_FOLDER_URL_SUCCESS, + POST_TO_SERVICE, } from './constants'; -export function loadDocuments(documentPaths, fileKey) { +export function loadDocuments(documentPaths, documentKeys, fileKey) { return { type: LOAD_DOCUMENTS, documentPaths, + documentKeys, fileKey, }; } @@ -33,7 +35,7 @@ export function documentsLoadingError(error) { } export function uploadDocument(buildingId, documentPath, document, tags, - name, fileKey) { + name, fileKey, servicePostURL, servicePostBody) { return { type: UPLOAD_DOCUMENT, buildingId, @@ -42,6 +44,18 @@ export function uploadDocument(buildingId, documentPath, document, tags, tags, name, fileKey, + servicePostURL, + servicePostBody, + }; +} + +export function postToService(serviceURL, body, docRes, fileKey) { + return { + type: POST_TO_SERVICE, + serviceURL, + body, + docRes, + fileKey, }; } diff --git a/src/containers/Documents/constants.js b/src/containers/Documents/constants.js index 5e8ab2d6..4efbcad5 100644 --- a/src/containers/Documents/constants.js +++ b/src/containers/Documents/constants.js @@ -6,3 +6,4 @@ export const UPLOAD_DOCUMENT_SUCCESS = 'UPLOAD_DOCUMENT_SUCCESS'; export const UPLOAD_DOCUMENT_ERROR = 'UPLOAD_DOCUMENT_ERROR'; export const LOAD_FOLDER_URL = 'LOAD_FOLDER_URL'; export const LOAD_FOLDER_URL_SUCCESS = 'LOAD_FOLDER_URL_SUCCESS'; +export const POST_TO_SERVICE = 'POST_TO_SERVICE'; diff --git a/src/containers/Documents/sagas.js b/src/containers/Documents/sagas.js index 518211ca..95cd3f92 100644 --- a/src/containers/Documents/sagas.js +++ b/src/containers/Documents/sagas.js @@ -6,6 +6,7 @@ import { LOAD_DOCUMENTS, UPLOAD_DOCUMENT, LOAD_FOLDER_URL, + POST_TO_SERVICE, } from './constants'; import { @@ -14,18 +15,22 @@ import { documentUploaded, documentUploadError, folderUrlLoaded, + postToService, } from './actions'; function* getDocuments(action) { - const { documentPaths, fileKey } = action; + const { documentPaths, documentKeys, fileKey } = action; const pathsString = documentPaths.reduce((acc, val) => ( `${acc}paths[]=${val}&` ), ''); + const keysString = documentKeys.reduce((acc, val) => ( + `${acc}keys[]=${val}&` + ), ''); const res = yield call( request, - `${documentURL}?${pathsString}`, { + `${documentURL}?${pathsString}${keysString}`, { method: 'GET', headers: getHeaders(), } @@ -38,6 +43,23 @@ function* getDocuments(action) { } } +function* postToServiceSaga(action) { + const { serviceURL, body } = action; + const res = yield call( + request, + `${serviceURL}`, { + method: 'POST', + headers: getHeaders(), + body: JSON.stringify(body), + } + ); + if (!res.err) { + yield put(documentUploaded(action.docRes, action.fileKey)); + } else { + yield put(documentUploadError(res.err)); + } +} + function* uploadDocument(action) { const { buildingId, documentPath, document, tags, name, fileKey } = action; @@ -57,7 +79,13 @@ function* uploadDocument(action) { ); if (!res.err) { - yield put(documentUploaded(res, fileKey)); + if (action.servicePostURL !== undefined) { + const { servicePostURL, servicePostBody } = action; + servicePostBody.document_key = res.data.key; + yield put(postToService(servicePostURL, servicePostBody, res, fileKey)); + } else { + yield put(documentUploaded(res, fileKey)); + } } else { yield put(documentUploadError(res.err)); } @@ -82,5 +110,6 @@ function* getFolderUrl(action) { export default function* () { yield takeLatest(LOAD_DOCUMENTS, getDocuments); yield takeLatest(UPLOAD_DOCUMENT, uploadDocument); + yield takeLatest(POST_TO_SERVICE, postToServiceSaga); yield takeLatest(LOAD_FOLDER_URL, getFolderUrl); } diff --git a/src/utils/restServices.js b/src/utils/restServices.js index b77a127f..0a2ae8de 100644 --- a/src/utils/restServices.js +++ b/src/utils/restServices.js @@ -16,4 +16,4 @@ export const documentURL = `${documentService}/document/`; export const accountURL = `${utilityService}/account/`; export const billsURL = `${utilityService}/bills/`; export const projectURL = `${projectService}/project/`; -export const projectDocumentURL = `${projectService}/document/`; +export const projectDocumentURL = `${projectService}/project/document/`; -- GitLab From e10e46250d1d5d69e0b5079cd06c46ee2fca0552 Mon Sep 17 00:00:00 2001 From: Conrad S Date: Thu, 23 Feb 2017 10:01:40 -0500 Subject: [PATCH 09/15] Catch empty projectList error and return None --- src/components/BuildingOverview/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/BuildingOverview/index.js b/src/components/BuildingOverview/index.js index 0333ce5d..9196bc94 100644 --- a/src/components/BuildingOverview/index.js +++ b/src/components/BuildingOverview/index.js @@ -23,7 +23,7 @@ export default class BuildingOverview extends Component { renderProjects = () => { const projectList = this.props.projects.list; - if (projectList.length <= 0) { + if (!projectList || projectList.length <= 0) { return (

None

); -- GitLab From 77af5016b6a96cbf0b2e7ee7a945cc3dfd29d2a4 Mon Sep 17 00:00:00 2001 From: Conrad S Date: Fri, 24 Feb 2017 14:27:25 -0500 Subject: [PATCH 10/15] Add links to box folder --- src/components/BuildingOverview/index.js | 5 +++++ src/components/LinkBarDetail/index.js | 4 ++-- src/components/Project/index.js | 9 ++++++++- 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/components/BuildingOverview/index.js b/src/components/BuildingOverview/index.js index 9196bc94..45014d37 100644 --- a/src/components/BuildingOverview/index.js +++ b/src/components/BuildingOverview/index.js @@ -21,6 +21,10 @@ export default class BuildingOverview extends Component { }; } + componentDidMount() { + this.props.getFolderUrl(this.state.documentPath); + } + renderProjects = () => { const projectList = this.props.projects.list; if (!projectList || projectList.length <= 0) { @@ -46,6 +50,7 @@ export default class BuildingOverview extends Component { { name: 'Overview', url: '' }, ]} links={[ + { name: 'Building Folder', url: this.props.documents.folderUrl, tags: '' }, /* { name: 'Sales Force', url: '//google.com', tags: '' }, { name: 'Engineering', url: '//google.com', tags: 'engineering/' }, { name: 'Finance', url: '//google.com', tags: 'finance/' }, */ diff --git a/src/components/LinkBarDetail/index.js b/src/components/LinkBarDetail/index.js index 96f797ae..0746568f 100644 --- a/src/components/LinkBarDetail/index.js +++ b/src/components/LinkBarDetail/index.js @@ -24,9 +24,9 @@ const generateBreadcrumbs = (rootURL, breadcrumbs) => { const generateLinks = (rootURL, links) => { const linkList = links.map(val => ( ( - + {val.name} - + ) )); return linkList; diff --git a/src/components/Project/index.js b/src/components/Project/index.js index 23845077..333c99ce 100644 --- a/src/components/Project/index.js +++ b/src/components/Project/index.js @@ -28,6 +28,7 @@ export default class Project extends Component { componentDidMount() { // Get all of the files for this project this.getProjectDocuments(); + this.props.getFolderUrl(this.state.projectDocumentsPath); } // Make a call to project service to get a list of documents associated with this project @@ -185,7 +186,12 @@ export default class Project extends Component { { name: 'Overview', url: '' }, { name: `Project ${this.props.params.projectId}`, url: 'null' }, ]} - links={[]} + links={[ + { name: 'Project Folder', url: this.props.documents.folderUrl, tags: '' }, + /* { name: 'Sales Force', url: '//google.com', tags: '' }, + { name: 'Engineering', url: '//google.com', tags: 'engineering/' }, + { name: 'Finance', url: '//google.com', tags: 'finance/' }, */ + ]} />
@@ -215,4 +221,5 @@ Project.propTypes = { documents: documentsPropType, getDocuments: PropTypes.func, uploadDocument: PropTypes.func, + getFolderUrl: PropTypes.func, }; -- GitLab From 02ec7b26ab0ad76de4130166a4c26d2502ceee86 Mon Sep 17 00:00:00 2001 From: Alessandro DiMarco Date: Tue, 28 Feb 2017 11:10:11 -0500 Subject: [PATCH 11/15] Switch building_id proptype to number --- src/containers/Building/propTypes.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/containers/Building/propTypes.js b/src/containers/Building/propTypes.js index f78618d6..7aa650c8 100644 --- a/src/containers/Building/propTypes.js +++ b/src/containers/Building/propTypes.js @@ -21,7 +21,7 @@ export const overviewPropTypes = { }; export const projectPropTypes = { - building_id: string, + building_id: number, client_id: number, created: string, id: number, -- GitLab From 221f7dbe4c9efa49e3fc2dc0c1781bce62e68053 Mon Sep 17 00:00:00 2001 From: Alessandro DiMarco Date: Tue, 28 Feb 2017 11:10:58 -0500 Subject: [PATCH 12/15] Check if projectlist is empty before rendering projectdetail page --- src/components/Project/index.js | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/components/Project/index.js b/src/components/Project/index.js index 333c99ce..a05cdafb 100644 --- a/src/components/Project/index.js +++ b/src/components/Project/index.js @@ -174,10 +174,12 @@ export default class Project extends Component { } render() { - /* eslint-disable eqeqeq */ - const projectExists = this.props.projects.list.reduce((acc, val) => ( - acc || (val.id == this.props.params.projectId) - ), false); + let projectExists = false; + if (this.props.projects.list !== undefined) { + projectExists = this.props.projects.list.reduce((acc, val) => ( + acc || val.id === parseInt(this.props.params.projectId, 10) + ), false); + } return (
Date: Tue, 28 Feb 2017 11:20:31 -0500 Subject: [PATCH 13/15] Only call document service if keys array is non empty --- src/components/Project/index.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/components/Project/index.js b/src/components/Project/index.js index a05cdafb..fd16df84 100644 --- a/src/components/Project/index.js +++ b/src/components/Project/index.js @@ -43,7 +43,9 @@ export default class Project extends Component { val.document_key )); // Call document service with the keys - this.props.getDocuments([], documentKeys, this.state.fileKey); + if (documentKeys.length > 0) { + this.props.getDocuments([], documentKeys, this.state.fileKey); + } } else { this.setState({ error: `Failed to retrieve project documents. | ${res.err.message}` }); } -- GitLab From c1ac6046d6e42ef3505d9a2c886522e5f71808a9 Mon Sep 17 00:00:00 2001 From: Conrad S Date: Tue, 28 Feb 2017 12:16:17 -0500 Subject: [PATCH 14/15] Changes to error messages and loading --- src/components/ErrorAlert/index.js | 1 + src/components/Project/index.js | 35 +++++++++++++++++++-------- src/containers/Documents/propTypes.js | 4 +-- 3 files changed, 28 insertions(+), 12 deletions(-) diff --git a/src/components/ErrorAlert/index.js b/src/components/ErrorAlert/index.js index 87d606aa..d0f6f506 100644 --- a/src/components/ErrorAlert/index.js +++ b/src/components/ErrorAlert/index.js @@ -22,6 +22,7 @@ class ErrorAlert extends Component { render() { const { error, genericMessage } = this.props; + console.log(error); return (
{ + this.projectDocumentsLoading = true; request(`${projectDocumentURL}?project_id=${this.props.params.projectId}`, { method: 'GET', headers: getHeaders(), @@ -47,8 +50,9 @@ export default class Project extends Component { this.props.getDocuments([], documentKeys, this.state.fileKey); } } else { - this.setState({ error: `Failed to retrieve project documents. | ${res.err.message}` }); + this.setState({ error: res.err }); } + this.projectDocumentsLoading = false; }); } @@ -64,7 +68,7 @@ export default class Project extends Component { }), }).then((res) => { if (res.err) { - this.setState({ error: `Failed to save the document to project service. | ${res.err.message}` }); + this.setState({ error: res.err }); } }); } @@ -182,6 +186,15 @@ export default class Project extends Component { acc || val.id === parseInt(this.props.params.projectId, 10) ), false); } + let mainContent = (
Loading...
); + console.log(`project document: ${this.state.projectDocumentsLoading}`); + console.log(`documents: ${this.props.documents.loading}`); + console.log(`projects: ${this.props.projects.loading}`); + if (!this.state.projectDocumentsLoading && + !this.props.documents.loading && + !this.props.projects.loading) { + mainContent = projectExists ? this.generateDocumentHTML() : 'This project does not exist'; + } return (
-
- {this.state.error} -
- {projectExists ? this.generateDocumentHTML() : 'This project does not exist'} + + + {mainContent}
diff --git a/src/containers/Documents/propTypes.js b/src/containers/Documents/propTypes.js index 185bf293..cc8a037b 100644 --- a/src/containers/Documents/propTypes.js +++ b/src/containers/Documents/propTypes.js @@ -1,6 +1,6 @@ import { PropTypes } from 'react'; -const { shape, arrayOf, oneOfType, string, number, bool } = PropTypes; +const { shape, arrayOf, oneOfType, string, number, bool, instanceOf } = PropTypes; export const documentProps = shape({ box_id: number, @@ -21,7 +21,7 @@ export default shape({ loading: bool, error: oneOfType([ bool, - string, + instanceOf(Error), ]), folderUrl: string, files: shape({ -- GitLab From 009581804e3b181fb44e7a6bbb8863cdcdee4858 Mon Sep 17 00:00:00 2001 From: Conrad S Date: Tue, 28 Feb 2017 12:22:39 -0500 Subject: [PATCH 15/15] Improve loading --- src/components/ErrorAlert/index.js | 1 - src/components/Project/index.js | 7 ++----- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/src/components/ErrorAlert/index.js b/src/components/ErrorAlert/index.js index d0f6f506..87d606aa 100644 --- a/src/components/ErrorAlert/index.js +++ b/src/components/ErrorAlert/index.js @@ -22,7 +22,6 @@ class ErrorAlert extends Component { render() { const { error, genericMessage } = this.props; - console.log(error); return (
{ - this.projectDocumentsLoading = true; + this.setState({ projectDocumentsLoading: true }); request(`${projectDocumentURL}?project_id=${this.props.params.projectId}`, { method: 'GET', headers: getHeaders(), @@ -52,7 +52,7 @@ export default class Project extends Component { } else { this.setState({ error: res.err }); } - this.projectDocumentsLoading = false; + this.setState({ projectDocumentsLoading: false }); }); } @@ -187,9 +187,6 @@ export default class Project extends Component { ), false); } let mainContent = (
Loading...
); - console.log(`project document: ${this.state.projectDocumentsLoading}`); - console.log(`documents: ${this.props.documents.loading}`); - console.log(`projects: ${this.props.projects.loading}`); if (!this.state.projectDocumentsLoading && !this.props.documents.loading && !this.props.projects.loading) { -- GitLab