Skip to content

Commit 9a83d67

Browse files
refactor: Enable TypeScript support in this repo (#1459)
1 parent 356b183 commit 9a83d67

File tree

84 files changed

+213
-134
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

84 files changed

+213
-134
lines changed

Makefile

+1
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ validate:
5555
make validate-no-uncommitted-package-lock-changes
5656
npm run i18n_extract
5757
npm run lint -- --max-warnings 0
58+
npm run types
5859
npm run test
5960
npm run build
6061
npm run bundlewatch

package.json

+4-3
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,15 @@
1313
"build": "fedx-scripts webpack",
1414
"bundlewatch": "bundlewatch",
1515
"i18n_extract": "fedx-scripts formatjs extract",
16-
"lint": "fedx-scripts eslint --ext .js --ext .jsx .",
17-
"lint:fix": "fedx-scripts eslint --fix --ext .js --ext .jsx .",
16+
"lint": "fedx-scripts eslint --ext .js --ext .jsx --ext .ts --ext .tsx .",
17+
"lint:fix": "fedx-scripts eslint --fix --ext .js --ext .jsx --ext .ts --ext .tsx .",
1818
"prepare": "husky install",
1919
"postinstall": "patch-package",
2020
"snapshot": "fedx-scripts jest --updateSnapshot",
2121
"start": "fedx-scripts webpack-dev-server --progress",
2222
"dev": "PUBLIC_PATH=/learning/ MFE_CONFIG_API_URL='http://localhost:8000/api/mfe_config/v1' fedx-scripts webpack-dev-server --progress --host apps.local.openedx.io",
23-
"test": "fedx-scripts jest --coverage --passWithNoTests"
23+
"test": "fedx-scripts jest --coverage --passWithNoTests",
24+
"types": "tsc --noEmit"
2425
},
2526
"author": "edX",
2627
"license": "AGPL-3.0",

src/constants.js renamed to src/constants.ts

+6-5
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ export const DECODE_ROUTES = {
1616
],
1717
REDIRECT_HOME: 'home/:courseId',
1818
REDIRECT_SURVEY: 'survey/:courseId',
19-
};
19+
} as const satisfies Readonly<{ [k: string]: string | readonly string[] }>;
2020

2121
export const ROUTES = {
2222
UNSUBSCRIBE: '/goal-unsubscribe/:token',
@@ -25,15 +25,15 @@ export const ROUTES = {
2525
DASHBOARD: 'dashboard',
2626
ENTERPRISE_LEARNER_DASHBOARD: 'enterprise-learner-dashboard',
2727
CONSENT: 'consent',
28-
};
28+
} as const satisfies Readonly<{ [k: string]: string }>;
2929

3030
export const REDIRECT_MODES = {
3131
DASHBOARD_REDIRECT: 'dashboard-redirect',
3232
ENTERPRISE_LEARNER_DASHBOARD_REDIRECT: 'enterprise-learner-dashboard-redirect',
3333
CONSENT_REDIRECT: 'consent-redirect',
3434
HOME_REDIRECT: 'home-redirect',
3535
SURVEY_REDIRECT: 'survey-redirect',
36-
};
36+
} as const satisfies Readonly<{ [k: string]: string }>;
3737

3838
export const VERIFIED_MODES = [
3939
'professional',
@@ -44,14 +44,15 @@ export const VERIFIED_MODES = [
4444
'executive-education',
4545
'paid-executive-education',
4646
'paid-bootcamp',
47-
];
47+
] as const satisfies readonly string[];
4848

4949
export const WIDGETS = {
5050
DISCUSSIONS: 'DISCUSSIONS',
5151
NOTIFICATIONS: 'NOTIFICATIONS',
52-
};
52+
} as const satisfies Readonly<{ [k: string]: string }>;
5353

5454
export const LOADING = 'loading';
5555
export const LOADED = 'loaded';
5656
export const FAILED = 'failed';
5757
export const DENIED = 'denied';
58+
export type StatusValue = typeof LOADING | typeof LOADED | typeof FAILED | typeof DENIED;

src/course-home/data/slice.js

+6-4
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
/* eslint-disable no-param-reassign */
22
import { createSlice } from '@reduxjs/toolkit';
33

4-
export const LOADING = 'loading';
5-
export const LOADED = 'loaded';
6-
export const FAILED = 'failed';
7-
export const DENIED = 'denied';
4+
import {
5+
LOADING,
6+
LOADED,
7+
FAILED,
8+
DENIED,
9+
} from '@src/constants';
810

911
const slice = createSlice({
1012
name: 'course-home',
File renamed without changes.

src/courseware/course/course-exit/CourseRecommendations.jsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,9 @@ import {
1212
} from '@openedx/paragon';
1313
import PropTypes from 'prop-types';
1414
import truncate from 'truncate-html';
15+
import { FAILED, LOADED, LOADING } from '@src/constants';
1516
import { useModel } from '../../../generic/model-store';
1617
import fetchCourseRecommendations from './data/thunks';
17-
import { FAILED, LOADED, LOADING } from './data/slice';
1818
import CatalogSuggestion from './CatalogSuggestion';
1919
import PageLoading from '../../../generic/PageLoading';
2020
import { logClick } from './utils';

src/courseware/course/course-exit/data/slice.js

+5-4
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
/* eslint-disable no-param-reassign */
22
import { createSlice } from '@reduxjs/toolkit';
3-
4-
export const LOADING = 'loading';
5-
export const LOADED = 'loaded';
6-
export const FAILED = 'failed';
3+
import {
4+
LOADING,
5+
LOADED,
6+
FAILED,
7+
} from '@src/constants';
78

89
const slice = createSlice({
910
courseId: null,
File renamed without changes.

src/courseware/course/new-sidebar/SidebarContext.js

-5
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import React from 'react';
2+
import type { WIDGETS } from '@src/constants';
3+
import type { SIDEBARS } from './sidebars';
4+
5+
export type SidebarId = keyof typeof SIDEBARS;
6+
export type WidgetId = keyof typeof WIDGETS;
7+
export type UpgradeNotificationState = (
8+
| 'accessLastHour'
9+
| 'accessHoursLeft'
10+
| 'accessDaysLeft'
11+
| 'FPDdaysLeft'
12+
| 'FPDLastHour'
13+
| 'accessDateView'
14+
| 'PastExpirationDate'
15+
);
16+
17+
export interface SidebarContextData {
18+
toggleSidebar: (sidebarId?: SidebarId | null, widgetId?: WidgetId | null) => void;
19+
onNotificationSeen: () => void;
20+
setNotificationStatus: React.Dispatch<'active' | 'inactive'>;
21+
currentSidebar: SidebarId | null;
22+
notificationStatus: 'active' | 'inactive';
23+
upgradeNotificationCurrentState: UpgradeNotificationState;
24+
setUpgradeNotificationCurrentState: React.Dispatch<UpgradeNotificationState>;
25+
shouldDisplaySidebarOpen: boolean;
26+
shouldDisplayFullScreen: boolean;
27+
courseId: string;
28+
unitId: string;
29+
hideDiscussionbar: boolean;
30+
hideNotificationbar: boolean;
31+
isNotificationbarAvailable: boolean;
32+
isDiscussionbarAvailable: boolean;
33+
}
34+
35+
const SidebarContext = React.createContext<SidebarContextData>({} as SidebarContextData);
36+
37+
export default SidebarContext;

src/courseware/course/new-sidebar/SidebarContextProvider.jsx renamed to src/courseware/course/new-sidebar/SidebarContextProvider.tsx

+7-12
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import React, {
22
useCallback, useEffect, useMemo, useState,
33
} from 'react';
4-
import PropTypes from 'prop-types';
54

65
import isEmpty from 'lodash/isEmpty';
76

@@ -13,7 +12,13 @@ import { WIDGETS } from '../../../constants';
1312
import SidebarContext from './SidebarContext';
1413
import { SIDEBARS } from './sidebars';
1514

16-
const SidebarProvider = ({
15+
interface Props {
16+
courseId: string;
17+
unitId: string;
18+
children?: React.ReactNode;
19+
}
20+
21+
const SidebarProvider: React.FC<Props> = ({
1722
courseId,
1823
unitId,
1924
children,
@@ -122,14 +127,4 @@ const SidebarProvider = ({
122127
);
123128
};
124129

125-
SidebarProvider.propTypes = {
126-
courseId: PropTypes.string.isRequired,
127-
unitId: PropTypes.string.isRequired,
128-
children: PropTypes.node,
129-
};
130-
131-
SidebarProvider.defaultProps = {
132-
children: null,
133-
};
134-
135130
export default SidebarProvider;

src/courseware/course/new-sidebar/common/SidebarBase.jsx renamed to src/courseware/course/new-sidebar/common/SidebarBase.tsx

+20-31
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import React, { useCallback, useContext } from 'react';
2-
import PropTypes from 'prop-types';
32

43
import classNames from 'classnames';
54

@@ -10,18 +9,30 @@ import { ArrowBackIos, Close } from '@openedx/paragon/icons';
109
import { useEventListener } from '../../../../generic/hooks';
1110
import { WIDGETS } from '../../../../constants';
1211
import messages from '../messages';
13-
import SidebarContext from '../SidebarContext';
12+
import SidebarContext, { type SidebarId } from '../SidebarContext';
1413

15-
const SidebarBase = ({
16-
title,
14+
interface Props {
15+
title?: string;
16+
ariaLabel: string;
17+
sidebarId: SidebarId;
18+
className?: string;
19+
children: React.ReactNode;
20+
showTitleBar?: boolean;
21+
width?: string;
22+
allowFullHeight?: boolean;
23+
showBorder?: boolean;
24+
}
25+
26+
const SidebarBase: React.FC<Props> = ({
27+
title = '',
1728
ariaLabel,
1829
sidebarId,
1930
className,
2031
children,
21-
showTitleBar,
22-
width,
23-
allowFullHeight,
24-
showBorder,
32+
showTitleBar = true,
33+
width = '45rem',
34+
allowFullHeight = false,
35+
showBorder = true,
2536
}) => {
2637
const intl = useIntl();
2738
const {
@@ -58,8 +69,7 @@ const SidebarBase = ({
5869
onClick={() => toggleSidebar(null)}
5970
onKeyDown={() => toggleSidebar(null)}
6071
role="button"
61-
tabIndex="0"
62-
alt={intl.formatMessage(messages.responsiveCloseSidebarTray)}
72+
tabIndex={0}
6373
>
6474
<Icon src={ArrowBackIos} />
6575
<span className="font-weight-bold m-2 d-inline-block">
@@ -90,25 +100,4 @@ const SidebarBase = ({
90100
);
91101
};
92102

93-
SidebarBase.propTypes = {
94-
title: PropTypes.string,
95-
ariaLabel: PropTypes.string.isRequired,
96-
sidebarId: PropTypes.string.isRequired,
97-
className: PropTypes.string,
98-
children: PropTypes.element.isRequired,
99-
showTitleBar: PropTypes.bool,
100-
width: PropTypes.string,
101-
allowFullHeight: PropTypes.bool,
102-
showBorder: PropTypes.bool,
103-
};
104-
105-
SidebarBase.defaultProps = {
106-
title: '',
107-
width: '45rem',
108-
allowFullHeight: false,
109-
showTitleBar: true,
110-
className: '',
111-
showBorder: true,
112-
};
113-
114103
export default SidebarBase;

src/courseware/course/new-sidebar/icons/RightSidebarFilled.jsx renamed to src/courseware/course/new-sidebar/icons/RightSidebarFilled.tsx

-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
import * as React from 'react';
2-
31
const RightSidebarFilled = (props) => (
42
<svg
53
width={24}

src/courseware/course/new-sidebar/icons/RightSidebarOutlined.jsx renamed to src/courseware/course/new-sidebar/icons/RightSidebarOutlined.tsx

-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
import * as React from 'react';
2-
31
const RightSidebarOutlined = (props) => (
42
<svg
53
width={24}
+1-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ describe('DiscussionsWidget', () => {
3131
excludeFetchSequence: false,
3232
});
3333
axiosMock = new MockAdapter(getAuthenticatedHttpClient());
34-
const state = store.getState();
34+
const state = store.getState() as any; // TODO: remove 'any' once redux state gets types
3535
courseId = state.courseware.courseId;
3636
[unitId] = Object.keys(state.models.units);
3737

0 commit comments

Comments
 (0)