Skip to content

Commit

Permalink
new pages for admin user
Browse files Browse the repository at this point in the history
  • Loading branch information
ELiuHub committed Jul 27, 2022
1 parent 7ded05d commit 4bc181a
Show file tree
Hide file tree
Showing 13 changed files with 1,177 additions and 207 deletions.
840 changes: 829 additions & 11 deletions package-lock.json

Large diffs are not rendered by default.

6 changes: 5 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@
"private": true,
"dependencies": {
"@aws-amplify/ui-react": "^3.1.0",
"@material-ui/core": "^4.12.4",
"@emotion/react": "^11.9.3",
"@emotion/styled": "^11.9.3",
"@material-ui/icons": "^4.11.3",
"@mui/material": "^5.9.2",
"@testing-library/jest-dom": "^5.16.4",
"@testing-library/react": "^13.3.0",
"@testing-library/user-event": "^13.5.0",
Expand All @@ -13,6 +16,7 @@
"lforms": "^29.3.1",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-router-dom": "^6.3.0",
"react-scripts": "5.0.1",
"react-toastify": "^9.0.5",
"web-vitals": "^2.1.4"
Expand Down
15 changes: 0 additions & 15 deletions resourceId.txt

This file was deleted.

185 changes: 12 additions & 173 deletions src/App.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { useEffect, useState } from 'react';
import { FhirQ } from './form';
import { ToastContainer, toast, Zoom} from 'react-toastify';
import axios from 'axios';
import Navbar from './navbar';
import { Amplify, Auth, Signer} from 'aws-amplify';
import Navbar from './Components/navbar';
import Form from './Pages/form';
import Upload from './Pages/upload';
import Admin from './Pages/admin';
import { Routes, Route } from 'react-router-dom'
import { Amplify } from 'aws-amplify';
import { withAuthenticator } from '@aws-amplify/ui-react';

import '@aws-amplify/ui-react/styles.css';
Expand All @@ -13,176 +13,15 @@ import awsExports from './aws-exports';
Amplify.configure(awsExports);

function App() {
const [patientID, setPatientID] = useState('');

useEffect(() => {
renderForm();
}, []);

function notify(type, text) {
if (type === 'success') {
toast.success(text, {
position: "top-center",
autoClose: 3000,
transition: Zoom,
hideProgressBar: true,
closeOnClick: true,
pauseOnHover: true,
draggable: false,
progress: undefined,
});
} else {
toast.error(text, {
position: "top-center",
autoClose: 3000,
transition: Zoom,
hideProgressBar: true,
closeOnClick: true,
pauseOnHover: true,
draggable: false,
progress: undefined,
});
}
}

async function renderForm() {
let formDef = FhirQ;
window.LForms.Util.addFormToPage(formDef, 'formContainer');
}

async function loadResponse() {
let searchParameter = '?subject=Patient/' + patientID;
let signedURL = await signRequest('get', searchParameter);

await axios.get(signedURL).then((resp) => {
if (resp.data["entry"][1]["search"]["mode"] === "match") {
let fhirForm = FhirQ;
let lhcForm = window.LForms.Util.convertFHIRQuestionnaireToLForms(fhirForm, 'R4');
let formWithUserData = window.LForms.Util.mergeFHIRDataIntoLForms("QuestionnaireResponse", resp.data["entry"][1]["resource"], lhcForm, "R4");
window.LForms.Util.addFormToPage(formWithUserData, 'formContainer');
notify('success', 'Form loaded.');
} else {
notify('error', 'Error loading form.');
}
})
}

async function sendToHealthlake() {
let searchParameter = '?subject=Patient/' + patientID;
let signedURL = await signRequest('get', searchParameter);

await axios.get(signedURL).then((resp) => {
if (resp.data["entry"].length === 1) {
storeResponse();
} else if (resp.data["entry"][1]["search"]["mode"] === "match") {
updateResponse(resp.data["entry"][1]["resource"]["id"]);
}
})
}

async function updateResponse(resourceID) {
let signedURL = await signRequest('put', resourceID);

await axios({
method: 'put',
url: signedURL.url,
headers: signedURL.headers,
data: signedURL.data
}).then((response) => {
console.log(response);
notify('success','Form updated.');
});
}

async function storeResponse() {
let signedURL = await signRequest('post');

await axios({
method: 'post',
url: signedURL.url,
headers: signedURL.headers,
data: signedURL.data
}).then((response) => {
console.log(response);
if (response.status === 201) {
notify('success','Form submitted.');
renderForm();
} else {
notify('error', 'Error submitting form.')
}
});
}

async function signRequest(requestMethod, param) {
const credentials = {
access_key: (await Auth.currentCredentials()).accessKeyId,
secret_key: (await Auth.currentCredentials()).secretAccessKey,
session_token: (await Auth.currentCredentials()).sessionToken
};

let dataStore = 'https://healthlake.us-east-1.amazonaws.com/datastore/92641762d5c7ea1f301847e4b3633356/r4/';
let resourceType = 'QuestionnaireResponse';
let endpoint = dataStore + resourceType;

let fhirQR = window.LForms.Util.getFormFHIRData('QuestionnaireResponse', 'R4');
fhirQR.subject = {
reference: "Patient/" + patientID
}

const serviceInfo = {
service: 'healthlake',
region: 'us-east-1'
};

if (requestMethod === 'post') {
const request = {
method: 'POST',
url: endpoint,
data: JSON.stringify(fhirQR)
};

let signedRequest = Signer.sign(request, credentials, serviceInfo);
delete signedRequest.headers['host'];
return signedRequest;
} else if (requestMethod === 'put') {
let endpoint = dataStore + resourceType + '/' + param;
fhirQR.id = param;

const request = {
method: 'PUT',
url: endpoint,
data: JSON.stringify(fhirQR)
};

let signedRequest = Signer.sign(request, credentials, serviceInfo);
delete signedRequest.headers['host'];
signedRequest.headers['content-type'] = 'application/json';
return signedRequest;
} else {
let endpoint = dataStore + resourceType + param;
return Signer.signUrl(endpoint, credentials)
}
}

function numbersOnly(e) {
const re = /^[0-9\b]+$/;

if (e.target.value === '' || re.test(e.target.value)) {
setPatientID(e.target.value);
}
}


return (
<>
<Navbar />
<form style={{ marginLeft: '1em', marginTop: '1.5em'}}>
<label>Patient ID:</label>
<input style={{ margin: '0.5em', border: '1px solid'}} value={patientID} minLength={10} maxLength={10} required onChange={numbersOnly} />
</form>
<div id="formContainer" style={{ padding: '1em' }}></div>
<button onClick={sendToHealthlake} style={{ float: 'right', marginRight: '1em' }}>Submit</button>
<button onClick={loadResponse} style={{ float: 'left', marginLeft: '1em' }}>Load</button>
<ToastContainer />
<Routes>
<Route path="/" element={<Form />} />
<Route path="/upload" element={<Upload />} />
<Route path='/admin' element={<Admin />} />
</Routes>
</>
);
}
Expand Down
12 changes: 7 additions & 5 deletions src/navbar.js → src/Components/navbar.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import { AppBar, Toolbar, Button, Typography } from "@material-ui/core";
import { AppBar, Toolbar, Button, Typography } from "@mui/material";
import Sidebar from './sidebar';
import { Auth } from 'aws-amplify';
import { useEffect } from "react";
import { useEffect, useState } from "react";

export default function Navbar() {
const [admin, setAdmin] = useState(true);

useEffect(() => {
welcomeUser();
})
Expand All @@ -21,10 +24,9 @@ export default function Navbar() {
return (
<AppBar position="static">
<Toolbar>
{ admin ? <Sidebar /> : null}
<Typography id="headText" style={{ flex: 1 }}></Typography>
<div>
<Button onClick={signOut} variant="outlined" color="inherit">Sign out</Button>
</div>
<Button onClick={signOut} variant="outlined" color="inherit">Sign out</Button>
</Toolbar>
</AppBar>
)
Expand Down
32 changes: 32 additions & 0 deletions src/Components/sidebar.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { useState } from 'react';
import { Drawer, List, ListItemText, Box, IconButton, ListItem } from '@mui/material'
import { Menu } from '@material-ui/icons';
import { useNavigate } from "react-router-dom";

export default function Sidebar() {
const [isOpen, setIsOpen] = useState(false);
let navigate = useNavigate();

return (
<>
<IconButton color="inherit" sx={{ mr: 2 }} onClick={() => setIsOpen(true)}>
<Menu />
</IconButton>
<Drawer open={isOpen} anchor="left" onClose={() => setIsOpen(false)}>
<Box width='15rem' role='presentation' onClick={() => setIsOpen(false)}>
<List disablePadding>
<ListItem button onClick={() => navigate('/upload')}>
<ListItemText primary="Upload a form" />
</ListItem>
<ListItem button onClick={() => navigate('/')}>
<ListItemText primary="Fill out a form" />
</ListItem>
<ListItem button onClick={() => navigate('/admin')}>
<ListItemText primary="Add an admin user" />
</ListItem>
</List>
</Box>
</Drawer>
</>
)
}
27 changes: 27 additions & 0 deletions src/Helpers/notification.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { toast, Zoom} from 'react-toastify';

export function Notify(type, text) {
if (type === 'success') {
toast.success(text, {
position: "top-center",
autoClose: 3000,
transition: Zoom,
hideProgressBar: true,
closeOnClick: true,
pauseOnHover: true,
draggable: false,
progress: undefined,
});
} else {
toast.error(text, {
position: "top-center",
autoClose: 3000,
transition: Zoom,
hideProgressBar: true,
closeOnClick: true,
pauseOnHover: true,
draggable: false,
progress: undefined,
});
}
}
63 changes: 63 additions & 0 deletions src/Pages/admin.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { Box, TextField, Stack, FormControlLabel, Checkbox, Button } from '@mui/material'
import { useState } from 'react'

function Admin() {
const [text, setText] = useState('');
const [errorText, setErrorText] = useState('');
const [checked, setChecked] = useState(false);

function isValidEmail(email) {
let re = /\S+@\S+\.\S+/;
return !(re.test(email));
}

function handleSubmit(e) {
e.preventDefault();
if (text === '') {
setErrorText("Please enter email");
} else if(isValidEmail(text)) {
setErrorText('Please enter a valid email')
} else {
setErrorText('');
if (checked) {
console.log('done')
}
}
};

const checkChanged = () => {
setChecked(!checked);
};

return (
<Box
component='form'
onSubmit={handleSubmit}
sx={{
display: 'flex',
marginTop: '3em',
justifyContent: 'center'
}}>
<Stack spacing={2}>
<h2>Authorize administrative privilages for another user</h2>
<TextField
value={text}
label="Email"
onChange={(e) => {setText(e.target.value)}}
error={isValidEmail(text)}
helperText={errorText}
variant="standard"
/>
<FormControlLabel
control={<Checkbox checked={checked} onChange={checkChanged}/>}
label="I want this user to be an administrator"
/>
<Box display="flex" justifyContent='flex-end'>
<Button type='submit' style={{width: 'fit-content'}}>Submit</Button>
</Box>
</Stack>
</Box>
)
}

export default Admin;
Loading

0 comments on commit 4bc181a

Please sign in to comment.