From 61b705bfe06cf604ce103e72fe930006c1af408a Mon Sep 17 00:00:00 2001 From: James Hughes Date: Tue, 4 Oct 2022 12:42:58 +0100 Subject: [PATCH 1/9] WIP: adding loading spinner --- src/components/UI/LoadingSpinner.css | 45 ++++++++++++++++++++++++++ src/components/UI/LoadingSpinner.tsx | 19 +++++++++++ src/components/fhir/FhirAuthoriser.tsx | 10 +++++- 3 files changed, 73 insertions(+), 1 deletion(-) create mode 100644 src/components/UI/LoadingSpinner.css create mode 100644 src/components/UI/LoadingSpinner.tsx diff --git a/src/components/UI/LoadingSpinner.css b/src/components/UI/LoadingSpinner.css new file mode 100644 index 0000000..de41bde --- /dev/null +++ b/src/components/UI/LoadingSpinner.css @@ -0,0 +1,45 @@ +.lds-dual-ring { + display: inline-block; + width: 64px; + height: 64px; + z-index: 1; +} + +.lds-dual-ring:after { + content: " "; + display: block; + width: 46px; + height: 46px; + margin: 1px; + border-radius: 50%; + border: 5px solid #ffffff; + border-color: #ffffff transparent #ffffff transparent; + animation: lds-dual-ring 1.2s linear infinite; + z-index: 1; +} + +.loading-spinner__overlay { + height: 100%; + width: 100%; + position: absolute; + top: 0; + left: 0; + background: rgba(0, 0, 0, 0.75); + display: flex; + justify-content: center; + align-items: center; + z-index: 1; +} + +.loading-spinner__message { + color: #ffffff; +} + +@keyframes lds-dual-ring { + 0% { + transform: rotate(0deg); + } + 100% { + transform: rotate(360deg); + } +} diff --git a/src/components/UI/LoadingSpinner.tsx b/src/components/UI/LoadingSpinner.tsx new file mode 100644 index 0000000..142d090 --- /dev/null +++ b/src/components/UI/LoadingSpinner.tsx @@ -0,0 +1,19 @@ +import { FC } from "react"; + +import "./LoadingSpinner.css"; + +interface Props { + asOverlay: boolean; + message: string; +} + +const LoadingSpinner: FC = (props) => { + return ( +
+
+
{props.message}
+
+ ); +}; + +export default LoadingSpinner; diff --git a/src/components/fhir/FhirAuthoriser.tsx b/src/components/fhir/FhirAuthoriser.tsx index 74d76ef..82eb685 100644 --- a/src/components/fhir/FhirAuthoriser.tsx +++ b/src/components/fhir/FhirAuthoriser.tsx @@ -1,6 +1,7 @@ import { FC, useEffect, useState } from "react"; import { oauth2 as SMART } from "fhirclient"; +import LoadingSpinner from "../UI/LoadingSpinner" import ModalWrapper from "../UI/ModalWrapper" import { ModalState } from "../UI/ModalWrapper" @@ -15,9 +16,12 @@ const CLIENT_SECRET = process.env.REACT_APP_CLIENT_SECRET; * @constructor */ const FhirAuthoriser: FC = () => { + const [isLoading, setIsLoading] = useState(false); const [modal, setModal] = useState(null); useEffect(() => { + setIsLoading(true); + SMART.authorize({ iss: FHIR_URL, redirectUri: "#/new_report", @@ -30,13 +34,17 @@ const FhirAuthoriser: FC = () => { setModal({ message: 'Something went wrong connecting to the FHIR authoriser. Please try again later.', isError: true, - }); + }); }) + + setIsLoading(false); }, []); return ( <> + {isLoading && } setModal(null)} /> +

Connecting to FHIR back end...

) From 04cee186d3fb20a30ae1a84bc82a1b6fee4563d6 Mon Sep 17 00:00:00 2001 From: James Hughes Date: Tue, 4 Oct 2022 14:10:34 +0100 Subject: [PATCH 2/9] loading spinner now using css module --- .../{LoadingSpinner.css => LoadingSpinner.module.css} | 0 src/components/UI/LoadingSpinner.tsx | 10 ++++++---- 2 files changed, 6 insertions(+), 4 deletions(-) rename src/components/UI/{LoadingSpinner.css => LoadingSpinner.module.css} (100%) diff --git a/src/components/UI/LoadingSpinner.css b/src/components/UI/LoadingSpinner.module.css similarity index 100% rename from src/components/UI/LoadingSpinner.css rename to src/components/UI/LoadingSpinner.module.css diff --git a/src/components/UI/LoadingSpinner.tsx b/src/components/UI/LoadingSpinner.tsx index 142d090..86dfc20 100644 --- a/src/components/UI/LoadingSpinner.tsx +++ b/src/components/UI/LoadingSpinner.tsx @@ -1,6 +1,8 @@ import { FC } from "react"; -import "./LoadingSpinner.css"; +// import "./LoadingSpinner.css"; + +import classes from "./LoadingSpinner.module.css" interface Props { asOverlay: boolean; @@ -9,9 +11,9 @@ interface Props { const LoadingSpinner: FC = (props) => { return ( -
-
-
{props.message}
+
+
+
{props.message}
); }; From b001f2a9efd11eaba55a2a97d41ee5fba534b734 Mon Sep 17 00:00:00 2001 From: James Hughes Date: Tue, 4 Oct 2022 14:13:25 +0100 Subject: [PATCH 3/9] removed unused import --- src/components/UI/LoadingSpinner.tsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/components/UI/LoadingSpinner.tsx b/src/components/UI/LoadingSpinner.tsx index 86dfc20..cb8d532 100644 --- a/src/components/UI/LoadingSpinner.tsx +++ b/src/components/UI/LoadingSpinner.tsx @@ -1,7 +1,5 @@ import { FC } from "react"; -// import "./LoadingSpinner.css"; - import classes from "./LoadingSpinner.module.css" interface Props { From 1465f895da4055141a58a7ee9cc531a42a9200ba Mon Sep 17 00:00:00 2001 From: James Hughes Date: Tue, 4 Oct 2022 14:19:07 +0100 Subject: [PATCH 4/9] added optional loading spinner message --- src/components/UI/LoadingSpinner.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/UI/LoadingSpinner.tsx b/src/components/UI/LoadingSpinner.tsx index cb8d532..02991f1 100644 --- a/src/components/UI/LoadingSpinner.tsx +++ b/src/components/UI/LoadingSpinner.tsx @@ -4,7 +4,7 @@ import classes from "./LoadingSpinner.module.css" interface Props { asOverlay: boolean; - message: string; + message?: string; } const LoadingSpinner: FC = (props) => { From 5565311eb032af6973c235461055f28384995c6e Mon Sep 17 00:00:00 2001 From: James Hughes Date: Tue, 4 Oct 2022 17:37:35 +0100 Subject: [PATCH 5/9] applying auto formatting --- src/components/UI/Backdrop.module.css | 14 ++-- src/components/UI/Backdrop.tsx | 13 ++-- src/components/UI/Card.module.css | 10 +-- src/components/UI/Card.tsx | 6 +- src/components/UI/LoadingSpinner.module.css | 62 ++++++++-------- src/components/UI/LoadingSpinner.tsx | 18 ++--- src/components/UI/Modal.module.css | 76 +++++++++---------- src/components/UI/Modal.tsx | 82 ++++++++++----------- src/components/UI/ModalWrapper.tsx | 38 +++++----- src/components/fhir/FhirAuthoriser.tsx | 24 +++--- 10 files changed, 167 insertions(+), 176 deletions(-) diff --git a/src/components/UI/Backdrop.module.css b/src/components/UI/Backdrop.module.css index f65a311..79076d5 100644 --- a/src/components/UI/Backdrop.module.css +++ b/src/components/UI/Backdrop.module.css @@ -1,9 +1,9 @@ .backdrop { - position: fixed; - top: 0; - left: 0; - width: 100%; - height: 100vh; - background: rgba(0, 0, 0, 0.75); - z-index: 10; + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100vh; + background: rgba(0, 0, 0, 0.75); + z-index: 10; } diff --git a/src/components/UI/Backdrop.tsx b/src/components/UI/Backdrop.tsx index 1b97a66..585d3b6 100644 --- a/src/components/UI/Backdrop.tsx +++ b/src/components/UI/Backdrop.tsx @@ -4,16 +4,15 @@ import ReactDOM from "react-dom"; import classes from "./Backdrop.module.css"; interface Props { - onClick: () => void; + onClick: () => void; } -const Backdrop: FC = (props:Props) => { - const backdropElement: HTMLElement | null = document.getElementById("backdrop-hook"); +const Backdrop: FC = (props: Props) => { + const backdropElement: HTMLElement | null = document.getElementById("backdrop-hook"); - return backdropElement ? ReactDOM.createPortal( -
, - backdropElement - ) : null; + return backdropElement + ? ReactDOM.createPortal(
, backdropElement) + : null; }; export default Backdrop; diff --git a/src/components/UI/Card.module.css b/src/components/UI/Card.module.css index a107078..79e9f44 100644 --- a/src/components/UI/Card.module.css +++ b/src/components/UI/Card.module.css @@ -1,7 +1,7 @@ .card { - padding: 1rem; - margin: 1rem; - box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2); - border-radius: 0.5rem; - background-color: white; + padding: 1rem; + margin: 1rem; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2); + border-radius: 0.5rem; + background-color: white; } diff --git a/src/components/UI/Card.tsx b/src/components/UI/Card.tsx index cef8a76..57a2894 100644 --- a/src/components/UI/Card.tsx +++ b/src/components/UI/Card.tsx @@ -7,11 +7,7 @@ import { FC } from "react"; * @constructor */ const Card: FC = (props) => { - return ( -
- {props.children} -
- ); + return
{props.children}
; }; export default Card; diff --git a/src/components/UI/LoadingSpinner.module.css b/src/components/UI/LoadingSpinner.module.css index de41bde..aa9b326 100644 --- a/src/components/UI/LoadingSpinner.module.css +++ b/src/components/UI/LoadingSpinner.module.css @@ -1,45 +1,45 @@ .lds-dual-ring { - display: inline-block; - width: 64px; - height: 64px; - z-index: 1; + display: inline-block; + width: 64px; + height: 64px; + z-index: 1; } .lds-dual-ring:after { - content: " "; - display: block; - width: 46px; - height: 46px; - margin: 1px; - border-radius: 50%; - border: 5px solid #ffffff; - border-color: #ffffff transparent #ffffff transparent; - animation: lds-dual-ring 1.2s linear infinite; - z-index: 1; + content: " "; + display: block; + width: 46px; + height: 46px; + margin: 1px; + border-radius: 50%; + border: 5px solid #ffffff; + border-color: #ffffff transparent #ffffff transparent; + animation: lds-dual-ring 1.2s linear infinite; + z-index: 1; } .loading-spinner__overlay { - height: 100%; - width: 100%; - position: absolute; - top: 0; - left: 0; - background: rgba(0, 0, 0, 0.75); - display: flex; - justify-content: center; - align-items: center; - z-index: 1; + height: 100%; + width: 100%; + position: absolute; + top: 0; + left: 0; + background: rgba(0, 0, 0, 0.75); + display: flex; + justify-content: center; + align-items: center; + z-index: 1; } .loading-spinner__message { - color: #ffffff; + color: #ffffff; } @keyframes lds-dual-ring { - 0% { - transform: rotate(0deg); - } - 100% { - transform: rotate(360deg); - } + 0% { + transform: rotate(0deg); + } + 100% { + transform: rotate(360deg); + } } diff --git a/src/components/UI/LoadingSpinner.tsx b/src/components/UI/LoadingSpinner.tsx index 02991f1..5f1c96c 100644 --- a/src/components/UI/LoadingSpinner.tsx +++ b/src/components/UI/LoadingSpinner.tsx @@ -1,19 +1,19 @@ import { FC } from "react"; -import classes from "./LoadingSpinner.module.css" +import classes from "./LoadingSpinner.module.css"; interface Props { - asOverlay: boolean; - message?: string; + asOverlay: boolean; + message?: string; } const LoadingSpinner: FC = (props) => { - return ( -
-
-
{props.message}
-
- ); + return ( +
+
+
{props.message}
+
+ ); }; export default LoadingSpinner; diff --git a/src/components/UI/Modal.module.css b/src/components/UI/Modal.module.css index 4489b24..d4b3972 100644 --- a/src/components/UI/Modal.module.css +++ b/src/components/UI/Modal.module.css @@ -1,73 +1,73 @@ .modal { - z-index: 100; - position: fixed; - top: 22vh; - left: 10%; - width: 80%; - background: white; - box-shadow: 0 2px 8px rgba(0, 0, 0, 0.26); - border-radius: 8px; + z-index: 100; + position: fixed; + top: 22vh; + left: 10%; + width: 80%; + background: white; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.26); + border-radius: 8px; } .modal__header { - width: 100%; - padding: 1rem 0.5rem; - background: #2a006e; - color: white; + width: 100%; + padding: 1rem 0.5rem; + background: #2a006e; + color: white; } .modal__header h2 { - margin: 0.5rem; + margin: 0.5rem; } .modal__content { - padding: 1rem 0.5rem; - color: black; + padding: 1rem 0.5rem; + color: black; } .modal__footer { - padding: 1rem 0.5rem; + padding: 1rem 0.5rem; } .modal__btn { - color: white; - text-align: center; - padding: 0.5rem; - border-radius: 0.3rem; - background-color: rgb(110, 44, 186); - width: 100px; - cursor: pointer; + color: white; + text-align: center; + padding: 0.5rem; + border-radius: 0.3rem; + background-color: rgb(110, 44, 186); + width: 100px; + cursor: pointer; } .error { - background: rgb(204, 92, 92); + background: rgb(204, 92, 92); } @media (min-width: 768px) { - .modal { - left: calc(50% - 20rem); - width: 40rem; - } + .modal { + left: calc(50% - 20rem); + width: 40rem; + } } .modal-enter { - transform: translateY(-10rem); - opacity: 0; + transform: translateY(-10rem); + opacity: 0; } .modal-enter-active { - transform: translateY(0); - opacity: 1; - transition: all 200ms; + transform: translateY(0); + opacity: 1; + transition: all 200ms; } .modal-exit { - transform: translateY(0); - opacity: 1; + transform: translateY(0); + opacity: 1; } .modal-exit-active { - transform: translateY(-10rem); - opacity: 0; - transition: all 200ms; + transform: translateY(-10rem); + opacity: 0; + transition: all 200ms; } diff --git a/src/components/UI/Modal.tsx b/src/components/UI/Modal.tsx index 16eb6aa..a533d98 100644 --- a/src/components/UI/Modal.tsx +++ b/src/components/UI/Modal.tsx @@ -5,61 +5,53 @@ import Backdrop from "./Backdrop"; import classes from "./Modal.module.css"; interface ModalOverlayProps { - className?: string; - headerClass?: string; - header: string; - onSubmit?: () => void | undefined; - contentClass?: string; - footerClass?: string; - footer?: ReactElement; - children: ReactElement; - isError: boolean | null | undefined; + className?: string; + headerClass?: string; + header: string; + onSubmit?: () => void | undefined; + contentClass?: string; + footerClass?: string; + footer?: ReactElement; + children: ReactElement; + isError: boolean | null | undefined; } interface ModalProps extends ModalOverlayProps { - show: boolean; - onCancel: () => void; + show: boolean; + onCancel: () => void; } -const ModalOverlay: FC = (props:ModalOverlayProps) => { - const errorClass = props.isError ? 'error' : 'info'; +const ModalOverlay: FC = (props: ModalOverlayProps) => { + const errorClass = props.isError ? "error" : "info"; - const content = ( -
-
-

{props.header}

-
-
event.preventDefault() - } - > -
- {props.children} -
+ const content = ( +
+
+

{props.header}

+
+ event.preventDefault()}> +
{props.children}
-
- {props.footer} -
- -
- ); - - const modalElement: HTMLElement | null = document.getElementById("modal-hook"); - return modalElement ? ReactDOM.createPortal(content, modalElement) : null; +
{props.footer}
+ +
+ ); + + const modalElement: HTMLElement | null = document.getElementById("modal-hook"); + return modalElement ? ReactDOM.createPortal(content, modalElement) : null; }; const Modal: FC = (props) => { - return ( - <> - {props.show && - <> - - - - } - - ); + return ( + <> + {props.show && ( + <> + + + + )} + + ); }; export default Modal; diff --git a/src/components/UI/ModalWrapper.tsx b/src/components/UI/ModalWrapper.tsx index 126b475..30adae9 100644 --- a/src/components/UI/ModalWrapper.tsx +++ b/src/components/UI/ModalWrapper.tsx @@ -4,30 +4,34 @@ import Modal from "./Modal"; import classes from "./Modal.module.css"; export interface ModalState { - message: string | null | undefined; - isError: boolean | null | undefined; + message: string | null | undefined; + isError: boolean | null | undefined; } export interface Props { - onClear: () => void; - isError: boolean | null | undefined; - modalMessage: string | null | undefined; + onClear: () => void; + isError: boolean | null | undefined; + modalMessage: string | null | undefined; } const ModalWrapper: FC = (props: Props) => { - const { onClear, isError, modalMessage } = props; + const { onClear, isError, modalMessage } = props; - return ( - Okay} - > -

{modalMessage}

-
- ); + return ( + + Okay + + } + > +

{modalMessage}

+
+ ); }; export default ModalWrapper; diff --git a/src/components/fhir/FhirAuthoriser.tsx b/src/components/fhir/FhirAuthoriser.tsx index 82eb685..7d6f434 100644 --- a/src/components/fhir/FhirAuthoriser.tsx +++ b/src/components/fhir/FhirAuthoriser.tsx @@ -1,9 +1,9 @@ import { FC, useEffect, useState } from "react"; import { oauth2 as SMART } from "fhirclient"; -import LoadingSpinner from "../UI/LoadingSpinner" -import ModalWrapper from "../UI/ModalWrapper" -import { ModalState } from "../UI/ModalWrapper" +import LoadingSpinner from "../UI/LoadingSpinner"; +import ModalWrapper from "../UI/ModalWrapper"; +import { ModalState } from "../UI/ModalWrapper"; const FHIR_URL = process.env.REACT_APP_FHIR_URL; const CLIENT_ID = process.env.REACT_APP_CLIENT_ID; @@ -28,26 +28,26 @@ const FhirAuthoriser: FC = () => { clientId: CLIENT_ID, clientSecret: CLIENT_SECRET, }) - .then() - .catch((error)=> { - console.log(error); - setModal({ - message: 'Something went wrong connecting to the FHIR authoriser. Please try again later.', - isError: true, + .then() + .catch((error) => { + console.log(error); + setModal({ + message: "Something went wrong connecting to the FHIR authoriser. Please try again later.", + isError: true, + }); }); - }) setIsLoading(false); }, []); return ( <> - {isLoading && } + {isLoading && } setModal(null)} />

Connecting to FHIR back end...

- ) + ); }; export default FhirAuthoriser; From a828c88aefdad63f59ac69f80f737dd1f84963b1 Mon Sep 17 00:00:00 2001 From: James Hughes Date: Tue, 4 Oct 2022 17:43:38 +0100 Subject: [PATCH 6/9] style update --- src/components/UI/Modal.module.css | 1 - 1 file changed, 1 deletion(-) diff --git a/src/components/UI/Modal.module.css b/src/components/UI/Modal.module.css index 91d85b7..fc3f215 100644 --- a/src/components/UI/Modal.module.css +++ b/src/components/UI/Modal.module.css @@ -6,7 +6,6 @@ width: 80%; background: white; box-shadow: 0 2px 8px rgba(0, 0, 0, 0.26); - border-radius: 8px; } .modal__header { From c6dda96b7e7b37d2cec7c9ec416bc0a1c9dc0562 Mon Sep 17 00:00:00 2001 From: James Hughes Date: Tue, 4 Oct 2022 17:48:29 +0100 Subject: [PATCH 7/9] removed unused useEffect --- src/components/reports/ReportForm.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/reports/ReportForm.tsx b/src/components/reports/ReportForm.tsx index b5d4c1e..07fbc3e 100644 --- a/src/components/reports/ReportForm.tsx +++ b/src/components/reports/ReportForm.tsx @@ -1,4 +1,4 @@ -import { FC, useContext, useEffect, useRef, useState } from "react"; +import { FC, useContext, useRef, useState } from "react"; import { Form, Formik, FormikHelpers, FormikProps } from "formik"; import * as Yup from "yup"; import { FhirContext } from "../fhir/FhirContext"; From a7dec022b836017ab46d73a8acd9abf91961a1a7 Mon Sep 17 00:00:00 2001 From: James Hughes Date: Wed, 5 Oct 2022 10:14:54 +0100 Subject: [PATCH 8/9] added .finally() to promise to set loading to false --- src/components/fhir/FhirAuthoriser.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/components/fhir/FhirAuthoriser.tsx b/src/components/fhir/FhirAuthoriser.tsx index 7d6f434..593236e 100644 --- a/src/components/fhir/FhirAuthoriser.tsx +++ b/src/components/fhir/FhirAuthoriser.tsx @@ -35,9 +35,10 @@ const FhirAuthoriser: FC = () => { message: "Something went wrong connecting to the FHIR authoriser. Please try again later.", isError: true, }); + }) + .finally(() => { + setIsLoading(false); }); - - setIsLoading(false); }, []); return ( From 4b84967e4c76b33c1c13e12442c44ce45611a59b Mon Sep 17 00:00:00 2001 From: James Hughes Date: Wed, 5 Oct 2022 10:22:16 +0100 Subject: [PATCH 9/9] removed unnecessary html element --- src/components/fhir/FhirAuthoriser.tsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/components/fhir/FhirAuthoriser.tsx b/src/components/fhir/FhirAuthoriser.tsx index 593236e..9ea9b23 100644 --- a/src/components/fhir/FhirAuthoriser.tsx +++ b/src/components/fhir/FhirAuthoriser.tsx @@ -45,8 +45,6 @@ const FhirAuthoriser: FC = () => { <> {isLoading && } setModal(null)} /> - -

Connecting to FHIR back end...

); };