Skip to content

Commit 1738b1f

Browse files
chore(client): fix several type errors (freeCodeCamp#58500)
1 parent acfabb6 commit 1738b1f

File tree

20 files changed

+147
-99
lines changed

20 files changed

+147
-99
lines changed

client/src/components/Header/components/auth-or-profile.tsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
11
import React from 'react';
22
import { useTranslation } from 'react-i18next';
3-
import type { User } from '../../../redux/prop-types';
43
import { Link, AvatarRenderer } from '../../helpers';
54
import Login from './login';
65

76
interface AuthOrProfileProps {
8-
user?: User;
7+
user?: {
8+
isDonating: boolean;
9+
username: string;
10+
picture: string;
11+
yearsTopContributor: string[];
12+
};
913
}
1014
const AuthOrProfile = ({ user }: AuthOrProfileProps): JSX.Element => {
1115
const { t } = useTranslation();

client/src/components/Header/components/menu-button.tsx

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,13 @@ import React, { RefObject } from 'react';
22
import { useTranslation } from 'react-i18next';
33
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
44
import { faBars } from '@fortawesome/free-solid-svg-icons';
5-
import { User } from '../../../redux/prop-types';
65

76
interface MenuButtonProps {
87
className?: string;
98
displayMenu?: boolean;
109
innerRef?: RefObject<HTMLButtonElement>;
1110
showMenu: () => void;
1211
hideMenu: () => void;
13-
user?: User;
1412
}
1513

1614
const MenuButton = ({

client/src/components/Header/components/nav-links.tsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,13 @@ import { openSignoutModal, toggleTheme } from '../../../redux/actions';
1313
import { Link } from '../../helpers';
1414
import { LocalStorageThemes } from '../../../redux/types';
1515
import { themeSelector } from '../../../redux/selectors';
16-
import { User } from '../../../redux/prop-types';
1716
import SupporterBadge from '../../../assets/icons/supporter-badge';
1817

1918
export interface NavLinksProps {
2019
displayMenu: boolean;
2120
showMenu: () => void;
2221
hideMenu: () => void;
23-
user?: User;
22+
user?: { isDonating: boolean; username: string };
2423
menuButtonRef: React.RefObject<HTMLButtonElement>;
2524
openSignoutModal: () => void;
2625
theme: LocalStorageThemes;

client/src/components/Header/components/universal-nav.tsx

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { Link, SkeletonSprite } from '../../helpers';
77
import { SEARCH_EXPOSED_WIDTH } from '../../../../config/misc';
88
import FreeCodeCampLogo from '../../../assets/icons/freecodecamp-logo';
99
import MenuButton from './menu-button';
10-
import NavLinks, { type NavLinksProps } from './nav-links';
10+
import NavLinks from './nav-links';
1111
import AuthOrProfile from './auth-or-profile';
1212
import LanguageList from './language-list';
1313

@@ -18,10 +18,17 @@ const SearchBarOptimized = Loadable(
1818
() => import('../../search/searchBar/search-bar-optimized')
1919
);
2020

21-
type UniversalNavProps = Omit<
22-
NavLinksProps,
23-
'toggleTheme' | 'openSignoutModal'
24-
> & {
21+
type UniversalNavProps = {
22+
displayMenu: boolean;
23+
showMenu: () => void;
24+
hideMenu: () => void;
25+
menuButtonRef: React.RefObject<HTMLButtonElement>;
26+
user: {
27+
isDonating: boolean;
28+
username: string;
29+
picture: string;
30+
yearsTopContributor: string[];
31+
};
2532
fetchState: { pending: boolean };
2633
searchBarRef?: React.RefObject<HTMLDivElement>;
2734
pathname: string;
@@ -81,7 +88,6 @@ const UniversalNav = ({
8188
hideMenu={hideMenu}
8289
innerRef={menuButtonRef}
8390
showMenu={showMenu}
84-
user={user}
8591
/>
8692
{!isSearchExposedWidth && search}
8793
<NavLinks
Lines changed: 40 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,92 +1,85 @@
1-
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
2-
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
3-
/* eslint-disable @typescript-eslint/no-unsafe-return */
4-
51
import React from 'react';
62
import { create, ReactTestRendererJSON } from 'react-test-renderer';
73
import AuthOrProfile from './components/auth-or-profile';
84

5+
const defaultUserProps = {
6+
user: {
7+
username: 'test-user',
8+
picture: 'https://freecodecamp.org/image.png',
9+
isDonating: false,
10+
yearsTopContributor: []
11+
},
12+
pending: false,
13+
pathName: '/learn'
14+
};
15+
16+
const donatingUserProps = {
17+
...defaultUserProps,
18+
user: {
19+
...defaultUserProps.user,
20+
isDonating: true
21+
}
22+
};
23+
24+
const topContributorUserProps = {
25+
...defaultUserProps,
26+
user: {
27+
...defaultUserProps.user,
28+
yearsTopContributor: ['2020']
29+
}
30+
};
31+
32+
const topDonatingContributorUserProps = {
33+
...topContributorUserProps,
34+
user: {
35+
...topContributorUserProps.user,
36+
isDonating: true
37+
}
38+
};
39+
940
jest.mock('../../analytics');
1041

1142
describe('<AuthOrProfile />', () => {
1243
it('has avatar with default border for default users', () => {
13-
const defaultUserProps = {
14-
user: {
15-
username: 'test-user',
16-
picture: 'https://freecodecamp.org/image.png'
17-
},
18-
pending: false,
19-
pathName: '/learn'
20-
};
21-
2244
const componentTree = create(
2345
<AuthOrProfile {...defaultUserProps} />
2446
).toJSON();
2547
expect(avatarHasClass(componentTree, 'default-border')).toBeTruthy();
2648
});
2749

2850
it('has avatar with gold border for donating users', () => {
29-
const donatingUserProps = {
30-
user: {
31-
username: 'test-user',
32-
picture: 'https://freecodecamp.org/image.png',
33-
isDonating: true
34-
},
35-
pending: false,
36-
pathName: '/learn'
37-
};
38-
3951
const componentTree = create(
4052
<AuthOrProfile {...donatingUserProps} />
4153
).toJSON();
4254
expect(avatarHasClass(componentTree, 'gold-border')).toBeTruthy();
4355
});
4456

4557
it('has avatar with blue border for top contributors', () => {
46-
const topContributorUserProps = {
47-
user: {
48-
username: 'test-user',
49-
picture: 'https://freecodecamp.org/image.png',
50-
yearsTopContributor: [2020]
51-
},
52-
pending: false,
53-
pathName: '/learn'
54-
};
55-
5658
const componentTree = create(
5759
<AuthOrProfile {...topContributorUserProps} />
5860
).toJSON();
5961
expect(avatarHasClass(componentTree, 'blue-border')).toBeTruthy();
6062
});
6163

6264
it('has avatar with purple border for donating top contributors', () => {
63-
const topDonatingContributorUserProps = {
64-
user: {
65-
username: 'test-user',
66-
picture: 'https://freecodecamp.org/image.png',
67-
isDonating: true,
68-
yearsTopContributor: [2020]
69-
},
70-
pending: false,
71-
pathName: '/learn'
72-
};
73-
7465
const componentTree = create(
7566
<AuthOrProfile {...topDonatingContributorUserProps} />
7667
).toJSON();
7768
expect(avatarHasClass(componentTree, 'purple-border')).toBeTruthy();
7869
});
7970
});
8071

81-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
82-
const profileNavItem = (component: any) => component.children[0];
72+
type Component = {
73+
children: { props: { className: string } }[];
74+
};
75+
const profileNavItem = (component: Component) => component.children[0];
8376

8477
const avatarHasClass = (
8578
componentTree: ReactTestRendererJSON | ReactTestRendererJSON[] | null,
8679
classes: string
8780
) => {
8881
return (
89-
profileNavItem(componentTree).props.className ===
82+
profileNavItem(componentTree as unknown as Component).props.className ===
9083
'avatar-container ' + classes
9184
);
9285
};

client/src/components/Header/index.tsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
import React from 'react';
66
import { ConnectedProps, connect } from 'react-redux';
77
import { createSelector } from 'reselect';
8-
import { User } from '../../redux/prop-types';
98
import { examInProgressSelector } from '../../redux/selectors';
109

1110
import UniversalNav from './components/universal-nav';
@@ -26,7 +25,12 @@ type PropsFromRedux = ConnectedProps<typeof connector>;
2625

2726
type Props = PropsFromRedux & {
2827
fetchState: { pending: boolean };
29-
user: User;
28+
user: {
29+
isDonating: boolean;
30+
username: string;
31+
picture: string;
32+
yearsTopContributor: string[];
33+
};
3034
skipButtonText: string;
3135
pathname: string;
3236
};

client/src/components/Map/index.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,6 @@ const superBlockHeadings: { [key in SuperBlockStage]: string } = {
5757
[SuperBlockStage.Professional]: 'landing.professional-certs-heading',
5858
[SuperBlockStage.Extra]: 'landing.interview-prep-heading',
5959
[SuperBlockStage.Legacy]: 'landing.legacy-curriculum-heading',
60-
[SuperBlockStage.New]: '', // TODO: add translation
6160
[SuperBlockStage.Next]: 'landing.next-heading',
6261
[SuperBlockStage.NextEnglish]: 'landing.next-english-heading',
6362
[SuperBlockStage.Upcoming]: 'landing.upcoming-heading'

client/src/components/profile/components/portfolio.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,10 @@ class PortfolioSettings extends Component<PortfolioProps, PortfolioState> {
202202
});
203203
}
204204

205-
getUrlValidation(url: string) {
205+
getUrlValidation(url: string): {
206+
state: 'success' | 'warning' | 'error';
207+
message: string;
208+
} {
206209
const { t } = this.props;
207210
const len = url.length;
208211

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
export { parseDate, formatYears } from './utils';
1+
export { parseDate } from './utils';

client/src/components/profile/profile.test.tsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,13 +90,19 @@ function renderWithRedux(ui: JSX.Element) {
9090
}
9191
describe('<Profile/>', () => {
9292
it('renders the report button on another persons profile', () => {
93+
// TODO: Profile is a mess, it shouldn't depend on the entire user. Each
94+
// component Camper, Stats, HeatMap etc should be get the relevant data from
95+
// the store themselves.
96+
97+
// @ts-expect-error - quick hack to mollify TS.
9398
renderWithRedux(<Profile {...notMyProfileProps} />);
9499

95100
const reportButton: HTMLElement = screen.getByText('buttons.flag-user');
96101
expect(reportButton).toHaveAttribute('href', '/user/string/report-user');
97102
});
98103

99104
it('renders correctly', () => {
105+
// @ts-expect-error - quick hack to mollify TS.
100106
const { container } = renderWithRedux(<Profile {...notMyProfileProps} />);
101107

102108
expect(container).toMatchSnapshot();

client/src/components/settings/delete-modal.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ function DeleteModal(props: DeleteModalProps): JSX.Element {
6868
/>
6969
</FormGroup>
7070
<Spacer size='xs' />
71+
{/* @ts-expect-error The UI lib's types don't allow this: https://github.com/freeCodeCamp/ui/issues/473 */}
7172
<Button
7273
block={true}
7374
size='large'

client/src/components/settings/reset-modal.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ function ResetModal(props: ResetModalProps): JSX.Element {
6666
/>
6767
</FormGroup>
6868
<Spacer size='xs' />
69+
{/* @ts-expect-error freecodecamp/ui doesn't allow disable to be false: https://github.com/freeCodeCamp/ui/issues/473 */}
6970
<Button
7071
block={true}
7172
size='large'

client/src/redux/prop-types.ts

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -152,21 +152,6 @@ export interface PrerequisiteChallenge {
152152
slug?: string;
153153
}
154154

155-
export type ExtendedChallenge = {
156-
block: string;
157-
challengeType: number;
158-
dashedName: string;
159-
fields: {
160-
slug: string;
161-
};
162-
id: string;
163-
isCompleted: boolean;
164-
order: number;
165-
superBlock: SuperBlocks;
166-
stepNumber: number;
167-
title: string;
168-
};
169-
170155
export type ChallengeNode = {
171156
challenge: {
172157
block: string;

0 commit comments

Comments
 (0)