diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/components/Loading/Loading.tsx (renamed from src/components/Loading/Loading.js) | 2 | ||||
| -rw-r--r-- | src/components/SolutionCard/SolutionCard.tsx (renamed from src/components/SolutionCard/SolutionCard.js) | 22 | ||||
| -rw-r--r-- | src/index.tsx (renamed from src/index.js) | 19 | ||||
| -rw-r--r-- | src/pages/Contribute/Contribute.tsx (renamed from src/pages/Contribute/Contribute.js) | 4 | ||||
| -rw-r--r-- | src/pages/Profile/Profile.tsx (renamed from src/pages/Profile/Profile.js) | 19 | ||||
| -rw-r--r-- | src/pages/Profile/Registration.tsx (renamed from src/pages/Profile/Registration/Registration.js) | 21 | ||||
| -rw-r--r-- | src/pages/Scoreboard/Scoreboard.tsx (renamed from src/pages/Scoreboard/Scoreboard.js) | 12 | ||||
| -rw-r--r-- | src/pages/Timer/Timer.tsx (renamed from src/pages/Timer/Timer.js) | 26 | ||||
| -rw-r--r-- | src/pages/Timer/TimerButton.tsx (renamed from src/pages/Timer/TimerButton/TimerButton.js) | 30 | ||||
| -rw-r--r-- | src/react-app-env.d.ts | 1 | ||||
| -rw-r--r-- | src/requests.js | 24 | ||||
| -rw-r--r-- | src/requests.ts | 11 | ||||
| -rw-r--r-- | src/types.d.ts | 17 | 
13 files changed, 127 insertions, 81 deletions
| diff --git a/src/components/Loading/Loading.js b/src/components/Loading/Loading.tsx index e8793cc..a784be1 100644 --- a/src/components/Loading/Loading.js +++ b/src/components/Loading/Loading.tsx @@ -16,7 +16,7 @@ const useStyles = makeStyles(theme => ({    },  })); -const Loading = () => { +const Loading: React.FC = () => {    const classes = useStyles();    return ( diff --git a/src/components/SolutionCard/SolutionCard.js b/src/components/SolutionCard/SolutionCard.tsx index fdd4bdf..5adbff9 100644 --- a/src/components/SolutionCard/SolutionCard.js +++ b/src/components/SolutionCard/SolutionCard.tsx @@ -11,6 +11,7 @@ import {    Menu,    MenuItem,  } from '@material-ui/core'; +import { Solution } from '../../types';  import { makeStyles } from '@material-ui/core/styles';  import TimerIcon from '@material-ui/icons/Timer'; @@ -44,22 +45,29 @@ const useStyles = makeStyles(theme => ({    },  })); -const SolutionCard = ({ data, removeThisCard }) => { + +interface PropTypes { +  data: Solution; +  removeThisCard: (id: number) => void; +} + + +const SolutionCard: React.FC<PropTypes> = ({ data, removeThisCard }) => {    const classes = useStyles(); -  const [anchorEl, setAnchorEl] = useState(null); +  const [anchorEl, setAnchorEl] = useState<HTMLElement | null>(null);    const author = data.author? data.author.username : 'anonymous';    const date = new Date(data.date); -  const handleOpenMenu = event => { +  const handleOpenMenu = (event: React.MouseEvent<HTMLButtonElement>): void => {      setAnchorEl(event.currentTarget);    }; -  const handleClose = () => { +  const handleClose = (): void => {      setAnchorEl(null);    }; -  const handleDelete = () => { +  const handleDelete = (): void => {      del(`solutions/${data.id}/`).then(() => {        removeThisCard(data.id);      }); @@ -77,11 +85,11 @@ const SolutionCard = ({ data, removeThisCard }) => {          }          title={author}          subheader={date.toLocaleString('default', DATE_FORMAT)} -        action={( +        action={            <IconButton onClick={handleOpenMenu}>              <MoreVertIcon />            </IconButton> -        )} +        }        />        <Menu          anchorEl={anchorEl} diff --git a/src/index.js b/src/index.tsx index 49c66e7..360ca89 100644 --- a/src/index.js +++ b/src/index.tsx @@ -5,6 +5,7 @@ import {    BenzinThemeProvider,    Header,  } from 'react-benzin'; +import { User, Solution } from './types';  import 'typeface-roboto'; @@ -21,11 +22,10 @@ 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 App: React.FC = () => { +  const [page, setPage] = useState<string>('app'); +  const [user, setUser] = useState<User>({ username: 'anonymous', id: null }); +  const [recentSolutions, setRecentSolutions] = useState<Solution[]>([]);    const headerContents = {      app: (<TimerIcon />), @@ -35,15 +35,15 @@ const App = () => {    };    useEffect(() => { -    const userId = +localStorage.getItem('userId'); +    const userId = localStorage.getItem('userId');      if (userId) {        get('users/').then(response => { -        setUser(response.data.filter(user => user.id === +userId)[0]); +        setUser(response.data.filter((user: User) => user.id === +userId)[0]);        });      }    }, []); -  const Page = ({ page }) => { +  const Page: React.FC<{ page: string }> = ({ page }) => {      switch (page) {        case 'app':          return ( @@ -73,7 +73,8 @@ const App = () => {      <BenzinThemeProvider>        <Header          logo={{ -          title: 'ChronoCube' +          title: 'ChronoCube', +          icon: null          }}          contents={headerContents}          page={page} diff --git a/src/pages/Contribute/Contribute.js b/src/pages/Contribute/Contribute.tsx index aa1c3f7..4c37fb9 100644 --- a/src/pages/Contribute/Contribute.js +++ b/src/pages/Contribute/Contribute.tsx @@ -17,6 +17,7 @@ import NewReleasesIcon from '@material-ui/icons/NewReleases';  import { Window, ContentSection } from 'react-benzin'; +import developers from '../../developers.json';  const useStyles = makeStyles(theme => ({    mono: { @@ -31,10 +32,9 @@ const useStyles = makeStyles(theme => ({  })); -const developers = require('../../developers.json'); -const Contribute = () => { +const Contribute: React.FC = () => {    const classes = useStyles();    return ( diff --git a/src/pages/Profile/Profile.js b/src/pages/Profile/Profile.tsx index 65c3734..83acb30 100644 --- a/src/pages/Profile/Profile.js +++ b/src/pages/Profile/Profile.tsx @@ -5,12 +5,13 @@ import {    makeStyles,  } from '@material-ui/core'; -import Registration from './Registration/Registration'; +import Registration from './Registration';  import {    Window,    ContentSection,    SmartList,  } from 'react-benzin'; +import { User, Solution, RenderPropTypes } from '../../types';  import SolutionCard from '../../components/SolutionCard/SolutionCard'; @@ -27,12 +28,18 @@ const useStyles = makeStyles(theme => ({  })); -const Profile = ({ user, setUser }) => { +interface PropTypes { +  user: User; +  setUser: (user: User) => void; +} + + +const Profile: React.FC<PropTypes> = ({ user, setUser }) => {    const classes = useStyles(); -  const [profileSolutions, setProfileSolutions] = useState([]); +  const [profileSolutions, setProfileSolutions] = useState<Solution[]>([]); -  const handleLogout = () => { +  const handleLogout = (): void => {      setUser({ username: 'anonymous', id: null });      localStorage.clear();    }; @@ -43,11 +50,11 @@ const Profile = ({ user, setUser }) => {      });    }, [user]); -  const removeSolution = (id) => { +  const removeSolution = (id: number): void => {      setProfileSolutions(profileSolutions.filter((solution => solution.id !== id)));    }; -  const renderItem = ({ index, style }) => { +  const renderItem: React.FC<RenderPropTypes> = ({ index, style }) => {      return (        <div style={style} className={classes.cell}>          <SolutionCard data={profileSolutions[index]} removeThisCard={removeSolution} /> diff --git a/src/pages/Profile/Registration/Registration.js b/src/pages/Profile/Registration.tsx index b2d5503..a5e0f3e 100644 --- a/src/pages/Profile/Registration/Registration.js +++ b/src/pages/Profile/Registration.tsx @@ -7,25 +7,30 @@ import {    FormControlLabel,    Grid,  } from '@material-ui/core'; +import { User } from '../../types';  import { ContentSection } from 'react-benzin'; -import { get, post } from '../../../requests'; +import { get, post } from '../../requests'; -const Registration = ({ setUser }) => { +interface PropTypes { +  setUser: (user: User) => void; +} -  const [username, setUsername] = useState(''); -  const [isRememberMe, setIsRememberMe] = useState(false); +const Registration: React.FC<PropTypes> = ({ setUser }) => { -  const handleChange = (event) => { +  const [username, setUsername] = useState<string>(''); +  const [isRememberMe, setIsRememberMe] = useState<boolean>(false); + +  const handleChange = (event: React.ChangeEvent<HTMLInputElement>): void => {      setUsername(event.target.value);    }; -  const handleCheck = (event) => { +  const handleCheck = (event: React.ChangeEvent<HTMLInputElement>): void => {      setIsRememberMe(event.target.checked);    }; -  const handleSubmit = () => { +  const handleSubmit = (): void => {      if (username !== '') {        post('users/', { username })          .then(response => { @@ -37,7 +42,7 @@ const Registration = ({ setUser }) => {          })          .catch(err => {            get('users/').then(response => { -            const user = response.data.filter(user => user.username === username)[0]; +            const user = response.data.filter((user: User) => user.username === username)[0];              setUser(user);              if (isRememberMe) {                localStorage.setItem('userId', user.id); diff --git a/src/pages/Scoreboard/Scoreboard.js b/src/pages/Scoreboard/Scoreboard.tsx index 47c0899..e4185bd 100644 --- a/src/pages/Scoreboard/Scoreboard.js +++ b/src/pages/Scoreboard/Scoreboard.tsx @@ -3,6 +3,7 @@ import React, { useEffect, useState } from 'react';  import { makeStyles } from '@material-ui/core/styles';  import { Window, SmartList } from 'react-benzin'; +import { Solution, RenderPropTypes } from '../../types';  import SolutionCard from '../../components/SolutionCard/SolutionCard';  import Loading from '../../components/Loading/Loading'; @@ -22,17 +23,18 @@ const useStyles = makeStyles(theme => ({    }  })); -const Scoreboard = () => { + +const Scoreboard: React.FC = () => {    const classes = useStyles(); -  const [solutions, setSolutions] = useState([]); +  const [solutions, setSolutions] = useState<Solution[]>([]); -  const updateSolutions = () => { +  const updateSolutions = (): void => {      get('scoreboard/').then(response => {          setSolutions(response.data);      });    }; -  const removeSolution = id => { +  const removeSolution = (id: number): void => {      updateSolutions();    }; @@ -40,7 +42,7 @@ const Scoreboard = () => {      setTimeout(updateSolutions, 300);    }, []); -  const renderItem = ({ index, style }) => { +  const renderItem: React.FC<RenderPropTypes> = ({ index, style }) => {      return (        <div style={style} className={classes.cell}>          <SolutionCard data={solutions[index]} removeThisCard={removeSolution}/> diff --git a/src/pages/Timer/Timer.js b/src/pages/Timer/Timer.tsx index 6020c1b..a890815 100644 --- a/src/pages/Timer/Timer.js +++ b/src/pages/Timer/Timer.tsx @@ -7,8 +7,9 @@ import {    ContentSection,    SmartList,  } from 'react-benzin'; +import { User, Solution, RenderPropTypes } from '../../types'; -import TimerButton from './TimerButton/TimerButton'; +import TimerButton from './TimerButton';  import SolutionCard from '../../components/SolutionCard/SolutionCard';  import { Button, makeStyles } from '@material-ui/core'; @@ -23,29 +24,38 @@ const useStyles = makeStyles(theme => ({    },  })); -const Timer = ({ user, recentSolutions, setRecentSolutions, setPage }) => { + +interface PropTypes { +  user: User; +  recentSolutions: Solution[]; +  setRecentSolutions: (newRecentSolutions: Solution[]) => void; +  setPage: (newPage: string) => void; +} + + +const Timer: React.FC<PropTypes> = ({ user, recentSolutions, setRecentSolutions, setPage }) => {    const classes = useStyles(); -  const registerResult = result => { -    const solution = { author_id: user.id, result }; +  const registerResult = (result: string): void => { +    const solution = { 'author_id': user.id, result };      post('solutions/', solution).then(response => {        setRecentSolutions([response.data].concat(recentSolutions));      });    }; -  const handleLearnMore = () => { +  const handleLearnMore = (): void => {      setPage('contribute');    }; -  const handleLogin = () => { +  const handleLogin = (): void => {      setPage('profile');    }; -  const removeSolution = (id) => { +  const removeSolution = (id: number): void => {      setRecentSolutions(recentSolutions.filter((solution => solution.id !== id)));    }; -  const renderItem = ({ index, style }) => { +  const renderItem: React.FC<RenderPropTypes> = ({ index, style }) => {      const solution = recentSolutions[index];      return (        <div style={style} className={classes.cell}> diff --git a/src/pages/Timer/TimerButton/TimerButton.js b/src/pages/Timer/TimerButton.tsx index fdb6b7c..0a3bf38 100644 --- a/src/pages/Timer/TimerButton/TimerButton.js +++ b/src/pages/Timer/TimerButton.tsx @@ -12,13 +12,21 @@ const useStyles = makeStyles(theme => ({    },  })); -const TimerButton = ({ registerResult }) => { + +interface PropTypes { +  registerResult: (result: string) => void; +} + +type Mode = 'idle' | 'countdown' | 'running' | 'over'; + + +const TimerButton: React.FC<PropTypes> = ({ registerResult }) => {    const classes = useStyles();    const SPACE = 32;    const maxCountdown = 15000; -  const [time, setTime] = useState('00:00:00'); -  const [mode, setMode] = useState('idle'); +  const [time, setTime] = useState<string>('00:00:00'); +  const [mode, setMode] = useState<Mode>('idle');    useEffect(()=> {      const timestamp = Date.now(); @@ -29,14 +37,14 @@ const TimerButton = ({ 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') { @@ -44,12 +52,12 @@ const TimerButton = ({ registerResult }) => {      }    }, [mode]); -  const handleKeyPress = event => { +  const handleKeyPress = (event: KeyboardEvent): void => {      event.preventDefault();      if (event.keyCode === SPACE && mode === 'idle' ) setMode('countdown');    }; -  const handleKeyUp = event => { +  const handleKeyUp = (event: KeyboardEvent): void => {      if (event.keyCode === SPACE) {        if (mode === 'running') {          registerResult(time); @@ -66,13 +74,13 @@ const TimerButton = ({ 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'; @@ -81,7 +89,7 @@ const TimerButton = ({ registerResult }) => {      }    }; -  const helperColor = () => { +  const helperColor = (): 'primary' | 'secondary' | 'textSecondary' => {      switch (mode) {        case 'running': return 'primary';        case 'over': return 'secondary'; @@ -99,7 +107,7 @@ const TimerButton = ({ registerResult }) => {    );  }; -const convertTimeToString = timeDelta => { +const convertTimeToString = (timeDelta: number): string => {    let resultTime = '';    const minute = Math.floor(timeDelta / 60000); 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 @@ +/// <reference types="react-scripts" /> 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..0242ed5 --- /dev/null +++ b/src/requests.ts @@ -0,0 +1,11 @@ +import axios, { AxiosResponse } from 'axios'; + +const baseUrl = 'https://eugvs.pythonanywhere.com/'; +const baseApiUrl = baseUrl + 'api/'; + +export const get = (url: string): Promise<AxiosResponse> => axios.get(baseApiUrl + url); + +export const del = (url: string): Promise<AxiosResponse> => axios.delete(baseApiUrl + url); + +export const post = (url: string, data: object): Promise<AxiosResponse> => axios.post(baseApiUrl + url, data); + diff --git a/src/types.d.ts b/src/types.d.ts new file mode 100644 index 0000000..949d410 --- /dev/null +++ b/src/types.d.ts @@ -0,0 +1,17 @@ +export interface User { +  username: string; +  id: number | null; +} + +export interface Solution { +  id: number; +  result: string; +  date: string; +  author: User; +} + +interface RenderPropTypes { +  index: number; +  style: React.CSSProperties; +} + | 
