fix(description): Adjust for new description format
This commit is contained in:
		@@ -26,13 +26,6 @@ export default function settingsController(app) {
 | 
				
			|||||||
    createValidatorErrorHandler(alertTypes.danger),
 | 
					    createValidatorErrorHandler(alertTypes.danger),
 | 
				
			||||||
    updateMyCurrentChallenge
 | 
					    updateMyCurrentChallenge
 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
  api.post(
 | 
					 | 
				
			||||||
    '/update-my-current-challenge',
 | 
					 | 
				
			||||||
    ifNoUser401,
 | 
					 | 
				
			||||||
    updateMyCurrentChallengeValidators,
 | 
					 | 
				
			||||||
    createValidatorErrorHandler(alertTypes.danger),
 | 
					 | 
				
			||||||
    updateMyCurrentChallenge
 | 
					 | 
				
			||||||
  );
 | 
					 | 
				
			||||||
  api.post('/update-my-portfolio', ifNoUser401, updateMyPortfolio);
 | 
					  api.post('/update-my-portfolio', ifNoUser401, updateMyPortfolio);
 | 
				
			||||||
  api.post('/update-my-projects', ifNoUser401, updateMyProjects);
 | 
					  api.post('/update-my-projects', ifNoUser401, updateMyProjects);
 | 
				
			||||||
  api.post(
 | 
					  api.post(
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,10 +1,11 @@
 | 
				
			|||||||
import helmet from 'helmet';
 | 
					import helmet from 'helmet';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { homeLocation } from '../../../config/env';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
let trusted = [
 | 
					let trusted = [
 | 
				
			||||||
  "'self'",
 | 
					  "'self'",
 | 
				
			||||||
  'https://search.freecodecamp.org',
 | 
					  'https://search.freecodecamp.org',
 | 
				
			||||||
  'https://www.freecodecamp.rocks',
 | 
					  homeLocation,
 | 
				
			||||||
  'https://api.freecodecamp.rocks',
 | 
					 | 
				
			||||||
  'https://' + process.env.AUTH0_DOMAIN
 | 
					  'https://' + process.env.AUTH0_DOMAIN
 | 
				
			||||||
];
 | 
					];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -12,9 +13,7 @@ const host = process.env.HOST || 'localhost';
 | 
				
			|||||||
const port = process.env.SYNC_PORT || '3000';
 | 
					const port = process.env.SYNC_PORT || '3000';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if (process.env.NODE_ENV !== 'production') {
 | 
					if (process.env.NODE_ENV !== 'production') {
 | 
				
			||||||
  trusted = trusted.concat([
 | 
					  trusted = trusted.concat([`ws://${host}:${port}`, 'http://localhost:8000']);
 | 
				
			||||||
    `ws://${host}:${port}`
 | 
					 | 
				
			||||||
  ]);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default function csp() {
 | 
					export default function csp() {
 | 
				
			||||||
@@ -73,11 +72,9 @@ export default function csp() {
 | 
				
			|||||||
        '*',
 | 
					        '*',
 | 
				
			||||||
        'data:'
 | 
					        'data:'
 | 
				
			||||||
      ],
 | 
					      ],
 | 
				
			||||||
      mediaSrc: [
 | 
					      mediaSrc: ['*.bitly.com', '*.amazonaws.com', '*.twitter.com'].concat(
 | 
				
			||||||
        '*.bitly.com',
 | 
					        trusted
 | 
				
			||||||
        '*.amazonaws.com',
 | 
					      ),
 | 
				
			||||||
        '*.twitter.com'
 | 
					 | 
				
			||||||
      ].concat(trusted),
 | 
					 | 
				
			||||||
      frameSrc: [
 | 
					      frameSrc: [
 | 
				
			||||||
        '*.gitter.im',
 | 
					        '*.gitter.im',
 | 
				
			||||||
        '*.gitter.im https:',
 | 
					        '*.gitter.im https:',
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -22,7 +22,7 @@ export const ChallengeNode = PropTypes.shape({
 | 
				
			|||||||
  block: PropTypes.string,
 | 
					  block: PropTypes.string,
 | 
				
			||||||
  challengeType: PropTypes.number,
 | 
					  challengeType: PropTypes.number,
 | 
				
			||||||
  dashedName: PropTypes.string,
 | 
					  dashedName: PropTypes.string,
 | 
				
			||||||
  description: PropTypes.arrayOf(PropTypes.string),
 | 
					  description: PropTypes.string,
 | 
				
			||||||
  files: PropTypes.shape({
 | 
					  files: PropTypes.shape({
 | 
				
			||||||
    indexhtml: FileType,
 | 
					    indexhtml: FileType,
 | 
				
			||||||
    indexjs: FileType
 | 
					    indexjs: FileType
 | 
				
			||||||
@@ -34,6 +34,7 @@ export const ChallengeNode = PropTypes.shape({
 | 
				
			|||||||
  guideUrl: PropTypes.string,
 | 
					  guideUrl: PropTypes.string,
 | 
				
			||||||
  head: PropTypes.arrayOf(PropTypes.string),
 | 
					  head: PropTypes.arrayOf(PropTypes.string),
 | 
				
			||||||
  challengeOrder: PropTypes.number,
 | 
					  challengeOrder: PropTypes.number,
 | 
				
			||||||
 | 
					  instructions: PropTypes.string,
 | 
				
			||||||
  isBeta: PropTypes.bool,
 | 
					  isBeta: PropTypes.bool,
 | 
				
			||||||
  isComingSoon: PropTypes.bool,
 | 
					  isComingSoon: PropTypes.bool,
 | 
				
			||||||
  isLocked: PropTypes.bool,
 | 
					  isLocked: PropTypes.bool,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -41,7 +41,7 @@ const reduxFormPropTypes = {
 | 
				
			|||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const propTypes = {
 | 
					const propTypes = {
 | 
				
			||||||
  description: PropTypes.arrayOf(PropTypes.string),
 | 
					  description: PropTypes.string,
 | 
				
			||||||
  executeChallenge: PropTypes.func.isRequired,
 | 
					  executeChallenge: PropTypes.func.isRequired,
 | 
				
			||||||
  id: PropTypes.string,
 | 
					  id: PropTypes.string,
 | 
				
			||||||
  output: PropTypes.string,
 | 
					  output: PropTypes.string,
 | 
				
			||||||
@@ -126,7 +126,8 @@ export class BackEnd extends Component {
 | 
				
			|||||||
        challengeNode: {
 | 
					        challengeNode: {
 | 
				
			||||||
          fields: { blockName, slug },
 | 
					          fields: { blockName, slug },
 | 
				
			||||||
          title,
 | 
					          title,
 | 
				
			||||||
          description
 | 
					          description,
 | 
				
			||||||
 | 
					          instructions
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
      output,
 | 
					      output,
 | 
				
			||||||
@@ -145,7 +146,10 @@ export class BackEnd extends Component {
 | 
				
			|||||||
        <Spacer />
 | 
					        <Spacer />
 | 
				
			||||||
        <div>
 | 
					        <div>
 | 
				
			||||||
          <ChallengeTitle>{blockNameTitle}</ChallengeTitle>
 | 
					          <ChallengeTitle>{blockNameTitle}</ChallengeTitle>
 | 
				
			||||||
          <ChallengeDescription description={description} />
 | 
					          <ChallengeDescription
 | 
				
			||||||
 | 
					            description={description}
 | 
				
			||||||
 | 
					            instructions={instructions}
 | 
				
			||||||
 | 
					          />
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
        <div>
 | 
					        <div>
 | 
				
			||||||
          <Form
 | 
					          <Form
 | 
				
			||||||
@@ -200,6 +204,7 @@ export const query = graphql`
 | 
				
			|||||||
      title
 | 
					      title
 | 
				
			||||||
      guideUrl
 | 
					      guideUrl
 | 
				
			||||||
      description
 | 
					      description
 | 
				
			||||||
 | 
					      instructions
 | 
				
			||||||
      challengeType
 | 
					      challengeType
 | 
				
			||||||
      fields {
 | 
					      fields {
 | 
				
			||||||
        blockName
 | 
					        blockName
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -177,6 +177,7 @@ class ShowClassic extends Component {
 | 
				
			|||||||
          fields: { blockName, slug },
 | 
					          fields: { blockName, slug },
 | 
				
			||||||
          title,
 | 
					          title,
 | 
				
			||||||
          description,
 | 
					          description,
 | 
				
			||||||
 | 
					          instructions,
 | 
				
			||||||
          videoUrl
 | 
					          videoUrl
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
@@ -227,6 +228,7 @@ class ShowClassic extends Component {
 | 
				
			|||||||
              className='full-height'
 | 
					              className='full-height'
 | 
				
			||||||
              description={description}
 | 
					              description={description}
 | 
				
			||||||
              guideUrl={createGuideUrl(slug)}
 | 
					              guideUrl={createGuideUrl(slug)}
 | 
				
			||||||
 | 
					              instructions={instructions}
 | 
				
			||||||
              section={dasherize(blockName)}
 | 
					              section={dasherize(blockName)}
 | 
				
			||||||
              title={blockNameTitle}
 | 
					              title={blockNameTitle}
 | 
				
			||||||
              videoUrl={videoUrl}
 | 
					              videoUrl={videoUrl}
 | 
				
			||||||
@@ -271,6 +273,7 @@ export const query = graphql`
 | 
				
			|||||||
    challengeNode(fields: { slug: { eq: $slug } }) {
 | 
					    challengeNode(fields: { slug: { eq: $slug } }) {
 | 
				
			||||||
      title
 | 
					      title
 | 
				
			||||||
      description
 | 
					      description
 | 
				
			||||||
 | 
					      instructions
 | 
				
			||||||
      challengeType
 | 
					      challengeType
 | 
				
			||||||
      videoUrl
 | 
					      videoUrl
 | 
				
			||||||
      fields {
 | 
					      fields {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,44 +1,29 @@
 | 
				
			|||||||
import React from 'react';
 | 
					import React, { Fragment } from 'react';
 | 
				
			||||||
import PropTypes from 'prop-types';
 | 
					import PropTypes from 'prop-types';
 | 
				
			||||||
import { Col, Row } from '@freecodecamp/react-bootstrap';
 | 
					import { Col, Row } from '@freecodecamp/react-bootstrap';
 | 
				
			||||||
import { descriptionRegex } from '../../../../utils';
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
import './challenge-description.css';
 | 
					import './challenge-description.css';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const propTypes = {
 | 
					const propTypes = {
 | 
				
			||||||
  description: PropTypes.arrayOf(PropTypes.string),
 | 
					  description: PropTypes.string,
 | 
				
			||||||
 | 
					  instructions: PropTypes.string,
 | 
				
			||||||
  section: PropTypes.string
 | 
					  section: PropTypes.string
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function renderDescription(description) {
 | 
					function ChallengeDescription({ description, instructions, section }) {
 | 
				
			||||||
  if (!Array.isArray(description)) {
 | 
					 | 
				
			||||||
    return null;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  return description.map((line, index) => {
 | 
					 | 
				
			||||||
    if (descriptionRegex.test(line)) {
 | 
					 | 
				
			||||||
      return (
 | 
					 | 
				
			||||||
        <div
 | 
					 | 
				
			||||||
          dangerouslySetInnerHTML={{ __html: line }}
 | 
					 | 
				
			||||||
          key={line.slice(-6) + index}
 | 
					 | 
				
			||||||
        />
 | 
					 | 
				
			||||||
      );
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    return (
 | 
					 | 
				
			||||||
      <p
 | 
					 | 
				
			||||||
        className='wrappable'
 | 
					 | 
				
			||||||
        dangerouslySetInnerHTML={{ __html: line }}
 | 
					 | 
				
			||||||
        key={line.slice(-6) + index}
 | 
					 | 
				
			||||||
      />
 | 
					 | 
				
			||||||
    );
 | 
					 | 
				
			||||||
  });
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
function ChallengeDescription({ description, section }) {
 | 
					 | 
				
			||||||
  // TODO: Remove bootstrap
 | 
					 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
    <Row>
 | 
					    <Row>
 | 
				
			||||||
      <Col className={`challenge-instructions ${section}`} xs={12}>
 | 
					      <Col className={`challenge-instructions ${section}`} xs={12}>
 | 
				
			||||||
        {renderDescription(description)}
 | 
					        <div dangerouslySetInnerHTML={{ __html: description }} />
 | 
				
			||||||
 | 
					        {instructions ? (
 | 
				
			||||||
 | 
					          <Fragment>
 | 
				
			||||||
 | 
					            <hr />
 | 
				
			||||||
 | 
					            <div dangerouslySetInnerHTML={{ __html: instructions }} />
 | 
				
			||||||
 | 
					            <hr />
 | 
				
			||||||
 | 
					          </Fragment>
 | 
				
			||||||
 | 
					        ) : (
 | 
				
			||||||
 | 
					          <hr />
 | 
				
			||||||
 | 
					        )}
 | 
				
			||||||
      </Col>
 | 
					      </Col>
 | 
				
			||||||
    </Row>
 | 
					    </Row>
 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,4 +1,4 @@
 | 
				
			|||||||
import React, { PureComponent } from 'react';
 | 
					import React, { Component } from 'react';
 | 
				
			||||||
import PropTypes from 'prop-types';
 | 
					import PropTypes from 'prop-types';
 | 
				
			||||||
import ReactDom from 'react-dom';
 | 
					import ReactDom from 'react-dom';
 | 
				
			||||||
import { connect } from 'react-redux';
 | 
					import { connect } from 'react-redux';
 | 
				
			||||||
@@ -29,16 +29,17 @@ const mapDispatchToProps = dispatch =>
 | 
				
			|||||||
const MathJax = global.MathJax;
 | 
					const MathJax = global.MathJax;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const propTypes = {
 | 
					const propTypes = {
 | 
				
			||||||
  description: PropTypes.arrayOf(PropTypes.string),
 | 
					  description: PropTypes.string,
 | 
				
			||||||
  guideUrl: PropTypes.string,
 | 
					  guideUrl: PropTypes.string,
 | 
				
			||||||
  initConsole: PropTypes.func.isRequired,
 | 
					  initConsole: PropTypes.func.isRequired,
 | 
				
			||||||
 | 
					  instructions: PropTypes.string,
 | 
				
			||||||
  section: PropTypes.string,
 | 
					  section: PropTypes.string,
 | 
				
			||||||
  tests: PropTypes.arrayOf(PropTypes.object),
 | 
					  tests: PropTypes.arrayOf(PropTypes.object),
 | 
				
			||||||
  title: PropTypes.string,
 | 
					  title: PropTypes.string,
 | 
				
			||||||
  videoUrl: PropTypes.string
 | 
					  videoUrl: PropTypes.string
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export class SidePanel extends PureComponent {
 | 
					export class SidePanel extends Component {
 | 
				
			||||||
  constructor(props) {
 | 
					  constructor(props) {
 | 
				
			||||||
    super(props);
 | 
					    super(props);
 | 
				
			||||||
    this.bindTopDiv = this.bindTopDiv.bind(this);
 | 
					    this.bindTopDiv = this.bindTopDiv.bind(this);
 | 
				
			||||||
@@ -84,6 +85,7 @@ export class SidePanel extends PureComponent {
 | 
				
			|||||||
    const {
 | 
					    const {
 | 
				
			||||||
      title,
 | 
					      title,
 | 
				
			||||||
      description,
 | 
					      description,
 | 
				
			||||||
 | 
					      instructions,
 | 
				
			||||||
      guideUrl,
 | 
					      guideUrl,
 | 
				
			||||||
      tests,
 | 
					      tests,
 | 
				
			||||||
      section,
 | 
					      section,
 | 
				
			||||||
@@ -95,7 +97,7 @@ export class SidePanel extends PureComponent {
 | 
				
			|||||||
        <Spacer />
 | 
					        <Spacer />
 | 
				
			||||||
        <div>
 | 
					        <div>
 | 
				
			||||||
          <ChallengeTitle>{title}</ChallengeTitle>
 | 
					          <ChallengeTitle>{title}</ChallengeTitle>
 | 
				
			||||||
          <ChallengeDescription description={description} section={section} />
 | 
					          <ChallengeDescription description={description} instructions={instructions} section={section} />
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
        <ToolPanel guideUrl={guideUrl} videoUrl={videoUrl} />
 | 
					        <ToolPanel guideUrl={guideUrl} videoUrl={videoUrl} />
 | 
				
			||||||
        <TestSuite tests={tests} />
 | 
					        <TestSuite tests={tests} />
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,36 +1,23 @@
 | 
				
			|||||||
import React, { PureComponent } from 'react';
 | 
					import React from 'react';
 | 
				
			||||||
import PropTypes from 'prop-types';
 | 
					import PropTypes from 'prop-types';
 | 
				
			||||||
import ChallengeTitle from '../components/Challenge-Title';
 | 
					import ChallengeTitle from '../components/Challenge-Title';
 | 
				
			||||||
import Spacer from '../../../components/helpers/Spacer';
 | 
					import Spacer from '../../../components/helpers/Spacer';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const propTypes = {
 | 
					const propTypes = {
 | 
				
			||||||
  description: PropTypes.arrayOf(PropTypes.string),
 | 
					  description: PropTypes.string,
 | 
				
			||||||
  isCompleted: PropTypes.bool,
 | 
					  isCompleted: PropTypes.bool,
 | 
				
			||||||
  isSignedIn: PropTypes.bool,
 | 
					  isSignedIn: PropTypes.bool,
 | 
				
			||||||
  title: PropTypes.string
 | 
					  title: PropTypes.string
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default class SidePanel extends PureComponent {
 | 
					export default function SidePanel({ title, description, isCompleted }) {
 | 
				
			||||||
  renderDescription(title = '', description = []) {
 | 
					  return (
 | 
				
			||||||
    return description.map((line, index) => (
 | 
					    <div>
 | 
				
			||||||
      <li
 | 
					      <Spacer />
 | 
				
			||||||
        className='step-text wrappable'
 | 
					      <ChallengeTitle isCompleted={isCompleted}>{title}</ChallengeTitle>
 | 
				
			||||||
        dangerouslySetInnerHTML={{ __html: line }}
 | 
					      <div dangerouslySetInnerHTML={{ __html: description }} />
 | 
				
			||||||
        key={title.slice(6) + index}
 | 
					    </div>
 | 
				
			||||||
      />
 | 
					  );
 | 
				
			||||||
    ));
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  render() {
 | 
					 | 
				
			||||||
    const { title, description, isCompleted } = this.props;
 | 
					 | 
				
			||||||
    return (
 | 
					 | 
				
			||||||
      <div>
 | 
					 | 
				
			||||||
        <Spacer />
 | 
					 | 
				
			||||||
        <ChallengeTitle isCompleted={isCompleted}>{title}</ChallengeTitle>
 | 
					 | 
				
			||||||
        <ul>{this.renderDescription(title, description)}</ul>
 | 
					 | 
				
			||||||
      </div>
 | 
					 | 
				
			||||||
    );
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
SidePanel.displayName = 'ProjectSidePanel';
 | 
					SidePanel.displayName = 'ProjectSidePanel';
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -39,7 +39,6 @@ class GuideArticle extends Component {
 | 
				
			|||||||
      },
 | 
					      },
 | 
				
			||||||
      pageContext: { meta }
 | 
					      pageContext: { meta }
 | 
				
			||||||
    } = this.props;
 | 
					    } = this.props;
 | 
				
			||||||
    console.log(title);
 | 
					 | 
				
			||||||
    return (
 | 
					    return (
 | 
				
			||||||
      <Layout>
 | 
					      <Layout>
 | 
				
			||||||
        <Helmet>
 | 
					        <Helmet>
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user