chore(client): Migration of SolutionViewer component to Typescript. (#43694)
* The Solutionviewer .js file has been migrated into the .tsx file. * Apply suggestions from code review I have added the suggestions and before adding them to the commit, I have checked it once locally and it doesn't throw any new error. Co-authored-by: Nicholas Carrigan (he/him) <nhcarrigan@gmail.com> * Update the SolutionViewer.tsx Added the "null" and "undefined" type to "solution" property. * Update SolutionViewer.tsx * Update ProjectModal.tsx * Update ProjectModal.tsx * Update SolutionViewer.tsx * Update ProjectModal.tsx * Apply suggestions from code review Co-authored-by: Shaun Hamilton <shauhami020@gmail.com> * Update client/src/components/SolutionViewer/ProjectModal.tsx Co-authored-by: Shaun Hamilton <shauhami020@gmail.com> * Apply suggestions from code review Co-authored-by: Shaun Hamilton <shauhami020@gmail.com> * Apply suggestions from code review Co-authored-by: Nicholas Carrigan (he/him) <nhcarrigan@gmail.com> * type of solution prop has been changed into "solution?:string;" * assert solution is not `null` for modal Co-authored-by: Nicholas Carrigan (he/him) <nhcarrigan@gmail.com> Co-authored-by: Shaun Hamilton <shauhami020@gmail.com>
This commit is contained in:
@ -32,7 +32,7 @@ type SolutionStateType = {
|
||||
const initSolutionState: SolutionStateType = {
|
||||
projectTitle: '',
|
||||
challengeFiles: null,
|
||||
solution: null,
|
||||
solution: '',
|
||||
isOpen: false
|
||||
};
|
||||
|
||||
@ -156,10 +156,10 @@ const ShowProjectLinks = (props: IShowProjectLinksProps): JSX.Element => {
|
||||
</li>
|
||||
)
|
||||
);
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-call */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-return */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
|
||||
/* eslint-enable @typescript-eslint/no-unsafe-assignment */
|
||||
/* eslint-enable @typescript-eslint/no-unsafe-call */
|
||||
/* eslint-enable @typescript-eslint/no-unsafe-return */
|
||||
/* eslint-enable @typescript-eslint/no-unsafe-member-access */
|
||||
};
|
||||
|
||||
const {
|
||||
@ -185,7 +185,9 @@ const ShowProjectLinks = (props: IShowProjectLinksProps): JSX.Element => {
|
||||
handleSolutionModalHide={handleSolutionModalHide}
|
||||
isOpen={isOpen}
|
||||
projectTitle={projectTitle}
|
||||
solution={solution}
|
||||
// 'solution' is theoretically never 'null', if it a JsAlgoData cert
|
||||
// which is the only time we use the modal
|
||||
solution={solution as undefined | string}
|
||||
/>
|
||||
) : null}
|
||||
<Trans i18nKey='certification.project.footnote'>
|
||||
|
@ -1,34 +1,24 @@
|
||||
import { Button, Modal } from '@freecodecamp/react-bootstrap';
|
||||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { ChallengeFiles } from '../../redux/prop-types';
|
||||
import SolutionViewer from './SolutionViewer';
|
||||
|
||||
const propTypes = {
|
||||
challengeFiles: PropTypes.array,
|
||||
// TODO: removed once refactored to TS
|
||||
// PropTypes.shape({
|
||||
// contents: PropTypes.string,
|
||||
// ext: PropTypes.string,
|
||||
// key: PropTypes.string,
|
||||
// name: PropTypes.string,
|
||||
// path: PropTypes.string
|
||||
// })
|
||||
// ),
|
||||
handleSolutionModalHide: PropTypes.func,
|
||||
isOpen: PropTypes.bool,
|
||||
projectTitle: PropTypes.string,
|
||||
solution: PropTypes.string
|
||||
type ProjectModalProps = {
|
||||
challengeFiles: ChallengeFiles;
|
||||
handleSolutionModalHide: () => void;
|
||||
isOpen: boolean;
|
||||
projectTitle: string;
|
||||
solution?: string;
|
||||
};
|
||||
|
||||
const ProjectModal = props => {
|
||||
const {
|
||||
isOpen,
|
||||
projectTitle,
|
||||
challengeFiles,
|
||||
solution,
|
||||
handleSolutionModalHide
|
||||
} = props;
|
||||
const ProjectModal = ({
|
||||
isOpen,
|
||||
projectTitle,
|
||||
challengeFiles,
|
||||
solution,
|
||||
handleSolutionModalHide
|
||||
}: ProjectModalProps): JSX.Element => {
|
||||
const { t } = useTranslation();
|
||||
return (
|
||||
<Modal
|
||||
@ -54,7 +44,6 @@ const ProjectModal = props => {
|
||||
);
|
||||
};
|
||||
|
||||
ProjectModal.propTypes = propTypes;
|
||||
ProjectModal.displayName = 'ProjectModal';
|
||||
|
||||
export default ProjectModal;
|
@ -1,70 +0,0 @@
|
||||
import { Panel } from '@freecodecamp/react-bootstrap';
|
||||
import Prism from 'prismjs';
|
||||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
|
||||
const prismLang = {
|
||||
css: 'css',
|
||||
js: 'javascript',
|
||||
jsx: 'javascript',
|
||||
html: 'markup'
|
||||
};
|
||||
|
||||
const SolutionViewer = ({
|
||||
challengeFiles,
|
||||
solution = '// The solution is not available for this project'
|
||||
}) =>
|
||||
challengeFiles?.length ? (
|
||||
challengeFiles.map(challengeFile => (
|
||||
<Panel
|
||||
bsStyle='primary'
|
||||
className='solution-viewer'
|
||||
key={challengeFile.ext}
|
||||
>
|
||||
<Panel.Heading>{challengeFile.ext.toUpperCase()}</Panel.Heading>
|
||||
<Panel.Body>
|
||||
<pre>
|
||||
<code
|
||||
className={`language-${prismLang[challengeFile.ext]}`}
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: Prism.highlight(
|
||||
challengeFile.contents.trim(),
|
||||
Prism.languages[prismLang[challengeFile.ext]]
|
||||
)
|
||||
}}
|
||||
/>
|
||||
</pre>
|
||||
</Panel.Body>
|
||||
</Panel>
|
||||
))
|
||||
) : (
|
||||
<Panel
|
||||
bsStyle='primary'
|
||||
className='solution-viewer'
|
||||
key={solution.slice(0, 10)}
|
||||
>
|
||||
<Panel.Heading>JS</Panel.Heading>
|
||||
<Panel.Body>
|
||||
<pre>
|
||||
<code
|
||||
className='language-markup'
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: Prism.highlight(
|
||||
solution.trim(),
|
||||
Prism.languages.js,
|
||||
'javascript'
|
||||
)
|
||||
}}
|
||||
/>
|
||||
</pre>
|
||||
</Panel.Body>
|
||||
</Panel>
|
||||
);
|
||||
|
||||
SolutionViewer.displayName = 'SolutionViewer';
|
||||
SolutionViewer.propTypes = {
|
||||
challengeFiles: PropTypes.array,
|
||||
solution: PropTypes.string
|
||||
};
|
||||
|
||||
export default SolutionViewer;
|
67
client/src/components/SolutionViewer/SolutionViewer.tsx
Normal file
67
client/src/components/SolutionViewer/SolutionViewer.tsx
Normal file
@ -0,0 +1,67 @@
|
||||
import { Panel } from '@freecodecamp/react-bootstrap';
|
||||
import Prism from 'prismjs';
|
||||
import React from 'react';
|
||||
import { ChallengeFile, ChallengeFiles } from '../../redux/prop-types';
|
||||
|
||||
type SolutionViewerProps = {
|
||||
challengeFiles: ChallengeFiles;
|
||||
solution?: string;
|
||||
};
|
||||
|
||||
function SolutionViewer({
|
||||
challengeFiles,
|
||||
solution = '// The solution is not available for this project'
|
||||
}: SolutionViewerProps): JSX.Element {
|
||||
return (
|
||||
<>
|
||||
{challengeFiles?.length ? (
|
||||
challengeFiles.map((challengeFile: ChallengeFile) => (
|
||||
<Panel
|
||||
bsStyle='primary'
|
||||
className='solution-viewer'
|
||||
key={challengeFile}
|
||||
>
|
||||
<Panel.Heading>{challengeFile.ext.toUpperCase()}</Panel.Heading>
|
||||
|
||||
<Panel.Body>
|
||||
<pre>
|
||||
<code
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: Prism.highlight(
|
||||
challengeFile.contents.trim(),
|
||||
Prism.languages[challengeFile.ext],
|
||||
''
|
||||
)
|
||||
}}
|
||||
/>
|
||||
</pre>
|
||||
</Panel.Body>
|
||||
</Panel>
|
||||
))
|
||||
) : (
|
||||
<Panel
|
||||
bsStyle='primary'
|
||||
className='solution-viewer'
|
||||
key={solution.slice(0, 10)}
|
||||
>
|
||||
<Panel.Heading>JS</Panel.Heading>
|
||||
<Panel.Body>
|
||||
<pre>
|
||||
<code
|
||||
className='language-markup'
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: Prism.highlight(
|
||||
solution.trim(),
|
||||
Prism.languages.js,
|
||||
'javascript'
|
||||
)
|
||||
}}
|
||||
/>
|
||||
</pre>
|
||||
</Panel.Body>
|
||||
</Panel>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
export default SolutionViewer;
|
Reference in New Issue
Block a user