diff --git a/.appversion b/.appversion new file mode 100644 index 00000000..afaf360d --- /dev/null +++ b/.appversion @@ -0,0 +1 @@ +1.0.0 \ No newline at end of file diff --git a/.eslintrc.js b/.eslintrc.js index cf870e58..df071e0b 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -24,6 +24,7 @@ module.exports = { plugins: ['react'], rules: { 'no-plusplus': ['error', { allowForLoopAfterthoughts: true }], + 'import/no-extraneous-dependencies': ['error', {'devDependencies': ['**/*.test.js', '**/*.test.jsx','**/*.spec.js', '**/*.spec.jsx']}], 'react/jsx-props-no-spreading': 'off', 'react/jsx-filename-extension': [1, { extensions: ['.js', '.jsx'] }], 'import/no-extraneous-dependencies': [ diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1ba67e96..e31bd051 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -7,23 +7,73 @@ on: jobs: build: runs-on: ubuntu-latest + env: + HELM_CHART_PATH: package/helm/ steps: - uses: actions/checkout@v1 - name: Set env - run: echo "RELEASE_VERSION=$(echo $GITHUB_SHA | head -c7)" >> $GITHUB_ENV + run: | + APP_VERSION=$(cat .appversion) + echo "ARTIFACT_VERSION=$(echo $APP_VERSION-${{github.run_number}})" >> $GITHUB_ENV - name: NCG Docker Registry env: DOCKER_REGISTRY_URL: docker.io - NCG_PASSWORD: ${{ secrets.DOCKER_NCG_PASSWORD }} - NCG_USERNAME: ${{ secrets.DOCKER_NCG_USERNAME }} + NCG_PASSWORD: ${{ secrets.DOCKER_PASSWORD }} + NCG_USERNAME: ${{ secrets.DOCKER_USERNAME }} run: docker login -u $NCG_USERNAME -p $NCG_PASSWORD $DOCKER_REGISTRY_URL - name: Build docker image for NCG env: CONTAINER_REPO_NAME: hiu-ui - NCG_USERNAME: ${{ secrets.DOCKER_NCG_USERNAME }} - run: docker build --build-arg BACKEND_BASE_URL=https://ncg-dev.projecteka.in/ --build-arg BASE_NAME=/hiu --build-arg BACKEND_API_PATH=hiu-api --build-arg DICOM_SERVER_PATH=/dicom-web --build-arg VIEWER_PAGE=/viewer/ --build-arg TITLE=NCG -t $NCG_USERNAME/$CONTAINER_REPO_NAME:$RELEASE_VERSION . + NCG_USERNAME: ${{ secrets.DOCKER_USERNAME }} + run: docker build -f package/docker/Dockerfile -t $NCG_USERNAME/$CONTAINER_REPO_NAME:$ARTIFACT_VERSION . - name: Push Docker image to NCG Registry env: CONTAINER_REPO_NAME: hiu-ui - NCG_USERNAME: ${{ secrets.DOCKER_NCG_USERNAME }} - run: docker push $NCG_USERNAME/$CONTAINER_REPO_NAME:$RELEASE_VERSION \ No newline at end of file + NCG_USERNAME: ${{ secrets.DOCKER_USERNAME }} + run: docker push $NCG_USERNAME/$CONTAINER_REPO_NAME:$ARTIFACT_VERSION + - name: Tag Docker Container with latest tag + env: + CONTAINER_REPO_NAME: hiu-ui + DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }} + run: docker tag $DOCKER_USERNAME/$CONTAINER_REPO_NAME:$ARTIFACT_VERSION $DOCKER_USERNAME/$CONTAINER_REPO_NAME:latest + - name: Push Latest Docker Container to Registry + env: + CONTAINER_REPO_NAME: hiu-ui + DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }} + run: docker push $DOCKER_USERNAME/$CONTAINER_REPO_NAME:latest + - name: Helm - Update Version and Image Tag + run: | + yq --inplace '.image.tag = "${{ env.ARTIFACT_VERSION }}"' $HELM_CHART_PATH/values.yaml + yq --inplace '.version = "${{ env.ARTIFACT_VERSION }}"' $HELM_CHART_PATH/Chart.yaml + + - name: Helm Lint + run: helm lint $HELM_CHART_PATH + + - name: Helm Package + run: helm package $HELM_CHART_PATH + + - name: Helm - Checkout Charts Repository + uses: actions/checkout@v2 + with: + repository: Bahmniindiadistro/helm-charts + ref: gh-pages + path: helm-charts + persist-credentials: false + + - name: Helm - Copy chart + run: mkdir -p helm-charts/hiu-ui/ && cp hiu-ui-${{ env.ARTIFACT_VERSION }}.tgz helm-charts/hiu-ui/ + + - name: Helm - reIndex + working-directory: helm-charts/ + run: helm repo index --merge index.yaml --url https://bahmniindiadistro.github.io/helm-charts/ . + + - name: Helm - Publish Chart + working-directory: helm-charts/ + run: | + git config user.name ${{ secrets.BAHMNI_USERNAME}} + git config user.email ${{ secrets.BAHMNI_EMAIL}} + git add . + git commit -m "Release of hiu-ui-${{ env.ARTIFACT_VERSION }}" + git push 'https://${{ secrets.BAHMNI_USERNAME}}:${{ secrets.BAHMNI_PAT}}@github.com/bahmniindiadistro/helm-charts.git' gh-pages + + diff --git a/.github/workflows/uat.yml b/.github/workflows/uat.yml index e8eaa5d3..c41b6d0c 100644 --- a/.github/workflows/uat.yml +++ b/.github/workflows/uat.yml @@ -17,16 +17,16 @@ jobs: - name: NHA Docker Registry env: DOCKER_REGISTRY_URL: docker.io - NHA_PASSWORD: ${{ secrets.DOCKER_NHA_PASSWORD }} - NHA_USERNAME: ${{ secrets.DOCKER_NHA_USERNAME }} + NHA_PASSWORD: ${{ secrets.DOCKER_PASSWORD }} + NHA_USERNAME: ${{ secrets.DOCKER_USERNAME }} run: docker login -u $NHA_USERNAME -p $NHA_PASSWORD $DOCKER_REGISTRY_URL - name: Build docker image for NHA env: CONTAINER_REPO_NAME: hiu-ui - NHA_USERNAME: ${{ secrets.DOCKER_NHA_USERNAME }} - run: docker build --build-arg BACKEND_BASE_URL=http://uat.ndhm.gov.in/ --build-arg BASE_NAME=/hiu --build-arg BACKEND_API_PATH=api-hiu --build-arg DICOM_SERVER_PATH=/dicom-web --build-arg VIEWER_PAGE=/viewer/ --build-arg TITLE=NHA -t $NHA_USERNAME/$CONTAINER_REPO_NAME:$RELEASE_VERSION . + NHA_USERNAME: ${{ secrets.DOCKER_USERNAME }} + run: docker build -t $NHA_USERNAME/$CONTAINER_REPO_NAME:$RELEASE_VERSION . - name: Push Docker image to NHA Registry env: CONTAINER_REPO_NAME: hiu-ui - NHA_USERNAME: ${{ secrets.DOCKER_NHA_USERNAME }} + NHA_USERNAME: ${{ secrets.DOCKER_USERNAME }} run: docker push $NHA_USERNAME/$CONTAINER_REPO_NAME:$RELEASE_VERSION diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index d6f6cb95..00000000 --- a/Dockerfile +++ /dev/null @@ -1,26 +0,0 @@ -FROM node:8 as build-deps -WORKDIR /app -COPY . ./ -RUN npm install - -ARG BACKEND_BASE_URL='http://host.docker.internal:8003' -ARG BASE_NAME='@' -ARG BACKEND_API_PATH='/' -ARG DICOM_SERVER_PATH='/' -ARG VIEWER_PAGE='/viewer/' -ARG TITLE='NCG' - -ENV BACKEND_BASE_URL=${BACKEND_BASE_URL} -ENV BASE_NAME ${BASE_NAME} -ENV BACKEND_API_PATH ${BACKEND_API_PATH} -ENV DICOM_SERVER_PATH ${DICOM_SERVER_PATH} -ENV REACT_APP_SITE_TITLE=${TITLE} -ENV DICOM_VIEWER_PAGE=${VIEWER_PAGE} -RUN npm run build - -# stage: 2 — the production environment -FROM node:13.12.0-alpine -RUN npm install -g serve -COPY --from=build-deps /app/dist/ dist/ -EXPOSE 5000 -CMD ["serve", "dist/", "-l", "5000"] \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..23e4a196 --- /dev/null +++ b/LICENSE @@ -0,0 +1,7 @@ +Copyright 2021 Thoughtworks Technologies India Private limited + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/README.md b/README.md index 98b4f59a..d22162bd 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,24 @@ -## Available Scripts +This is a forked repo from project-eka, includes few ui-enchancements and session management. + +## To run locally: + +update src path in index.html as `/bundle.js` + +### 1. using docker + +To build a image, you can run: + +### `docker build -t hiu-ui .` + +To run the container, + +you can update docker-compose.development.yml environment variable if needed, you can run: + +### `docker-compose -f docker-compose.development.yml up hiu-ui` + +Note: BACKEND_BASE_URL, BASE_NAME are mandatory in docker-compose.development.yml + +###2. using npm In the project directory, you can run: @@ -36,20 +56,28 @@ devServer: { Launches the test runner in the interactive watch mode. -## Plugging in the reference HIU-UI to HIU-Server +## Plugging in the reference HIU-UI to Local-HIU-Server -create a file ".env" in the root directory. with the following contents +update src/Config.js. with the following contents ``` -BACKEND_BASE_URL = 'http://localhost:8003' -BASE_NAME = '/hiu' -BACKEND_API_PATH= '/' -DICOM_VIEWER_PAGE= '/viewer/' -DICOM_SERVER_PATH= '/dicom-web' -REACT_APP_SITE_TITLE= 'NCG' +BACKEND_BASE_URL: 'http://localhost:8003', +BASE_NAME: '/hiu', +BACKEND_API_PATH: '/', +DICOM_VIEWER_PAGE: '/viewer/', +DICOM_SERVER_PATH: '/dicom-web', +TITLE: 'NCG' ``` The above should be self explanatory, essentially it says that the HIU-Service is running on http://localhost:8003 +Add the following to the Config file for the specific timezone. The following is for IST TimeZone UTC+5:30 + +```aidl +TIMEZONE_OFFSET: '+05:30' +``` + +Note: If you haven't specify TimeZone, it will be UTC by default + If you are testing with the reference HIU-Service, and thats running locally on a different port, most likely Chrome will not allow you to make Http calls because of CORS restrictions. To do this, there are many ways - for example, use a proxy like HAProxy and put your HIU-UI and HIU-Server behind the proxy and route the calls appropriately. For development purpose, you can start chrome with disabled web security. @@ -60,4 +88,4 @@ open -na Google\ Chrome --args --disable-web-security --user-data-dir=$HOME/loca Note the above will start a new process of Chrome. Use this only for local testing and do not use this for accessing any public websites, and terminate this specific process as soon as you are done. -The latest versions of Safari also allows you disable Cross-Origin Restrictions. Enable the developer menu from Preferences >> Advanced, and select "Disable Cross-Origin Restrictions" from the develop menu. Again be careful of browsing external and public websites, and uncheck the above option "Disable Cross-Orgin .. " as soon as you are done. \ No newline at end of file +The latest versions of Safari also allows you disable Cross-Origin Restrictions. Enable the developer menu from Preferences >> Advanced, and select "Disable Cross-Origin Restrictions" from the develop menu. Again be careful of browsing external and public websites, and uncheck the above option "Disable Cross-Orgin .. " as soon as you are done. diff --git a/docker-compose.development.yml b/docker-compose.development.yml new file mode 100644 index 00000000..e87df289 --- /dev/null +++ b/docker-compose.development.yml @@ -0,0 +1,15 @@ +version: '3' +services: + hiu-ui: + image: "hiu-ui:latest" + environment: + BACKEND_BASE_URL: "" + BASE_NAME: '/hiu' + BACKEND_API_PATH: "/hiu-api" + DICOM_SERVER_PATH: '/' + VIEWER_PAGE: "/viewer/" + TITLE: 'NCG' + TIMEZONE_OFFSET: "+05:30" + ports: + - "8000:5000" + diff --git a/entryPoint.sh b/entryPoint.sh new file mode 100644 index 00000000..f7664461 --- /dev/null +++ b/entryPoint.sh @@ -0,0 +1,17 @@ +#!/bin/sh + +file="/dist/bundle.js" +set -xe +: "${BACKEND_BASE_URL?BACKEND_BASE_URL is not defined}" +: "${BASE_NAME?BASE_NAME is not defined}" + +sed -i 's|TITLE:[^,]*|TITLE: '\"$TITLE\"'|g' $file +sed -i 's|BACKEND_BASE_URL:[^,]*|BACKEND_BASE_URL: '\"$BACKEND_BASE_URL\"'|g' $file +sed -i 's|BACKEND_API_PATH:[^,]*|BACKEND_API_PATH: '\"$BACKEND_API_PATH\"'|g' $file +sed -i 's|BASE_NAME:[^,]*|BASE_NAME: '\"$BASE_NAME\"'|g' $file +sed -i 's|DICOM_VIEWER_PAGE:[^,]*|DICOM_VIEWER_PAGE: '\"$DICOM_VIEWER_PAGE\"'|g' $file +sed -i 's|DICOM_SERVER_PATH:[^,]*|DICOM_SERVER_PATH: '\"$DICOM_SERVER_PATH\"'|g' $file +sed -i 's|TIMEZONE_OFFSET:[^,]*|TIMEZONE_OFFSET: '\"$TIMEZONE_OFFSET\"'|g' $file + + +exec "$@" \ No newline at end of file diff --git a/index.html b/index.html index 64829e60..f7722f96 100644 --- a/index.html +++ b/index.html @@ -9,6 +9,6 @@
- + diff --git a/index.js b/index.js index 4e94cac4..9c27cc4f 100644 --- a/index.js +++ b/index.js @@ -11,6 +11,7 @@ import { MuiPickersUtilsProvider } from "@material-ui/pickers"; import { teal } from "@material-ui/core/colors"; // main app import App from "./src/App"; +import Config from "./src/Config"; const theme = createMuiTheme({ palette: { @@ -28,7 +29,7 @@ const theme = createMuiTheme({ } }); -document.querySelector('title').innerHTML=REACT_APP_SITE_TITLE; +document.querySelector('title').innerHTML= Config.TITLE; ReactDOM.render( diff --git a/package.json b/package.json index ada12d52..8edccb5b 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,7 @@ "test": "jest --passWithNoTests", "test:update:snapshot": "npm test -- -u", "test:watch": "jest --watch", - "build": "rm -rf dist && MODE=PROD webpack --config ./webpack/webpack.prod.config.js", + "build": "rm -rf dist && MODE=PROD webpack --config ./webpack/webpack.common.js", "dev": "./node_modules/.bin/webpack-dev-server --config ./webpack/webpack.dev.config.js", "start": "http-server dist", "lint": "eslint src", diff --git a/package/docker/Dockerfile b/package/docker/Dockerfile new file mode 100644 index 00000000..df0b268e --- /dev/null +++ b/package/docker/Dockerfile @@ -0,0 +1,16 @@ +FROM node:8 as build-deps +WORKDIR /app +COPY . ./ +RUN npm install +RUN npm run build + +# stage: 2 ?~@~T the production environment +FROM node:13.12.0-alpine +RUN npm install -g serve@13.0.4 +COPY --from=build-deps /app/dist/ dist/ +EXPOSE 5000 + +COPY entryPoint.sh / +RUN chmod +x entryPoint.sh +ENTRYPOINT ["/entryPoint.sh"] +CMD ["serve", "dist/", "-l", "5000"] diff --git a/package/helm/.helmignore b/package/helm/.helmignore new file mode 100644 index 00000000..0e8a0eb3 --- /dev/null +++ b/package/helm/.helmignore @@ -0,0 +1,23 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/package/helm/Chart.yaml b/package/helm/Chart.yaml new file mode 100644 index 00000000..a7861a1a --- /dev/null +++ b/package/helm/Chart.yaml @@ -0,0 +1,5 @@ +apiVersion: v2 +name: hiu-ui +description: Helm chart for hiu-ui +type: application +version: 1.0.0 \ No newline at end of file diff --git a/package/helm/templates/configMap.yaml b/package/helm/templates/configMap.yaml new file mode 100644 index 00000000..054a9582 --- /dev/null +++ b/package/helm/templates/configMap.yaml @@ -0,0 +1,12 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ .Chart.Name }}-config +data: + BACKEND_BASE_URL: "{{ .Values.config.BACKEND_BASE_URL }}" + BASE_NAME: "{{ .Values.config.BASE_NAME }}" + BACKEND_API_PATH: "{{ .Values.config.BACKEND_API_PATH }}" + DICOM_SERVER_PATH: "{{ .Values.config.DICOM_SERVER_PATH }}" + VIEWER_PAGE: "{{ .Values.config.VIEWER_PAGE }}" + TITLE: "{{ .Values.config.TITLE }}" + TIMEZONE_OFFSET: "{{ .Values.config.TIMEZONE_OFFSET }}" diff --git a/package/helm/templates/deployment.yaml b/package/helm/templates/deployment.yaml new file mode 100644 index 00000000..c7c2da8a --- /dev/null +++ b/package/helm/templates/deployment.yaml @@ -0,0 +1,63 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ .Chart.Name }} + labels: + app: {{ .Chart.Name }} + environment: {{ .Values.metadata.labels.environment }} + +spec: + {{- if not .Values.autoscaling.enabled }} + replicas: {{ .Values.replicaCount }} + {{- end }} + selector: + matchLabels: + app: {{ .Chart.Name }} + environment: {{ .Values.metadata.labels.environment }} + revisionHistoryLimit: 5 + template: + metadata: + labels: + app: {{ .Chart.Name }} + environment: {{ .Values.metadata.labels.environment }} + spec: + {{ if or .Values.global.nodeSelector .Values.nodeSelector }} + nodeSelector: + {{ if .Values.nodeSelector }} + {{ .Values.nodeSelector | toYaml | nindent 8}} + {{ else }} + {{.Values.global.nodeSelector | toYaml | nindent 8}} + {{ end }} + {{ end }} + + {{ if or .Values.global.affinity .Values.affinity }} + affinity: + {{ if .Values.affinity }} + {{ .Values.affinity | toYaml | nindent 8}} + {{ else }} + {{.Values.global.affinity | toYaml | nindent 8}} + {{ end }} + {{ end }} + + {{ if or .Values.global.tolerations .Values.tolerations }} + tolerations: + {{ if .Values.tolerations }} + {{ .Values.tolerations | toYaml | nindent 8}} + {{ else }} + {{.Values.global.tolerations | toYaml | nindent 8}} + {{ end }} + {{ end }} + + containers: + - name: {{ .Chart.Name }} + image: "{{ .Values.image.repository }}/{{ .Values.image.name }}:{{ .Values.image.tag | default .Chart.AppVersion }}" + ports: + - containerPort: 5000 + protocol: TCP + envFrom: + - configMapRef: + name: {{ .Chart.Name }}-config + optional: false + resources: + {{- toYaml .Values.resources | nindent 12 }} + restartPolicy: Always diff --git a/package/helm/templates/hpa.yaml b/package/helm/templates/hpa.yaml new file mode 100644 index 00000000..18d71e7c --- /dev/null +++ b/package/helm/templates/hpa.yaml @@ -0,0 +1,29 @@ +{{- if .Values.autoscaling.enabled }} +apiVersion: autoscaling/v2beta1 +kind: HorizontalPodAutoscaler +metadata: + name: {{ .Chart.Name }} + labels: + app: {{ .Chart.Name }} + environment: {{ .Values.metadata.labels.environment }} +spec: + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: {{ .Chart.Name }} + minReplicas: {{ .Values.autoscaling.minReplicas }} + maxReplicas: {{ .Values.autoscaling.maxReplicas }} + metrics: + {{- if .Values.autoscaling.targetCPUUtilizationPercentage }} + - type: Resource + resource: + name: cpu + targetAverageUtilization: {{ .Values.autoscaling.targetCPUUtilizationPercentage }} + {{- end }} + {{- if .Values.autoscaling.targetMemoryUtilizationPercentage }} + - type: Resource + resource: + name: memory + targetAverageUtilization: {{ .Values.autoscaling.targetMemoryUtilizationPercentage }} + {{- end }} +{{- end }} diff --git a/package/helm/templates/service.yaml b/package/helm/templates/service.yaml new file mode 100644 index 00000000..a84e7b13 --- /dev/null +++ b/package/helm/templates/service.yaml @@ -0,0 +1,18 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ .Chart.Name }} + labels: + app: {{ .Chart.Name }} + environment: {{ .Values.metadata.labels.environment }} + +spec: + type: {{ .Values.service.type }} + ports: + - port: {{ .Values.service.port }} + targetPort: 5000 + protocol: TCP + name: '5000' + selector: + app: {{ .Chart.Name }} + environment: {{ .Values.metadata.labels.environment }} \ No newline at end of file diff --git a/package/helm/values.yaml b/package/helm/values.yaml new file mode 100644 index 00000000..e16e2f24 --- /dev/null +++ b/package/helm/values.yaml @@ -0,0 +1,36 @@ +global: + nodeSelector: {} + affinity: {} + tolerations: {} + +replicaCount: 1 + +metadata: + labels: + environment: dev + +image: + repository: bahmniindiadistro + name: hiu-ui + tag: latest + +service: + type: ClusterIP + port: 5000 + +config: + BACKEND_BASE_URL: "" + BASE_NAME: '/hiuser' + BACKEND_API_PATH: "/hiu-api" + DICOM_SERVER_PATH: '/' + VIEWER_PAGE: "/viewer/" + TITLE: "HIU" + TIMEZONE_OFFSET: "+05:30" + + +autoscaling: + enabled: false + +nodeSelector: {} +affinity: {} +tolerations: {} diff --git a/src/App.js b/src/App.js index 7873ec6e..b53be15e 100644 --- a/src/App.js +++ b/src/App.js @@ -9,6 +9,7 @@ import LandingPage from './pages/LandingPage/LandingPageContainer'; import PatientHealthInformation from './pages/PatientHealthInformation'; import PrivateRoute from './components/PrivateRoute/PrivateRoute'; import history from './history'; +import Config from "./Config"; const useStyles = makeStyles(() => ({ container: { @@ -22,7 +23,7 @@ function App() { <> - + - Note:  - - - condition note 1, condition note 2 - - - -`; diff --git a/src/components/AttachmentLink/AttachmentLink.view.js b/src/components/AttachmentLink/AttachmentLink.view.js index 91f338e2..5a404f1c 100644 --- a/src/components/AttachmentLink/AttachmentLink.view.js +++ b/src/components/AttachmentLink/AttachmentLink.view.js @@ -32,7 +32,7 @@ const AttachmentLink = ({ consentReqId, attachmentPath, linkTitle }) => { ); }; - return {linkTitle}; + return {linkTitle}; }; AttachmentLink.propTypes = { diff --git a/src/components/AttachmentLink/__tests__/AttachmentLink.test.js b/src/components/AttachmentLink/__tests__/AttachmentLink.test.js index 0998617b..25368832 100644 --- a/src/components/AttachmentLink/__tests__/AttachmentLink.test.js +++ b/src/components/AttachmentLink/__tests__/AttachmentLink.test.js @@ -6,9 +6,9 @@ describe('AttachmentLink', () => { it('should render properly', () => { const wrapper = shallow( ); expect(wrapper).toMatchSnapshot(); diff --git a/src/components/Binary/BinaryComponent.js b/src/components/Binary/BinaryComponent.js index dcd4ef3d..8ad59bc1 100644 --- a/src/components/Binary/BinaryComponent.js +++ b/src/components/Binary/BinaryComponent.js @@ -10,10 +10,10 @@ const BinaryComponent = ({ data, consentReqId, enclosed }) => {
Attachments (Binary) : + consentReqId={consentReqId} + attachmentPath={atob(entry.data)} + linkTitle="Link to Attachment" + />
) : (
@@ -23,8 +23,8 @@ const BinaryComponent = ({ data, consentReqId, enclosed }) => { data.map((entry, index) => (
- {renderContent(entry)} -
+ {renderContent(entry)} +
)) ) : ( diff --git a/src/components/Breadcrumb/Breadcrumb.view.js b/src/components/Breadcrumb/Breadcrumb.view.js index 5ee4a8c4..8722ed7d 100644 --- a/src/components/Breadcrumb/Breadcrumb.view.js +++ b/src/components/Breadcrumb/Breadcrumb.view.js @@ -3,6 +3,7 @@ import Typography from '@material-ui/core/Typography'; import Breadcrumbs from '@material-ui/core/Breadcrumbs'; import Link from '@material-ui/core/Link'; import { makeStyles } from '@material-ui/core/styles'; +import Config from "../../Config"; const useStyles = makeStyles((theme) => ({ container: { @@ -15,7 +16,7 @@ const Breadcrumb = () => { const classes = useStyles(); return ( - + Consent List Health Data diff --git a/src/components/Composition/CompositionComponent.js b/src/components/Composition/CompositionComponent.js index 26ee1f9b..0ae80e70 100644 --- a/src/components/Composition/CompositionComponent.js +++ b/src/components/Composition/CompositionComponent.js @@ -1,9 +1,9 @@ import React from 'react'; import * as PropTypes from 'prop-types'; -import {formatDateString} from '../common/HealthInfo/FhirResourcesUtils'; -import DischargeSummary from "../DischargeSummary/DischargeSummary.view"; import Divider from '@material-ui/core/Divider'; import { Box } from '@material-ui/core'; +import {formatDateString} from '../common/HealthInfo/FhirResourcesUtils'; +import DischargeSummary from "../DischargeSummary/DischargeSummary.view"; import EncounterComponent from '../Encounter/EncounterComponent'; import CompositionSectionComponent from './CompositionSectionComponent'; @@ -37,19 +37,19 @@ const CompositionComponent = ({ composition, consentReqId, resources }) => { }; return ( -
- - - - - {} - -
+
+ + + + + + +
); }; export default CompositionComponent; \ No newline at end of file diff --git a/src/components/Composition/CompositionSectionComponent.js b/src/components/Composition/CompositionSectionComponent.js index 643cb64b..179f3a85 100644 --- a/src/components/Composition/CompositionSectionComponent.js +++ b/src/components/Composition/CompositionSectionComponent.js @@ -1,22 +1,22 @@ import React from 'react'; import * as PropTypes from 'prop-types'; +import Divider from '@material-ui/core/Divider'; +import { Box } from '@material-ui/core'; +import Toolbar from '@material-ui/core/Toolbar'; +import Typography from '@material-ui/core/Typography'; import ObservationTable from '../ObservationTable/ObservationTable'; import MedicationRequestsComponent from '../Medication/MedicationRequestsComponent'; import {getConceptDisplay, formatDateString} from '../common/HealthInfo/FhirResourcesUtils'; import ConditionsComponent from "../Condition/ConditionsComponent"; import DiagnosticReportComponent from "../DiagnosticReport/DiagnosticReportComponent"; -import Divider from '@material-ui/core/Divider'; import DocumentReferenceComponent from '../DocumentReference/DocumentReferenceComponent'; import BinaryComponent from '../Binary/BinaryComponent'; -import { Box } from '@material-ui/core'; -import Toolbar from '@material-ui/core/Toolbar'; -import Typography from '@material-ui/core/Typography'; import AllergiesComponent from '../AllergyIntolerance'; import ImmunizationRecordComponent from '../ImmunizationRecord'; const CompositionSectionComponent = ({ composition, consentReqId, resources }) => { const resourcesInComposition = resources; - const getSectionType = (section) => section.code && getConceptDisplay(section.code) + ':'; + const getSectionType = (section) => section.code && `${getConceptDisplay(section.code) }:`; const resourcesInSection = (resourceType, section) => { return( resourcesInComposition @@ -37,26 +37,31 @@ const CompositionSectionComponent = ({ composition, consentReqId, resources }) = const SectionHeader = ({ section}) => { return ( - - #{getSectionType(section)} {section.title} - + + + # + {getSectionType(section)} + {' '} + {section.title} + + ); }; return composition.section ? ( composition.section.map( (section) => { return ( - - - - - - - - - - - + + + + + + + + + + + ); }) ) : ( diff --git a/src/components/Condition/ConditionOnset/__tests__/ConditionOnset.test.js b/src/components/Condition/ConditionOnset/__tests__/ConditionOnset.test.js index b94d7abc..87cecf53 100644 --- a/src/components/Condition/ConditionOnset/__tests__/ConditionOnset.test.js +++ b/src/components/Condition/ConditionOnset/__tests__/ConditionOnset.test.js @@ -5,6 +5,7 @@ import ConditionOnset from '../ConditionOnset.view'; describe('ConditionOnset', () => { let wrapper; let mockData; + global.TIMEZONE_OFFSET = '-05:00'; it('should render properly', () => { mockData = { @@ -32,7 +33,7 @@ describe('ConditionOnset', () => { onsetDateTime: '2020-02-20T00:30:08.000+0000', }; wrapper = shallow(); - expect(wrapper.find('span').at(0).text()).toEqual('Onset time: 20/02/2020'); + expect(wrapper.find('span').at(0).text()).toEqual('Onset time: 19/02/2020'); }); it('should show onsetAge', () => { @@ -54,7 +55,7 @@ describe('ConditionOnset', () => { }, }; wrapper = shallow(); - expect(wrapper.find('span').at(0).text()).toEqual('Period start: 01/02/2020, end: 20/02/2020'); + expect(wrapper.find('span').at(0).text()).toEqual('Period start: 31/01/2020, end: 19/02/2020'); }); it('should show onsetRange', () => { diff --git a/src/components/Condition/ConditionOnset/__tests__/__snapshots__/ConditionOnset.test.js.snap b/src/components/Condition/ConditionOnset/__tests__/__snapshots__/ConditionOnset.test.js.snap index 07bfaa7d..4c15c6c5 100644 --- a/src/components/Condition/ConditionOnset/__tests__/__snapshots__/ConditionOnset.test.js.snap +++ b/src/components/Condition/ConditionOnset/__tests__/__snapshots__/ConditionOnset.test.js.snap @@ -2,6 +2,6 @@ exports[`ConditionOnset should render properly 1`] = ` - Onset time: 20/02/2020 + Onset time: 19/02/2020 `; diff --git a/src/components/Condition/__tests__/ConditionsComponent.test.js b/src/components/Condition/__tests__/ConditionsComponent.test.js index d25b7f4c..2c718e08 100644 --- a/src/components/Condition/__tests__/ConditionsComponent.test.js +++ b/src/components/Condition/__tests__/ConditionsComponent.test.js @@ -4,6 +4,7 @@ import ConditionsComponent from '../ConditionsComponent'; import TableStyles from '../../common/Styles/Table.style'; describe('ConditionsComponent', () => { + global.TIMEZONE_OFFSET = '-05:00'; const mockData = [ { code: { @@ -68,7 +69,7 @@ describe('ConditionsComponent', () => { }); it('should render correct data in table body', () => { - expect(wrapper.find('.table-cell').at(0).text()).toEqual('19/02/2020'); + expect(wrapper.find('.table-cell').at(0).text()).toEqual('18/02/2020'); expect(wrapper.find('.table-cell').at(1).text()).toContain('day1'); expect(wrapper.find('.table-cell').at(2).text()).toContain('Severity: severity'); expect(wrapper.find('.table-cell').at(2).text()).toContain('Clinical Status: clinical status'); diff --git a/src/components/Condition/__tests__/__snapshots__/ConditionsComponent.test.js.snap b/src/components/Condition/__tests__/__snapshots__/ConditionsComponent.test.js.snap index a6cc0d86..9337f44b 100644 --- a/src/components/Condition/__tests__/__snapshots__/ConditionsComponent.test.js.snap +++ b/src/components/Condition/__tests__/__snapshots__/ConditionsComponent.test.js.snap @@ -368,7 +368,7 @@ exports[`ConditionsComponent should render properly 1`] = ` - 19/02/2020 + 18/02/2020 - { const headerRow = { name: 'Name', - jataayuId: 'Jataayu ID', + jataayuId: 'Patient Identifier', requestStatus: 'Request Status', consentGrantedDate: 'Consent granted on', consentExpiryDate: 'Consent expiry on', @@ -118,11 +118,11 @@ const ConsentsListTable = ({ loadConsents, consentsList, loading }) => { '' ) }))} - title={ + title={( Consent List - } + )} actions={[ { icon: 'refresh', diff --git a/src/components/ConsentsListTable/__tests__/ConsentsListTable.test.js b/src/components/ConsentsListTable/__tests__/ConsentsListTable.test.js index afec9c1b..0dae6d98 100644 --- a/src/components/ConsentsListTable/__tests__/ConsentsListTable.test.js +++ b/src/components/ConsentsListTable/__tests__/ConsentsListTable.test.js @@ -18,6 +18,7 @@ describe('ConsentsListTable', () => { navLink: '', }, ]; + global.TIMEZONE_OFFSET = '-05:00'; const wrapper = shallow( , ); @@ -29,11 +30,12 @@ describe('ConsentsListTable', () => { it('should render data in consent list when status is granted', () => { expect(wrapper.find(MaterialTable).length).toEqual(1); + console.log(wrapper.find(MaterialTable).props().data[0].expiredOn); expect(wrapper.find(MaterialTable).props().data[0].name).toEqual('John Smith'); expect(wrapper.find(MaterialTable).props().data[0].status).toEqual('Consent Granted'); - expect(wrapper.find(MaterialTable).props().data[0].grantedOn).toEqual('19/02/2020 06:00'); - expect(wrapper.find(MaterialTable).props().data[0].expiredOn).toEqual('20/02/2020 08:47'); - expect(wrapper.find(MaterialTable).props().data[0].createdOn).toEqual('18/02/2020 08:47'); + expect(wrapper.find(MaterialTable).props().data[0].grantedOn).toEqual('18/02/2020 07:30 PM'); + expect(wrapper.find(MaterialTable).props().data[0].expiredOn).toEqual('19/02/2020 10:17 PM'); + expect(wrapper.find(MaterialTable).props().data[0].createdOn).toEqual('17/02/2020 10:17 PM'); expect(wrapper.find(MaterialTable).props().data[0].navLink).not.toEqual(''); }); @@ -46,7 +48,7 @@ describe('ConsentsListTable', () => { expect(wrapper.find(MaterialTable).props().data[0].status).toEqual('Request Denied'); expect(wrapper.find(MaterialTable).props().data[0].grantedOn).toEqual('-'); expect(wrapper.find(MaterialTable).props().data[0].expiredOn).toEqual('-'); - expect(wrapper.find(MaterialTable).props().data[0].createdOn).toEqual('18/02/2020 08:47'); + expect(wrapper.find(MaterialTable).props().data[0].createdOn).toEqual('17/02/2020 10:17 PM'); expect(wrapper.find(MaterialTable).props().data[0].navLink).toEqual(''); }); diff --git a/src/components/ConsentsListTable/__tests__/__snapshots__/ConsentsListTable.test.js.snap b/src/components/ConsentsListTable/__tests__/__snapshots__/ConsentsListTable.test.js.snap index 08f84db3..52706063 100644 --- a/src/components/ConsentsListTable/__tests__/__snapshots__/ConsentsListTable.test.js.snap +++ b/src/components/ConsentsListTable/__tests__/__snapshots__/ConsentsListTable.test.js.snap @@ -28,7 +28,7 @@ exports[`ConsentsListTable should render properly 1`] = ` }, Object { "field": "id", - "title": "Jataayu ID", + "title": "Patient Identifier", }, Object { "field": "status", @@ -59,9 +59,9 @@ exports[`ConsentsListTable should render properly 1`] = ` data={ Array [ Object { - "createdOn": "18/02/2020 08:47", - "expiredOn": "20/02/2020 08:47", - "grantedOn": "19/02/2020 06:00", + "createdOn": "17/02/2020 10:17 PM", + "expiredOn": "19/02/2020 10:17 PM", + "grantedOn": "18/02/2020 07:30 PM", "id": undefined, "name": "John Smith", "navLink": { const performerArray = []; @@ -57,7 +58,7 @@ const DiagnosticReportComponent = ({ data, consentReqId }) => { }; const getDicomAddress = (entry) => { - var imageUrl = undefined; + let imageUrl; const imagingStudyList = getResultsList( getNestedObject(entry, 'imagingStudy'), 'ImagingStudy', @@ -97,7 +98,7 @@ const DiagnosticReportComponent = ({ data, consentReqId }) => { function generateImageUrl(url) { const urlArray = url.split('/'); const StudyInstanceUID = urlArray.slice(-1).pop(); - const dicomCtx = btoa(DICOM_SERVER_PATH); + const dicomCtx = btoa(Config.DICOM_SERVER_PATH); const dicomUrl = `${window.location.origin }/viewer/${ @@ -163,16 +164,23 @@ const DiagnosticReportComponent = ({ data, consentReqId }) => { Performer: {extractPerformer(entry)} - { entry.conclusion && -
  • - Conclusion: {entry.conclusion} -
  • - } - { getDicomAddress(entry) && + { entry.conclusion && (
  • - DICOM image + + Conclusion: + {entry.conclusion} +
  • - } + )} + { getDicomAddress(entry) && ( +
  • + + {' '} + DICOM image + {' '} + +
  • + )} {renderObservations(entry)} {renderPresentedForm(entry)} diff --git a/src/components/DiagnosticReport/__tests__/DiagnosticReportComponent.test.js b/src/components/DiagnosticReport/__tests__/DiagnosticReportComponent.test.js index 0e1f41a3..feb23e7f 100644 --- a/src/components/DiagnosticReport/__tests__/DiagnosticReportComponent.test.js +++ b/src/components/DiagnosticReport/__tests__/DiagnosticReportComponent.test.js @@ -41,6 +41,7 @@ describe('DiagnosticReportComponent', () => { ]; global.BACKEND_BASE_URL = 'http://localhost:3000/'; global.BACKEND_API_PATH = 'hiu-api'; + global.TIMEZONE_OFFSET = '-05:00'; const wrapper = shallow( { }); it('should show report details list with correct data', () => { - expect(wrapper.find('.report-details-list li').at(0).text()).toEqual('Date: 03/11/2019'); + expect(wrapper.find('.report-details-list li').at(0).text()).toEqual('Date: 02/11/2019'); expect(wrapper.find('.report-details-list li').at(1).text()).toEqual('Status: final'); expect(wrapper.find('.report-details-list li').at(2).text()).toEqual('Performer: text'); }); diff --git a/src/components/DiagnosticReport/__tests__/__snapshots__/DiagnosticReportComponent.test.js.snap b/src/components/DiagnosticReport/__tests__/__snapshots__/DiagnosticReportComponent.test.js.snap index 053831b0..e8a6a793 100644 --- a/src/components/DiagnosticReport/__tests__/__snapshots__/DiagnosticReportComponent.test.js.snap +++ b/src/components/DiagnosticReport/__tests__/__snapshots__/DiagnosticReportComponent.test.js.snap @@ -342,7 +342,7 @@ exports[`DiagnosticReportComponent should render properly 1`] = ` Date: - 03/11/2019 + 02/11/2019
  • diff --git a/src/components/DischargeSummary/DischargeSummary.view.js b/src/components/DischargeSummary/DischargeSummary.view.js index 89d4adda..4a71741b 100644 --- a/src/components/DischargeSummary/DischargeSummary.view.js +++ b/src/components/DischargeSummary/DischargeSummary.view.js @@ -1,10 +1,10 @@ import React from 'react'; import * as PropTypes from 'prop-types'; import Typography from '@material-ui/core/Typography'; -import useStyle from './DischargeSummary.style'; -import { formatDateString } from '../common/HealthInfo/FhirResourcesUtils'; import Grid from '@material-ui/core/Grid'; import Box from '@material-ui/core/Box'; +import useStyle from './DischargeSummary.style'; +import { formatDateString } from '../common/HealthInfo/FhirResourcesUtils'; const DischargeSummary = ({ title, startDate, endDate, authors, status, date }) => { const classes = useStyle(); @@ -15,14 +15,39 @@ const DischargeSummary = ({ title, startDate, endDate, authors, status, date }) - Document: {title} + Document: + {' '} + {title} - {date &&
    Date: {date}
    } - {start && end && (Admitted from {start} to {end})} - {authors.length &&
    Authors: { authors.join(', ') }
    } - {status &&
    Status: {status.toUpperCase()}
    } + {date && ( +
    + Date: + {date} +
    +)} + {start && end && ( + + Admitted from + {start} + {' '} + to + {end} + +)} + {authors.length && ( +
    + Authors: + { authors.join(', ') } +
    +)} + {status && ( +
    + Status: + {status.toUpperCase()} +
    +)}
    ) : '' diff --git a/src/components/DischargeSummary/__tests__/DischargeSummary.test.js b/src/components/DischargeSummary/__tests__/DischargeSummary.test.js index 2201a230..afbf1ad8 100644 --- a/src/components/DischargeSummary/__tests__/DischargeSummary.test.js +++ b/src/components/DischargeSummary/__tests__/DischargeSummary.test.js @@ -5,6 +5,7 @@ import DischargeSummary from "../DischargeSummary.view"; describe('DischargeSummary', () => { let wrapper; + global.TIMEZONE_OFFSET = '-05:00'; beforeEach(() => { wrapper = shallow( @@ -13,7 +14,7 @@ describe('DischargeSummary', () => { startDate="2018-04-01T15:30:10+01:00" endDate="2018-04-10T15:30:10+01:00" authors={['abc', 'xyz']} - status={'final'} + status="final" /> ); }); diff --git a/src/components/DischargeSummary/__tests__/__snapshots__/DischargeSummary.test.js.snap b/src/components/DischargeSummary/__tests__/__snapshots__/DischargeSummary.test.js.snap index f7f15394..a6a25a84 100644 --- a/src/components/DischargeSummary/__tests__/__snapshots__/DischargeSummary.test.js.snap +++ b/src/components/DischargeSummary/__tests__/__snapshots__/DischargeSummary.test.js.snap @@ -14,7 +14,8 @@ exports[`DischargeSummary should render properly 1`] = ` color="inherit" variant="h6" > - Document: + Document: + Discharge Summary @@ -25,9 +26,10 @@ exports[`DischargeSummary should render properly 1`] = ` - Admitted from + Admitted from 01/04/2018 - to + + to 10/04/2018
    diff --git a/src/components/DocumentReference/DocumentReferenceComponent.js b/src/components/DocumentReference/DocumentReferenceComponent.js index 9fffd802..55c13391 100644 --- a/src/components/DocumentReference/DocumentReferenceComponent.js +++ b/src/components/DocumentReference/DocumentReferenceComponent.js @@ -58,48 +58,50 @@ const DocumentReferenceComponent = ({ data, consentReqId, enclosed }) => { variant="h6" component="h6" > - {enclosed && 'Enclosed '} Clinical Document : + {enclosed && 'Enclosed '} + {' '} + Clinical Document : {' '} {entry.type ? entry.type.text : ''}
      - {extractAuthor(entry) && + {extractAuthor(entry) && (
    • Author: {extractAuthor(entry)}
    • - } - {entry.date && + )} + {entry.date && (
    • Date: {formatDateString(entry.date)}
    • - } - {entry.description && + )} + {entry.description && (
    • Description: {entry.description}
    • - } - {entry.status && + )} + {entry.status && (
    • Status: {entry.status}
    • - } - {entry.docStatus && + )} + {entry.docStatus && (
    • Document Status: {entry.docStatus}
    • - } - {extractContext(entry.context) && + )} + {extractContext(entry.context) && (
    • Context: {extractContext(entry.context)}
    • - } + )}
    {renderContent(entry)}
    diff --git a/src/components/DocumentReference/__tests__/DocumentReferenceComponent.test.js b/src/components/DocumentReference/__tests__/DocumentReferenceComponent.test.js index b3384189..b8c3569d 100644 --- a/src/components/DocumentReference/__tests__/DocumentReferenceComponent.test.js +++ b/src/components/DocumentReference/__tests__/DocumentReferenceComponent.test.js @@ -28,7 +28,7 @@ describe('DocumentReferenceComponent', () => { display: 'Shriya', reference: "Patient/RVH1003", }, - date: "2019-12-24T09:43:41+05:30", + date: "2019-12-24T09:43:41", description: "Human readable description - about the document", context: { encounter: [ @@ -38,8 +38,8 @@ describe('DocumentReferenceComponent', () => { } ], period: { - start: "2019-12-24T08:43:41+05:30", - end: "2019-12-24T10:43:41+05:30", + start: "2019-12-24T08:43:41", + end: "2019-12-24T10:43:41", } }, content: [ @@ -61,6 +61,7 @@ describe('DocumentReferenceComponent', () => { ]; global.BACKEND_BASE_URL = 'http://localhost:3000/'; global.BACKEND_API_PATH = 'hiu-api'; + global.TIMEZONE_OFFSET = '-05:00'; const wrapper = shallow( - Clinical Document : + + Clinical Document : Clinical Note diff --git a/src/components/Encounter/EncounterComponent.js b/src/components/Encounter/EncounterComponent.js index c7c67eb1..67a1d4ea 100644 --- a/src/components/Encounter/EncounterComponent.js +++ b/src/components/Encounter/EncounterComponent.js @@ -7,16 +7,16 @@ const getEncDetails = (enc) => { const details = [getCodingDisplay(enc.class), enc.status]; if (enc.period) { details.push( - formatDateString(enc.period.start, true) - + '-' - + formatDateString(enc.period.end, true) + `${formatDateString(enc.period.start, true) + }-${ + formatDateString(enc.period.end, true)}` ); } return details.join(', '); } const getEncDiagnosis = (encounter) => { - let diagnosis = encounter && encounter.diagnosis; + const diagnosis = encounter && encounter.diagnosis; if (diagnosis) { return diagnosis.map(diag => { if (diag.condition && diag.condition.targetResource) { @@ -34,11 +34,11 @@ const EncounterComponent = ({ composition }) => {
    Encounter:
      -
    • - {getEncDetails(composition.encounter.targetResource)} +
    • + {getEncDetails(composition.encounter.targetResource)}
    • -
    • - {'Diagnosis: ' + getEncDiagnosis(composition.encounter.targetResource)} +
    • + {`Diagnosis: ${ getEncDiagnosis(composition.encounter.targetResource)}`}
    diff --git a/src/components/Header/Header.view.js b/src/components/Header/Header.view.js index 7c9cf86c..e97e6421 100644 --- a/src/components/Header/Header.view.js +++ b/src/components/Header/Header.view.js @@ -5,6 +5,7 @@ import AppBar from '@material-ui/core/AppBar'; import Toolbar from '@material-ui/core/Toolbar'; import Button from '@material-ui/core/Button'; import Link from '@material-ui/core/Link'; +import Config from "../../Config"; const Header = () => { const logout = () => { @@ -17,7 +18,7 @@ const Header = () => { - + LOGO diff --git a/src/components/HealthInformation/HealthInformationContent.view.js b/src/components/HealthInformation/HealthInformationContent.view.js index 6f30e124..9a17792f 100644 --- a/src/components/HealthInformation/HealthInformationContent.view.js +++ b/src/components/HealthInformation/HealthInformationContent.view.js @@ -107,7 +107,7 @@ const HealthInformationContent = ({ consentReqId, hipName, data }) => { /> - +
    ); diff --git a/src/components/Medication/DosageTiming/__tests__/DosageTiming.test.js b/src/components/Medication/DosageTiming/__tests__/DosageTiming.test.js index e18ea2a1..636317ae 100644 --- a/src/components/Medication/DosageTiming/__tests__/DosageTiming.test.js +++ b/src/components/Medication/DosageTiming/__tests__/DosageTiming.test.js @@ -10,6 +10,7 @@ describe('DosageTiming', () => { event: ['1','2019-01-21T12:00:00+01:00','2019-01-22T12:00:00+01:00'], }, }; + global.TIMEZONE_OFFSET = '-05:00'; const wrapper = shallow( , ); diff --git a/src/components/Medication/MedicationRequestsComponent.js b/src/components/Medication/MedicationRequestsComponent.js index 21fca484..0bd17c30 100644 --- a/src/components/Medication/MedicationRequestsComponent.js +++ b/src/components/Medication/MedicationRequestsComponent.js @@ -89,7 +89,7 @@ const MedicationRequestsComponent = ({ medicationRequests }) => (medicationReque {findMedicationName(mr)} {` (${mr.status})`}
      - {} +
    diff --git a/src/components/Medication/__tests__/MedicationRequestsComponent.test.js b/src/components/Medication/__tests__/MedicationRequestsComponent.test.js index 5dd86899..92a9b5ef 100644 --- a/src/components/Medication/__tests__/MedicationRequestsComponent.test.js +++ b/src/components/Medication/__tests__/MedicationRequestsComponent.test.js @@ -4,6 +4,7 @@ import MedicationRequestsComponent from '../MedicationRequestsComponent'; import TableStyles from '../../common/Styles/Table.style'; describe('MedicationRequestsComponent', () => { + global.TIMEZONE_OFFSET = '-05:00'; const mockData = [ { resourceType: 'MedicationRequest', @@ -51,7 +52,7 @@ describe('MedicationRequestsComponent', () => { }); it('should show correct data of medication requests', () => { - expect(wrapper.find('.table-cell').at(0).text()).toEqual('22/01/2020'); + expect(wrapper.find('.table-cell').at(0).text()).toEqual('21/01/2020'); expect(wrapper.find('.table-cell').at(1).text()).toEqual('display (active)'); mockData[0].medicationReference.targetResource = { diff --git a/src/components/Medication/__tests__/__snapshots__/MedicationRequestsComponent.test.js.snap b/src/components/Medication/__tests__/__snapshots__/MedicationRequestsComponent.test.js.snap index cdcf8038..3dcd91e4 100644 --- a/src/components/Medication/__tests__/__snapshots__/MedicationRequestsComponent.test.js.snap +++ b/src/components/Medication/__tests__/__snapshots__/MedicationRequestsComponent.test.js.snap @@ -368,7 +368,7 @@ exports[`MedicationRequestsComponent should render properly 1`] = ` - 22/01/2020 + 21/01/2020 (components ? components.map((component) => ( diff --git a/src/components/ObservationTable/__tests__/ObservationTable.test.js b/src/components/ObservationTable/__tests__/ObservationTable.test.js index b46f6fbd..a0981b32 100644 --- a/src/components/ObservationTable/__tests__/ObservationTable.test.js +++ b/src/components/ObservationTable/__tests__/ObservationTable.test.js @@ -20,6 +20,7 @@ describe('ObservationTable', () => { ] }, ]; + global.TIMEZONE_OFFSET = '-05:00'; const wrapper = shallow( ); @@ -33,7 +34,7 @@ describe('ObservationTable', () => { expect(wrapper.find('.table-cell').at(0).text()).toEqual(''); mockData[0].effectiveDateTime = "2020-01-03"; wrapper.setProps({data:mockData}); - expect(wrapper.find('.table-cell').at(0).text()).toEqual('03/01/2020 05:30'); + expect(wrapper.find('.table-cell').at(0).text()).toEqual('02/01/2020 07:00 PM'); }); it('should render class name according to the condition', () => { @@ -43,7 +44,7 @@ describe('ObservationTable', () => { wrapper.setProps({data:mockData}); expect(wrapper.find('.parent-row').exists()).toEqual(false); expect(wrapper.find('.children-row').exists()).toEqual(true); - expect(wrapper.find('.table-cell').at(0).text()).toEqual('03/01/2020 05:30'); + expect(wrapper.find('.table-cell').at(0).text()).toEqual('02/01/2020 07:00 PM'); }); it('should render code text in table data', () => { diff --git a/src/components/PrivateRoute/PrivateRoute.js b/src/components/PrivateRoute/PrivateRoute.js index c67bc6d2..aebaab29 100644 --- a/src/components/PrivateRoute/PrivateRoute.js +++ b/src/components/PrivateRoute/PrivateRoute.js @@ -1,22 +1,20 @@ -import React from 'react'; -import _ from 'lodash'; -import * as PropTypes from 'prop-types'; -import jwtDecode from 'jwt-decode'; -import { Route, Redirect, withRouter } from 'react-router-dom'; +import React from "react"; +import * as PropTypes from "prop-types"; +import { Route, Redirect, withRouter } from "react-router-dom"; +import { verify, getAccessToken } from "../../auth"; -const RESET_PASSWORD_PATH = '/reset-password'; +const RESET_PASSWORD_PATH = "/reset-password"; const PrivateRoute = ({ component: Component, history, ...rest }) => { - const accessToken = localStorage.getItem('auth-token'); - const isAuth = !_.isEmpty(accessToken); + const accessToken = getAccessToken(); const render = (props) => { - if (!isAuth) { + const { isTokenValid, isUserVerified } = verify(accessToken); + if (!isTokenValid) { return ; } - const decodedToken = jwtDecode(accessToken); - const { isVerified } = decodedToken; - if (!isVerified) { + + if (!isUserVerified) { return rest.path === RESET_PASSWORD_PATH ? ( ) : ( diff --git a/src/components/PrivateRoute/PrivateRoute.spec.js b/src/components/PrivateRoute/PrivateRoute.spec.js new file mode 100644 index 00000000..b962afa5 --- /dev/null +++ b/src/components/PrivateRoute/PrivateRoute.spec.js @@ -0,0 +1,108 @@ +/* eslint-disable import/no-extraneous-dependencies */ +import * as React from "react"; +import { Button } from "@material-ui/core"; +import { mount } from "enzyme"; +import { MemoryRouter } from "react-router-dom"; +import * as jwtDecode from "jwt-decode"; +import PrivateRoute from "./PrivateRoute"; + +jest.mock("react-router-dom", () => ({ + ...jest.requireActual("react-router-dom"), + Redirect: ({ to }) => `Redirected to ${to}`, +})); + +jest.mock("jwt-decode"); + +function PrivatePage() { + return

    Hello

    ; +} + +describe("JWT tests", () => { + it("should redirect to login when accessToken is empty", () => { + localStorage.setItem("auth-token", ""); + const wrapper = mount( + + + {" "} + + ); + expect(wrapper.exists(Button)).toBe(false); + expect(wrapper.text().includes("Redirected to /login")).toBe(true); + localStorage.clear(); + }); + + it("should redirect to login when accessToken is invalid", () => { + localStorage.setItem("auth-token", "someToken"); + const wrapper = mount( + + + {" "} + + ); + expect(wrapper.exists(Button)).toBe(false); + expect(wrapper.text().includes("Redirected to /login")).toBe(true); + localStorage.clear(); + }); + + it("should allow user to visit private page when the accessToken is valid and user is verified", () => { + localStorage.setItem("auth-token", "validToken"); + jwtDecode.mockImplementation(() => { + return { + role: "ADMIN", + isVerified: true, + exp: Date.now().valueOf() + 10000, + username: "admin", + }; + }); + + const wrapper = mount( + + + + ); + expect(wrapper.exists(PrivatePage)).toBe(true); + localStorage.clear(); + }); + + it("should take user to Login page when the accessToken is expired", () => { + localStorage.setItem("auth-token", "validToken"); + jwtDecode.mockImplementation(() => { + return { + role: "ADMIN", + isVerified: true, + exp: Date.now().valueOf() - 100, + username: "admin", + }; + }); + + const wrapper = mount( + + + + ); + expect(wrapper.exists(PrivatePage)).toBe(false); + expect(wrapper.text().includes("Redirected to /login")).toBe(true); + localStorage.clear(); + }); + + it("should redirect user to reset-password page when the accessToken is valid but the user is not verified", () => { + localStorage.setItem("auth-token", "validToken"); + jwtDecode.mockImplementation(() => { + return { + role: "ADMIN", + isVerified: false, + exp: Date.now().valueOf() + 1000, + username: "admin", + }; + }); + + const wrapper = mount( + + + + ); + expect(wrapper.exists(PrivatePage)).toBe(false); + expect(wrapper.text().includes("Redirected to /reset-password")).toBe(true); + localStorage.clear(); + }); +}); diff --git a/src/components/RequestType/RequestType.js b/src/components/RequestType/RequestType.js index a3e492f3..2117896a 100644 --- a/src/components/RequestType/RequestType.js +++ b/src/components/RequestType/RequestType.js @@ -4,8 +4,8 @@ import FormControl from '@material-ui/core/FormControl'; import FormGroup from '@material-ui/core/FormGroup'; import FormControlLabel from '@material-ui/core/FormControlLabel'; import Checkbox from '@material-ui/core/Checkbox'; -import RequestTypeStyles from './RequestType.style'; import Grid from '@material-ui/core/Grid'; +import RequestTypeStyles from './RequestType.style'; const RequestType = ({ requestTypes, handleChange }) => ( diff --git a/src/components/RequestType/__tests__/__snapshots__/RequestType.test.js.snap b/src/components/RequestType/__tests__/__snapshots__/RequestType.test.js.snap index 257608ab..f62ba647 100644 --- a/src/components/RequestType/__tests__/__snapshots__/RequestType.test.js.snap +++ b/src/components/RequestType/__tests__/__snapshots__/RequestType.test.js.snap @@ -361,11 +361,7 @@ exports[`RequestType should render properly 1`] = ` value="Patient History" > - } + checkedIcon={} className="check-box" classes={ Object { @@ -375,11 +371,7 @@ exports[`RequestType should render properly 1`] = ` } } color="primary" - icon={ - - } + icon={} inputProps={ Object { "data-indeterminate": false, @@ -389,26 +381,18 @@ exports[`RequestType should render properly 1`] = ` value="Patient History" > - } + checkedIcon={} className="check-box" classes={ Object { - "checked": "PrivateSwitchBase-checked-117 Mui-checked", - "disabled": "PrivateSwitchBase-disabled-118 Mui-disabled", - "input": "PrivateSwitchBase-input-119", - "root": "PrivateSwitchBase-root-116 MuiCheckbox-root MuiCheckbox-colorPrimary", + "checked": "PrivateSwitchBase-checked-2 Mui-checked", + "disabled": "PrivateSwitchBase-disabled-3 Mui-disabled", + "input": "PrivateSwitchBase-input-4", + "root": "PrivateSwitchBase-root-1 MuiCheckbox-root MuiCheckbox-colorPrimary", } } color="primary" - icon={ - - } + icon={} inputProps={ Object { "data-indeterminate": false, @@ -418,7 +402,7 @@ exports[`RequestType should render properly 1`] = ` value="Patient History" > - - + + - + - } + checkedIcon={} className="check-box" classes={ Object { @@ -816,11 +791,7 @@ exports[`RequestType should render properly 1`] = ` } } color="primary" - icon={ - - } + icon={} inputProps={ Object { "data-indeterminate": false, @@ -830,26 +801,18 @@ exports[`RequestType should render properly 1`] = ` value="Medications" > - } + checkedIcon={} className="check-box" classes={ Object { - "checked": "PrivateSwitchBase-checked-117 Mui-checked", - "disabled": "PrivateSwitchBase-disabled-118 Mui-disabled", - "input": "PrivateSwitchBase-input-119", - "root": "PrivateSwitchBase-root-116 MuiCheckbox-root MuiCheckbox-colorPrimary", + "checked": "PrivateSwitchBase-checked-2 Mui-checked", + "disabled": "PrivateSwitchBase-disabled-3 Mui-disabled", + "input": "PrivateSwitchBase-input-4", + "root": "PrivateSwitchBase-root-1 MuiCheckbox-root MuiCheckbox-colorPrimary", } } color="primary" - icon={ - - } + icon={} inputProps={ Object { "data-indeterminate": false, @@ -859,7 +822,7 @@ exports[`RequestType should render properly 1`] = ` value="Medications" > - - + + - + - } + checkedIcon={} className="check-box" classes={ Object { @@ -1257,11 +1211,7 @@ exports[`RequestType should render properly 1`] = ` } } color="primary" - icon={ - - } + icon={} inputProps={ Object { "data-indeterminate": false, @@ -1271,26 +1221,18 @@ exports[`RequestType should render properly 1`] = ` value="Diagnosis Lab" > - } + checkedIcon={} className="check-box" classes={ Object { - "checked": "PrivateSwitchBase-checked-117 Mui-checked", - "disabled": "PrivateSwitchBase-disabled-118 Mui-disabled", - "input": "PrivateSwitchBase-input-119", - "root": "PrivateSwitchBase-root-116 MuiCheckbox-root MuiCheckbox-colorPrimary", + "checked": "PrivateSwitchBase-checked-2 Mui-checked", + "disabled": "PrivateSwitchBase-disabled-3 Mui-disabled", + "input": "PrivateSwitchBase-input-4", + "root": "PrivateSwitchBase-root-1 MuiCheckbox-root MuiCheckbox-colorPrimary", } } color="primary" - icon={ - - } + icon={} inputProps={ Object { "data-indeterminate": false, @@ -1300,7 +1242,7 @@ exports[`RequestType should render properly 1`] = ` value="Diagnosis Lab" > - - + + - + - } + checkedIcon={} className="check-box" classes={ Object { @@ -1698,11 +1631,7 @@ exports[`RequestType should render properly 1`] = ` } } color="primary" - icon={ - - } + icon={} inputProps={ Object { "data-indeterminate": false, @@ -1712,26 +1641,18 @@ exports[`RequestType should render properly 1`] = ` value="Radiology Lab" > - } + checkedIcon={} className="check-box" classes={ Object { - "checked": "PrivateSwitchBase-checked-117 Mui-checked", - "disabled": "PrivateSwitchBase-disabled-118 Mui-disabled", - "input": "PrivateSwitchBase-input-119", - "root": "PrivateSwitchBase-root-116 MuiCheckbox-root MuiCheckbox-colorPrimary", + "checked": "PrivateSwitchBase-checked-2 Mui-checked", + "disabled": "PrivateSwitchBase-disabled-3 Mui-disabled", + "input": "PrivateSwitchBase-input-4", + "root": "PrivateSwitchBase-root-1 MuiCheckbox-root MuiCheckbox-colorPrimary", } } color="primary" - icon={ - - } + icon={} inputProps={ Object { "data-indeterminate": false, @@ -1741,7 +1662,7 @@ exports[`RequestType should render properly 1`] = ` value="Radiology Lab" > - - + + - + - } + checkedIcon={} className="check-box" classes={ Object { @@ -2139,11 +2051,7 @@ exports[`RequestType should render properly 1`] = ` } } color="primary" - icon={ - - } + icon={} inputProps={ Object { "data-indeterminate": false, @@ -2153,26 +2061,18 @@ exports[`RequestType should render properly 1`] = ` value="Observations" > - } + checkedIcon={} className="check-box" classes={ Object { - "checked": "PrivateSwitchBase-checked-117 Mui-checked", - "disabled": "PrivateSwitchBase-disabled-118 Mui-disabled", - "input": "PrivateSwitchBase-input-119", - "root": "PrivateSwitchBase-root-116 MuiCheckbox-root MuiCheckbox-colorPrimary", + "checked": "PrivateSwitchBase-checked-2 Mui-checked", + "disabled": "PrivateSwitchBase-disabled-3 Mui-disabled", + "input": "PrivateSwitchBase-input-4", + "root": "PrivateSwitchBase-root-1 MuiCheckbox-root MuiCheckbox-colorPrimary", } } color="primary" - icon={ - - } + icon={} inputProps={ Object { "data-indeterminate": false, @@ -2182,7 +2082,7 @@ exports[`RequestType should render properly 1`] = ` value="Observations" > - - + + - + { const [localPatientId, setPatientId] = useState(patientId); const [textInput, setTextInput] = useState(''); + const [isHealthIDNumber, setIsHealthIDNumber] = useState(false); const [selectedCmSuffixValue, setSelectedCmSuffixValue] = useState( cmConfigList.length > 0 ? cmConfigList[0].userIdSuffix : '' ); @@ -47,6 +48,11 @@ const SearchPatient = ({ }; const onChangeSearch = (e) => { + if(!isNaN(e.target.value[0])) { + setIsHealthIDNumber(true); + } + else + setIsHealthIDNumber(false); setTextInput(e.target.value); onSearchResetState(); }; @@ -72,13 +78,13 @@ const SearchPatient = ({ } }} /> - {cmConfigList.map((value) => ( {value.userIdSuffix} ))} - + } { @@ -25,7 +25,7 @@ export class BundleContext { } if (entry.fullUrl) { - console.warn("Resource.id is null. Falling back on default implementation of fullUrl format urn:uuid:uuid. Bundle entry fullUrl=" + entry.fullUrl); + console.warn(`Resource.id is null. Falling back on default implementation of fullUrl format urn:uuid:uuid. Bundle entry fullUrl=${ entry.fullUrl}`); // TODO very simplistic regex, looking for the last colon till the end. will work for urn:uuid:id or similar. const matches = entry.fullUrl.match(/[^:]+$/); if (matches) { @@ -40,7 +40,7 @@ export class BundleContext { if (reference.type) return reference.type; const ref = reference.reference; if (ref.startsWith("#")) { - console.error("Unexpected resource reference to contained resources. Can not resolve:" + ref); + console.error(`Unexpected resource reference to contained resources. Can not resolve:${ ref}`); return undefined; } return ref.substring(0, ref.indexOf("/")); diff --git a/src/components/common/HealthInfo/DaywiseGroup.js b/src/components/common/HealthInfo/DaywiseGroup.js index 0164f67b..78aa3050 100644 --- a/src/components/common/HealthInfo/DaywiseGroup.js +++ b/src/components/common/HealthInfo/DaywiseGroup.js @@ -145,7 +145,7 @@ class HealthInfoProcessor { } } else { this.sortBundleEntryForProcessing(bundle); - console.log('procecssing bundle: ' + bundle.id); + console.log(`procecssing bundle: ${ bundle.id}`); bundle.entry.forEach(e => { const resourceProcessor = this.getResourceProcessor(e); if (resourceProcessor) { diff --git a/src/components/common/HealthInfo/FhirResourceProcessors.js b/src/components/common/HealthInfo/FhirResourceProcessors.js index 3fa82b60..96f8c4e9 100644 --- a/src/components/common/HealthInfo/FhirResourceProcessors.js +++ b/src/components/common/HealthInfo/FhirResourceProcessors.js @@ -286,7 +286,7 @@ export class EncounterProcessor extends FhirResourceProcessor { process(encounter, bundleContext) { if (encounter.diagnosis) { encounter.diagnosis.forEach((diag) => { - let condition = bundleContext.findReference('Condition', diag.condition); + const condition = bundleContext.findReference('Condition', diag.condition); if (condition) { diag.condition.targetResource = condition; this.addParentResource(condition, encounter); diff --git a/src/components/common/HealthInfo/FhirResourcesUtils.js b/src/components/common/HealthInfo/FhirResourcesUtils.js index 686c8d44..cc22ac59 100644 --- a/src/components/common/HealthInfo/FhirResourcesUtils.js +++ b/src/components/common/HealthInfo/FhirResourcesUtils.js @@ -1,3 +1,6 @@ +import moment from "moment"; +import Config from "../../../Config"; + const processingOrder = [ 'bundle', 'composition', @@ -148,20 +151,17 @@ const getConceptDisplay = function (codeableConcept) { return coding.display || coding.code; }; -const leftPadZero = (n) => { - return n > 9 ? `${n}` : `0${n}`; -}; const formatDateString = function (aDate, includeTime) { if (aDate) { const dateString = aDate.toString(); if (dateString.length > 0) { - const dt = new Date(dateString); - let dtStr = `${leftPadZero(dt.getDate())}/${leftPadZero(dt.getMonth() + 1)}/${dt.getFullYear()}`; + const momentDate = moment.utc(aDate); + let dt = momentDate.utcOffset(Config.TIMEZONE_OFFSET).format('DD/MM/YYYY'); if (includeTime) { - dtStr = `${dtStr} ${leftPadZero(dt.getHours())}:${leftPadZero(dt.getMinutes())}`; + dt = momentDate.utcOffset(Config.TIMEZONE_OFFSET).format('DD/MM/YYYY hh:mm A'); } - return dtStr; + return dt; } return ''; } diff --git a/src/pages/LandingPage/LandingPage.js b/src/pages/LandingPage/LandingPage.js index ede4fbe6..7e20f76f 100644 --- a/src/pages/LandingPage/LandingPage.js +++ b/src/pages/LandingPage/LandingPage.js @@ -105,9 +105,11 @@ const LandingPage = ({
    - + diff --git a/src/pages/LoginPage/LoginPage.js b/src/pages/LoginPage/LoginPage.js index 3f1c5d2b..367a129d 100644 --- a/src/pages/LoginPage/LoginPage.js +++ b/src/pages/LoginPage/LoginPage.js @@ -1,86 +1,84 @@ -import React, { useState } from 'react'; -import * as PropTypes from 'prop-types'; -import Avatar from '@material-ui/core/Avatar'; -import Button from '@material-ui/core/Button'; -import CssBaseline from '@material-ui/core/CssBaseline'; -import TextField from '@material-ui/core/TextField'; -// import FormControlLabel from "@material-ui/core/FormControlLabel"; -// import Checkbox from "@material-ui/core/Checkbox"; -// import Grid from "@material-ui/core/Grid"; -import Link from '@material-ui/core/Link'; -import Box from '@material-ui/core/Box'; -import LockOutlinedIcon from '@material-ui/icons/LockOutlined'; -import Typography from '@material-ui/core/Typography'; -import { makeStyles } from '@material-ui/core/styles'; -import Container from '@material-ui/core/Container'; -import { Redirect } from 'react-router-dom'; -import Visibility from '@material-ui/icons/Visibility'; -import VisibilityOff from '@material-ui/icons/VisibilityOff'; -import OutlinedInput from '@material-ui/core/OutlinedInput'; -import InputAdornment from '@material-ui/core/InputAdornment'; -import IconButton from '@material-ui/core/IconButton'; -import InputLabel from '@material-ui/core/InputLabel'; -import FormControl from '@material-ui/core/FormControl'; -import _ from 'lodash'; +import React, { useState } from "react"; +import * as PropTypes from "prop-types"; +import Avatar from "@material-ui/core/Avatar"; +import Button from "@material-ui/core/Button"; +import CssBaseline from "@material-ui/core/CssBaseline"; +import TextField from "@material-ui/core/TextField"; +import LockOutlinedIcon from "@material-ui/icons/LockOutlined"; +import Typography from "@material-ui/core/Typography"; +import { makeStyles } from "@material-ui/core/styles"; +import Container from "@material-ui/core/Container"; +import { Redirect } from "react-router-dom"; +import Visibility from "@material-ui/icons/Visibility"; +import VisibilityOff from "@material-ui/icons/VisibilityOff"; +import OutlinedInput from "@material-ui/core/OutlinedInput"; +import InputAdornment from "@material-ui/core/InputAdornment"; +import IconButton from "@material-ui/core/IconButton"; +import InputLabel from "@material-ui/core/InputLabel"; +import FormControl from "@material-ui/core/FormControl"; +import _ from "lodash"; +import { getAccessToken, verify } from "../../auth"; +import Config from "../../Config"; function SupportInformation() { return ( - - For access please send an email to {SUPPORT_EMAIL} with your registered client id + + For access please send an email to {Config.SUPPORT_EMAIL} with your + registered client id ); } -const useStyles = makeStyles(theme => ({ +const useStyles = makeStyles((theme) => ({ paper: { marginTop: theme.spacing(8), - display: 'flex', - flexDirection: 'column', - alignItems: 'center' + display: "flex", + flexDirection: "column", + alignItems: "center", }, avatar: { margin: theme.spacing(1), - backgroundColor: theme.palette.secondary.main + backgroundColor: theme.palette.secondary.main, }, form: { - width: '100%', // Fix IE 11 issue. - marginTop: theme.spacing(1) + width: "100%", // Fix IE 11 issue. + marginTop: theme.spacing(1), }, textField: { - margin: 0 + margin: 0, }, formControl: { - margin: theme.spacing(1, 0) + margin: theme.spacing(1, 0), }, submit: { - margin: theme.spacing(3, 0, 2) + margin: theme.spacing(3, 0, 2), }, error: { paddingTop: 20, - color: '#f44336' - } + color: "#f44336", + }, })); export default function SignIn({ onSignIn, error }) { const classes = useStyles(); - const [userName, setUserName] = useState(''); - const [password, setPassword] = useState(''); + const [userName, setUserName] = useState(""); + const [password, setPassword] = useState(""); const [showPassword, setShowPassword] = useState(false); - const handleMouseDownPassword = event => { + const handleMouseDownPassword = (event) => { event.preventDefault(); }; - - const isAuth = localStorage.getItem('auth-token'); + const accessToken = getAccessToken(); + const { isTokenValid } = verify(accessToken); return (
    - { _.isNil(SUPPORT_EMAIL) ? undefined : SupportInformation()} + {_.isNil(Config.SUPPORT_EMAIL) ? undefined : SupportInformation()} - {isAuth && } + {isTokenValid && }
    @@ -110,7 +108,7 @@ export default function SignIn({ onSignIn, error }) { autoComplete="userName" autoFocus value={userName} - onChange={e => setUserName(e.target.value)} + onChange={(e) => setUserName(e.target.value)} /> setPassword(e.target.value)} + onChange={(e) => setPassword(e.target.value)} endAdornment={ - {/* } - label="Remember me" - /> */} - {/* - - - Forgot password? - - - - - {"Don't have an account? Sign Up"} - - - */}
    @@ -187,9 +169,9 @@ export default function SignIn({ onSignIn, error }) { SignIn.propTypes = { error: PropTypes.bool, - onSignIn: PropTypes.func.isRequired + onSignIn: PropTypes.func.isRequired, }; SignIn.defaultProps = { - error: false + error: false, }; diff --git a/src/pages/PatientHealthInformation/PatientHealthInformation.view.js b/src/pages/PatientHealthInformation/PatientHealthInformation.view.js index 70245939..f23fd802 100644 --- a/src/pages/PatientHealthInformation/PatientHealthInformation.view.js +++ b/src/pages/PatientHealthInformation/PatientHealthInformation.view.js @@ -88,8 +88,7 @@ const PatientHealthInformation = ({ const handleSnackbarClose = () => setSnackbarOpen(false); let content = renderLoadingMessage(); - - if (isHealthInfoAvailable) { + if (isHealthInfoAvailable && !error) { content = renderHealthInfo( patientData, dateArray, diff --git a/src/pages/RequestAccess/RequestAccess.js b/src/pages/RequestAccess/RequestAccess.js index 875769e3..04a4de93 100644 --- a/src/pages/RequestAccess/RequestAccess.js +++ b/src/pages/RequestAccess/RequestAccess.js @@ -53,12 +53,12 @@ const RequestAccess = ({ }); }; const handleStarteDateChange = (date) => { - var startDate = date; + const startDate = date; setSelectedStartDate(startDate); }; const handleEndDateChange = (date) => { - var startDate = selectedStartDate; - var endDate = date; + const startDate = selectedStartDate; + const endDate = date; if (startDate.getTime() < endDate.getTime()) { setSelectedEndDate(endDate); } @@ -84,7 +84,7 @@ const RequestAccess = ({ - + diff --git a/src/redux/apiWrapper.js b/src/redux/apiWrapper.js index 7e9ee9b8..8643cdd9 100644 --- a/src/redux/apiWrapper.js +++ b/src/redux/apiWrapper.js @@ -1,12 +1,13 @@ import axios from 'axios'; import { defaultHeaders } from '../constants'; +import Config from "../Config"; export default ( method, url, data, headers = defaultHeaders, - baseURL = BACKEND_BASE_URL + BACKEND_API_PATH, + baseURL = Config.BACKEND_BASE_URL + Config.BACKEND_API_PATH, ) => axios({ headers, method, diff --git a/src/redux/sagas/loadCmConfigSaga.js b/src/redux/sagas/loadCmConfigSaga.js index cf75aa1d..32e8f42f 100644 --- a/src/redux/sagas/loadCmConfigSaga.js +++ b/src/redux/sagas/loadCmConfigSaga.js @@ -1,5 +1,5 @@ -import { APP_CONFIG_ACTION_TYPES } from "../actions/configAppActions"; import { call, put } from "redux-saga/effects"; +import { APP_CONFIG_ACTION_TYPES } from "../actions/configAppActions"; import loadCmConfigApi from "../apiCalls/loadCmConfig"; function* fetchConfigRequest(action) { diff --git a/src/redux/sagas/signInSaga.js b/src/redux/sagas/signInSaga.js index a5e7c6ec..bb25672b 100644 --- a/src/redux/sagas/signInSaga.js +++ b/src/redux/sagas/signInSaga.js @@ -2,6 +2,7 @@ import { call, put } from 'redux-saga/effects'; import { ACTION_TYPES } from '../actions/onSignInActions'; import signInApi from '../apiCalls/signInApi'; import history from '../../history'; +import Config from "../../Config"; function* onSignIn(action) { try { @@ -26,7 +27,7 @@ function* onSignInSuccess(action) { 'auth-token', action.payload.data.accessToken ); - history.push(BASE_NAME); + history.push(Config.BASE_NAME); } export default { diff --git a/webpack/webpack.dev.config.js b/webpack/webpack.dev.config.js index 979bb8f2..e9fac2cc 100644 --- a/webpack/webpack.dev.config.js +++ b/webpack/webpack.dev.config.js @@ -1,26 +1,5 @@ -var webpack = require("webpack"); var path = require("path"); var commonWebpackConfig = require("./webpack.common"); -const dotenv = require("dotenv").config(); -if (dotenv.error) { - throw dotenv.error; -} - -if (!process.env.BACKEND_BASE_URL) { - throw "BACKEND_BASE_URL not found"; -} -if (!process.env.BACKEND_API_PATH) { - throw "BACKEND_API_PATH not found"; -} -if (!process.env.DICOM_SERVER_PATH) { - throw "DICOM_SERVER_PATH not found"; -} -if (!process.env.BASE_NAME) { - throw "BASE_NAME not found"; -} -if (!process.env.REACT_APP_SITE_TITLE) { - throw "REACT_APP_SITE_TITLE not found"; -} var parentDir = path.join(__dirname, "../"); @@ -29,15 +8,6 @@ module.exports = { ...commonWebpackConfig, plugins: [ ...commonWebpackConfig.plugins, - new webpack.DefinePlugin({ - BACKEND_BASE_URL: JSON.stringify(process.env.BACKEND_BASE_URL), - BASE_NAME: JSON.stringify(process.env.BASE_NAME), - BACKEND_API_PATH: JSON.stringify(process.env.BACKEND_API_PATH), - DICOM_SERVER_PATH: JSON.stringify(process.env.DICOM_SERVER_PATH), - DICOM_BASE_URL: JSON.stringify(process.env.DICOM_BASE_URL), - REACT_APP_SITE_TITLE: JSON.stringify(process.env.REACT_APP_SITE_TITLE), - SUPPORT_EMAIL: JSON.stringify(process.env.SUPPORT_EMAIL) - }), ], devServer: { contentBase: parentDir, diff --git a/webpack/webpack.prod.config.js b/webpack/webpack.prod.config.js deleted file mode 100644 index 05b0e920..00000000 --- a/webpack/webpack.prod.config.js +++ /dev/null @@ -1,35 +0,0 @@ -var webpack = require("webpack"); -var commonWebpackConfig = require("./webpack.common"); -const _ = require("dotenv").config(); - -if (!process.env.BACKEND_BASE_URL) { - throw "BACKEND_BASE_URL not found"; -} -if (!process.env.BASE_NAME) { - throw "BASE_NAME not found"; -} -if (!process.env.BACKEND_API_PATH) { - throw "BACKEND_API_PATH not found"; -} -if (!process.env.DICOM_SERVER_PATH) { - throw "DICOM_SERVER_PATH not found"; -} -if (!process.env.REACT_APP_SITE_TITLE) { - throw "REACT_APP_SITE_TITLE not found"; -} - -module.exports = { - mode: "production", - ...commonWebpackConfig, - plugins: [ - ...commonWebpackConfig.plugins, - new webpack.DefinePlugin({ - BACKEND_BASE_URL: JSON.stringify(process.env.BACKEND_BASE_URL), - BASE_NAME: JSON.stringify(process.env.BASE_NAME), - BACKEND_API_PATH: JSON.stringify(process.env.BACKEND_API_PATH), - DICOM_SERVER_PATH: JSON.stringify(process.env.DICOM_SERVER_PATH), - REACT_APP_SITE_TITLE: JSON.stringify(process.env.REACT_APP_SITE_TITLE), - SUPPORT_EMAIL: JSON.stringify(process.env.SUPPORT_EMAIL) - }) - ] -};