Skip to content
Snippets Groups Projects
Commit 4f80ddd6 authored by Björn Modée's avatar Björn Modée Committed by Albin Henriksson
Browse files

Resolve "Create a dashboard"

parent 26b83bf4
No related branches found
No related tags found
1 merge request!59Resolve "Create a dashboard"
Pipeline #40077 passed with warnings
......@@ -1125,6 +1125,49 @@
"resolved": "https://registry.npmjs.org/@csstools/normalize.css/-/normalize.css-10.1.0.tgz",
"integrity": "sha512-ij4wRiunFfaJxjB0BdrYHIH8FxBJpOwNPhhAcunlmPdXudL1WQV1qoP9un6JsEBAgQH+7UXyyjh0g7jTxXK6tg=="
},
"@devexpress/dx-chart-core": {
"version": "2.7.5",
"resolved": "https://registry.npmjs.org/@devexpress/dx-chart-core/-/dx-chart-core-2.7.5.tgz",
"integrity": "sha512-ZSpBN7SjnOhBOcvmuYZ5U+XyUYKlsTrYXCYMfFH2qXwvqh0e0UbhzW1FPfDXdWqx0Y52MtPX0HJrBC4QqH7Bcg==",
"requires": {
"d3-array": "^2.4.0",
"d3-scale": "^3.2.0",
"d3-shape": "^1.3.7"
}
},
"@devexpress/dx-core": {
"version": "2.7.5",
"resolved": "https://registry.npmjs.org/@devexpress/dx-core/-/dx-core-2.7.5.tgz",
"integrity": "sha512-VQQkz0uUqQ7YuVZeBEx1JFqpSSe5Bz9Qy2T0XAbilBQ8IItj74xjzaFMCNjuASAKXOJGtG0RUh+BOKrMGV7jlg=="
},
"@devexpress/dx-react-chart": {
"version": "2.7.5",
"resolved": "https://registry.npmjs.org/@devexpress/dx-react-chart/-/dx-react-chart-2.7.5.tgz",
"integrity": "sha512-j3nPsHrMiCbgm6olZCykxHOxxJ2XXG0CVihMYGOoyenM74Ed+NIaLi1bk2VtxKZdEPB5UrWgU10rd9SLH45BsQ==",
"requires": {
"@devexpress/dx-chart-core": "2.7.5",
"d3-scale": "^3.2.0",
"d3-shape": "^1.3.7"
}
},
"@devexpress/dx-react-chart-material-ui": {
"version": "2.7.5",
"resolved": "https://registry.npmjs.org/@devexpress/dx-react-chart-material-ui/-/dx-react-chart-material-ui-2.7.5.tgz",
"integrity": "sha512-uS450uSP1D6mZ2jgtueShqaATNRVqJEwqhgyRQUXL/gQyTrTCvM61TC5NLyEYCOW6RkiHK1BabWbhJlVATZbeg==",
"requires": {
"clsx": "^1.0.4",
"prop-types": "^15.7.2"
}
},
"@devexpress/dx-react-core": {
"version": "2.7.5",
"resolved": "https://registry.npmjs.org/@devexpress/dx-react-core/-/dx-react-core-2.7.5.tgz",
"integrity": "sha512-YwJ4l8nnMs/vghqamo8OzirDnrbT1ZNIcMP5xJFJJQIyfYAXvGGDS4yLeYI4cwitBg/d2O4jMOReXDB8tUaDDQ==",
"requires": {
"@devexpress/dx-core": "2.7.5",
"prop-types": "^15.7.2"
}
},
"@emotion/hash": {
"version": "0.8.0",
"resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.8.0.tgz",
......@@ -5416,6 +5459,73 @@
"type": "^1.0.1"
}
},
"d3-array": {
"version": "2.12.1",
"resolved": "https://registry.npmjs.org/d3-array/-/d3-array-2.12.1.tgz",
"integrity": "sha512-B0ErZK/66mHtEsR1TkPEEkwdy+WDesimkM5gpZr5Dsg54BiTA5RXtYW5qTLIAcekaS9xfZrzBLF/OAkB3Qn1YQ==",
"requires": {
"internmap": "^1.0.0"
}
},
"d3-color": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/d3-color/-/d3-color-2.0.0.tgz",
"integrity": "sha512-SPXi0TSKPD4g9tw0NMZFnR95XVgUZiBH+uUTqQuDu1OsE2zomHU7ho0FISciaPvosimixwHFl3WHLGabv6dDgQ=="
},
"d3-format": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/d3-format/-/d3-format-2.0.0.tgz",
"integrity": "sha512-Ab3S6XuE/Q+flY96HXT0jOXcM4EAClYFnRGY5zsjRGNy6qCYrQsMffs7cV5Q9xejb35zxW5hf/guKw34kvIKsA=="
},
"d3-interpolate": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-2.0.1.tgz",
"integrity": "sha512-c5UhwwTs/yybcmTpAVqwSFl6vrQ8JZJoT5F7xNFK9pymv5C0Ymcc9/LIJHtYIggg/yS9YHw8i8O8tgb9pupjeQ==",
"requires": {
"d3-color": "1 - 2"
}
},
"d3-path": {
"version": "1.0.9",
"resolved": "https://registry.npmjs.org/d3-path/-/d3-path-1.0.9.tgz",
"integrity": "sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg=="
},
"d3-scale": {
"version": "3.2.4",
"resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-3.2.4.tgz",
"integrity": "sha512-PG6gtpbPCFqKbvdBEswQcJcTzHC8VEd/XzezF5e68KlkT4/ggELw/nR1tv863jY6ufKTvDlzCMZvhe06codbbA==",
"requires": {
"d3-array": "^2.3.0",
"d3-format": "1 - 2",
"d3-interpolate": "1.2.0 - 2",
"d3-time": "1 - 2",
"d3-time-format": "2 - 3"
}
},
"d3-shape": {
"version": "1.3.7",
"resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-1.3.7.tgz",
"integrity": "sha512-EUkvKjqPFUAZyOlhY5gzCxCeI0Aep04LwIRpsZ/mLFelJiUfnK56jo5JMDSE7yyP2kLSb6LtF+S5chMk7uqPqw==",
"requires": {
"d3-path": "1"
}
},
"d3-time": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/d3-time/-/d3-time-2.1.1.tgz",
"integrity": "sha512-/eIQe/eR4kCQwq7yxi7z4c6qEXf2IYGcjoWB5OOQy4Tq9Uv39/947qlDcN2TLkiTzQWzvnsuYPB9TrWaNfipKQ==",
"requires": {
"d3-array": "2"
}
},
"d3-time-format": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-3.0.0.tgz",
"integrity": "sha512-UXJh6EKsHBTjopVqZBhFysQcoXSv/5yLONZvkQ5Kk3qbwiUYkdX17Xa1PT6U1ZWXGGfB1ey5L8dKMlFq2DO0Ag==",
"requires": {
"d3-time": "1 - 2"
}
},
"damerau-levenshtein": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.6.tgz",
......@@ -8492,6 +8602,11 @@
"side-channel": "^1.0.4"
}
},
"internmap": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/internmap/-/internmap-1.0.1.tgz",
"integrity": "sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw=="
},
"ip": {
"version": "1.1.5",
"resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz",
......
......@@ -3,6 +3,9 @@
"version": "0.1.0",
"private": true,
"dependencies": {
"@devexpress/dx-react-chart": "^2.7.5",
"@devexpress/dx-react-chart-material-ui": "^2.7.5",
"@devexpress/dx-react-core": "^2.7.5",
"@material-ui/core": "^4.11.3",
"@material-ui/icons": "^4.11.2",
"@material-ui/lab": "^4.0.0-alpha.57",
......
......@@ -23,6 +23,7 @@ import { getRoles } from '../../actions/roles'
import { logoutUser } from '../../actions/user'
import { useAppDispatch, useAppSelector } from '../../hooks'
import CompetitionManager from './competitions/CompetitionManager'
import Dashboard from './dashboard/Dashboard'
import RegionManager from './regions/Regions'
import { LeftDrawer } from './styled'
import UserManager from './users/UserManager'
......@@ -45,7 +46,9 @@ const useStyles = makeStyles((theme: Theme) =>
content: {
flexGrow: 1,
backgroundColor: theme.palette.background.default,
paddingLeft: theme.spacing(31),
paddingTop: theme.spacing(2),
paddingLeft: theme.spacing(35),
paddingRight: theme.spacing(5),
},
})
)
......@@ -138,9 +141,7 @@ const AdminView: React.FC = () => {
<div className={classes.toolbar} />
<Switch>
<Route exact path={[path, `${path}/startsida`]}>
<Typography variant="h1" noWrap>
Startsida
</Typography>
<Dashboard />
</Route>
<Route path={`${path}/regioner`}>
<RegionManager />
......
import { createStyles, makeStyles, Paper, Theme, Typography } from '@material-ui/core'
import Grid from '@material-ui/core/Grid'
import React from 'react'
import CurrentUser from './components/CurrentUser'
import NumberOfCompetitions from './components/NumberOfCompetitions'
import NumberOfRegions from './components/NumberOfRegions'
import NumberOfUsers from './components/NumberOfUsers'
const useStyles = makeStyles((theme: Theme) =>
createStyles({
root: {
flexGrow: 1,
},
paper: {
padding: theme.spacing(2),
textAlign: 'center',
color: theme.palette.text.secondary,
},
})
)
const Dashboard: React.FC = () => {
const classes = useStyles()
return (
<div className={classes.root}>
<div>
<Grid container spacing={3}>
<Grid item xs={4}>
<Paper className={classes.paper}>
<CurrentUser />
</Paper>
</Grid>
<Grid item xs>
<Paper className={classes.paper}>
<Typography variant="h4">Antal Användare:</Typography>
<NumberOfUsers />
</Paper>
</Grid>
<Grid item xs>
<Paper className={classes.paper}>
<Typography variant="h4">Antal Regioner:</Typography>
<NumberOfRegions />
</Paper>
</Grid>
<Grid item xs>
<Paper className={classes.paper}>
<Typography variant="h4">Antal Tävlingar:</Typography>
<NumberOfCompetitions />
</Paper>
</Grid>
</Grid>
</div>
</div>
)
}
export default Dashboard
import { Box, Typography } from '@material-ui/core'
import React from 'react'
import { useAppSelector } from '../../../../hooks'
const CurrentUser: React.FC = () => {
const currentUser = useAppSelector((state: { user: { userInfo: any } }) => state.user.userInfo)
return (
<div>
<Box display="flex" flexDirection="column" alignContent="flex-start">
<div>
<Typography variant="h2">
Välkommen{currentUser && currentUser.name ? `, ${currentUser.name}` : ''}!
</Typography>
</div>
<div>
<Typography variant="h6">Email: {currentUser && currentUser.email}</Typography>
</div>
<div>
<Typography variant="h6">Region: {currentUser && currentUser.city && currentUser.city.name}</Typography>
</div>
<div>
<Typography variant="h6">Roll: {currentUser && currentUser.role && currentUser.role.name}</Typography>
</div>
</Box>
</div>
)
}
export default CurrentUser
import { Box, Typography } from '@material-ui/core'
import React, { useEffect } from 'react'
import { getSearchUsers } from '../../../../actions/searchUser'
import { useAppDispatch, useAppSelector } from '../../../../hooks'
const NumberOfCompetitions: React.FC = () => {
const cities = useAppSelector((state) => state.cities.cities)
const dispatch = useAppDispatch()
const handleCount = () => {
if (cities.length >= 1000000) {
;<div>{cities.length / 1000000 + 'M'}</div>
} else if (cities.length >= 1000) {
;<div>{cities.length / 1000 + 'K'}</div>
}
return <div>{cities.length}</div>
}
useEffect(() => {
dispatch(getSearchUsers())
}, [])
return (
<div>
<Box width="100%" height="100%">
<div>
<Typography variant="h4">{handleCount()}</Typography>
</div>
</Box>
</div>
)
}
export default NumberOfCompetitions
import { Box, Typography } from '@material-ui/core'
import React, { useEffect } from 'react'
import { getSearchUsers } from '../../../../actions/searchUser'
import { useAppDispatch, useAppSelector } from '../../../../hooks'
const NumberOfRegions: React.FC = () => {
const competitionTotal = useAppSelector((state) => state.competitions.total)
const dispatch = useAppDispatch()
const handleCount = () => {
if (competitionTotal >= 1000000) {
;<div>{competitionTotal / 1000000 + 'M'}</div>
} else if (competitionTotal >= 1000) {
;<div>{competitionTotal / 1000 + 'K'}</div>
}
return <div>{competitionTotal}</div>
}
useEffect(() => {
dispatch(getSearchUsers())
}, [])
return (
<div>
<Box width="100%" height="100%">
<div>
<Typography variant="h4">{handleCount()}</Typography>
</div>
</Box>
</div>
)
}
export default NumberOfRegions
import { Box, Typography } from '@material-ui/core'
import React, { useEffect } from 'react'
import { getSearchUsers } from '../../../../actions/searchUser'
import { useAppDispatch, useAppSelector } from '../../../../hooks'
const NumberOfUsers: React.FC = () => {
const usersTotal = useAppSelector((state) => state.searchUsers.total)
const dispatch = useAppDispatch()
const handleCount = () => {
if (usersTotal >= 1000000) {
;<div>{usersTotal / 1000000 + 'M'}</div>
} else if (usersTotal >= 1000) {
;<div>{usersTotal / 1000 + 'K'}</div>
}
return <div>{usersTotal}</div>
}
useEffect(() => {
dispatch(getSearchUsers())
}, [])
return (
<div>
<Box width="100%" height="100%">
<div>
<Typography variant="h4">{handleCount()}</Typography>
</div>
</Box>
</div>
)
}
export default NumberOfUsers
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment