ronantakizawa/codereview-bench huggingface dataset:
Repository: freeCodeCamp/freeCodeCamp
File: client/src/components/Donation/donation-modal.tsx (TypeScript)

Code before:
    else return <BearProgressModal className='donation-icon' />;
  } else if (recentlyClaimedBlock !== null) {
    return <Cup className='donation-icon' />;
  } else {
    return <Heart className='donation-icon' />;
  }
};

function getctaNumberBetween1To10() {
  const min = 1;
  const max = 10;
  return Math.floor(Math.random() * (max - min + 1)) + min;
}

function DonateModal({
  show,
  closeDonationModal,
  executeGA,
  location,
  recentlyClaimedBlock
}: DonateModalProps): JSX.Element {
  const [closeLabel, setCloseLabel] = useState(false);
  const [ctaNumber, setCtaNumber] = useState(0);
  const [isDisabled, setIsDisabled] = useState(true);
  const [showSkipButton, setShowSkipButton] = useState(false);
  const loadElementsIdividually = useFeature('load_elements_individually').on;
  const { t } = useTranslation();
  const handleProcessing = () => {
    setCloseLabel(true);
  };

  useEffect(() => {
    if (!loadElementsIdividually) {
      setIsDisabled(false);
      setShowSkipButton(true);
      return;
    }
    const timer = setTimeout(() => {
      setIsDisabled(false);
      setShowSkipButton(true);
    }, 4000);
    return () => clearTimeout(timer);
  }, [loadElementsIdividually]);

  useEffect(() => {
    if (show) {
      void playTone('donation');
      executeGA({ event: 'pageview', pagePath: '/donation-modal' });
      executeGA({
        event: 'donation_view',
        action: `Displayed ${

Review comment (suggestion):
```suggestion
  const loadElementsIndividually = useFeature('load_elements_individually').on;
```

Code after:
    ) : (
      <BearProgressModal className='donation-icon' />
    );
  } else {
    return recentlyClaimedBlock ? (
      <Cup className='donation-icon' />
    ) : (
      <Heart className='donation-icon' />
    );
  }
};

function getctaNumberBetween1To10() {
  const min = 1;
  const max = 10;
  return Math.floor(Math.random() * (max - min + 1)) + min;
}

function DonateModal({
  show,
  closeDonationModal,
  executeGA,
  location,
  recentlyClaimedBlock
}: DonateModalProps): JSX.Element {
  const [closeLabel, setCloseLabel] = useState(false);
  const [ctaNumber, setCtaNumber] = useState(0);
  const [isDisabled, setIsDisabled] = useState(true);
  const [showSkipButton, setShowSkipButton] = useState(false);
  const loadElementsIndividually = useFeature('load_elements_individually').on;
  const { t } = useTranslation();
  const handleProcessing = () => {
    setCloseLabel(true);
  };

  useEffect(() => {
    if (loadElementsIndividually) {
      const timer = setTimeout(() => {
        setIsDisabled(false);
        setShowSkipButton(true);
      }, 4000);
      return () => clearTimeout(timer);
    } else {
      setIsDisabled(false);
      setShowSkipButton(true);
    }
  }, [loadElementsIndividually]);

  useEffect(() => {
    if (show) {
      void playTone('donation');
Repository: freeCodeCamp/freeCodeCamp
File: client/src/components/OfflineWarning/offline-warning.test.tsx (TypeScript)

Code before:
import React from 'react';
import { render, act, screen } from '@testing-library/react';

import OfflineWarning from './offline-warning';

jest.useFakeTimers();

describe('<OfflineWarning />', () => {
  it('renders null when isOnline, isServerOnline and isSignedIn are true', () => {
    const { container } = render(
      <OfflineWarning isOnline={true} isServerOnline={true} isSignedIn={true} />
    );
    act(() => jest.runOnlyPendingTimers());
    expect(container).toBeEmptyDOMElement();
  });

  it('renders the misc.offline message when isOnline is false', () => {
    render(
      <OfflineWarning
        isOnline={false}
        isServerOnline={true}
        isSignedIn={true}
      />
    );
    act(() => jest.runOnlyPendingTimers());
    expect(screen.getByText('misc.offline')).toBeInTheDocument();
  });

  it('renders the placeholder anchor tag', () => {
    render(
      <OfflineWarning
        isOnline={true}
        isServerOnline={false}
        isSignedIn={true}
      />
    );
    act(() => jest.runOnlyPendingTimers());
    expect(screen.getByText('placeholder').tagName).toBe('A');

Review comment (suggestion):
Could we / should we use `runAllTimers` here instead of `runOnlyPendingTimers`?

Looking at the doc, `runOnlyPendingTimers` seems to be for advanced cases (but I don't have much experience with fake timers):

> There are also scenarios where you might have a recursive timer – that is a timer that sets a new timer in its own callback.

https://jestjs.io/docs/timer-mocks#run-pending-timers

Code after:
import React from 'react';
import { render, act, screen } from '@testing-library/react';

import OfflineWarning from './offline-warning';

jest.useFakeTimers();

describe('<OfflineWarning />', () => {
  it('renders null when isOnline, isServerOnline and isSignedIn are true', () => {
    const { container } = render(
      <OfflineWarning isOnline={true} isServerOnline={true} isSignedIn={true} />
    );
    act(() => jest.runAllTimers());
    expect(container).toBeEmptyDOMElement();
  });

  it('renders the misc.offline message when isOnline is false', () => {
    render(
      <OfflineWarning
        isOnline={false}
        isServerOnline={true}
        isSignedIn={true}
      />
    );
    act(() => jest.runAllTimers());
    expect(screen.getByText('misc.offline')).toBeInTheDocument();
  });

  it('renders the placeholder anchor tag if isServerOnline is false', () => {
    render(
      <OfflineWarning
        isOnline={true}
        isServerOnline={false}
        isSignedIn={true}
      />
    );
    act(() => jest.runAllTimers());
    expect(screen.getByText('placeholder').tagName).toBe('A');
Repository: freeCodeCamp/freeCodeCamp
File: client/src/components/OfflineWarning/offline-warning.test.tsx (TypeScript)

Code before:
import OfflineWarning from './offline-warning';

jest.useFakeTimers();

describe('<OfflineWarning />', () => {
  it('renders null when isOnline, isServerOnline and isSignedIn are true', () => {
    const { container } = render(
      <OfflineWarning isOnline={true} isServerOnline={true} isSignedIn={true} />
    );
    act(() => jest.runOnlyPendingTimers());
    expect(container).toBeEmptyDOMElement();
  });

  it('renders the misc.offline message when isOnline is false', () => {
    render(
      <OfflineWarning
        isOnline={false}
        isServerOnline={true}
        isSignedIn={true}
      />
    );
    act(() => jest.runOnlyPendingTimers());
    expect(screen.getByText('misc.offline')).toBeInTheDocument();
  });

  it('renders the placeholder anchor tag', () => {
    render(
      <OfflineWarning
        isOnline={true}
        isServerOnline={false}
        isSignedIn={true}
      />
    );
    act(() => jest.runOnlyPendingTimers());
    expect(screen.getByText('placeholder').tagName).toBe('A');
  });

  it('renders null when isSignedIn is false', () => {
    const { container } = render(
      <OfflineWarning
        isOnline={true}
        isServerOnline={true}
        isSignedIn={false}
      />
    );
    act(() => jest.runOnlyPendingTimers());
    expect(container).toBeEmptyDOMElement();
  });

  it('renders the misc.offline message when isOnline and isServerOnline are false', () => {
    render(

Review comment (suggestion):
```suggestion
  it('renders the placeholder anchor tag if isServerOnline is false', () => {
```

Code after:
import OfflineWarning from './offline-warning';

jest.useFakeTimers();

describe('<OfflineWarning />', () => {
  it('renders null when isOnline, isServerOnline and isSignedIn are true', () => {
    const { container } = render(
      <OfflineWarning isOnline={true} isServerOnline={true} isSignedIn={true} />
    );
    act(() => jest.runAllTimers());
    expect(container).toBeEmptyDOMElement();
  });

  it('renders the misc.offline message when isOnline is false', () => {
    render(
      <OfflineWarning
        isOnline={false}
        isServerOnline={true}
        isSignedIn={true}
      />
    );
    act(() => jest.runAllTimers());
    expect(screen.getByText('misc.offline')).toBeInTheDocument();
  });

  it('renders the placeholder anchor tag if isServerOnline is false', () => {
    render(
      <OfflineWarning
        isOnline={true}
        isServerOnline={false}
        isSignedIn={true}
      />
    );
    act(() => jest.runAllTimers());
    expect(screen.getByText('placeholder').tagName).toBe('A');
    expect(screen.getByText('placeholder')).toHaveAttribute(
      'href',
      'mailto:support@freecodecamp.org'
    );
  });

  it('renders null when isSignedIn is false', () => {
    const { container } = render(
      <OfflineWarning
        isOnline={true}
        isServerOnline={true}
        isSignedIn={false}
      />
    );
    act(() => jest.runAllTimers());
    expect(container).toBeEmptyDOMElement();
Repository: freeCodeCamp/freeCodeCamp
File: client/src/components/OfflineWarning/offline-warning.test.tsx (TypeScript)

Code before:
    act(() => jest.runOnlyPendingTimers());
    expect(container).toBeEmptyDOMElement();
  });

  it('renders the misc.offline message when isOnline is false', () => {
    render(
      <OfflineWarning
        isOnline={false}
        isServerOnline={true}
        isSignedIn={true}
      />
    );
    act(() => jest.runOnlyPendingTimers());
    expect(screen.getByText('misc.offline')).toBeInTheDocument();
  });

  it('renders the placeholder anchor tag', () => {
    render(
      <OfflineWarning
        isOnline={true}
        isServerOnline={false}
        isSignedIn={true}
      />
    );
    act(() => jest.runOnlyPendingTimers());
    expect(screen.getByText('placeholder').tagName).toBe('A');
  });

  it('renders null when isSignedIn is false', () => {
    const { container } = render(
      <OfflineWarning
        isOnline={true}
        isServerOnline={true}
        isSignedIn={false}
      />
    );
    act(() => jest.runOnlyPendingTimers());
    expect(container).toBeEmptyDOMElement();
  });

  it('renders the misc.offline message when isOnline and isServerOnline are false', () => {
    render(
      <OfflineWarning
        isOnline={false}
        isServerOnline={false}
        isSignedIn={true}
      />
    );
    act(() => jest.runOnlyPendingTimers());
    expect(screen.getByText('misc.offline')).toBeInTheDocument();
  });

Review comment (suggestion):
We could also check if the element contains the correct link:

```suggestion
    expect(screen.getByText('placeholder').tagName).toBe('A');
    expect(screen.getByText('placeholder')).toHaveAttribute('href', 'mailto:support@freecodecamp.org');
```


Code after:
    act(() => jest.runAllTimers());
    expect(container).toBeEmptyDOMElement();
  });

  it('renders the misc.offline message when isOnline is false', () => {
    render(
      <OfflineWarning
        isOnline={false}
        isServerOnline={true}
        isSignedIn={true}
      />
    );
    act(() => jest.runAllTimers());
    expect(screen.getByText('misc.offline')).toBeInTheDocument();
  });

  it('renders the placeholder anchor tag if isServerOnline is false', () => {
    render(
      <OfflineWarning
        isOnline={true}
        isServerOnline={false}
        isSignedIn={true}
      />
    );
    act(() => jest.runAllTimers());
    expect(screen.getByText('placeholder').tagName).toBe('A');
    expect(screen.getByText('placeholder')).toHaveAttribute(
      'href',
      'mailto:support@freecodecamp.org'
    );
  });

  it('renders null when isSignedIn is false', () => {
    const { container } = render(
      <OfflineWarning
        isOnline={true}
        isServerOnline={true}
        isSignedIn={false}
      />
    );
    act(() => jest.runAllTimers());
    expect(container).toBeEmptyDOMElement();
  });

  it('renders the misc.offline message when isOnline and isServerOnline are false', () => {
    render(
      <OfflineWarning
        isOnline={false}
        isServerOnline={false}
        isSignedIn={true}
      />
Repository: freeCodeCamp/freeCodeCamp
File: api/src/routes/challenge.ts (TypeScript)

Code before:
import {
  Type,
  type FastifyPluginCallbackTypebox
} from '@fastify/type-provider-typebox';
import jwt from 'jsonwebtoken';
import { uniqBy } from 'lodash';
import { jwtSecret } from '../../../config/secrets';
import { fixPartiallyCompletedChallengeItem } from '../utils';
import { getChallenges } from '../utils/get-challenges';
import { updateUserChallengeData } from '../utils/common-challenge-functions';
interface JwtPayload {
  userToken: string;
}

export const challengeRoutes: FastifyPluginCallbackTypebox = (
  fastify,
  _options,
  done
) => {
  const challenges = getChallenges();
  fastify.post(
    '/challenge/coderoad-challenge-completed',
    {
      schema: {
        body: Type.Object({
          tutorialId: Type.String()
        }),
        response: {
          200: Type.Object({ msg: Type.String() }),
          400: Type.Object({
            msg: Type.String()
          }),
          500: Type.Object({
            message: Type.Literal('Something went wrong.'),
            type: Type.Literal('danger')
          })
        }
      },
      attachValidation: true
    },
    async (req, reply) => {
      let userToken;

      const { 'coderoad-user-token': encodedUserToken } = req.headers;
      const { tutorialId } = req.body;

      if (!tutorialId) {

Review comment (suggestion):
```suggestion
    '/coderoad-challenge-completed',
```

Code after:
import { type FastifyPluginCallbackTypebox } from '@fastify/type-provider-typebox';
import jwt from 'jsonwebtoken';
import { uniqBy } from 'lodash';
import { jwtSecret } from '../../../config/secrets';
import { getChallenges } from '../utils/get-challenges';
import { updateUserChallengeData } from '../utils/common-challenge-functions';
import { formatValidationError } from '../utils/error-formatting';
import { schemas } from '../schemas';
import { getPoints, ProgressTimestamp } from '../utils/progress';
import { challengeTypes } from '../../../config/challenge-types';
import {
  canSubmitCodeRoadCertProject,
  createProject,
  updateProject
} from './helpers/challenge-helpers';

interface JwtPayload {
  userToken: string;
}

/**
 * Plugin for the challenge submission endpoints.
 *
 * @param fastify The Fastify instance.
 * @param _options Options passed to the plugin via `fastify.register(plugin, options)`.
 * @param done The callback to signal that the plugin is ready.
 */
export const challengeRoutes: FastifyPluginCallbackTypebox = (
  fastify,
  _options,
  done
) => {
  const challenges = getChallenges();

  // eslint-disable-next-line @typescript-eslint/unbound-method
  fastify.addHook('onRequest', fastify.csrfProtection);
  fastify.addHook('onRequest', fastify.authenticateSession);

  fastify.post(
    '/coderoad-challenge-completed',
    {
      schema: schemas.coderoadChallengeCompleted,
      attachValidation: true
    },
    async (req, reply) => {
      let userToken;
Repository: freeCodeCamp/freeCodeCamp
File: api/src/routes/challenge.ts (TypeScript)

Code before:

        if (!user)
          return {
            type: 'error',
            msg: 'User for user token not found'
          } as const;

        const completedDate = Date.now();
        const { completedChallenges = [], partiallyCompletedChallenges = [] } =
          user;

        const isCompleted = completedChallenges.some(
          challenge => challenge.id === challengeId
        );

        if (challengeType === 13 && !isCompleted) {
          const finalChallenge = {
            id: challengeId,
            completedDate
          };

          await fastify.prisma.user.update({
            where: { id: req.session.user.id },
            data: {
              partiallyCompletedChallenges: uniqBy(
                [
                  finalChallenge,
                  ...partiallyCompletedChallenges.map(
                    fixPartiallyCompletedChallengeItem
                  )
                ],
                'id'
              )
            }
          });
        } else {
          await updateUserChallengeData(fastify, user, challengeId, {
            id: challengeId,
            completedDate
          });
        }
      } catch {
        void reply.code(400);
        return {
          type: 'error',
          msg: 'An error occurred trying to submit the challenge'
        } as const;
      }
      return {
        type: 'success',
        msg: 'Successfully submitted challenge'

Review comment (suggestion):
should this wait until challengeTypes is in config folder, https://github.com/freeCodeCamp/freeCodeCamp/pull/51027

Code after:
          return { type: 'error', msg: 'User token not found' } as const;
        }

        const { userId } = tokenInfo;

        const user = await fastify.prisma.user.findFirstOrThrow({
          where: { id: userId }
        });

        if (!user) {
          void reply.code(400);
          return {
            type: 'error',
            msg: 'User for user token not found'
          } as const;
        }

        const completedDate = Date.now();
        const { completedChallenges = [], partiallyCompletedChallenges = [] } =
          user;

        const isCompleted = completedChallenges.some(
          challenge => challenge.id === challengeId
        );

        if (challengeType === 13 && !isCompleted) {
          const finalChallenge = {
            id: challengeId,
            completedDate
          };

          await fastify.prisma.user.update({
            where: { id: req.session.user.id },
            data: {
              partiallyCompletedChallenges: uniqBy(
                [finalChallenge, ...partiallyCompletedChallenges],
                'id'
              )
            }
          });
        } else {
          await updateUserChallengeData(fastify, user, challengeId, {
            id: challengeId,
            completedDate
          });
        }
      } catch {
        void reply.code(400);
        return {
          type: 'error',
          msg: 'An error occurred trying to submit the challenge'
Repository: freeCodeCamp/freeCodeCamp
File: api/src/utils/index.ts (TypeScript)

Code before:
 * Utility to encode a buffer to a base64 URI.
 *
 * @param buf The buffer to encode.
 * @returns The encoded string.
 */
export function base64URLEncode(buf: Buffer): string {
  return buf
    .toString('base64')
    .replace(/\+/g, '-')
    .replace(/\//g, '_')
    .replace(/=/g, '');
}
export const verifier = base64URLEncode(randomBytes(32));

function sha256(buf: Buffer) {
  return createHash('sha256').update(buf).digest();
}
export const challenge = base64URLEncode(sha256(Buffer.from(verifier)));

/**
 *
 * @param obj This is the full challenge object.
 * @returns This is the challenge object with only the id and completedDate.
 */
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export const fixPartiallyCompletedChallengeItem = (obj: any) =>
  pick(obj, ['id', 'completedDate']);


Review comment (suggestion):
This is a nit, so don't mind me, but we should be able to do something like:

`obj: { id: string, completedDate: number, [key: string]: unknown}`

This will at least force us to validate those properties exist when passing in an argument to this function. 

Code after:
import { randomBytes, createHash } from 'crypto';

/**
 * Utility to encode a buffer to a base64 URI.
 *
 * @param buf The buffer to encode.
 * @returns The encoded string.
 */
export function base64URLEncode(buf: Buffer): string {
  return buf
    .toString('base64')
    .replace(/\+/g, '-')
    .replace(/\//g, '_')
    .replace(/=/g, '');
}
export const verifier = base64URLEncode(randomBytes(32));

function sha256(buf: Buffer) {
  return createHash('sha256').update(buf).digest();
}
export const challenge = base64URLEncode(sha256(Buffer.from(verifier)));
Repository: freeCodeCamp/freeCodeCamp
File: api/src/utils/get-challenges.ts (TypeScript)

Code before:
import { flatten } from 'lodash';

// TODO: keeping curriculum in memory is handy if we want to field requests that
// need to 'query' the curriculum, but if we force the client to handle
// redirectToCurrentChallenge and, instead, only report the current challenge id
// via the user object, then we should *not* store this so it can be garbage
// collected.
import curriculum from '../../../config/curriculum.json';
import { SuperBlocks } from '../../../config/superblocks';
import { type ChallengeNode } from '../../../client/src/redux/prop-types';

type Curriculum = { [keyValue in SuperBlocks]?: CurriculumProps };
type SuperBlockKeys = keyof Curriculum;

// eslint-disable-next-line @typescript-eslint/no-unused-vars
interface Block<T> {
  challenges: ChallengeNode['challenge'][];
}

interface CurriculumProps {
  blocks: Record<string, Block<ChallengeNode['challenge'][]>>;
}

export function getChallenges() {
  const superBlockKeys = Object.keys(SuperBlocks) as SuperBlockKeys[];
  const typedCurriculum: Curriculum = curriculum;

  return superBlockKeys
    .map(key => typedCurriculum[key]?.blocks)
    .reduce((accumulator: ChallengeNode['challenge'][], superBlock) => {
      const blockKeys = Object.keys(superBlock ?? {});
      const challengesForBlock = blockKeys.map(
        key => superBlock?.[key]?.challenges ?? []
      );
      return [...accumulator, ...flatten(challengesForBlock)];

Review comment (suggestion):
```suggestion
```
Let's not import from the client. For one thing the types in there are often bad guesses and for another we want the api to be the source of truth for types.

Code after:
// TODO: keeping curriculum in memory is handy if we want to field requests that
// need to 'query' the curriculum, but if we force the client to handle
// redirectToCurrentChallenge and, instead, only report the current challenge id
// via the user object, then we should *not* store this so it can be garbage
// collected.
import curriculum from '../../../config/curriculum.json';
import { SuperBlocks } from '../../../config/superblocks';

type Curriculum = { [keyValue in SuperBlocks]?: CurriculumProps };
type SuperBlockKeys = keyof Curriculum;

// eslint-disable-next-line @typescript-eslint/no-unused-vars
interface Block {
  challenges: {
    id: string;
    tests?: { id?: string }[];
    challengeType: number;
  }[];
}

interface CurriculumProps {
  blocks: Record<string, Block>;
}

export function getChallenges() {
  const superBlockKeys = Object.keys(SuperBlocks) as SuperBlockKeys[];
  const typedCurriculum: Curriculum = curriculum as Curriculum;

  return superBlockKeys
    .map(key => typedCurriculum[key]?.blocks)
    .reduce((accumulator: Block['challenges'], superBlock) => {
      const blockKeys = Object.keys(superBlock ?? {});
      const challengesForBlock = blockKeys.map(
        key => superBlock?.[key]?.challenges ?? []
      );