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 = {
|
const initSolutionState: SolutionStateType = {
|
||||||
projectTitle: '',
|
projectTitle: '',
|
||||||
challengeFiles: null,
|
challengeFiles: null,
|
||||||
solution: null,
|
solution: '',
|
||||||
isOpen: false
|
isOpen: false
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -156,10 +156,10 @@ const ShowProjectLinks = (props: IShowProjectLinksProps): JSX.Element => {
|
|||||||
</li>
|
</li>
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
|
/* eslint-enable @typescript-eslint/no-unsafe-assignment */
|
||||||
/* eslint-disable @typescript-eslint/no-unsafe-call */
|
/* eslint-enable @typescript-eslint/no-unsafe-call */
|
||||||
/* eslint-disable @typescript-eslint/no-unsafe-return */
|
/* eslint-enable @typescript-eslint/no-unsafe-return */
|
||||||
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
|
/* eslint-enable @typescript-eslint/no-unsafe-member-access */
|
||||||
};
|
};
|
||||||
|
|
||||||
const {
|
const {
|
||||||
@ -185,7 +185,9 @@ const ShowProjectLinks = (props: IShowProjectLinksProps): JSX.Element => {
|
|||||||
handleSolutionModalHide={handleSolutionModalHide}
|
handleSolutionModalHide={handleSolutionModalHide}
|
||||||
isOpen={isOpen}
|
isOpen={isOpen}
|
||||||
projectTitle={projectTitle}
|
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}
|
) : null}
|
||||||
<Trans i18nKey='certification.project.footnote'>
|
<Trans i18nKey='certification.project.footnote'>
|
||||||
|
@ -1,34 +1,24 @@
|
|||||||
import { Button, Modal } from '@freecodecamp/react-bootstrap';
|
import { Button, Modal } from '@freecodecamp/react-bootstrap';
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { ChallengeFiles } from '../../redux/prop-types';
|
||||||
import SolutionViewer from './SolutionViewer';
|
import SolutionViewer from './SolutionViewer';
|
||||||
|
|
||||||
const propTypes = {
|
type ProjectModalProps = {
|
||||||
challengeFiles: PropTypes.array,
|
challengeFiles: ChallengeFiles;
|
||||||
// TODO: removed once refactored to TS
|
handleSolutionModalHide: () => void;
|
||||||
// PropTypes.shape({
|
isOpen: boolean;
|
||||||
// contents: PropTypes.string,
|
projectTitle: string;
|
||||||
// ext: PropTypes.string,
|
solution?: string;
|
||||||
// key: PropTypes.string,
|
|
||||||
// name: PropTypes.string,
|
|
||||||
// path: PropTypes.string
|
|
||||||
// })
|
|
||||||
// ),
|
|
||||||
handleSolutionModalHide: PropTypes.func,
|
|
||||||
isOpen: PropTypes.bool,
|
|
||||||
projectTitle: PropTypes.string,
|
|
||||||
solution: PropTypes.string
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const ProjectModal = props => {
|
const ProjectModal = ({
|
||||||
const {
|
isOpen,
|
||||||
isOpen,
|
projectTitle,
|
||||||
projectTitle,
|
challengeFiles,
|
||||||
challengeFiles,
|
solution,
|
||||||
solution,
|
handleSolutionModalHide
|
||||||
handleSolutionModalHide
|
}: ProjectModalProps): JSX.Element => {
|
||||||
} = props;
|
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
@ -54,7 +44,6 @@ const ProjectModal = props => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
ProjectModal.propTypes = propTypes;
|
|
||||||
ProjectModal.displayName = 'ProjectModal';
|
ProjectModal.displayName = 'ProjectModal';
|
||||||
|
|
||||||
export default 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