Skip to content

Commit

Permalink
Evan dev validation loading results (#46)
Browse files Browse the repository at this point in the history
* Results outline + transition from loading

* Rest of content and components

* Enlarged status card font size

* Separate summary from results card
  • Loading branch information
ebrockainq authored Apr 1, 2024
1 parent 5ed967e commit cdd54a5
Show file tree
Hide file tree
Showing 6 changed files with 343 additions and 1 deletion.
63 changes: 63 additions & 0 deletions src/components/c-cda/validation/ResultsStatusCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import React from 'react'
import { Card, Typography, Box } from '@mui/material'

type CardType = 'error' | 'warning' | 'info'

interface ResultsStatusCardProps {
type: CardType
count: number
messages: string[]
}

const ResultsStatusCard: React.FC<ResultsStatusCardProps> = ({ type, count, messages }) => {
const colorMap = {
error: '#FF5252',
warning: '#83380E',
info: '#122953',
}

return (
<Card
sx={{
width: 334,
borderRadius: '0px 0px 8px 8px',
boxShadow: '0px 4px 4px 0px rgba(0, 0, 0, 0.25)',
opacity: 1,
display: 'flex',
flexDirection: 'column',
}}
>
<Box
sx={{
bgcolor: colorMap[type],
height: 16,
display: 'flex',
alignItems: 'center',
paddingX: 1,
}}
></Box>

<Box
sx={{
padding: '14px',
bgcolor: 'white',
borderBottomLeftRadius: '8px',
borderBottomRightRadius: '8px',
display: 'flex',
flexDirection: 'column',
}}
>
<Typography variant="subtitle1" sx={{ fontWeight: 'bold', mb: 2 }}>
{`${count} ${type.charAt(0).toUpperCase() + type.slice(1)}`}
</Typography>
{messages.map((message, index) => (
<Typography key={index} variant="body2" sx={{ mt: 1 }}>
{message}
</Typography>
))}
</Box>
</Card>
)
}

export default ResultsStatusCard
55 changes: 55 additions & 0 deletions src/components/c-cda/validation/ValidationResultsSummary.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import React from 'react'
import { Typography, Box } from '@mui/material'
import ResultsStatusCard from './ResultsStatusCard'
import ValidationStatusIndicator from './ValidationStatusIndicator'

export default function ValidatorResultsSummary() {
const errors = ['1 Error in C-CDA MDHT Conformance']
const warnings = ['1 Warning']
const infos = ['1 Info', '1 Info', '1 Info']
return (
<Box>
<Typography variant="h4" sx={{ fontWeight: 'bold' }}>
Summary
</Typography>
<Typography sx={{ mt: 1 }}>
Thank you for using our CCDA (Consolidated Clinical Document Architecture) Validator. We have processed your
CCDA file and here is a summary of the validation results:
</Typography>
<ValidationStatusIndicator status="error" />
<ValidationStatusIndicator status="warning" />
<ValidationStatusIndicator status="pass" />

<Typography sx={{ mt: 2, fontWeight: 'bold' }}>Detailed Report:</Typography>
<Typography sx={{ mt: 2 }}>
Pass: Your CCDA document has successfully passed our validation process. Congratulations! It complies with the
CCDA standards, ensuring its interoperability and correctness.
</Typography>
<Typography sx={{ mt: 1 }}>
Warning: Your CCDA document has passed the basic validation, but there are some issues that need your attention.
Please review the warnings below and take necessary actions to enhance the quality of your document.
</Typography>
<Typography sx={{ mt: 1, mb: 2 }}>
Fail: Unfortunately, your CCDA document did not pass the validation. It indicates significant issues that must
be resolved. Please review the errors below for detailed information on what needs to be corrected.
</Typography>

<Typography variant="h5" sx={{ mt: 2, fontWeight: 'bold' }}>
Results Total
</Typography>
<Box sx={{ display: 'flex', justifyContent: 'space-around', mt: 2, flexWrap: 'wrap' }}>
<Box sx={{ flex: '0 1 auto' }}>
<ResultsStatusCard type="error" count={1} messages={errors} />
</Box>
<Box sx={{ flex: '0 1 auto' }}>
<ResultsStatusCard type="warning" count={1} messages={warnings} />
</Box>
<Box sx={{ flex: '0 1 auto' }}>
<ResultsStatusCard type="info" count={3} messages={infos} />
</Box>
</Box>

<Typography sx={{ mt: 4, fontWeight: 'bold' }}>C-CDA MDHT Conformance</Typography>
</Box>
)
}
38 changes: 38 additions & 0 deletions src/components/c-cda/validation/ValidationStatusIndicator.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import React from 'react'
import { Box, Typography, LinearProgress } from '@mui/material'

type ValidationStatus = 'error' | 'warning' | 'pass'

interface ValidationStatusIndicatorProps {
status: ValidationStatus
}

const ValidationStatusIndicator: React.FC<ValidationStatusIndicatorProps> = ({ status }) => {
const statusMap: { [key in ValidationStatus]: { color: string; value: number } } = {
error: { color: '#FF5252', value: 5 },
warning: { color: '#83380E', value: 50 },
pass: { color: '#122953', value: 100 },
}

const statusInfo = statusMap[status]

return (
<Box sx={{ width: '100%', mt: 1 }}>
<Typography>Validation Status: {status.charAt(0).toUpperCase() + status.slice(1)}</Typography>
<LinearProgress
variant="determinate"
value={statusInfo.value}
sx={{
height: '5px',
mt: 2,
backgroundColor: 'lightgrey',
'& .MuiLinearProgress-bar': {
backgroundColor: statusInfo.color,
},
}}
/>
</Box>
)
}

export default ValidationStatusIndicator
93 changes: 93 additions & 0 deletions src/components/c-cda/validation/ValidatorLoadingCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import React, { useState, useEffect, FC } from 'react'
import { Card, CardContent, Typography, IconButton, LinearProgress, Backdrop, Button } from '@mui/material'
import CloseIcon from '@mui/icons-material/Close'
import ValidatorResultsCard from './ValidatorResultsCard'

interface ValidatorLoadingCardProps {
open: boolean
handleClose: () => void
onLoadingComplete: () => void
}

const ValidatorLoadingCard: FC<ValidatorLoadingCardProps> = ({ open, handleClose, onLoadingComplete }) => {
const [progress, setProgress] = useState(0)

useEffect(() => {
if (open) {
setProgress(0)
const timer = setInterval(() => {
setProgress((prevProgress) => {
if (prevProgress >= 100) {
clearInterval(timer)
onLoadingComplete()
return 100
}
return prevProgress + 10
})
}, 300)

return () => {
clearInterval(timer)
}
} else {
setProgress(0)
}
}, [open, onLoadingComplete])

return (
<Backdrop sx={{ color: '#fff', zIndex: (theme) => theme.zIndex.drawer + 1 }} open={open}>
<Card sx={{ position: 'absolute', width: '30%', minWidth: 300, pl: '18px', pr: '18px' }}>
<CardContent>
<IconButton sx={{ position: 'absolute', right: 18, top: 8 }} onClick={handleClose}>
<CloseIcon />
</IconButton>
<Typography variant="h3" component="div" sx={{ fontWeight: 'bold' }}>
Your files are validating...
</Typography>
<Typography sx={{ mt: 2, mb: 2 }}>Estimate time: {Math.round((1 - progress / 100) * 3)} seconds</Typography>
<LinearProgress
variant="determinate"
value={progress}
sx={{
height: 4,
borderRadius: 5,
mt: 2,
backgroundColor: 'lightblue',
'& .MuiLinearProgress-bar': {
backgroundColor: 'blue',
},
}}
/>
<Typography sx={{ mt: 2 }}>
Don&apos;t close out this given tab or refresh the screen, if you do the validation will stop.
</Typography>
</CardContent>
</Card>
</Backdrop>
)
}
const ValidationComponent = () => {
const [validationOpen, setValidationOpen] = useState(false)
const [resultsOpen, setResultsOpen] = useState(false)

const handleLoadingComplete = () => {
setValidationOpen(false)
setResultsOpen(true)
}

return (
<>
<Button variant="contained" onClick={() => setValidationOpen(true)}>
VALIDATE
</Button>
<ValidatorLoadingCard
open={validationOpen}
handleClose={() => setValidationOpen(false)}
onLoadingComplete={handleLoadingComplete}
/>
<ValidatorResultsCard open={resultsOpen} handleClose={() => setResultsOpen(false)} />
</>
)
}

export default ValidationComponent
92 changes: 92 additions & 0 deletions src/components/c-cda/validation/ValidatorResultsCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import React, { FC, useRef } from 'react'
import {
Backdrop,
Card,
IconButton,
Typography,
Accordion,
AccordionSummary,
AccordionDetails,
Button,
Box,
Divider,
} from '@mui/material'
import CloseIcon from '@mui/icons-material/Close'
import ExpandMoreIcon from '@mui/icons-material/ExpandMore'
import KeyboardArrowUpIcon from '@mui/icons-material/KeyboardArrowUp'
import ValidatorResultsSummary from './ValidationResultsSummary'

interface ValidatorResultsCardProps {
open: boolean
handleClose: () => void
}

const ValidatorResultsCard: FC<ValidatorResultsCardProps> = ({ open, handleClose }) => {
const handleBackToTop = () => {
if (mainContentRef.current) {
mainContentRef.current.scrollTop = 0
}
}

const mainContentRef = useRef<HTMLDivElement>(null)

return (
<Backdrop sx={{ color: '#fff', zIndex: (theme) => theme.zIndex.drawer + 1 }} open={open} onClick={handleClose}>
<Card
sx={{
position: 'absolute',
width: '85%',
height: '80%',
minWidth: 300,
display: 'flex',
flexDirection: 'column',
}}
onClick={(e) => e.stopPropagation()}
>
<Box sx={{ p: 2, display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
<Typography variant="h5">Validation Results</Typography>
<IconButton onClick={handleClose}>
<CloseIcon />
</IconButton>
</Box>
<Divider />
<Box sx={{ display: 'flex', flexGrow: 1, overflow: 'hidden' }}>
<Box sx={{ width: '20%', borderRight: 1, borderColor: 'divider' }}>
<Typography sx={{ p: 2, fontWeight: 'bold' }}>Summary & Results</Typography>

<Accordion>
<AccordionSummary expandIcon={<ExpandMoreIcon />}>
<Typography sx={{ fontWeight: 'bold' }}>S&CC Vocabulary Validation Conformance</Typography>
</AccordionSummary>
<AccordionDetails>{/* future accordion options */}</AccordionDetails>
</Accordion>

<Accordion>
<AccordionSummary expandIcon={<ExpandMoreIcon />}>
<Typography sx={{ fontWeight: 'bold' }}>S&CC Reference C-CDA Validation</Typography>
</AccordionSummary>
<AccordionDetails>{/* future accordion options */}</AccordionDetails>
</Accordion>

<Typography sx={{ p: 2, fontWeight: 'bold' }}>Original C-CDA</Typography>
</Box>

<Box ref={mainContentRef} sx={{ width: '80%', overflow: 'auto', p: 4 }}>
<ValidatorResultsSummary />
</Box>
</Box>
<Divider />
<Box sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', p: 2 }}>
<Button variant="contained" color="primary">
Save Results
</Button>
<Button variant="text" startIcon={<KeyboardArrowUpIcon />} onClick={handleBackToTop}>
Back to Top
</Button>
</Box>
</Card>
</Backdrop>
)
}

export default ValidatorResultsCard
3 changes: 2 additions & 1 deletion src/components/c-cda/validation/uscdi-v3/V3FullTab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
Typography,
} from '@mui/material'
import { useState } from 'react'
import ValidationComponent from '../ValidatorLoadingCard'

// TODO: Create a generic version of this to Support unique functionality
// (API calls, select data, etc.) of different C-CDA validators without duplication
Expand Down Expand Up @@ -145,7 +146,7 @@ export default function V3FullTab() {

{/* Buttons */}
<Box display="flex" flexDirection="row" justifyContent="space-between" sx={{ pt: 4 }}>
<Button variant="contained">VALIDATE</Button>
<ValidationComponent></ValidationComponent>
<Box>
<Button variant="outlined">DOWNLOAD SELECTED SCENARIO FILE</Button>
<Button sx={{ ml: 2 }} variant="outlined">
Expand Down

0 comments on commit cdd54a5

Please sign in to comment.