Repository: freeCodeCamp/freeCodeCamp
File: client/src/templates/Introduction/components/super-block-intro.tsx (TypeScript)

Code before:
import { useFeatureIsOn } from '@growthbook/growthbook-react';
import { SuperBlocks } from '../../../../../shared/config/curriculum';
import { SuperBlockIcon } from '../../../assets/superblock-icon';
import { Link } from '../../../components/helpers';
import CapIcon from '../../../assets/icons/cap';
import DumbbellIcon from '../../../assets/icons/dumbbell';
import CommunityIcon from '../../../assets/icons/community';
import { CompletedChallenge } from '../../../redux/prop-types';
import { completedChallengesSelector } from '../../../redux/selectors';

interface SuperBlockIntroQueryData {
  challengeNode: {
    challenge: {
      fields: {
        slug: string;
      };
    };
  };
}

interface SuperBlockIntroProps {
  superBlock: SuperBlocks;
  onCertificationDonationAlertClick: () => void;
  isDonating: boolean;
  completedChallenges: CompletedChallenge[];
}

const mapStateToProps = createSelector(
  completedChallengesSelector,
  (completedChallenges: CompletedChallenge[]) => ({
    completedChallenges
  })
);

export const ConditionalDonationAlert = ({
  superBlock,
  onCertificationDonationAlertClick,
  isDonating
}: Omit<SuperBlockIntroProps, 'completedChallenges'>): JSX.Element | null => {
  const { t } = useTranslation();

  const betaCertifications: SuperBlocks[] = [];

  const unfinishedCertifications = [
    SuperBlocks.A2English,
    SuperBlocks.B1English,
    SuperBlocks.A2Spanish,
    SuperBlocks.FullStackDeveloper
  ];

  if (!isDonating && betaCertifications.includes(superBlock))

Review comment (suggestion):
It's best not to redefine the `completedChallenges` prop here since it's already defined by `mapStateToProps` and can be inferred using `ConnectedProps`.

The docs are pretty good: https://redux.js.org/usage/usage-with-typescript#typing-the-connect-higher-order-component and we have a few examples in the codebase e.g. client/src/components/Header/index.tsx

Code after:
import { SuperBlocks } from '../../../../../shared/config/curriculum';
import { SuperBlockIcon } from '../../../assets/superblock-icon';
import { Link } from '../../../components/helpers';
import CapIcon from '../../../assets/icons/cap';
import DumbbellIcon from '../../../assets/icons/dumbbell';
import CommunityIcon from '../../../assets/icons/community';
import { CompletedChallenge } from '../../../redux/prop-types';
import { completedChallengesSelector } from '../../../redux/selectors';

interface SuperBlockIntroQueryData {
  challengeNode: {
    challenge: {
      fields: {
        slug: string;
      };
    };
  };
}

type ReduxProps = ConnectedProps<typeof connector>;

interface ConditionalDonationAlertProps {
  superBlock: SuperBlocks;
  onCertificationDonationAlertClick: () => void;
  isDonating: boolean;
}

interface SuperBlockIntroProps
  extends ConditionalDonationAlertProps,
    ReduxProps {}

const mapStateToProps = (state: unknown) => ({
  completedChallenges: completedChallengesSelector(
    state
  ) as CompletedChallenge[]
});

const connector = connect(mapStateToProps);

export const ConditionalDonationAlert = ({
  superBlock,
  onCertificationDonationAlertClick,
  isDonating
}: ConditionalDonationAlertProps): JSX.Element | null => {
  const { t } = useTranslation();

  const betaCertifications: SuperBlocks[] = [];

  const unfinishedCertifications = [
    SuperBlocks.A2English,
    SuperBlocks.B1English,