Skip to content
This repository was archived by the owner on Jul 31, 2023. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 15 additions & 7 deletions src/App.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ export default class App extends Component {
.then(questionnaire => {
this.setState({ questionnaire: questionnaire });
this.setState({ response: response});
this.setState({ isFetchingArtifacts: false});
});
});
}
Expand All @@ -109,11 +110,18 @@ export default class App extends Component {
let acCoverage = this.appContext.coverage;
let acQuestionnaire = this.appContext.questionnaire;
let acResponse = this.appContext.response;
if(acOrder && acCoverage && !acQuestionnaire && !acResponse) {
// TODO: There's an additional case where you could launch
// with just the order/coverage by invoking the operation
// but I think the endpoint extension on coverage which
// would facilitate that is going away in ballot.
if(isContainedQuestionnaire && questionnaire) {
// TODO: This is a workaround for getting adaptive forms to work
// in its current form, adaptive forms do not operate with the
// package operation
const reloadQuestionnaire = questionnaire !== undefined;
this.setState({
isFetchingArtifacts: true,
reloadQuestionnaire
})
this.fetchResourcesAndExecuteCql(acOrder, acCoverage, acQuestionnaire, questionnaire);

} else if(acOrder && acCoverage && !acQuestionnaire && !acResponse) {
searchByOrder(acOrder, this.smart).then((res) => {
// TODO: Don't know how to deal with multiple QRs
// Let user pick with a UI? Force orders to
Expand Down Expand Up @@ -146,12 +154,12 @@ export default class App extends Component {
}
}

fetchResourcesAndExecuteCql(order, coverage, questionnaire) {
fetchResourcesAndExecuteCql(order, coverage, questionnaire, containedQuestionnaire) {
fetchFhirVersion(this.props.smart.state.serverUrl)
.then(fhirVersion => {
this.fhirVersion = fhirVersion;

fetchArtifactsOperation(order, coverage, questionnaire, this.smart, this.consoleLog)
fetchArtifactsOperation(order, coverage, questionnaire, this.smart, this.consoleLog, containedQuestionnaire)
.then(artifacts => {
console.log("fetched needed artifacts:", artifacts);
const orderResource = artifacts.order;
Expand Down
2 changes: 1 addition & 1 deletion src/LogPage.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ class LogPage extends Component {

componentDidMount(){
const logRequest = new XMLHttpRequest();
logRequest.open("GET", "../logs");
logRequest.open("GET", "../api/logs");
logRequest.setRequestHeader("Content-Type", "application/json");
logRequest.onload = (e) => {
this.setState({logs: JSON.parse(logRequest.responseText).sort((a,b)=>{return b.createdAt - a.createdAt})});
Expand Down
13 changes: 9 additions & 4 deletions src/backend/database/impl.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,18 +31,22 @@ function getCountAndIncrement() {
}

function postLog(log) {
log.createdAt = Date.now();
db.get("logs").push(log).write();
}

function getLog(id) {
return db.get("logs").find({id: id}).value();
}
function getLogs() {
return db.get("logs").value();
}

function putLog(id, log) {
db.get("logs")
.find({ id: id })
.assign(log)
.write();
.find({ id: id })
.assign(log).write();
}

function deleteClient(id) {
Expand All @@ -56,6 +60,7 @@ module.exports = {
deleteClient,
postLog,
getLog,
getLogs,
putLog,
getCountAndIncrement
};
};
11 changes: 10 additions & 1 deletion src/backend/routes/database.js
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ router.post("/logs", (req, res) => {

router.put("/logs/:id", (req, res) => {
const newLog = req.body;
db.putLog(req.params.id, newLog);
db.putLog(parseInt(req.params.id), newLog);
res.sendStatus(200);
});

Expand All @@ -84,4 +84,13 @@ router.get("/logs/:id", (req, res) => {
}
});

router.get("/api/logs", (req, res) => {
const result = db.getLogs();
if(result) {
res.send(result);
} else {
res.sendStatus(404)
}
})

module.exports = router;
51 changes: 35 additions & 16 deletions src/components/QuestionnaireForm/QuestionnaireForm.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ export default class QuestionnaireForm extends Component {
this.smart = props.smart;
this.patientId = props.patientId;
this.fhirVersion = props.fhirVersion;
this.FHIR_PREFIX = props.FHIR_PREFIX;
this.appContext = props.appContext;
this.partialForms = {};
this.handleGtable = this.handleGtable.bind(this);
Expand Down Expand Up @@ -73,8 +72,7 @@ export default class QuestionnaireForm extends Component {
savedResponse: mergedResponse
})
} else {

this.loadPreviousForm();
this.loadPreviousForm(false);

// If not using saved QuestionnaireResponse, create a new one
let newResponse = {
Expand Down Expand Up @@ -173,12 +171,15 @@ export default class QuestionnaireForm extends Component {
return `QuestionnaireResponse?_lastUpdated=gt${updateDate.toISOString().split('T')[0]}&status=in-progress`
}

loadPreviousForm() {
loadPreviousForm(showError = true) {
// search for any QuestionnaireResponses
this.smart.request(this.getRetrieveSaveQuestionnaireUrl() +
"&subject=" + this.getPatient()).then((result) => {
this.popupClear("Would you like to load a previous form?", "Cancel", false);
this.processSavedQuestionnaireResponses(result, true);
let questionnaireResponseUrl = this.getRetrieveSaveQuestionnaireUrl();
questionnaireResponseUrl = questionnaireResponseUrl + "&subject=" + this.getPatient();
console.log("Using URL " + questionnaireResponseUrl);

this.smart.request(questionnaireResponseUrl).then((result) => {
this.popupClear("Would you like to load a previously in-progress form?", "Cancel", false);
this.processSavedQuestionnaireResponses(result, showError);
}, ((result) => {
this.popupClear("Error: failed to load previous in-progress forms", "OK", true);
this.popupLaunch();
Expand All @@ -187,7 +188,17 @@ export default class QuestionnaireForm extends Component {

// retrieve next sets of questions
loadNextQuestions() {
const url = this.props.FILE_PATH + "fhir" + "/" + this.fhirVersion + "/" + "Questionnaire/$next-question";
// this is a temp fix for adaptive forms
// TODO: figure out what to do about next-question standardization.
let qformUrl = this.props.appContext.questionnaire;
if(qformUrl) {
const urlArray = qformUrl.split('/');
urlArray.pop();
qformUrl = urlArray.join('/');
} else {
qformUrl = 'http://localhost:8090/fhir/r4/Questionnaire'
}
const url = `${qformUrl}/$next-question`;

const currentQuestionnaireResponse = window.LForms.Util.getFormFHIRData('QuestionnaireResponse', this.fhirVersion, "#formContainer");;
//const mergedResponse = this.mergeResponseForSameLinkId(currentQuestionnaireResponse);
Expand Down Expand Up @@ -228,13 +239,14 @@ export default class QuestionnaireForm extends Component {
let count = 0;

partialResponses.entry.forEach(bundleEntry => {
let questionnaireId = null;
if(bundleEntry.resource.contained) {
questionnaireId = bundleEntry.resource?.contained[0]?.id;
let idMatch = false;
if(bundleEntry.resource.contained){
const questionnaireId = bundleEntry.resource?.contained[0].id;
idMatch = this.props.qform.id === questionnaireId;
}
const questionaireIdUrl = bundleEntry.resource.questionnaire;
const questionnaireIdUrl = bundleEntry.resource.questionnaire;

if (this.props.qform.id === questionnaireId || questionaireIdUrl.includes(this.props.qform.id)) {
if ( idMatch || questionnaireIdUrl.includes(this.props.qform.id)) {
count = count + 1;
// add the option to the popupOptions
let date = new Date(bundleEntry.resource.authored);
Expand Down Expand Up @@ -371,7 +383,7 @@ export default class QuestionnaireForm extends Component {
e.url == "http://hl7.org/fhir/StructureDefinition/cqf-expression" || e.url == "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-initialExpression"
);

if (isGtable && containsValueExpression) {
if (isGtable && containsValueExpression && !this.props.standalone) {
// check if the prepopulationResult contains any value
// if yes, then need to add corresponding sub-items then provide the answer
// need to figure out which value is provided from the prepopulationResult though
Expand Down Expand Up @@ -977,7 +989,14 @@ export default class QuestionnaireForm extends Component {
}

console.log(requestOptions);
let url = this.FHIR_PREFIX + this.fhirVersion + "/QuestionnaireResponse";
let url = this.props.appContext.questionnaire;
if(url) {
const urlArray = url.split('/');
url = urlArray.slice(0, -2).join('/');
} else {
url = 'http://localhost:8090/fhir/r4'
}
url = url + "/QuestionnaireResponse";
console.log(url);
fetch(url, requestOptions).then(handleFetchErrors).then(r => {
let msg = "QuestionnaireResponse sent to Payer";
Expand Down
1 change: 1 addition & 0 deletions src/launch.js
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ function callback(log) {
"launch=" +
encodeURIComponent(log.launchContextId);
}
updateLog(log);
window.location.href = authRedirect;

}
Expand Down
13 changes: 10 additions & 3 deletions src/util/fetchArtifacts.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import "isomorphic-fetch";
import { buildFhirUrl, isRequestReference } from "./util";
function fetchArtifactsOperation(order, coverage, questionnaire, smart, consoleLog) {
function fetchArtifactsOperation(order, coverage, questionnaire, smart, consoleLog, containedQuestionnaire) {
// fetch from operation
// parse return parameters similar to function below
return new Promise(function(resolve, reject) {
Expand Down Expand Up @@ -46,9 +46,16 @@ function fetchArtifactsOperation(order, coverage, questionnaire, smart, consoleL
.then((e)=> {return e.json()}).then((result) => {
// TODO: Handle multiple questionnaires
const bundle = result.parameter[0].resource.entry;
const questionnaire = bundle.find((e) => e.resource.resourceType === "Questionnaire")?.resource;
let questionnaire;

retVal.questionnaire = questionnaire;
if (containedQuestionnaire) {
retVal.questionnaire = containedQuestionnaire;
questionnaire = containedQuestionnaire;
} else {
questionnaire = bundle.find((e) => e.resource.resourceType === "Questionnaire")?.resource;
retVal.questionnaire = questionnaire;
}

retVal.isAdaptiveFormWithoutExtension = questionnaire.extension && questionnaire.extension.length > 0;

findQuestionnaireEmbeddedCql(questionnaire.item);
Expand Down
4 changes: 3 additions & 1 deletion src/util/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,9 @@ function postToLogs(log, callback) {
logRequest.open("POST", "../logs");
logRequest.setRequestHeader("Content-Type", "application/json");
logRequest.onload = function() {
callback(JSON.parse(logRequest.responseText));
if(callback) {
callback(JSON.parse(logRequest.responseText));
}
};
logRequest.send(JSON.stringify(log));
}
Expand Down