diff --git a/client/src/actions/cities.ts b/client/src/actions/cities.ts index a54475c7cbd69b06db3476cd7d6c08ebd7739070..9226aee57b2f477d85d9d5fa781174d097773afc 100644 --- a/client/src/actions/cities.ts +++ b/client/src/actions/cities.ts @@ -11,11 +11,11 @@ export const getCities = () => async (dispatch: AppDispatch) => { payload: res.data.items, }) dispatch({ - type: Types.SET_COMPETITIONS_TOTAL, + type: Types.SET_CITIES_COUNT, payload: res.data.total_count, }) dispatch({ - type: Types.SET_COMPETITIONS_COUNT, + type: Types.SET_CITIES_TOTAL, payload: res.data.count, }) }) diff --git a/client/src/actions/user.test.ts b/client/src/actions/user.test.ts index 156b17183a76117f87ead4f049346d85e499fea0..6ca594fa6630b35018eab088f21576836ef478f4 100644 --- a/client/src/actions/user.test.ts +++ b/client/src/actions/user.test.ts @@ -39,6 +39,9 @@ it('dispatches correct actions when logging in user', async () => { }) it('dispatches correct action when logging out user', async () => { + ;(mockedAxios.post as jest.Mock).mockImplementation((path: string, params?: any) => { + return Promise.resolve({ data: {} }) + }) const store = mockStore({}) await logoutUser()(store.dispatch) expect(store.getActions()).toEqual([{ type: Types.SET_UNAUTHENTICATED }]) diff --git a/client/src/actions/user.ts b/client/src/actions/user.ts index 30374ccafb38fd3c1f6e9a72378104b2cf2611fd..e14ea4c046013922a5e573998170b8bc46c0bcdc 100644 --- a/client/src/actions/user.ts +++ b/client/src/actions/user.ts @@ -40,11 +40,13 @@ export const getUserData = () => async (dispatch: AppDispatch) => { }) } -export const logoutUser = () => (dispatch: AppDispatch) => { - localStorage.removeItem('token') - delete axios.defaults.headers.common['Authorization'] - dispatch({ - type: Types.SET_UNAUTHENTICATED, +export const logoutUser = () => async (dispatch: AppDispatch) => { + await axios.post('/auth/logout').then(() => { + localStorage.removeItem('token') + delete axios.defaults.headers.common['Authorization'] + dispatch({ + type: Types.SET_UNAUTHENTICATED, + }) + window.location.href = '/' //redirect to login page }) - window.location.href = '/' //redirect to login page } diff --git a/client/src/pages/admin/dashboard/components/NumberOfCompetitions.tsx b/client/src/pages/admin/dashboard/components/NumberOfCompetitions.tsx index da5d015fd52d77de7e599e4f1bc2a62cee805483..87d8272ae035ce56d509dd99380bdb1ed17426a6 100644 --- a/client/src/pages/admin/dashboard/components/NumberOfCompetitions.tsx +++ b/client/src/pages/admin/dashboard/components/NumberOfCompetitions.tsx @@ -1,23 +1,23 @@ import { Box, Typography } from '@material-ui/core' import React, { useEffect } from 'react' -import { getSearchUsers } from '../../../../actions/searchUser' +import { getCompetitions } from '../../../../actions/competitions' import { useAppDispatch, useAppSelector } from '../../../../hooks' const NumberOfCompetitions: React.FC = () => { - const cities = useAppSelector((state) => state.cities.cities) + const competitions = useAppSelector((state) => state.competitions.competitions) 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> + if (competitions.length >= 1000000) { + ;<div>{competitions.length / 1000000 + 'M'}</div> + } else if (competitions.length >= 1000) { + ;<div>{competitions.length / 1000 + 'K'}</div> } - return <div>{cities.length}</div> + return <div>{competitions.length}</div> } useEffect(() => { - dispatch(getSearchUsers()) + dispatch(getCompetitions()) }, []) return ( <div> diff --git a/client/src/pages/admin/dashboard/components/NumberOfRegions.tsx b/client/src/pages/admin/dashboard/components/NumberOfRegions.tsx index a48b41a61f7a46089cedcd9e6a981b9ca625ec56..360b3663b0e45e9a24018f855ede3023c95bf39a 100644 --- a/client/src/pages/admin/dashboard/components/NumberOfRegions.tsx +++ b/client/src/pages/admin/dashboard/components/NumberOfRegions.tsx @@ -1,23 +1,23 @@ import { Box, Typography } from '@material-ui/core' import React, { useEffect } from 'react' -import { getSearchUsers } from '../../../../actions/searchUser' +import { getCities } from '../../../../actions/cities' import { useAppDispatch, useAppSelector } from '../../../../hooks' const NumberOfRegions: React.FC = () => { - const competitionTotal = useAppSelector((state) => state.competitions.total) + const regions = useAppSelector((state) => state.cities.total) const dispatch = useAppDispatch() const handleCount = () => { - if (competitionTotal >= 1000000) { - ;<div>{competitionTotal / 1000000 + 'M'}</div> - } else if (competitionTotal >= 1000) { - ;<div>{competitionTotal / 1000 + 'K'}</div> + if (regions >= 1000000) { + ;<div>{regions / 1000000 + 'M'}</div> + } else if (regions >= 1000) { + ;<div>{regions / 1000 + 'K'}</div> } - return <div>{competitionTotal}</div> + return <div>{regions}</div> } useEffect(() => { - dispatch(getSearchUsers()) + dispatch(getCities()) }, []) return ( <div> diff --git a/client/src/pages/admin/users/UserManager.tsx b/client/src/pages/admin/users/UserManager.tsx index df9cdec0b1618291b3efbe903aea69f94351aaad..20f5738604e48abe05d2ac280aff1ec56d896f6d 100644 --- a/client/src/pages/admin/users/UserManager.tsx +++ b/client/src/pages/admin/users/UserManager.tsx @@ -181,7 +181,7 @@ const UserManager: React.FC = (props: any) => { ))} </TableBody> </Table> - {(!users || users.length === 0) && <Typography>Inga tävlingar hittades med nuvarande filter</Typography>} + {(!users || users.length === 0) && <Typography>Inga användare hittades med nuvarande filter</Typography>} </TableContainer> <TablePagination component="div" diff --git a/client/src/pages/presentationEditor/components/SlideEditor.tsx b/client/src/pages/presentationEditor/components/SlideEditor.tsx index 9baa97918f2b11276bd12bf17ba8fc4f466cf9b2..a71b9262727741ea7fd29e703374c913f0d8dbb3 100644 --- a/client/src/pages/presentationEditor/components/SlideEditor.tsx +++ b/client/src/pages/presentationEditor/components/SlideEditor.tsx @@ -4,7 +4,7 @@ import { useAppSelector } from '../../../hooks' import { ImageComponent, TextComponent } from '../../../interfaces/ApiModels' import CheckboxComponent from './CheckboxComponent' import ImageComponentDisplay from './ImageComponentDisplay' -import { SlideEditorContainer } from './styled' +import { SlideEditorContainer, SlideEditorContainerRatio, SlideEditorPaper } from './styled' import TextComponentDisplay from './TextComponentDisplay' const SlideEditor: React.FC = () => { @@ -14,19 +14,23 @@ const SlideEditor: React.FC = () => { ) return ( <SlideEditorContainer> - {components && - components.map((component) => { - switch (component.type_id) { - case ComponentTypes.Checkbox: - return <CheckboxComponent key={component.id} component={component} /> - case ComponentTypes.Text: - return <TextComponentDisplay key={component.id} component={component as TextComponent} /> - case ComponentTypes.Image: - return <ImageComponentDisplay key={component.id} component={component as ImageComponent} /> - default: - break - } - })} + <SlideEditorContainerRatio> + <SlideEditorPaper> + {components && + components.map((component) => { + switch (component.type_id) { + case ComponentTypes.Checkbox: + return <CheckboxComponent key={component.id} component={component} /> + case ComponentTypes.Text: + return <TextComponentDisplay key={component.id} component={component as TextComponent} /> + case ComponentTypes.Image: + return <ImageComponentDisplay key={component.id} component={component as ImageComponent} /> + default: + break + } + })} + </SlideEditorPaper> + </SlideEditorContainerRatio> </SlideEditorContainer> ) } diff --git a/client/src/pages/presentationEditor/components/styled.tsx b/client/src/pages/presentationEditor/components/styled.tsx index c4584f87468ceea090ecabca872e8000d3b58988..d91e1db6f58216b26f56cc153f958afec360c7eb 100644 --- a/client/src/pages/presentationEditor/components/styled.tsx +++ b/client/src/pages/presentationEditor/components/styled.tsx @@ -7,11 +7,29 @@ export const SettingsTab = styled(Tab)` ` export const SlideEditorContainer = styled.div` + height: 100%; display: flex; align-items: center; justify-content: center; + background-color: rgba(0, 0, 0, 0.08); +` + +export const SlideEditorContainerRatio = styled.div` + padding-top: 56.25%; + width: 100%; + height: 0; + overflow: hidden; + padding-top: 56.25%; + position: relative; +` + +export const SlideEditorPaper = styled.div` + position: absolute; + top: 0; + left: 0; width: 100%; height: 100%; + background: white; ` export const HiddenInput = styled.input` diff --git a/client/src/utils/checkAuthentication.test.ts b/client/src/utils/checkAuthentication.test.ts index 901f331d6cc32c68e2a87c32338e879719c736af..6d12e1fc77cab5e2575af85e0b91c22ae29ad731 100644 --- a/client/src/utils/checkAuthentication.test.ts +++ b/client/src/utils/checkAuthentication.test.ts @@ -13,7 +13,9 @@ it('dispatches correct actions when auth token is ok', async () => { ;(mockedAxios.get as jest.Mock).mockImplementation((path: string, params?: any) => { return Promise.resolve(userRes) }) - + ;(mockedAxios.post as jest.Mock).mockImplementation((path: string, params?: any) => { + return Promise.resolve({ data: {} }) + }) const spy = jest.spyOn(store, 'dispatch') const testToken = 'Bearer eyJ0eXAiOiJeyJ0eXAiOiJKV1QeyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJPbmxpbmUgSldUIEJ1aWxkZXIiLCJpYXQiOjE2MTgzMDQ5MzksImV4cCI6MzI1MTI1MjU3NTcsImF1ZCI6Ind3dy5leGFtcGxlLmNvbSIsInN1YiI6Impyb2NrZXRAZXhhbXBsZS5jb20iLCJHaXZlbk5hbWUiOiJKb2hubnkiLCJTdXJuYW1lIjoiUm9ja2V0IiwiRW1haWwiOiJqcm9ja2V0QGV4YW1wbGUuY29tIiwiUm9sZSI6WyJNYW5hZ2VyIiwiUHJvamVjdCBBZG1pbmlzdHJhdG9yIl19.DrOOcCo5jMR-SNERE0uRp_kolQ2HjX8-hHXYEMnIxSceyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJPbmxpbmUgSldUIEJ1aWxkZXIiLCJpYXQiOjE2MTgzMDQ5MzksImV4cCI6MzI1MTI1MjU3NTcsImF1ZCI6Ind3dy5leGFtcGxlLmNvbSIsInN1YiI6Impyb2NrZXRAZXhhbXBsZS5jb20iLCJHaXZlbk5hbWUiOiJKb2hubnkiLCJTdXJuYW1lIjoiUm9ja2V0IiwiRW1haWwiOiJqcm9ja2V0QGV4YW1wbGUuY29tIiwiUm9sZSI6WyJNYW5hZ2VyIiwiUHJvamVjdCBBZG1pbmlzdHJhdG9yIl19.DrOOcCo5jMR-SNERE0uRp_kolQ2HjX8-hHXYEMnIxSceyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJPbmxpbmUgSldUIEJ1aWxkZXIiLCJpYXQiOjE2MTgzMDQ5MzksImV4cCI6MzI1MTI1MjU3NTcsImF1ZCI6Ind3dy5leGFtcGxlLmNvbSIsInN1YiI6Impyb2NrZXRAZXhhbXBsZS5jb20iLCJHaXZlbk5hbWUiOiJKb2hubnkiLCJTdXJuYW1lIjoiUm9ja2V0IiwiRW1haWwiOiJqcm9ja2V0QGV4YW1wbGUuY29tIiwiUm9sZSI6WyJNYW5hZ2VyIiwiUHJvamVjdCBBZG1pbmlzdHJhdG9yIl19.DrOOcCo5jMR-SNERE0uRp_kolQ2HjX8-hHXYEMnIxSceyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJPbmxpbmUgSldUIEJ1aWxkZXIiLCJpYXQiOjE2MTgzMDQ5MzksImV4cCI6MzI1MTI1MjU3NTcsImF1ZCI6Ind3dy5leGFtcGxlLmNvbSIsInN1YiI6Impyb2NrZXRAZXhhbXBsZS5jb20iLCJHaXZlbk5hbWUiOiJKb2hubnkiLCJTdXJuYW1lIjoiUm9ja2V0IiwiRW1haWwiOiJqcm9ja2V0QGV4YW1wbGUuY29tIiwiUm9sZSI6WyJNYW5hZ2VyIiwiUHJvamVjdCBBZG1pbmlzdHJhdG9yIl19.DrOOcCo5jMR-SNERE0uRp_kolQ2HjX8-hHXYEMnIxSciLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJPbmxpbmUgSldUIEJ1aWxkZXIiLCJpYXQiOjE2MTgzMDQ5MzksImV4cCI6MzI1MTI1MjU3NTcsImF1ZCI6Ind3dy5leGFtcGxlLmNvbSIsInN1YiI6Impyb2NrZXRAZXhhbXBsZS5jb20iLCJHaXZlbk5hbWUiOiJKb2hubnkiLCJTdXJuYW1lIjoiUm9ja2V0IiwiRW1haWwiOiJqcm9ja2V0QGV4YW1wbGUuY29tIiwiUm9sZSI6WyJNYW5hZ2VyIiwiUHJvamVjdCBBZG1pbmlzdHJhdG9yIl19.DrOOcCo5jMR-SNERE0uRp_kolQ2HjX8-hHXYEMnIxScKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJPbmxpbmUgSldUIEJ1aWxkZXIiLCJpYXQiOjE2MTgzMDQ5MzksImV4cCI6MzI1MTI1MjU3NTcsImF1ZCI6Ind3dy5leGFtcGxlLmNvbSIsInN1YiI6Impyb2NrZXRAZXhhbXBsZS5jb20iLCJHaXZlbk5hbWUiOiJKb2hubnkiLCJTdXJuYW1lIjoiUm9ja2V0IiwiRW1haWwiOiJqcm9ja2V0QGV4YW1wbGUuY29tIiwiUm9sZSI6WyJNYW5hZ2VyIiwiUHJvamVjdCBBZG1pbmlzdHJhdG9yIl19.DrOOcCo5jMR-SNERE0uRp_kolQ2HjX8-hHXYEMnIxSc' @@ -30,7 +32,9 @@ it('dispatches correct actions when getting user data fails', async () => { ;(mockedAxios.get as jest.Mock).mockImplementation((path: string, params?: any) => { return Promise.reject(new Error('failed getting user data')) }) - + ;(mockedAxios.post as jest.Mock).mockImplementation((path: string, params?: any) => { + return Promise.resolve({ data: {} }) + }) const spy = jest.spyOn(store, 'dispatch') const testToken = 'Bearer eyJ0eXAiOiJeyJ0eXAiOiJKV1QeyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJPbmxpbmUgSldUIEJ1aWxkZXIiLCJpYXQiOjE2MTgzMDQ5MzksImV4cCI6MzI1MTI1MjU3NTcsImF1ZCI6Ind3dy5leGFtcGxlLmNvbSIsInN1YiI6Impyb2NrZXRAZXhhbXBsZS5jb20iLCJHaXZlbk5hbWUiOiJKb2hubnkiLCJTdXJuYW1lIjoiUm9ja2V0IiwiRW1haWwiOiJqcm9ja2V0QGV4YW1wbGUuY29tIiwiUm9sZSI6WyJNYW5hZ2VyIiwiUHJvamVjdCBBZG1pbmlzdHJhdG9yIl19.DrOOcCo5jMR-SNERE0uRp_kolQ2HjX8-hHXYEMnIxSceyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJPbmxpbmUgSldUIEJ1aWxkZXIiLCJpYXQiOjE2MTgzMDQ5MzksImV4cCI6MzI1MTI1MjU3NTcsImF1ZCI6Ind3dy5leGFtcGxlLmNvbSIsInN1YiI6Impyb2NrZXRAZXhhbXBsZS5jb20iLCJHaXZlbk5hbWUiOiJKb2hubnkiLCJTdXJuYW1lIjoiUm9ja2V0IiwiRW1haWwiOiJqcm9ja2V0QGV4YW1wbGUuY29tIiwiUm9sZSI6WyJNYW5hZ2VyIiwiUHJvamVjdCBBZG1pbmlzdHJhdG9yIl19.DrOOcCo5jMR-SNERE0uRp_kolQ2HjX8-hHXYEMnIxSceyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJPbmxpbmUgSldUIEJ1aWxkZXIiLCJpYXQiOjE2MTgzMDQ5MzksImV4cCI6MzI1MTI1MjU3NTcsImF1ZCI6Ind3dy5leGFtcGxlLmNvbSIsInN1YiI6Impyb2NrZXRAZXhhbXBsZS5jb20iLCJHaXZlbk5hbWUiOiJKb2hubnkiLCJTdXJuYW1lIjoiUm9ja2V0IiwiRW1haWwiOiJqcm9ja2V0QGV4YW1wbGUuY29tIiwiUm9sZSI6WyJNYW5hZ2VyIiwiUHJvamVjdCBBZG1pbmlzdHJhdG9yIl19.DrOOcCo5jMR-SNERE0uRp_kolQ2HjX8-hHXYEMnIxSceyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJPbmxpbmUgSldUIEJ1aWxkZXIiLCJpYXQiOjE2MTgzMDQ5MzksImV4cCI6MzI1MTI1MjU3NTcsImF1ZCI6Ind3dy5leGFtcGxlLmNvbSIsInN1YiI6Impyb2NrZXRAZXhhbXBsZS5jb20iLCJHaXZlbk5hbWUiOiJKb2hubnkiLCJTdXJuYW1lIjoiUm9ja2V0IiwiRW1haWwiOiJqcm9ja2V0QGV4YW1wbGUuY29tIiwiUm9sZSI6WyJNYW5hZ2VyIiwiUHJvamVjdCBBZG1pbmlzdHJhdG9yIl19.DrOOcCo5jMR-SNERE0uRp_kolQ2HjX8-hHXYEMnIxSciLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJPbmxpbmUgSldUIEJ1aWxkZXIiLCJpYXQiOjE2MTgzMDQ5MzksImV4cCI6MzI1MTI1MjU3NTcsImF1ZCI6Ind3dy5leGFtcGxlLmNvbSIsInN1YiI6Impyb2NrZXRAZXhhbXBsZS5jb20iLCJHaXZlbk5hbWUiOiJKb2hubnkiLCJTdXJuYW1lIjoiUm9ja2V0IiwiRW1haWwiOiJqcm9ja2V0QGV4YW1wbGUuY29tIiwiUm9sZSI6WyJNYW5hZ2VyIiwiUHJvamVjdCBBZG1pbmlzdHJhdG9yIl19.DrOOcCo5jMR-SNERE0uRp_kolQ2HjX8-hHXYEMnIxScKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJPbmxpbmUgSldUIEJ1aWxkZXIiLCJpYXQiOjE2MTgzMDQ5MzksImV4cCI6MzI1MTI1MjU3NTcsImF1ZCI6Ind3dy5leGFtcGxlLmNvbSIsInN1YiI6Impyb2NrZXRAZXhhbXBsZS5jb20iLCJHaXZlbk5hbWUiOiJKb2hubnkiLCJTdXJuYW1lIjoiUm9ja2V0IiwiRW1haWwiOiJqcm9ja2V0QGV4YW1wbGUuY29tIiwiUm9sZSI6WyJNYW5hZ2VyIiwiUHJvamVjdCBBZG1pbmlzdHJhdG9yIl19.DrOOcCo5jMR-SNERE0uRp_kolQ2HjX8-hHXYEMnIxSc' @@ -43,12 +47,18 @@ it('dispatches correct actions when getting user data fails', async () => { }) it('dispatches no actions when no token exists', async () => { + ;(mockedAxios.post as jest.Mock).mockImplementation((path: string, params?: any) => { + return Promise.resolve({ data: {} }) + }) const spy = jest.spyOn(store, 'dispatch') await CheckAuthentication() expect(spy).not.toBeCalled() }) it('dispatches correct actions when token is expired', async () => { + ;(mockedAxios.post as jest.Mock).mockImplementation((path: string, params?: any) => { + return Promise.resolve({ data: {} }) + }) const testToken = 'Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJPbmxpbmUgSldUIEJ1aWxkZXIiLCJpYXQiOjE2MTgzMDY1MTUsImV4cCI6MTU4Njc3MDUxNSwiYXVkIjoid3d3LmV4YW1wbGUuY29tIiwic3ViIjoianJvY2tldEBleGFtcGxlLmNvbSIsIkdpdmVuTmFtZSI6IkpvaG5ueSIsIlN1cm5hbWUiOiJSb2NrZXQiLCJFbWFpbCI6Impyb2NrZXRAZXhhbXBsZS5jb20iLCJSb2xlIjpbIk1hbmFnZXIiLCJQcm9qZWN0IEFkbWluaXN0cmF0b3IiXX0.R5-oWGGumd-YWPoKyziJmVB8SdX6B9SsV6m7novIfgg' localStorage.setItem('token', testToken) diff --git a/client/src/utils/checkAuthentication.ts b/client/src/utils/checkAuthentication.ts index 231781543c4b8c3088585568fbeedbcab4e16f41..a782ea10f79a65998ed7d1a9e091361aa6a48982 100644 --- a/client/src/utils/checkAuthentication.ts +++ b/client/src/utils/checkAuthentication.ts @@ -4,8 +4,8 @@ import Types from '../actions/types' import { logoutUser } from '../actions/user' import store from '../store' -const UnAuthorized = () => { - logoutUser()(store.dispatch) +const UnAuthorized = async () => { + await logoutUser()(store.dispatch) } export const CheckAuthentication = async () => { @@ -29,7 +29,7 @@ export const CheckAuthentication = async () => { UnAuthorized() }) } else { - UnAuthorized() + await UnAuthorized() } } }