diff --git a/.eslintrc.json b/.eslintrc.json index 8c2331ab88..727fd51ac7 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -2,6 +2,22 @@ "extends": ["react-app", "plugin:@typescript-eslint/recommended"], "plugins": ["simple-import-sort"], "rules": { + "no-restricted-imports": [ + "error", + { + "paths": [ + { + "name": "react-redux", + "importNames": [ + // TODO: Create typed hook for useDispatch + // "useDispatch", + "useSelector" + ], + "message": "Use the typed hook \"useTypedSelector\" instead." + } + ] + } + ], "@typescript-eslint/no-empty-function": "off", "@typescript-eslint/interface-name-prefix": "off", "@typescript-eslint/camelcase": "off", @@ -11,7 +27,19 @@ "@typescript-eslint/no-explicit-any": "off", "@typescript-eslint/explicit-module-boundary-types": "off", "@typescript-eslint/ban-ts-comment": "warn", - "@typescript-eslint/ban-types": "off", + "@typescript-eslint/ban-types": [ + "error", + { + // TODO: Change this to true someday + "extendDefaults": false, + "types": { + "React.FunctionComponent": { + "message": "Use React.FC instead", + "fixWith": "React.FC" + } + } + } + ], "simple-import-sort/imports": "error" } } diff --git a/src/assets/PortSvg.tsx b/src/assets/PortSvg.tsx index faeecd00f0..bdaf749c70 100644 --- a/src/assets/PortSvg.tsx +++ b/src/assets/PortSvg.tsx @@ -1,8 +1,10 @@ +import React from 'react'; + type Props = { port: string; }; -const PortSvg = ({ port }: Props) => ( +const PortSvg: React.FC = ({ port }) => ( void; - options?: Partial; - isDisabled?: boolean; -}; - const defaultOptions = { className: '', fullWidth: false, @@ -27,7 +19,15 @@ const defaultOptions = { minimal: true }; -const ControlButton: React.FC = ({ +type Props = { + label?: string; + icon?: IconName; + onClick?: () => void; + options?: Partial; + isDisabled?: boolean; +}; + +const ControlButton: React.FC = ({ label = '', icon, onClick, diff --git a/src/commons/Markdown.tsx b/src/commons/Markdown.tsx index b19821f5ed..ea324f00a6 100644 --- a/src/commons/Markdown.tsx +++ b/src/commons/Markdown.tsx @@ -3,7 +3,7 @@ import classNames from 'classnames'; import React from 'react'; import { Converter } from 'showdown'; -type MarkdownProps = { +type Props = { className?: string; content: string; openLinksInNewWindow?: boolean; @@ -12,7 +12,7 @@ type MarkdownProps = { tasklists?: boolean; }; -const Markdown: React.FC = props => { +const Markdown: React.FC = props => { const converter = new Converter({ tables: true, simplifiedAutoLink: props.simplifiedAutoLink, diff --git a/src/commons/SimpleDropdown.tsx b/src/commons/SimpleDropdown.tsx index c68c9872fd..6aca5c2668 100644 --- a/src/commons/SimpleDropdown.tsx +++ b/src/commons/SimpleDropdown.tsx @@ -10,9 +10,13 @@ type Props = { popoverProps?: Partial>; }; -function SimpleDropdown(props: Props) { - const { options, selectedValue, onClick, buttonProps, popoverProps } = props; - +const SimpleDropdown = ({ + options, + selectedValue, + onClick, + buttonProps, + popoverProps +}: Props) => { const handleClick = (value: T['value']) => { onClick?.(value); }; @@ -37,6 +41,6 @@ function SimpleDropdown(props: Props) { ); -} +}; export default SimpleDropdown; diff --git a/src/commons/__tests__/ContentDisplay.tsx b/src/commons/__tests__/ContentDisplay.tsx index 307367c118..bf3138083c 100644 --- a/src/commons/__tests__/ContentDisplay.tsx +++ b/src/commons/__tests__/ContentDisplay.tsx @@ -2,8 +2,7 @@ import ContentDisplay, { ContentDisplayProps } from '../ContentDisplay'; import { renderTreeJson } from '../utils/TestUtils'; const mockProps: ContentDisplayProps = { - display:
Test Content
, - loadContentDispatch: () => {} + display:
Test Content
}; test('ContentDisplay page renders correctly', () => { diff --git a/src/commons/achievement/AchievementCard.tsx b/src/commons/achievement/AchievementCard.tsx index bf68d6adec..7db9ddc9b2 100644 --- a/src/commons/achievement/AchievementCard.tsx +++ b/src/commons/achievement/AchievementCard.tsx @@ -7,7 +7,7 @@ import { AchievementStatus } from '../../features/achievement/AchievementTypes'; import AchievementDeadline from './card/AchievementDeadline'; import AchievementXp from './card/AchievementXp'; -type AchievementCardProps = { +type Props = { uuid: string; focusState: [string, any]; isDropdownOpen?: boolean; @@ -15,9 +15,13 @@ type AchievementCardProps = { toggleDropdown?: () => void; }; -const AchievementCard: React.FC = props => { - const { uuid, focusState, isDropdownOpen, shouldRender, toggleDropdown } = props; - +const AchievementCard: React.FC = ({ + uuid, + focusState, + isDropdownOpen, + shouldRender, + toggleDropdown +}) => { const inferencer = useContext(AchievementContext); const [focusUuid, setFocusUuid] = focusState; diff --git a/src/commons/achievement/AchievementCommentCard.tsx b/src/commons/achievement/AchievementCommentCard.tsx index ae259c2650..42255758a9 100644 --- a/src/commons/achievement/AchievementCommentCard.tsx +++ b/src/commons/achievement/AchievementCommentCard.tsx @@ -7,10 +7,12 @@ import { useTypedSelector } from '../utils/Hooks'; import { showWarningMessage } from '../utils/notifications/NotificationsHelper'; import { assessmentTypeLink } from '../utils/ParamParseHelper'; -const AchievementCommentCard: React.FC<{ +type Props = { assessment: Assessment; showToQuestion: boolean; -}> = ({ assessment, showToQuestion }) => { +}; + +const AchievementCommentCard: React.FC = ({ assessment, showToQuestion }) => { const navigate = useNavigate(); const courseId = useTypedSelector(store => store.session.courseId); const toMission = useMemo( diff --git a/src/commons/achievement/AchievementFilter.tsx b/src/commons/achievement/AchievementFilter.tsx index d63dabcc95..47c34718a0 100644 --- a/src/commons/achievement/AchievementFilter.tsx +++ b/src/commons/achievement/AchievementFilter.tsx @@ -4,13 +4,13 @@ import React from 'react'; import { getFilterColor } from '../../features/achievement/AchievementConstants'; import { FilterStatus } from '../../features/achievement/AchievementTypes'; -type AchievementFilterProps = { +type Props = { filterState: [FilterStatus, any]; icon: IconName; ownStatus: FilterStatus; }; -const AchievementFilter: React.FC = ({ filterState, icon, ownStatus }) => { +const AchievementFilter: React.FC = ({ filterState, icon, ownStatus }) => { const [globalStatus, setGlobalStatus] = filterState; return ( diff --git a/src/commons/achievement/AchievementManualEditor.tsx b/src/commons/achievement/AchievementManualEditor.tsx index 859eee93bb..456f1956b9 100644 --- a/src/commons/achievement/AchievementManualEditor.tsx +++ b/src/commons/achievement/AchievementManualEditor.tsx @@ -10,15 +10,6 @@ import { import { showSuccessMessage, showWarningMessage } from '../utils/notifications/NotificationsHelper'; -type AchievementManualEditorProps = { - hiddenState: [boolean, any]; - userState: [AchievementUser | undefined, any]; - studio: string; - users: AchievementUser[]; - getUsers: () => void; - updateGoalProgress: (studentCourseRegId: number, progress: GoalProgress) => void; -}; - const GoalSelect = Select.ofType(); const goalRenderer: ItemRenderer = (goal, { handleClick }) => ( @@ -40,7 +31,16 @@ export function updateGoalProcessed() { showSuccessMessage('Goal updated'); } -const AchievementManualEditor: React.FC = props => { +type Props = { + hiddenState: [boolean, any]; + userState: [AchievementUser | undefined, any]; + studio: string; + users: AchievementUser[]; + getUsers: () => void; + updateGoalProgress: (studentCourseRegId: number, progress: GoalProgress) => void; +}; + +const AchievementManualEditor: React.FC = props => { const { userState, hiddenState, studio, getUsers, updateGoalProgress } = props; const users = studio === 'Staff' @@ -75,7 +75,7 @@ const AchievementManualEditor: React.FC = props => const [goal, changeGoal] = useState(undefined); const [selectedUser, changeSelectedUser] = userState; - const [count, changeCount] = useState(0); + const [count, changeCount] = useState(0); const [viewHidden, changeViewHidden] = hiddenState; const updateGoal = () => { diff --git a/src/commons/achievement/AchievementOverview.tsx b/src/commons/achievement/AchievementOverview.tsx index f535043ef5..0bcbee3b35 100644 --- a/src/commons/achievement/AchievementOverview.tsx +++ b/src/commons/achievement/AchievementOverview.tsx @@ -6,12 +6,12 @@ import { FETCH_TOTAL_XP, FETCH_TOTAL_XP_ADMIN } from '../application/types/Sessi import { useTypedSelector } from '../utils/Hooks'; import AchievementLevel from './overview/AchievementLevel'; -type AchievementOverviewProps = { +type Props = { name: string; userState: [AchievementUser | undefined, any]; }; -const AchievementOverview: React.FC = ({ name, userState }) => { +const AchievementOverview: React.FC = ({ name, userState }) => { const [selectedUser] = userState; const crid = selectedUser?.courseRegId; const userCrid = useTypedSelector(store => store.session.courseRegId); diff --git a/src/commons/achievement/AchievementTask.tsx b/src/commons/achievement/AchievementTask.tsx index ef339823ce..6b23aeaae5 100644 --- a/src/commons/achievement/AchievementTask.tsx +++ b/src/commons/achievement/AchievementTask.tsx @@ -8,18 +8,18 @@ import { import { AchievementStatus, FilterStatus } from '../../features/achievement/AchievementTypes'; import AchievementCard from './AchievementCard'; -type AchievementTaskProps = { +type Props = { uuid: string; filterStatus: FilterStatus; focusState: [string, any]; }; -const AchievementTask: React.FC = ({ uuid, filterStatus, focusState }) => { +const AchievementTask: React.FC = ({ uuid, filterStatus, focusState }) => { const inferencer = useContext(AchievementContext); const prerequisiteUuids = [...inferencer.getImmediateChildren(uuid)]; const taskColor = getAbilityColor(); - const [isDropdownOpen, setIsDropdownOpen] = useState(false); + const [isDropdownOpen, setIsDropdownOpen] = useState(false); const toggleDropdown = () => setIsDropdownOpen(!isDropdownOpen); /** diff --git a/src/commons/achievement/AchievementView.tsx b/src/commons/achievement/AchievementView.tsx index 7ed9361097..01ef0864bf 100644 --- a/src/commons/achievement/AchievementView.tsx +++ b/src/commons/achievement/AchievementView.tsx @@ -17,13 +17,13 @@ import { prettifyDate } from './utils/DateHelper'; import AchievementViewCompletion from './view/AchievementViewCompletion'; import AchievementViewGoal from './view/AchievementViewGoal'; -type AchievementViewProps = { +type Props = { focusUuid: string; assessments?: Map; userState?: [AchievementUser | undefined, any]; }; -const AchievementView: React.FC = ({ focusUuid, userState }) => { +const AchievementView: React.FC = ({ focusUuid, userState }) => { const assessmentId = !Number.isNaN(+focusUuid) && +focusUuid !== 0 ? +focusUuid : undefined; let courseRegId: number | undefined; diff --git a/src/commons/achievement/card/AchievementDeadline.tsx b/src/commons/achievement/card/AchievementDeadline.tsx index d1f313bb03..6ebf56a22c 100644 --- a/src/commons/achievement/card/AchievementDeadline.tsx +++ b/src/commons/achievement/card/AchievementDeadline.tsx @@ -5,13 +5,13 @@ import React from 'react'; import { DeadlineColors } from '../../../features/achievement/AchievementConstants'; import { isExpired, prettifyDeadline, timeFromExpired } from '../utils/DateHelper'; -type AchievementDeadlineProps = { +const twoDays = new Date(0, 0, 2).getTime() - new Date(0, 0, 0).getTime(); + +type Props = { deadline?: Date; }; -const twoDays = new Date(0, 0, 2).getTime() - new Date(0, 0, 0).getTime(); - -const AchievementDeadline: React.FC = ({ deadline }) => { +const AchievementDeadline: React.FC = ({ deadline }) => { // red deadline color for core achievements that are expiring in less than 2 days const deadlineColor = deadline !== undefined && !isExpired(deadline) && timeFromExpired(deadline) <= twoDays diff --git a/src/commons/achievement/card/AchievementXp.tsx b/src/commons/achievement/card/AchievementXp.tsx index 46db34b621..18338e8e32 100644 --- a/src/commons/achievement/card/AchievementXp.tsx +++ b/src/commons/achievement/card/AchievementXp.tsx @@ -2,16 +2,16 @@ import { Icon } from '@blueprintjs/core'; import { IconNames } from '@blueprintjs/icons'; import React from 'react'; -type AchievementXpProps = { - isBonus: boolean; - xp: number; -}; - const stringifyXp = (xp: number, isBonus: boolean) => { return (isBonus ? 'Total ' : '') + xp + ' XP'; }; -const AchievementXp: React.FC = ({ isBonus, xp }) => { +type Props = { + isBonus: boolean; + xp: number; +}; + +const AchievementXp: React.FC = ({ isBonus, xp }) => { return (
{xp !== 0 && ( diff --git a/src/commons/achievement/control/AchievementEditor.tsx b/src/commons/achievement/control/AchievementEditor.tsx index 4f477138be..9388ff6972 100644 --- a/src/commons/achievement/control/AchievementEditor.tsx +++ b/src/commons/achievement/control/AchievementEditor.tsx @@ -4,13 +4,13 @@ import { AchievementContext } from 'src/features/achievement/AchievementConstant import AchievementAdder from './achievementEditor/AchievementAdder'; import EditableCard from './achievementEditor/EditableCard'; -type AchievementEditorProps = { +let editableCards: JSX.Element[] = []; + +type Props = { requestPublish: () => void; }; -let editableCards: JSX.Element[] = []; - -const AchievementEditor: React.FC = ({ requestPublish }) => { +const AchievementEditor: React.FC = ({ requestPublish }) => { const inferencer = useContext(AchievementContext); /** @@ -24,7 +24,7 @@ const AchievementEditor: React.FC = ({ requestPublish }) * at one go. The newUuid holds the newly created achievement uuid until the new achievement * is added into the inferencer. */ - const [newUuid, setNewUuid] = useState(''); + const [newUuid, setNewUuid] = useState(''); const allowNewUuid = newUuid === ''; const releaseUuid = () => setNewUuid(''); diff --git a/src/commons/achievement/control/AchievementPreview.tsx b/src/commons/achievement/control/AchievementPreview.tsx index 62e5ca019b..1e3c9023f3 100644 --- a/src/commons/achievement/control/AchievementPreview.tsx +++ b/src/commons/achievement/control/AchievementPreview.tsx @@ -7,15 +7,12 @@ import { generateAchievementTasks } from 'src/pages/achievement/subcomponents/Ac import AchievementView from '../AchievementView'; -type AchievementPreviewProps = { +type Props = { awaitPublish: boolean; publishChanges: () => void; }; -const AchievementPreview: React.FC = ({ - awaitPublish, - publishChanges -}) => { +const AchievementPreview: React.FC = ({ awaitPublish, publishChanges }) => { const inferencer = useContext(AchievementContext); // Show AchievementView when viewMode is true, otherwise show AchievementTask @@ -25,7 +22,7 @@ const AchievementPreview: React.FC = ({ * Marks the achievement uuid that is currently on focus (selected) * If an achievement is focused, the cards glow and dashboard displays the AchievementView */ - const focusState = useState(''); + const focusState = useState(''); const [focusUuid] = focusState; return ( diff --git a/src/commons/achievement/control/GoalEditor.tsx b/src/commons/achievement/control/GoalEditor.tsx index 3e8703741a..9d0a40ef25 100644 --- a/src/commons/achievement/control/GoalEditor.tsx +++ b/src/commons/achievement/control/GoalEditor.tsx @@ -4,13 +4,13 @@ import { AchievementContext } from 'src/features/achievement/AchievementConstant import EditableGoal from './goalEditor/EditableGoal'; import GoalAdder from './goalEditor/GoalAdder'; -type GoalEditorProps = { +let editableGoals: JSX.Element[] = []; + +type Props = { requestPublish: () => void; }; -let editableGoals: JSX.Element[] = []; - -const GoalEditor: React.FC = ({ requestPublish }) => { +const GoalEditor: React.FC = ({ requestPublish }) => { const inferencer = useContext(AchievementContext); /** @@ -24,7 +24,7 @@ const GoalEditor: React.FC = ({ requestPublish }) => { * at one go. The newUuid holds the newly created goal uuid until the new goal * is added into the inferencer. */ - const [newUuid, setNewUuid] = useState(''); + const [newUuid, setNewUuid] = useState(''); const allowNewUuid = newUuid === ''; const releaseUuid = () => setNewUuid(''); diff --git a/src/commons/achievement/control/achievementEditor/AchievementAdder.tsx b/src/commons/achievement/control/achievementEditor/AchievementAdder.tsx index 45dc7cfc03..eaba2abe2a 100644 --- a/src/commons/achievement/control/achievementEditor/AchievementAdder.tsx +++ b/src/commons/achievement/control/achievementEditor/AchievementAdder.tsx @@ -5,12 +5,12 @@ import { AchievementContext } from 'src/features/achievement/AchievementConstant import { achievementTemplate } from './AchievementTemplate'; -type AchievementAdderProps = { +type Props = { allowNewUuid: boolean; setNewUuid: (uuid: string) => void; }; -const AchievementAdder: React.FC = ({ allowNewUuid, setNewUuid }) => { +const AchievementAdder: React.FC = ({ allowNewUuid, setNewUuid }) => { const inferencer = useContext(AchievementContext); const addAchievement = () => setNewUuid(inferencer.insertAchievement(achievementTemplate)); diff --git a/src/commons/achievement/control/achievementEditor/AchievementSettings.tsx b/src/commons/achievement/control/achievementEditor/AchievementSettings.tsx index cb33ac98ae..cf92a42bba 100644 --- a/src/commons/achievement/control/achievementEditor/AchievementSettings.tsx +++ b/src/commons/achievement/control/achievementEditor/AchievementSettings.tsx @@ -8,7 +8,7 @@ import EditableGoalUuids from './achievementSettings/EditableGoalUuids'; import EditablePosition from './achievementSettings/EditablePosition'; import EditablePrerequisiteUuids from './achievementSettings/EditablePrerequisiteUuids'; -type AchievementSettingsProps = { +type Props = { changeCardBackground: (cardBackground: string) => void; changeGoalUuids: (goalUuids: string[]) => void; changePosition: (position: number) => void; @@ -17,19 +17,18 @@ type AchievementSettingsProps = { editableAchievement: AchievementItem; }; -const AchievementSettings: React.FC = props => { - const { - changeCardBackground, - changeGoalUuids, - changePosition, - changePrerequisiteUuids, - changeIsVariableXp, - editableAchievement - } = props; +const AchievementSettings: React.FC = ({ + changeCardBackground, + changeGoalUuids, + changePosition, + changePrerequisiteUuids, + changeIsVariableXp, + editableAchievement +}) => { const { uuid, cardBackground, goalUuids, position, prerequisiteUuids, isVariableXp } = editableAchievement; - const [isOpen, setOpen] = useState(false); + const [isOpen, setOpen] = useState(false); const toggleOpen = () => setOpen(!isOpen); return ( diff --git a/src/commons/achievement/control/achievementEditor/AchievementUuidCopier.tsx b/src/commons/achievement/control/achievementEditor/AchievementUuidCopier.tsx index 885862936d..ed8e550228 100644 --- a/src/commons/achievement/control/achievementEditor/AchievementUuidCopier.tsx +++ b/src/commons/achievement/control/achievementEditor/AchievementUuidCopier.tsx @@ -4,11 +4,11 @@ import { Tooltip2 } from '@blueprintjs/popover2'; import React from 'react'; import { showSuccessMessage } from 'src/commons/utils/notifications/NotificationsHelper'; -type AchievementUuidCopierProps = { +type Props = { uuid: string; }; -const AchievmenetUuidCopier: React.FC = ({ uuid }) => { +const AchievmenetUuidCopier: React.FC = ({ uuid }) => { const hoverText = 'Click to copy achievement UUID'; const copy = () => { navigator.clipboard.writeText(uuid); diff --git a/src/commons/achievement/control/achievementEditor/EditableCard.tsx b/src/commons/achievement/control/achievementEditor/EditableCard.tsx index 17ceace87e..62c7ff0369 100644 --- a/src/commons/achievement/control/achievementEditor/EditableCard.tsx +++ b/src/commons/achievement/control/achievementEditor/EditableCard.tsx @@ -21,14 +21,6 @@ import { import EditableDate from './EditableDate'; import EditableView from './EditableView'; -type EditableCardProps = { - uuid: string; - isNewAchievement: boolean; - releaseUuid: () => void; - removeCard: (uuid: string) => void; - requestPublish: () => void; -}; - const init = (achievement: AchievementItem): State => { return { editableAchievement: achievement, @@ -136,15 +128,27 @@ const reducer = (state: State, action: Action) => { } }; -const EditableCard: React.FC = props => { - const { uuid, isNewAchievement, releaseUuid, removeCard, requestPublish } = props; +type Props = { + uuid: string; + isNewAchievement: boolean; + releaseUuid: () => void; + removeCard: (uuid: string) => void; + requestPublish: () => void; +}; +const EditableCard: React.FC = ({ + uuid, + isNewAchievement, + releaseUuid, + removeCard, + requestPublish +}) => { const inferencer = useContext(AchievementContext); const achievement = inferencer.getAchievement(uuid); const achievementClone = useMemo(() => cloneDeep(achievement), [achievement]); const [state, dispatch] = useReducer(reducer, achievementClone, init); - const [isNew, setIsNew] = useState(isNewAchievement); + const [isNew, setIsNew] = useState(isNewAchievement); const { editableAchievement, isDirty } = state; const { cardBackground, deadline, release, title, view, xp } = editableAchievement; diff --git a/src/commons/achievement/control/achievementEditor/EditableDate.tsx b/src/commons/achievement/control/achievementEditor/EditableDate.tsx index 33e7929454..751325508d 100644 --- a/src/commons/achievement/control/achievementEditor/EditableDate.tsx +++ b/src/commons/achievement/control/achievementEditor/EditableDate.tsx @@ -4,14 +4,14 @@ import { Tooltip2 } from '@blueprintjs/popover2'; import React, { useState } from 'react'; import { prettifyDate } from 'src/commons/achievement/utils/DateHelper'; -type EditableDateProps = { +type Props = { type: string; date?: Date; changeDate: (date?: Date) => void; }; -const EditableDate: React.FC = ({ type, date, changeDate }) => { - const [isOpen, setOpen] = useState(false); +const EditableDate: React.FC = ({ type, date, changeDate }) => { + const [isOpen, setOpen] = useState(false); const toggleOpen = () => setOpen(!isOpen); const hoverText = date === undefined ? `No ${type}` : `${prettifyDate(date)}`; diff --git a/src/commons/achievement/control/achievementEditor/EditableView.tsx b/src/commons/achievement/control/achievementEditor/EditableView.tsx index 0e8c82d986..cbb1184d1b 100644 --- a/src/commons/achievement/control/achievementEditor/EditableView.tsx +++ b/src/commons/achievement/control/achievementEditor/EditableView.tsx @@ -3,15 +3,16 @@ import { IconNames } from '@blueprintjs/icons'; import { Tooltip2 } from '@blueprintjs/popover2'; import React, { useState } from 'react'; import { AchievementView } from 'src/features/achievement/AchievementTypes'; -type EditableViewProps = { + +type Props = { changeView: (view: AchievementView) => void; view: AchievementView; }; -const EditableView: React.FC = ({ changeView, view }) => { +const EditableView: React.FC = ({ changeView, view }) => { const { coverImage, description, completionText } = view; - const [isOpen, setOpen] = useState(false); + const [isOpen, setOpen] = useState(false); const toggleOpen = () => setOpen(!isOpen); const changeCoverImage = (coverImage: string) => changeView({ ...view, coverImage }); diff --git a/src/commons/achievement/control/achievementEditor/achievementSettings/EditableGoalUuids.tsx b/src/commons/achievement/control/achievementEditor/achievementSettings/EditableGoalUuids.tsx index e074028c16..165d9ebf68 100644 --- a/src/commons/achievement/control/achievementEditor/achievementSettings/EditableGoalUuids.tsx +++ b/src/commons/achievement/control/achievementEditor/achievementSettings/EditableGoalUuids.tsx @@ -5,12 +5,12 @@ import React, { useContext } from 'react'; import { AchievementContext } from 'src/features/achievement/AchievementConstants'; import { AchievementGoal } from 'src/features/achievement/AchievementTypes'; -type EditableGoalUuidsProps = { +type Props = { changeGoalUuids: (goalUuids: string[]) => void; goalUuids: string[]; }; -const EditableGoalUuids: React.FC = ({ changeGoalUuids, goalUuids }) => { +const EditableGoalUuids: React.FC = ({ changeGoalUuids, goalUuids }) => { const inferencer = useContext(AchievementContext); const allGoalUuids = inferencer.getAllGoalUuids(); const selectedUuids = goalUuids.filter( diff --git a/src/commons/achievement/control/achievementEditor/achievementSettings/EditablePosition.tsx b/src/commons/achievement/control/achievementEditor/achievementSettings/EditablePosition.tsx index e52e71a4bf..a540b924a7 100644 --- a/src/commons/achievement/control/achievementEditor/achievementSettings/EditablePosition.tsx +++ b/src/commons/achievement/control/achievementEditor/achievementSettings/EditablePosition.tsx @@ -3,12 +3,12 @@ import { ItemRenderer, Select } from '@blueprintjs/select'; import React, { useContext } from 'react'; import { AchievementContext } from 'src/features/achievement/AchievementConstants'; -type EditablePositionProps = { +type Props = { changePosition: (position: number) => void; position: number; }; -const EditablePosition: React.FC = ({ changePosition, position }) => { +const EditablePosition: React.FC = ({ changePosition, position }) => { const inferencer = useContext(AchievementContext); const maxPosition = inferencer.listTaskUuids().length + 1; const positionOptions = [...Array(maxPosition + 1).keys()]; // [0..maxPosition + 1] diff --git a/src/commons/achievement/control/achievementEditor/achievementSettings/EditablePrerequisiteUuids.tsx b/src/commons/achievement/control/achievementEditor/achievementSettings/EditablePrerequisiteUuids.tsx index b402393f43..13b6691016 100644 --- a/src/commons/achievement/control/achievementEditor/achievementSettings/EditablePrerequisiteUuids.tsx +++ b/src/commons/achievement/control/achievementEditor/achievementSettings/EditablePrerequisiteUuids.tsx @@ -5,15 +5,17 @@ import React, { useContext } from 'react'; import { AchievementContext } from 'src/features/achievement/AchievementConstants'; import { AchievementItem } from 'src/features/achievement/AchievementTypes'; -type EditablePrerequisiteUuidsProps = { +type Props = { changePrerequisiteUuids: (prerequisiteUuids: string[]) => void; uuid: string; prerequisiteUuids: string[]; }; -const EditablePrerequisiteUuids: React.FC = props => { - const { changePrerequisiteUuids, uuid, prerequisiteUuids } = props; - +const EditablePrerequisiteUuids: React.FC = ({ + changePrerequisiteUuids, + uuid, + prerequisiteUuids +}) => { const enablePrerequisites = false; const inferencer = useContext(AchievementContext); diff --git a/src/commons/achievement/control/common/ItemDeleter.tsx b/src/commons/achievement/control/common/ItemDeleter.tsx index 063381a46f..8745815ab9 100644 --- a/src/commons/achievement/control/common/ItemDeleter.tsx +++ b/src/commons/achievement/control/common/ItemDeleter.tsx @@ -4,12 +4,12 @@ import { Tooltip2 } from '@blueprintjs/popover2'; import React from 'react'; import { showSimpleConfirmDialog } from 'src/commons/utils/DialogHelper'; -type ItemDeleterProps = { +type Props = { deleteItem: () => void; item: string; }; -const ItemDeleter: React.FC = ({ deleteItem, item }) => { +const ItemDeleter: React.FC = ({ deleteItem, item }) => { const confirmDelete = async () => { const confirm = await showSimpleConfirmDialog({ contents: `Are you sure you want to delete '${item}' ?`, diff --git a/src/commons/achievement/control/common/ItemSaver.tsx b/src/commons/achievement/control/common/ItemSaver.tsx index 780b9e5220..cdb37181b8 100644 --- a/src/commons/achievement/control/common/ItemSaver.tsx +++ b/src/commons/achievement/control/common/ItemSaver.tsx @@ -7,12 +7,12 @@ import { showWarningMessage } from 'src/commons/utils/notifications/NotificationsHelper'; -type ItemSaverProps = { +type Props = { discardChanges: () => void; saveChanges: () => void; }; -const ItemSaver: React.FC = ({ discardChanges, saveChanges }) => { +const ItemSaver: React.FC = ({ discardChanges, saveChanges }) => { const handleSaveChanges = () => { saveChanges(); showSuccessMessage('Saved changes locally'); diff --git a/src/commons/achievement/control/goalEditor/EditableDate.tsx b/src/commons/achievement/control/goalEditor/EditableDate.tsx index 33e7929454..751325508d 100644 --- a/src/commons/achievement/control/goalEditor/EditableDate.tsx +++ b/src/commons/achievement/control/goalEditor/EditableDate.tsx @@ -4,14 +4,14 @@ import { Tooltip2 } from '@blueprintjs/popover2'; import React, { useState } from 'react'; import { prettifyDate } from 'src/commons/achievement/utils/DateHelper'; -type EditableDateProps = { +type Props = { type: string; date?: Date; changeDate: (date?: Date) => void; }; -const EditableDate: React.FC = ({ type, date, changeDate }) => { - const [isOpen, setOpen] = useState(false); +const EditableDate: React.FC = ({ type, date, changeDate }) => { + const [isOpen, setOpen] = useState(false); const toggleOpen = () => setOpen(!isOpen); const hoverText = date === undefined ? `No ${type}` : `${prettifyDate(date)}`; diff --git a/src/commons/achievement/control/goalEditor/EditableGoal.tsx b/src/commons/achievement/control/goalEditor/EditableGoal.tsx index f3bf9d4eb5..5da4a32df3 100644 --- a/src/commons/achievement/control/goalEditor/EditableGoal.tsx +++ b/src/commons/achievement/control/goalEditor/EditableGoal.tsx @@ -13,14 +13,6 @@ import { } from './EditableGoalTypes'; import EditableMeta from './EditableMeta'; -type EditableGoalProps = { - uuid: string; - isNewGoal: boolean; - releaseUuid: () => void; - removeCard: (uuid: string) => void; - requestPublish: () => void; -}; - const init = (goal: GoalDefinition): State => { return { editableGoal: goal, @@ -63,15 +55,27 @@ const reducer = (state: State, action: Action) => { } }; -const EditableGoal: React.FC = props => { - const { uuid, isNewGoal, releaseUuid, removeCard, requestPublish } = props; +type Props = { + uuid: string; + isNewGoal: boolean; + releaseUuid: () => void; + removeCard: (uuid: string) => void; + requestPublish: () => void; +}; +const EditableGoal: React.FC = ({ + uuid, + isNewGoal, + releaseUuid, + removeCard, + requestPublish +}) => { const inferencer = useContext(AchievementContext); const goal = inferencer.getGoalDefinition(uuid); const goalClone = useMemo(() => cloneDeep(goal), [goal]); const [state, dispatch] = useReducer(reducer, goalClone, init); - const [isNew, setIsNew] = useState(isNewGoal); + const [isNew, setIsNew] = useState(isNewGoal); const { editableGoal, isDirty } = state; const { meta, text } = editableGoal; diff --git a/src/commons/achievement/control/goalEditor/EditableMeta.tsx b/src/commons/achievement/control/goalEditor/EditableMeta.tsx index 2979e9e680..665b2a7b30 100644 --- a/src/commons/achievement/control/goalEditor/EditableMeta.tsx +++ b/src/commons/achievement/control/goalEditor/EditableMeta.tsx @@ -17,12 +17,12 @@ import EditableBinaryMeta from './metaDetails/EditableBinaryMeta'; import EditableEventMeta from './metaDetails/EditableEventMeta'; import EditableManualMeta from './metaDetails/EditableManualMeta'; -type EditableMetaProps = { +type Props = { changeMeta: (meta: GoalMeta) => void; meta: GoalMeta; }; -const EditableMeta: React.FC = ({ changeMeta, meta }) => { +const EditableMeta: React.FC = ({ changeMeta, meta }) => { const { type } = meta; const TypeSelect = Select.ofType(); diff --git a/src/commons/achievement/control/goalEditor/EditableTime.tsx b/src/commons/achievement/control/goalEditor/EditableTime.tsx index 1fb56a694d..36374356f5 100644 --- a/src/commons/achievement/control/goalEditor/EditableTime.tsx +++ b/src/commons/achievement/control/goalEditor/EditableTime.tsx @@ -4,14 +4,14 @@ import { Tooltip2 } from '@blueprintjs/popover2'; import React, { useState } from 'react'; import { prettifyTime } from 'src/commons/achievement/utils/DateHelper'; -type EditableTimeProps = { +type Props = { type: string; time?: Date; changeTime: (time?: Date) => void; }; -const EditableTime: React.FC = ({ type, time, changeTime }) => { - const [isOpen, setOpen] = useState(false); +const EditableTime: React.FC = ({ type, time, changeTime }) => { + const [isOpen, setOpen] = useState(false); const toggleOpen = () => setOpen(!isOpen); const hoverText = time === undefined ? `No ${type}` : `${prettifyTime(time)}`; diff --git a/src/commons/achievement/control/goalEditor/GoalAdder.tsx b/src/commons/achievement/control/goalEditor/GoalAdder.tsx index 86082b58b6..dfef7affd3 100644 --- a/src/commons/achievement/control/goalEditor/GoalAdder.tsx +++ b/src/commons/achievement/control/goalEditor/GoalAdder.tsx @@ -5,12 +5,12 @@ import { AchievementContext } from 'src/features/achievement/AchievementConstant import { goalDefinitionTemplate } from './GoalTemplate'; -type GoalAdderProps = { +type Props = { allowNewUuid: boolean; setNewUuid: (uuid: string) => void; }; -const GoalAdder: React.FC = ({ allowNewUuid, setNewUuid }) => { +const GoalAdder: React.FC = ({ allowNewUuid, setNewUuid }) => { const inferencer = useContext(AchievementContext); const addGoal = () => setNewUuid(inferencer.insertGoalDefinition(goalDefinitionTemplate)); diff --git a/src/commons/achievement/control/goalEditor/metaDetails/EditableAssessmentMeta.tsx b/src/commons/achievement/control/goalEditor/metaDetails/EditableAssessmentMeta.tsx index 7ab159fb06..cbd42deb3c 100644 --- a/src/commons/achievement/control/goalEditor/metaDetails/EditableAssessmentMeta.tsx +++ b/src/commons/achievement/control/goalEditor/metaDetails/EditableAssessmentMeta.tsx @@ -3,13 +3,12 @@ import { Tooltip2 } from '@blueprintjs/popover2'; import React from 'react'; import { AssessmentMeta, GoalMeta } from 'src/features/achievement/AchievementTypes'; -type EditableAssessmentMetaProps = { +type Props = { assessmentMeta: AssessmentMeta; changeMeta: (meta: GoalMeta) => void; }; -const EditableAssessmentMeta: React.FC = props => { - const { assessmentMeta, changeMeta } = props; +const EditableAssessmentMeta: React.FC = ({ assessmentMeta, changeMeta }) => { const { assessmentNumber, requiredCompletionFrac } = assessmentMeta; const changeAssessmentNumber = (assessmentNumber: number) => diff --git a/src/commons/achievement/control/goalEditor/metaDetails/EditableBinaryMeta.tsx b/src/commons/achievement/control/goalEditor/metaDetails/EditableBinaryMeta.tsx index 17368edba1..8fd93115c6 100644 --- a/src/commons/achievement/control/goalEditor/metaDetails/EditableBinaryMeta.tsx +++ b/src/commons/achievement/control/goalEditor/metaDetails/EditableBinaryMeta.tsx @@ -12,11 +12,6 @@ import { AND, BooleanExpression, OR } from 'src/features/achievement/ExpressionT * Why is this even a possible boolean expression? why would anyone ever use false? */ -type EditableBinaryMetaProps = { - binaryMeta: BinaryMeta; - changeMeta: (meta: GoalMeta) => void; -}; - type Joiner = 'AND' | 'OR'; const JoinerSelect = Select.ofType(); const joinerRenderer: ItemRenderer = (joiner, { handleClick }) => ( @@ -44,7 +39,12 @@ const conditionSplitter = (condition: BooleanExpression): string[] => { } }; -const EditableBinaryMeta: React.FC = ({ binaryMeta, changeMeta }) => { +type Props = { + binaryMeta: BinaryMeta; + changeMeta: (meta: GoalMeta) => void; +}; + +const EditableBinaryMeta: React.FC = ({ binaryMeta, changeMeta }) => { const { condition, targetCount } = binaryMeta; const joiners: string[] = []; diff --git a/src/commons/achievement/control/goalEditor/metaDetails/EditableEventMeta.tsx b/src/commons/achievement/control/goalEditor/metaDetails/EditableEventMeta.tsx index b2ea3beb5d..7089660cff 100644 --- a/src/commons/achievement/control/goalEditor/metaDetails/EditableEventMeta.tsx +++ b/src/commons/achievement/control/goalEditor/metaDetails/EditableEventMeta.tsx @@ -8,17 +8,17 @@ import { EventMeta, EventType, GoalMeta } from 'src/features/achievement/Achieve import EditableDate from '../EditableDate'; import EditableTime from '../EditableTime'; -type EditableEventMetaProps = { - changeMeta: (meta: GoalMeta) => void; - eventMeta: EventMeta; -}; - const EventSelect = Select.ofType(); const eventRenderer: ItemRenderer = (eventName, { handleClick }) => ( ); -const EditableEventMeta: React.FC = ({ changeMeta, eventMeta }) => { +type Props = { + changeMeta: (meta: GoalMeta) => void; + eventMeta: EventMeta; +}; + +const EditableEventMeta: React.FC = ({ changeMeta, eventMeta }) => { const { eventNames, targetCount, release, deadline, observeFrom, observeTo } = eventMeta; const changeTargetCount = (targetCount: number) => diff --git a/src/commons/achievement/control/goalEditor/metaDetails/EditableManualMeta.tsx b/src/commons/achievement/control/goalEditor/metaDetails/EditableManualMeta.tsx index b68c59ecbc..6f500ab972 100644 --- a/src/commons/achievement/control/goalEditor/metaDetails/EditableManualMeta.tsx +++ b/src/commons/achievement/control/goalEditor/metaDetails/EditableManualMeta.tsx @@ -4,12 +4,12 @@ import { Tooltip2 } from '@blueprintjs/popover2'; import React from 'react'; import { GoalMeta, ManualMeta } from 'src/features/achievement/AchievementTypes'; -type EditableManualMetaProps = { +type Props = { changeMeta: (meta: GoalMeta) => void; manualMeta: ManualMeta; }; -const EditableManualMeta: React.FC = ({ changeMeta, manualMeta }) => { +const EditableManualMeta: React.FC = ({ changeMeta, manualMeta }) => { const { targetCount } = manualMeta; const changeTargetCount = (targetCount: number) => diff --git a/src/commons/achievement/overview/AchievementLevel.tsx b/src/commons/achievement/overview/AchievementLevel.tsx index d8cf6985c2..223fec2250 100644 --- a/src/commons/achievement/overview/AchievementLevel.tsx +++ b/src/commons/achievement/overview/AchievementLevel.tsx @@ -5,12 +5,12 @@ import { xpPerLevel } from '../../../features/achievement/AchievementConstants'; import Constants from '../../utils/Constants'; import AchievementMilestone from './AchievementMilestone'; -type AchievementLevelProps = { +type Props = { studentXp: number; }; -const AchievementLevel: React.FC = ({ studentXp }) => { - const [showMilestone, setShowMilestone] = useState(false); +const AchievementLevel: React.FC = ({ studentXp }) => { + const [showMilestone, setShowMilestone] = useState(false); const displayMilestone = () => setShowMilestone(true); const hideMilestone = () => setShowMilestone(false); diff --git a/src/commons/achievement/overview/AchievementMilestone.tsx b/src/commons/achievement/overview/AchievementMilestone.tsx index 78224168ec..65d9fb77d8 100644 --- a/src/commons/achievement/overview/AchievementMilestone.tsx +++ b/src/commons/achievement/overview/AchievementMilestone.tsx @@ -2,12 +2,12 @@ import React from 'react'; import Constants from '../../utils/Constants'; -type AchievementMilestoneProps = { +type Props = { studentXp: number; }; // 36k XP = Level 37 -const AchievementMilestone: React.FC = ({ studentXp }) => { +const AchievementMilestone: React.FC = ({ studentXp }) => { return (

Your Total XP

diff --git a/src/commons/achievement/view/AchievementViewCompletion.tsx b/src/commons/achievement/view/AchievementViewCompletion.tsx index 8178eacd57..e90018696d 100644 --- a/src/commons/achievement/view/AchievementViewCompletion.tsx +++ b/src/commons/achievement/view/AchievementViewCompletion.tsx @@ -1,13 +1,11 @@ import React from 'react'; -type AchievementViewCompletionProps = { +type Props = { awardedXp: number; completionText: string; }; -const AchievementViewCompletion: React.FC = props => { - const { awardedXp, completionText } = props; - +const AchievementViewCompletion: React.FC = ({ awardedXp, completionText }) => { const paragraphs = completionText ? completionText.split('\n') : ['']; return ( diff --git a/src/commons/achievement/view/AchievementViewGoal.tsx b/src/commons/achievement/view/AchievementViewGoal.tsx index 08dbd9ed15..b73a5f516a 100644 --- a/src/commons/achievement/view/AchievementViewGoal.tsx +++ b/src/commons/achievement/view/AchievementViewGoal.tsx @@ -3,10 +3,6 @@ import React from 'react'; import { AchievementGoal } from '../../../features/achievement/AchievementTypes'; -type AchievementViewGoalProps = { - goals: AchievementGoal[]; -}; - /** * Maps an array of goalUuid to Goal component * @@ -37,7 +33,11 @@ const mapGoalToJSX = (goal: AchievementGoal) => { ); }; -const AchievementViewGoal: React.FC = ({ goals }) => { +type Props = { + goals: AchievementGoal[]; +}; + +const AchievementViewGoal: React.FC = ({ goals }) => { return ( <>

Progress

diff --git a/src/commons/application/ApplicationTypes.ts b/src/commons/application/ApplicationTypes.ts index 4d9ee2cd2b..2f23ef9c28 100644 --- a/src/commons/application/ApplicationTypes.ts +++ b/src/commons/application/ApplicationTypes.ts @@ -1,6 +1,5 @@ import { Chapter, Language, SourceError, Variant } from 'js-slang/dist/types'; -import { AcademyState } from '../../features/academy/AcademyTypes'; import { AchievementState } from '../../features/achievement/AchievementTypes'; import { DashboardState } from '../../features/dashboard/DashboardTypes'; import { GradingQuery } from '../../features/grading/GradingTypes'; @@ -25,7 +24,6 @@ import { SessionState } from './types/SessionTypes'; export type OverallState = { readonly router: RouterState; - readonly academy: AcademyState; readonly achievement: AchievementState; readonly playground: PlaygroundState; readonly session: SessionState; @@ -297,10 +295,6 @@ export const getLanguageConfig = ( export const defaultRouter: RouterState = null; -export const defaultAcademy: AcademyState = { - gameCanvas: undefined -}; - export const defaultDashboard: DashboardState = { gradingSummary: { cols: [], @@ -558,7 +552,6 @@ export const defaultSideContentManager: SideContentManagerState = { export const defaultState: OverallState = { router: defaultRouter, - academy: defaultAcademy, achievement: defaultAchievement, dashboard: defaultDashboard, playground: defaultPlayground, diff --git a/src/commons/application/__tests__/Application.tsx b/src/commons/application/__tests__/Application.tsx index 12d071314c..54ff1729f2 100644 --- a/src/commons/application/__tests__/Application.tsx +++ b/src/commons/application/__tests__/Application.tsx @@ -1,4 +1,4 @@ -import { useSelector } from 'react-redux'; +import { useTypedSelector } from 'src/commons/utils/Hooks'; import { shallowRender } from 'src/commons/utils/TestUtils'; import Application from '../Application'; @@ -19,7 +19,7 @@ jest.mock('react-redux', () => ({ useDispatch: jest.fn(), useSelector: jest.fn() })); -const useSelectorMock = useSelector as jest.Mock; +const useSelectorMock = useTypedSelector as jest.Mock; test('Application renders correctly', () => { useSelectorMock.mockReturnValue({ name: 'Bob' }); diff --git a/src/commons/application/reducers/RootReducer.ts b/src/commons/application/reducers/RootReducer.ts index 2e2e9affbe..6d44a73187 100644 --- a/src/commons/application/reducers/RootReducer.ts +++ b/src/commons/application/reducers/RootReducer.ts @@ -1,6 +1,5 @@ import { combineReducers } from 'redux'; -import { AcademyReducer as academy } from '../../../features/academy/AcademyReducer'; import { AchievementReducer as achievement } from '../../../features/achievement/AchievementReducer'; import { DashboardReducer as dashboard } from '../../../features/dashboard/DashboardReducer'; import { PlaygroundReducer as playground } from '../../../features/playground/PlaygroundReducer'; @@ -14,7 +13,6 @@ import { SessionsReducer as session } from './SessionsReducer'; const createRootReducer = () => combineReducers({ router, - academy, achievement, dashboard, playground, diff --git a/src/commons/assessmentWorkspace/AssessmentWorkspace.tsx b/src/commons/assessmentWorkspace/AssessmentWorkspace.tsx index ae3146472a..ed790279c3 100644 --- a/src/commons/assessmentWorkspace/AssessmentWorkspace.tsx +++ b/src/commons/assessmentWorkspace/AssessmentWorkspace.tsx @@ -97,6 +97,7 @@ import { } from '../workspace/WorkspaceActions'; import { WorkspaceLocation, WorkspaceState } from '../workspace/WorkspaceTypes'; import AssessmentWorkspaceGradingResult from './AssessmentWorkspaceGradingResult'; + export type AssessmentWorkspaceProps = { assessmentId: number; needsPassword: boolean; diff --git a/src/commons/assessmentWorkspace/AssessmentWorkspaceGradingResult.tsx b/src/commons/assessmentWorkspace/AssessmentWorkspaceGradingResult.tsx index 450cf6f0f2..db1eea1ac4 100644 --- a/src/commons/assessmentWorkspace/AssessmentWorkspaceGradingResult.tsx +++ b/src/commons/assessmentWorkspace/AssessmentWorkspaceGradingResult.tsx @@ -4,9 +4,7 @@ import React from 'react'; import Markdown from '../Markdown'; import { getPrettyDate } from '../utils/DateHelper'; -type AssessmentWorkspaceGradingResultProps = StateProps; - -type StateProps = { +type Props = { graderName: string; gradedAt: string; xp: number; @@ -14,7 +12,7 @@ type StateProps = { comments?: string; }; -const AssessmentWorkspaceGradingResult: React.FC = props => ( +const AssessmentWorkspaceGradingResult: React.FC = props => (
diff --git a/src/commons/assessmentWorkspace/__tests__/__snapshots__/AssessmentWorkspace.tsx.snap b/src/commons/assessmentWorkspace/__tests__/__snapshots__/AssessmentWorkspace.tsx.snap index d025a4a9a1..8c418ef182 100644 --- a/src/commons/assessmentWorkspace/__tests__/__snapshots__/AssessmentWorkspace.tsx.snap +++ b/src/commons/assessmentWorkspace/__tests__/__snapshots__/AssessmentWorkspace.tsx.snap @@ -219,7 +219,7 @@ exports[`AssessmentWorkspace AssessmentWorkspace page with ContestVoting questio class="editor-container" >
void; }; -export const ControlBarClearButton: React.FC = ({ - handleReplOutputClear -}) => { +export const ControlBarClearButton: React.FC = ({ handleReplOutputClear }) => { return ; }; diff --git a/src/commons/controlBar/ControlBarEvalButton.tsx b/src/commons/controlBar/ControlBarEvalButton.tsx index 8096e3ef1e..67380d2a78 100644 --- a/src/commons/controlBar/ControlBarEvalButton.tsx +++ b/src/commons/controlBar/ControlBarEvalButton.tsx @@ -4,15 +4,12 @@ import React from 'react'; import ControlButton from '../ControlButton'; -type ControlBarEvalButtonProps = { +type Props = { handleReplEval: () => void; isRunning: boolean; }; -export const ControlBarEvalButton: React.FC = ({ - handleReplEval, - isRunning -}) => { +export const ControlBarEvalButton: React.FC = ({ handleReplEval, isRunning }) => { return isRunning ? null : ( diff --git a/src/commons/controlBar/ControlBarGoogleDriveButtons.tsx b/src/commons/controlBar/ControlBarGoogleDriveButtons.tsx index 8e8b2890e8..ce70690d60 100644 --- a/src/commons/controlBar/ControlBarGoogleDriveButtons.tsx +++ b/src/commons/controlBar/ControlBarGoogleDriveButtons.tsx @@ -7,7 +7,13 @@ import { PersistenceFile, PersistenceState } from '../../features/persistence/Pe import ControlButton from '../ControlButton'; import { useResponsive } from '../utils/Hooks'; -export type ControlBarGoogleDriveButtonsProps = { +const stateToIntent: { [state in PersistenceState]: Intent } = { + INACTIVE: Intent.NONE, + SAVED: Intent.PRIMARY, + DIRTY: Intent.WARNING +}; + +type Props = { isFolderModeEnabled: boolean; loggedInAs?: string; currentFile?: PersistenceFile; @@ -19,13 +25,7 @@ export type ControlBarGoogleDriveButtonsProps = { onPopoverOpening?: () => any; }; -const stateToIntent: { [state in PersistenceState]: Intent } = { - INACTIVE: Intent.NONE, - SAVED: Intent.PRIMARY, - DIRTY: Intent.WARNING -}; - -export const ControlBarGoogleDriveButtons: React.FC = props => { +export const ControlBarGoogleDriveButtons: React.FC = props => { const { isMobileBreakpoint } = useResponsive(); const state: PersistenceState = props.currentFile ? props.isDirty diff --git a/src/commons/controlBar/ControlBarQuestionViewButton.tsx b/src/commons/controlBar/ControlBarQuestionViewButton.tsx index fe01b3e639..710c8ac634 100644 --- a/src/commons/controlBar/ControlBarQuestionViewButton.tsx +++ b/src/commons/controlBar/ControlBarQuestionViewButton.tsx @@ -6,13 +6,11 @@ import ControlButton from '../ControlButton'; * @prop questionProgress a tuple of (current question number, question length) where * the current question number is 1-based. */ -type ControlBarQuestionViewButtonProps = { +type Props = { questionProgress: [number, number] | null; }; -export const ControlBarQuestionViewButton: React.FC = ({ - questionProgress -}) => { +export const ControlBarQuestionViewButton: React.FC = ({ questionProgress }) => { return ( = ({ onClick }) => { +export const ControlBarResetButton: React.FC = ({ onClick }) => { return ; }; diff --git a/src/commons/controlBar/ControlBarReturnToAcademyButton.tsx b/src/commons/controlBar/ControlBarReturnToAcademyButton.tsx index b15bee36a1..9478eb02b5 100644 --- a/src/commons/controlBar/ControlBarReturnToAcademyButton.tsx +++ b/src/commons/controlBar/ControlBarReturnToAcademyButton.tsx @@ -3,13 +3,11 @@ import React from 'react'; import ControlButton from '../ControlButton'; -type ControlBarReturnToAcademyButtonProps = { +type Props = { onClick?(): any; }; -export const ControlBarReturnToAcademyButton: React.FC = ({ - onClick -}) => { +export const ControlBarReturnToAcademyButton: React.FC = ({ onClick }) => { return ( = ({ +export const ControlBarToggleEditModeButton: React.FC = ({ toggleEditMode, editingMode }) => { diff --git a/src/commons/controlBar/ControlBarToggleFolderModeButton.tsx b/src/commons/controlBar/ControlBarToggleFolderModeButton.tsx index 5be7620b71..2735537470 100644 --- a/src/commons/controlBar/ControlBarToggleFolderModeButton.tsx +++ b/src/commons/controlBar/ControlBarToggleFolderModeButton.tsx @@ -5,14 +5,14 @@ import React from 'react'; import ControlButton from '../ControlButton'; -type ControlBarToggleFolderModeButtonProps = { +type Props = { isFolderModeEnabled: boolean; isSessionActive: boolean; isPersistenceActive: boolean; toggleFolderMode: () => void; }; -export const ControlBarToggleFolderModeButton: React.FC = ({ +export const ControlBarToggleFolderModeButton: React.FC = ({ isFolderModeEnabled, isSessionActive, isPersistenceActive, diff --git a/src/commons/controlBar/github/ControlBarGitHubButtons.tsx b/src/commons/controlBar/github/ControlBarGitHubButtons.tsx index 21e4938064..c9e4d761ea 100644 --- a/src/commons/controlBar/github/ControlBarGitHubButtons.tsx +++ b/src/commons/controlBar/github/ControlBarGitHubButtons.tsx @@ -8,7 +8,7 @@ import { useResponsive } from 'src/commons/utils/Hooks'; import { GitHubSaveInfo } from '../../../features/github/GitHubTypes'; import ControlButton from '../../ControlButton'; -export type ControlBarGitHubButtonsProps = { +type Props = { isFolderModeEnabled: boolean; loggedInAs?: Octokit; githubSaveInfo: GitHubSaveInfo; @@ -26,7 +26,7 @@ export type ControlBarGitHubButtonsProps = { * * @param props Component properties */ -export const ControlBarGitHubButtons: React.FC = props => { +export const ControlBarGitHubButtons: React.FC = props => { const { isMobileBreakpoint } = useResponsive(); const filePath = props.githubSaveInfo.filePath || ''; diff --git a/src/commons/delay/Delay.tsx b/src/commons/delay/Delay.tsx index 0d92837c5a..5c190739cb 100644 --- a/src/commons/delay/Delay.tsx +++ b/src/commons/delay/Delay.tsx @@ -1,6 +1,6 @@ import React from 'react'; -export type DelayProps = { +type Props = { children: JSX.Element; waitInMsBeforeRender: number; }; @@ -8,10 +8,8 @@ export type DelayProps = { /** * Delays the rendering of child components by a set time. */ -const Delay: React.FC = (props: DelayProps) => { - const { children, waitInMsBeforeRender } = props; - - const [isRendered, setIsRendered] = React.useState(false); +const Delay: React.FC = ({ children, waitInMsBeforeRender }) => { + const [isRendered, setIsRendered] = React.useState(false); React.useEffect(() => { const timeoutId = setTimeout(() => setIsRendered(true), waitInMsBeforeRender); diff --git a/src/commons/dropdown/DropdownAbout.tsx b/src/commons/dropdown/DropdownAbout.tsx index 6350792a7f..9f759cffa8 100644 --- a/src/commons/dropdown/DropdownAbout.tsx +++ b/src/commons/dropdown/DropdownAbout.tsx @@ -4,12 +4,12 @@ import React from 'react'; import { Links } from '../utils/Constants'; -type DialogProps = { +type Props = { isOpen: boolean; onClose: () => void; }; -const DropdownAbout: React.FC = props => ( +const DropdownAbout: React.FC = props => ( void; }; -const DropdownCreateCourse: React.FC = props => { +const DropdownCreateCourse: React.FC = props => { const dispatch = useDispatch(); const [courseConfig, setCourseConfig] = React.useState({ diff --git a/src/commons/dropdown/DropdownHelp.tsx b/src/commons/dropdown/DropdownHelp.tsx index b731301b7d..5ff6305035 100644 --- a/src/commons/dropdown/DropdownHelp.tsx +++ b/src/commons/dropdown/DropdownHelp.tsx @@ -6,12 +6,12 @@ import Markdown from '../Markdown'; import { Links } from '../utils/Constants'; import { useTypedSelector } from '../utils/Hooks'; -type DialogProps = { +type Props = { isOpen: boolean; onClose: () => void; }; -const DropdownHelp: React.FC = props => { +const DropdownHelp: React.FC = props => { const moduleHelpText = useTypedSelector(store => store.session.moduleHelpText); return ( diff --git a/src/commons/editor/Editor.tsx b/src/commons/editor/Editor.tsx index bf10545724..ef98c0afb8 100644 --- a/src/commons/editor/Editor.tsx +++ b/src/commons/editor/Editor.tsx @@ -643,7 +643,7 @@ const EditorBase = React.memo((props: EditorProps & LocalStateProps) => { }, []); return ( - +
diff --git a/src/commons/editor/tabs/EditorTab.tsx b/src/commons/editor/tabs/EditorTab.tsx index 94ea329864..9eabde9332 100644 --- a/src/commons/editor/tabs/EditorTab.tsx +++ b/src/commons/editor/tabs/EditorTab.tsx @@ -3,16 +3,14 @@ import { IconNames } from '@blueprintjs/icons'; import classNames from 'classnames'; import React from 'react'; -export type EditorTabProps = { +type Props = { filePath: string; isActive: boolean; setActive: () => void; remove: () => void; }; -const EditorTab: React.FC = (props: EditorTabProps) => { - const { filePath, isActive, setActive, remove } = props; - +const EditorTab: React.FC = ({ filePath, isActive, setActive, remove }) => { const onClick = (e: React.MouseEvent) => { // Stop the click event from propagating to the parent component. e.stopPropagation(); diff --git a/src/commons/editor/tabs/EditorTabContainer.tsx b/src/commons/editor/tabs/EditorTabContainer.tsx index b3c2fbe2f1..b884fbbe73 100644 --- a/src/commons/editor/tabs/EditorTabContainer.tsx +++ b/src/commons/editor/tabs/EditorTabContainer.tsx @@ -3,7 +3,7 @@ import React from 'react'; import EditorTab from './EditorTab'; import { getShortestUniqueFilePaths } from './utils'; -export type EditorTabContainerProps = { +type Props = { baseFilePath: string; filePaths: string[]; activeEditorTabIndex: number; @@ -11,15 +11,13 @@ export type EditorTabContainerProps = { removeEditorTabByIndex: (editorTabIndex: number) => void; }; -const EditorTabContainer: React.FC = (props: EditorTabContainerProps) => { - const { - baseFilePath, - filePaths, - activeEditorTabIndex, - setActiveEditorTabIndex, - removeEditorTabByIndex - } = props; - +const EditorTabContainer: React.FC = ({ + baseFilePath, + filePaths, + activeEditorTabIndex, + setActiveEditorTabIndex, + removeEditorTabByIndex +}) => { const handleHorizontalScroll = (e: React.WheelEvent) => { e.currentTarget.scrollTo({ left: e.currentTarget.scrollLeft + e.deltaY diff --git a/src/commons/fileSystemView/FileSystemView.tsx b/src/commons/fileSystemView/FileSystemView.tsx index 5aeb2b6590..f248b92505 100644 --- a/src/commons/fileSystemView/FileSystemView.tsx +++ b/src/commons/fileSystemView/FileSystemView.tsx @@ -12,18 +12,17 @@ import FileSystemViewIndentationPadding from './FileSystemViewIndentationPadding import FileSystemViewList from './FileSystemViewList'; import FileSystemViewPlaceholderNode from './FileSystemViewPlaceholderNode'; -export type FileSystemViewProps = { +type Props = { workspaceLocation: WorkspaceLocation; basePath: string; }; -const FileSystemView: React.FC = (props: FileSystemViewProps) => { - const { workspaceLocation, basePath } = props; +const FileSystemView: React.FC = ({ workspaceLocation, basePath }) => { const fileSystem = useTypedSelector(state => state.fileSystem.inBrowserFileSystem); - const [isAddingNewFile, setIsAddingNewFile] = React.useState(false); - const [isAddingNewDirectory, setIsAddingNewDirectory] = React.useState(false); - const [fileSystemViewListKey, setFileSystemViewListKey] = React.useState(0); + const [isAddingNewFile, setIsAddingNewFile] = React.useState(false); + const [isAddingNewDirectory, setIsAddingNewDirectory] = React.useState(false); + const [fileSystemViewListKey, setFileSystemViewListKey] = React.useState(0); const handleCreateNewFile = () => setIsAddingNewFile(true); const handleCreateNewDirectory = () => setIsAddingNewDirectory(true); diff --git a/src/commons/fileSystemView/FileSystemViewContextMenu.tsx b/src/commons/fileSystemView/FileSystemViewContextMenu.tsx index 51c8a68dee..a107d6bf87 100644 --- a/src/commons/fileSystemView/FileSystemViewContextMenu.tsx +++ b/src/commons/fileSystemView/FileSystemViewContextMenu.tsx @@ -4,7 +4,7 @@ import classNames from 'classnames'; import React from 'react'; import classes from 'src/styles/ContextMenu.module.scss'; -export type FileSystemViewContextMenuProps = { +type Props = { children?: JSX.Element; className?: string; createNewFile?: () => void; @@ -14,10 +14,15 @@ export type FileSystemViewContextMenuProps = { remove?: () => void; }; -const FileSystemViewContextMenu: React.FC = ( - props: FileSystemViewContextMenuProps -) => { - const { children, className, createNewFile, createNewDirectory, open, rename, remove } = props; +const FileSystemViewContextMenu: React.FC = ({ + children, + className, + createNewFile, + createNewDirectory, + open, + rename, + remove +}) => { const [menuProps, toggleMenu] = useMenuState(); const [anchorPoint, setAnchorPoint] = React.useState({ x: 0, y: 0 }); diff --git a/src/commons/fileSystemView/FileSystemViewDirectoryNode.tsx b/src/commons/fileSystemView/FileSystemViewDirectoryNode.tsx index 4c136de3b1..fa59e26c4e 100644 --- a/src/commons/fileSystemView/FileSystemViewDirectoryNode.tsx +++ b/src/commons/fileSystemView/FileSystemViewDirectoryNode.tsx @@ -16,7 +16,7 @@ import FileSystemViewIndentationPadding from './FileSystemViewIndentationPadding import FileSystemViewList from './FileSystemViewList'; import FileSystemViewPlaceholderNode from './FileSystemViewPlaceholderNode'; -export type FileSystemViewDirectoryNodeProps = { +type Props = { workspaceLocation: WorkspaceLocation; fileSystem: FSModule; basePath: string; @@ -25,24 +25,21 @@ export type FileSystemViewDirectoryNodeProps = { refreshParentDirectory: () => void; }; -const FileSystemViewDirectoryNode: React.FC = ( - props: FileSystemViewDirectoryNodeProps -) => { - const { - workspaceLocation, - fileSystem, - basePath, - directoryName, - indentationLevel, - refreshParentDirectory - } = props; +const FileSystemViewDirectoryNode: React.FC = ({ + workspaceLocation, + fileSystem, + basePath, + directoryName, + indentationLevel, + refreshParentDirectory +}) => { const fullPath = path.join(basePath, directoryName); - const [isExpanded, setIsExpanded] = React.useState(false); - const [isEditing, setIsEditing] = React.useState(false); - const [isAddingNewFile, setIsAddingNewFile] = React.useState(false); - const [isAddingNewDirectory, setIsAddingNewDirectory] = React.useState(false); - const [fileSystemViewListKey, setFileSystemViewListKey] = React.useState(0); + const [isExpanded, setIsExpanded] = React.useState(false); + const [isEditing, setIsEditing] = React.useState(false); + const [isAddingNewFile, setIsAddingNewFile] = React.useState(false); + const [isAddingNewDirectory, setIsAddingNewDirectory] = React.useState(false); + const [fileSystemViewListKey, setFileSystemViewListKey] = React.useState(0); const dispatch = useDispatch(); const toggleIsExpanded = () => { diff --git a/src/commons/fileSystemView/FileSystemViewFileName.tsx b/src/commons/fileSystemView/FileSystemViewFileName.tsx index 12aee8c411..d1611a64b6 100644 --- a/src/commons/fileSystemView/FileSystemViewFileName.tsx +++ b/src/commons/fileSystemView/FileSystemViewFileName.tsx @@ -11,7 +11,7 @@ import { } from '../workspace/WorkspaceActions'; import { WorkspaceLocation } from '../workspace/WorkspaceTypes'; -export type FileSystemViewFileNameProps = { +type Props = { workspaceLocation: WorkspaceLocation; fileSystem: FSModule; basePath: string; @@ -22,21 +22,17 @@ export type FileSystemViewFileNameProps = { refreshDirectory: () => void; }; -const FileSystemViewFileName: React.FC = ( - props: FileSystemViewFileNameProps -) => { - const { - workspaceLocation, - fileSystem, - basePath, - fileName, - isDirectory, - isEditing, - setIsEditing, - refreshDirectory - } = props; - - const [editedFileName, setEditedFileName] = React.useState(fileName); +const FileSystemViewFileName: React.FC = ({ + workspaceLocation, + fileSystem, + basePath, + fileName, + isDirectory, + isEditing, + setIsEditing, + refreshDirectory +}) => { + const [editedFileName, setEditedFileName] = React.useState(fileName); const dispatch = useDispatch(); const handleInputOnChange = (e: React.ChangeEvent) => diff --git a/src/commons/fileSystemView/FileSystemViewFileNode.tsx b/src/commons/fileSystemView/FileSystemViewFileNode.tsx index 489a76e778..99136f4447 100644 --- a/src/commons/fileSystemView/FileSystemViewFileNode.tsx +++ b/src/commons/fileSystemView/FileSystemViewFileNode.tsx @@ -13,7 +13,7 @@ import FileSystemViewContextMenu from './FileSystemViewContextMenu'; import FileSystemViewFileName from './FileSystemViewFileName'; import FileSystemViewIndentationPadding from './FileSystemViewIndentationPadding'; -export type FileSystemViewFileNodeProps = { +type Props = { workspaceLocation: WorkspaceLocation; fileSystem: FSModule; basePath: string; @@ -22,13 +22,15 @@ export type FileSystemViewFileNodeProps = { refreshDirectory: () => void; }; -const FileSystemViewFileNode: React.FC = ( - props: FileSystemViewFileNodeProps -) => { - const { workspaceLocation, fileSystem, basePath, fileName, indentationLevel, refreshDirectory } = - props; - - const [isEditing, setIsEditing] = React.useState(false); +const FileSystemViewFileNode: React.FC = ({ + workspaceLocation, + fileSystem, + basePath, + fileName, + indentationLevel, + refreshDirectory +}) => { + const [isEditing, setIsEditing] = React.useState(false); const dispatch = useDispatch(); const fullPath = path.join(basePath, fileName); diff --git a/src/commons/fileSystemView/FileSystemViewIndentationPadding.tsx b/src/commons/fileSystemView/FileSystemViewIndentationPadding.tsx index eae7adb6a8..004e3f63a2 100644 --- a/src/commons/fileSystemView/FileSystemViewIndentationPadding.tsx +++ b/src/commons/fileSystemView/FileSystemViewIndentationPadding.tsx @@ -1,16 +1,12 @@ import React from 'react'; -export type FileSystemViewIndentationPaddingProps = { +type Props = { indentationLevel: number; }; const SPACING_PER_LEVEL = 19; -const FileSystemViewIndentationPadding: React.FC = ( - props: FileSystemViewIndentationPaddingProps -) => { - const { indentationLevel } = props; - +const FileSystemViewIndentationPadding: React.FC = ({ indentationLevel }) => { const indentationStyle: React.CSSProperties = { paddingLeft: `${SPACING_PER_LEVEL * indentationLevel}px` }; diff --git a/src/commons/fileSystemView/FileSystemViewList.tsx b/src/commons/fileSystemView/FileSystemViewList.tsx index 1b2ed2daa4..b49462853a 100644 --- a/src/commons/fileSystemView/FileSystemViewList.tsx +++ b/src/commons/fileSystemView/FileSystemViewList.tsx @@ -9,16 +9,19 @@ import { WorkspaceLocation } from '../workspace/WorkspaceTypes'; import FileSystemViewDirectoryNode from './FileSystemViewDirectoryNode'; import FileSystemViewFileNode from './FileSystemViewFileNode'; -export type FileSystemViewListProps = { +type Props = { workspaceLocation: WorkspaceLocation; fileSystem: FSModule; basePath: string; indentationLevel: number; }; -const FileSystemViewList: React.FC = (props: FileSystemViewListProps) => { - const { workspaceLocation, fileSystem, basePath, indentationLevel } = props; - +const FileSystemViewList: React.FC = ({ + workspaceLocation, + fileSystem, + basePath, + indentationLevel +}) => { const [dirNames, setDirNames] = React.useState(undefined); const [fileNames, setFileNames] = React.useState(undefined); diff --git a/src/commons/fileSystemView/FileSystemViewPlaceholderNode.tsx b/src/commons/fileSystemView/FileSystemViewPlaceholderNode.tsx index ffeca549ca..3a985c323e 100644 --- a/src/commons/fileSystemView/FileSystemViewPlaceholderNode.tsx +++ b/src/commons/fileSystemView/FileSystemViewPlaceholderNode.tsx @@ -1,17 +1,13 @@ import React from 'react'; import classes from 'src/styles/FileSystemView.module.scss'; -export type FileSystemViewPlaceholderNodeProps = { +type Props = { processFileName: (fileName: string) => void; removePlaceholder: () => void; }; -const FileSystemViewPlaceholderNode: React.FC = ( - props: FileSystemViewPlaceholderNodeProps -) => { - const { processFileName, removePlaceholder } = props; - - const [fileName, setFileName] = React.useState(''); +const FileSystemViewPlaceholderNode: React.FC = ({ processFileName, removePlaceholder }) => { + const [fileName, setFileName] = React.useState(''); const handleInputOnChange = (e: React.ChangeEvent) => setFileName(e.target.value); diff --git a/src/commons/mobileWorkspace/DraggableRepl.tsx b/src/commons/mobileWorkspace/DraggableRepl.tsx index 9f6d1bcd41..f0001cb648 100644 --- a/src/commons/mobileWorkspace/DraggableRepl.tsx +++ b/src/commons/mobileWorkspace/DraggableRepl.tsx @@ -3,14 +3,14 @@ import Draggable, { DraggableEventHandler } from 'react-draggable'; import Repl, { ReplProps } from '../repl/Repl'; -type DraggableReplProps = { +type Props = { position: { x: number; y: number }; onDrag: DraggableEventHandler; disabled: boolean; replProps: ReplProps; }; -const DraggableRepl: React.FC = (props: DraggableReplProps) => { +const DraggableRepl: React.FC = props => { return ( = props => { +const MobileKeyboard: React.FC = props => { const [isKeyboardShown, setIsKeyoardShown] = React.useState(false); const [buttonContent, setButtonContent] = React.useState('ᐸ'); const [keyboardPosition, setKeyboardPosition] = React.useState({ x: 0, y: 0 }); diff --git a/src/commons/mobileWorkspace/MobileWorkspace.tsx b/src/commons/mobileWorkspace/MobileWorkspace.tsx index 68a8351f5f..42d20b7979 100644 --- a/src/commons/mobileWorkspace/MobileWorkspace.tsx +++ b/src/commons/mobileWorkspace/MobileWorkspace.tsx @@ -16,9 +16,7 @@ import DraggableRepl from './DraggableRepl'; import MobileKeyboard from './MobileKeyboard'; import MobileSideContent, { MobileSideContentProps } from './mobileSideContent/MobileSideContent'; -export type MobileWorkspaceProps = StateProps; - -type StateProps = { +export type MobileWorkspaceProps = { editorContainerProps?: EditorContainerProps; // Either editorProps or mcqProps must be provided hasUnsavedChanges?: boolean; // Not used in Playground mcqProps?: McqChooserProps; // Not used in Playground diff --git a/src/commons/mocks/StoreMocks.ts b/src/commons/mocks/StoreMocks.ts index 7ba02a5b3e..1f14b69822 100644 --- a/src/commons/mocks/StoreMocks.ts +++ b/src/commons/mocks/StoreMocks.ts @@ -3,7 +3,6 @@ import { DeepPartial, Store } from 'redux'; import mockStore from 'redux-mock-store'; import { - defaultAcademy, defaultAchievement, defaultDashboard, defaultFileSystem, @@ -20,7 +19,6 @@ export function mockInitialStore(overrides?: DeepPartial): Store ({ useSelector: jest.fn() })); -const useSelectorMock = useSelector as jest.Mock; +const useSelectorMock = useTypedSelector as jest.Mock; const useLocationMock = useLocation as jest.Mock; describe('NavigationBar', () => { diff --git a/src/commons/navigationBar/subcomponents/AcademyNavigationBar.tsx b/src/commons/navigationBar/subcomponents/AcademyNavigationBar.tsx index 9644bd177a..2d35125653 100644 --- a/src/commons/navigationBar/subcomponents/AcademyNavigationBar.tsx +++ b/src/commons/navigationBar/subcomponents/AcademyNavigationBar.tsx @@ -8,11 +8,11 @@ import { assessmentTypeLink } from 'src/commons/utils/ParamParseHelper'; import { Role } from '../../application/ApplicationTypes'; import { createDesktopNavlink, NavbarEntryInfo, renderNavlinksFromInfo } from '../NavigationBar'; -type OwnProps = { +type Props = { assessmentTypes?: AssessmentType[]; }; -const AcademyNavigationBar: React.FunctionComponent = ({ assessmentTypes }) => { +const AcademyNavigationBar: React.FC = ({ assessmentTypes }) => { const { role, courseId } = useSession(); const isEnrolledInACourse = !!role; diff --git a/src/commons/navigationBar/subcomponents/__tests__/AcademyNavigationBar.tsx b/src/commons/navigationBar/subcomponents/__tests__/AcademyNavigationBar.tsx index 1256b291a7..8778b2c6b7 100644 --- a/src/commons/navigationBar/subcomponents/__tests__/AcademyNavigationBar.tsx +++ b/src/commons/navigationBar/subcomponents/__tests__/AcademyNavigationBar.tsx @@ -1,4 +1,4 @@ -import { useSelector } from 'react-redux'; +import { useTypedSelector } from 'src/commons/utils/Hooks'; import { deepFilter, shallowRender } from 'src/commons/utils/TestUtils'; import { Role } from '../../../application/ApplicationTypes'; @@ -8,7 +8,7 @@ jest.mock('react-redux', () => ({ ...jest.requireActual('react-redux'), useSelector: jest.fn() })); -const useSelectorMock = useSelector as jest.Mock; +const useSelectorMock = useTypedSelector as jest.Mock; const assessmentTypes = ['Missions', 'Quests', 'Paths', 'Contests', 'Others']; const staffRoutes = ['grading', 'groundcontrol', 'sourcereel', 'gamesimulator', 'dashboard']; diff --git a/src/commons/notificationBadge/NotificationBadge.tsx b/src/commons/notificationBadge/NotificationBadge.tsx index e6c3a38f73..10625477e5 100644 --- a/src/commons/notificationBadge/NotificationBadge.tsx +++ b/src/commons/notificationBadge/NotificationBadge.tsx @@ -8,16 +8,14 @@ import { useSession } from '../utils/Hooks'; import { filterNotificationsById } from './NotificationBadgeHelper'; import { Notification, NotificationType, NotificationTypes } from './NotificationBadgeTypes'; -type NotificationBadgeProps = OwnProps; - -type OwnProps = { +type Props = { className?: string; disableHover?: boolean; // Set to true to disable popover content large?: boolean; // Set to true to use large style notificationFilter?: (notifications: Notification[]) => Notification[]; }; -const NotificationBadge: React.FC = props => { +const NotificationBadge: React.FC = props => { const dispatch = useDispatch(); const { notifications: initialNotifications } = useSession(); diff --git a/src/commons/repl/Repl.tsx b/src/commons/repl/Repl.tsx index 98ef021922..4cc233ab6e 100644 --- a/src/commons/repl/Repl.tsx +++ b/src/commons/repl/Repl.tsx @@ -38,7 +38,7 @@ type OwnProps = { replButtons: Array; }; -const Repl: React.FC = (props: ReplProps) => { +const Repl: React.FC = props => { const cards = props.output.map((slice, index) => ( = (props: ReplProps) => { ); }; -export const Output: React.FC = (props: OutputProps) => { +export const Output: React.FC = props => { switch (props.output.type) { case 'code': return ( diff --git a/src/commons/repl/ReplInput.tsx b/src/commons/repl/ReplInput.tsx index 83bc5ea1b3..73ddaee98a 100644 --- a/src/commons/repl/ReplInput.tsx +++ b/src/commons/repl/ReplInput.tsx @@ -34,7 +34,7 @@ type OwnProps = { replButtons: Array; }; -export const ReplInput: React.FC = (props: ReplInputProps) => { +export const ReplInput: React.FC = props => { const { onFocus, onBlur } = props; const replInput = React.useRef(null); diff --git a/src/commons/sagas/AchievementSaga.ts b/src/commons/sagas/AchievementSaga.ts index fc97c02ecb..f455545116 100644 --- a/src/commons/sagas/AchievementSaga.ts +++ b/src/commons/sagas/AchievementSaga.ts @@ -196,10 +196,10 @@ export default function* AchievementSaga(): SagaIterator { // Flash the home icon if there is an error and the user is in the CSE machine or subst viz tab const introIcon = document.getElementById(SideContentType.introduction + '-icon'); const cseTab = document.getElementById( - 'bp4-tab-panel_side-content-tabs_' + SideContentType.cseMachine + 'bp5-tab-panel_side-content-tabs_' + SideContentType.cseMachine ); const substTab = document.getElementById( - 'bp4-tab-panel_side-content-tabs_' + SideContentType.substVisualizer + 'bp5-tab-panel_side-content-tabs_' + SideContentType.substVisualizer ); if ( (cseTab && cseTab.ariaHidden === 'false') || diff --git a/src/commons/sideBar/SideBar.tsx b/src/commons/sideBar/SideBar.tsx index e18d5083da..39c9813dae 100644 --- a/src/commons/sideBar/SideBar.tsx +++ b/src/commons/sideBar/SideBar.tsx @@ -18,17 +18,15 @@ export type SideBarTab = { id?: SideContentType; }; -export type SideBarProps = { +type Props = { tabs: SideBarTab[]; isExpanded: boolean; expandSideBar: () => void; collapseSideBar: () => void; }; -const SideBar: React.FC = (props: SideBarProps) => { - const { tabs, isExpanded, expandSideBar, collapseSideBar } = props; - - const [selectedTabIndex, setSelectedTabIndex] = React.useState(0); +const SideBar: React.FC = ({ tabs, isExpanded, expandSideBar, collapseSideBar }) => { + const [selectedTabIndex, setSelectedTabIndex] = React.useState(0); const handleTabSelection = (tabIndex: number) => { if (selectedTabIndex === tabIndex) { diff --git a/src/commons/sideContent/SideContentHelper.ts b/src/commons/sideContent/SideContentHelper.ts index de02c6affd..27b747432b 100644 --- a/src/commons/sideContent/SideContentHelper.ts +++ b/src/commons/sideContent/SideContentHelper.ts @@ -1,7 +1,7 @@ -import * as bp3core from '@blueprintjs/core'; +import * as bpcore from '@blueprintjs/core'; import { TabId } from '@blueprintjs/core'; -import * as bp3icons from '@blueprintjs/icons'; -import * as bp3popover from '@blueprintjs/popover2'; +import * as bpicons from '@blueprintjs/icons'; +import * as bppopover from '@blueprintjs/popover2'; import * as jsslang from 'js-slang'; import * as jsslangDist from 'js-slang/dist'; import lodash from 'lodash'; @@ -32,9 +32,9 @@ const requireProvider = (x: string) => { 'react/jsx-runtime': JSXRuntime, 'react-ace': ace, 'react-dom': ReactDOM, - '@blueprintjs/core': bp3core, - '@blueprintjs/icons': bp3icons, - '@blueprintjs/popover2': bp3popover, + '@blueprintjs/core': bpcore, + '@blueprintjs/icons': bpicons, + '@blueprintjs/popover2': bppopover, 'js-slang': jsslang, 'js-slang/dist': jsslangDist, lodash, diff --git a/src/commons/sideContent/content/SideContentAutograder.tsx b/src/commons/sideContent/content/SideContentAutograder.tsx index 6560daaa68..698ddeb473 100644 --- a/src/commons/sideContent/content/SideContentAutograder.tsx +++ b/src/commons/sideContent/content/SideContentAutograder.tsx @@ -28,9 +28,9 @@ type OwnProps = { workspaceLocation: WorkspaceLocation; }; -const SideContentAutograder: React.FunctionComponent = props => { - const [showsTestcases, setTestcasesShown] = React.useState(true); - const [showsResults, setResultsShown] = React.useState(true); +const SideContentAutograder: React.FC = props => { + const [showsTestcases, setTestcasesShown] = React.useState(true); + const [showsResults, setResultsShown] = React.useState(true); const { testcases, autogradingResults, handleTestcaseEval, workspaceLocation } = props; diff --git a/src/commons/sideContent/content/SideContentCanvasOutput.tsx b/src/commons/sideContent/content/SideContentCanvasOutput.tsx index 2b5d356857..cf5deda5a4 100644 --- a/src/commons/sideContent/content/SideContentCanvasOutput.tsx +++ b/src/commons/sideContent/content/SideContentCanvasOutput.tsx @@ -1,8 +1,6 @@ import React, { useEffect, useRef } from 'react'; -type SideContentCanvasOutputProps = StateProps; - -type StateProps = { +type Props = { canvas: HTMLCanvasElement; }; @@ -10,7 +8,7 @@ type StateProps = { * Takes the output of the rendered graphics (in a hidden canvas tag under ) * and makes it into a new output for viewing. */ -const SideContentCanvasOutput: React.FC = ({ canvas }) => { +const SideContentCanvasOutput: React.FC = ({ canvas }) => { const parentRef = useRef(null); useEffect(() => { diff --git a/src/commons/sideContent/content/SideContentContestLeaderboard.tsx b/src/commons/sideContent/content/SideContentContestLeaderboard.tsx index d678400f15..d072cc3131 100644 --- a/src/commons/sideContent/content/SideContentContestLeaderboard.tsx +++ b/src/commons/sideContent/content/SideContentContestLeaderboard.tsx @@ -26,11 +26,9 @@ type StateProps = { * @param props {orderedContestEntries: an ordered list by desc score of leaderboard entries to display, * handleContestEntryClick: displays contest entry answer in assessment workspace editor} */ -const SideContentContestLeaderboard: React.FunctionComponent< - SideContentContestLeaderboardProps -> = props => { +const SideContentContestLeaderboard: React.FC = props => { const { orderedContestEntries, handleContestEntryClick, leaderboardType } = props; - const [showLeaderboard, setShowLeaderboard] = useState(true); + const [showLeaderboard, setShowLeaderboard] = useState(true); /** * Contest Leaderboard inner components diff --git a/src/commons/sideContent/content/SideContentContestVoting.tsx b/src/commons/sideContent/content/SideContentContestVoting.tsx index 15b58cb9a9..f6c12fe6f6 100644 --- a/src/commons/sideContent/content/SideContentContestVoting.tsx +++ b/src/commons/sideContent/content/SideContentContestVoting.tsx @@ -6,7 +6,7 @@ import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react' import { ContestEntry } from '../../assessment/AssessmentTypes'; -export type SideContentContestVotingProps = DispatchProps & StateProps; +type SideContentContestVotingProps = DispatchProps & StateProps; type DispatchProps = { handleContestEntryClick: (submissionId: number, answer: string) => void; @@ -28,15 +28,14 @@ const TIERS = [ { name: 'D', color: 'rgb(127, 191, 255)', score: 1 } ]; -const SideContentContestVoting: React.FunctionComponent = props => { - const { - contestEntries, - canSave, - isValid, - handleContestEntryClick, - handleVotingSubmissionChange - } = props; - const [showContestEntries, setShowContestEntries] = useState(true); +const SideContentContestVoting: React.FC = ({ + contestEntries, + canSave, + isValid, + handleContestEntryClick, + handleVotingSubmissionChange +}) => { + const [showContestEntries, setShowContestEntries] = useState(true); const [currentDraggedItem, setCurrentDraggedItem] = useState(null); const [hoveredTier, setHoveredTier] = useState(null); diff --git a/src/commons/sideContent/content/SideContentContestVotingContainer.tsx b/src/commons/sideContent/content/SideContentContestVotingContainer.tsx index 8aaa379a37..85bac3f44e 100644 --- a/src/commons/sideContent/content/SideContentContestVotingContainer.tsx +++ b/src/commons/sideContent/content/SideContentContestVotingContainer.tsx @@ -20,11 +20,13 @@ type StateProps = { * Container to separate behaviour concerns from rendering concerns * Stores component-level voting ranking state */ -const SideContentContestVotingContainer: React.FunctionComponent< - SideContentContestVotingContainerProps -> = props => { - const { canSave, contestEntries, handleSave, handleContestEntryClick } = props; - const [isValid, setIsValid] = useState(true); +const SideContentContestVotingContainer: React.FC = ({ + canSave, + contestEntries, + handleSave, + handleContestEntryClick +}) => { + const [isValid, setIsValid] = useState(true); const [votingSubmission, setVotingSubmission] = useState([]); useEffect(() => { diff --git a/src/commons/sideContent/content/SideContentDataVisualizer.tsx b/src/commons/sideContent/content/SideContentDataVisualizer.tsx index a7516b3d8e..4b991f216d 100644 --- a/src/commons/sideContent/content/SideContentDataVisualizer.tsx +++ b/src/commons/sideContent/content/SideContentDataVisualizer.tsx @@ -96,7 +96,7 @@ class SideContentDataVisualizerBase extends React.Component Previous -

+

Call {this.state.currentStep + 1}/{this.state.steps.length}