From e472cae35cda3cf82a2d65531d38e74530bc5c92 Mon Sep 17 00:00:00 2001 From: chrisdeyloff Date: Tue, 26 Feb 2019 16:39:33 -0500 Subject: [PATCH 1/2] update to instructions.txt with suggested changes --- dot-net/WhatWouldYouChange/INSTRUCTIONS.txt | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/dot-net/WhatWouldYouChange/INSTRUCTIONS.txt b/dot-net/WhatWouldYouChange/INSTRUCTIONS.txt index be2263d6..6099d16d 100644 --- a/dot-net/WhatWouldYouChange/INSTRUCTIONS.txt +++ b/dot-net/WhatWouldYouChange/INSTRUCTIONS.txt @@ -5,4 +5,14 @@ Suggested Changes: - \ No newline at end of file + * Program.cs + * Missing dot in file name + * ExampleClass.cs + * Check if file exists before attempting to open/read. + * Use using statement for `fs` and `streamReader` to ensure resources are disposed and the file is closed. + * For `File.Open`, use `FileShare.Read` to allow multiple opening of the file by the current process or other processes. + * In catch statement, use either the `@` symbol (verbatim string) or StringBuilder. Preferably use verbatim for ease of development and readability. Also, verbatim would be more performant than standard string concatenation. However, if remaining with string concatenation, use `+=` for ease of development. + * When setting `exampleText`, use `this.` to indicate it's scope as a class property. + * Create an async version of `ExampleMethod` to read a potentially large file asynchronously which would improve performance. Use `ReadToEndAsync` along with async/await and use TPL in Program.cs. + * Place the `catch` text into either a const variable, resource file or config file to centralize the string and prevent duplicate code. + * If `exampleText` is not going to be utilized elsewhere, return the text result from `ExampleMethod` instead because `exampleText` is unnecessarily using resources. From abd0b4f734323fbf9bfcede9ed24e03ad6b5f659 Mon Sep 17 00:00:00 2001 From: chrisdeyloff Date: Tue, 26 Feb 2019 20:28:26 -0500 Subject: [PATCH 2/2] unit test interview updates. installed xUnit to replace MSTest. --- .gitignore | 4 +- .../Services/LessonServiceUnitTests.cs | 21 +- .../WriteUnitTest.UnitTests.csproj | 50 +- .../WriteUnitTest.UnitTests/packages.config | 12 + .../WriteUnitTest/Entities/Lesson.cs | 1 + .../WriteUnitTest/INSTRUCTIONS.txt | 12 +- .../Repositories/LessonRepository.cs | 2 + .../Repositories/ModuleRepository.cs | 21 +- .../WriteUnitTest/Services/LessonService.cs | 16 +- javascript/SMART-on-FHIR/README.md | 2 + javascript/SMART-on-FHIR/Test.md | 27 - .../chrisdeyloff-smart-fhir-api/README.md | 16 + .../chrisdeyloff-smart-fhir-api/app.js | 42 + .../chrisdeyloff-smart-fhir-api/bin/www | 90 + .../package-lock.json | 2924 +++ .../chrisdeyloff-smart-fhir-api/package.json | 18 + .../routes/patient.js | 37 + .../chrisdeyloff-smart-fhir/.gitignore | 23 + .../chrisdeyloff-smart-fhir/README.md | 19 + .../chrisdeyloff-smart-fhir/package-lock.json | 16163 ++++++++++++++++ .../chrisdeyloff-smart-fhir/package.json | 29 + .../public/favicon.ico | Bin 0 -> 3870 bytes .../chrisdeyloff-smart-fhir/public/index.html | 41 + .../public/manifest.json | 15 + .../chrisdeyloff-smart-fhir/src/API.js | 43 + .../chrisdeyloff-smart-fhir/src/App.css | 22 + .../chrisdeyloff-smart-fhir/src/App.js | 81 + .../chrisdeyloff-smart-fhir/src/App.test.js | 9 + .../chrisdeyloff-smart-fhir/src/Error.js | 11 + .../src/PatientInfo.css | 15 + .../src/PatientInfo.js | 84 + .../chrisdeyloff-smart-fhir/src/Spinner.css | 12 + .../chrisdeyloff-smart-fhir/src/Spinner.js | 13 + .../src/images/rings.svg | 42 + .../chrisdeyloff-smart-fhir/src/index.css | 14 + .../chrisdeyloff-smart-fhir/src/index.js | 12 + .../chrisdeyloff-smart-fhir/src/logo.svg | 7 + .../src/serviceWorker.js | 135 + 38 files changed, 20017 insertions(+), 68 deletions(-) create mode 100644 dot-net/UnitTesting/WriteUnitTest.UnitTests/packages.config create mode 100644 javascript/SMART-on-FHIR/README.md delete mode 100644 javascript/SMART-on-FHIR/Test.md create mode 100644 javascript/SMART-on-FHIR/chrisdeyloff-smart-fhir-api/README.md create mode 100644 javascript/SMART-on-FHIR/chrisdeyloff-smart-fhir-api/app.js create mode 100644 javascript/SMART-on-FHIR/chrisdeyloff-smart-fhir-api/bin/www create mode 100644 javascript/SMART-on-FHIR/chrisdeyloff-smart-fhir-api/package-lock.json create mode 100644 javascript/SMART-on-FHIR/chrisdeyloff-smart-fhir-api/package.json create mode 100644 javascript/SMART-on-FHIR/chrisdeyloff-smart-fhir-api/routes/patient.js create mode 100644 javascript/SMART-on-FHIR/chrisdeyloff-smart-fhir/.gitignore create mode 100644 javascript/SMART-on-FHIR/chrisdeyloff-smart-fhir/README.md create mode 100644 javascript/SMART-on-FHIR/chrisdeyloff-smart-fhir/package-lock.json create mode 100644 javascript/SMART-on-FHIR/chrisdeyloff-smart-fhir/package.json create mode 100644 javascript/SMART-on-FHIR/chrisdeyloff-smart-fhir/public/favicon.ico create mode 100644 javascript/SMART-on-FHIR/chrisdeyloff-smart-fhir/public/index.html create mode 100644 javascript/SMART-on-FHIR/chrisdeyloff-smart-fhir/public/manifest.json create mode 100644 javascript/SMART-on-FHIR/chrisdeyloff-smart-fhir/src/API.js create mode 100644 javascript/SMART-on-FHIR/chrisdeyloff-smart-fhir/src/App.css create mode 100644 javascript/SMART-on-FHIR/chrisdeyloff-smart-fhir/src/App.js create mode 100644 javascript/SMART-on-FHIR/chrisdeyloff-smart-fhir/src/App.test.js create mode 100644 javascript/SMART-on-FHIR/chrisdeyloff-smart-fhir/src/Error.js create mode 100644 javascript/SMART-on-FHIR/chrisdeyloff-smart-fhir/src/PatientInfo.css create mode 100644 javascript/SMART-on-FHIR/chrisdeyloff-smart-fhir/src/PatientInfo.js create mode 100644 javascript/SMART-on-FHIR/chrisdeyloff-smart-fhir/src/Spinner.css create mode 100644 javascript/SMART-on-FHIR/chrisdeyloff-smart-fhir/src/Spinner.js create mode 100644 javascript/SMART-on-FHIR/chrisdeyloff-smart-fhir/src/images/rings.svg create mode 100644 javascript/SMART-on-FHIR/chrisdeyloff-smart-fhir/src/index.css create mode 100644 javascript/SMART-on-FHIR/chrisdeyloff-smart-fhir/src/index.js create mode 100644 javascript/SMART-on-FHIR/chrisdeyloff-smart-fhir/src/logo.svg create mode 100644 javascript/SMART-on-FHIR/chrisdeyloff-smart-fhir/src/serviceWorker.js diff --git a/.gitignore b/.gitignore index 6c00c877..ead9ca31 100644 --- a/.gitignore +++ b/.gitignore @@ -6,4 +6,6 @@ build/ # Package Files # *.jar -*.log \ No newline at end of file +*.log +/dot-net/UnitTesting/.vs/WriteUnitTest/v15/Server/sqlite3 +/dot-net/UnitTesting/WriteUnitTest/obj/Debug diff --git a/dot-net/UnitTesting/WriteUnitTest.UnitTests/Services/LessonServiceUnitTests.cs b/dot-net/UnitTesting/WriteUnitTest.UnitTests/Services/LessonServiceUnitTests.cs index c016f412..914f8364 100644 --- a/dot-net/UnitTesting/WriteUnitTest.UnitTests/Services/LessonServiceUnitTests.cs +++ b/dot-net/UnitTesting/WriteUnitTest.UnitTests/Services/LessonServiceUnitTests.cs @@ -1,13 +1,26 @@ -using Microsoft.VisualStudio.TestTools.UnitTesting; +using Xunit; +using WriteUnitTest.Services; +using WriteUnitTest.Entities; namespace WriteUnitTest.UnitTests.Services { - [TestClass] public class LessonServiceUnitTests { - [TestMethod] - public void UpdateLessonGrade_Test() + private LessonService service = null; + + public LessonServiceUnitTests() { + this.service = new LessonService(); + } + + [Theory] + [InlineData(12, 80.0d, true)] + [InlineData(46, 65.0d, false)] + public void UpdateLessonGrade_Validate_IsPassed_Test(int lessonId, double grade, bool expected) + { + var lesson = this.service.UpdateLessonGrade(lessonId, grade); + + Assert.Equal(expected, lesson.IsPassed); } } } \ No newline at end of file diff --git a/dot-net/UnitTesting/WriteUnitTest.UnitTests/WriteUnitTest.UnitTests.csproj b/dot-net/UnitTesting/WriteUnitTest.UnitTests/WriteUnitTest.UnitTests.csproj index f3d83f84..b2cc638c 100644 --- a/dot-net/UnitTesting/WriteUnitTest.UnitTests/WriteUnitTest.UnitTests.csproj +++ b/dot-net/UnitTesting/WriteUnitTest.UnitTests/WriteUnitTest.UnitTests.csproj @@ -1,5 +1,8 @@  + + + Debug AnyCPU @@ -16,6 +19,8 @@ $(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages False UnitTest + + true @@ -35,7 +40,22 @@ 4 + + ..\..\..\..\..\..\Program Files (x86)\Microsoft Visual Studio\2017\Community\Common7\IDE\PublicAssemblies\Microsoft.VisualStudio.QualityTools.UnitTestFramework.dll + + + ..\packages\xunit.abstractions.2.0.3\lib\net35\xunit.abstractions.dll + + + ..\packages\xunit.assert.2.4.1\lib\netstandard1.1\xunit.assert.dll + + + ..\packages\xunit.extensibility.core.2.4.1\lib\net452\xunit.core.dll + + + ..\packages\xunit.extensibility.execution.2.4.1\lib\net452\xunit.execution.desktop.dll + @@ -43,18 +63,24 @@ - - - - False - - - + + + + {00a40a05-8314-4f25-a444-46ddeac3497e} + WriteUnitTest + + + + + + + + @@ -75,6 +101,16 @@ + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + + + + + + + React App + + + +
+ + + diff --git a/javascript/SMART-on-FHIR/chrisdeyloff-smart-fhir/public/manifest.json b/javascript/SMART-on-FHIR/chrisdeyloff-smart-fhir/public/manifest.json new file mode 100644 index 00000000..1f2f141f --- /dev/null +++ b/javascript/SMART-on-FHIR/chrisdeyloff-smart-fhir/public/manifest.json @@ -0,0 +1,15 @@ +{ + "short_name": "React App", + "name": "Create React App Sample", + "icons": [ + { + "src": "favicon.ico", + "sizes": "64x64 32x32 24x24 16x16", + "type": "image/x-icon" + } + ], + "start_url": ".", + "display": "standalone", + "theme_color": "#000000", + "background_color": "#ffffff" +} diff --git a/javascript/SMART-on-FHIR/chrisdeyloff-smart-fhir/src/API.js b/javascript/SMART-on-FHIR/chrisdeyloff-smart-fhir/src/API.js new file mode 100644 index 00000000..4d46888a --- /dev/null +++ b/javascript/SMART-on-FHIR/chrisdeyloff-smart-fhir/src/API.js @@ -0,0 +1,43 @@ +const axios = require("axios"); +const API_URL = 'http://localhost:3000/Patient/'; + +// Get Patient Info +export async function getPatientInfo(patientId) { + try { + const url = `${API_URL}${patientId}`; + const response = await axios.get(url); + const data = response.data; + return data; + } catch (error) { + console.log(error); + } + + // return rp({ + // ...API_OPTIONS, + // url: `${API_ADDRESS}/Patient/${patientID}` + // }) + // .catch((rpError) => { + // // Rethrow an interpreted error + // throw interpretError(rpError) + // }) +} + +// Get Patient Conditions +export async function getPatientConditions(patientId) { + try { + const url = `${API_URL}condition/${patientId}`; + const response = await axios.get(url); + const data = response.data; + return data; + } catch (error) { + console.log(error); + } +// return rp({ +// ...API_OPTIONS, +// url: `${API_ADDRESS}/Condition?patient=${patientID}` +// }) +// .catch((rpError) => { +// // Rethrow an interpreted error +// throw interpretError(rpError) +// }) +} \ No newline at end of file diff --git a/javascript/SMART-on-FHIR/chrisdeyloff-smart-fhir/src/App.css b/javascript/SMART-on-FHIR/chrisdeyloff-smart-fhir/src/App.css new file mode 100644 index 00000000..835ff468 --- /dev/null +++ b/javascript/SMART-on-FHIR/chrisdeyloff-smart-fhir/src/App.css @@ -0,0 +1,22 @@ +.App { + text-align: center; +} + +.app-header { + background-color: #09255e; + color: white; + line-height: 5vh; + min-height: 5vh; + width: 100%; + font-size: x-large; +} + +section { + margin-top: 2em; + text-align: center; +} + +.input-label { + text-align: left; + margin-right: 0.4em; +} \ No newline at end of file diff --git a/javascript/SMART-on-FHIR/chrisdeyloff-smart-fhir/src/App.js b/javascript/SMART-on-FHIR/chrisdeyloff-smart-fhir/src/App.js new file mode 100644 index 00000000..7fc82002 --- /dev/null +++ b/javascript/SMART-on-FHIR/chrisdeyloff-smart-fhir/src/App.js @@ -0,0 +1,81 @@ +import React, { Component } from 'react'; + +import './App.css'; +import { getPatientInfo } from './API'; + +import PatientInfo from './PatientInfo'; +import Spinner from './Spinner'; +import Error from './Error'; + +class App extends Component { + constructor(props) { + super(props); + this.state = { + error: null, + isSearching: false, + patientInfo: null, + patientId: '' + }; + } + + componentDidMount() { + if (window.location.hash) { + this.searchPatient(window.location.hash.substr(1)); // strip initial # char + } + } + + onSubmit = (event) => { + event.preventDefault(); + this.searchPatient(this.state.patientId); + } + + searchPatient(patientId) { + (async () => { + patientId = patientId.replace(/\D/g, ''); // remove non-numeric chars + if (patientId.length !== 7) { + this.setState({ error: 'Please enter a valid numeric patient id (7 digits).' }); + return; + } + + window.location.hash = patientId; + this.setState({isSearching: true, error: null, patientId, patientInfo: null}); + try { + const patientInfo = await getPatientInfo(patientId) + this.setState({patientInfo, isSearching: false}); + } + catch (error) { + this.setState({error, isSearching: false}); + } + })(); + } + + updatePatientId = (event) => { + this.setState({ + patientId: event.target.value + }); + } + + render() { + const {error, isSearching, patientId, patientInfo} = this.state; + + return ( +
+
+ Patient Search +
+
+
+ + + + {isSearching && Searching for patient} + {patientInfo && } + {error && {error}} + +
+
+ ); + } +} + +export default App; \ No newline at end of file diff --git a/javascript/SMART-on-FHIR/chrisdeyloff-smart-fhir/src/App.test.js b/javascript/SMART-on-FHIR/chrisdeyloff-smart-fhir/src/App.test.js new file mode 100644 index 00000000..a754b201 --- /dev/null +++ b/javascript/SMART-on-FHIR/chrisdeyloff-smart-fhir/src/App.test.js @@ -0,0 +1,9 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; +import App from './App'; + +it('renders without crashing', () => { + const div = document.createElement('div'); + ReactDOM.render(, div); + ReactDOM.unmountComponentAtNode(div); +}); diff --git a/javascript/SMART-on-FHIR/chrisdeyloff-smart-fhir/src/Error.js b/javascript/SMART-on-FHIR/chrisdeyloff-smart-fhir/src/Error.js new file mode 100644 index 00000000..3bddae95 --- /dev/null +++ b/javascript/SMART-on-FHIR/chrisdeyloff-smart-fhir/src/Error.js @@ -0,0 +1,11 @@ + +import React from 'react'; + +export default function Error({ children }) { + return ( +
+
An error has occurred:
+
{children}
+
+ ); +} \ No newline at end of file diff --git a/javascript/SMART-on-FHIR/chrisdeyloff-smart-fhir/src/PatientInfo.css b/javascript/SMART-on-FHIR/chrisdeyloff-smart-fhir/src/PatientInfo.css new file mode 100644 index 00000000..b9096ecf --- /dev/null +++ b/javascript/SMART-on-FHIR/chrisdeyloff-smart-fhir/src/PatientInfo.css @@ -0,0 +1,15 @@ +.patient-info { + border-radius: 5px; + border: thin solid lightgray; + margin: 2em 0; + padding: 0.5em; + } + +.patient-info-table { + margin-top: 0.5em; +} + +.patient-detail-info { + font-size: larger; + font-weight: bold; +} \ No newline at end of file diff --git a/javascript/SMART-on-FHIR/chrisdeyloff-smart-fhir/src/PatientInfo.js b/javascript/SMART-on-FHIR/chrisdeyloff-smart-fhir/src/PatientInfo.js new file mode 100644 index 00000000..22faf0ca --- /dev/null +++ b/javascript/SMART-on-FHIR/chrisdeyloff-smart-fhir/src/PatientInfo.js @@ -0,0 +1,84 @@ +import React, { Component } from 'react'; +import ReactTable from 'react-table'; + +import './PatientInfo.css'; +import 'react-table/react-table.css'; + +import { getPatientConditions } from './API'; +// import { capitalize } from './utils'; +import Error from './Error'; +import Spinner from './Spinner'; +import * as moment from 'moment'; +import * as capitalize from 'capitalize'; + +const COLUMNS = [ + { Header: 'Condition', accessor: (c) => c.resource.code.text, id: 'condition', Cell: props =>
{props.value}
}, + { Header: 'Date Recorded', accessor: (c) => c.resource.dateRecorded, id: 'dateRecorded', Cell: props => moment(props.value).format('LL') }, + { Header: 'PubMed', accessor: (c) => , id: 'pubMed'} +]; +const TABLE_PROPS = { + columns: COLUMNS, + className: 'patient-info-table', + defaultSorted: [ + {id: 'dateRecorded', desc: true} + ], + noDataText: 'No patient conditions found.', + defaultPageSize: 10 +} + +function PubMedLink({ condition }) { + const conditionName = condition.resource.code.text; + const url = `https://www.ncbi.nlm.nih.gov/pubmed/?term=${encodeURIComponent(conditionName)}`; + return ( + + PubMed + + ); +} + +function isConditionActive(condition) { + return condition.resource.clinicalStatus === 'active'; +} + +class PatientInfo extends Component { + constructor(props) { + super(props); + this.state = {isSearching: true, conditions: null}; + } + + componentDidMount() { + (async () => { + try { + const conditions = await getPatientConditions(this.props.patient.id); + const activeConditions = conditions.entry + ? conditions.entry.filter(isConditionActive) + : []; + this.setState({conditions: activeConditions, isSearching: false}) + } + catch (error) { + this.setState({error, isSearching: false}); + } + })(); + } + + render() { + const { patient } = this.props; + const { error, conditions, isSearching } = this.state; + return ( +
+
+
{capitalize.words(patient.name[0].text)} ({patient.id})
+
Birth Date: {moment(patient.birthDate).format('LL')}
+
Gender: {capitalize.words(patient.gender)}
+
+ {isSearching && Getting patient conditions} + {error && {error}} + {conditions && ( + + )} +
+ ) + } +} + +export default PatientInfo; \ No newline at end of file diff --git a/javascript/SMART-on-FHIR/chrisdeyloff-smart-fhir/src/Spinner.css b/javascript/SMART-on-FHIR/chrisdeyloff-smart-fhir/src/Spinner.css new file mode 100644 index 00000000..2493c084 --- /dev/null +++ b/javascript/SMART-on-FHIR/chrisdeyloff-smart-fhir/src/Spinner.css @@ -0,0 +1,12 @@ +/* .Spinner { + line-height: 1.5em; + margin: 1em 0; + } */ + + .Spinner svg { + fill: darkblue; + margin-right: 0.25em; + vertical-align: middle; + stroke: darkblue; + } + \ No newline at end of file diff --git a/javascript/SMART-on-FHIR/chrisdeyloff-smart-fhir/src/Spinner.js b/javascript/SMART-on-FHIR/chrisdeyloff-smart-fhir/src/Spinner.js new file mode 100644 index 00000000..a5bf5799 --- /dev/null +++ b/javascript/SMART-on-FHIR/chrisdeyloff-smart-fhir/src/Spinner.js @@ -0,0 +1,13 @@ +import React from 'react'; + +import './Spinner.css'; +import { ReactComponent as Rings } from './images/rings.svg'; + +export default function Spinner({ children }) { + return ( +
+ + {children || 'Please wait'}... +
+ ); +} \ No newline at end of file diff --git a/javascript/SMART-on-FHIR/chrisdeyloff-smart-fhir/src/images/rings.svg b/javascript/SMART-on-FHIR/chrisdeyloff-smart-fhir/src/images/rings.svg new file mode 100644 index 00000000..ad9cb74d --- /dev/null +++ b/javascript/SMART-on-FHIR/chrisdeyloff-smart-fhir/src/images/rings.svg @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/javascript/SMART-on-FHIR/chrisdeyloff-smart-fhir/src/index.css b/javascript/SMART-on-FHIR/chrisdeyloff-smart-fhir/src/index.css new file mode 100644 index 00000000..cee5f348 --- /dev/null +++ b/javascript/SMART-on-FHIR/chrisdeyloff-smart-fhir/src/index.css @@ -0,0 +1,14 @@ +body { + margin: 0; + padding: 0; + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", + "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", + sans-serif; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +code { + font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New", + monospace; +} diff --git a/javascript/SMART-on-FHIR/chrisdeyloff-smart-fhir/src/index.js b/javascript/SMART-on-FHIR/chrisdeyloff-smart-fhir/src/index.js new file mode 100644 index 00000000..0c5e75da --- /dev/null +++ b/javascript/SMART-on-FHIR/chrisdeyloff-smart-fhir/src/index.js @@ -0,0 +1,12 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; +import './index.css'; +import App from './App'; +import * as serviceWorker from './serviceWorker'; + +ReactDOM.render(, document.getElementById('root')); + +// If you want your app to work offline and load faster, you can change +// unregister() to register() below. Note this comes with some pitfalls. +// Learn more about service workers: http://bit.ly/CRA-PWA +serviceWorker.unregister(); diff --git a/javascript/SMART-on-FHIR/chrisdeyloff-smart-fhir/src/logo.svg b/javascript/SMART-on-FHIR/chrisdeyloff-smart-fhir/src/logo.svg new file mode 100644 index 00000000..6b60c104 --- /dev/null +++ b/javascript/SMART-on-FHIR/chrisdeyloff-smart-fhir/src/logo.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/javascript/SMART-on-FHIR/chrisdeyloff-smart-fhir/src/serviceWorker.js b/javascript/SMART-on-FHIR/chrisdeyloff-smart-fhir/src/serviceWorker.js new file mode 100644 index 00000000..2283ff9c --- /dev/null +++ b/javascript/SMART-on-FHIR/chrisdeyloff-smart-fhir/src/serviceWorker.js @@ -0,0 +1,135 @@ +// This optional code is used to register a service worker. +// register() is not called by default. + +// This lets the app load faster on subsequent visits in production, and gives +// it offline capabilities. However, it also means that developers (and users) +// will only see deployed updates on subsequent visits to a page, after all the +// existing tabs open on the page have been closed, since previously cached +// resources are updated in the background. + +// To learn more about the benefits of this model and instructions on how to +// opt-in, read http://bit.ly/CRA-PWA + +const isLocalhost = Boolean( + window.location.hostname === 'localhost' || + // [::1] is the IPv6 localhost address. + window.location.hostname === '[::1]' || + // 127.0.0.1/8 is considered localhost for IPv4. + window.location.hostname.match( + /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/ + ) +); + +export function register(config) { + if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) { + // The URL constructor is available in all browsers that support SW. + const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href); + if (publicUrl.origin !== window.location.origin) { + // Our service worker won't work if PUBLIC_URL is on a different origin + // from what our page is served on. This might happen if a CDN is used to + // serve assets; see https://github.com/facebook/create-react-app/issues/2374 + return; + } + + window.addEventListener('load', () => { + const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`; + + if (isLocalhost) { + // This is running on localhost. Let's check if a service worker still exists or not. + checkValidServiceWorker(swUrl, config); + + // Add some additional logging to localhost, pointing developers to the + // service worker/PWA documentation. + navigator.serviceWorker.ready.then(() => { + console.log( + 'This web app is being served cache-first by a service ' + + 'worker. To learn more, visit http://bit.ly/CRA-PWA' + ); + }); + } else { + // Is not localhost. Just register service worker + registerValidSW(swUrl, config); + } + }); + } +} + +function registerValidSW(swUrl, config) { + navigator.serviceWorker + .register(swUrl) + .then(registration => { + registration.onupdatefound = () => { + const installingWorker = registration.installing; + if (installingWorker == null) { + return; + } + installingWorker.onstatechange = () => { + if (installingWorker.state === 'installed') { + if (navigator.serviceWorker.controller) { + // At this point, the updated precached content has been fetched, + // but the previous service worker will still serve the older + // content until all client tabs are closed. + console.log( + 'New content is available and will be used when all ' + + 'tabs for this page are closed. See http://bit.ly/CRA-PWA.' + ); + + // Execute callback + if (config && config.onUpdate) { + config.onUpdate(registration); + } + } else { + // At this point, everything has been precached. + // It's the perfect time to display a + // "Content is cached for offline use." message. + console.log('Content is cached for offline use.'); + + // Execute callback + if (config && config.onSuccess) { + config.onSuccess(registration); + } + } + } + }; + }; + }) + .catch(error => { + console.error('Error during service worker registration:', error); + }); +} + +function checkValidServiceWorker(swUrl, config) { + // Check if the service worker can be found. If it can't reload the page. + fetch(swUrl) + .then(response => { + // Ensure service worker exists, and that we really are getting a JS file. + const contentType = response.headers.get('content-type'); + if ( + response.status === 404 || + (contentType != null && contentType.indexOf('javascript') === -1) + ) { + // No service worker found. Probably a different app. Reload the page. + navigator.serviceWorker.ready.then(registration => { + registration.unregister().then(() => { + window.location.reload(); + }); + }); + } else { + // Service worker found. Proceed as normal. + registerValidSW(swUrl, config); + } + }) + .catch(() => { + console.log( + 'No internet connection found. App is running in offline mode.' + ); + }); +} + +export function unregister() { + if ('serviceWorker' in navigator) { + navigator.serviceWorker.ready.then(registration => { + registration.unregister(); + }); + } +}