From 550f00b93c03a9ad98ef9bb1197c0fbfd5b1e572 Mon Sep 17 00:00:00 2001 From: eug-vs Date: Sat, 21 Mar 2020 14:17:58 +0300 Subject: chore!: migrate index.js -> index.tsx --- src/index.js | 87 ----------------------------------------------- src/index.tsx | 91 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/react-app-env.d.ts | 1 + 3 files changed, 92 insertions(+), 87 deletions(-) delete mode 100644 src/index.js create mode 100644 src/index.tsx create mode 100644 src/react-app-env.d.ts (limited to 'src') diff --git a/src/index.js b/src/index.js deleted file mode 100644 index 49c66e7..0000000 --- a/src/index.js +++ /dev/null @@ -1,87 +0,0 @@ -import React, { useState, useEffect } from 'react'; -import ReactDOM from 'react-dom'; - -import { - BenzinThemeProvider, - Header, -} from 'react-benzin'; - -import 'typeface-roboto'; - -import Timer from './pages/Timer/Timer'; -import Scoreboard from './pages/Scoreboard/Scoreboard'; -import Contribute from './pages/Contribute/Contribute'; -import Profile from './pages/Profile/Profile'; - -import TimerIcon from '@material-ui/icons/Timer'; -import AccountCircleIcon from '@material-ui/icons/AccountCircle'; -import AssignmentIcon from '@material-ui/icons/Assignment'; -import GitHubIcon from '@material-ui/icons/GitHub'; - -import { get } from './requests'; - - -const App = () => { - - const [page, setPage] = useState('app'); - const [user, setUser] = useState({ username: 'anonymous', id: null }); - const [recentSolutions, setRecentSolutions] = useState([]); - - const headerContents = { - app: (), - profile: (), - scoreboard: (), - contribute: (), - }; - - useEffect(() => { - const userId = +localStorage.getItem('userId'); - if (userId) { - get('users/').then(response => { - setUser(response.data.filter(user => user.id === +userId)[0]); - }); - } - }, []); - - const Page = ({ page }) => { - switch (page) { - case 'app': - return ( - - ); - - case 'profile': - return ; - - case 'scoreboard': - return ; - - case 'contribute': - return ; - - default: - return ; - } - }; - - return ( - -
- - - ); -}; - -document.body.style.overflow = 'hidden'; -ReactDOM.render(, document.getElementById('root')); diff --git a/src/index.tsx b/src/index.tsx new file mode 100644 index 0000000..eb43b7e --- /dev/null +++ b/src/index.tsx @@ -0,0 +1,91 @@ +import React, { useState, useEffect } from 'react'; +import ReactDOM from 'react-dom'; + +import { + BenzinThemeProvider, + Header, +} from 'react-benzin'; + +import 'typeface-roboto'; + +import Timer from './pages/Timer/Timer'; +import Scoreboard from './pages/Scoreboard/Scoreboard'; +import Contribute from './pages/Contribute/Contribute'; +import Profile from './pages/Profile/Profile'; + +import TimerIcon from '@material-ui/icons/Timer'; +import AccountCircleIcon from '@material-ui/icons/AccountCircle'; +import AssignmentIcon from '@material-ui/icons/Assignment'; +import GitHubIcon from '@material-ui/icons/GitHub'; + +import { get } from './requests'; + +interface User { + username: string; + id: number | null; +} + +const App: React.FC = () => { + const [page, setPage] = useState('app'); + const [user, setUser] = useState({ username: 'anonymous', id: null }); + const [recentSolutions, setRecentSolutions] = useState([]); + + const headerContents = { + app: (), + profile: (), + scoreboard: (), + contribute: (), + }; + + useEffect(() => { + const userId = localStorage.getItem('userId'); + if (userId) { + get('users/').then(response => { + setUser(response.data.filter((user: User) => user.id === +userId)[0]); + }); + } + }, []); + + const Page: React.FC<{ page: string }> = ({ page }) => { + switch (page) { + case 'app': + return ( + + ); + + case 'profile': + return ; + + case 'scoreboard': + return ; + + case 'contribute': + return ; + + default: + return ; + } + }; + + return ( + +
+ + + ); +}; + +document.body.style.overflow = 'hidden'; +ReactDOM.render(, document.getElementById('root')); diff --git a/src/react-app-env.d.ts b/src/react-app-env.d.ts new file mode 100644 index 0000000..6431bc5 --- /dev/null +++ b/src/react-app-env.d.ts @@ -0,0 +1 @@ +/// -- cgit v1.2.3 From f4d8ee37400f25d4fec3638b1ba73e8661c30959 Mon Sep 17 00:00:00 2001 From: eug-vs Date: Sat, 21 Mar 2020 14:29:05 +0300 Subject: feat: add types.d.ts, migrate Scoreboard --- src/index.tsx | 7 +--- src/pages/Scoreboard/Scoreboard.js | 68 --------------------------------- src/pages/Scoreboard/Scoreboard.tsx | 76 +++++++++++++++++++++++++++++++++++++ src/types.d.ts | 12 ++++++ 4 files changed, 90 insertions(+), 73 deletions(-) delete mode 100644 src/pages/Scoreboard/Scoreboard.js create mode 100644 src/pages/Scoreboard/Scoreboard.tsx create mode 100644 src/types.d.ts (limited to 'src') diff --git a/src/index.tsx b/src/index.tsx index eb43b7e..360ca89 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -5,6 +5,7 @@ import { BenzinThemeProvider, Header, } from 'react-benzin'; +import { User, Solution } from './types'; import 'typeface-roboto'; @@ -20,15 +21,11 @@ import GitHubIcon from '@material-ui/icons/GitHub'; import { get } from './requests'; -interface User { - username: string; - id: number | null; -} const App: React.FC = () => { const [page, setPage] = useState('app'); const [user, setUser] = useState({ username: 'anonymous', id: null }); - const [recentSolutions, setRecentSolutions] = useState([]); + const [recentSolutions, setRecentSolutions] = useState([]); const headerContents = { app: (), diff --git a/src/pages/Scoreboard/Scoreboard.js b/src/pages/Scoreboard/Scoreboard.js deleted file mode 100644 index 47c0899..0000000 --- a/src/pages/Scoreboard/Scoreboard.js +++ /dev/null @@ -1,68 +0,0 @@ -import React, { useEffect, useState } from 'react'; - -import { makeStyles } from '@material-ui/core/styles'; - -import { Window, SmartList } from 'react-benzin'; - -import SolutionCard from '../../components/SolutionCard/SolutionCard'; -import Loading from '../../components/Loading/Loading'; - -import { get } from '../../requests'; - - -const useStyles = makeStyles(theme => ({ - cell: { - display: 'flex', - justifyContent: 'center', - padding: theme.spacing(4), - - '& .MuiCard-root': { - width: '30%', - } - } -})); - -const Scoreboard = () => { - const classes = useStyles(); - const [solutions, setSolutions] = useState([]); - - const updateSolutions = () => { - get('scoreboard/').then(response => { - setSolutions(response.data); - }); - }; - - const removeSolution = id => { - updateSolutions(); - }; - - useEffect(() => { - setTimeout(updateSolutions, 300); - }, []); - - const renderItem = ({ index, style }) => { - return ( -
- -
- ) - }; - - return ( - - { solutions.length === 0 && -
- -
- } - -
- ) -}; - - -export default Scoreboard; diff --git a/src/pages/Scoreboard/Scoreboard.tsx b/src/pages/Scoreboard/Scoreboard.tsx new file mode 100644 index 0000000..c6826d2 --- /dev/null +++ b/src/pages/Scoreboard/Scoreboard.tsx @@ -0,0 +1,76 @@ +import React, { useEffect, useState } from 'react'; + +import { makeStyles } from '@material-ui/core/styles'; + +import { Window, SmartList } from 'react-benzin'; +import { Solution } from '../../types'; + +import SolutionCard from '../../components/SolutionCard/SolutionCard'; +import Loading from '../../components/Loading/Loading'; + +import { get } from '../../requests'; + + +const useStyles = makeStyles(theme => ({ + cell: { + display: 'flex', + justifyContent: 'center', + padding: theme.spacing(4), + + '& .MuiCard-root': { + width: '30%', + } + } +})); + + +interface RenderPropTypes { + index: number; + style: React.CSSProperties; +} + + +const Scoreboard: React.FC = () => { + const classes = useStyles(); + const [solutions, setSolutions] = useState([]); + + const updateSolutions = () => { + get('scoreboard/').then(response => { + setSolutions(response.data); + }); + }; + + const removeSolution = (id: number) => { + updateSolutions(); + }; + + useEffect(() => { + setTimeout(updateSolutions, 300); + }, []); + + const renderItem: React.FC = ({ index, style }) => { + return ( +
+ +
+ ) + }; + + return ( + + { solutions.length === 0 && +
+ +
+ } + +
+ ) +}; + + +export default Scoreboard; diff --git a/src/types.d.ts b/src/types.d.ts new file mode 100644 index 0000000..cfc60bc --- /dev/null +++ b/src/types.d.ts @@ -0,0 +1,12 @@ +export interface User { + username: string; + id: number | null; +} + +export interface Solution { + id: number; + result: string; + date: string; + author: User; +} + -- cgit v1.2.3 From bfc2a9bc3c1ecbef31e76e36fed79a8500f0d0fd Mon Sep 17 00:00:00 2001 From: eug-vs Date: Sat, 21 Mar 2020 14:32:21 +0300 Subject: chore: migrate Contribute page --- src/pages/Contribute/Contribute.js | 157 ----------------------------------- src/pages/Contribute/Contribute.tsx | 158 ++++++++++++++++++++++++++++++++++++ src/types.d.ts | 4 + 3 files changed, 162 insertions(+), 157 deletions(-) delete mode 100644 src/pages/Contribute/Contribute.js create mode 100644 src/pages/Contribute/Contribute.tsx (limited to 'src') diff --git a/src/pages/Contribute/Contribute.js b/src/pages/Contribute/Contribute.js deleted file mode 100644 index aa1c3f7..0000000 --- a/src/pages/Contribute/Contribute.js +++ /dev/null @@ -1,157 +0,0 @@ -import React from 'react'; - -import { - Typography, - Button, - List, - ListItem, - Link, - Avatar, - Divider, - makeStyles, -} from '@material-ui/core'; - -import TrendingUpIcon from '@material-ui/icons/TrendingUp'; -import BugReportIcon from '@material-ui/icons/BugReport'; -import NewReleasesIcon from '@material-ui/icons/NewReleases'; - -import { Window, ContentSection } from 'react-benzin'; - - -const useStyles = makeStyles(theme => ({ - mono: { - padding: theme.spacing(4), - - '& .MuiAvatar-root': { - marginRight: theme.spacing(2), - width: theme.spacing(6), - height: theme.spacing(6), - } - }, -})); - - -const developers = require('../../developers.json'); - - -const Contribute = () => { - const classes = useStyles(); - - return ( - -
- -

- ChronoCube is an Open-Source application, and we welcome anyone who desires to help our project! -

- -
- -

We only use modern and most relevant technologies to achieve the best results!

-
    -
  • - Django REST Framework -
  • -
  • - React.js -
  • -
  • - Material UI components -
  • -
-

Special thanks to other Open-Source projects which made ChronoCube possible:

-
    -
  • - react-window -
  • -
-
- -

Thank You for considering helping our project!

-

- All the development process is being tracked on - the KanBan board. - You can always check it to see what is the current state of the project. - To contribute your code, fork our repository and then open - a - Pull Request. We will carefully review and, hopefully, accept it! - If you are unfamiliar with this kind of workflow, we recommend - reading GitHub guidelines. -

-

- We always welcome newcomers! If you are unfamiliar with certain technologies or even with the - development in general, it is great time to start learning something new! - Our community will kindly assist every your step, and with us you can easily become - highly-evaluated developer! -

- - -
- - - { - developers.map(developer => { - const githubUrl = `https://github.com/${developer.username}`; - - return ( -
- - - - -
- - {developer.username} - - - {developer.role} - -
-
- -
- ) - }) - } - - - You can be here! - -
- -
-
-
- ); -}; - - -export default Contribute; diff --git a/src/pages/Contribute/Contribute.tsx b/src/pages/Contribute/Contribute.tsx new file mode 100644 index 0000000..854c5c1 --- /dev/null +++ b/src/pages/Contribute/Contribute.tsx @@ -0,0 +1,158 @@ +import React from 'react'; + +import { + Typography, + Button, + List, + ListItem, + Link, + Avatar, + Divider, + makeStyles, +} from '@material-ui/core'; + +import TrendingUpIcon from '@material-ui/icons/TrendingUp'; +import BugReportIcon from '@material-ui/icons/BugReport'; +import NewReleasesIcon from '@material-ui/icons/NewReleases'; + +import { Window, ContentSection } from 'react-benzin'; +import { Developer } from '../../types'; + + +const useStyles = makeStyles(theme => ({ + mono: { + padding: theme.spacing(4), + + '& .MuiAvatar-root': { + marginRight: theme.spacing(2), + width: theme.spacing(6), + height: theme.spacing(6), + } + }, +})); + + +const developers: Developer[] = require('../../developers.json'); + + +const Contribute: React.FC = () => { + const classes = useStyles(); + + return ( + +
+ +

+ ChronoCube is an Open-Source application, and we welcome anyone who desires to help our project! +

+ +
+ +

We only use modern and most relevant technologies to achieve the best results!

+
    +
  • + Django REST Framework +
  • +
  • + React.js +
  • +
  • + Material UI components +
  • +
+

Special thanks to other Open-Source projects which made ChronoCube possible:

+
    +
  • + react-window +
  • +
+
+ +

Thank You for considering helping our project!

+

+ All the development process is being tracked on + the KanBan board. + You can always check it to see what is the current state of the project. + To contribute your code, fork our repository and then open + a + Pull Request. We will carefully review and, hopefully, accept it! + If you are unfamiliar with this kind of workflow, we recommend + reading GitHub guidelines. +

+

+ We always welcome newcomers! If you are unfamiliar with certain technologies or even with the + development in general, it is great time to start learning something new! + Our community will kindly assist every your step, and with us you can easily become + highly-evaluated developer! +

+ + +
+ + + { + developers.map(developer => { + const githubUrl = `https://github.com/${developer.username}`; + + return ( +
+ + + + +
+ + {developer.username} + + + {developer.role} + +
+
+ +
+ ) + }) + } + + + You can be here! + +
+ +
+
+
+ ); +}; + + +export default Contribute; diff --git a/src/types.d.ts b/src/types.d.ts index cfc60bc..fb3d86e 100644 --- a/src/types.d.ts +++ b/src/types.d.ts @@ -10,3 +10,7 @@ export interface Solution { author: User; } +export interface Developer { + username: string; + role: string; +} -- cgit v1.2.3 From e32c8be0a4b7f135c01449c3603da347728819a8 Mon Sep 17 00:00:00 2001 From: eug-vs Date: Sat, 21 Mar 2020 14:35:19 +0300 Subject: chore: migrate requests.ts --- src/requests.js | 24 ------------------------ src/requests.ts | 24 ++++++++++++++++++++++++ 2 files changed, 24 insertions(+), 24 deletions(-) delete mode 100644 src/requests.js create mode 100644 src/requests.ts (limited to 'src') diff --git a/src/requests.js b/src/requests.js deleted file mode 100644 index ad45dcf..0000000 --- a/src/requests.js +++ /dev/null @@ -1,24 +0,0 @@ -import axios from 'axios' - -const baseUrl = 'https://eugvs.pythonanywhere.com/'; -const baseApiUrl = baseUrl + 'api/'; - -export const get = (url) => { - return axios.get( - baseApiUrl + url, - ); -}; - -export const post = (url, data) => { - return axios.post( - baseApiUrl + url, - data - ); -}; - -export const del = (url, data) => { - return axios.delete( - baseApiUrl + url, - data - ) -}; diff --git a/src/requests.ts b/src/requests.ts new file mode 100644 index 0000000..eeb2ee7 --- /dev/null +++ b/src/requests.ts @@ -0,0 +1,24 @@ +import axios from 'axios' + +const baseUrl = 'https://eugvs.pythonanywhere.com/'; +const baseApiUrl = baseUrl + 'api/'; + +export const get = (url: string) => { + return axios.get( + baseApiUrl + url, + ); +}; + +export const post = (url: string, data: object) => { + return axios.post( + baseApiUrl + url, + data + ); +}; + +export const del = (url: string, data: object) => { + return axios.delete( + baseApiUrl + url, + data + ) +}; -- cgit v1.2.3 From f3a684937565f3bd94034f3389aa95fea908f0c4 Mon Sep 17 00:00:00 2001 From: eug-vs Date: Sat, 21 Mar 2020 15:06:30 +0300 Subject: chore: fix linting errors :rotating_light: --- src/pages/Contribute/Contribute.tsx | 3 +-- src/pages/Scoreboard/Scoreboard.tsx | 4 ++-- src/requests.ts | 8 ++++---- src/types.d.ts | 4 ---- 4 files changed, 7 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/src/pages/Contribute/Contribute.tsx b/src/pages/Contribute/Contribute.tsx index 854c5c1..4c37fb9 100644 --- a/src/pages/Contribute/Contribute.tsx +++ b/src/pages/Contribute/Contribute.tsx @@ -16,8 +16,8 @@ import BugReportIcon from '@material-ui/icons/BugReport'; import NewReleasesIcon from '@material-ui/icons/NewReleases'; import { Window, ContentSection } from 'react-benzin'; -import { Developer } from '../../types'; +import developers from '../../developers.json'; const useStyles = makeStyles(theme => ({ mono: { @@ -32,7 +32,6 @@ const useStyles = makeStyles(theme => ({ })); -const developers: Developer[] = require('../../developers.json'); const Contribute: React.FC = () => { diff --git a/src/pages/Scoreboard/Scoreboard.tsx b/src/pages/Scoreboard/Scoreboard.tsx index c6826d2..9b9ee01 100644 --- a/src/pages/Scoreboard/Scoreboard.tsx +++ b/src/pages/Scoreboard/Scoreboard.tsx @@ -34,13 +34,13 @@ const Scoreboard: React.FC = () => { const classes = useStyles(); const [solutions, setSolutions] = useState([]); - const updateSolutions = () => { + const updateSolutions = (): void => { get('scoreboard/').then(response => { setSolutions(response.data); }); }; - const removeSolution = (id: number) => { + const removeSolution = (id: number): void => { updateSolutions(); }; diff --git a/src/requests.ts b/src/requests.ts index eeb2ee7..961d8d6 100644 --- a/src/requests.ts +++ b/src/requests.ts @@ -1,22 +1,22 @@ -import axios from 'axios' +import axios, { AxiosResponse } from 'axios'; const baseUrl = 'https://eugvs.pythonanywhere.com/'; const baseApiUrl = baseUrl + 'api/'; -export const get = (url: string) => { +export const get = (url: string): Promise => { return axios.get( baseApiUrl + url, ); }; -export const post = (url: string, data: object) => { +export const post = (url: string, data: object): Promise => { return axios.post( baseApiUrl + url, data ); }; -export const del = (url: string, data: object) => { +export const del = (url: string, data: object): Promise => { return axios.delete( baseApiUrl + url, data diff --git a/src/types.d.ts b/src/types.d.ts index fb3d86e..cfc60bc 100644 --- a/src/types.d.ts +++ b/src/types.d.ts @@ -10,7 +10,3 @@ export interface Solution { author: User; } -export interface Developer { - username: string; - role: string; -} -- cgit v1.2.3 From 2ca9cbb36e25e280a1b26c9dc03eaea30e1dcc9d Mon Sep 17 00:00:00 2001 From: eug-vs Date: Sat, 21 Mar 2020 15:20:41 +0300 Subject: refactor: improve requests.ts --- src/requests.ts | 21 ++++----------------- 1 file changed, 4 insertions(+), 17 deletions(-) (limited to 'src') diff --git a/src/requests.ts b/src/requests.ts index 961d8d6..0242ed5 100644 --- a/src/requests.ts +++ b/src/requests.ts @@ -3,22 +3,9 @@ import axios, { AxiosResponse } from 'axios'; const baseUrl = 'https://eugvs.pythonanywhere.com/'; const baseApiUrl = baseUrl + 'api/'; -export const get = (url: string): Promise => { - return axios.get( - baseApiUrl + url, - ); -}; +export const get = (url: string): Promise => axios.get(baseApiUrl + url); -export const post = (url: string, data: object): Promise => { - return axios.post( - baseApiUrl + url, - data - ); -}; +export const del = (url: string): Promise => axios.delete(baseApiUrl + url); + +export const post = (url: string, data: object): Promise => axios.post(baseApiUrl + url, data); -export const del = (url: string, data: object): Promise => { - return axios.delete( - baseApiUrl + url, - data - ) -}; -- cgit v1.2.3 From 2e9e20414c2ea49d7f40bcff09b89897e13fd2f4 Mon Sep 17 00:00:00 2001 From: eug-vs Date: Sat, 21 Mar 2020 15:32:02 +0300 Subject: chore: migrate components to Typescript --- src/components/Loading/Loading.js | 33 -------- src/components/Loading/Loading.tsx | 33 ++++++++ src/components/SolutionCard/SolutionCard.js | 114 ------------------------- src/components/SolutionCard/SolutionCard.tsx | 122 +++++++++++++++++++++++++++ 4 files changed, 155 insertions(+), 147 deletions(-) delete mode 100644 src/components/Loading/Loading.js create mode 100644 src/components/Loading/Loading.tsx delete mode 100644 src/components/SolutionCard/SolutionCard.js create mode 100644 src/components/SolutionCard/SolutionCard.tsx (limited to 'src') diff --git a/src/components/Loading/Loading.js b/src/components/Loading/Loading.js deleted file mode 100644 index e8793cc..0000000 --- a/src/components/Loading/Loading.js +++ /dev/null @@ -1,33 +0,0 @@ -import React from 'react'; - -import { - Card, - CardHeader, -} from '@material-ui/core'; - -import { makeStyles } from '@material-ui/core/styles'; -import CircularProgress from '@material-ui/core/CircularProgress'; - - -const useStyles = makeStyles(theme => ({ - root: { - padding: theme.spacing(1), - background: theme.palette.background.elevation2, - }, -})); - -const Loading = () => { - const classes = useStyles(); - - return ( - - )} - title="Loading" - subheader="Please, wait." - /> - - ) -}; - -export default Loading; diff --git a/src/components/Loading/Loading.tsx b/src/components/Loading/Loading.tsx new file mode 100644 index 0000000..a784be1 --- /dev/null +++ b/src/components/Loading/Loading.tsx @@ -0,0 +1,33 @@ +import React from 'react'; + +import { + Card, + CardHeader, +} from '@material-ui/core'; + +import { makeStyles } from '@material-ui/core/styles'; +import CircularProgress from '@material-ui/core/CircularProgress'; + + +const useStyles = makeStyles(theme => ({ + root: { + padding: theme.spacing(1), + background: theme.palette.background.elevation2, + }, +})); + +const Loading: React.FC = () => { + const classes = useStyles(); + + return ( + + )} + title="Loading" + subheader="Please, wait." + /> + + ) +}; + +export default Loading; diff --git a/src/components/SolutionCard/SolutionCard.js b/src/components/SolutionCard/SolutionCard.js deleted file mode 100644 index fdd4bdf..0000000 --- a/src/components/SolutionCard/SolutionCard.js +++ /dev/null @@ -1,114 +0,0 @@ -import React, { useState } from 'react'; - -import { - Typography, - Card, - CardHeader, - CardContent, - IconButton, - Avatar, - Grid, - Menu, - MenuItem, -} from '@material-ui/core'; - -import { makeStyles } from '@material-ui/core/styles'; -import TimerIcon from '@material-ui/icons/Timer'; -import MoreVertIcon from '@material-ui/icons/MoreVert'; -import DeleteIcon from '@material-ui/icons/Delete'; - -import { del } from '../../requests'; - - -const DATE_FORMAT = { - month: 'long', - day: 'numeric', - year: 'numeric', - hour: '2-digit', - minute: '2-digit', -}; - -const useStyles = makeStyles(theme => ({ - root: { - padding: theme.spacing(1), - background: theme.palette.background.elevation2, - - '& .MuiTypography-h3': { - margin: theme.spacing(2), - }, - }, - menu: { - '& ul': { - background: theme.palette.background.elevation3, - } - }, -})); - -const SolutionCard = ({ data, removeThisCard }) => { - const classes = useStyles(); - const [anchorEl, setAnchorEl] = useState(null); - - const author = data.author? data.author.username : 'anonymous'; - const date = new Date(data.date); - - const handleOpenMenu = event => { - setAnchorEl(event.currentTarget); - }; - - const handleClose = () => { - setAnchorEl(null); - }; - - const handleDelete = () => { - del(`solutions/${data.id}/`).then(() => { - removeThisCard(data.id); - }); - handleClose(); - }; - - return ( - - ) - : - ({author[0].toUpperCase()}) - } - title={author} - subheader={date.toLocaleString('default', DATE_FORMAT)} - action={( - - - - )} - /> - - - - Delete - - - - - - - - - - { data.result } - - - - - - ) -}; - -export default SolutionCard; diff --git a/src/components/SolutionCard/SolutionCard.tsx b/src/components/SolutionCard/SolutionCard.tsx new file mode 100644 index 0000000..5adbff9 --- /dev/null +++ b/src/components/SolutionCard/SolutionCard.tsx @@ -0,0 +1,122 @@ +import React, { useState } from 'react'; + +import { + Typography, + Card, + CardHeader, + CardContent, + IconButton, + Avatar, + Grid, + Menu, + MenuItem, +} from '@material-ui/core'; +import { Solution } from '../../types'; + +import { makeStyles } from '@material-ui/core/styles'; +import TimerIcon from '@material-ui/icons/Timer'; +import MoreVertIcon from '@material-ui/icons/MoreVert'; +import DeleteIcon from '@material-ui/icons/Delete'; + +import { del } from '../../requests'; + + +const DATE_FORMAT = { + month: 'long', + day: 'numeric', + year: 'numeric', + hour: '2-digit', + minute: '2-digit', +}; + +const useStyles = makeStyles(theme => ({ + root: { + padding: theme.spacing(1), + background: theme.palette.background.elevation2, + + '& .MuiTypography-h3': { + margin: theme.spacing(2), + }, + }, + menu: { + '& ul': { + background: theme.palette.background.elevation3, + } + }, +})); + + +interface PropTypes { + data: Solution; + removeThisCard: (id: number) => void; +} + + +const SolutionCard: React.FC = ({ data, removeThisCard }) => { + const classes = useStyles(); + const [anchorEl, setAnchorEl] = useState(null); + + const author = data.author? data.author.username : 'anonymous'; + const date = new Date(data.date); + + const handleOpenMenu = (event: React.MouseEvent): void => { + setAnchorEl(event.currentTarget); + }; + + const handleClose = (): void => { + setAnchorEl(null); + }; + + const handleDelete = (): void => { + del(`solutions/${data.id}/`).then(() => { + removeThisCard(data.id); + }); + handleClose(); + }; + + return ( + + ) + : + ({author[0].toUpperCase()}) + } + title={author} + subheader={date.toLocaleString('default', DATE_FORMAT)} + action={ + + + + } + /> + + + + Delete + + + + + + + + + + { data.result } + + + + + + ) +}; + +export default SolutionCard; -- cgit v1.2.3 From 146947a665dbc1d2960d2062a22a106de0c71062 Mon Sep 17 00:00:00 2001 From: eug-vs Date: Sat, 21 Mar 2020 15:44:40 +0300 Subject: chore: migrate profile page to Typescript :label: --- src/pages/Profile/Profile.js | 88 ------------------------ src/pages/Profile/Profile.tsx | 95 ++++++++++++++++++++++++++ src/pages/Profile/Registration.tsx | 85 +++++++++++++++++++++++ src/pages/Profile/Registration/Registration.js | 80 ---------------------- src/pages/Scoreboard/Scoreboard.tsx | 8 +-- src/types.d.ts | 5 ++ 6 files changed, 186 insertions(+), 175 deletions(-) delete mode 100644 src/pages/Profile/Profile.js create mode 100644 src/pages/Profile/Profile.tsx create mode 100644 src/pages/Profile/Registration.tsx delete mode 100644 src/pages/Profile/Registration/Registration.js (limited to 'src') diff --git a/src/pages/Profile/Profile.js b/src/pages/Profile/Profile.js deleted file mode 100644 index 65c3734..0000000 --- a/src/pages/Profile/Profile.js +++ /dev/null @@ -1,88 +0,0 @@ -import React, { useState, useEffect } from 'react'; - -import { - Button, - makeStyles, -} from '@material-ui/core'; - -import Registration from './Registration/Registration'; -import { - Window, - ContentSection, - SmartList, -} from 'react-benzin'; - -import SolutionCard from '../../components/SolutionCard/SolutionCard'; - -import { get } from '../../requests'; - - -const useStyles = makeStyles(theme => ({ - primary: { - padding: theme.spacing(4), - }, - cell: { - padding: theme.spacing(5), - }, -})); - - -const Profile = ({ user, setUser }) => { - const classes = useStyles(); - - const [profileSolutions, setProfileSolutions] = useState([]); - - const handleLogout = () => { - setUser({ username: 'anonymous', id: null }); - localStorage.clear(); - }; - - useEffect(() => { - get(`solutions/?author=${user.id}`).then(response => { - setProfileSolutions(response.data.reverse()); - }); - }, [user]); - - const removeSolution = (id) => { - setProfileSolutions(profileSolutions.filter((solution => solution.id !== id))); - }; - - const renderItem = ({ index, style }) => { - return ( -
- -
- ); - }; - - return ( - <> - -
- { user.id? ( - -

Total amount of solutions: {profileSolutions.length}

-

You can always log out from your account!

- -
- ): ( - - ) - } -
-
- - - - - ) -}; - - -export default Profile; diff --git a/src/pages/Profile/Profile.tsx b/src/pages/Profile/Profile.tsx new file mode 100644 index 0000000..bbf55f1 --- /dev/null +++ b/src/pages/Profile/Profile.tsx @@ -0,0 +1,95 @@ +import React, { useState, useEffect } from 'react'; + +import { + Button, + makeStyles, +} from '@material-ui/core'; + +import Registration from './Registration'; +import { + Window, + ContentSection, + SmartList, +} from 'react-benzin'; +import { User, Solution, RenderPropTypes } from '../../types'; + +import SolutionCard from '../../components/SolutionCard/SolutionCard'; + +import { get } from '../../requests'; + + +const useStyles = makeStyles(theme => ({ + primary: { + padding: theme.spacing(4), + }, + cell: { + padding: theme.spacing(5), + }, +})); + + +interface PropTypes { + user: User; + setUser: (user: User) => void; +} + + +const Profile: React.FC = ({ user, setUser }) => { + const classes = useStyles(); + + const [profileSolutions, setProfileSolutions] = useState([]); + + const handleLogout = () => { + setUser({ username: 'anonymous', id: null }); + localStorage.clear(); + }; + + useEffect(() => { + get(`solutions/?author=${user.id}`).then(response => { + setProfileSolutions(response.data.reverse()); + }); + }, [user]); + + const removeSolution = (id: number): void => { + setProfileSolutions(profileSolutions.filter((solution => solution.id !== id))); + }; + + const renderItem: React.FC = ({ index, style }) => { + return ( +
+ +
+ ); + }; + + return ( + <> + +
+ { user.id? ( + +

Total amount of solutions: {profileSolutions.length}

+

You can always log out from your account!

+ +
+ ): ( + + ) + } +
+
+ + + + + ) +}; + + +export default Profile; diff --git a/src/pages/Profile/Registration.tsx b/src/pages/Profile/Registration.tsx new file mode 100644 index 0000000..30e357d --- /dev/null +++ b/src/pages/Profile/Registration.tsx @@ -0,0 +1,85 @@ +import React, {useState} from 'react'; + +import { + TextField, + Button, + Checkbox, + FormControlLabel, + Grid, +} from '@material-ui/core'; +import { User } from '../../types'; + +import { ContentSection } from 'react-benzin'; +import { get, post } from '../../requests'; + + +interface PropTypes { + setUser: (user: User) => void; +} + +const Registration: React.FC = ({ setUser }) => { + + const [username, setUsername] = useState(''); + const [isRememberMe, setIsRememberMe] = useState(false); + + const handleChange = (event: React.ChangeEvent): void => { + setUsername(event.target.value); + }; + + const handleCheck = (event: React.ChangeEvent): void => { + setIsRememberMe(event.target.checked); + }; + + const handleSubmit = () => { + if (username !== '') { + post('users/', { username }) + .then(response => { + const user = response.data; + setUser(user); + if (isRememberMe) { + localStorage.setItem('userId', user.id); + } + }) + .catch(err => { + get('users/').then(response => { + const user = response.data.filter((user: User) => user.username === username)[0]; + setUser(user); + if (isRememberMe) { + localStorage.setItem('userId', user.id); + } + }); + }); + } + }; + + return ( + +

Choose yourself a username to track your progress and compete with others:

+ + + + + + } + label="Remember me" + /> + + + + + +
+ ); +}; + + +export default Registration; diff --git a/src/pages/Profile/Registration/Registration.js b/src/pages/Profile/Registration/Registration.js deleted file mode 100644 index b2d5503..0000000 --- a/src/pages/Profile/Registration/Registration.js +++ /dev/null @@ -1,80 +0,0 @@ -import React, {useState} from 'react'; - -import { - TextField, - Button, - Checkbox, - FormControlLabel, - Grid, -} from '@material-ui/core'; - -import { ContentSection } from 'react-benzin'; -import { get, post } from '../../../requests'; - - -const Registration = ({ setUser }) => { - - const [username, setUsername] = useState(''); - const [isRememberMe, setIsRememberMe] = useState(false); - - const handleChange = (event) => { - setUsername(event.target.value); - }; - - const handleCheck = (event) => { - setIsRememberMe(event.target.checked); - }; - - const handleSubmit = () => { - if (username !== '') { - post('users/', { username }) - .then(response => { - const user = response.data; - setUser(user); - if (isRememberMe) { - localStorage.setItem('userId', user.id); - } - }) - .catch(err => { - get('users/').then(response => { - const user = response.data.filter(user => user.username === username)[0]; - setUser(user); - if (isRememberMe) { - localStorage.setItem('userId', user.id); - } - }); - }); - } - }; - - return ( - -

Choose yourself a username to track your progress and compete with others:

- - - - - - } - label="Remember me" - /> - - - - - -
- ); -}; - - -export default Registration; diff --git a/src/pages/Scoreboard/Scoreboard.tsx b/src/pages/Scoreboard/Scoreboard.tsx index 9b9ee01..e4185bd 100644 --- a/src/pages/Scoreboard/Scoreboard.tsx +++ b/src/pages/Scoreboard/Scoreboard.tsx @@ -3,7 +3,7 @@ import React, { useEffect, useState } from 'react'; import { makeStyles } from '@material-ui/core/styles'; import { Window, SmartList } from 'react-benzin'; -import { Solution } from '../../types'; +import { Solution, RenderPropTypes } from '../../types'; import SolutionCard from '../../components/SolutionCard/SolutionCard'; import Loading from '../../components/Loading/Loading'; @@ -24,12 +24,6 @@ const useStyles = makeStyles(theme => ({ })); -interface RenderPropTypes { - index: number; - style: React.CSSProperties; -} - - const Scoreboard: React.FC = () => { const classes = useStyles(); const [solutions, setSolutions] = useState([]); diff --git a/src/types.d.ts b/src/types.d.ts index cfc60bc..949d410 100644 --- a/src/types.d.ts +++ b/src/types.d.ts @@ -10,3 +10,8 @@ export interface Solution { author: User; } +interface RenderPropTypes { + index: number; + style: React.CSSProperties; +} + -- cgit v1.2.3 From 9e2132cd54e5f5e6b85c7d949ac982cb95566027 Mon Sep 17 00:00:00 2001 From: eug-vs Date: Sat, 21 Mar 2020 16:04:26 +0300 Subject: chore: migrate Timer page to Typescript :label: --- src/pages/Timer/Timer.js | 92 -------------------- src/pages/Timer/Timer.tsx | 102 ++++++++++++++++++++++ src/pages/Timer/TimerButton.tsx | 130 +++++++++++++++++++++++++++++ src/pages/Timer/TimerButton/TimerButton.js | 122 --------------------------- 4 files changed, 232 insertions(+), 214 deletions(-) delete mode 100644 src/pages/Timer/Timer.js create mode 100644 src/pages/Timer/Timer.tsx create mode 100644 src/pages/Timer/TimerButton.tsx delete mode 100644 src/pages/Timer/TimerButton/TimerButton.js (limited to 'src') diff --git a/src/pages/Timer/Timer.js b/src/pages/Timer/Timer.js deleted file mode 100644 index 6020c1b..0000000 --- a/src/pages/Timer/Timer.js +++ /dev/null @@ -1,92 +0,0 @@ -import React from 'react'; - -import { post } from '../../requests'; - -import { - Window, - ContentSection, - SmartList, -} from 'react-benzin'; - -import TimerButton from './TimerButton/TimerButton'; -import SolutionCard from '../../components/SolutionCard/SolutionCard'; - -import { Button, makeStyles } from '@material-ui/core'; - - -const useStyles = makeStyles(theme => ({ - primary: { - padding: theme.spacing(4), - }, - cell: { - padding: theme.spacing(5), - }, -})); - -const Timer = ({ user, recentSolutions, setRecentSolutions, setPage }) => { - const classes = useStyles(); - - const registerResult = result => { - const solution = { author_id: user.id, result }; - post('solutions/', solution).then(response => { - setRecentSolutions([response.data].concat(recentSolutions)); - }); - }; - - const handleLearnMore = () => { - setPage('contribute'); - }; - - const handleLogin = () => { - setPage('profile'); - }; - - const removeSolution = (id) => { - setRecentSolutions(recentSolutions.filter((solution => solution.id !== id))); - }; - - const renderItem = ({ index, style }) => { - const solution = recentSolutions[index]; - return ( -
- -
- ); - }; - - return ( - <> - -
- -

- ChronoCube is a professional speedcubing timer. - Share your results publicly - let everyone see your progress and - achievements! - Every speedcuber will benefit - from using it - both amateur and professional! -

- -
- {user.id === null && - -

Tell us your name so we can track your progress

- -
- } - -
-
- - - - - ); -}; - - -export default Timer; diff --git a/src/pages/Timer/Timer.tsx b/src/pages/Timer/Timer.tsx new file mode 100644 index 0000000..3ceb674 --- /dev/null +++ b/src/pages/Timer/Timer.tsx @@ -0,0 +1,102 @@ +import React from 'react'; + +import { post } from '../../requests'; + +import { + Window, + ContentSection, + SmartList, +} from 'react-benzin'; +import { User, Solution, RenderPropTypes } from '../../types'; + +import TimerButton from './TimerButton'; +import SolutionCard from '../../components/SolutionCard/SolutionCard'; + +import { Button, makeStyles } from '@material-ui/core'; + + +const useStyles = makeStyles(theme => ({ + primary: { + padding: theme.spacing(4), + }, + cell: { + padding: theme.spacing(5), + }, +})); + + +interface PropTypes { + user: User; + recentSolutions: Solution[]; + setRecentSolutions: (newRecentSolutions: Solution[]) => void; + setPage: (newPage: string) => void; +} + + +const Timer: React.FC = ({ user, recentSolutions, setRecentSolutions, setPage }) => { + const classes = useStyles(); + + const registerResult = (result: string): void => { + const solution = { author_id: user.id, result }; + post('solutions/', solution).then(response => { + setRecentSolutions([response.data].concat(recentSolutions)); + }); + }; + + const handleLearnMore = (): void => { + setPage('contribute'); + }; + + const handleLogin = (): void => { + setPage('profile'); + }; + + const removeSolution = (id: number): void => { + setRecentSolutions(recentSolutions.filter((solution => solution.id !== id))); + }; + + const renderItem: React.FC = ({ index, style }) => { + const solution = recentSolutions[index]; + return ( +
+ +
+ ); + }; + + return ( + <> + +
+ +

+ ChronoCube is a professional speedcubing timer. + Share your results publicly - let everyone see your progress and + achievements! + Every speedcuber will benefit + from using it - both amateur and professional! +

+ +
+ {user.id === null && + +

Tell us your name so we can track your progress

+ +
+ } + +
+
+ + + + + ); +}; + + +export default Timer; diff --git a/src/pages/Timer/TimerButton.tsx b/src/pages/Timer/TimerButton.tsx new file mode 100644 index 0000000..86bbf76 --- /dev/null +++ b/src/pages/Timer/TimerButton.tsx @@ -0,0 +1,130 @@ +import React, { useState, useEffect } from 'react'; + +import { Paper, Typography } from '@material-ui/core'; +import { makeStyles } from '@material-ui/core/styles'; + +const useStyles = makeStyles(theme => ({ + root: { + textAlign: 'center', + padding: theme.spacing(5), + background: theme.palette.background.elevation3, + marginTop: theme.spacing(10), + }, +})); + + +interface PropTypes { + registerResult: (result: string) => void; +} + +type Mode = 'idle' | 'countdown' | 'running' | 'over'; + + +const TimerButton: React.FC = ({ registerResult }) => { + const classes = useStyles(); + + const SPACE = 32; + const maxCountdown = 15000; + const [time, setTime] = useState('00:00:00'); + const [mode, setMode] = useState('idle'); + + useEffect(()=> { + const timestamp = Date.now(); + + if (mode === 'countdown') { + const repeater = setInterval(() => { + const timeDelta = maxCountdown - (Date.now() - timestamp); + if (timeDelta <= 0) setMode('over'); + setTime(convertTimeToString(timeDelta)); + }, 10); + return () => clearInterval(repeater); + } + + if (mode === 'running') { + const repeater = setInterval(() => { + setTime(convertTimeToString(Date.now() - timestamp)); + }, 10); + return () => clearInterval(repeater); + } + + if (mode === 'over') { + setTime('00:00:00'); + } + }, [mode]); + + const handleKeyPress = (event: KeyboardEvent): void => { + event.preventDefault(); + if (event.keyCode === SPACE && mode === 'idle' ) setMode('countdown'); + }; + + const handleKeyUp = (event: KeyboardEvent): void => { + if (event.keyCode === SPACE) { + if (mode === 'running') { + registerResult(time); + setMode('idle'); + } else if (mode === 'over') { + setMode('idle'); + } else { + setMode('running'); + } + } + }; + + useEffect(() => { + window.addEventListener('keyup', handleKeyUp); + window.addEventListener('keypress', handleKeyPress); + + return () => { + window.removeEventListener('keyup', handleKeyUp); + window.removeEventListener('keypress', handleKeyPress); + }; + }); + + const composeHelperText = () => { + switch (mode) { + case 'running': return 'Go fast!'; + case 'countdown': return 'Release SPACE to begin'; + case 'over': return 'You are too late!'; + default: return 'Hold SPACE to start countdown'; + } + }; + + const helperColor = () => { + switch (mode) { + case 'running': return 'primary'; + case 'over': return 'secondary'; + default: return 'textSecondary'; + } + }; + + return ( + + {time} + + {composeHelperText()} + + + ); +}; + +const convertTimeToString = (timeDelta: number): string => { + let resultTime = ''; + + const minute = Math.floor(timeDelta / 60000); + if (minute < 10) resultTime += '0'; + resultTime += minute + ':'; + + let second = Math.floor(timeDelta / 1000); + if (second > 59) second %= 60; + if (second < 10) resultTime += '0'; + resultTime += second + ':'; + + const mill = Math.floor((timeDelta % 1000) / 10); + if (mill < 10) resultTime += '0'; + resultTime += mill; + + return resultTime; +}; + + +export default TimerButton; diff --git a/src/pages/Timer/TimerButton/TimerButton.js b/src/pages/Timer/TimerButton/TimerButton.js deleted file mode 100644 index fdb6b7c..0000000 --- a/src/pages/Timer/TimerButton/TimerButton.js +++ /dev/null @@ -1,122 +0,0 @@ -import React, { useState, useEffect } from 'react'; - -import { Paper, Typography } from '@material-ui/core'; -import { makeStyles } from '@material-ui/core/styles'; - -const useStyles = makeStyles(theme => ({ - root: { - textAlign: 'center', - padding: theme.spacing(5), - background: theme.palette.background.elevation3, - marginTop: theme.spacing(10), - }, -})); - -const TimerButton = ({ registerResult }) => { - const classes = useStyles(); - - const SPACE = 32; - const maxCountdown = 15000; - const [time, setTime] = useState('00:00:00'); - const [mode, setMode] = useState('idle'); - - useEffect(()=> { - const timestamp = Date.now(); - - if (mode === 'countdown') { - const repeater = setInterval(() => { - const timeDelta = maxCountdown - (Date.now() - timestamp); - if (timeDelta <= 0) setMode('over'); - setTime(convertTimeToString(timeDelta)); - }, 10); - return () => clearInterval(repeater); - } - - if (mode === 'running') { - const repeater = setInterval(() => { - setTime(convertTimeToString(Date.now() - timestamp)); - }, 10); - return () => clearInterval(repeater); - } - - if (mode === 'over') { - setTime('00:00:00'); - } - }, [mode]); - - const handleKeyPress = event => { - event.preventDefault(); - if (event.keyCode === SPACE && mode === 'idle' ) setMode('countdown'); - }; - - const handleKeyUp = event => { - if (event.keyCode === SPACE) { - if (mode === 'running') { - registerResult(time); - setMode('idle'); - } else if (mode === 'over') { - setMode('idle'); - } else { - setMode('running'); - } - } - }; - - useEffect(() => { - window.addEventListener('keyup', handleKeyUp); - window.addEventListener('keypress', handleKeyPress); - - return () => { - window.removeEventListener('keyup', handleKeyUp); - window.removeEventListener('keypress', handleKeyPress); - }; - }); - - const composeHelperText = () => { - switch (mode) { - case 'running': return 'Go fast!'; - case 'countdown': return 'Release SPACE to begin'; - case 'over': return 'You are too late!'; - default: return 'Hold SPACE to start countdown'; - } - }; - - const helperColor = () => { - switch (mode) { - case 'running': return 'primary'; - case 'over': return 'secondary'; - default: return 'textSecondary'; - } - }; - - return ( - - {time} - - {composeHelperText()} - - - ); -}; - -const convertTimeToString = timeDelta => { - let resultTime = ''; - - const minute = Math.floor(timeDelta / 60000); - if (minute < 10) resultTime += '0'; - resultTime += minute + ':'; - - let second = Math.floor(timeDelta / 1000); - if (second > 59) second %= 60; - if (second < 10) resultTime += '0'; - resultTime += second + ':'; - - const mill = Math.floor((timeDelta % 1000) / 10); - if (mill < 10) resultTime += '0'; - resultTime += mill; - - return resultTime; -}; - - -export default TimerButton; -- cgit v1.2.3 From 0267191d92814e753b966ce3bdfbd9b804b313d7 Mon Sep 17 00:00:00 2001 From: eug-vs Date: Sat, 21 Mar 2020 16:05:52 +0300 Subject: fix: add missing types --- src/pages/Profile/Profile.tsx | 2 +- src/pages/Profile/Registration.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/pages/Profile/Profile.tsx b/src/pages/Profile/Profile.tsx index bbf55f1..83acb30 100644 --- a/src/pages/Profile/Profile.tsx +++ b/src/pages/Profile/Profile.tsx @@ -39,7 +39,7 @@ const Profile: React.FC = ({ user, setUser }) => { const [profileSolutions, setProfileSolutions] = useState([]); - const handleLogout = () => { + const handleLogout = (): void => { setUser({ username: 'anonymous', id: null }); localStorage.clear(); }; diff --git a/src/pages/Profile/Registration.tsx b/src/pages/Profile/Registration.tsx index 30e357d..a5e0f3e 100644 --- a/src/pages/Profile/Registration.tsx +++ b/src/pages/Profile/Registration.tsx @@ -30,7 +30,7 @@ const Registration: React.FC = ({ setUser }) => { setIsRememberMe(event.target.checked); }; - const handleSubmit = () => { + const handleSubmit = (): void => { if (username !== '') { post('users/', { username }) .then(response => { -- cgit v1.2.3 From 0f6c4e7e4d44314707535e2d7e3aba7b638cd2dd Mon Sep 17 00:00:00 2001 From: eug-vs Date: Sat, 21 Mar 2020 16:11:31 +0300 Subject: fix: add more missing types :ok_hand: --- src/pages/Timer/Timer.tsx | 2 +- src/pages/Timer/TimerButton.tsx | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/pages/Timer/Timer.tsx b/src/pages/Timer/Timer.tsx index 3ceb674..a890815 100644 --- a/src/pages/Timer/Timer.tsx +++ b/src/pages/Timer/Timer.tsx @@ -37,7 +37,7 @@ const Timer: React.FC = ({ user, recentSolutions, setRecentSolutions, const classes = useStyles(); const registerResult = (result: string): void => { - const solution = { author_id: user.id, result }; + const solution = { 'author_id': user.id, result }; post('solutions/', solution).then(response => { setRecentSolutions([response.data].concat(recentSolutions)); }); diff --git a/src/pages/Timer/TimerButton.tsx b/src/pages/Timer/TimerButton.tsx index 86bbf76..0a3bf38 100644 --- a/src/pages/Timer/TimerButton.tsx +++ b/src/pages/Timer/TimerButton.tsx @@ -37,14 +37,14 @@ const TimerButton: React.FC = ({ registerResult }) => { if (timeDelta <= 0) setMode('over'); setTime(convertTimeToString(timeDelta)); }, 10); - return () => clearInterval(repeater); + return (): void => clearInterval(repeater); } if (mode === 'running') { const repeater = setInterval(() => { setTime(convertTimeToString(Date.now() - timestamp)); }, 10); - return () => clearInterval(repeater); + return (): void => clearInterval(repeater); } if (mode === 'over') { @@ -74,13 +74,13 @@ const TimerButton: React.FC = ({ registerResult }) => { window.addEventListener('keyup', handleKeyUp); window.addEventListener('keypress', handleKeyPress); - return () => { + return (): void => { window.removeEventListener('keyup', handleKeyUp); window.removeEventListener('keypress', handleKeyPress); }; }); - const composeHelperText = () => { + const composeHelperText = (): string => { switch (mode) { case 'running': return 'Go fast!'; case 'countdown': return 'Release SPACE to begin'; @@ -89,7 +89,7 @@ const TimerButton: React.FC = ({ registerResult }) => { } }; - const helperColor = () => { + const helperColor = (): 'primary' | 'secondary' | 'textSecondary' => { switch (mode) { case 'running': return 'primary'; case 'over': return 'secondary'; -- cgit v1.2.3