Skip to content

Refactor frontend part 6 #2800

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 36 commits into from
Mar 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
1dfec66
Add generic type argument to column definitions
RichDom2185 Feb 21, 2024
0fadb9b
Migrate bp4 classes to bp5
RichDom2185 Feb 21, 2024
5897a08
Remove unused `AcademyReducer` and dependents
RichDom2185 Feb 21, 2024
079ed55
Update imports
RichDom2185 Feb 21, 2024
c0f6994
Fix lint
RichDom2185 Feb 21, 2024
7c558ac
Undo test import change
RichDom2185 Feb 21, 2024
4f469e7
Merge branch 'master' into fe-refactor-6
RichDom2185 Feb 22, 2024
1f3eddb
Merge branch 'master' of https://github.com/source-academy/frontend i…
RichDom2185 Feb 23, 2024
8a6fda7
Remove unnecessay `loadContentDispatch` sometimes
RichDom2185 Feb 23, 2024
b9c72db
Update test snapshots
RichDom2185 Feb 23, 2024
07055f8
Merge branch 'master' into fe-refactor-6
RichDom2185 Feb 23, 2024
37c346a
Merge branch 'master' into fe-refactor-6
RichDom2185 Feb 23, 2024
33e1cba
Merge branch 'master' of https://github.com/source-academy/frontend i…
RichDom2185 Feb 23, 2024
d9b3aa6
Merge branch 'master' into fe-refactor-6
RichDom2185 Feb 23, 2024
c842fbf
Make component typings more consistent
RichDom2185 Feb 23, 2024
e540c7f
Bump dependencies
RichDom2185 Feb 23, 2024
4768000
Merge branch 'master' into fe-refactor-6
RichDom2185 Feb 24, 2024
177b463
Merge branch 'master' into fe-refactor-6
RichDom2185 Feb 24, 2024
6865ab8
Merge branch 'master' into fe-refactor-6
RichDom2185 Feb 26, 2024
6826844
Merge branch 'master' into fe-refactor-6
RichDom2185 Mar 1, 2024
1491ffe
Merge branch 'master' of https://github.com/source-academy/frontend i…
RichDom2185 Mar 12, 2024
76e2ed6
Fix class name typo
RichDom2185 Mar 12, 2024
d84e3e8
Merge branch 'master' into fe-refactor-6
RichDom2185 Mar 12, 2024
6c24626
Change relative import to project-based import
sayomaki Mar 12, 2024
57a00bd
Merge branch 'master' of https://github.com/source-academy/frontend i…
RichDom2185 Mar 15, 2024
58e0389
Merge branch 'master' of https://github.com/source-academy/frontend i…
RichDom2185 Mar 16, 2024
a494835
Bump dependencies
RichDom2185 Mar 16, 2024
ef64c1b
Update test snapshots
RichDom2185 Mar 16, 2024
d74d621
Standardize typings
RichDom2185 Mar 16, 2024
d6dd78a
Remove unnecessary generic type arguments
RichDom2185 Mar 16, 2024
5c4b1d7
Standardize ControlBar components typings
RichDom2185 Mar 16, 2024
59f8c9d
Standardize more component typings
RichDom2185 Mar 17, 2024
e2b3947
Fix compile error
RichDom2185 Mar 17, 2024
f2ac0d0
Standardize remaining component typings
RichDom2185 Mar 17, 2024
c462aaa
Ban `React.FunctionComponent` type
RichDom2185 Mar 17, 2024
94b334e
Ban `useSelector` import
RichDom2185 Mar 17, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 29 additions & 1 deletion .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand All @@ -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"
}
}
4 changes: 3 additions & 1 deletion src/assets/PortSvg.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import React from 'react';

type Props = {
port: string;
};

const PortSvg = ({ port }: Props) => (
const PortSvg: React.FC<Props> = ({ port }) => (
<svg
xmlns="http://www.w3.org/2000/svg"
id="port-svg6348"
Expand Down
18 changes: 9 additions & 9 deletions src/commons/ControlButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,6 @@ type ButtonOptions = {
type?: 'submit' | 'reset' | 'button';
};

type ControlButtonProps = {
label?: string;
icon?: IconName;
onClick?: () => void;
options?: Partial<ButtonOptions>;
isDisabled?: boolean;
};

const defaultOptions = {
className: '',
fullWidth: false,
Expand All @@ -27,7 +19,15 @@ const defaultOptions = {
minimal: true
};

const ControlButton: React.FC<ControlButtonProps> = ({
type Props = {
label?: string;
icon?: IconName;
onClick?: () => void;
options?: Partial<ButtonOptions>;
isDisabled?: boolean;
};

const ControlButton: React.FC<Props> = ({
label = '',
icon,
onClick,
Expand Down
4 changes: 2 additions & 2 deletions src/commons/Markdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -12,7 +12,7 @@ type MarkdownProps = {
tasklists?: boolean;
};

const Markdown: React.FC<MarkdownProps> = props => {
const Markdown: React.FC<Props> = props => {
const converter = new Converter({
tables: true,
simplifiedAutoLink: props.simplifiedAutoLink,
Expand Down
12 changes: 8 additions & 4 deletions src/commons/SimpleDropdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,13 @@ type Props<T extends OptionType> = {
popoverProps?: Partial<React.ComponentProps<typeof Popover2>>;
};

function SimpleDropdown<T extends OptionType>(props: Props<T>) {
const { options, selectedValue, onClick, buttonProps, popoverProps } = props;

const SimpleDropdown = <T extends OptionType>({
options,
selectedValue,
onClick,
buttonProps,
popoverProps
}: Props<T>) => {
const handleClick = (value: T['value']) => {
onClick?.(value);
};
Expand All @@ -37,6 +41,6 @@ function SimpleDropdown<T extends OptionType>(props: Props<T>) {
<Button {...buttonProps}>{buttonLabel()}</Button>
</Popover2>
);
}
};

export default SimpleDropdown;
3 changes: 1 addition & 2 deletions src/commons/__tests__/ContentDisplay.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@ import ContentDisplay, { ContentDisplayProps } from '../ContentDisplay';
import { renderTreeJson } from '../utils/TestUtils';

const mockProps: ContentDisplayProps = {
display: <div> Test Content </div>,
loadContentDispatch: () => {}
display: <div> Test Content </div>
};

test('ContentDisplay page renders correctly', () => {
Expand Down
12 changes: 8 additions & 4 deletions src/commons/achievement/AchievementCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,21 @@ 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;
shouldRender: boolean;
toggleDropdown?: () => void;
};

const AchievementCard: React.FC<AchievementCardProps> = props => {
const { uuid, focusState, isDropdownOpen, shouldRender, toggleDropdown } = props;

const AchievementCard: React.FC<Props> = ({
uuid,
focusState,
isDropdownOpen,
shouldRender,
toggleDropdown
}) => {
const inferencer = useContext(AchievementContext);

const [focusUuid, setFocusUuid] = focusState;
Expand Down
6 changes: 4 additions & 2 deletions src/commons/achievement/AchievementCommentCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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<Props> = ({ assessment, showToQuestion }) => {
const navigate = useNavigate();
const courseId = useTypedSelector(store => store.session.courseId);
const toMission = useMemo(
Expand Down
4 changes: 2 additions & 2 deletions src/commons/achievement/AchievementFilter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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<AchievementFilterProps> = ({ filterState, icon, ownStatus }) => {
const AchievementFilter: React.FC<Props> = ({ filterState, icon, ownStatus }) => {
const [globalStatus, setGlobalStatus] = filterState;

return (
Expand Down
22 changes: 11 additions & 11 deletions src/commons/achievement/AchievementManualEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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<AchievementGoal>();
const goalRenderer: ItemRenderer<AchievementGoal> = (goal, { handleClick }) => (
<MenuItem key={goal.uuid} onClick={handleClick} text={goal.text} />
Expand All @@ -40,7 +31,16 @@ export function updateGoalProcessed() {
showSuccessMessage('Goal updated');
}

const AchievementManualEditor: React.FC<AchievementManualEditorProps> = 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> = props => {
const { userState, hiddenState, studio, getUsers, updateGoalProgress } = props;
const users =
studio === 'Staff'
Expand Down Expand Up @@ -75,7 +75,7 @@ const AchievementManualEditor: React.FC<AchievementManualEditorProps> = props =>

const [goal, changeGoal] = useState<AchievementGoal | undefined>(undefined);
const [selectedUser, changeSelectedUser] = userState;
const [count, changeCount] = useState<number>(0);
const [count, changeCount] = useState(0);
const [viewHidden, changeViewHidden] = hiddenState;

const updateGoal = () => {
Expand Down
4 changes: 2 additions & 2 deletions src/commons/achievement/AchievementOverview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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<AchievementOverviewProps> = ({ name, userState }) => {
const AchievementOverview: React.FC<Props> = ({ name, userState }) => {
const [selectedUser] = userState;
const crid = selectedUser?.courseRegId;
const userCrid = useTypedSelector(store => store.session.courseRegId);
Expand Down
6 changes: 3 additions & 3 deletions src/commons/achievement/AchievementTask.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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<AchievementTaskProps> = ({ uuid, filterStatus, focusState }) => {
const AchievementTask: React.FC<Props> = ({ uuid, filterStatus, focusState }) => {
const inferencer = useContext(AchievementContext);
const prerequisiteUuids = [...inferencer.getImmediateChildren(uuid)];
const taskColor = getAbilityColor();

const [isDropdownOpen, setIsDropdownOpen] = useState<boolean>(false);
const [isDropdownOpen, setIsDropdownOpen] = useState(false);
const toggleDropdown = () => setIsDropdownOpen(!isDropdownOpen);

/**
Expand Down
4 changes: 2 additions & 2 deletions src/commons/achievement/AchievementView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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<number, Assessment>;
userState?: [AchievementUser | undefined, any];
};

const AchievementView: React.FC<AchievementViewProps> = ({ focusUuid, userState }) => {
const AchievementView: React.FC<Props> = ({ focusUuid, userState }) => {
const assessmentId = !Number.isNaN(+focusUuid) && +focusUuid !== 0 ? +focusUuid : undefined;
let courseRegId: number | undefined;

Expand Down
8 changes: 4 additions & 4 deletions src/commons/achievement/card/AchievementDeadline.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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<AchievementDeadlineProps> = ({ deadline }) => {
const AchievementDeadline: React.FC<Props> = ({ deadline }) => {
// red deadline color for core achievements that are expiring in less than 2 days
const deadlineColor =
deadline !== undefined && !isExpired(deadline) && timeFromExpired(deadline) <= twoDays
Expand Down
12 changes: 6 additions & 6 deletions src/commons/achievement/card/AchievementXp.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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<AchievementXpProps> = ({ isBonus, xp }) => {
type Props = {
isBonus: boolean;
xp: number;
};

const AchievementXp: React.FC<Props> = ({ isBonus, xp }) => {
return (
<div className="xp">
{xp !== 0 && (
Expand Down
10 changes: 5 additions & 5 deletions src/commons/achievement/control/AchievementEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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<AchievementEditorProps> = ({ requestPublish }) => {
const AchievementEditor: React.FC<Props> = ({ requestPublish }) => {
const inferencer = useContext(AchievementContext);

/**
Expand All @@ -24,7 +24,7 @@ const AchievementEditor: React.FC<AchievementEditorProps> = ({ 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<string>('');
const [newUuid, setNewUuid] = useState('');
const allowNewUuid = newUuid === '';
const releaseUuid = () => setNewUuid('');

Expand Down
9 changes: 3 additions & 6 deletions src/commons/achievement/control/AchievementPreview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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<AchievementPreviewProps> = ({
awaitPublish,
publishChanges
}) => {
const AchievementPreview: React.FC<Props> = ({ awaitPublish, publishChanges }) => {
const inferencer = useContext(AchievementContext);

// Show AchievementView when viewMode is true, otherwise show AchievementTask
Expand All @@ -25,7 +22,7 @@ const AchievementPreview: React.FC<AchievementPreviewProps> = ({
* 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<string>('');
const focusState = useState('');
const [focusUuid] = focusState;

return (
Expand Down
Loading