Skip to content

Commit 73e980b

Browse files
Merge pull request #31 from topcoder-platform/PROD-2560_check_submit_code
PROD-2560 - fix issue where hints flash when you resubmit
2 parents f0659eb + 00093d0 commit 73e980b

File tree

8 files changed

+85
-52
lines changed

8 files changed

+85
-52
lines changed

client/src/templates/Challenges/classic/editor.tsx

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,8 @@ import {
5555
stopResetting,
5656
isProjectPreviewModalOpenSelector,
5757
openModal,
58-
isChallengeCompletedSelector
58+
isChallengeCompletedSelector,
59+
testsRunningSelector
5960
} from '../redux';
6061
import GreenPass from '../../../assets/icons/green-pass';
6162
import Code from '../../../assets/icons/code';
@@ -107,6 +108,7 @@ interface EditorProps {
107108
}) => void;
108109
usesMultifileEditor: boolean;
109110
isChallengeCompleted: boolean;
111+
testsRunning: boolean;
110112
}
111113

112114
// TODO: this is grab bag of unrelated properties. There's no need for them to
@@ -136,6 +138,7 @@ const mapStateToProps = createSelector(
136138
userSelector,
137139
challengeTestsSelector,
138140
isChallengeCompletedSelector,
141+
testsRunningSelector,
139142
(
140143
canFocus: boolean,
141144
{ challengeType }: { challengeType: number },
@@ -146,7 +149,8 @@ const mapStateToProps = createSelector(
146149
isSignedIn: boolean,
147150
{ theme = Themes.Default }: { theme: Themes },
148151
tests: [{ text: string; testString: string }],
149-
isChallengeCompleted: boolean
152+
isChallengeCompleted: boolean,
153+
testsRunning: boolean
150154
) => ({
151155
canFocus: open ? false : canFocus,
152156
challengeType,
@@ -156,7 +160,8 @@ const mapStateToProps = createSelector(
156160
output,
157161
theme,
158162
tests,
159-
isChallengeCompleted
163+
isChallengeCompleted,
164+
testsRunning
160165
})
161166
);
162167

@@ -584,6 +589,7 @@ const Editor = (props: EditorProps): JSX.Element => {
584589
challengeHasErrors={challengeHasErrors()}
585590
tryToSubmitChallenge={tryToSubmitChallenge}
586591
isEditorInFocus={isEditorInFocus}
592+
isRunningTests={props.testsRunning}
587593
/>,
588594
outputNode,
589595
callback
@@ -1089,7 +1095,7 @@ const Editor = (props: EditorProps): JSX.Element => {
10891095
dataRef.current.outputNode = lowerJawElement;
10901096
updateOutputZone();
10911097
// eslint-disable-next-line react-hooks/exhaustive-deps
1092-
}, [props.tests]);
1098+
}, [props.tests, props.testsRunning]);
10931099

10941100
useEffect(() => {
10951101
const editor = dataRef.current.editor;

client/src/templates/Challenges/classic/lower-jaw.tsx

Lines changed: 51 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,10 @@
1-
import React, { useState, useEffect } from 'react';
1+
import React, {
2+
useState,
3+
useEffect,
4+
useMemo,
5+
useCallback,
6+
useRef
7+
} from 'react';
28
import { useTranslation } from 'react-i18next';
39

410
import TestFail from '../../../assets/icons/test-fail';
@@ -16,18 +22,18 @@ interface LowerJawProps {
1622
challengeHasErrors?: boolean;
1723
testsLength?: number;
1824
attemptsNumber?: number;
25+
isRunningTests?: boolean;
1926
}
2027

2128
const LowerJaw = ({
22-
openHelpModal,
2329
challengeIsCompleted,
2430
challengeHasErrors,
2531
hint,
2632
tryToExecuteChallenge,
2733
tryToSubmitChallenge,
2834
attemptsNumber,
29-
testsLength,
30-
isEditorInFocus
35+
isEditorInFocus,
36+
isRunningTests
3137
}: LowerJawProps): JSX.Element => {
3238
const [previousHint, setpreviousHint] = useState('');
3339
const [runningTests, setRunningTests] = useState(false);
@@ -37,6 +43,14 @@ const LowerJaw = ({
3743
const { t } = useTranslation();
3844
const submitButtonRef = React.createRef<HTMLButtonElement>();
3945
const testFeedbackRef = React.createRef<HTMLDivElement>();
46+
const challengeHasBeenCompletedRef = useRef(false);
47+
48+
// if a challenge was ever completed keep the state as completed
49+
if (challengeIsCompleted) {
50+
challengeHasBeenCompletedRef.current = true;
51+
}
52+
// keep the value of the reference.current as a separate value for convenience
53+
const challengeHasBeenCompleted = challengeHasBeenCompletedRef.current;
4054

4155
useEffect(() => {
4256
if (attemptsNumber && attemptsNumber > 0) {
@@ -67,15 +81,15 @@ const LowerJaw = ({
6781
}, [challengeHasErrors, hint]);
6882

6983
useEffect(() => {
70-
if (challengeIsCompleted && submitButtonRef?.current) {
84+
if (challengeHasBeenCompleted && submitButtonRef?.current) {
7185
submitButtonRef.current.focus();
7286
setTimeout(() => {
7387
setTestBtnariaHidden(true);
7488
}, 500);
7589
}
7690

7791
// eslint-disable-next-line react-hooks/exhaustive-deps
78-
}, [challengeIsCompleted]);
92+
}, [challengeHasBeenCompleted]);
7993

8094
// eslint-disable-next-line react-hooks/exhaustive-deps
8195
useEffect(() => {
@@ -84,12 +98,23 @@ const LowerJaw = ({
8498
}
8599
});
86100

87-
const renderTestFeedbackContainer = () => {
101+
const sentencePicker = useCallback(() => {
102+
const sentenceArray = [
103+
'learn.sorry-try-again',
104+
'learn.sorry-keep-trying',
105+
'learn.sorry-getting-there',
106+
'learn.sorry-hang-in-there',
107+
'learn.sorry-dont-giveup'
108+
];
109+
return attemptsNumber
110+
? sentenceArray[attemptsNumber % sentenceArray.length]
111+
: sentenceArray[0];
112+
}, [attemptsNumber]);
113+
114+
const feedbackContent = useMemo(() => {
88115
if (attemptsNumber === 0) {
89116
return '';
90-
} else if (runningTests) {
91-
return '';
92-
} else if (challengeIsCompleted) {
117+
} else if (challengeHasBeenCompleted) {
93118
const submitKeyboardInstructions = isEditorInFocus ? (
94119
<span className='sr-only'>{t('aria.submit')}</span>
95120
) : (
@@ -142,69 +167,49 @@ const LowerJaw = ({
142167
</>
143168
);
144169
}
145-
};
146-
147-
const sentencePicker = () => {
148-
const sentenceArray = [
149-
'learn.sorry-try-again',
150-
'learn.sorry-keep-trying',
151-
'learn.sorry-getting-there',
152-
'learn.sorry-hang-in-there',
153-
'learn.sorry-dont-giveup'
154-
];
155-
return attemptsNumber
156-
? sentenceArray[attemptsNumber % sentenceArray.length]
157-
: sentenceArray[0];
158-
};
159-
160-
const renderHelpButton = () => {
161-
const isAtteptsLargerThanTest =
162-
attemptsNumber && testsLength && attemptsNumber >= testsLength;
163-
164-
if (isAtteptsLargerThanTest && !challengeIsCompleted)
165-
return (
166-
<button
167-
className='btn-block btn fade-in'
168-
id='help-button'
169-
onClick={openHelpModal}
170-
>
171-
{t('buttons.ask-for-help')}
172-
</button>
173-
);
174-
};
170+
}, [
171+
attemptsNumber,
172+
challengeHasBeenCompleted,
173+
hint,
174+
isEditorInFocus,
175+
isFeedbackHidden,
176+
previousHint,
177+
sentencePicker,
178+
t
179+
]);
175180

176181
const renderButtons = () => {
177182
return (
178183
<>
179184
<button
180185
id='test-button'
181-
className={`btn btn-primary ${challengeIsCompleted ? 'sr-only' : ''}`}
186+
className={`btn btn-primary ${
187+
challengeHasBeenCompleted ? 'sr-only' : ''
188+
}`}
182189
aria-hidden={testBtnariaHidden}
183190
onClick={tryToExecuteChallenge}
184191
>
185192
{t('buttons.check-code')}
193+
{isRunningTests && '...'}
186194
</button>
187195
<div id='action-buttons-container'>
188196
<button
189197
id='submit-button'
190-
aria-hidden={!challengeIsCompleted}
198+
aria-hidden={!challengeHasBeenCompleted}
191199
className='btn btn-primary'
192200
onClick={tryToSubmitChallenge}
193201
ref={submitButtonRef}
194202
>
195203
{t('buttons.submit-and-go')}
196204
</button>
197-
{renderHelpButton()}
198205
</div>
199206
</>
200207
);
201208
};
202209

203-
const feedbackContent = renderTestFeedbackContainer();
204-
205210
return (
206211
<div className='action-row-container'>
207-
{feedbackContent && (
212+
{!isRunningTests && feedbackContent && (
208213
<div
209214
style={runningTests ? { height: `${testFeedbackheight}px` } : {}}
210215
className={`test-feedback`}

client/src/templates/Challenges/classic/show.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,8 @@ import {
4646
previewMounted,
4747
updateChallengeMeta,
4848
openModal,
49-
setEditorFocusability
49+
setEditorFocusability,
50+
testsRunningSelector
5051
} from '../redux';
5152
import { savedChallengesSelector } from '../../../redux';
5253
import { getGuideUrl } from '../utils';
@@ -61,6 +62,7 @@ import '../components/test-frame.css';
6162
const mapStateToProps = createStructuredSelector({
6263
challengeFiles: challengeFilesSelector,
6364
tests: challengeTestsSelector,
65+
testsRunning: testsRunningSelector,
6466
output: consoleOutputSelector,
6567
isChallengeCompleted: isChallengeCompletedSelector,
6668
savedChallenges: savedChallengesSelector
@@ -104,6 +106,7 @@ interface ShowClassicProps {
104106
};
105107
t: TFunction;
106108
tests: Test[];
109+
testsRunning: boolean;
107110
updateChallengeMeta: (arg0: ChallengeMeta) => void;
108111
openModal: (modal: string) => void;
109112
setEditorFocusability: (canFocus: boolean) => void;
@@ -337,6 +340,7 @@ class ShowClassic extends Component<ShowClassicProps, ShowClassicState> {
337340
instructionsPanelRef={this.instructionsPanelRef}
338341
showToolPanel={showToolPanel}
339342
videoUrl={this.getVideoUrl()}
343+
testsRunning={this.props.testsRunning}
340344
/>
341345
);
342346
}

client/src/templates/Challenges/components/side-panel.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ interface SidePanelProps {
2727
instructionsPanelRef: React.RefObject<HTMLDivElement>;
2828
showToolPanel: boolean;
2929
tests: Test[];
30+
testsRunning: boolean;
3031
videoUrl: string;
3132
}
3233

@@ -38,6 +39,7 @@ export function SidePanel({
3839
instructionsPanelRef,
3940
showToolPanel = false,
4041
tests,
42+
testsRunning,
4143
videoUrl
4244
}: SidePanelProps): JSX.Element {
4345
const isChallengeComplete = tests.every(test => test.pass && !test.err);
@@ -85,6 +87,7 @@ export function SidePanel({
8587
guideUrl={guideUrl}
8688
videoUrl={videoUrl}
8789
challengeIsCompleted={isChallengeComplete}
90+
isRunningTests={testsRunning}
8891
/>
8992
)}
9093
<TestSuite tests={tests} />
@@ -93,6 +96,7 @@ export function SidePanel({
9396
guideUrl={guideUrl}
9497
videoUrl={videoUrl}
9598
challengeIsCompleted={isChallengeComplete}
99+
isRunningTests={testsRunning}
96100
/>
97101
)}
98102
</div>

client/src/templates/Challenges/components/tool-panel.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ interface ToolPanelProps {
5252
saveChallenge: () => void;
5353
isMobile?: boolean;
5454
isSignedIn: boolean;
55+
isRunningTests?: boolean;
5556
openHelpModal: () => void;
5657
openVideoModal: () => void;
5758
openResetModal: () => void;
@@ -66,6 +67,7 @@ function ToolPanel({
6667
saveChallenge,
6768
isMobile,
6869
isSignedIn,
70+
isRunningTests,
6971
openHelpModal,
7072
openVideoModal,
7173
openResetModal,
@@ -95,6 +97,7 @@ function ToolPanel({
9597
onClick={handleRunTests}
9698
>
9799
{isMobile ? t('buttons.run') : t('buttons.run-test')}
100+
{isRunningTests && ' ...'}
98101
</Button>
99102
)}
100103
{challengeIsCompleted && (

client/src/templates/Challenges/redux/action-types.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ export const actionTypes = createTypes(
1818
'updateTests',
1919
'updateLogs',
2020
'cancelTests',
21+
'updateTestsRunning',
2122

2223
'logsToConsole',
2324

client/src/templates/Challenges/redux/execute-challenge-saga.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,8 @@ import {
4747
updateTests,
4848
openModal,
4949
isBuildEnabledSelector,
50-
disableBuildOnError
50+
disableBuildOnError,
51+
updateTestsRunning
5152
} from './';
5253

5354
// How long before bailing out of a preview.
@@ -101,6 +102,7 @@ export function* executeChallengeSaga({ payload }) {
101102
try {
102103
yield put(initLogs());
103104
yield put(initConsole(i18next.t('learn.running-tests')));
105+
yield put(updateTestsRunning(true));
104106
// reset tests to initial state
105107
const tests = (yield select(challengeTestsSelector)).map(
106108
({ text, testString }) => ({ text, testString })
@@ -139,6 +141,7 @@ export function* executeChallengeSaga({ payload }) {
139141
}
140142
yield put(updateConsole(i18next.t('learn.tests-completed')));
141143
yield put(logsToConsole(i18next.t('learn.console-output')));
144+
yield put(updateTestsRunning(false));
142145
} catch (e) {
143146
yield put(updateConsole(e));
144147
} finally {

0 commit comments

Comments
 (0)