// Package Utilities import { Alert, Grid, Col, Row, Button } from '@freecodecamp/react-bootstrap'; import { graphql } from 'gatsby'; import React, { Component } from 'react'; import Helmet from 'react-helmet'; import { TFunction, Trans, withTranslation } from 'react-i18next'; import { connect } from 'react-redux'; import { bindActionCreators } from 'redux'; import type { Dispatch } from 'redux'; import { createSelector } from 'reselect'; // Local Utilities import Spacer from '../../../components/helpers/spacer'; import LearnLayout from '../../../components/layouts/learn'; import ChallengeTitle from '../components/challenge-title'; import PrismFormatted from '../components/prism-formatted'; import { challengeTypes } from '../../../../utils/challenge-types'; import CompletionModal from '../components/completion-modal'; import GreenPass from '../../../assets/icons/green-pass'; import HelpModal from '../components/help-modal'; import Hotkeys from '../components/Hotkeys'; import { completedChallengesSelector, isSignedInSelector, hideCodeAlly, partiallyCompletedChallengesSelector, showCodeAllySelector, tryToShowCodeAlly, userTokenSelector } from '../../../redux'; import { challengeMounted, isChallengeCompletedSelector, updateChallengeMeta, openModal, updateSolutionFormValues } from '../redux'; import { createFlashMessage } from '../../../components/Flash/redux'; import { ChallengeNode, ChallengeMeta, CompletedChallenge } from '../../../redux/prop-types'; import ProjectToolPanel from '../projects/tool-panel'; import SolutionForm from '../projects/solution-form'; import { FlashMessages } from '../../../components/Flash/redux/flash-messages'; import './codeally.css'; // Redux const mapStateToProps = createSelector( completedChallengesSelector, isChallengeCompletedSelector, isSignedInSelector, partiallyCompletedChallengesSelector, showCodeAllySelector, userTokenSelector, ( completedChallenges: CompletedChallenge[], isChallengeCompleted: boolean, isSignedIn: boolean, partiallyCompletedChallenges: CompletedChallenge[], showCodeAlly: boolean, userToken: string | null ) => ({ completedChallenges, isChallengeCompleted, isSignedIn, partiallyCompletedChallenges, showCodeAlly, userToken }) ); const mapDispatchToProps = (dispatch: Dispatch) => bindActionCreators( { challengeMounted, createFlashMessage, hideCodeAlly, openCompletionModal: () => openModal('completion'), tryToShowCodeAlly, updateChallengeMeta, updateSolutionFormValues }, dispatch ); // Types interface ShowCodeAllyProps { challengeMounted: (arg0: string) => void; completedChallenges: CompletedChallenge[]; createFlashMessage: typeof createFlashMessage; data: { challengeNode: ChallengeNode }; hideCodeAlly: () => void; isChallengeCompleted: boolean; isSignedIn: boolean; openCompletionModal: () => void; pageContext: { challengeMeta: ChallengeMeta; }; partiallyCompletedChallenges: CompletedChallenge[]; showCodeAlly: boolean; t: TFunction; tryToShowCodeAlly: () => void; updateChallengeMeta: (arg0: ChallengeMeta) => void; updateSolutionFormValues: () => void; userToken: string | null; } // Component class ShowCodeAlly extends Component { static displayName: string; private _container: HTMLElement | null = null; componentDidMount(): void { const { challengeMounted, data: { challengeNode: { challenge: { challengeType, helpCategory, title } } }, pageContext: { challengeMeta }, updateChallengeMeta } = this.props; updateChallengeMeta({ ...challengeMeta, title, challengeType, helpCategory }); challengeMounted(challengeMeta.id); this._container?.focus(); } componentWillUnmount() { this.props.hideCodeAlly(); } handleSubmit = ({ showCompletionModal }: { showCompletionModal: boolean; }) => { const { completedChallenges, createFlashMessage, data: { challengeNode: { challenge: { id: challengeId } } }, openCompletionModal, partiallyCompletedChallenges } = this.props; const isPartiallyCompleted = partiallyCompletedChallenges.some( challenge => challenge.id === challengeId ); const isCompleted = completedChallenges.some( challenge => challenge.id === challengeId ); if (!isPartiallyCompleted && !isCompleted) { createFlashMessage({ type: 'danger', message: FlashMessages.CompleteProjectFirst }); } else if (showCompletionModal) { openCompletionModal(); } }; render() { const { completedChallenges, data: { challengeNode: { challenge: { block, certification, challengeType, description, fields: { blockName }, id: challengeId, instructions, notes, superBlock, title, translationPending, url } } }, isChallengeCompleted, isSignedIn, pageContext: { challengeMeta: { nextChallengePath, prevChallengePath } }, partiallyCompletedChallenges, showCodeAlly, t, tryToShowCodeAlly, updateSolutionFormValues, userToken = null } = this.props; const envVariables = userToken ? `&envVariables=CODEROAD_WEBHOOK_TOKEN=${userToken}` : ''; const isPartiallyCompleted = partiallyCompletedChallenges.some( challenge => challenge.id === challengeId ); const isCompleted = completedChallenges.some( challenge => challenge.id === challengeId ); return showCodeAlly ? (