fix: Render completed checkmark in ChallengeTitle (#36746)
* fix: Render completed checkmark in ChallengeTitle when user has passed the challenge * fix: Update ChallengeTitle snapshot
This commit is contained in:
@ -3,6 +3,7 @@ import PropTypes from 'prop-types';
|
|||||||
import Link from '../../../components/helpers/Link';
|
import Link from '../../../components/helpers/Link';
|
||||||
|
|
||||||
import './challenge-title.css';
|
import './challenge-title.css';
|
||||||
|
import GreenPass from '../../../assets/icons/GreenPass';
|
||||||
|
|
||||||
const propTypes = {
|
const propTypes = {
|
||||||
children: PropTypes.string,
|
children: PropTypes.string,
|
||||||
@ -21,13 +22,6 @@ function ChallengeTitle({
|
|||||||
prevChallengePath,
|
prevChallengePath,
|
||||||
showPrevNextBtns
|
showPrevNextBtns
|
||||||
}) {
|
}) {
|
||||||
let icon = null;
|
|
||||||
if (isCompleted) {
|
|
||||||
icon = (
|
|
||||||
// TODO Use SVG here
|
|
||||||
<i className='ion-checkmark text-primary' title='Completed' />
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return (
|
return (
|
||||||
<div className='challenge-title-wrap'>
|
<div className='challenge-title-wrap'>
|
||||||
{showPrevNextBtns ? (
|
{showPrevNextBtns ? (
|
||||||
@ -41,7 +35,11 @@ function ChallengeTitle({
|
|||||||
) : null}
|
) : null}
|
||||||
<h2 className='text-center challenge-title'>
|
<h2 className='text-center challenge-title'>
|
||||||
{children || 'Happy Coding!'}
|
{children || 'Happy Coding!'}
|
||||||
{icon}
|
{isCompleted ? (
|
||||||
|
<GreenPass
|
||||||
|
style={{ height: '15px', width: '15px', marginLeft: '5px' }}
|
||||||
|
/>
|
||||||
|
) : null}
|
||||||
</h2>
|
</h2>
|
||||||
{showPrevNextBtns ? (
|
{showPrevNextBtns ? (
|
||||||
<Link
|
<Link
|
||||||
|
@ -7,13 +7,15 @@ import ChallengeDescription from './Challenge-Description';
|
|||||||
import ToolPanel from './Tool-Panel';
|
import ToolPanel from './Tool-Panel';
|
||||||
import TestSuite from './Test-Suite';
|
import TestSuite from './Test-Suite';
|
||||||
|
|
||||||
import { challengeTestsSelector } from '../redux';
|
import { challengeTestsSelector, isChallengeCompletedSelector } from '../redux';
|
||||||
import { createSelector } from 'reselect';
|
import { createSelector } from 'reselect';
|
||||||
import './side-panel.css';
|
import './side-panel.css';
|
||||||
|
|
||||||
const mapStateToProps = createSelector(
|
const mapStateToProps = createSelector(
|
||||||
|
isChallengeCompletedSelector,
|
||||||
challengeTestsSelector,
|
challengeTestsSelector,
|
||||||
tests => ({
|
(isChallengeCompleted, tests) => ({
|
||||||
|
isChallengeCompleted,
|
||||||
tests
|
tests
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
@ -25,6 +27,7 @@ const propTypes = {
|
|||||||
guideUrl: PropTypes.string,
|
guideUrl: PropTypes.string,
|
||||||
instructions: PropTypes.string,
|
instructions: PropTypes.string,
|
||||||
introPath: PropTypes.string,
|
introPath: PropTypes.string,
|
||||||
|
isChallengeCompleted: PropTypes.bool,
|
||||||
nextChallengePath: PropTypes.string,
|
nextChallengePath: PropTypes.string,
|
||||||
prevChallengePath: PropTypes.string,
|
prevChallengePath: PropTypes.string,
|
||||||
section: PropTypes.string,
|
section: PropTypes.string,
|
||||||
@ -59,6 +62,7 @@ export class SidePanel extends Component {
|
|||||||
description,
|
description,
|
||||||
instructions,
|
instructions,
|
||||||
introPath,
|
introPath,
|
||||||
|
isChallengeCompleted,
|
||||||
guideUrl,
|
guideUrl,
|
||||||
nextChallengePath,
|
nextChallengePath,
|
||||||
prevChallengePath,
|
prevChallengePath,
|
||||||
@ -73,6 +77,7 @@ export class SidePanel extends Component {
|
|||||||
<div>
|
<div>
|
||||||
<ChallengeTitle
|
<ChallengeTitle
|
||||||
introPath={introPath}
|
introPath={introPath}
|
||||||
|
isCompleted={isChallengeCompleted}
|
||||||
nextChallengePath={nextChallengePath}
|
nextChallengePath={nextChallengePath}
|
||||||
prevChallengePath={prevChallengePath}
|
prevChallengePath={prevChallengePath}
|
||||||
showPrevNextBtns={showPrevNextBtns}
|
showPrevNextBtns={showPrevNextBtns}
|
||||||
|
@ -15,10 +15,64 @@ exports[`<ChallengeTitle/> renders correctly 1`] = `
|
|||||||
className="text-center challenge-title"
|
className="text-center challenge-title"
|
||||||
>
|
>
|
||||||
title text
|
title text
|
||||||
<i
|
<span
|
||||||
className="ion-checkmark text-primary"
|
className="sr-only"
|
||||||
title="Completed"
|
>
|
||||||
/>
|
Passed
|
||||||
|
</span>
|
||||||
|
<svg
|
||||||
|
height="50"
|
||||||
|
style={
|
||||||
|
Object {
|
||||||
|
"height": "15px",
|
||||||
|
"marginLeft": "5px",
|
||||||
|
"width": "15px",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
viewBox="0 0 200 200"
|
||||||
|
width="50"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<g>
|
||||||
|
<title>
|
||||||
|
Passed
|
||||||
|
</title>
|
||||||
|
<circle
|
||||||
|
cx="100"
|
||||||
|
cy="99"
|
||||||
|
fill="#858591"
|
||||||
|
r="95"
|
||||||
|
stroke="#858591"
|
||||||
|
strokeDasharray="null"
|
||||||
|
strokeLinecap="null"
|
||||||
|
strokeLinejoin="null"
|
||||||
|
/>
|
||||||
|
<rect
|
||||||
|
fill="#ffffff"
|
||||||
|
height="30"
|
||||||
|
stroke="#ffffff"
|
||||||
|
strokeDasharray="null"
|
||||||
|
strokeLinecap="null"
|
||||||
|
strokeLinejoin="null"
|
||||||
|
transform="rotate(-45, 120, 106.321)"
|
||||||
|
width="128.85878"
|
||||||
|
x="55.57059"
|
||||||
|
y="91.32089"
|
||||||
|
/>
|
||||||
|
<rect
|
||||||
|
fill="#ffffff"
|
||||||
|
height="30"
|
||||||
|
stroke="#ffffff"
|
||||||
|
strokeDasharray="null"
|
||||||
|
strokeLinecap="null"
|
||||||
|
strokeLinejoin="null"
|
||||||
|
transform="rotate(45, 66.75, 123.75)"
|
||||||
|
width="80.66548"
|
||||||
|
x="26.41726"
|
||||||
|
y="108.75"
|
||||||
|
/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
</h2>
|
</h2>
|
||||||
<a
|
<a
|
||||||
aria-label="Next lesson"
|
aria-label="Next lesson"
|
||||||
|
@ -13,6 +13,7 @@ import codeStorageEpic from './code-storage-epic';
|
|||||||
import { createExecuteChallengeSaga } from './execute-challenge-saga';
|
import { createExecuteChallengeSaga } from './execute-challenge-saga';
|
||||||
import { createCurrentChallengeSaga } from './current-challenge-saga';
|
import { createCurrentChallengeSaga } from './current-challenge-saga';
|
||||||
import { challengeTypes } from '../../../../utils/challengeTypes';
|
import { challengeTypes } from '../../../../utils/challengeTypes';
|
||||||
|
import { completedChallengesSelector } from '../../../redux';
|
||||||
|
|
||||||
export const ns = 'challenge';
|
export const ns = 'challenge';
|
||||||
export const backendNS = 'backendChallenge';
|
export const backendNS = 'backendChallenge';
|
||||||
@ -153,6 +154,11 @@ export const challengeFilesSelector = state => state[ns].challengeFiles;
|
|||||||
export const challengeMetaSelector = state => state[ns].challengeMeta;
|
export const challengeMetaSelector = state => state[ns].challengeMeta;
|
||||||
export const challengeTestsSelector = state => state[ns].challengeTests;
|
export const challengeTestsSelector = state => state[ns].challengeTests;
|
||||||
export const consoleOutputSelector = state => state[ns].consoleOut;
|
export const consoleOutputSelector = state => state[ns].consoleOut;
|
||||||
|
export const isChallengeCompletedSelector = state => {
|
||||||
|
const completedChallenges = completedChallengesSelector(state);
|
||||||
|
const { id: currentChallengeId } = challengeMetaSelector(state);
|
||||||
|
return completedChallenges.some(({ id }) => id === currentChallengeId);
|
||||||
|
};
|
||||||
export const isCodeLockedSelector = state => state[ns].isCodeLocked;
|
export const isCodeLockedSelector = state => state[ns].isCodeLocked;
|
||||||
export const isCompletionModalOpenSelector = state =>
|
export const isCompletionModalOpenSelector = state =>
|
||||||
state[ns].modal.completion;
|
state[ns].modal.completion;
|
||||||
|
Reference in New Issue
Block a user