Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision

Target

Select target project
  • tddd96-grupp11/teknikattan-scoring-system
1 result
Select Git revision
  • dev
  • master
2 results
Show changes
Showing
with 342 additions and 133 deletions
export interface Competition {
name: string
id: number
city_id: number
year: number
}
export interface CompetitionFilterParams {
name?: string
year?: number
cityId?: number
styleId?: number
page: number
pageSize: number
}
export interface Position {
x: number
y: number
}
export interface Size {
w: number
h: number
}
export interface UserData { export interface CompetitionFilterParams {
id: number
name?: string name?: string
email: string year?: number
role_id: number cityId?: number
city_id: number styleId?: number
page: number
pageSize: number
}
export interface SearchUserFilterParams {
name?: string
year?: number
cityId?: number
styleId?: number
page: number
pageSize: number
} }
export interface UserFilterParams { export interface UserFilterParams {
......
export interface ServerResponse {
code: number
message: string
}
export interface FormModel<T> {
model: T
error?: string
}
//#region LOGIN
export interface AccountLoginModel { export interface AccountLoginModel {
email: string email: string
password: string password: string
} }
export interface CompetitionLoginModel {
code: string
}
//#endregion
////ADD////
export interface AddCompetitionModel { export interface AddCompetitionModel {
name: string name: string
city: string city: string
year: number year: number
} }
export interface CompetitionLoginModel {
code: string
}
export interface AddUserModel { export interface AddUserModel {
email: string email: string
password: string password: string
...@@ -21,9 +34,15 @@ export interface AddUserModel { ...@@ -21,9 +34,15 @@ export interface AddUserModel {
name?: string name?: string
} }
export interface AddCityModel {
name: string
}
////EDIT////
export interface EditUserModel { export interface EditUserModel {
email: string email: string
role: string role: string
city: string city: string
name?: string name?: string
password?: string
} }
export interface Role {
id: number
name: string
}
export interface SearchUSerFilterParams {
name?: string
year?: number
cityId?: number
styleId?: number
page: number
pageSize: number
}
export interface Slide {
competition_id: number
id: number
order: number
timer: number
title: string
}
export interface City { export interface Team {
id: number id: number
name: string name: string
} }
export interface ViewParams {
id: string
code: string
}
import { render } from '@testing-library/react' import { render } from '@testing-library/react'
import mockedAxios from 'axios'
import React from 'react' import React from 'react'
import { Provider } from 'react-redux' import { Provider } from 'react-redux'
import { BrowserRouter } from 'react-router-dom' import { BrowserRouter } from 'react-router-dom'
...@@ -6,6 +7,42 @@ import store from '../../store' ...@@ -6,6 +7,42 @@ import store from '../../store'
import AdminPage from './AdminPage' import AdminPage from './AdminPage'
it('renders admin view', () => { it('renders admin view', () => {
const cityRes: any = {
data: {
items: [
{
id: 1,
name: 'Link\u00f6ping',
},
{
id: 2,
name: 'Stockholm',
},
],
count: 2,
total_count: 3,
},
}
const rolesRes: any = {
data: {
items: [
{
id: 1,
name: 'role1',
},
{
id: 2,
name: 'role2',
},
],
count: 2,
total_count: 3,
},
}
;(mockedAxios.get as jest.Mock).mockImplementation((path: string, params?: any) => {
if (path === '/misc/cities') return Promise.resolve(cityRes)
else return Promise.resolve(rolesRes)
})
render( render(
<Provider store={store}> <Provider store={store}>
<BrowserRouter> <BrowserRouter>
......
...@@ -12,18 +12,21 @@ import { ...@@ -12,18 +12,21 @@ import {
} from '@material-ui/core' } from '@material-ui/core'
import { createStyles, makeStyles, Theme } from '@material-ui/core/styles' import { createStyles, makeStyles, Theme } from '@material-ui/core/styles'
import DashboardIcon from '@material-ui/icons/Dashboard' import DashboardIcon from '@material-ui/icons/Dashboard'
import MailIcon from '@material-ui/icons/Mail' import ExitToAppIcon from '@material-ui/icons/ExitToApp'
import React from 'react' import LocationCityIcon from '@material-ui/icons/LocationCity'
import PeopleIcon from '@material-ui/icons/People'
import SettingsOverscanIcon from '@material-ui/icons/SettingsOverscan'
import React, { useEffect } from 'react'
import { Link, Route, Switch, useRouteMatch } from 'react-router-dom' import { Link, Route, Switch, useRouteMatch } from 'react-router-dom'
import { getCities } from '../../actions/cities'
import { getRoles } from '../../actions/roles'
import { logoutUser } from '../../actions/user' import { logoutUser } from '../../actions/user'
import { useAppDispatch } from '../../hooks' import { useAppDispatch, useAppSelector } from '../../hooks'
import CompetitionManager from './components/CompetitionManager' import CompetitionManager from './competitions/CompetitionManager'
import Regions from './components/Regions' import RegionManager from './regions/Regions'
import UserManager from './components/UserManager'
import { LeftDrawer } from './styled' import { LeftDrawer } from './styled'
import UserManager from './users/UserManager'
const drawerWidth = 250 const drawerWidth = 250
const menuItems = ['Startsida', 'Regioner', 'Användare', 'Tävlingshanterare']
const useStyles = makeStyles((theme: Theme) => const useStyles = makeStyles((theme: Theme) =>
createStyles({ createStyles({
...@@ -42,7 +45,7 @@ const useStyles = makeStyles((theme: Theme) => ...@@ -42,7 +45,7 @@ const useStyles = makeStyles((theme: Theme) =>
content: { content: {
flexGrow: 1, flexGrow: 1,
backgroundColor: theme.palette.background.default, backgroundColor: theme.palette.background.default,
paddingLeft: theme.spacing(30), paddingLeft: theme.spacing(31),
}, },
}) })
) )
...@@ -55,13 +58,50 @@ const AdminView: React.FC = () => { ...@@ -55,13 +58,50 @@ const AdminView: React.FC = () => {
dispatch(logoutUser()) dispatch(logoutUser())
} }
const dispatch = useAppDispatch() const dispatch = useAppDispatch()
const currentUser = useAppSelector((state) => state.user.userInfo)
const isAdmin = () => currentUser && currentUser.role.name === 'Admin'
const menuAdminItems = [
{ text: 'Startsida', icon: DashboardIcon },
{ text: 'Regioner', icon: LocationCityIcon },
{ text: 'Användare', icon: PeopleIcon },
{ text: 'Tävlingshanterare', icon: SettingsOverscanIcon },
]
const menuEditorItems = [
{ text: 'Startsida', icon: DashboardIcon },
{ text: 'Tävlingshanterare', icon: SettingsOverscanIcon },
]
const renderItems = () => {
const menuItems = isAdmin() ? menuAdminItems : menuEditorItems
return menuItems.map((value, index) => (
<ListItem
button
component={Link}
key={value.text}
to={`${url}/${value.text.toLowerCase()}`}
selected={index === openIndex}
onClick={() => setOpenIndex(index)}
>
<ListItemIcon>{React.createElement(value.icon)}</ListItemIcon>
<ListItemText primary={value.text} />
</ListItem>
))
}
useEffect(() => {
dispatch(getCities())
dispatch(getRoles())
}, [])
return ( return (
<div className={classes.root}> <div className={classes.root}>
<CssBaseline /> <CssBaseline />
<AppBar position="fixed" className={classes.appBar}> <AppBar position="fixed" className={classes.appBar}>
<Toolbar> <Toolbar>
<Typography variant="h5" noWrap> <Typography variant="h5" noWrap>
{menuItems[openIndex]} {isAdmin() ? menuAdminItems[openIndex].text : menuEditorItems[openIndex].text}
</Typography> </Typography>
</Toolbar> </Toolbar>
</AppBar> </AppBar>
...@@ -76,25 +116,18 @@ const AdminView: React.FC = () => { ...@@ -76,25 +116,18 @@ const AdminView: React.FC = () => {
<div> <div>
<div className={classes.toolbar} /> <div className={classes.toolbar} />
<Divider /> <Divider />
<List> <List>{renderItems()}</List>
{menuItems.map((text, index) => (
<ListItem
button
component={Link}
key={text}
to={`${url}/${text.toLowerCase()}`}
selected={index === openIndex}
onClick={() => setOpenIndex(index)}
>
<ListItemIcon>{index === 0 ? <DashboardIcon /> : <MailIcon />}</ListItemIcon>
<ListItemText primary={text} />
</ListItem>
))}
</List>
<Divider /> <Divider />
<List> <List>
<ListItem> <ListItem>
<Button onClick={handleLogout} type="submit" fullWidth variant="contained" color="primary"> <Button
onClick={handleLogout}
type="submit"
fullWidth
variant="contained"
color="primary"
endIcon={<ExitToAppIcon></ExitToAppIcon>}
>
Logga ut Logga ut
</Button> </Button>
</ListItem> </ListItem>
...@@ -110,7 +143,7 @@ const AdminView: React.FC = () => { ...@@ -110,7 +143,7 @@ const AdminView: React.FC = () => {
</Typography> </Typography>
</Route> </Route>
<Route path={`${path}/regioner`}> <Route path={`${path}/regioner`}>
<Regions /> <RegionManager />
</Route> </Route>
<Route path={`${path}/användare`}> <Route path={`${path}/användare`}>
<UserManager /> <UserManager />
......
...@@ -6,22 +6,15 @@ import React from 'react' ...@@ -6,22 +6,15 @@ import React from 'react'
import * as Yup from 'yup' import * as Yup from 'yup'
import { getCompetitions } from '../../../actions/competitions' import { getCompetitions } from '../../../actions/competitions'
import { useAppDispatch, useAppSelector } from '../../../hooks' import { useAppDispatch, useAppSelector } from '../../../hooks'
import { City } from '../../../interfaces/City' import { City } from '../../../interfaces/ApiModels'
import { AddCompetitionModel } from '../../../interfaces/models' import { AddCompetitionModel, FormModel } from '../../../interfaces/FormModels'
import { AddCompetitionButton, AddCompetitionContent, AddCompetitionForm } from './styled' import { AddButton, AddContent, AddForm } from '../styledComp'
interface ServerResponse { type formType = FormModel<AddCompetitionModel>
code: number
message: string
}
interface AddCompetitionFormModel {
model: AddCompetitionModel
error?: string
}
const noCitySelected = 'Välj stad' const noCitySelected = 'Välj stad'
const competitionSchema: Yup.SchemaOf<AddCompetitionFormModel> = Yup.object({ const competitionSchema: Yup.SchemaOf<formType> = Yup.object({
model: Yup.object() model: Yup.object()
.shape({ .shape({
name: Yup.string().required('Namn krävs'), name: Yup.string().required('Namn krävs'),
...@@ -51,17 +44,14 @@ const AddCompetition: React.FC = (props: any) => { ...@@ -51,17 +44,14 @@ const AddCompetition: React.FC = (props: any) => {
const dispatch = useAppDispatch() const dispatch = useAppDispatch()
const id = open ? 'simple-popover' : undefined const id = open ? 'simple-popover' : undefined
const currentYear = new Date().getFullYear() const currentYear = new Date().getFullYear()
const handleCompetitionSubmit = async ( const handleCompetitionSubmit = async (values: formType, actions: FormikHelpers<formType>) => {
values: AddCompetitionFormModel,
actions: FormikHelpers<AddCompetitionFormModel>
) => {
const params = { const params = {
name: values.model.name, name: values.model.name,
year: values.model.year, year: values.model.year,
city_id: selectedCity?.id as number, city_id: selectedCity?.id as number,
} }
await axios await axios
.post<ServerResponse>('/competitions', params) .post('/competitions', params)
.then(() => { .then(() => {
actions.resetForm() actions.resetForm()
setAnchorEl(null) setAnchorEl(null)
...@@ -79,14 +69,19 @@ const AddCompetition: React.FC = (props: any) => { ...@@ -79,14 +69,19 @@ const AddCompetition: React.FC = (props: any) => {
}) })
} }
const competitionInitialValues: AddCompetitionFormModel = { const competitionInitialValues: formType = {
model: { name: '', city: userCity?.name ? userCity.name : noCitySelected, year: currentYear }, model: { name: '', city: userCity?.name ? userCity.name : noCitySelected, year: currentYear },
} }
return ( return (
<div> <div>
<AddCompetitionButton color="secondary" variant="contained" onClick={handleClick}> <AddButton
style={{ backgroundColor: '#4caf50', color: '#fcfcfc' }}
color="default"
variant="contained"
onClick={handleClick}
>
Ny Tävling Ny Tävling
</AddCompetitionButton> </AddButton>
<Popover <Popover
id={id} id={id}
open={open} open={open}
...@@ -101,14 +96,14 @@ const AddCompetition: React.FC = (props: any) => { ...@@ -101,14 +96,14 @@ const AddCompetition: React.FC = (props: any) => {
horizontal: 'center', horizontal: 'center',
}} }}
> >
<AddCompetitionContent> <AddContent>
<Formik <Formik
initialValues={competitionInitialValues} initialValues={competitionInitialValues}
validationSchema={competitionSchema} validationSchema={competitionSchema}
onSubmit={handleCompetitionSubmit} onSubmit={handleCompetitionSubmit}
> >
{(formik) => ( {(formik) => (
<AddCompetitionForm onSubmit={formik.handleSubmit}> <AddForm onSubmit={formik.handleSubmit}>
<TextField <TextField
label="Namn" label="Namn"
name="model.name" name="model.name"
...@@ -170,10 +165,10 @@ const AddCompetition: React.FC = (props: any) => { ...@@ -170,10 +165,10 @@ const AddCompetition: React.FC = (props: any) => {
{formik.errors.error} {formik.errors.error}
</Alert> </Alert>
)} )}
</AddCompetitionForm> </AddForm>
)} )}
</Formik> </Formik>
</AddCompetitionContent> </AddContent>
</Popover> </Popover>
</div> </div>
) )
......
...@@ -14,13 +14,12 @@ import TableRow from '@material-ui/core/TableRow' ...@@ -14,13 +14,12 @@ import TableRow from '@material-ui/core/TableRow'
import MoreHorizIcon from '@material-ui/icons/MoreHoriz' import MoreHorizIcon from '@material-ui/icons/MoreHoriz'
import axios from 'axios' import axios from 'axios'
import React, { useEffect } from 'react' import React, { useEffect } from 'react'
import { Link } from 'react-router-dom' import { Link, useHistory } from 'react-router-dom'
import { getCities } from '../../../actions/cities'
import { getCompetitions, setFilterParams } from '../../../actions/competitions' import { getCompetitions, setFilterParams } from '../../../actions/competitions'
import { useAppDispatch, useAppSelector } from '../../../hooks' import { useAppDispatch, useAppSelector } from '../../../hooks'
import { CompetitionFilterParams } from '../../../interfaces/CompetitionFilterParams' import { CompetitionFilterParams } from '../../../interfaces/FilterParams'
import { FilterContainer, RemoveMenuItem, TopBar, YearFilterTextField } from '../styledComp'
import AddCompetition from './AddCompetition' import AddCompetition from './AddCompetition'
import { FilterContainer, RemoveCompetition, TopBar, YearFilterTextField } from './styled'
const useStyles = makeStyles((theme: Theme) => const useStyles = makeStyles((theme: Theme) =>
createStyles({ createStyles({
...@@ -44,6 +43,7 @@ const CompetitionManager: React.FC = (props: any) => { ...@@ -44,6 +43,7 @@ const CompetitionManager: React.FC = (props: any) => {
const classes = useStyles() const classes = useStyles()
const noFilterText = 'Alla' const noFilterText = 'Alla'
const dispatch = useAppDispatch() const dispatch = useAppDispatch()
const history = useHistory()
const handleClick = (event: React.MouseEvent<HTMLButtonElement>, id: number) => { const handleClick = (event: React.MouseEvent<HTMLButtonElement>, id: number) => {
setAnchorEl(event.currentTarget) setAnchorEl(event.currentTarget)
setActiveId(id) setActiveId(id)
...@@ -55,7 +55,6 @@ const CompetitionManager: React.FC = (props: any) => { ...@@ -55,7 +55,6 @@ const CompetitionManager: React.FC = (props: any) => {
} }
useEffect(() => { useEffect(() => {
dispatch(getCities())
dispatch(getCompetitions()) dispatch(getCompetitions())
}, []) }, [])
...@@ -176,9 +175,9 @@ const CompetitionManager: React.FC = (props: any) => { ...@@ -176,9 +175,9 @@ const CompetitionManager: React.FC = (props: any) => {
onChangePage={(event, newPage) => handleFilterChange({ ...filterParams, page: newPage })} onChangePage={(event, newPage) => handleFilterChange({ ...filterParams, page: newPage })}
/> />
<Menu id="simple-menu" anchorEl={anchorEl} keepMounted open={Boolean(anchorEl)} onClose={handleClose}> <Menu id="simple-menu" anchorEl={anchorEl} keepMounted open={Boolean(anchorEl)} onClose={handleClose}>
<MenuItem onClick={handleClose}>Starta</MenuItem> <MenuItem onClick={() => history.push(`/presenter/id=${activeId}&code=123123`)}>Starta</MenuItem>
<MenuItem onClick={handleClose}>Duplicera</MenuItem> <MenuItem onClick={handleClose}>Duplicera</MenuItem>
<RemoveCompetition onClick={handleDeleteCompetition}>Ta bort</RemoveCompetition> <RemoveMenuItem onClick={handleDeleteCompetition}>Ta bort</RemoveMenuItem>
</Menu> </Menu>
</div> </div>
) )
......
import { Grid, TextField } from '@material-ui/core'
import FormControl from '@material-ui/core/FormControl'
import { createStyles, makeStyles, Theme } from '@material-ui/core/styles'
import AddIcon from '@material-ui/icons/Add'
import { Alert, AlertTitle } from '@material-ui/lab'
import axios from 'axios'
import { Formik, FormikHelpers } from 'formik'
import React from 'react'
import * as Yup from 'yup'
import { getCities } from '../../../actions/cities'
import { useAppDispatch } from '../../../hooks'
import { AddCityModel, FormModel } from '../../../interfaces/FormModels'
import { AddButton, AddForm } from '../styledComp'
const useStyles = makeStyles((theme: Theme) =>
createStyles({
table: {
width: '100%',
},
margin: {
margin: theme.spacing(1),
},
button: {
width: '40px',
height: '40px',
marginTop: '20px',
},
})
)
type formType = FormModel<AddCityModel>
const schema: Yup.SchemaOf<formType> = Yup.object({
model: Yup.object()
.shape({
name: Yup.string()
.required('Minst två bokstäver krävs')
.min(2)
.matches(/[a-zA-Z]/, 'Namnet får enbart innehålla a-z, A-Z.'),
})
.required(),
error: Yup.string().optional(),
})
const AddRegion: React.FC = (props: any) => {
const classes = useStyles()
const dispatch = useAppDispatch()
const handleSubmit = async (values: formType, actions: FormikHelpers<formType>) => {
const params = {
name: values.model.name,
}
await axios
.post('/misc/cities', params)
.then(() => {
actions.resetForm()
dispatch(getCities())
})
.catch(({ response }) => {
console.warn(response.data)
if (response.data && response.data.message)
actions.setFieldError('error', response.data && response.data.message)
else actions.setFieldError('error', 'Something went wrong, please try again')
})
.finally(() => {
actions.setSubmitting(false)
})
}
const initValues: formType = {
model: { name: '' },
}
return (
<Formik initialValues={initValues} validationSchema={schema} onSubmit={handleSubmit}>
{(formik) => (
<AddForm onSubmit={formik.handleSubmit}>
<FormControl className={classes.margin}>
<Grid container={true}>
<TextField
className={classes.margin}
helperText={formik.touched.model?.name ? formik.errors.model?.name : ''}
error={Boolean(formik.touched.model?.name && formik.errors.model?.name)}
onChange={formik.handleChange}
onBlur={formik.handleBlur}
name="model.name"
label="Region"
></TextField>
<AddButton
style={{ backgroundColor: '#4caf50', color: '#fcfcfc' }}
className={classes.button}
color="default"
variant="contained"
type="submit"
>
<AddIcon></AddIcon>
</AddButton>
</Grid>
</FormControl>
{formik.errors.error && (
<Alert severity="error">
<AlertTitle>Error</AlertTitle>
{formik.errors.error}
</Alert>
)}
</AddForm>
)}
</Formik>
)
}
export default AddRegion
import { Button, Menu, TextField, Typography } from '@material-ui/core' import { Button, Menu, Typography } from '@material-ui/core'
import FormControl from '@material-ui/core/FormControl'
import Paper from '@material-ui/core/Paper' import Paper from '@material-ui/core/Paper'
import { createStyles, makeStyles, Theme } from '@material-ui/core/styles' import { createStyles, makeStyles, Theme } from '@material-ui/core/styles'
import Table from '@material-ui/core/Table' import Table from '@material-ui/core/Table'
...@@ -13,8 +12,8 @@ import axios from 'axios' ...@@ -13,8 +12,8 @@ import axios from 'axios'
import React, { useEffect } from 'react' import React, { useEffect } from 'react'
import { getCities } from '../../../actions/cities' import { getCities } from '../../../actions/cities'
import { useAppDispatch, useAppSelector } from '../../../hooks' import { useAppDispatch, useAppSelector } from '../../../hooks'
import { RemoveCompetition, TopBar } from './styled' import { RemoveMenuItem, TopBar } from '../styledComp'
import AddRegion from './AddRegion'
const useStyles = makeStyles((theme: Theme) => const useStyles = makeStyles((theme: Theme) =>
createStyles({ createStyles({
table: { table: {
...@@ -26,12 +25,12 @@ const useStyles = makeStyles((theme: Theme) => ...@@ -26,12 +25,12 @@ const useStyles = makeStyles((theme: Theme) =>
}) })
) )
const UserManager: React.FC = (props: any) => { const RegionManager: React.FC = (props: any) => {
const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null) const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null)
const [activeId, setActiveId] = React.useState<number | undefined>(undefined) const [activeId, setActiveId] = React.useState<number | undefined>(undefined)
const citiesTotal = useAppSelector((state) => state.cities.total) const citiesTotal = useAppSelector((state) => state.cities.total)
const cities = useAppSelector((state) => state.cities.cities) const cities = useAppSelector((state) => state.cities.cities)
const [newCity, setNewCity] = React.useState() const [newCity, setNewCity] = React.useState<string>()
const classes = useStyles() const classes = useStyles()
const dispatch = useAppDispatch() const dispatch = useAppDispatch()
const handleClose = () => { const handleClose = () => {
...@@ -81,12 +80,7 @@ const UserManager: React.FC = (props: any) => { ...@@ -81,12 +80,7 @@ const UserManager: React.FC = (props: any) => {
return ( return (
<div> <div>
<TopBar> <TopBar>
<FormControl className={classes.margin}> <AddRegion></AddRegion>
<TextField className={classes.margin} value={newCity} onChange={handleChange} label="Region"></TextField>
<Button color="primary" variant="contained" onClick={handleAddCity}>
Lägg till
</Button>
</FormControl>
</TopBar> </TopBar>
<TableContainer component={Paper}> <TableContainer component={Paper}>
<Table className={classes.table} aria-label="simple table"> <Table className={classes.table} aria-label="simple table">
...@@ -113,10 +107,10 @@ const UserManager: React.FC = (props: any) => { ...@@ -113,10 +107,10 @@ const UserManager: React.FC = (props: any) => {
{(!cities || cities.length === 0) && <Typography>Inga regioner hittades</Typography>} {(!cities || cities.length === 0) && <Typography>Inga regioner hittades</Typography>}
</TableContainer> </TableContainer>
<Menu id="simple-menu" anchorEl={anchorEl} keepMounted open={Boolean(anchorEl)} onClose={handleClose}> <Menu id="simple-menu" anchorEl={anchorEl} keepMounted open={Boolean(anchorEl)} onClose={handleClose}>
<RemoveCompetition onClick={handleDeleteCity}>Ta bort</RemoveCompetition> <RemoveMenuItem onClick={handleDeleteCity}>Ta bort</RemoveMenuItem>
</Menu> </Menu>
</div> </div>
) )
} }
export default UserManager export default RegionManager
...@@ -7,20 +7,22 @@ export const TopBar = styled.div` ...@@ -7,20 +7,22 @@ export const TopBar = styled.div`
align-items: flex-end; align-items: flex-end;
` `
export const AddCompetitionButton = styled(Button)` export const AddButton = styled(Button)`
margin-bottom: 8px; margin-bottom: 8px;
` `
export const AddCompetitionForm = styled.form` export const AddForm = styled.form`
display: flex; display: flex;
flex-direction: column; flex-direction: column;
` `
export const AddCompetitionContent = styled.div` export const AddContent = styled.div`
padding: 15px; padding: 25px;
padding-bottom: 40px;
width: 300px;
` `
export const RemoveCompetition = styled(MenuItem)` export const RemoveMenuItem = styled(MenuItem)`
color: red; color: red;
` `
......
import { Button, FormControl, InputLabel, MenuItem, Popover, TextField } from '@material-ui/core' import { Button, FormControl, InputLabel, MenuItem, Popover, TextField } from '@material-ui/core'
import PersonAddIcon from '@material-ui/icons/PersonAdd'
import { Alert, AlertTitle } from '@material-ui/lab' import { Alert, AlertTitle } from '@material-ui/lab'
import axios from 'axios' import axios from 'axios'
import { Formik, FormikHelpers } from 'formik' import { Formik, FormikHelpers } from 'formik'
...@@ -6,28 +7,19 @@ import React from 'react' ...@@ -6,28 +7,19 @@ import React from 'react'
import * as Yup from 'yup' import * as Yup from 'yup'
import { getSearchUsers } from '../../../actions/searchUser' import { getSearchUsers } from '../../../actions/searchUser'
import { useAppDispatch, useAppSelector } from '../../../hooks' import { useAppDispatch, useAppSelector } from '../../../hooks'
import { City } from '../../../interfaces/City' import { City, Role } from '../../../interfaces/ApiModels'
import { AddUserModel } from '../../../interfaces/models' import { AddUserModel, FormModel } from '../../../interfaces/FormModels'
import { Role } from '../../../interfaces/Role' import { AddButton, AddContent, AddForm } from '../styledComp'
import { AddCompetitionButton, AddCompetitionContent, AddCompetitionForm } from './styled'
interface ServerResponse { type formType = FormModel<AddUserModel>
code: number
message: string
}
interface AddUserFormModel {
model: AddUserModel
error?: string
}
const noRoleSelected = 'Välj roll' const noRoleSelected = 'Välj roll'
const noCitySelected = 'Välj stad' const noCitySelected = 'Välj stad'
const userSchema: Yup.SchemaOf<AddUserFormModel> = Yup.object({ const userSchema: Yup.SchemaOf<formType> = Yup.object({
model: Yup.object() model: Yup.object()
.shape({ .shape({
name: Yup.string(), //.required('Namn krävs'), name: Yup.string(),
email: Yup.string().email().required('Email krävs'), email: Yup.string().email().required('Email krävs'),
password: Yup.string() password: Yup.string()
.required('Lösenord krävs.') .required('Lösenord krävs.')
...@@ -58,7 +50,7 @@ const AddUser: React.FC = (props: any) => { ...@@ -58,7 +50,7 @@ const AddUser: React.FC = (props: any) => {
const open = Boolean(anchorEl) const open = Boolean(anchorEl)
const dispatch = useAppDispatch() const dispatch = useAppDispatch()
const id = open ? 'simple-popover' : undefined const id = open ? 'simple-popover' : undefined
const handleCompetitionSubmit = async (values: AddUserFormModel, actions: FormikHelpers<AddUserFormModel>) => { const handleSubmit = async (values: formType, actions: FormikHelpers<formType>) => {
const params = { const params = {
email: values.model.email, email: values.model.email,
password: values.model.password, password: values.model.password,
...@@ -67,7 +59,7 @@ const AddUser: React.FC = (props: any) => { ...@@ -67,7 +59,7 @@ const AddUser: React.FC = (props: any) => {
role_id: selectedRole?.id as number, role_id: selectedRole?.id as number,
} }
await axios await axios
.post<ServerResponse>('/auth/signup', params) .post('/auth/signup', params)
.then(() => { .then(() => {
actions.resetForm() actions.resetForm()
setAnchorEl(null) setAnchorEl(null)
...@@ -86,14 +78,20 @@ const AddUser: React.FC = (props: any) => { ...@@ -86,14 +78,20 @@ const AddUser: React.FC = (props: any) => {
}) })
} }
const userInitialValues: AddUserFormModel = { const userInitialValues: formType = {
model: { email: '', password: '', name: '', city: noCitySelected, role: noRoleSelected }, model: { email: '', password: '', name: '', city: noCitySelected, role: noRoleSelected },
} }
return ( return (
<div> <div>
<AddCompetitionButton color="secondary" variant="contained" onClick={handleClick}> <AddButton
style={{ backgroundColor: '#4caf50', color: '#fcfcfc' }}
color="default"
variant="contained"
onClick={handleClick}
endIcon={<PersonAddIcon></PersonAddIcon>}
>
Ny Användare Ny Användare
</AddCompetitionButton> </AddButton>
<Popover <Popover
id={id} id={id}
open={open} open={open}
...@@ -108,10 +106,10 @@ const AddUser: React.FC = (props: any) => { ...@@ -108,10 +106,10 @@ const AddUser: React.FC = (props: any) => {
horizontal: 'center', horizontal: 'center',
}} }}
> >
<AddCompetitionContent> <AddContent>
<Formik initialValues={userInitialValues} validationSchema={userSchema} onSubmit={handleCompetitionSubmit}> <Formik initialValues={userInitialValues} validationSchema={userSchema} onSubmit={handleSubmit}>
{(formik) => ( {(formik) => (
<AddCompetitionForm onSubmit={formik.handleSubmit}> <AddForm onSubmit={formik.handleSubmit}>
<TextField <TextField
label="Email" label="Email"
name="model.email" name="model.email"
...@@ -208,10 +206,10 @@ const AddUser: React.FC = (props: any) => { ...@@ -208,10 +206,10 @@ const AddUser: React.FC = (props: any) => {
{formik.errors.error} {formik.errors.error}
</Alert> </Alert>
)} )}
</AddCompetitionForm> </AddForm>
)} )}
</Formik> </Formik>
</AddCompetitionContent> </AddContent>
</Popover> </Popover>
</div> </div>
) )
......