diff --git a/.eslintrc.json b/.eslintrc.json index df1ce9fef6..a183b8c4c6 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -54,7 +54,46 @@ "plugin:@typescript-eslint/recommended", "plugin:@typescript-eslint/recommended-requiring-type-checking" ], - "plugins": ["@typescript-eslint"] + "plugins": ["@typescript-eslint"], + "rules": { + "@typescript-eslint/naming-convention": [ + "error", + { + "selector": "default", + "format": ["camelCase"], + "leadingUnderscore": "allow", + "trailingUnderscore": "allow" + }, + + { + "selector": "variable", + "format": ["camelCase", "UPPER_CASE", "PascalCase"], + "leadingUnderscore": "allowSingleOrDouble", + "trailingUnderscore": "allow" + }, + { + "selector": "typeLike", + "format": ["PascalCase"], + "custom": { + "regex": "^I[A-Z]|[a-zA-Z]Type$", + "match": false + } + }, + { + "selector": "typeProperty", + "format": ["camelCase", "PascalCase"] + }, + { + "selector": "objectLiteralProperty", + "format": ["camelCase", "PascalCase"], + "leadingUnderscore": "allowSingleOrDouble" + }, + { + "selector": "function", + "format": ["camelCase", "PascalCase"] + } + ] + } }, { "files": [ diff --git a/client/src/client-only-routes/show-certification.tsx b/client/src/client-only-routes/show-certification.tsx index 33074c2152..6e0c743739 100644 --- a/client/src/client-only-routes/show-certification.tsx +++ b/client/src/client-only-routes/show-certification.tsx @@ -36,7 +36,7 @@ import ShowProjectLinks from './show-project-links'; const { clientLocale } = envData as { clientLocale: keyof typeof langCodes }; const localeCode = langCodes[clientLocale]; -type CertType = { +type Cert = { username: string; name: string; certName: string; @@ -44,8 +44,8 @@ type CertType = { completionTime: number; date: number; }; -interface IShowCertificationProps { - cert: CertType; +interface ShowCertificationProps { + cert: Cert; certDashedName: string; certSlug: string; createFlashMessage: typeof createFlashMessage; @@ -82,7 +82,7 @@ const requestedUserSelector = (state: unknown, { username = '' }) => const validCertSlugs = certMap.map(cert => cert.certSlug); -const mapStateToProps = (state: unknown, props: IShowCertificationProps) => { +const mapStateToProps = (state: unknown, props: ShowCertificationProps) => { const isValidCert = validCertSlugs.some(slug => slug === props.certSlug); return createSelector( showCertSelector, @@ -92,10 +92,10 @@ const mapStateToProps = (state: unknown, props: IShowCertificationProps) => { isDonatingSelector, requestedUserSelector, ( - cert: CertType, - fetchState: IShowCertificationProps['fetchState'], + cert: Cert, + fetchState: ShowCertificationProps['fetchState'], signedInUserName: string, - userFetchState: IShowCertificationProps['userFetchState'], + userFetchState: ShowCertificationProps['userFetchState'], isDonating: boolean, user ) => ({ @@ -116,7 +116,7 @@ const mapDispatchToProps = (dispatch: Dispatch) => dispatch ); -const ShowCertification = (props: IShowCertificationProps): JSX.Element => { +const ShowCertification = (props: ShowCertificationProps): JSX.Element => { const { t } = useTranslation(); const [isDonationSubmitted, setIsDonationSubmitted] = useState(false); const [isDonationDisplayed, setIsDonationDisplayed] = useState(false); diff --git a/client/src/client-only-routes/show-profile-or-four-oh-four.tsx b/client/src/client-only-routes/show-profile-or-four-oh-four.tsx index c4e0ed9c6d..1bda0338f1 100644 --- a/client/src/client-only-routes/show-profile-or-four-oh-four.tsx +++ b/client/src/client-only-routes/show-profile-or-four-oh-four.tsx @@ -5,7 +5,7 @@ import { connect } from 'react-redux'; import { isBrowser } from '../../utils/index'; import FourOhFour from '../components/FourOhFour'; import Loader from '../components/helpers/loader'; -import Profile from '../components/profile/Profile'; +import Profile from '../components/profile/profile'; import { userByNameSelector, userProfileFetchStateSelector, @@ -14,7 +14,7 @@ import { } from '../redux'; import { User } from '../redux/prop-types'; -interface IShowProfileOrFourOhFourProps { +interface ShowProfileOrFourOhFourProps { fetchProfileForUser: (username: string) => void; fetchState: { pending: boolean; @@ -37,12 +37,12 @@ const createIsSessionUserSelector = maybeUser.toLowerCase() === usernameSelector(state); const makeMapStateToProps = - () => (state: unknown, props: IShowProfileOrFourOhFourProps) => { + () => (state: unknown, props: ShowProfileOrFourOhFourProps) => { const requestedUserSelector = createRequestedUserSelector(); const isSessionUserSelector = createIsSessionUserSelector(); const fetchState = userProfileFetchStateSelector( state - ) as IShowProfileOrFourOhFourProps['fetchState']; + ) as ShowProfileOrFourOhFourProps['fetchState']; return { requestedUser: requestedUserSelector(state, props), isSessionUser: isSessionUserSelector(state, props), @@ -52,12 +52,12 @@ const makeMapStateToProps = }; const mapDispatchToProps: { - fetchProfileForUser: IShowProfileOrFourOhFourProps['fetchProfileForUser']; + fetchProfileForUser: ShowProfileOrFourOhFourProps['fetchProfileForUser']; } = { fetchProfileForUser }; -class ShowProfileOrFourOhFour extends Component { +class ShowProfileOrFourOhFour extends Component { componentDidMount() { const { requestedUser, maybeUser, fetchProfileForUser } = this.props; if (isEmpty(requestedUser)) { diff --git a/client/src/client-only-routes/show-project-links.tsx b/client/src/client-only-routes/show-project-links.tsx index bc243df3a0..b927bf8c0c 100644 --- a/client/src/client-only-routes/show-project-links.tsx +++ b/client/src/client-only-routes/show-project-links.tsx @@ -12,27 +12,27 @@ import { import { maybeUrlRE } from '../utils'; -interface IShowProjectLinksProps { +interface ShowProjectLinksProps { certName: string; name: string; user: User; } -type SolutionStateType = { +type SolutionState = { projectTitle: string; challengeFiles: ChallengeFiles; solution: CompletedChallenge['solution']; isOpen: boolean; }; -const initSolutionState: SolutionStateType = { +const initSolutionState: SolutionState = { projectTitle: '', challengeFiles: null, solution: '', isOpen: false }; -const ShowProjectLinks = (props: IShowProjectLinksProps): JSX.Element => { +const ShowProjectLinks = (props: ShowProjectLinksProps): JSX.Element => { const [solutionState, setSolutionState] = useState(initSolutionState); const handleSolutionModalHide = () => setSolutionState(initSolutionState); diff --git a/client/src/client-only-routes/show-settings.tsx b/client/src/client-only-routes/show-settings.tsx index c49e9337be..d411f67fab 100644 --- a/client/src/client-only-routes/show-settings.tsx +++ b/client/src/client-only-routes/show-settings.tsx @@ -28,7 +28,7 @@ import { submitNewAbout, updateUserFlag, verifyCert } from '../redux/settings'; const { apiLocation } = envData; // TODO: update types for actions -interface IShowSettingsProps { +interface ShowSettingsProps { createFlashMessage: typeof createFlashMessage; isSignedIn: boolean; navigate: (location: string) => void; @@ -70,7 +70,7 @@ const mapDispatchToProps = { verifyCert }; -export function ShowSettings(props: IShowSettingsProps): JSX.Element { +export function ShowSettings(props: ShowSettingsProps): JSX.Element { const { t } = useTranslation(); const { createFlashMessage, diff --git a/client/src/client-only-routes/show-user.tsx b/client/src/client-only-routes/show-user.tsx index f2cac138a6..d60045e93e 100644 --- a/client/src/client-only-routes/show-user.tsx +++ b/client/src/client-only-routes/show-user.tsx @@ -23,7 +23,7 @@ import { reportUser } from '../redux'; -interface IShowUserProps { +interface ShowUserProps { email: string; isSignedIn: boolean; reportUser: (payload: { @@ -45,7 +45,7 @@ const mapStateToProps = createSelector( userSelector, ( isSignedIn, - userFetchState: IShowUserProps['userFetchState'], + userFetchState: ShowUserProps['userFetchState'], { email }: { email: string } ) => ({ isSignedIn, @@ -65,7 +65,7 @@ function ShowUser({ t, userFetchState, username -}: IShowUserProps) { +}: ShowUserProps) { const [textarea, setTextarea] = useState(''); function handleChange(e: React.ChangeEvent) { diff --git a/client/src/components/Donation/DonateForm.tsx b/client/src/components/Donation/DonateForm.tsx index 1cf6fc7ce7..1c1582fc81 100644 --- a/client/src/components/Donation/DonateForm.tsx +++ b/client/src/components/Donation/DonateForm.tsx @@ -27,9 +27,9 @@ import { } from '../../redux'; import Spacer from '../helpers/spacer'; import DonateCompletion from './DonateCompletion'; -import type { AddDonationData } from './PaypalButton'; -import PaypalButton from './PaypalButton'; import PatreonButton from './patreon-button'; +import type { AddDonationData } from './paypal-button'; +import PaypalButton from './paypal-button'; import StripeCardForm, { HandleAuthentication } from './stripe-card-form'; import WalletsWrapper from './walletsButton'; diff --git a/client/src/components/Donation/PayPalButtonScriptLoader.tsx b/client/src/components/Donation/paypal-button-script-loader.tsx similarity index 97% rename from client/src/components/Donation/PayPalButtonScriptLoader.tsx rename to client/src/components/Donation/paypal-button-script-loader.tsx index cd47af4180..6a01378d93 100644 --- a/client/src/components/Donation/PayPalButtonScriptLoader.tsx +++ b/client/src/components/Donation/paypal-button-script-loader.tsx @@ -4,8 +4,9 @@ import ReactDOM from 'react-dom'; import { scriptLoader, scriptRemover } from '../../utils/script-loaders'; -import type { AddDonationData } from './PaypalButton'; +import type { AddDonationData } from './paypal-button'; +/* eslint-disable @typescript-eslint/naming-convention */ type PayPalButtonScriptLoaderProps = { isMinimalForm: boolean | undefined; clientId: string; @@ -43,6 +44,7 @@ type PayPalButtonScriptLoaderProps = { }; planId: string | null; }; +/* eslint-enable @typescript-eslint/naming-convention */ type PayPalButtonScriptLoaderState = { isSdkLoaded: boolean; diff --git a/client/src/components/Donation/paypal-button.test.tsx b/client/src/components/Donation/paypal-button.test.tsx index c1bd045461..9f971d4e37 100644 --- a/client/src/components/Donation/paypal-button.test.tsx +++ b/client/src/components/Donation/paypal-button.test.tsx @@ -1,7 +1,7 @@ import { render } from '@testing-library/react'; import React from 'react'; -import { PaypalButton } from './PaypalButton'; +import { PaypalButton } from './paypal-button'; const commonProps = { donationAmount: 500, diff --git a/client/src/components/Donation/PaypalButton.tsx b/client/src/components/Donation/paypal-button.tsx similarity index 96% rename from client/src/components/Donation/PaypalButton.tsx rename to client/src/components/Donation/paypal-button.tsx index 3ede8777d7..e33306ab6f 100644 --- a/client/src/components/Donation/PaypalButton.tsx +++ b/client/src/components/Donation/paypal-button.tsx @@ -13,7 +13,7 @@ import { } from '../../../../config/donation-settings'; import envData from '../../../../config/env.json'; import { signInLoadingSelector, userSelector } from '../../redux'; -import PayPalButtonScriptLoader from './PayPalButtonScriptLoader'; +import PayPalButtonScriptLoader from './paypal-button-script-loader'; type PaypalButtonProps = { addDonation: (data: AddDonationData) => void; @@ -138,7 +138,7 @@ export class PaypalButton extends Component< return (
- {/* help needed */} + {/* eslint-disable @typescript-eslint/naming-convention */} + {/* eslint-enable @typescript-eslint/naming-convention */}
); } diff --git a/client/src/components/Donation/stripe-card-form.tsx b/client/src/components/Donation/stripe-card-form.tsx index 22da886572..29388d4b80 100644 --- a/client/src/components/Donation/stripe-card-form.tsx +++ b/client/src/components/Donation/stripe-card-form.tsx @@ -16,7 +16,7 @@ import type { import React, { useState } from 'react'; import envData from '../../../../config/env.json'; -import { AddDonationData } from './PaypalButton'; +import { AddDonationData } from './paypal-button'; const { stripePublicKey }: { stripePublicKey: string | null } = envData; @@ -132,7 +132,7 @@ const StripeCardForm = ({ ) => { if (stripe) { return stripe.confirmCardPayment(clientSecret, { - // eslint-disable-next-line camelcase + // eslint-disable-next-line camelcase, @typescript-eslint/naming-convention payment_method: paymentMethod }); } diff --git a/client/src/components/Donation/walletsButton.tsx b/client/src/components/Donation/walletsButton.tsx index 6665cd1dd4..49a1655b41 100644 --- a/client/src/components/Donation/walletsButton.tsx +++ b/client/src/components/Donation/walletsButton.tsx @@ -7,7 +7,7 @@ import { Stripe, loadStripe } from '@stripe/stripe-js'; import type { Token, PaymentRequest } from '@stripe/stripe-js'; import React, { useState, useEffect } from 'react'; import envData from '../../../../config/env.json'; -import { AddDonationData } from './PaypalButton'; +import { AddDonationData } from './paypal-button'; const { stripePublicKey }: { stripePublicKey: string | null } = envData; diff --git a/client/src/components/landing/components/big-call-to-action.tsx b/client/src/components/landing/components/big-call-to-action.tsx index b81f327adf..99e5d5d3b5 100644 --- a/client/src/components/landing/components/big-call-to-action.tsx +++ b/client/src/components/landing/components/big-call-to-action.tsx @@ -2,11 +2,11 @@ import React from 'react'; import { useTranslation } from 'react-i18next'; import Login from '../../Header/components/Login'; -interface bigCallToActionProps { +interface BigCallToActionProps { pageName: string; } -const BigCallToAction = ({ pageName }: bigCallToActionProps): JSX.Element => { +const BigCallToAction = ({ pageName }: BigCallToActionProps): JSX.Element => { const { t } = useTranslation(); return ( diff --git a/client/src/components/landing/components/campers-image.tsx b/client/src/components/landing/components/campers-image.tsx index dda48610e2..fe94b118c0 100644 --- a/client/src/components/landing/components/campers-image.tsx +++ b/client/src/components/landing/components/campers-image.tsx @@ -6,28 +6,22 @@ import { Spacer, ImageLoader } from '../../helpers'; const LARGE_SCREEN_SIZE = 1200; -interface campersImageProps { +interface CampersImageProps { pageName: string; } -interface imageSizeProps { - spacerSize: number; - height: number; - width: number; -} - -const donateImageSize: imageSizeProps = { +const donateImageSize = { spacerSize: 0, height: 345, width: 585 }; -const landingImageSize: imageSizeProps = { +const landingImageSize = { spacerSize: 2, height: 442, width: 750 }; -function CampersImage({ pageName }: campersImageProps): JSX.Element { +function CampersImage({ pageName }: CampersImageProps): JSX.Element { const { t } = useTranslation(); const { spacerSize, height, width } = diff --git a/client/src/components/landing/components/certifications.tsx b/client/src/components/landing/components/certifications.tsx index db9d3563b9..141ffd3606 100644 --- a/client/src/components/landing/components/certifications.tsx +++ b/client/src/components/landing/components/certifications.tsx @@ -5,13 +5,13 @@ import Map from '../../Map/index'; import { Spacer } from '../../helpers'; import BigCallToAction from './big-call-to-action'; -interface certificationProps { +interface CertificationProps { pageName: string; } const Certifications = ({ pageName = 'landing' -}: certificationProps): JSX.Element => { +}: CertificationProps): JSX.Element => { const { t } = useTranslation(); return ( diff --git a/client/src/components/landing/components/landing-top.tsx b/client/src/components/landing/components/landing-top.tsx index bf2ab5efe0..32126eaf09 100644 --- a/client/src/components/landing/components/landing-top.tsx +++ b/client/src/components/landing/components/landing-top.tsx @@ -15,12 +15,12 @@ import { Spacer } from '../../helpers'; import BigCallToAction from './big-call-to-action'; import CampersImage from './campers-image'; -interface landingTopProps { +interface LandingTopProps { pageName: string; } const { clientLocale } = envData; -function LandingTop({ pageName }: landingTopProps): JSX.Element { +function LandingTop({ pageName }: LandingTopProps): JSX.Element { const { t } = useTranslation(); const showChineseLogos = ['chinese', 'chinese-tradition'].includes( clientLocale diff --git a/client/src/components/profile/__snapshots__/Profile.test.tsx.snap b/client/src/components/profile/__snapshots__/profile.test.tsx.snap similarity index 100% rename from client/src/components/profile/__snapshots__/Profile.test.tsx.snap rename to client/src/components/profile/__snapshots__/profile.test.tsx.snap diff --git a/client/src/components/profile/components/TimeLine.tsx b/client/src/components/profile/components/TimeLine.tsx index 4cccc6889b..0505e63b5a 100644 --- a/client/src/components/profile/components/TimeLine.tsx +++ b/client/src/components/profile/components/TimeLine.tsx @@ -20,10 +20,10 @@ import { getTitleFromId } from '../../../../../utils'; import CertificationIcon from '../../../assets/icons/certification-icon'; -import { ChallengeFiles } from '../../../redux/prop-types'; +import { ChallengeFiles, CompletedChallenge } from '../../../redux/prop-types'; import { maybeUrlRE } from '../../../utils'; import { FullWidthRow, Link } from '../../helpers'; -import TimelinePagination from './TimelinePagination'; +import TimelinePagination from './timeline-pagination'; import './timeline.css'; @@ -37,32 +37,15 @@ const localeCode = langCodes[clientLocale]; // Items per page in timeline. const ITEMS_PER_PAGE = 15; -interface CompletedMap { - id: string; - completedDate: number; - challengeType: number; - solution: string; - challengeFiles: ChallengeFiles; - githubLink: string; -} - interface TimelineProps { - completedMap: CompletedMap[]; + completedMap: CompletedChallenge[]; t: TFunction; username: string; } -interface SortedTimeline { - id: string; - completedDate: number; - challengeFiles: ChallengeFiles; - githubLink: string; - solution: string; -} - interface TimelineInnerProps extends TimelineProps { idToNameMap: Map; - sortedTimeline: SortedTimeline[]; + sortedTimeline: CompletedChallenge[]; totalPages: number; } @@ -83,12 +66,12 @@ function TimelineInner({ function viewSolution( id: string, - solution_: string, + solution_: string | undefined | null, challengeFiles_: ChallengeFiles ): void { setSolutionToView(id); setSolutionOpen(true); - setSolution(solution_); + setSolution(solution_ ?? ''); setChallengeFiles(challengeFiles_); } @@ -115,8 +98,8 @@ function TimelineInner({ function renderViewButton( id: string, challengeFiles: ChallengeFiles, - githubLink: string, - solution: string + githubLink?: string, + solution?: string | null ): React.ReactNode { if (challengeFiles?.length) { return ( @@ -159,7 +142,7 @@ function TimelineInner({ ); - } else if (maybeUrlRE.test(solution)) { + } else if (solution && maybeUrlRE.test(solution)) { return (