Skip to content

Commit

Permalink
Separate props interface into parts; add logic to convert api respons…
Browse files Browse the repository at this point in the history
…e to array.
  • Loading branch information
Matthew-Grayson committed Apr 14, 2024
1 parent 94889f4 commit 61a783b
Show file tree
Hide file tree
Showing 2 changed files with 134 additions and 108 deletions.
91 changes: 29 additions & 62 deletions frontend/src/components/ReadySetCyber/RSCDetail.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,56 +5,42 @@ import Grid from '@mui/material/Grid';
import Stack from '@mui/material/Stack';
import Divider from '@mui/material/Divider';
import Button from '@mui/material/Button';
import Typography from '@mui/material/Typography';
import { RSCSideNav } from './RSCSideNav';
import { RSCResult } from './RSCResult';
import { RSCQuestion } from './RSCQuestion';
import { Typography } from '@mui/material';
import { Category, Entry, RSCQuestion } from './RSCQuestion';
import { useAuthContext } from 'context';

export const RSCDetail: React.FC = () => {
const { apiGet } = useAuthContext();
const { id } = useParams<{ id: string }>();
const [details, setDetails] = React.useState<any>({});
const [categories, setCategories] = useState<Category[]>([]);

const fetchResult = useCallback(async () => {
try {
const data = await apiGet(`/assessments/${id}`);
// console.log(data["Data Security"]);
// console.log(data["Data Security"][0]);
// console.log(data["Data Security"][0]["question"]);
// console.log(data["Data Security"][0]["question"].longForm);

setDetails(data);
console.log('API Response:', data); // Continue to log the data for verification
if (data && typeof data === 'object' && !Array.isArray(data)) {
const transformedCategories = Object.entries(data).map(
([name, entries]) => ({
name,
entries: entries as Entry[]
})
);
setCategories(transformedCategories);
} else {
console.error('Unexpected response format:', data);
setCategories([]); // Fallback to an empty array if the format isn't correct
}
} catch (e) {
console.error(e);
console.error('Failed to fetch categories:', e);
setCategories([]); // Ensure categories is reset to an empty array on error
}
}, [apiGet, id]);

useEffect(() => {
fetchResult();
}, [fetchResult]);

const dataSecurity = details['Data Security'];

// console.log("Key 0: ", Object.keys(data)[0]);

// console.log("This is Security: ", dataSecurity[0]);
// console.log("Details: ", typeof details);
// for (const question in data) {
// console.log(question);
// }

// Object.keys(data).forEach((key)=> {
// console.log(key, dataSecurity[key]);
// }
// );

// Object.keys(details).forEach((key)=> {
// console.log(key, details[key]);
// // Object.keys(details[key]).forEach((key2)=> {
// // console.log(key2, details[key][key2]);
// // });
// });
console.log('Transformed categories:', categories);

return (
<Box sx={{ flexGrow: 1, padding: 2 }}>
Expand All @@ -64,10 +50,10 @@ export const RSCDetail: React.FC = () => {
</Grid>
<Grid item xs={8}>
<Box sx={{ flexGrow: 1, padding: 2, backgroundColor: 'white' }}>
<Stack>
<Stack spacing={2}>
<Stack
direction="row"
justifyContent={'space-between'}
justifyContent="space-between"
alignItems="center"
padding={2}
>
Expand All @@ -79,8 +65,10 @@ export const RSCDetail: React.FC = () => {
</Button>
</Stack>
<Divider />
<h3>Thank you for completing the ReadySetCyber questionnaire!</h3>
<p>
<Typography variant="h6" component="h3" gutterBottom>
Thank you for completing the ReadySetCyber questionnaire!
</Typography>
<Typography>
Below, you’ll find a full summary of your completed
ReadySetCyber questionnaire. Please note the areas where you can
improve your organization’s cybersecurity posture, along with
Expand All @@ -90,31 +78,10 @@ export const RSCDetail: React.FC = () => {
Crossfeed, CISA’s Attack Surface Management platform, for free
vulnerability scanning services to kickstart or enhance your
cybersecurity measures.
</p>
<Box>
{/* <RSCResult
id={result.id}
type={result.type}
createdAt={result.date}
categories={[]}
questions={[]}
/> */}
</Box>
{/* {console.log("Details: ", details)} */}
{/* {details.forEach((detail) => {
<>
<RSCQuestion key={detail.id} question={detail} />
<br />
</>
}); */}
<div>
{Object.entries(details).map(([detail]) => (
// <div key={detail}>
// <strong>{detail}:</strong>
// </div>
<RSCQuestion key={detail} category={details} />
))}
</div>
</Typography>
{categories.map((category, index) => (
<RSCQuestion key={index} categories={[category]} />
))}
</Stack>
</Box>
</Grid>
Expand Down
151 changes: 105 additions & 46 deletions frontend/src/components/ReadySetCyber/RSCQuestion.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,59 +5,118 @@ import Stack from '@mui/material/Stack';
import Button from '@mui/material/Button';

interface Props {
category: {
question: {
id: string;
longForm: string;
number: string;
};
selection: string;
};
categories: Category[];
}

export const RSCQuestion: React.FC<Props> = (props) => {
const question = props.category.question;
const category = props.category;
const answers = props.category.selection;
export interface Category {
entries: Entry[];
name: string;
}

console.log(
'Question: ',
Object.entries(category).map(([key, value]) => ({
key,
value
}))
);
export interface Entry {
question: Question;
selection: string;
}

interface Question {
description: string;
longForm: string;
name: string;
number: string;
resources: Resource[];
}

interface Resource {
description: string;
name: string;
type: string;
url: string;
}

export const RSCQuestion: React.FC<Props> = ({ categories }) => {
return (
<div>
<Box
sx={{ width: '100%', bgcolor: '#D3D3D3', padding: 2, borderRadius: 2 }}
>
{/* <Typography variant="h6" gutterBottom component="div">
Question {question.number}
</Typography> */}
<Typography variant="h6" gutterBottom component="div">
{question.longForm}
</Typography>
<Stack direction="row" spacing={2} padding={2} paddingLeft={0}>
<Button key={answers} variant="contained" color="primary">
{answers}{' '}
</Button>
</Stack>
<Box
sx={{
width: '100%',
bgcolor: 'background.paper',
padding: 2,
borderRadius: 2
}}
>
<h3>Recommended Resources</h3>
<h4>Resource Type</h4>
<h5>Resource Title</h5>
<p>Resource Description</p>
{categories.map((category, catIndex) => (
<Box key={catIndex} sx={{ marginBottom: 4 }}>
<Typography
variant="h5"
gutterBottom
component="div"
sx={{ marginTop: 2, color: '#1976d2' }}
>
{category.name}
</Typography>
{category.entries.map((entry, entryIndex) => (
<Box
key={entryIndex}
sx={{
width: '100%',
bgcolor: '#f0f0f0',
padding: 2,
borderRadius: 2,
marginBottom: 2
}}
>
<Typography variant="h6" gutterBottom>
Question {entry.question.number}
</Typography>
<Typography variant="subtitle1" gutterBottom>
{entry.question.longForm}
</Typography>
{entry.question.description && (
<Typography variant="body2" sx={{ marginBottom: 2 }}>
{entry.question.description}
</Typography>
)}
<Typography variant="subtitle2" gutterBottom>
Response: {entry.selection}
</Typography>
{entry.question.resources.length > 0 && (
<Box
sx={{
bgcolor: 'white',
borderRadius: 1,
padding: 2,
marginTop: 1
}}
>
<Typography variant="h6" gutterBottom>
Recommended Resources
</Typography>
{entry.question.resources.map((resource, resIndex) => (
<Box
key={resIndex}
sx={{
borderBottom: '1px solid #ccc',
paddingBottom: 1,
marginBottom: 1
}}
>
<Typography variant="subtitle1">
{resource.type}
</Typography>
<Typography variant="subtitle2">
{resource.name}
</Typography>
<Typography variant="body2">
{resource.description}
</Typography>
<Button
variant="outlined"
color="primary"
href={resource.url}
target="_blank"
>
Visit Resource
</Button>
</Box>
))}
</Box>
)}
</Box>
))}
</Box>
</Box>
))}
</div>
);
};

0 comments on commit 61a783b

Please sign in to comment.