Skip to content

Commit

Permalink
Merge pull request #22 from mcode/patient-portal-integrate
Browse files Browse the repository at this point in the history
clickable responses
  • Loading branch information
smalho01 authored Aug 25, 2022
2 parents bb950cc + f4cdd24 commit 6b9df08
Show file tree
Hide file tree
Showing 7 changed files with 87 additions and 70 deletions.
2 changes: 1 addition & 1 deletion src/components/Dashboard/Dashboard.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ const Dashboard = (props) => {
<div className={classes.dashboardArea}>
{resources.length > 0?
resources.map((e) => {
return <DashboardElement key = {e.id} resource = {e}/>
return <DashboardElement key = {e.id} resource = {e} client={props.client}/>
}): <div>{message}</div>}
</div>
);
Expand Down
19 changes: 16 additions & 3 deletions src/components/Dashboard/DashboardElement.jsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,26 @@
import React, { memo } from 'react';
import React, { memo, useState, useEffect } from 'react';
import { retrieveLaunchContext } from '../../util/util';
import { headers } from '../../util/data.js';

import useStyles from './styles';
const DashboardElement = (props) => {
const classes = useStyles();
const resource = props.resource;
const clientState = props.client.state;
const relaunch = () => {
const link = {
appContext: encodeURIComponent(`response=QuestionnaireResponse/${resource.id}`),
type: "smart",
url: headers.launchUrl.value
}
retrieveLaunchContext(link, clientState.tokenResponse.accessToken, clientState.tokenResponse.patient, clientState.serverUrl, 'r4').then((e) => {
window.open(e.url, "_blank");
})
}

return (
<div className = {classes.dashboardElement}>
<div>ID:{resource.id}</div>
<div className = {classes.dashboardElement} onClick={relaunch}>
<div>ID: {resource.id}</div>
<div>Questionnaire: {resource.questionnaire}</div>
</div>
);
Expand Down
3 changes: 2 additions & 1 deletion src/components/DisplayBox/DisplayBox.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import PropTypes from 'prop-types';
import axios from 'axios';
import SMARTBox from '../SMARTBox/SMARTBox';
import ReactMarkdown from 'react-markdown';
import { retrieveLaunchContext } from '../../util/util';
import './displayBox.css';

const propTypes = {
Expand Down Expand Up @@ -202,7 +203,7 @@ export default class DisplayBox extends Component{
let linkCopy = Object.assign({}, link);

if (link.type === 'smart' && (this.props.fhirAccessToken || this.props.ehrLaunch) && !this.state.smartLink) {
this.props.retrieveLaunchContext(
retrieveLaunchContext(
linkCopy, this.props.fhirAccessToken,
this.props.patientId, this.props.fhirServerUrl, this.props.fhirVersion
).then((result) => {
Expand Down
3 changes: 2 additions & 1 deletion src/components/RequestBox/RequestBox.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { getAge } from "../../util/fhir";
import _ from "lodash";
import "./request.css";
import { PrefetchTemplate } from "../../PrefetchTemplate";
import { retrieveLaunchContext } from "../../util/util";
import axios from 'axios';

export default class RequestBox extends Component {
Expand Down Expand Up @@ -317,7 +318,7 @@ export default class RequestBox extends Component {

let linkCopy = Object.assign({}, link);

return this.props.retrieveLaunchContext(
return retrieveLaunchContext(
linkCopy, this.props.fhirAccessToken,
this.state.patient.id, this.props.fhirServerUrl, this.props.fhirVersion
).then((result) => {
Expand Down
1 change: 0 additions & 1 deletion src/containers/PatientPortal.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ const PatientPortal = () => {

}, [token])


return (
<div className={classes.background}>

Expand Down
64 changes: 1 addition & 63 deletions src/containers/RequestBuilder.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import RequestBox from '../components/RequestBox/RequestBox';
import buildRequest from '../util/buildRequest.js';
import { types, headers, defaultValues } from '../util/data.js';
import { createJwt, login, setupKeys } from '../util/auth';
import axios from 'axios';

export default class RequestBuilder extends Component {
constructor(props) {
Expand Down Expand Up @@ -198,65 +197,6 @@ export default class RequestBuilder extends Component {
this.setState({ openPatient: false })
}

/**
* Retrieves a SMART launch context from an endpoint to append as a "launch" query parameter to a SMART app launch URL (see SMART docs for more about launch context).
* This applies mainly if a SMART app link on a card is to be launched. The link needs a "launch" query param with some opaque value from the SMART server entity.
* This function generates the launch context (for HSPC Sandboxes only) for a SMART application by pinging a specific endpoint on the FHIR base URL and returns
* a Promise to resolve the newly modified link.
* @param {*} link - The SMART app launch URL
* @param {*} accessToken - The access token provided to the CDS Hooks Sandbox by the FHIR server
* @param {*} patientId - The identifier of the patient in context
* @param {*} fhirBaseUrl - The base URL of the FHIR server in context
*/
retrieveLaunchContext(link, accessToken, patientId, fhirBaseUrl, fhirVersion) {
return new Promise((resolve, reject) => {
const headers = accessToken ?
{
"Accept": 'application/json',
"Authorization": `Bearer ${accessToken.access_token}`
}
:
{
"Accept": 'application/json'
};
const launchParameters = {
patient: patientId,
};

if (link.appContext) {
launchParameters.appContext = link.appContext;
}

// May change when the launch context creation endpoint becomes a standard endpoint for all EHR providers
axios({
method: 'post',
url: `${fhirBaseUrl}/_services/smart/Launch`,
headers,
data: {
launchUrl: link.url,
parameters: launchParameters,
},
}).then((result) => {
if (result.data && Object.prototype.hasOwnProperty.call(result.data, 'launch_id')) {
if (link.url.indexOf('?') < 0) {
link.url += '?';
} else {
link.url += '&';
}
link.url += `launch=${result.data.launch_id}`;
link.url += `&iss=${fhirBaseUrl}`;
return resolve(link);
}
console.error('FHIR server endpoint did not return a launch_id to launch the SMART app. See network calls to the Launch endpoint for more details');
link.error = true;
return reject(link);
}).catch((err) => {
console.error('Cannot grab launch context from the FHIR server endpoint to launch the SMART app. See network calls to the Launch endpoint for more details', err);
link.error = true;
return reject(link);
});
});
}

render() {
const header =
Expand Down Expand Up @@ -361,7 +301,6 @@ retrieveLaunchContext(link, accessToken, patientId, fhirBaseUrl, fhirVersion) {
fhirServerUrl={this.state.baseUrl}
fhirVersion={'r4'}
patientId={this.state.patient.id}
retrieveLaunchContext={this.retrieveLaunchContext}
launchUrl={this.state.launchUrl}
responseExpirationDays={this.state.responseExpirationDays}
ref={this.requestBox}
Expand Down Expand Up @@ -398,8 +337,7 @@ retrieveLaunchContext(link, accessToken, patientId, fhirBaseUrl, fhirVersion) {
fhirVersion={'r4'}
ehrUrl={this.state.ehrUrl}
access_token={this.state.token}
takeSuggestion={this.takeSuggestion}
retrieveLaunchContext={this.retrieveLaunchContext} />
takeSuggestion={this.takeSuggestion} />
</div>

</div>
Expand Down
65 changes: 65 additions & 0 deletions src/util/util.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import axios from 'axios';

/**
* Retrieves a SMART launch context from an endpoint to append as a "launch" query parameter to a SMART app launch URL (see SMART docs for more about launch context).
* This applies mainly if a SMART app link on a card is to be launched. The link needs a "launch" query param with some opaque value from the SMART server entity.
* This function generates the launch context (for HSPC Sandboxes only) for a SMART application by pinging a specific endpoint on the FHIR base URL and returns
* a Promise to resolve the newly modified link.
* @param {*} link - The SMART app launch URL
* @param {*} accessToken - The access token provided to the CDS Hooks Sandbox by the FHIR server
* @param {*} patientId - The identifier of the patient in context
* @param {*} fhirBaseUrl - The base URL of the FHIR server in context
*/
function retrieveLaunchContext(link, accessToken, patientId, fhirBaseUrl, fhirVersion) {
return new Promise((resolve, reject) => {
const headers = accessToken ?
{
"Accept": 'application/json',
"Authorization": `Bearer ${accessToken.access_token}`
}
:
{
"Accept": 'application/json'
};
const launchParameters = {
patient: patientId,
};

if (link.appContext) {
launchParameters.appContext = link.appContext;
}

// May change when the launch context creation endpoint becomes a standard endpoint for all EHR providers
axios({
method: 'post',
url: `${fhirBaseUrl}/_services/smart/Launch`,
headers,
data: {
launchUrl: link.url,
parameters: launchParameters,
},
}).then((result) => {
if (result.data && Object.prototype.hasOwnProperty.call(result.data, 'launch_id')) {
if (link.url.indexOf('?') < 0) {
link.url += '?';
} else {
link.url += '&';
}
link.url += `launch=${result.data.launch_id}`;
link.url += `&iss=${fhirBaseUrl}`;
return resolve(link);
}
console.error('FHIR server endpoint did not return a launch_id to launch the SMART app. See network calls to the Launch endpoint for more details');
link.error = true;
return reject(link);
}).catch((err) => {
console.error('Cannot grab launch context from the FHIR server endpoint to launch the SMART app. See network calls to the Launch endpoint for more details', err);
link.error = true;
return reject(link);
});
});
}

export {
retrieveLaunchContext
}

0 comments on commit 6b9df08

Please sign in to comment.