ronantakizawa/codereview-bench huggingface dataset:
Repository: freeCodeCamp/freeCodeCamp
File: tools/ui-components/src/modal/modal.tsx (TypeScript)

Code before:

  if (showCloseButton) {
    classes = classes.concat(' ', 'flex items-center justify-between');

    return (
      <div className={classes}>
        <Dialog.Title
          className={`m-0 pl-[${TITLE_LEFT_PADDING}px] flex-1 text-md text-center`}
        >
          {children}
        </Dialog.Title>
        <CloseButton onClick={onClose} />
      </div>
    );
  }

  return (
    <div className={classes}>
      <Dialog.Title className='m-0 text-md text-center'>
        {children}
      </Dialog.Title>
    </div>
  );
};

const Body = ({ children }: { children: ReactNode }) => {
  return (
    <div className='p-[15px] border-b-1 border-solid border-foreground-secondary'>
      {children}
    </div>
  );
};

const Footer = ({ children }: { children: ReactNode }) => {
  return <div className='p-[15px]'>{children}</div>;
};

const Modal = ({
  children,
  open,
  onClose,
  size = 'medium',
  variant = 'default'
}: ModalProps) => {
  let panelClasses = PANEL_DEFAULT_CLASSES;

  if (size === 'medium') {
    panelClasses = panelClasses.concat(' ', 'w-[600px]');
  } else if (size === 'large') {
    panelClasses = panelClasses.concat(' ', 'w-[900px]');
  }

Review comment (suggestion):
I'm making `center` the default value as the majority of modals in /learn have the `text-center` class added.

I'm not sure if this is the right call, or the default value should be `start` instead (like the [browser default](https://developer.mozilla.org/en-US/docs/Web/CSS/text-align#formal_definition)), or there is no default and we should ask the consumers to explicitly set the alignment.

Code after:

  if (showCloseButton) {
    classes = classes.concat(' ', 'flex items-center justify-between');

    return (
      <div className={classes}>
        <Dialog.Title
          className={`m-0 pl-[${TITLE_LEFT_PADDING}px] flex-1 text-md text-center`}
        >
          {children}
        </Dialog.Title>
        <CloseButton onClick={onClose} />
      </div>
    );
  }

  return (
    <div className={classes}>
      <Dialog.Title className='m-0 text-md text-center'>
        {children}
      </Dialog.Title>
    </div>
  );
};

const Body = ({ children, alignment = 'center' }: BodyProps) => {
  return (
    <div
      className={`p-[15px] border-b-1 border-solid border-foreground-secondary text-${alignment}`}
    >
      {children}
    </div>
  );
};

const Footer = ({ children }: { children: ReactNode }) => {
  return <div className='p-[15px]'>{children}</div>;
};

const Modal = ({
  children,
  open,
  onClose,
  size = 'medium',
  variant = 'default'
}: ModalProps) => {
  let panelClasses = PANEL_DEFAULT_CLASSES;

  if (size === 'medium') {
    panelClasses = panelClasses.concat(' ', 'w-[600px]');
  } else if (size === 'large') {
Repository: freeCodeCamp/freeCodeCamp
File: tools/ui-components/src/modal/types.ts (TypeScript)

Code before:
import { type ReactNode } from 'react';

export interface ModalProps {
  children: ReactNode;
  open: boolean;
  onClose: () => void;
  size?: 'large' | 'medium';
  variant?: 'default' | 'danger';
}

export interface HeaderProps {
  children: ReactNode;
  showCloseButton?: boolean;
}


Review comment (suggestion):
We need `left` because there is at least one modal in /learn that contains code blocks, and programming code (or at least the programming languages we support) reads from left to right.


Code after:
import { type ReactNode } from 'react';

export interface ModalProps {
  children: ReactNode;
  open: boolean;
  onClose: () => void;
  size?: 'large' | 'medium';
  variant?: 'default' | 'danger';
}

export interface HeaderProps {
  children: ReactNode;
  showCloseButton?: boolean;
}

export interface BodyProps {
  children: ReactNode;

  /**
   * Use `start` for better right-to-left support.
   * Use `left` if the modal body contains code blocks.
   */
  alignment?: 'center' | 'left' | 'start';
}
Repository: freeCodeCamp/freeCodeCamp
File: client/src/components/settings/certification.tsx (TypeScript)

Code before:
    };

    return (
      <SolutionDisplayWidget
        completedChallenge={completedProject}
        dataCy={projectTitle}
        projectTitle={projectTitle}
        showExamResults={showExamResults}
        showUserCode={showUserCode}
        showProjectPreview={showProjectPreview}
        displayContext='settings'
      ></SolutionDisplayWidget>
    );
  };

  const Certification = ({
    certName,
    t
  }: {
    certName: Exclude<CertTitle, 'Legacy Full Stack'>;
    t: TFunction;
  }) => {
    const { certSlug } = certsToProjects[certName][0];
    return (
      <FullWidthRow>
        <Spacer size='medium' />
        <h3 className='text-center' id={`cert-${certSlug}`}>
          {t(`certification.title.${certName}`, certName)}
        </h3>
        <Table>
          <thead>
            <tr>
              <th>{t('settings.labels.project-name')}</th>
              <th>{t('settings.labels.solution')}</th>
            </tr>
          </thead>
          <tbody>
            <ProjectsFor
              certName={certName}
              isCert={getUserIsCertMap()[certName]}
            />
          </tbody>
        </Table>
      </FullWidthRow>
    );
  };

  function ProjectsFor({
    certName,
    isCert
  }: {

Review comment (suggestion):
I'm not sure why, but `ScrollableAnchor` doesn't work correctly without a wrapper element. A `div` here also works, but `section` is more appropriate.

Code after:
    };

    return (
      <SolutionDisplayWidget
        completedChallenge={completedProject}
        dataCy={projectTitle}
        projectTitle={projectTitle}
        showExamResults={showExamResults}
        showUserCode={showUserCode}
        showProjectPreview={showProjectPreview}
        displayContext='settings'
      ></SolutionDisplayWidget>
    );
  };

  const Certification = ({
    certName,
    t
  }: {
    certName: Exclude<CertTitle, 'Legacy Full Stack'>;
    t: TFunction;
  }) => {
    const { certSlug } = certsToProjects[certName][0];
    return (
      <ScrollableAnchor id={`cert-${certSlug}`}>
        <section>
          <FullWidthRow>
            <Spacer size='medium' />
            <h3 className='text-center'>
              {t(`certification.title.${certName}`, certName)}
            </h3>
            <Table>
              <thead>
                <tr>
                  <th>{t('settings.labels.project-name')}</th>
                  <th>{t('settings.labels.solution')}</th>
                </tr>
              </thead>
              <tbody>
                <ProjectsFor
                  certName={certName}
                  isCert={getUserIsCertMap()[certName]}
                />
              </tbody>
            </Table>
          </FullWidthRow>
        </section>
      </ScrollableAnchor>
    );
  };
Repository: freeCodeCamp/freeCodeCamp
File: client/src/templates/Challenges/components/scene/scene.tsx (TypeScript)

Code before:
import React, { useEffect, useState, useRef } from 'react'; //, ReactElement } from 'react';
import { Col } from '@freecodecamp/ui';
import { FullScene } from '../../../../redux/prop-types';
import { Loader } from '../../../../components/helpers';
import ClosedCaptionsIcon from '../../../../assets/icons/closedcaptions';
import { sounds, images, backgrounds, characterAssets } from './scene-assets';
import Character from './character';

import './scene.css';

export function Scene({
  scene,
  isPlaying,
  setIsPlaying
}: {
  scene: FullScene;
  isPlaying: boolean;
  setIsPlaying: (isPlaying: boolean) => void;
}): JSX.Element {
  const { setup, commands } = scene;
  const { audio, alwaysShowDialogue } = setup;

  const audioTimestamp =
    audio.startTimestamp !== null && audio.finishTimestamp !== null
      ? `#t=${audio.startTimestamp},${audio.finishTimestamp}`
      : '';

  const audioRef = useRef<HTMLAudioElement>(
    new Audio(`${sounds}/${audio.filename}${audioTimestamp}`)
  );

  const loadImage = (src: string | null) => {
    if (src) new Image().src = src;
  };

  // on mount
  useEffect(() => {
    const { current } = audioRef;
    current.addEventListener('canplaythrough', audioLoaded);

    // preload images
    loadImage(`${backgrounds}/${setup.background}`);


Review comment (suggestion):
```suggestion
  setIsPlaying: (shouldPlay: boolean) => void;
```

Code after:
import React, { useEffect, useState, useRef } from 'react'; //, ReactElement } from 'react';
import { Col } from '@freecodecamp/ui';
import { FullScene } from '../../../../redux/prop-types';
import { Loader } from '../../../../components/helpers';
import ClosedCaptionsIcon from '../../../../assets/icons/closedcaptions';
import { sounds, images, backgrounds, characterAssets } from './scene-assets';
import Character from './character';

import './scene.css';

export function Scene({
  scene,
  isPlaying,
  setIsPlaying
}: {
  scene: FullScene;
  isPlaying: boolean;
  setIsPlaying: (shouldPlay: boolean) => void;
}): JSX.Element {
  const { setup, commands } = scene;
  const { audio, alwaysShowDialogue } = setup;

  const audioTimestamp =
    audio.startTimestamp !== null && audio.finishTimestamp !== null
      ? `#t=${audio.startTimestamp},${audio.finishTimestamp}`
      : '';

  const audioRef = useRef<HTMLAudioElement>(
    new Audio(`${sounds}/${audio.filename}${audioTimestamp}`)
  );

  const loadImage = (src: string | null) => {
    if (src) new Image().src = src;
  };

  // on mount
  useEffect(() => {
    const { current } = audioRef;
    current.addEventListener('canplaythrough', audioLoaded);

    // preload images
    loadImage(`${backgrounds}/${setup.background}`);
Repository: freeCodeCamp/freeCodeCamp
File: client/src/templates/Challenges/dialogue/show.tsx (TypeScript)

Code before:
  handleAssignmentChange = (
    event: React.ChangeEvent<HTMLInputElement>,
    totalAssignments: number
  ): void => {
    const assignmentsCompleted = event.target.checked
      ? this.state.assignmentsCompleted + 1
      : this.state.assignmentsCompleted - 1;
    const allAssignmentsCompleted = totalAssignments === assignmentsCompleted;

    this.setState({
      assignmentsCompleted,
      allAssignmentsCompleted
    });
  };

  onVideoLoad = () => {
    this.setState({
      videoIsLoaded: true
    });
  };

  setIsScenePlaying = (isPlaying: boolean) => {
    this.setState({
      isScenePlaying: isPlaying
    });
  };

  render() {
    const {
      data: {
        challengeNode: {
          challenge: {
            title,
            description,
            superBlock,
            block,
            fields: { blockName },
            assignments,
            translationPending,
            scene
          }
        }
      },
      openHelpModal,
      pageContext: {
        challengeMeta: { nextChallengePath, prevChallengePath }
      },
      isChallengeCompleted,
      t
    } = this.props;


Review comment (suggestion):
```suggestion
  setIsScenePlaying = (shouldPlay: boolean) => {
    this.setState({
      isScenePlaying: shouldPlay
    });
  };
```

Code after:
  handleAssignmentChange = (
    event: React.ChangeEvent<HTMLInputElement>,
    totalAssignments: number
  ): void => {
    const assignmentsCompleted = event.target.checked
      ? this.state.assignmentsCompleted + 1
      : this.state.assignmentsCompleted - 1;
    const allAssignmentsCompleted = totalAssignments === assignmentsCompleted;

    this.setState({
      assignmentsCompleted,
      allAssignmentsCompleted
    });
  };

  onVideoLoad = () => {
    this.setState({
      videoIsLoaded: true
    });
  };

  setIsScenePlaying = (shouldPlay: boolean) => {
    this.setState({
      isScenePlaying: shouldPlay
    });
  };

  render() {
    const {
      data: {
        challengeNode: {
          challenge: {
            title,
            description,
            superBlock,
            block,
            fields: { blockName },
            assignments,
            translationPending,
            scene
          }
        }
      },
      openHelpModal,
      pageContext: {
        challengeMeta: { nextChallengePath, prevChallengePath }
      },
      isChallengeCompleted,
      t
    } = this.props;
Repository: freeCodeCamp/freeCodeCamp
File: client/src/templates/Challenges/fill-in-the-blank/show.tsx (TypeScript)

Code before:
  };

  addCodeTags(str: string, index: number, numberOfBlanks: number): string {
    if (index === 0) return `${str}</code>`;
    if (index < numberOfBlanks) return `<code>${str}</code>`;
    return `<code>${str}`;
  }

  addPrismClass(index: number, numberOfBlanks: number): string {
    if (index === 0) return `first-code-tag`;
    if (index < numberOfBlanks) return `middle-code-tag`;
    return `last-code-tag`;
  }

  addInputClass(index: number): string {
    const { answersCorrect } = this.state;
    if (answersCorrect[index] === true) return 'green-underline';
    if (answersCorrect[index] === false) return 'red-underline';
    return '';
  }

  setIsScenePlaying = (isPlaying: boolean) => {
    this.setState({
      isScenePlaying: isPlaying
    });
  };

  render() {
    const {
      data: {
        challengeNode: {
          challenge: {
            title,
            description,
            instructions,
            superBlock,
            block,
            translationPending,
            fields: { blockName },
            fillInTheBlank: { sentence, blanks },
            audioPath,
            scene
          }
        }
      },
      openHelpModal,
      pageContext: {
        challengeMeta: { nextChallengePath, prevChallengePath }
      },
      t,
      isChallengeCompleted

Review comment (suggestion):
```suggestion
  setIsScenePlaying = (shouldPlay: boolean) => {
    this.setState({
      isScenePlaying: shouldPlay
    });
  };
```

Code after:
  };

  addCodeTags(str: string, index: number, numberOfBlanks: number): string {
    if (index === 0) return `${str}</code>`;
    if (index < numberOfBlanks) return `<code>${str}</code>`;
    return `<code>${str}`;
  }

  addPrismClass(index: number, numberOfBlanks: number): string {
    if (index === 0) return `first-code-tag`;
    if (index < numberOfBlanks) return `middle-code-tag`;
    return `last-code-tag`;
  }

  addInputClass(index: number): string {
    const { answersCorrect } = this.state;
    if (answersCorrect[index] === true) return 'green-underline';
    if (answersCorrect[index] === false) return 'red-underline';
    return '';
  }

  setIsScenePlaying = (shouldPlay: boolean) => {
    this.setState({
      isScenePlaying: shouldPlay
    });
  };

  render() {
    const {
      data: {
        challengeNode: {
          challenge: {
            title,
            description,
            instructions,
            superBlock,
            block,
            translationPending,
            fields: { blockName },
            fillInTheBlank: { sentence, blanks },
            audioPath,
            scene
          }
        }
      },
      openHelpModal,
      pageContext: {
        challengeMeta: { nextChallengePath, prevChallengePath }
      },
      t,
      isChallengeCompleted
Repository: freeCodeCamp/freeCodeCamp
File: client/src/templates/Challenges/odin/show.tsx (TypeScript)

Code before:
  handleAssignmentChange = (
    event: React.ChangeEvent<HTMLInputElement>,
    totalAssignments: number
  ): void => {
    const assignmentsCompleted = event.target.checked
      ? this.state.assignmentsCompleted + 1
      : this.state.assignmentsCompleted - 1;
    const allAssignmentsCompleted = totalAssignments === assignmentsCompleted;

    this.setState({
      assignmentsCompleted,
      allAssignmentsCompleted
    });
  };

  onVideoLoad = () => {
    this.setState({
      videoIsLoaded: true
    });
  };

  setIsScenePlaying = (isPlaying: boolean) => {
    this.setState({
      isScenePlaying: isPlaying
    });
  };

  render() {
    const {
      data: {
        challengeNode: {
          challenge: {
            title,
            description,
            superBlock,
            block,
            videoId,
            videoLocaleIds,
            bilibiliIds,
            fields: { blockName },
            question: { text, answers, solution },
            assignments,
            audioPath,
            translationPending,
            scene
          }
        }
      },
      openCompletionModal,
      openHelpModal,
      pageContext: {

Review comment (suggestion):
```suggestion
  setIsScenePlaying = (shouldPlay: boolean) => {
    this.setState({
      isScenePlaying: shouldPlay
    });
  };
```

Code after:
  handleAssignmentChange = (
    event: React.ChangeEvent<HTMLInputElement>,
    totalAssignments: number
  ): void => {
    const assignmentsCompleted = event.target.checked
      ? this.state.assignmentsCompleted + 1
      : this.state.assignmentsCompleted - 1;
    const allAssignmentsCompleted = totalAssignments === assignmentsCompleted;

    this.setState({
      assignmentsCompleted,
      allAssignmentsCompleted
    });
  };

  onVideoLoad = () => {
    this.setState({
      videoIsLoaded: true
    });
  };

  setIsScenePlaying = (shouldPlay: boolean) => {
    this.setState({
      isScenePlaying: shouldPlay
    });
  };

  render() {
    const {
      data: {
        challengeNode: {
          challenge: {
            title,
            description,
            superBlock,
            block,
            videoId,
            videoLocaleIds,
            bilibiliIds,
            fields: { blockName },
            question: { text, answers, solution },
            assignments,
            audioPath,
            translationPending,
            scene
          }
        }
      },
      openCompletionModal,
      openHelpModal,
      pageContext: {
Repository: freeCodeCamp/freeCodeCamp
File: client/src/components/profile/components/portfolio-projects.tsx (TypeScript)

Code before:
  portfolioProjects
}: PortfolioProjectsProps): JSX.Element | null => {
  const { t } = useTranslation();
  if (!portfolioProjects.length) {
    return null;
  }
  return (
    <>
      <h2 className='text-center'>{t('profile.portfolio')}</h2>
      {portfolioProjects.map(({ title, url, image, description, id }) => (
        <div className='portfolio-container' key={id}>
          <h3>{title}</h3>
          <p>{description}</p>
          <a href={url} rel='nofollow noopener noreferrer' target='_blank'>
            {t('buttons.view')}
            <span className='sr-only'>
              {title}, {t('aria.opens-new-window')}
            </span>
            <FontAwesomeIcon id='link-icon' icon={faArrowUpRightFromSquare} />
          </a>
          {image && (
            <img
              alt=''
              className='portfolio-screen-shot'
              src={image}
              onError="this.src=require('https://d33wubrfki0l68.cloudfront.net/2f7693e1933ac514c960f51ceae72c91c6716eb2/b2efd/img/fcc_primary_small.svg')"
            />
          )}
        </div>
      ))}
      <hr />
    </>
  );
};


Review comment (suggestion):
```suggestion
              onError={({ currentTarget }) => {
                currentTarget.src =
                  'https://cdn.freecodecamp.org/platform/universal/fcc_meta_1920X1080-indigo.png';
              }}
```

Code after:
  portfolioProjects
}: PortfolioProjectsProps): JSX.Element | null => {
  const { t } = useTranslation();
  if (!portfolioProjects.length) {
    return null;
  }
  return (
    <>
      <h2 className='text-center'>{t('profile.portfolio')}</h2>
      {portfolioProjects.map(({ title, url, image, description, id }) => (
        <div className='portfolio-container' key={id}>
          <h3>{title}</h3>
          <p>{description}</p>
          <a href={url} rel='nofollow noopener noreferrer' target='_blank'>
            {t('buttons.view')}
            <span className='sr-only'>
              {title}, {t('aria.opens-new-window')}
            </span>
            <FontAwesomeIcon id='link-icon' icon={faArrowUpRightFromSquare} />
          </a>
          {image && (
            <img
              alt=''
              className='portfolio-screen-shot'
              src={image}
              onError={({ currentTarget }) => {
                currentTarget.src =
                  'https://cdn.freecodecamp.org/platform/universal/fcc_meta_1920X1080-indigo.png';
              }}
            />
          )}
        </div>
      ))}
      <hr />
    </>
  );
};
Repository: freeCodeCamp/freeCodeCamp
File: client/src/components/Donation/donation-modal.tsx (TypeScript)

Code before:
  recentlyClaimedBlock
}: DonateModalProps): JSX.Element {
  useEffect(() => {
    if (show) {
      void playTone('donation');
      callGA({ event: 'pageview', pagePath: '/donation-modal' });
      callGA({
        event: 'donation_view',
        action: `Displayed ${
          recentlyClaimedBlock !== null ? 'Block' : 'Progress'
        } Donation Modal`
      });
    }
  }, [show, recentlyClaimedBlock]);

  const handleModalHide = () => {
    // If modal is open on a SuperBlock page
    if (isLocationSuperBlock(location)) {
      goToAnchor('claim-cert-block');
    }
  };

  return (
    <Modal
      bsSize='lg'
      className='donation-modal'
      onExited={handleModalHide}
      show={show}
      data-cy='donation-modal'
    >
      <DonationModalBody
        closeDonationModal={closeDonationModal}
        recentlyClaimedBlock={recentlyClaimedBlock}
      />
    </Modal>
  );
}

DonateModal.displayName = 'DonateModal';

export default connect(mapStateToProps, mapDispatchToProps)(DonateModal);


Review comment (suggestion):
`Modal` doesn't accept `className`. I moved the class to the `div` within the `Modal.Body` instead (see line 277 of `donation-modal-body.tsx`).

Code after:
  recentlyClaimedBlock
}: DonateModalProps): JSX.Element {
  useEffect(() => {
    if (show) {
      void playTone('donation');
      callGA({ event: 'pageview', pagePath: '/donation-modal' });
      callGA({
        event: 'donation_view',
        action: `Displayed ${
          recentlyClaimedBlock !== null ? 'Block' : 'Progress'
        } Donation Modal`
      });
    }
  }, [show, recentlyClaimedBlock]);

  const handleModalHide = () => {
    // If modal is open on a SuperBlock page
    if (isLocationSuperBlock(location)) {
      goToAnchor('claim-cert-block');
    }
  };

  return (
    <Modal size='large' onClose={handleModalHide} open={show}>
      <DonationModalBody
        closeDonationModal={closeDonationModal}
        recentlyClaimedBlock={recentlyClaimedBlock}
      />
    </Modal>
  );
}

DonateModal.displayName = 'DonateModal';

export default connect(mapStateToProps, mapDispatchToProps)(DonateModal);