ronantakizawa/codereview-bench huggingface dataset:
Repository: freeCodeCamp/freeCodeCamp
File: client/src/templates/Challenges/quiz/show.tsx (TypeScript)

Code before:
  useEffect(() => {
    updateChallengeMeta({
      ...challengeMeta,
      title,
      challengeType,
      helpCategory
    });
    challengeMounted(challengeMeta.id);
  }, [
    title,
    challengeMeta,
    challengeType,
    helpCategory,
    challengeMounted,
    updateChallengeMeta
  ]);

  const handleAnswersCheck = () => {
    const unansweredQuestions = quizData.reduce(
      (accumulator, currentQuestion, currentIndex) => {
        if (currentQuestion.selectedAnswer == null) {
          accumulator.push(currentIndex + 1);
        }
        return accumulator;
      },
      [] as number[]
    );

    if (unansweredQuestions.length) {
      setErrorMessage(
        t('learn.quiz.unanswered-questions', {
          unansweredQuestions: unansweredQuestions.join(', ')
        })
      );
      return;
    }

    validateAnswers();
    setHasSubmitted(true);
  };

  const handleSubmitAndGo = () => {
    openCompletionModal();
  };

  // Handle error message display on submit.
  // We keep the logic in a useEffect hook in order to subscribe to the `correctAnswerCount` change
  // as `correctAnswerCount` is a React state and its value is updated asynchronously,
  useEffect(() => {
    if (!hasSubmitted) {
      return;

Review comment (suggestion):
```suggestion
      []
```
Another nit. No need for an assertion if you provide the type to reduce.

Code after:
      title,
      challengeType,
      helpCategory
    });
    challengeMounted(challengeMeta.id);
  }, [
    title,
    challengeMeta,
    challengeType,
    helpCategory,
    challengeMounted,
    updateChallengeMeta
  ]);

  const handleAnswersCheck = () => {
    validateAnswers();
    setHasSubmitted(true);
  };

  const handleSubmitAndGo = () => {
    openCompletionModal();
  };

  function getErrorMessage() {
    if (!hasSubmitted) return '';

    const unansweredList = quizData.reduce<number[]>(
      (acc, curr, id) => (curr.selectedAnswer == null ? [...acc, id + 1] : acc),
      []
    );

    if (unansweredList.length > 0) {
      return t('learn.quiz.unanswered-questions', {
        unansweredQuestions: unansweredList.join(', ')
      });
    }

    return t('learn.quiz.have-n-correct-questions', {
      correctAnswerCount,
      total: quiz.length
    });
  }

  const errorMessage = getErrorMessage();

  return (
    <Hotkeys
      executeChallenge={!isPassed ? handleAnswersCheck : handleSubmitAndGo}
      containerRef={container}
      nextChallengePath={nextChallengePath}
      prevChallengePath={prevChallengePath}
Repository: freeCodeCamp/freeCodeCamp
File: client/src/templates/Challenges/quiz/show.tsx (TypeScript)

Code before:
    challengeMeta,
    challengeType,
    helpCategory,
    challengeMounted,
    updateChallengeMeta
  ]);

  const handleAnswersCheck = () => {
    const unansweredQuestions = quizData.reduce<number[]>(
      (acc, curr, id) => (curr.selectedAnswer == null ? [...acc, id + 1] : acc),
      []
    );

    if (unansweredQuestions.length) {
      setErrorMessage(
        t('learn.quiz.unanswered-questions', {
          unansweredQuestions: unansweredQuestions.join(', ')
        })
      );
      return;
    }

    const correctCount = quizData.reduce(
      (acc, curr) => (curr.selectedAnswer === curr.correctAnswer ? ++acc : acc),
      0
    );

    validateAnswers();
    setHasSubmitted(true);

    setErrorMessage(
      t('learn.quiz.have-n-correct-questions', {
        correctAnswerCount: correctCount,
        total: quiz.length
      })
    );
  };

  const handleSubmitAndGo = () => {
    openCompletionModal();
  };

  return (
    <Hotkeys
      executeChallenge={!isPassed ? handleAnswersCheck : handleSubmitAndGo}
      containerRef={container}
      nextChallengePath={nextChallengePath}
      prevChallengePath={prevChallengePath}
    >
      <LearnLayout>
        <Helmet

Review comment (suggestion):
I ended up computing the correct answer count here, rather than using the `correctAnswerCount` value from `useQuiz`.

The issue with `correctAnswerCount` is, its value is only updated when `validateAnswers` is called. However, `correctAnswerCount` is actually a state, so the update doesn't happen immediately, and thus we can't use it to construct the error message (the correct count would be 0).

We would either need to call `setErrorMessage` in a `useEffect` in order to catch the state update, or we can just compute the correct count ourselves.

Code after:
    challengeMounted(challengeMeta.id);
  }, [
    title,
    challengeMeta,
    challengeType,
    helpCategory,
    challengeMounted,
    updateChallengeMeta
  ]);

  const handleAnswersCheck = () => {
    validateAnswers();
    setHasSubmitted(true);
  };

  const handleSubmitAndGo = () => {
    openCompletionModal();
  };

  function getErrorMessage() {
    if (!hasSubmitted) return '';

    const unansweredList = quizData.reduce<number[]>(
      (acc, curr, id) => (curr.selectedAnswer == null ? [...acc, id + 1] : acc),
      []
    );

    if (unansweredList.length > 0) {
      return t('learn.quiz.unanswered-questions', {
        unansweredQuestions: unansweredList.join(', ')
      });
    }

    return t('learn.quiz.have-n-correct-questions', {
      correctAnswerCount,
      total: quiz.length
    });
  }

  const errorMessage = getErrorMessage();

  return (
    <Hotkeys
      executeChallenge={!isPassed ? handleAnswersCheck : handleSubmitAndGo}
      containerRef={container}
      nextChallengePath={nextChallengePath}
      prevChallengePath={prevChallengePath}
    >
      <LearnLayout>
        <Helmet
          title={`${blockNameTitle} | ${t('learn.learn')} | freeCodeCamp.org`}
Repository: freeCodeCamp/freeCodeCamp
File: client/src/redux/settings/settings-sagas.js (JavaScript)

Code before:
    yield put(updateMySocialsComplete({ ...data, payload: update }));
    yield put(createFlashMessage({ ...data }));
  } catch (e) {
    yield put(updateMySocialsError);
  }
}

function* updateMySoundSaga({ payload: update }) {
  try {
    store.set('fcc-sound', !!update.sound);
    const data = {
      message: 'flash.updated-sound',
      type: 'success'
    };
    yield put(updateMySoundComplete({ ...data, payload: update }));
    yield put(createFlashMessage({ ...data }));
  } catch (e) {
    yield put(updateMySoundError);
  }
}

function* updateMyThemeSaga({ payload: update }) {
  try {
    const { data } = yield call(putUpdateMyTheme, update);
    const theme = { ...data }.variables.theme;
    localStorage.setItem('theme', theme);
    yield put(updateMyThemeComplete({ ...data, payload: update }));
    yield put(createFlashMessage({ ...data }));
  } catch (e) {
    yield put(updateMyThemeError);
  }
}

function* updateMyKeyboardShortcutsSaga({ payload: update }) {
  try {
    const { data } = yield call(putUpdateMyKeyboardShortcuts, update);
    yield put(updateMyKeyboardShortcutsComplete({ ...data, payload: update }));
    yield put(createFlashMessage({ ...data }));
  } catch (e) {
    yield put(updateMyKeyboardShortcutsError);
  }
}

function* updateMyHonestySaga({ payload: update }) {
  try {
    const { data } = yield call(putUpdateMyHonesty, update);
    yield put(updateMyHonestyComplete({ ...data, payload: update }));
    yield put(createFlashMessage({ ...data }));
  } catch (e) {
    yield put(updateMyHonestyError);
  }

Review comment (suggestion):
```suggestion
    localStorage.setItem('theme', update.theme);
```
The message coming back from the api does not include the theme.

Code after:
    yield put(createFlashMessage({ ...data }));
  } catch (e) {
    yield put(updateMySocialsError);
  }
}

function* updateMySoundSaga({ payload: update }) {
  try {
    store.set('fcc-sound', !!update.sound);
    const data = {
      message: 'flash.updated-sound',
      type: 'success'
    };
    yield put(updateMySoundComplete({ ...data, payload: update }));
    yield put(createFlashMessage({ ...data }));
  } catch (e) {
    yield put(updateMySoundError);
  }
}

function* resetMyEditorLayoutSaga() {
  const layout = store.get('challenge-layout');

  if (layout) {
    try {
      const data = {
        message: 'flash.reset-editor-layout',
        type: 'success'
      };

      store.remove('challenge-layout');

      yield put(createFlashMessage({ ...data }));
      yield put(resetMyEditorLayoutComplete({ ...data }));
    } catch (e) {
      yield put(resetMyEditorLayoutError);
    }
  }
}

function* updateMyKeyboardShortcutsSaga({ payload: update }) {
  try {
    const { data } = yield call(putUpdateMyKeyboardShortcuts, update);
    yield put(updateMyKeyboardShortcutsComplete({ ...data, payload: update }));
    yield put(createFlashMessage({ ...data }));
  } catch (e) {
    yield put(updateMyKeyboardShortcutsError);
  }
}

function* updateMyHonestySaga({ payload: update }) {
Repository: freeCodeCamp/freeCodeCamp
File: client/src/client-only-routes/show-certification.tsx (TypeScript)

Code before:
    return <RedirectHome />;
  }

  const {
    date,
    name: userFullName = null,
    username,
    certTitle,
    certSlug,
    completionTime
  } = cert;

  const { user } = props;

  const displayName = userFullName ?? username;

  const certDate = new Date(date);
  const certYear = certDate.getFullYear();
  const certMonth = certDate.getMonth();
  const certURL = `https://freecodecamp.org${pathname}`;

  const currentTheme =
    localStorage.getItem('theme') == Themes.Night
      ? Themes.Night
      : Themes.Default;

  const donationCloseBtn = (
    <div>
      <Button
        block={true}
        size='small'
        variant='primary'
        onClick={hideDonationSection}
      >
        {t('buttons.close')}
      </Button>
    </div>
  );

  const donationSection = (
    <div
      className='donation-section'
      data-playwright-test-label='donation-section'
    >
      <Spacer size='large' />
      {!isDonationSubmitted && (
        <Row>
          <Col lg={8} lgOffset={2} sm={10} smOffset={1} xs={12}>
            <p data-playwright-test-label='donation-text'>
              {t('donate.only-you')}
            </p>

Review comment (suggestion):
```suggestion
```

The theme on the certification page is always default.

Code after:
    return <RedirectHome />;
  }

  const {
    date,
    name: userFullName = null,
    username,
    certTitle,
    certSlug,
    completionTime
  } = cert;

  const { user } = props;

  const displayName = userFullName ?? username;

  const certDate = new Date(date);
  const certYear = certDate.getFullYear();
  const certMonth = certDate.getMonth();
  const certURL = `https://freecodecamp.org${pathname}`;

  const donationCloseBtn = (
    <div>
      <Button
        block={true}
        size='small'
        variant='primary'
        onClick={hideDonationSection}
      >
        {t('buttons.close')}
      </Button>
    </div>
  );

  const donationSection = (
    <div
      className='donation-section'
      data-playwright-test-label='donation-section'
    >
      <Spacer size='l' />
      {!isDonationSubmitted && (
        <Row>
          <Col lg={8} lgOffset={2} sm={10} smOffset={1} xs={12}>
            <p data-playwright-test-label='donation-text'>
              {t('donate.only-you')}
            </p>
          </Col>
        </Row>
      )}
      <Row>
        <Col
Repository: freeCodeCamp/freeCodeCamp
File: client/src/client-only-routes/show-certification.tsx (TypeScript)

Code before:
  const donationSection = (
    <div
      className='donation-section'
      data-playwright-test-label='donation-section'
    >
      <Spacer size='large' />
      {!isDonationSubmitted && (
        <Row>
          <Col lg={8} lgOffset={2} sm={10} smOffset={1} xs={12}>
            <p data-playwright-test-label='donation-text'>
              {t('donate.only-you')}
            </p>
          </Col>
        </Row>
      )}
      <Row>
        <Col
          lg={8}
          lgOffset={2}
          sm={10}
          smOffset={1}
          xs={12}
          data-playwright-test-label='donation-form'
        >
          <MultiTierDonationForm
            defaultTheme={currentTheme}
            handleProcessing={handleProcessing}
            isMinimalForm={true}
            paymentContext={PaymentContext.Certificate}
          />
        </Col>
      </Row>
      <Spacer size='medium' />
      <Row>
        <Col sm={4} smOffset={4} xs={6} xsOffset={3}>
          {isDonationSubmitted && donationCloseBtn}
        </Col>
      </Row>
      <Spacer size='large' />
    </div>
  );

  const urlFriendlyCertTitle = encodeURIComponent(certTitle);
  const linkedInCredentialId = `${username}-${linkedInCredentialIds[certSlug]}`;

  const shareCertBtns = (
    <Row className='text-center'>
      <Col xs={12}>
        <Button
          block={true}
          size='large'

Review comment (suggestion):
```suggestion
            defaultTheme={Themes.Default}
```

Code after:
      <Spacer size='l' />
      {!isDonationSubmitted && (
        <Row>
          <Col lg={8} lgOffset={2} sm={10} smOffset={1} xs={12}>
            <p data-playwright-test-label='donation-text'>
              {t('donate.only-you')}
            </p>
          </Col>
        </Row>
      )}
      <Row>
        <Col
          lg={8}
          lgOffset={2}
          sm={10}
          smOffset={1}
          xs={12}
          data-playwright-test-label='donation-form'
        >
          <MultiTierDonationForm
            defaultTheme={LocalStorageThemes.Light}
            handleProcessing={handleProcessing}
            isMinimalForm={true}
            paymentContext={PaymentContext.Certificate}
          />
        </Col>
      </Row>
      <Spacer size='m' />
      <Row>
        <Col sm={4} smOffset={4} xs={6} xsOffset={3}>
          {isDonationSubmitted && donationCloseBtn}
        </Col>
      </Row>
      <Spacer size='l' />
    </div>
  );

  const urlFriendlyCertTitle = encodeURIComponent(certTitle);
  const linkedInCredentialId = `${username}-${linkedInCredentialIds[certSlug]}`;

  const shareCertBtns = (
    <Row className='text-center'>
      <Col xs={12}>
        <Button
          block={true}
          size='large'
          variant='primary'
          href={`https://www.linkedin.com/profile/add?startTask=CERTIFICATION_NAME&name=${urlFriendlyCertTitle}&organizationId=4831032&issueYear=${certYear}&issueMonth=${
            certMonth + 1
          }&certUrl=${certURL}&certId=${linkedInCredentialId}`}
          target='_blank'
Repository: freeCodeCamp/freeCodeCamp
File: client/src/redux/theme-saga.js (JavaScript)

Code before:
function* toggleThemeSaga() {
  const data = { type: 'success', message: 'flash.updated-themes' };
  const currentTheme = localStorage.getItem('theme');
  const invertedTheme = currentTheme === 'dark' ? 'light' : 'dark';
  localStorage.setItem('theme', invertedTheme);
  yield put(setTheme(invertedTheme));
  yield put(createFlashMessage({ ...data }));
}

function* initalizeThemeSaga() {
  // Wait for the fetch userComplete action
  yield take(actionTypes.fetchUserComplete);

  let selectTheme;
  const isUserThemeDark = (yield select(userThemeSelector)) === 'night';
  const isLocalStorageThemeDark = localStorage.getItem('theme') === 'dark';
  const isSysThemeDark = window.matchMedia(
    '(prefers-color-scheme: dark)'
  ).matches;

  // the order matters here
  if (isLocalStorageThemeDark || isUserThemeDark || isSysThemeDark) {
    selectTheme = 'dark';
  } else {
    selectTheme = 'light';
  }
  localStorage.setItem('theme', selectTheme);
  yield put(setTheme(selectTheme));
}

export function createThemeSaga(types) {
  return [
    takeEvery(types.toggleTheme, toggleThemeSaga),
    takeEvery(types.initializeTheme, initalizeThemeSaga)
  ];
}


Review comment (suggestion):
```suggestion
  const selectTheme =
    isLocalStorageThemeDark || isUserThemeDark || isSysThemeDark
      ? 'dark'
      : 'light';
```

Code after:
function* toggleThemeSaga() {
  const data = { type: 'success', message: 'flash.updated-themes' };
  const currentTheme = localStorage.getItem('theme');
  const invertedTheme = currentTheme === 'dark' ? 'light' : 'dark';
  localStorage.setItem('theme', invertedTheme);
  yield put(setTheme(invertedTheme));
  yield put(createFlashMessage({ ...data }));
}

function* initializeThemeSaga() {
  // Wait for the fetch userComplete action
  yield take(actionTypes.fetchUserComplete);

  const userTheme = yield select(userThemeSelector);
  const localStorageTheme = localStorage.getItem('theme');
  const isSysThemeDark = window.matchMedia(
    '(prefers-color-scheme: dark)'
  ).matches;

  let selectTheme = 'light';

  if (localStorageTheme !== null) {
    selectTheme = localStorageTheme === 'dark' ? 'dark' : 'light';
  } else if (userTheme) {
    selectTheme = userTheme === 'night' ? 'dark' : 'light';
  } else if (isSysThemeDark) {
    selectTheme = 'dark';
  }

  localStorage.setItem('theme', selectTheme);
  yield put(setTheme(selectTheme));
}

export function createThemeSaga(types) {
  return [
    takeEvery(types.toggleTheme, toggleThemeSaga),
    takeEvery(types.initializeTheme, initializeThemeSaga)
  ];
}
Repository: freeCodeCamp/freeCodeCamp
File: client/src/redux/theme-saga.js (JavaScript)

Code before:
import { userThemeSelector } from './selectors';

function* toggleThemeSaga() {
  const data = { type: 'success', message: 'flash.updated-themes' };
  const currentTheme = localStorage.getItem('theme');
  const invertedTheme = currentTheme === 'dark' ? 'light' : 'dark';
  localStorage.setItem('theme', invertedTheme);
  yield put(setTheme(invertedTheme));
  yield put(createFlashMessage({ ...data }));
}

function* initializeThemeSaga() {
  // Wait for the fetch userComplete action
  yield take(actionTypes.fetchUserComplete);

  const userTheme = yield select(userThemeSelector);
  const localStorageTheme = localStorage.getItem('theme');
  const isSysThemeDark = window.matchMedia(
    '(prefers-color-scheme: dark)'
  ).matches;

  let selectTheme = 'light';

  if (localStorageTheme !== null) {
    selectTheme = localStorageTheme === 'dark' ? 'dark' : 'light';
  } else if (userTheme !== null && userTheme !== undefined) {
    selectTheme = userTheme === 'night' ? 'dark' : 'light';
  } else if (isSysThemeDark === true) {
    selectTheme = 'dark';
  }

  localStorage.setItem('theme', selectTheme);
  yield put(setTheme(selectTheme));
}

export function createThemeSaga(types) {
  return [
    takeEvery(types.toggleTheme, toggleThemeSaga),
    takeEvery(types.initializeTheme, initializeThemeSaga)
  ];
}


Review comment (suggestion):
```suggestion
  } else if (userTheme) {
```
If `userTheme` exists, we can use it to decide `selectTheme`

Code after:
import { userThemeSelector } from './selectors';

function* toggleThemeSaga() {
  const data = { type: 'success', message: 'flash.updated-themes' };
  const currentTheme = localStorage.getItem('theme');
  const invertedTheme = currentTheme === 'dark' ? 'light' : 'dark';
  localStorage.setItem('theme', invertedTheme);
  yield put(setTheme(invertedTheme));
  yield put(createFlashMessage({ ...data }));
}

function* initializeThemeSaga() {
  // Wait for the fetch userComplete action
  yield take(actionTypes.fetchUserComplete);

  const userTheme = yield select(userThemeSelector);
  const localStorageTheme = localStorage.getItem('theme');
  const isSysThemeDark = window.matchMedia(
    '(prefers-color-scheme: dark)'
  ).matches;

  let selectTheme = 'light';

  if (localStorageTheme !== null) {
    selectTheme = localStorageTheme === 'dark' ? 'dark' : 'light';
  } else if (userTheme) {
    selectTheme = userTheme === 'night' ? 'dark' : 'light';
  } else if (isSysThemeDark) {
    selectTheme = 'dark';
  }

  localStorage.setItem('theme', selectTheme);
  yield put(setTheme(selectTheme));
}

export function createThemeSaga(types) {
  return [
    takeEvery(types.toggleTheme, toggleThemeSaga),
    takeEvery(types.initializeTheme, initializeThemeSaga)
  ];
}
Repository: freeCodeCamp/freeCodeCamp
File: client/src/redux/theme-saga.js (JavaScript)

Code before:
function* toggleThemeSaga() {
  const data = { type: 'success', message: 'flash.updated-themes' };
  const currentTheme = localStorage.getItem('theme');
  const invertedTheme = currentTheme === 'dark' ? 'light' : 'dark';
  localStorage.setItem('theme', invertedTheme);
  yield put(setTheme(invertedTheme));
  yield put(createFlashMessage({ ...data }));
}

function* initializeThemeSaga() {
  // Wait for the fetch userComplete action
  yield take(actionTypes.fetchUserComplete);

  const userTheme = yield select(userThemeSelector);
  const localStorageTheme = localStorage.getItem('theme');
  const isSysThemeDark = window.matchMedia(
    '(prefers-color-scheme: dark)'
  ).matches;

  let selectTheme = 'light';

  if (localStorageTheme !== null) {
    selectTheme = localStorageTheme === 'dark' ? 'dark' : 'light';
  } else if (userTheme !== null && userTheme !== undefined) {
    selectTheme = userTheme === 'night' ? 'dark' : 'light';
  } else if (isSysThemeDark === true) {
    selectTheme = 'dark';
  }

  localStorage.setItem('theme', selectTheme);
  yield put(setTheme(selectTheme));
}

export function createThemeSaga(types) {
  return [
    takeEvery(types.toggleTheme, toggleThemeSaga),
    takeEvery(types.initializeTheme, initializeThemeSaga)
  ];
}


Review comment (suggestion):
```suggestion
  } else if (isSysThemeDark) {
```
`thing === true` is equivalent to `thing` when it's a boolean, so we can skip the comparison.

Code after:
function* toggleThemeSaga() {
  const data = { type: 'success', message: 'flash.updated-themes' };
  const currentTheme = localStorage.getItem('theme');
  const invertedTheme = currentTheme === 'dark' ? 'light' : 'dark';
  localStorage.setItem('theme', invertedTheme);
  yield put(setTheme(invertedTheme));
  yield put(createFlashMessage({ ...data }));
}

function* initializeThemeSaga() {
  // Wait for the fetch userComplete action
  yield take(actionTypes.fetchUserComplete);

  const userTheme = yield select(userThemeSelector);
  const localStorageTheme = localStorage.getItem('theme');
  const isSysThemeDark = window.matchMedia(
    '(prefers-color-scheme: dark)'
  ).matches;

  let selectTheme = 'light';

  if (localStorageTheme !== null) {
    selectTheme = localStorageTheme === 'dark' ? 'dark' : 'light';
  } else if (userTheme) {
    selectTheme = userTheme === 'night' ? 'dark' : 'light';
  } else if (isSysThemeDark) {
    selectTheme = 'dark';
  }

  localStorage.setItem('theme', selectTheme);
  yield put(setTheme(selectTheme));
}

export function createThemeSaga(types) {
  return [
    takeEvery(types.toggleTheme, toggleThemeSaga),
    takeEvery(types.initializeTheme, initializeThemeSaga)
  ];
}