From d39fb6e4f4bda92fe37fb75ce0b61720201ed100 Mon Sep 17 00:00:00 2001 From: ebrockainq <112428189+ebrockainq@users.noreply.github.com> Date: Wed, 11 Sep 2024 13:24:39 -0400 Subject: [PATCH 1/6] Add test by criteria B1 tab * Changes from SITE-3986 * Update B1Tab.tsx * Create SMTPTestCases.tsx * Remove duplicate files * Add env variables and move API calls to ServerActions * Improve environment variable name * Remove env variables * Add Loading Button, Remove Default Profile Values * add IMAP/POP3 manual validation, attachment type field * Fix tab data carryover, fix include filter * Add XDR endpoint fields * Add XDR DocumentSelector handling * Fix incorrect emails * Fix missing doc select on XDR 3 * Add logs formatting * Fix reversed IMAP and POP3 icons * Add tooltip * Fix XDR logs and missing manual validations * Add attachment type tooltip * Remove Tooltips add XDR API call * Add error condition, add clear button * Fix more info sections, censor profile password * Add clear selected document * Remove accept/reject on API error * Fix XDR more info page * add tooltip and pop over for endpoint copy * Fix incorrect xdr email addresses * Replace popover system and fix error handling * Language improvements and fix clear button visibility trigger * Fix language errors * Add clear button to XDR send * Basic xdr functionality * Add manual validation, request/response, remining request fields, * add xdr document selector * Add XDR Document Select test functionality, add colorized XML display * Correct document selection per sub criteria * Fix failure detection on empty responses * Banish type errors * Less restrictive clear button * Fix CORS issue with document select * Update DocumentSelector.tsx * add prettier ignore to bugged line * Add improved warning triggers * Add backup content, fix criteriaMet icon on non manual tests * Language fix and null value handling --- src/components/direct/hisp/XDRTestCard.tsx | 2 +- src/components/direct/test-by-criteria/ServerActions.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/direct/hisp/XDRTestCard.tsx b/src/components/direct/hisp/XDRTestCard.tsx index 255918b2..6b003c10 100644 --- a/src/components/direct/hisp/XDRTestCard.tsx +++ b/src/components/direct/hisp/XDRTestCard.tsx @@ -456,7 +456,7 @@ const TestCard = ({ test, receive }: TestCardProps) => { renderMoreInfo() ) : showLogs ? ( - Log for XDR Test {test.name} + Log for {test.name} + setSaveReportError('')} + response={{ error: saveReportError }} + /> {isShowSampleDownloadButton && ( - - - )} - - - )} - {!_.isEmpty(directEmailAddressList) && ( - <> - {isAddingContactAddress || isDeletingContactAddress || isFetchingContactAddresses ? ( + + + ) : ( + <> + {isFetchingLoggedInUsersDirectEmailAdresses ? ( + + ) : ( + + + {isAddingDirectAddress || isDeletingDirectEmailGroup ? ( ) : ( <> + + Add a valid Direct email address to get started. + { addContactAddress()} - disabled={contactEmailFormatError || contactEmailAddressRef.current?.value === ''} + onClick={() => addDirectAddress()} + disabled={directEmailFormatError || directEmailAddressRef.current?.value === ''} + title="Add a Direct email address to manage its contacts." > @@ -336,47 +288,125 @@ const Register = () => { }} /> - - {!_.isEmpty(contactEmailAdressList) && ( - - {contactEmailAdressList.map((x) => { + {!_.isEmpty(directEmailAddressList) && ( + + + + + + + )} )} - - )} - - {!_.isEmpty(errorMessage) && ( - setErrorMessage('')} response={{ error: errorMessage }} /> - )} - {!_.isEmpty(successMessage) && ( - setSuccessMessage('')} - /> + {!_.isEmpty(directEmailAddressList) && ( + <> + {isAddingContactAddress || isDeletingContactAddress || isFetchingContactAddresses ? ( + + ) : ( + + <> + + + Manage contacts for selected email + + + addContactAddress()} + title="Add a contact email address for the selected Direct email address." + disabled={contactEmailFormatError || contactEmailAddressRef.current?.value === ''} + > + + + + ), + }} + /> + + + {!_.isEmpty(contactEmailAdressList) && ( + + {contactEmailAdressList.map((x) => { + return ( + + + + deleteContactAddress(x)} + disabled={contactEmailFormatError} + color="error" + title="Delete this contact email address." + > + + + + + ) + })} + + )} + + + + )} + + )} + + {!_.isEmpty(errorMessage) && ( + setErrorMessage('')} + response={{ error: errorMessage }} + /> + )} + {!_.isEmpty(successMessage) && ( + setSuccessMessage('')} + /> + )} + )} - + )} ) diff --git a/src/components/shared/PageAlertBox.tsx b/src/components/shared/PageAlertBox.tsx new file mode 100644 index 00000000..4e30d394 --- /dev/null +++ b/src/components/shared/PageAlertBox.tsx @@ -0,0 +1,35 @@ +import palette from '@/styles/palette' +import { Box, Typography } from '@mui/material' +import ErrorIcon from '@mui/icons-material/Error' + +type PageAlertBoxProps = { + message: string +} + +const PageAlertBox = (props: PageAlertBoxProps) => { + const message = props.message || null + return ( + + + + {message} + + + ) +} + +export default PageAlertBox From 76daaf1a026b1e03e2d4416a48ab5204df83fe18 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Fri, 13 Sep 2024 16:37:31 -0400 Subject: [PATCH 4/6] Add savescorecard API to .env as temp workaround --- .env | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.env b/.env index 6f1a09a2..c27226af 100644 --- a/.env +++ b/.env @@ -5,4 +5,7 @@ NEXT_PUBLIC_CCDA_VALIDATOR_CURES_V1_SENDER_URL=https://api.github.com/repos/onc- NEXT_PUBLIC_CCDA_VALIDATOR_CURES_V1_RECEIVER_URL=https://api.github.com/repos/onc-healthit/2015-edition-cures-update-data/contents/Cures Update Receiver SUT Test Data NEXT_PUBLIC_CCDA_VALIDATOR_CURES_DOWNLOAD_URL=https://codeload.github.com/onc-healthit/2015-edition-cures-update-data/zip/master NEXT_PUBLIC_RELEASE_VERSION_URL=https://raw.githubusercontent.com/onc-healthit/site-content/master/site-ui-4/version.md -NEXT_PUBLIC_RELEASE_DATE_URL=https://raw.githubusercontent.com/onc-healthit/site-content/master/site-ui-4/release-date.md \ No newline at end of file +NEXT_PUBLIC_RELEASE_DATE_URL=https://raw.githubusercontent.com/onc-healthit/site-content/master/site-ui-4/release-date.md + +# TODO: Allow for this to be dynamic per environment file and delete from here. See: https://phase.dev/blog/nextjs-public-runtime-variables/ +NEXT_PUBLIC_SCORECARD_SAVESCORECARDSERVICE_API=https://ccda.healthit.gov/scorecard/savescorecardservice From f1294c390938dd9a8eb720bc40dfd9c879b8ac95 Mon Sep 17 00:00:00 2001 From: akanuri9 <118755941+akanuri9@users.noreply.github.com> Date: Mon, 16 Sep 2024 14:22:34 -0400 Subject: [PATCH 5/6] Add Direct XDM Validator (#125) * XDM Validator Implementation * Update description for XDM * Add generic error constant and update Axios version --- package-lock.json | 8 +- package.json | 2 +- src/app/direct/validate/page.tsx | 7 -- src/app/direct/xdm/page.tsx | 7 ++ src/components/c-cda/validation/actions.ts | 5 +- src/components/direct/DirectHome.tsx | 6 +- src/components/direct/dcdt/actions.ts | 5 +- .../direct/transport-tool/actions.ts | 11 +- .../DirectMessage.tsx} | 24 +--- .../direct/validators/ValidatorHome.tsx | 36 ++++++ .../direct/validators/XDMResults.tsx | 103 ++++++++++++++++++ .../direct/validators/XDMValidator.tsx | 73 +++++++++++++ src/components/direct/validators/actions.ts | 48 ++++++++ src/constants/errorConstants.ts | 1 + 14 files changed, 291 insertions(+), 45 deletions(-) delete mode 100644 src/app/direct/validate/page.tsx create mode 100644 src/app/direct/xdm/page.tsx rename src/components/direct/{validate/Validate.tsx => validators/DirectMessage.tsx} (75%) create mode 100644 src/components/direct/validators/ValidatorHome.tsx create mode 100644 src/components/direct/validators/XDMResults.tsx create mode 100644 src/components/direct/validators/XDMValidator.tsx create mode 100644 src/components/direct/validators/actions.ts create mode 100644 src/constants/errorConstants.ts diff --git a/package-lock.json b/package-lock.json index f52e85d0..0ea236bf 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,7 +16,7 @@ "@mui/material": "^5.16.0", "@mui/material-nextjs": "^5.15.5", "@mui/x-data-grid": "^7.12.1", - "axios": "^1.6.8", + "axios": "^1.7.7", "dompurify": "^3.1.2", "lodash": "^4.17.21", "marked": "^12.0.2", @@ -1971,9 +1971,9 @@ } }, "node_modules/axios": { - "version": "1.7.4", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.4.tgz", - "integrity": "sha512-DukmaFRnY6AzAALSH4J2M3k6PkaC+MfaAGdEERRWcC9q3/TWQwLpHR8ZRLKTdQ3aBDL64EdluRDjJqKw+BPZEw==", + "version": "1.7.7", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.7.tgz", + "integrity": "sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q==", "dependencies": { "follow-redirects": "^1.15.6", "form-data": "^4.0.0", diff --git a/package.json b/package.json index 14d17d92..42686678 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,7 @@ "@mui/material": "^5.16.0", "@mui/material-nextjs": "^5.15.5", "@mui/x-data-grid": "^7.12.1", - "axios": "^1.6.8", + "axios": "^1.7.7", "dompurify": "^3.1.2", "lodash": "^4.17.21", "marked": "^12.0.2", diff --git a/src/app/direct/validate/page.tsx b/src/app/direct/validate/page.tsx deleted file mode 100644 index 4f11e2d1..00000000 --- a/src/app/direct/validate/page.tsx +++ /dev/null @@ -1,7 +0,0 @@ -import ValidateComponent from '@/components/direct/validate/Validate' - -const Validate = () => { - return -} - -export default Validate diff --git a/src/app/direct/xdm/page.tsx b/src/app/direct/xdm/page.tsx new file mode 100644 index 00000000..841d934c --- /dev/null +++ b/src/app/direct/xdm/page.tsx @@ -0,0 +1,7 @@ +import XDMComponent from '@/components/direct/validators/XDMValidator' + +const Validate = () => { + return +} + +export default Validate diff --git a/src/components/c-cda/validation/actions.ts b/src/components/c-cda/validation/actions.ts index dab608f1..dc8495a8 100644 --- a/src/components/c-cda/validation/actions.ts +++ b/src/components/c-cda/validation/actions.ts @@ -1,6 +1,7 @@ 'use server' import https from 'https' import axios from 'axios' +import { GENERIC_ERROR_MESSAGE } from '@/constants/errorConstants' //Get Scenario file options export async function getScenarioOptions(criteriaUrl: string) { const res = await fetch(criteriaUrl) @@ -77,7 +78,7 @@ export async function postToValidatorV3(prevState: object | undefined, formData: console.error(error.response?.data) return { response: { - error: 'Validator Service had an issue, Please try again later!', + error: GENERIC_ERROR_MESSAGE, errorStatus: error.response?.status, }, } @@ -126,7 +127,7 @@ export async function postToValidatorV1(prevState: object | undefined, formData: console.error(error.response?.data) return { response: { - error: 'Validator Service had an issue, Please try again later!', + error: GENERIC_ERROR_MESSAGE, errorStatus: error.response?.status, }, } diff --git a/src/components/direct/DirectHome.tsx b/src/components/direct/DirectHome.tsx index 4fd8b8bd..b8289683 100644 --- a/src/components/direct/DirectHome.tsx +++ b/src/components/direct/DirectHome.tsx @@ -162,10 +162,10 @@ const DirectHome = () => { cardWidthPercent={100} /> } cardWidthPercent={100} /> diff --git a/src/components/direct/dcdt/actions.ts b/src/components/direct/dcdt/actions.ts index 6cdfd9e4..d65e1257 100644 --- a/src/components/direct/dcdt/actions.ts +++ b/src/components/direct/dcdt/actions.ts @@ -1,4 +1,5 @@ 'use server' +import { GENERIC_ERROR_MESSAGE } from '@/constants/errorConstants' import axios from 'axios' export async function handleSubmitHosting(prevState: object | undefined, formData: FormData) { const hostingApi = process.env.DCDT_HOSTING_API @@ -27,7 +28,7 @@ export async function handleSubmitHosting(prevState: object | undefined, formDat console.error(error.response?.data) return { response: { - error: 'They was an error connecting to the backend, Please try again later!', + error: GENERIC_ERROR_MESSAGE, errorStatus: error.response?.status, }, } @@ -65,7 +66,7 @@ export async function handleSubmitDiscover(prevState: object | undefined, formDa console.error(error.response?.data) return { response: { - error: 'They was an error connecting to the backend, Please try again later!', + error: GENERIC_ERROR_MESSAGE, errorStatus: error.response?.status, }, } diff --git a/src/components/direct/transport-tool/actions.ts b/src/components/direct/transport-tool/actions.ts index 8e93f8df..feb03b5a 100644 --- a/src/components/direct/transport-tool/actions.ts +++ b/src/components/direct/transport-tool/actions.ts @@ -1,4 +1,5 @@ 'use server' +import { GENERIC_ERROR_MESSAGE } from '@/constants/errorConstants' import axios from 'axios' export async function getSampleCCDAFiles(sampleCCDAFilesEndpoint: string) { @@ -29,7 +30,7 @@ export async function handleSendMessageWithAttachmentFilepath(prevState: object console.error(error.response?.data) return { response: { - error: 'They was an error connecting to the backend, Please try again later!', + error: GENERIC_ERROR_MESSAGE, errorStatus: error.response?.status, }, } @@ -60,7 +61,7 @@ export async function handleSendMessageWithAttachmentFile(prevState: object | un console.error(error.response?.data) return { response: { - error: 'They was an error connecting to the backend, Please try again later!', + error: GENERIC_ERROR_MESSAGE, errorStatus: error.response?.status, }, } @@ -91,7 +92,7 @@ export async function handleSearchSITEInbox(prevState: object | undefined, formD console.error(error.response?.data) return { response: { - error: 'They was an error connecting to the backend, Please try again later!', + error: GENERIC_ERROR_MESSAGE, errorStatus: error.response?.status, }, } @@ -120,7 +121,7 @@ export async function handleSearchHHSInbox(prevState: object | undefined, formDa console.error(error.response?.data) return { response: { - error: 'They was an error connecting to the backend, Please try again later!', + error: GENERIC_ERROR_MESSAGE, errorStatus: error.response?.status, }, } @@ -151,7 +152,7 @@ export async function handleUploadTrustAnchor(prevState: object | undefined, for console.error(error.response?.data) return { response: { - error: 'They was an error connecting to the backend, Please try again later!', + error: GENERIC_ERROR_MESSAGE, errorStatus: error.response?.status, }, } diff --git a/src/components/direct/validate/Validate.tsx b/src/components/direct/validators/DirectMessage.tsx similarity index 75% rename from src/components/direct/validate/Validate.tsx rename to src/components/direct/validators/DirectMessage.tsx index e49f5721..10a9ef33 100644 --- a/src/components/direct/validate/Validate.tsx +++ b/src/components/direct/validators/DirectMessage.tsx @@ -1,4 +1,4 @@ -'use client' +/* 'use client' import BannerBox from '@/components/shared/BannerBox' import styles from '@/components/shared/styles.module.css' import { Box, Button, Container, Stack, TextField, Tooltip, Typography } from '@mui/material' @@ -10,26 +10,7 @@ import palette from '@/styles/palette' const Validate = () => { return ( <> - {/* Global Header */} - - Direct - , - - Validate - , - ]} - heading={'Validate Direct Message'} - description={ - <> - Ensure that your direct messaging system complies with legal and regulatory requirements, including HIPAA - regulations in the United States. Stay updated with any changes in the regulations that might impact the way - direct messages need to be handled and secured. - - } - /> - {/* Main Content */} + @@ -87,3 +68,4 @@ const Validate = () => { } export default Validate + */ diff --git a/src/components/direct/validators/ValidatorHome.tsx b/src/components/direct/validators/ValidatorHome.tsx new file mode 100644 index 00000000..487702bf --- /dev/null +++ b/src/components/direct/validators/ValidatorHome.tsx @@ -0,0 +1,36 @@ +/* 'use client' +import BannerBox from '@/components/shared/BannerBox' +import Link from 'next/link' +import styles from '@shared/styles.module.css' +import TabsComponent, { TabInputs } from '@/components/shared/TabsComponent' +import DirectMessage from './DirectMessage' +import XDM from './XDMValidator' + +const ValidatorHome = () => { + const validatorTabs: TabInputs[] = [ + { tabName: 'XDM VALIDATOR', tabIndex: 0, tabPanel: }, + { tabName: 'DIRECT MESSAGE', tabIndex: 1, tabPanel: }, + ] + return ( + <> + + + Direct + , + + Message Validators + , + ]} + heading={'Message Validators '} + description={<>} + /> + + + + ) +} + +export default ValidatorHome + */ diff --git a/src/components/direct/validators/XDMResults.tsx b/src/components/direct/validators/XDMResults.tsx new file mode 100644 index 00000000..a7c08825 --- /dev/null +++ b/src/components/direct/validators/XDMResults.tsx @@ -0,0 +1,103 @@ +import { Box, Button, Divider, Typography } from '@mui/material' +import _ from 'lodash' + +import ErrorDisplayCard from '@/components/c-cda/validation/results/ErrorDisplay' +import { useFormStatus } from 'react-dom' +import { useState, useEffect } from 'react' +import { CircularProgress } from '@mui/material' +import palette from '@/styles/palette' +import { Check } from '@mui/icons-material' +import ErrorIcon from '@mui/icons-material/Error' +interface ResultsComponentProps { + response: ContentProps + disabled?: boolean + buttonTitle: string +} +type ContentProps = { + pass: boolean + report: string + uploadedTrustAnchorFileName: string + error?: string + errorStatus?: number +} +const XDMResults = ({ response, buttonTitle }: ResultsComponentProps) => { + const [errorOpen, setErrorOpen] = useState(false) + const { pending } = useFormStatus() + + const handleErrorClose = () => { + setErrorOpen(false) + } + + useEffect(() => { + if (!pending && _.has(response, 'error')) { + setErrorOpen(true) + } + }, [pending, response]) + + return ( + <> + + + {!pending && _.has(response, 'error') && ( + + )} + + {!pending && !_.has(response, 'error') && !_.isEmpty(response) && ( + + + + Validator Results + + {response.pass && ( + + + +
{response.report}
+
+
+ )} + {!response.pass && ( + + + +
{response.report}
+
+
+ )} +
+ )} + + ) +} + +export default XDMResults diff --git a/src/components/direct/validators/XDMValidator.tsx b/src/components/direct/validators/XDMValidator.tsx new file mode 100644 index 00000000..7ba4707c --- /dev/null +++ b/src/components/direct/validators/XDMValidator.tsx @@ -0,0 +1,73 @@ +'use client' +import BannerBox from '@/components/shared/BannerBox' +import styles from '@/components/shared/styles.module.css' +import { Box, Container, Stack, Typography } from '@mui/material' +import Link from 'next/link' +import DragandDropFile from '@components/shared/DragandDropFile' +import { handleXDMUpload } from './actions' +import { useFormState } from 'react-dom' +import { useEffect, useState } from 'react' +import XDMResults from './XDMResults' + +const XDM = () => { + const [base64, setBase64] = useState(null) + const [data, handleSubmit] = useFormState(handleXDMUpload, { response: {} }) + const [fileContent, setFileContent] = useState(null) + + const formData = new FormData() + formData.append('zip', base64 || '') + const handleSubmitwithBase64 = handleSubmit.bind(null, formData) + + useEffect(() => { + const reader = new FileReader() + reader.onloadend = () => { + const result = reader.result as string + const base64String = result.split(',')[1] // Extract base64 part + setBase64(base64String) + } + if (fileContent) { + reader.readAsDataURL(fileContent) + } + }, [fileContent]) + + const getFileName = (data: File[]) => { + if (data !== undefined) { + setFileContent(data[0]) + } + } + + return ( + <> + {/* Global Header */} + + Direct + , + + XDM Validator + , + ]} + heading={'XDM Validator'} + description={<>Upload your XDM file to validate.} + /> + + {/* Main Content */} + +
+ + + + Upload your XDM file: + + + + + + +
+ + ) +} + +export default XDM diff --git a/src/components/direct/validators/actions.ts b/src/components/direct/validators/actions.ts new file mode 100644 index 00000000..5d15fb49 --- /dev/null +++ b/src/components/direct/validators/actions.ts @@ -0,0 +1,48 @@ +'use server' +import axios from 'axios' +import _ from 'lodash' + +export async function handleXDMUpload(prevState: object | undefined, formData: FormData) { + const Api = process.env.XDM_VALIDATOR_API + const uploadFile = formData.get('zip') + // console.log('uploaded File', uploadFile) + if (_.isEmpty(uploadFile)) { + return { + response: { + error: 'Please upload a file', + errorStatus: 400, + }, + } + } else { + const body = JSON.stringify({ + zip: uploadFile, + }) + const config = { + method: 'post', + url: Api, + data: body, + headers: { + 'Content-Type': 'application/json', + }, + } + console.log('Submitted data XDM Validator ', config) + try { + const response = await axios.request(config) + console.log('XDM Validator response status', response.status) + //console.log('XDM Validator response status', response.data) + return { response: response.data } + } catch (error) { + if (axios.isAxiosError(error)) { + console.error(error.response?.data) + return { + response: { + error: 'There was an error completing the request, Please try again later!', + errorStatus: error.response?.status, + }, + } + } else { + console.error(error) + } + } + } +} diff --git a/src/constants/errorConstants.ts b/src/constants/errorConstants.ts new file mode 100644 index 00000000..2117521e --- /dev/null +++ b/src/constants/errorConstants.ts @@ -0,0 +1 @@ +export const GENERIC_ERROR_MESSAGE: string = 'There was an error completing the request, Please try again later!' From d8c4e13fcc348a864fa21a31a362d0e837a30574 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Mon, 16 Sep 2024 22:55:34 -0400 Subject: [PATCH 6/6] Add Scorecard compare chart --- package-lock.json | 326 +++++++++++++++++- package.json | 3 +- .../scorecard/ScorecardResultsDialog.tsx | 2 +- .../next-steps/ScorecardNextSteps.tsx | 26 +- .../summary/ScorecardCompareChartSummary.tsx | 107 +++++- src/components/shared/SwitchWIthLabel.tsx | 32 ++ .../shared/dialog/DialogTemplate.tsx | 2 +- 7 files changed, 463 insertions(+), 35 deletions(-) create mode 100644 src/components/shared/SwitchWIthLabel.tsx diff --git a/package-lock.json b/package-lock.json index 0ea236bf..29a67fa1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,9 +15,10 @@ "@mui/lab": "^5.0.0-alpha.173", "@mui/material": "^5.16.0", "@mui/material-nextjs": "^5.15.5", + "@mui/x-charts": "^7.17.0", "@mui/x-data-grid": "^7.12.1", "axios": "^1.7.7", - "dompurify": "^3.1.2", + "dompurify": "^3.1.6", "lodash": "^4.17.21", "marked": "^12.0.2", "next": "14.2.3", @@ -246,9 +247,9 @@ } }, "node_modules/@babel/runtime": { - "version": "7.25.0", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.25.0.tgz", - "integrity": "sha512-7dRy4DwXwtzBrPbZflqxnvfxLF8kdZXPkhymtDeFoFqE6ldzjQFgYTtYIFARcLEYDrqfBfYcZt1WqFxRoyC9Rw==", + "version": "7.25.6", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.25.6.tgz", + "integrity": "sha512-VBj9MYyDb9tuLq7yzqjgzt6Q+IBQLrGZfdjOekyEirZPHxXWoTSGUTMrpsfi58Up73d13NfYLv8HT9vmznjzhQ==", "dependencies": { "regenerator-runtime": "^0.14.0" }, @@ -916,6 +917,81 @@ "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==" }, + "node_modules/@mui/x-charts": { + "version": "7.17.0", + "resolved": "https://registry.npmjs.org/@mui/x-charts/-/x-charts-7.17.0.tgz", + "integrity": "sha512-xDH/lOnb57+VBIA7q+1KlC0Ht1O46d/N2MEl1tUq1JYIXhA2Owi5cp+bcaof8Rvw5ApCmkoBxyUIjqT0guNIwA==", + "dependencies": { + "@babel/runtime": "^7.25.6", + "@mui/utils": "^5.16.6", + "@mui/x-charts-vendor": "7.16.0", + "@mui/x-internals": "7.17.0", + "@react-spring/rafz": "^9.7.4", + "@react-spring/web": "^9.7.4", + "clsx": "^2.1.1", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "@emotion/react": "^11.9.0", + "@emotion/styled": "^11.8.1", + "@mui/material": "^5.15.14 || ^6.0.0", + "@mui/system": "^5.15.14 || ^6.0.0", + "react": "^17.0.0 || ^18.0.0", + "react-dom": "^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@emotion/react": { + "optional": true + }, + "@emotion/styled": { + "optional": true + } + } + }, + "node_modules/@mui/x-charts-vendor": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@mui/x-charts-vendor/-/x-charts-vendor-7.16.0.tgz", + "integrity": "sha512-MyMCCl7eAM53rLbjqP4zbMy5hYtdeqCjAYCH2jpvBKdgugm2eaPLKOPM8bUVfen0wHA8BXleQrIrNceytFPyZA==", + "dependencies": { + "@babel/runtime": "^7.25.6", + "@types/d3-color": "^3.1.3", + "@types/d3-delaunay": "^6.0.4", + "@types/d3-interpolate": "^3.0.4", + "@types/d3-scale": "^4.0.8", + "@types/d3-shape": "^3.1.6", + "@types/d3-time": "^3.0.3", + "d3-color": "^3.1.0", + "d3-delaunay": "^6.0.4", + "d3-interpolate": "^3.0.1", + "d3-scale": "^4.0.2", + "d3-shape": "^3.2.0", + "d3-time": "^3.1.0", + "delaunator": "^5.0.1", + "robust-predicates": "^3.0.2" + } + }, + "node_modules/@mui/x-charts/node_modules/@mui/x-internals": { + "version": "7.17.0", + "resolved": "https://registry.npmjs.org/@mui/x-internals/-/x-internals-7.17.0.tgz", + "integrity": "sha512-FLlAGSJl/vsuaA/8hPGazXFppyzIzxApJJDZMoTS0geUmHd0hyooISV2ltllLmrZ/DGtHhI08m8GGnHL6/vVeg==", + "dependencies": { + "@babel/runtime": "^7.25.6", + "@mui/utils": "^5.16.6" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "react": "^17.0.0 || ^18.0.0" + } + }, "node_modules/@mui/x-data-grid": { "version": "7.12.1", "resolved": "https://registry.npmjs.org/@mui/x-data-grid/-/x-data-grid-7.12.1.tgz", @@ -1172,6 +1248,72 @@ "url": "https://opencollective.com/popperjs" } }, + "node_modules/@react-spring/animated": { + "version": "9.7.4", + "resolved": "https://registry.npmjs.org/@react-spring/animated/-/animated-9.7.4.tgz", + "integrity": "sha512-7As+8Pty2QlemJ9O5ecsuPKjmO0NKvmVkRR1n6mEotFgWar8FKuQt2xgxz3RTgxcccghpx1YdS1FCdElQNexmQ==", + "dependencies": { + "@react-spring/shared": "~9.7.4", + "@react-spring/types": "~9.7.4" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/@react-spring/core": { + "version": "9.7.4", + "resolved": "https://registry.npmjs.org/@react-spring/core/-/core-9.7.4.tgz", + "integrity": "sha512-GzjA44niEJBFUe9jN3zubRDDDP2E4tBlhNlSIkTChiNf9p4ZQlgXBg50qbXfSXHQPHak/ExYxwhipKVsQ/sUTw==", + "dependencies": { + "@react-spring/animated": "~9.7.4", + "@react-spring/shared": "~9.7.4", + "@react-spring/types": "~9.7.4" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/react-spring/donate" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/@react-spring/rafz": { + "version": "9.7.4", + "resolved": "https://registry.npmjs.org/@react-spring/rafz/-/rafz-9.7.4.tgz", + "integrity": "sha512-mqDI6rW0Ca8IdryOMiXRhMtVGiEGLIO89vIOyFQXRIwwIMX30HLya24g9z4olDvFyeDW3+kibiKwtZnA4xhldA==" + }, + "node_modules/@react-spring/shared": { + "version": "9.7.4", + "resolved": "https://registry.npmjs.org/@react-spring/shared/-/shared-9.7.4.tgz", + "integrity": "sha512-bEPI7cQp94dOtCFSEYpxvLxj0+xQfB5r9Ru1h8OMycsIq7zFZon1G0sHrBLaLQIWeMCllc4tVDYRTLIRv70C8w==", + "dependencies": { + "@react-spring/rafz": "~9.7.4", + "@react-spring/types": "~9.7.4" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/@react-spring/types": { + "version": "9.7.4", + "resolved": "https://registry.npmjs.org/@react-spring/types/-/types-9.7.4.tgz", + "integrity": "sha512-iQVztO09ZVfsletMiY+DpT/JRiBntdsdJ4uqk3UJFhrhS8mIC9ZOZbmfGSRs/kdbNPQkVyzucceDicQ/3Mlj9g==" + }, + "node_modules/@react-spring/web": { + "version": "9.7.4", + "resolved": "https://registry.npmjs.org/@react-spring/web/-/web-9.7.4.tgz", + "integrity": "sha512-UMvCZp7I5HCVIleSa4BwbNxynqvj+mJjG2m20VO2yPoi2pnCYANy58flvz9v/YcXTAvsmL655FV3pm5fbr6akA==", + "dependencies": { + "@react-spring/animated": "~9.7.4", + "@react-spring/core": "~9.7.4", + "@react-spring/shared": "~9.7.4", + "@react-spring/types": "~9.7.4" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, "node_modules/@rushstack/eslint-patch": { "version": "1.6.1", "resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.6.1.tgz", @@ -1202,6 +1344,50 @@ "cypress": "*" } }, + "node_modules/@types/d3-color": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-3.1.3.tgz", + "integrity": "sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==" + }, + "node_modules/@types/d3-delaunay": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-delaunay/-/d3-delaunay-6.0.4.tgz", + "integrity": "sha512-ZMaSKu4THYCU6sV64Lhg6qjf1orxBthaC161plr5KuPHo3CNm8DTHiLw/5Eq2b6TsNP0W0iJrUOFscY6Q450Hw==" + }, + "node_modules/@types/d3-interpolate": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-3.0.4.tgz", + "integrity": "sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==", + "dependencies": { + "@types/d3-color": "*" + } + }, + "node_modules/@types/d3-path": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-3.1.0.tgz", + "integrity": "sha512-P2dlU/q51fkOc/Gfl3Ul9kicV7l+ra934qBFXCFhrZMOL6du1TM0pm1ThYvENukyOn5h9v+yMJ9Fn5JK4QozrQ==" + }, + "node_modules/@types/d3-scale": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-4.0.8.tgz", + "integrity": "sha512-gkK1VVTr5iNiYJ7vWDI+yUFFlszhNMtVeneJ6lUTKPjprsvLLI9/tgEGiXJOnlINJA8FyA88gfnQsHbybVZrYQ==", + "dependencies": { + "@types/d3-time": "*" + } + }, + "node_modules/@types/d3-shape": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-3.1.6.tgz", + "integrity": "sha512-5KKk5aKGu2I+O6SONMYSNflgiP0WfZIQvVUMan50wHsLG1G94JlxEVnCpQARfTtzytuY0p/9PXXZb3I7giofIA==", + "dependencies": { + "@types/d3-path": "*" + } + }, + "node_modules/@types/d3-time": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-3.0.3.tgz", + "integrity": "sha512-2p6olUZ4w3s+07q3Tm2dbiMZy5pCDfYwtLXXHUnVzXgQlZ/OyPtUz6OL382BkOuGlLXqfT+wqv8Fw2v8/0geBw==" + }, "node_modules/@types/debug": { "version": "4.1.12", "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz", @@ -2554,6 +2740,111 @@ "url": "https://github.com/chalk/supports-color?sponsor=1" } }, + "node_modules/d3-array": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz", + "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==", + "dependencies": { + "internmap": "1 - 2" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-color": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", + "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-delaunay": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/d3-delaunay/-/d3-delaunay-6.0.4.tgz", + "integrity": "sha512-mdjtIZ1XLAM8bm/hx3WwjfHt6Sggek7qH043O8KEjDXN40xi3vx/6pYSVTwLjEgiXQTbvaouWKynLBiUZ6SK6A==", + "dependencies": { + "delaunator": "5" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-format": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.0.tgz", + "integrity": "sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-interpolate": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", + "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", + "dependencies": { + "d3-color": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-path": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz", + "integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-scale": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz", + "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==", + "dependencies": { + "d3-array": "2.10.0 - 3", + "d3-format": "1 - 3", + "d3-interpolate": "1.2.0 - 3", + "d3-time": "2.1.1 - 3", + "d3-time-format": "2 - 4" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-shape": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz", + "integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==", + "dependencies": { + "d3-path": "^3.1.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz", + "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==", + "dependencies": { + "d3-array": "2 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time-format": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz", + "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==", + "dependencies": { + "d3-time": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/damerau-levenshtein": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", @@ -2656,6 +2947,14 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/delaunator": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/delaunator/-/delaunator-5.0.1.tgz", + "integrity": "sha512-8nvh+XBe96aCESrGOqMp/84b13H9cdKbG5P2ejQCh4d4sK9RL4371qou9drQjMhvnPmhWl5hnmqbEE0fXr9Xnw==", + "dependencies": { + "robust-predicates": "^3.0.2" + } + }, "node_modules/delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", @@ -2718,9 +3017,9 @@ } }, "node_modules/dompurify": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.1.5.tgz", - "integrity": "sha512-lwG+n5h8QNpxtyrJW/gJWckL+1/DQiYMX8f7t8Z2AZTPw1esVrqjI63i7Zc2Gz0aKzLVMYC1V1PL/ky+aY/NgA==" + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.1.6.tgz", + "integrity": "sha512-cTOAhc36AalkjtBpfG6O8JimdTMWNXjiePT2xQH/ppBGi/4uIpmj8eKyIkMJErXWARyINV/sB38yf8JCLF5pbQ==" }, "node_modules/ecc-jsbn": { "version": "0.1.2", @@ -4289,6 +4588,14 @@ "node": ">= 0.4" } }, + "node_modules/internmap": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", + "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==", + "engines": { + "node": ">=12" + } + }, "node_modules/is-alphabetical": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-2.0.1.tgz", @@ -7333,6 +7640,11 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/robust-predicates": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.2.tgz", + "integrity": "sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg==" + }, "node_modules/run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", diff --git a/package.json b/package.json index 42686678..f354e741 100644 --- a/package.json +++ b/package.json @@ -21,9 +21,10 @@ "@mui/lab": "^5.0.0-alpha.173", "@mui/material": "^5.16.0", "@mui/material-nextjs": "^5.15.5", + "@mui/x-charts": "^7.17.0", "@mui/x-data-grid": "^7.12.1", "axios": "^1.7.7", - "dompurify": "^3.1.2", + "dompurify": "^3.1.6", "lodash": "^4.17.21", "marked": "^12.0.2", "next": "14.2.3", diff --git a/src/components/c-cda/scorecard/ScorecardResultsDialog.tsx b/src/components/c-cda/scorecard/ScorecardResultsDialog.tsx index 57fdffd1..dbb729be 100644 --- a/src/components/c-cda/scorecard/ScorecardResultsDialog.tsx +++ b/src/components/c-cda/scorecard/ScorecardResultsDialog.tsx @@ -145,7 +145,7 @@ export default function ScorecardResultsDialog({
- + diff --git a/src/components/c-cda/scorecard/next-steps/ScorecardNextSteps.tsx b/src/components/c-cda/scorecard/next-steps/ScorecardNextSteps.tsx index b266fddd..a90c09ab 100644 --- a/src/components/c-cda/scorecard/next-steps/ScorecardNextSteps.tsx +++ b/src/components/c-cda/scorecard/next-steps/ScorecardNextSteps.tsx @@ -2,11 +2,11 @@ import { ScorecardReferenceResultType, ScorecardResultsType, } from '@/components/c-cda/scorecard/types/ScorecardJsonResponseType' -import { Box, Divider, FormControlLabel, styled, Switch, Typography } from '@mui/material' +import { Box, Divider, Typography } from '@mui/material' import { useEffect, useState } from 'react' import { removeHashtagToUseHrefLinkAsIdForAnchor } from '../serverside/scorecardHelperService' import { HrefLinkValueEnum, SORT_ORDER_STARTING_VALUE } from '../types/ScorecardConstants' -// import { SortOrderEnum } from '../types/ScorecardConstants' +import SwitchWithLabel from '@/components/shared/SwitchWIthLabel' import ScorecardDetailedResults from './ScorecardDetailedResults' import ScorecardHeatMap from './ScorecardHeatMap' @@ -35,11 +35,6 @@ export default function ScorecardNextSteps({ setIsAscendingOrderChecked((prevIsAscendingOrderChecked) => !prevIsAscendingOrderChecked) } - const StyledFormControlLabelWithLabelOnLeft = styled(FormControlLabel)` - display: flex; - flex-direction: row; - ` - return ( @@ -47,18 +42,11 @@ export default function ScorecardNextSteps({ Next Steps - - } - // label={`Sorted by: ${isAscendingOrderChecked ? SortOrderEnum.ASCENDING : SortOrderEnum.DESCENDING} order`} - label="Toggle Sort Order" - name="wrapped" + diff --git a/src/components/c-cda/scorecard/summary/ScorecardCompareChartSummary.tsx b/src/components/c-cda/scorecard/summary/ScorecardCompareChartSummary.tsx index 9524c9b9..f28df6f9 100644 --- a/src/components/c-cda/scorecard/summary/ScorecardCompareChartSummary.tsx +++ b/src/components/c-cda/scorecard/summary/ScorecardCompareChartSummary.tsx @@ -1,16 +1,111 @@ +import SwitchWithLabel from '@/components/shared/SwitchWIthLabel' import { Box, Typography } from '@mui/material' +import { BarChart } from '@mui/x-charts/BarChart' +import { useState } from 'react' +import { GradeEnum, gradeStyleMap } from '../types/ScorecardConstants' +import { ScorecardResultsType, TotalGradesGiven } from '../types/ScorecardJsonResponseType' + +interface ScorecardCompareChartSummaryProps { + results: ScorecardResultsType | undefined +} +export default function ScorecardCompareChartSummary({ results }: ScorecardCompareChartSummaryProps) { + const initialGradeCategoryLabels = ['A+', 'A-', 'B+', 'B-', 'C', 'D'] + + const totalGradesGiven: TotalGradesGiven | undefined = results?.totalGradesGiven + + // Set grade data for each bar based on index order + // TODO: Consider if totalGradesGiven is undefined, don't show the chart instead of just setting to 0 as we are now. + // Instead, display an inline error. This inline error is template is in the shared folder (see Register Direct Email) + const initialGradeTotalCountData: number[] = [ + totalGradesGiven?.aPlusGrades ? totalGradesGiven.aPlusGrades : 0, + totalGradesGiven?.aMinusGrades ? totalGradesGiven.aMinusGrades : 0, + totalGradesGiven?.bPlusGrades ? totalGradesGiven.bPlusGrades : 0, + totalGradesGiven?.bMinusGrades ? totalGradesGiven.bMinusGrades : 0, + totalGradesGiven?.cGrades ? totalGradesGiven.cGrades : 0, + totalGradesGiven?.dGrades ? totalGradesGiven.dGrades : 0, + ] + + // Define the colors for each bar based on index order + const initialGradeColors: string[] = [ + gradeStyleMap[GradeEnum.A_PLUS].backgroundColor, + gradeStyleMap[GradeEnum.A_MINUS].backgroundColor, + gradeStyleMap[GradeEnum.B_PLUS].backgroundColor, + gradeStyleMap[GradeEnum.B_MINUS].backgroundColor, + gradeStyleMap[GradeEnum.C].backgroundColor, + gradeStyleMap[GradeEnum.D].backgroundColor, + ] + + const [isGradeOrderFlipped, setIsGradeOrderFlipped] = useState(false) + + const gradeTotalCountData: number[] = isGradeOrderFlipped + ? [...initialGradeTotalCountData].reverse() + : initialGradeTotalCountData + const gradeCategoryLabels: string[] = isGradeOrderFlipped + ? [...initialGradeCategoryLabels].reverse() + : initialGradeCategoryLabels + const gradeColors: string[] = isGradeOrderFlipped ? [...initialGradeColors].reverse() : initialGradeColors + + const handleFlipGradeOrder = () => { + setIsGradeOrderFlipped(!isGradeOrderFlipped) + } -export default function ScorecardCompareChartSummary() { return ( - - Compare - - - CHART + + + Compare + + + + + The following chart displays the total count for each possible grade received when compared with all C-CDA + Scorecard validations run since we started tracking data. It is intended to give a general idea of how your + grade compares to others, as well as to provide an assessment of the community as a whole. +
+ Note: To view exact total count data, please hover over a relevant grade bar.
+ + + {/* TODO: Make labels more bold? */} + +
) } diff --git a/src/components/shared/SwitchWIthLabel.tsx b/src/components/shared/SwitchWIthLabel.tsx new file mode 100644 index 00000000..6b0dad5e --- /dev/null +++ b/src/components/shared/SwitchWIthLabel.tsx @@ -0,0 +1,32 @@ +import { FormControlLabel, styled, Switch } from '@mui/material' + +const StyledFormControlLabelWithLabelOnRight = styled(FormControlLabel)` + display: flex; + flex-direction: row; +` +const StyledFormControlLabelWithLabelOnLeft = styled(FormControlLabel)` + display: flex; + flex-direction: row-reverse; +` + +interface SwitchWithLabelProps { + isChecked: boolean + handleToggleSwitch: (event: React.ChangeEvent) => void + labelText: string + labelOnRight?: boolean +} + +export default function SwitchWithLabel({ + isChecked, + handleToggleSwitch: handleChangeSwitch, + labelText, + labelOnRight, +}: SwitchWithLabelProps) { + const SwitchControl = + + return labelOnRight ? ( + + ) : ( + + ) +} diff --git a/src/components/shared/dialog/DialogTemplate.tsx b/src/components/shared/dialog/DialogTemplate.tsx index 78583457..228e21a8 100644 --- a/src/components/shared/dialog/DialogTemplate.tsx +++ b/src/components/shared/dialog/DialogTemplate.tsx @@ -43,7 +43,7 @@ const DialogTemplate: FC = ({ actionsContent, }) => { return ( - + {title}