diff --git a/frontend/.eslintrc b/frontend/.eslintrc index 5050a432..082220de 100644 --- a/frontend/.eslintrc +++ b/frontend/.eslintrc @@ -17,12 +17,17 @@ "ExportDeclaration": { "minProperties": 10, "multiline": true, "consistent": true } } ], + "react/prop-types": "off", + "react/jsx-props-no-spreading": "warn", "react/jsx-filename-extension": ["error", { "extensions": [".jsx", ".tsx"] }], - "import/extensions": [".js", ".mjs", ".jsx", ".ts", ".tsx"], + "react/state-in-constructor": "off", + "import/extensions": "off", "indent": "off", + "@typescript-eslint/ban-ts-ignore": "warn", "@typescript-eslint/indent": ["error", 2], "@typescript-eslint/prefer-interface": "off", "@typescript-eslint/explicit-function-return-type": ["error", { "allowExpressions": true }], + "@typescript-eslint/no-angle-bracket-type-assertion": "off", "@typescript-eslint/no-unused-vars": [ "error", { "vars": "all", "args": "after-used", "ignoreRestSiblings": true } diff --git a/frontend/package.json b/frontend/package.json index 0add4bf7..41635ceb 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -13,51 +13,51 @@ "check-all": "yarn tsc && yarn lint && yarn test" }, "dependencies": { - "@fortawesome/fontawesome-svg-core": "^1.2.17", - "@fortawesome/free-solid-svg-icons": "^5.8.1", + "@fortawesome/fontawesome-svg-core": "^1.2.22", + "@fortawesome/free-solid-svg-icons": "^5.10.2", "@fortawesome/react-fontawesome": "^0.1.4", - "firebase": "^5.11.1", + "firebase": "^6.4.2", "immutable": "^4.0.0-rc.12", - "react": "^16.8.6", - "react-beautiful-dnd": "^11.0.2", - "react-calendar": "^2.18.1", + "react": "^16.9.0", + "react-beautiful-dnd": "^11.0.5", + "react-calendar": "^2.19.1", "react-color": "^2.17.3", - "react-dev-utils": "^9.0.0", - "react-dom": "^16.8.6", - "react-dom-confetti": "^0.1.0", - "react-firebaseui": "^3.1.2", - "react-ga": "^2.5.7", + "react-dev-utils": "^9.0.3", + "react-dom": "^16.9.0", + "react-dom-confetti": "^0.1.1", + "react-firebaseui": "^4.0.0", + "react-ga": "^2.6.0", "react-live-clock": "^3.1.0", - "react-modal": "^3.8.1", - "react-redux": "^7.0.3", + "react-modal": "^3.10.1", + "react-redux": "^7.1.1", "react-search-box": "^2.0.1", - "react-toastify": "^5.1.0", - "redux": "^4.0.1", + "react-toastify": "^5.3.2", + "redux": "^4.0.4", "reselect": "^4.0.0" }, "devDependencies": { - "@types/jest": "^24.0.12", - "@types/node": "^11.13.9", - "@types/react": "^16.8.15", - "@types/react-beautiful-dnd": "^11.0.1", - "@types/react-color": "^3.0.0", - "@types/react-dom": "^16.8.4", + "@types/jest": "^24.0.18", + "@types/node": "^12.7.2", + "@types/react": "^16.9.2", + "@types/react-beautiful-dnd": "^11.0.3", + "@types/react-color": "^3.0.1", + "@types/react-dom": "^16.9.0", "@types/react-modal": "^3.8.2", - "@types/react-redux": "^7.0.8", - "@typescript-eslint/eslint-plugin": "^1.7.0", - "@typescript-eslint/parser": "^1.6.0", - "eslint": "^5.16.0", - "eslint-config-airbnb": "^17.1.0", - "eslint-config-react-app": "^4.0.0", - "eslint-plugin-import": "^2.17.2", - "eslint-plugin-jest": "^22.5.1", - "eslint-plugin-jsx-a11y": "^6.2.1", - "eslint-plugin-react": "^7.12.4", - "firebase-tools": "^6.8.0", + "@types/react-redux": "^7.1.2", + "@typescript-eslint/eslint-plugin": "^2.0.0", + "@typescript-eslint/parser": "^2.0.0", + "eslint": "^6.2.2", + "eslint-config-airbnb": "^18.0.1", + "eslint-config-react-app": "^5.0.1", + "eslint-plugin-import": "^2.18.2", + "eslint-plugin-jest": "^22.15.2", + "eslint-plugin-jsx-a11y": "^6.2.3", + "eslint-plugin-react": "^7.14.3", + "firebase-tools": "^7.3.0", "node-sass": "^4.12.0", - "react-scripts": "^3.0.0", - "svgo": "^1.2.2", - "typescript": "^3.4.5" + "react-scripts": "^3.1.1", + "svgo": "^1.3.0", + "typescript": "^3.6.2" }, "browserslist": { "production": [ diff --git a/frontend/src/components/TaskCreator/index.tsx b/frontend/src/components/TaskCreator/index.tsx index 3491a24d..410d53f9 100644 --- a/frontend/src/components/TaskCreator/index.tsx +++ b/frontend/src/components/TaskCreator/index.tsx @@ -54,6 +54,8 @@ const initialState = (): State => ({ export default class TaskCreator extends React.PureComponent<{}, State> { public readonly state: State = initialState(); + private addTask: HTMLInputElement | null | undefined; + /* * -------------------------------------------------------------------------------- * Part 1: Openers & Closers @@ -117,7 +119,7 @@ export default class TaskCreator extends React.PureComponent<{}, State> { return; } const newSubTasks = subTasks - .filter(subTask => subTask.name !== '') // remove empty subtasks + .filter((subTask) => subTask.name !== '') // remove empty subtasks // normalize orders: use current sequence as order;; remove useless id .map(({ id, ...rest }, order) => ({ ...rest, order })); const autoInFocus = inFocus || isToday(date); // Put task in focus is the due date is today. @@ -274,7 +276,7 @@ export default class TaskCreator extends React.PureComponent<{}, State> { private editSubTask = (subTaskId: string) => (e: SyntheticEvent) => { const name = e.currentTarget.value; this.setState(({ subTasks }: State) => ({ - subTasks: subTasks.map(s => (s.id === subTaskId ? { ...s, name } : s)), + subTasks: subTasks.map((s) => (s.id === subTaskId ? { ...s, name } : s)), })); }; @@ -298,7 +300,7 @@ export default class TaskCreator extends React.PureComponent<{}, State> { private deleteSubTask = (subtaskId: string) => (e: SyntheticEvent) => { e.preventDefault(); this.setState(({ subTasks }: State) => ({ - subTasks: subTasks.filter(s => s.id !== subtaskId), + subTasks: subTasks.filter((s) => s.id !== subtaskId), })); }; @@ -307,8 +309,6 @@ export default class TaskCreator extends React.PureComponent<{}, State> { */ private resetTask = () => this.setState({ ...initialState() }, this.focusTaskName); - private addTask: HTMLInputElement | null | undefined; - /** * Renders the editor for all the other info except main task name. * diff --git a/frontend/src/components/TaskView/FocusView/FocusTask.tsx b/frontend/src/components/TaskView/FocusView/FocusTask.tsx index 39f1435d..2e57a837 100644 --- a/frontend/src/components/TaskView/FocusView/FocusTask.tsx +++ b/frontend/src/components/TaskView/FocusView/FocusTask.tsx @@ -27,7 +27,7 @@ function FocusTask({ id, order, filterCompleted, original, filtered }: Props): R } return ( - {provided => ( + {(provided) => (
prevTasks.map(taskReplacer)); + setLocalTasks((prevTasks) => prevTasks.map(taskReplacer)); completeTaskInFocus(completedTaskIdOrder, localCompletedList); } else if ( source.droppableId === focusViewCompletedDroppableId @@ -101,7 +101,7 @@ function FocusView({ tasks, progress }: FocusViewProps): ReactElement { } }; - const onDoesShowCompletedTasksChange = (): void => setDoesShowCompletedTasks(prev => !prev); + const onDoesShowCompletedTasksChange = (): void => setDoesShowCompletedTasks((prev) => !prev); return (
@@ -113,7 +113,7 @@ function FocusView({ tasks, progress }: FocusViewProps): ReactElement {
- {provided => ( + {(provided) => (
{renderTaskList(localUncompletedList, false)} {provided.placeholder} @@ -121,7 +121,7 @@ function FocusView({ tasks, progress }: FocusViewProps): ReactElement { )} - {provided => ( + {(provided) => (
+ <> - + ); } diff --git a/frontend/src/components/TaskView/FutureView/FutureViewTask.tsx b/frontend/src/components/TaskView/FutureView/FutureViewTask.tsx index 4afbcedb..5c14f371 100644 --- a/frontend/src/components/TaskView/FutureView/FutureViewTask.tsx +++ b/frontend/src/components/TaskView/FutureView/FutureViewTask.tsx @@ -100,7 +100,7 @@ function FutureViewTask( ); }; - const renderMainTaskInfo = (simplified: boolean = false): ReactElement => { + const renderMainTaskInfo = (simplified = false): ReactElement => { if (simplified && isInMainList) { const style = { backgroundColor: color, height: '25px' }; return
; @@ -115,7 +115,7 @@ function FutureViewTask( ); }; - const renderSubTasks = (): ReactNode => filteredSubTasks.map(s => ( + const renderSubTasks = (): ReactNode => filteredSubTasks.map((s) => ( (futureViewConfigProvider.initialValue); - const screenIsSmall = useMappedWindowSize(size => size.width <= 840); - const toggleFocusViewInWideScreen = (): void => setDoesShowFocusViewInWideScreen(prev => !prev); - const switchView = (): void => setDoesShowFutureViewInSmallScreen(prev => !prev); + const screenIsSmall = useMappedWindowSize((size) => size.width <= 840); + const toggleFocusViewInWideScreen = (): void => setDoesShowFocusViewInWideScreen((prev) => !prev); + const switchView = (): void => setDoesShowFutureViewInSmallScreen((prev) => !prev); const FuturePanel = ({ children }: { readonly children?: ReactNode }): ReactElement => { const onChange = (c: FutureViewConfig): void => { setConfig(c); }; diff --git a/frontend/src/components/TitleBar/Onboarding/Onboard.tsx b/frontend/src/components/TitleBar/Onboarding/Onboard.tsx index 768723d9..57aa46fc 100644 --- a/frontend/src/components/TitleBar/Onboarding/Onboard.tsx +++ b/frontend/src/components/TitleBar/Onboarding/Onboard.tsx @@ -76,7 +76,7 @@ function AddClassOnBoarding({ classTags, showNext }: AddClassProps): ReactElemen
    - {classTags.map(tag => )} + {classTags.map((tag) => )}
@@ -150,14 +150,14 @@ function Onboard({ classTags, completedOnboarding }: Props): ReactElement | null return null; } - const showNext = (): void => setProgress(prev => prev + 1); + const showNext = (): void => setProgress((prev) => prev + 1); const showNextImport = (shouldImport: boolean): void => { if (shouldImport) { importCourseExams(); } showNext(); }; - const goBack = (): void => setProgress(prev => (prev > 1 ? prev - 1 : prev)); + const goBack = (): void => setProgress((prev) => (prev > 1 ? prev - 1 : prev)); const skipTutorial = (): void => setProgress(100); const onboardingContainerStyle: CSSProperties | undefined = progress > 0 @@ -180,7 +180,7 @@ function Onboard({ classTags, completedOnboarding }: Props): ReactElement | null const Connected = connect( ({ tags, settings: { completedOnboarding } }: State): Props => { - const classTags: Tag[] = Array.from(tags.values()).filter(t => t.classId != null); + const classTags: Tag[] = Array.from(tags.values()).filter((t) => t.classId != null); return { classTags, completedOnboarding }; }, )(Onboard); diff --git a/frontend/src/components/TitleBar/Tags/ClassTagAdder.tsx b/frontend/src/components/TitleBar/Tags/ClassTagAdder.tsx index fde4e090..f24b883c 100644 --- a/frontend/src/components/TitleBar/Tags/ClassTagAdder.tsx +++ b/frontend/src/components/TitleBar/Tags/ClassTagAdder.tsx @@ -73,7 +73,7 @@ function ClassTagAdder({ courses }: Props): ReactElement | null { name: value, color: getUnusedColor(), classId, }); // force the react search box to rerender due to its bug. - setKey(prev => prev + 1); + setKey((prev) => prev + 1); }; return (
diff --git a/frontend/src/components/TitleBar/Tags/ColorEditor.tsx b/frontend/src/components/TitleBar/Tags/ColorEditor.tsx index be9210e1..0d44b638 100644 --- a/frontend/src/components/TitleBar/Tags/ColorEditor.tsx +++ b/frontend/src/components/TitleBar/Tags/ColorEditor.tsx @@ -14,14 +14,14 @@ const colArray: string[] = Object.keys(colMap); export default function ColorEditor({ color, onChange }: Props): ReactElement { const [doesShowEditor, setDoesShowEditor] = React.useState(false); - const toggleEditor = (): void => setDoesShowEditor(s => !s); + const toggleEditor = (): void => setDoesShowEditor((s) => !s); const onChangeComplete = (e: { hex: string }): void => { onChange(e.hex); setDoesShowEditor(false); }; return ( - + <>
)} - + ); } diff --git a/frontend/src/components/TitleBar/Tags/rotation-color-picker.ts b/frontend/src/components/TitleBar/Tags/rotation-color-picker.ts index 1d5feb1d..6f5a3773 100644 --- a/frontend/src/components/TitleBar/Tags/rotation-color-picker.ts +++ b/frontend/src/components/TitleBar/Tags/rotation-color-picker.ts @@ -5,7 +5,7 @@ const allAvailableColors = Object.keys(colorMap); export default function getUnusedColor(): string { const { tags } = store.getState(); - const usedColorSet = new Set(Array.from(tags.values()).map(t => t.color)); - const color = allAvailableColors.find(c => !usedColorSet.has(c)); + const usedColorSet = new Set(Array.from(tags.values()).map((t) => t.color)); + const color = allAvailableColors.find((c) => !usedColorSet.has(c)); return color == null ? allAvailableColors[0] : color; } diff --git a/frontend/src/components/UI/CheckBox.test.tsx b/frontend/src/components/UI/CheckBox.test.tsx index 75583034..06ba0a5b 100644 --- a/frontend/src/components/UI/CheckBox.test.tsx +++ b/frontend/src/components/UI/CheckBox.test.tsx @@ -19,7 +19,7 @@ it('CheckBox can render', () => { function StatefulCheckBox({ disabled }: { readonly disabled: boolean }): ReactElement { const [checked, setChecked] = useState(false); - const onChange = (): void => setChecked(prev => !prev); + const onChange = (): void => setChecked((prev) => !prev); return ( ); diff --git a/frontend/src/components/UI/samwise-icon-types.tsx b/frontend/src/components/UI/samwise-icon-types.tsx index a0ea7d8f..bf675c89 100644 --- a/frontend/src/components/UI/samwise-icon-types.tsx +++ b/frontend/src/components/UI/samwise-icon-types.tsx @@ -1,4 +1,4 @@ -// eslint-disable-next-line import/prefer-default-export, reason: cannot export default type +// eslint-disable-next-line import/prefer-default-export export type IconName = | 'alert' | 'calendar-dark' diff --git a/frontend/src/components/Util/AppInit/LoginBarrier.tsx b/frontend/src/components/Util/AppInit/LoginBarrier.tsx index ff001683..f2235225 100644 --- a/frontend/src/components/Util/AppInit/LoginBarrier.tsx +++ b/frontend/src/components/Util/AppInit/LoginBarrier.tsx @@ -76,10 +76,10 @@ export default function LoginBarrier({ appRenderer }: Props): ReactElement { } const loadingOrLogin = loginStatus === false ? ( - + <>
- + ) : (

Loading...

); return ( diff --git a/frontend/src/components/Util/ErrorBoundary/index.tsx b/frontend/src/components/Util/ErrorBoundary/index.tsx index 6e02740a..d1d16499 100644 --- a/frontend/src/components/Util/ErrorBoundary/index.tsx +++ b/frontend/src/components/Util/ErrorBoundary/index.tsx @@ -12,13 +12,13 @@ export default class ErrorBoundary extends React.PureComponent { return { hasError: true }; } - private ignoreError = (): void => this.setState({ hasError: false }); - public componentDidCatch(error: Error | null, info: object): void { // eslint-disable-next-line no-console console.log({ error, info }); // necessary for error logging! } + private ignoreError = (): void => this.setState({ hasError: false }); + public render(): ReactElement { const { children } = this.props; const { hasError } = this.state; @@ -54,7 +54,7 @@ export default class ErrorBoundary extends React.PureComponent { style={{ color: 'white', textDecoration: 'underline' }} href="https://goo.gl/forms/PZUZ1Ze6kN82EmcD2" > - Send Feedback + Send Feedback