privacy policy

This commit is contained in:
Mateusz 2022-12-15 15:05:10 +01:00
parent 509d8dc6e9
commit 300e7d67db
13 changed files with 888 additions and 529 deletions

2
.env
View File

@ -1,3 +1,3 @@
REACT_APP_KC_URL=https://auth-dev.csi.wmi.amu.edu.pl/
REACT_APP_KC_REALM=gonito-dev
REACT_APP_KC_CLIENT_ID=gonito-dev-heroku
REACT_APP_KC_CLIENT_ID=gonito-dev-localhost

View File

@ -1,114 +1,134 @@
import {ThemeProvider} from 'styled-components';
import { ThemeProvider } from 'styled-components';
import theme from './utils/theme';
import LandingPage from './pages/LandingPage';
import Challenges from './pages/Challanges/Challenges';
import {BrowserRouter, Route, Routes} from 'react-router-dom';
import { BrowserRouter, Route, Routes } from 'react-router-dom';
import NavBar from './components/navigation/NavBar';
import {CHALLENGE_PAGE, CHALLENGES_PAGE, IS_MOBILE} from './utils/globals';
import {
CHALLENGE_PAGE,
CHALLENGES_PAGE,
IS_MOBILE,
POLICY_PRIVACY_PAGE,
} from './utils/globals';
import Challenge from './pages/Challenge';
import KeyCloakService from './services/KeyCloakService';
import React from 'react';
import LoggedBar from './components/navigation/LoggedBar';
import addUser from './api/addUser';
import Loading from './components/generic/Loading';
import {FlexColumn} from './utils/containers';
import { FlexColumn } from './utils/containers';
import PopupMessage from './components/generic/PopupMessage';
import PolicyPrivacy from './pages/PolicyPrivacy';
const App = () => {
const [loggedBarVisible, setLoggedBarVisible] = React.useState('100vw');
const [loggedBarHover, setLoggedBarHover] = React.useState(false);
const [popUpHeader, setPopUpHeader] = React.useState('');
const [popUpMessage, setPopUpMessage] = React.useState('');
React.useEffect(() => {
if (sessionStorage.getItem('logged') !== 'yes') {
if (KeyCloakService.isLoggedIn()) {
sessionStorage.setItem('logged', 'yes');
addUser();
}
}
setTimeout(() => {
if (sessionStorage.getItem('logged') === 'yes') {
if (!KeyCloakService.isLoggedIn()) {
KeyCloakService.doLogin();
}
}
}, 1500);
});
const popUpMessageHandler = (header, message) => {
setPopUpHeader(header);
setPopUpMessage(message);
};
const popUpMessageRender = () => {
if (popUpHeader !== '' || popUpMessage !== '') {
return (
<PopupMessage header={popUpHeader} message={popUpMessage} popUpMessageHandler={popUpMessageHandler}/>
);
}
};
const loggedBarVisibleHandler = () => {
if (loggedBarVisible === '0' && !loggedBarHover)
setLoggedBarVisible('100vw');
else setLoggedBarVisible('0');
};
const loggedBarHoverTrue = () => {
setLoggedBarHover(true);
};
const loggedBarHoverFalse = () => {
setLoggedBarHover(false);
};
const renderApp = () => {
return (
<BrowserRouter>
<ThemeProvider theme={theme}>
{popUpMessageRender()}
<NavBar loggedBarVisibleHandler={loggedBarVisibleHandler}/>
{!IS_MOBILE() ?
<LoggedBar visible={loggedBarVisible} loggedBarVisibleHandler={loggedBarVisibleHandler}
loggedBarHoverTrue={loggedBarHoverTrue}
loggedBarHoverFalse={loggedBarHoverFalse}
username={KeyCloakService.getUsername()}/> : ''}
<Routes>
<Route path={`${CHALLENGE_PAGE}/:challengeId`}
element={<Challenge popUpMessageHandler={popUpMessageHandler}/>}/>
<Route path={CHALLENGES_PAGE} element={<Challenges/>}/>
{
KeyCloakService.isLoggedIn() ? <>
<Route exact path='/' element={<Challenges/>}/>
<Route element={<Challenges/>}/>
</> : <>
<Route exact path='/' element={<LandingPage/>}/>
<Route element={<LandingPage/>}/>
</>
}
</Routes>
</ThemeProvider>
</BrowserRouter>
);
};
if (sessionStorage.getItem('logged') === 'yes') {
if (KeyCloakService.isLoggedIn()) {
return renderApp();
} else {
return (
<ThemeProvider theme={theme}>
<FlexColumn width='100vw' height='100vh'>
<Loading/>
</FlexColumn>
</ThemeProvider>
);
}
} else {
return renderApp();
const [loggedBarVisible, setLoggedBarVisible] = React.useState('100vw');
const [loggedBarHover, setLoggedBarHover] = React.useState(false);
const [popUpHeader, setPopUpHeader] = React.useState('');
const [popUpMessage, setPopUpMessage] = React.useState('');
React.useEffect(() => {
if (sessionStorage.getItem('logged') !== 'yes') {
if (KeyCloakService.isLoggedIn()) {
sessionStorage.setItem('logged', 'yes');
addUser();
}
}
setTimeout(() => {
if (sessionStorage.getItem('logged') === 'yes') {
if (!KeyCloakService.isLoggedIn()) {
KeyCloakService.doLogin();
}
}
}, 1500);
});
const popUpMessageHandler = (header, message) => {
setPopUpHeader(header);
setPopUpMessage(message);
};
const popUpMessageRender = () => {
if (popUpHeader !== '' || popUpMessage !== '') {
return (
<PopupMessage
header={popUpHeader}
message={popUpMessage}
popUpMessageHandler={popUpMessageHandler}
/>
);
}
};
const loggedBarVisibleHandler = () => {
if (loggedBarVisible === '0' && !loggedBarHover)
setLoggedBarVisible('100vw');
else setLoggedBarVisible('0');
};
const loggedBarHoverTrue = () => {
setLoggedBarHover(true);
};
const loggedBarHoverFalse = () => {
setLoggedBarHover(false);
};
const renderApp = () => {
return (
<BrowserRouter>
<ThemeProvider theme={theme}>
{popUpMessageRender()}
<NavBar loggedBarVisibleHandler={loggedBarVisibleHandler} />
{!IS_MOBILE() ? (
<LoggedBar
visible={loggedBarVisible}
loggedBarVisibleHandler={loggedBarVisibleHandler}
loggedBarHoverTrue={loggedBarHoverTrue}
loggedBarHoverFalse={loggedBarHoverFalse}
username={KeyCloakService.getUsername()}
/>
) : (
''
)}
<Routes>
<Route
path={`${CHALLENGE_PAGE}/:challengeId`}
element={<Challenge popUpMessageHandler={popUpMessageHandler} />}
/>
<Route path={CHALLENGES_PAGE} element={<Challenges />} />
<Route path={POLICY_PRIVACY_PAGE} element={<PolicyPrivacy />} />
{KeyCloakService.isLoggedIn() ? (
<>
<Route exact path="/" element={<Challenges />} />
<Route element={<Challenges />} />
</>
) : (
<>
<Route exact path="/" element={<LandingPage />} />
<Route element={<LandingPage />} />
</>
)}
</Routes>
</ThemeProvider>
</BrowserRouter>
);
};
if (sessionStorage.getItem('logged') === 'yes') {
if (KeyCloakService.isLoggedIn()) {
return renderApp();
} else {
return (
<ThemeProvider theme={theme}>
<FlexColumn width="100vw" height="100vh">
<Loading />
</FlexColumn>
</ThemeProvider>
);
}
} else {
return renderApp();
}
};
export default App;

View File

@ -0,0 +1,8 @@
<svg width="33" height="33" viewBox="0 0 33 33" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M3.26301 0.360924C2.60038 0.536053 2.09404 0.830019 1.59395 1.33039C1.08761 1.83701 0.800055 2.33737 0.625023 3.02538C0.5 3.49447 0.5 3.75717 0.5 14.2461C0.5 24.7351 0.5 24.9977 0.625023 25.4668C0.800055 26.1548 1.08761 26.6552 1.59395 27.1618C2.10029 27.6685 2.60038 27.9562 3.28801 28.1313C3.7506 28.2501 4.00064 28.2564 9.30161 28.2564C15.4402 28.2564 15.0839 28.2814 15.4215 27.8436C15.7528 27.4058 15.6528 26.7991 15.2027 26.4551L14.9839 26.2862L9.35162 26.2549C3.91313 26.2236 3.71309 26.2174 3.46929 26.0986C3.15674 25.9422 2.81292 25.5982 2.65665 25.2855C2.53162 25.0415 2.53162 24.8476 2.53162 14.2461C2.53162 3.64458 2.53162 3.45069 2.65665 3.20676C2.81292 2.89403 3.15674 2.55003 3.46929 2.39367C3.71309 2.26857 3.88812 2.26857 11.8458 2.26857H19.9723L20.2224 2.40618C20.5474 2.5813 20.9037 2.95658 21.0475 3.26931C21.1538 3.50073 21.16 3.84473 21.1913 7.52243C21.2225 11.2502 21.2288 11.5441 21.3351 11.7005C21.5101 11.9694 21.8039 12.1196 22.1665 12.1196C22.5728 12.1196 22.8603 11.9382 23.0541 11.5566L23.1979 11.2752L23.1729 7.27225C23.1542 2.86901 23.1729 3.06291 22.7541 2.23105C22.3415 1.4242 21.5101 0.704927 20.6412 0.410961L20.2224 0.267106L11.9709 0.254596C4.00689 0.242087 3.70059 0.248342 3.26301 0.360924Z" fill="black"/>
<path d="M5.16949 5.63979C4.86318 5.75237 4.76941 5.83994 4.61313 6.14016C4.38184 6.59674 4.53187 7.09711 5.00071 7.40984L5.20699 7.5537H8.50135H11.7957L12.002 7.40984C12.302 7.20969 12.4521 6.97827 12.4833 6.66554C12.5271 6.30278 12.3396 5.9275 12.0207 5.73361L11.7832 5.5835L8.59511 5.57099C6.0384 5.55848 5.36327 5.57099 5.16949 5.63979Z" fill="black"/>
<path d="M5.00082 11.0688C4.70076 11.2752 4.55074 11.5066 4.51948 11.8193C4.47572 12.1821 4.66326 12.5574 4.98206 12.7513L5.21961 12.9014L11.627 12.9201C15.1527 12.9326 18.1532 12.9201 18.3033 12.9014C18.6596 12.8513 19.0409 12.5136 19.1284 12.1758C19.2472 11.7443 19.0221 11.2314 18.6283 11.025C18.472 10.9437 17.5469 10.9312 11.8271 10.9312H5.20711L5.00082 11.0688Z" fill="black"/>
<path d="M23.4104 13.8959C19.5597 15.1906 17.053 16.0662 16.9155 16.1538C16.828 16.2101 16.6967 16.3789 16.6279 16.529C16.4967 16.798 16.4967 16.848 16.5217 20.1379C16.5467 23.7969 16.5529 23.8719 16.9718 25.0978C17.8594 27.6935 20.2911 30.2266 23.4729 31.859C24.4919 32.3844 24.5169 32.3844 25.5858 31.834C28.7677 30.1953 31.2056 27.6309 32.062 25.004C32.4621 23.7906 32.4621 23.7781 32.4871 20.1379C32.5121 16.848 32.5121 16.798 32.3808 16.529C32.3121 16.3789 32.1808 16.2101 32.0933 16.1538C31.912 16.0349 24.9482 13.6519 24.6232 13.5956C24.4669 13.5644 24.1543 13.6457 23.4104 13.8959ZM27.4737 16.6479L30.4742 17.6674V20.4757L30.468 23.284L30.3055 23.8969C29.8429 25.5919 28.7239 27.1618 27.0236 28.5191C26.4485 28.9757 25.5608 29.5761 24.9857 29.8826L24.5106 30.139L24.1481 29.9576C23.6042 29.6762 22.554 28.9694 21.8351 28.394C20.2536 27.1181 19.1534 25.5356 18.7033 23.8969L18.5408 23.284L18.5345 20.4757V17.6674L21.3476 16.7104C23.7355 15.9036 24.4731 15.6471 24.4731 15.6284C24.4731 15.6221 25.8234 16.085 27.4737 16.6479Z" fill="black"/>
<path d="M27.7113 19.0371C27.5675 19.1059 27.0299 19.7814 25.8422 21.3701C24.9233 22.596 24.1481 23.6217 24.1231 23.6593C24.0856 23.6905 23.6668 23.3215 23.0479 22.7086C22.204 21.8705 21.9915 21.6891 21.7727 21.6328C21.2976 21.5014 20.8475 21.7016 20.6287 22.1269C20.4912 22.4021 20.4724 22.6585 20.5662 22.9212C20.6537 23.1526 23.5418 26.0548 23.7981 26.1674C24.0669 26.2862 24.3294 26.2799 24.6045 26.1486C24.7982 26.0548 25.2358 25.5044 26.9736 23.1902C28.3989 21.2888 29.124 20.2693 29.149 20.1317C29.2303 19.7189 28.999 19.2185 28.6302 19.0309C28.3927 18.912 27.9613 18.912 27.7113 19.0371Z" fill="black"/>
<path d="M5.09471 16.3352C4.67588 16.5165 4.43834 16.9981 4.52585 17.4672C4.58211 17.7612 4.89467 18.1052 5.17597 18.1865C5.33225 18.2365 6.67625 18.2491 9.29548 18.2365C13.1274 18.2178 13.1837 18.2178 13.3587 18.0864C13.9713 17.6299 13.9713 16.8668 13.3587 16.4102C13.1837 16.2789 13.1274 16.2789 9.23296 16.2664C6.04488 16.2538 5.24473 16.2664 5.09471 16.3352Z" fill="black"/>
</svg>

After

Width:  |  Height:  |  Size: 4.0 KiB

View File

@ -1,18 +1,19 @@
import React from 'react';
import styled from 'styled-components';
import {Medium} from '../../utils/fonts';
import { Medium } from '../../utils/fonts';
import PropsTypes from 'prop-types';
const ButtonStyle = styled(Medium)`
display: flex;
justify-content: center;
align-items: center;
width: ${({width}) => width ? width : '64px'};
height: ${({height}) => height ? height : '28px'};
width: ${({ width }) => (width ? width : '64px')};
height: ${({ height }) => (height ? height : '28px')};
border-radius: 12px;
background-color: ${({theme, backgroundColor}) => backgroundColor ? backgroundColor : theme.colors.green};
color: ${({theme, color}) => color ? color : theme.colors.white};
box-shadow: ${({theme}) => theme.buttonShadow};
background-color: ${({ theme, backgroundColor }) =>
backgroundColor ? backgroundColor : theme.colors.green};
color: ${({ theme, color }) => (color ? color : theme.colors.white)};
box-shadow: ${({ theme }) => theme.buttonShadow};
cursor: pointer;
transition: transform 0.3s ease-in-out;
@ -26,30 +27,37 @@ const ButtonStyle = styled(Medium)`
`;
const Button = (props) => {
return (
<ButtonStyle as='button' onClick={props.handler} width={props.width} height={props.height}
color={props.color} backgroundColor={props.backgroundColor}>
{props.children}
</ButtonStyle>
);
return (
<ButtonStyle
as={props.as ? props.as : 'button'}
onClick={props.handler}
width={props.width}
height={props.height}
color={props.color}
backgroundColor={props.backgroundColor}
to={props.to}
>
{props.children}
</ButtonStyle>
);
};
Button.propTypes = {
handler: PropsTypes.func,
width: PropsTypes.string,
height: PropsTypes.string,
color: PropsTypes.string,
backgroundColor: PropsTypes.string,
children: PropsTypes.node
handler: PropsTypes.func,
width: PropsTypes.string,
height: PropsTypes.string,
color: PropsTypes.string,
backgroundColor: PropsTypes.string,
children: PropsTypes.node,
};
Button.defaultProps = {
handler: null,
width: '64px',
height: '28px',
color: '',
backgroundColor: '',
children: ''
handler: null,
width: '64px',
height: '28px',
color: '',
backgroundColor: '',
children: '',
};
export default Button;
export default Button;

View File

@ -1,46 +1,53 @@
import React from 'react';
import {Container} from '../../utils/containers';
import { Container } from '../../utils/containers';
import styled from 'styled-components';
import PropsTypes from 'prop-types';
const CircleNumberStyle = styled(Container)`
border-radius: ${({borderRadius}) => borderRadius ? borderRadius : '50%'};
background-color: ${({theme}) => theme.colors.green};
color: ${({theme}) => theme.colors.white};
border-radius: ${({ borderRadius }) => (borderRadius ? borderRadius : '50%')};
background-color: ${({ theme }) => theme.colors.green};
color: ${({ theme }) => theme.colors.white};
display: flex;
justify-content: center;
align-items: center;
font-family: 'Kanit', sans-serif;
font-size: 14px;
font-weight: 500;
width: ${({width}) => width ? width : '24px'};
height: ${({height}) => height ? height : '24px'};
width: ${({ width }) => (width ? width : '24px')};
height: ${({ height }) => (height ? height : '24px')};
margin: ${({ margin }) => (margin ? margin : '0')};
@media (min-width: ${({theme}) => theme.overMobile}) {
width: ${({width}) => width ? width : '36px'};
height: ${({height}) => height ? height : '36px'};
font-size: 22px;
@media (min-width: ${({ theme }) => theme.overMobile}) {
width: ${({ width }) => (width ? width : '36px')};
height: ${({ height }) => (height ? height : '36px')};
font-size: ${({ fontSize }) => (fontSize ? fontSize : '22px')};
}
`;
const CircleNumber = (props) => {
return (
<CircleNumberStyle width={props.width} borderRadius={props.borderRadius}>
{props.number}
</CircleNumberStyle>
);
return (
<CircleNumberStyle
width={props.width}
height={props.height}
fontSize={props.fontSize}
borderRadius={props.borderRadius}
margin={props.margin}
>
{props.number}
</CircleNumberStyle>
);
};
CircleNumber.propTypes = {
number: PropsTypes.string,
width: PropsTypes.string,
borderRadius: PropsTypes.string
number: PropsTypes.string,
width: PropsTypes.string,
borderRadius: PropsTypes.string,
};
CircleNumber.defaultProps = {
number: '',
width: null,
borderRadius: null
number: '',
width: null,
borderRadius: null,
};
export default CircleNumber;
export default CircleNumber;

View File

@ -1,21 +1,22 @@
import React from 'react';
import {FlexColumn, FlexRow, Svg, TransBack} from '../../utils/containers';
import {Menu} from '../../utils/fonts';
import { FlexColumn, FlexRow, Svg, TransBack } from '../../utils/containers';
import { Menu } from '../../utils/fonts';
import loginIco from '../../assets/login_ico.svg';
import userIco from '../../assets/user_ico.svg';
import registerIco from '../../assets/register_ico.svg';
import cupIco from '../../assets/cup_ico.svg';
import styled from 'styled-components';
import {Link} from 'react-router-dom';
import {CHALLENGES_PAGE} from '../../utils/globals';
import { Link } from 'react-router-dom';
import { CHALLENGES_PAGE, POLICY_PRIVACY_PAGE } from '../../utils/globals';
import PropsTypes from 'prop-types';
import KeyCloakService from '../../services/KeyCloakService';
import policyIco from '../../assets/policy_ico.svg';
const MobileNavMenuStyle = styled(FlexColumn)`
gap: 32px;
padding: 20px;
background-color: ${({theme}) => theme.colors.white};
box-shadow: ${({theme}) => theme.navShadow};
background-color: ${({ theme }) => theme.colors.white};
box-shadow: ${({ theme }) => theme.navShadow};
position: fixed;
top: 0;
left: 0;
@ -23,7 +24,8 @@ const MobileNavMenuStyle = styled(FlexColumn)`
align-items: flex-start;
z-index: 3;
a, button {
a,
button {
cursor: pointer;
div {
@ -38,69 +40,76 @@ const MobileNavMenuStyle = styled(FlexColumn)`
&:hover {
div {
background-color: ${({theme}) => theme.colors.green};
background-color: ${({ theme }) => theme.colors.green};
}
li {
color: ${({theme}) => theme.colors.green};
color: ${({ theme }) => theme.colors.green};
}
}
}
`;
const MobileNavMenu = (props) => {
return (
<TransBack transition='transform' alignmentX='flex-start' top='42px'
translateY={props.translateY} onClick={props.toggleNavMenu}>
<MobileNavMenuStyle as='ul' onMouseEnter={props.mobileMenuHoverTrue}
onMouseLeave={props.mobileMenuHoverFalse}>
<FlexRow as={Link} to={CHALLENGES_PAGE} gap='16px'>
<Svg width='16px' height='16px' src={cupIco}/>
<Menu as='li'>
Challenges
</Menu>
</FlexRow>
{!KeyCloakService.isLoggedIn() ?
<FlexRow as='button' onClick={KeyCloakService.doRegister} gap='16px'>
<Svg width='16px' height='16px' src={registerIco}/>
<Menu as='li'>
Register
</Menu>
</FlexRow> : ''}
{KeyCloakService.isLoggedIn() ?
<>
<FlexRow as='button' gap='16px'>
<Svg width='16px' height='16px' src={userIco} size='cover'/>
<Menu as='li'>
Profile
</Menu>
</FlexRow>
<FlexRow as='button' onClick={KeyCloakService.doLogout} gap='16px'>
<Svg width='16px' height='16px' src={loginIco} rotate='180deg'/>
<Menu as='li'>
Sign out
</Menu>
</FlexRow>
</> :
<FlexRow as='button' onClick={KeyCloakService.doLogin} gap='16px'>
<Svg width='16px' height='16px' src={loginIco}/>
<Menu as='li'>
Sign in
</Menu>
</FlexRow>}
</MobileNavMenuStyle>
</TransBack>
);
return (
<TransBack
transition="transform"
alignmentX="flex-start"
top="42px"
translateY={props.translateY}
onClick={props.toggleNavMenu}
>
<MobileNavMenuStyle
as="ul"
onMouseEnter={props.mobileMenuHoverTrue}
onMouseLeave={props.mobileMenuHoverFalse}
>
<FlexRow as={Link} to={CHALLENGES_PAGE} gap="16px">
<Svg width="16px" height="16px" src={cupIco} />
<Menu as="li">Challenges</Menu>
</FlexRow>
<FlexRow as={Link} to={POLICY_PRIVACY_PAGE} gap="12px">
<Svg size="cover" width="16px" height="16px" src={policyIco} />
<Menu as="li">Privacy policy</Menu>
</FlexRow>
{!KeyCloakService.isLoggedIn() ? (
<FlexRow as="button" onClick={KeyCloakService.doRegister} gap="16px">
<Svg width="16px" height="16px" src={registerIco} />
<Menu as="li">Register</Menu>
</FlexRow>
) : (
''
)}
{KeyCloakService.isLoggedIn() ? (
<>
<FlexRow as="button" gap="16px">
<Svg width="16px" height="16px" src={userIco} size="cover" />
<Menu as="li">Profile</Menu>
</FlexRow>
<FlexRow as="button" onClick={KeyCloakService.doLogout} gap="16px">
<Svg width="16px" height="16px" src={loginIco} rotate="180deg" />
<Menu as="li">Sign out</Menu>
</FlexRow>
</>
) : (
<FlexRow as="button" onClick={KeyCloakService.doLogin} gap="16px">
<Svg width="16px" height="16px" src={loginIco} />
<Menu as="li">Sign in</Menu>
</FlexRow>
)}
</MobileNavMenuStyle>
</TransBack>
);
};
MobileNavMenu.propTypes = {
translateY: PropsTypes.string,
toggleNavMenu: PropsTypes.func,
translateY: PropsTypes.string,
toggleNavMenu: PropsTypes.func,
};
MobileNavMenu.defaultProps = {
translateY: 'calc(-100vh - 42px)',
toggleNavMenu: null,
translateY: 'calc(-100vh - 42px)',
toggleNavMenu: null,
};
export default MobileNavMenu;
export default MobileNavMenu;

View File

@ -1,20 +1,21 @@
import React from 'react';
import {Container, FlexRow, Svg} from '../../../utils/containers';
import { Container, FlexRow, Svg } from '../../../utils/containers';
import Logo from '../../generic/Logo';
import styled from 'styled-components';
import menuButtonIcon from '../../../assets/menu-button.svg';
import MobileNavMenu from '../MobileNavMenu';
import {Link} from 'react-router-dom';
import { Link } from 'react-router-dom';
import loginIco from '../../../assets/login_ico.svg';
import userIco from '../../../assets/user_ico.svg';
import {Menu} from '../../../utils/fonts';
import { Menu } from '../../../utils/fonts';
import registerIco from '../../../assets/register_ico.svg';
import {CHALLENGES_PAGE} from '../../../utils/globals';
import { CHALLENGES_PAGE, POLICY_PRIVACY_PAGE } from '../../../utils/globals';
import cupIco from '../../../assets/cup_ico.svg';
import NavBarStyle from './NavBarStyle';
import KeyCloakService from '../../../services/KeyCloakService';
import Media from 'react-media';
import theme from '../../../utils/theme';
import policyIco from '../../../assets/policy_ico.svg';
const MenuButton = styled(Container)`
width: 20px;
@ -26,69 +27,95 @@ const MenuButton = styled(Container)`
cursor: pointer;
margin-top: 4px;
@media (min-width: ${({theme}) => theme.overMobile}) {
@media (min-width: ${({ theme }) => theme.overMobile}) {
display: none;
}
`;
const NavBar = (props) => {
const [navMenuTranslateY, setNavMenuTranslateY] = React.useState('calc(-100vh - 42px)');
const [mobileMenuHover, setMobileMenuHover] = React.useState(false);
const [navMenuTranslateY, setNavMenuTranslateY] = React.useState(
'calc(-100vh - 42px)'
);
const [mobileMenuHover, setMobileMenuHover] = React.useState(false);
const mobileMenuHoverTrue = () => {
setMobileMenuHover(true);
};
const mobileMenuHoverTrue = () => {
setMobileMenuHover(true);
};
const mobileMenuHoverFalse = () => {
setMobileMenuHover(false);
};
const mobileMenuHoverFalse = () => {
setMobileMenuHover(false);
};
const toggleNavMenu = () => {
if (navMenuTranslateY === 'calc(-100vh - 42px)') setNavMenuTranslateY('0');
else if (!mobileMenuHover) setNavMenuTranslateY('calc(-100vh - 42px)');
};
const toggleNavMenu = () => {
if ((navMenuTranslateY === 'calc(-100vh - 42px)'))
setNavMenuTranslateY('0');
else if (!mobileMenuHover)
setNavMenuTranslateY('calc(-100vh - 42px)');
};
return (
<NavBarStyle as='header'>
<FlexRow height='100%' alignmentX='space-between' as='nav'>
<Logo/>
{KeyCloakService.isLoggedIn() ?
<Media query={theme.mobile}>
<Svg as='button' width='20px' onClick={toggleNavMenu}
height='20px' src={userIco} size='cover' cursor='pointer'/>
</Media> :
<MenuButton as='button' onClick={toggleNavMenu}/>}
<FlexRow as='ul' className='ul-desktop' gap='32px'>
<FlexRow as={Link} to={CHALLENGES_PAGE} gap='16px'>
<Svg width='16px' height='16px' src={cupIco}/>
<Menu as='li'>
Challenges
</Menu>
</FlexRow>
{!KeyCloakService.isLoggedIn() ?
<FlexRow as='button' onClick={KeyCloakService.doRegister} gap='16px'>
<Svg width='16px' height='16px' src={registerIco}/>
<Menu as='li'>
Register
</Menu>
</FlexRow> : ''}
{KeyCloakService.isLoggedIn() ?
<Svg as='button' onClick={props.loggedBarVisibleHandler}
width='32px' height='32px' src={userIco} margin='0 16px 0 0'/> :
<FlexRow as='button' onClick={KeyCloakService.doLogin} gap='16px'>
<Svg width='16px' height='16px' src={loginIco}/>
<Menu as='li'>
Sign in
</Menu>
</FlexRow>}
</FlexRow>
return (
<NavBarStyle as="header">
<FlexRow height="100%" alignmentX="space-between" as="nav">
<Logo />
{KeyCloakService.isLoggedIn() ? (
<Media query={theme.mobile}>
<Svg
as="button"
width="20px"
onClick={toggleNavMenu}
height="20px"
src={userIco}
size="cover"
cursor="pointer"
/>
POLICY_PRIVACY_PAGE
</Media>
) : (
<MenuButton as="button" onClick={toggleNavMenu} />
)}
<FlexRow as="ul" className="ul-desktop" gap="32px">
<FlexRow as={Link} to={CHALLENGES_PAGE} gap="16px">
<Svg width="16px" height="16px" src={cupIco} />
<Menu as="li">Challenges</Menu>
</FlexRow>
<FlexRow as={Link} to={POLICY_PRIVACY_PAGE} gap="12px">
<Svg size="cover" width="16px" height="16px" src={policyIco} />
<Menu as="li">Privacy policy</Menu>
</FlexRow>
{!KeyCloakService.isLoggedIn() ? (
<FlexRow
as="button"
onClick={KeyCloakService.doRegister}
gap="16px"
>
<Svg width="16px" height="16px" src={registerIco} />
<Menu as="li">Register</Menu>
</FlexRow>
<MobileNavMenu mobileMenuHoverTrue={mobileMenuHoverTrue} mobileMenuHoverFalse={mobileMenuHoverFalse}
translateY={navMenuTranslateY} toggleNavMenu={toggleNavMenu}/>
</NavBarStyle>
);
) : (
''
)}
{KeyCloakService.isLoggedIn() ? (
<Svg
as="button"
onClick={props.loggedBarVisibleHandler}
width="32px"
height="32px"
src={userIco}
margin="0 16px 0 0"
/>
) : (
<FlexRow as="button" onClick={KeyCloakService.doLogin} gap="16px">
<Svg width="16px" height="16px" src={loginIco} />
<Menu as="li">Sign in</Menu>
</FlexRow>
)}
</FlexRow>
</FlexRow>
<MobileNavMenu
mobileMenuHoverTrue={mobileMenuHoverTrue}
mobileMenuHoverFalse={mobileMenuHoverFalse}
translateY={navMenuTranslateY}
toggleNavMenu={toggleNavMenu}
/>
</NavBarStyle>
);
};
export default NavBar;
export default NavBar;

View File

@ -1,9 +1,13 @@
import React from 'react';
import {FlexColumn} from '../../../utils/containers';
import {H2} from '../../../utils/fonts';
import { FlexColumn } from '../../../utils/containers';
import { H2 } from '../../../utils/fonts';
import getMyEntries from '../../../api/getMyEntries';
import Pager from '../../generic/Pager';
import {CALC_PAGES, EVALUATIONS_FORMAT, RENDER_WHEN} from '../../../utils/globals';
import {
CALC_PAGES,
EVALUATIONS_FORMAT,
RENDER_WHEN,
} from '../../../utils/globals';
import Media from 'react-media';
import theme from '../../../utils/theme';
import Loading from '../../generic/Loading';
@ -12,144 +16,168 @@ import myEntriesSearchQueryHandler from './myEntriesSearchQueryHandler';
import Search from '../../generic/Search';
const MyEntries = (props) => {
const [myEntriesFromAPI, setMyEntriesFromAPI] = React.useState({});
const [myEntriesAll, setMyEntriesAll] = React.useState({});
const [myEntries, setMyEntries] = React.useState({});
const [loading, setLoading] = React.useState(true);
const [pageNr, setPageNr] = React.useState(1);
const [whenSorted, setWhenSorted] = React.useState(false);
const [scoresSorted, setScoresSorted] = React.useState([]);
const [myEntriesFromAPI, setMyEntriesFromAPI] = React.useState({});
const [myEntriesAll, setMyEntriesAll] = React.useState({});
const [myEntries, setMyEntries] = React.useState({});
const [loading, setLoading] = React.useState(true);
const [pageNr, setPageNr] = React.useState(1);
const [whenSorted, setWhenSorted] = React.useState(false);
const [scoresSorted, setScoresSorted] = React.useState([]);
React.useEffect(() => {
challengesRequest();
// eslint-disable-next-line
}, []);
React.useEffect(() => {
challengesRequest();
// eslint-disable-next-line
}, []);
const searchQueryHandler = (event) => {
myEntriesSearchQueryHandler(event, myEntriesAll, setPageNr, setMyEntries);
};
const searchQueryHandler = (event) => {
myEntriesSearchQueryHandler(event, myEntriesAll, setPageNr, setMyEntries);
};
const getPossibleMetrics = () => {
let metrics = [];
for (let test of myEntriesFromAPI.tests) {
let myEval = `${test.metric}.${test.name}`;
if (myEval && !metrics.includes(myEval)) {
metrics.push(myEval);
}
}
return metrics;
};
const getPossibleMetrics = () => {
let metrics = [];
for (let test of myEntriesFromAPI.tests) {
let myEval = `${test.metric}.${test.name}`;
if (myEval && !metrics.includes(myEval)) {
metrics.push(myEval);
}
}
return metrics;
};
const nextPage = () => {
if (pageNr !== CALC_PAGES(myEntries ? myEntries : [])) {
let newPage = pageNr + 1;
setPageNr(newPage);
}
};
const nextPage = () => {
if (pageNr !== CALC_PAGES(myEntries ? myEntries : [])) {
let newPage = pageNr + 1;
setPageNr(newPage);
}
};
const previousPage = () => {
if (pageNr !== 1) {
let newPage = pageNr - 1;
setPageNr(newPage);
}
};
const previousPage = () => {
if (pageNr !== 1) {
let newPage = pageNr - 1;
setPageNr(newPage);
}
};
const getMyEntriesHeader = () => {
let header = ['#'];
for (let myEval of getPossibleMetrics()) {
header.push(myEval);
}
header.push('when');
return header;
};
const getMyEntriesHeader = () => {
let header = ['#'];
for (let myEval of getPossibleMetrics()) {
header.push(myEval);
}
header.push('when');
return header;
};
const challengesRequest = () => {
getMyEntries(props.challengeName, setMyEntriesFromAPI, setMyEntriesAll, setMyEntries, setLoading, setScoresSorted);
};
const mobileRender = () => {
};
const sortByUpdate = (elem, i) => {
let newEntries = myEntries;
switch (elem) {
case '#':
break;
case 'when':
if (whenSorted) {
newEntries = newEntries.sort((a, b) => (a.when < b.when) ? 1 : ((b.when < a.when) ? -1 : 0));
setWhenSorted(false);
} else {
newEntries = newEntries.sort((a, b) => (a.when > b.when) ? 1 : ((b.when > a.when) ? -1 : 0));
setWhenSorted(true);
}
break;
default:
// eslint-disable-next-line no-case-declarations
let metricIndex = getPossibleMetrics().indexOf(elem);
// eslint-disable-next-line no-case-declarations
let newScoresSorted = scoresSorted;
if (scoresSorted[metricIndex]) {
newEntries = newEntries.sort((a, b) => (b.evaluations ? b.evaluations[elem] : -1) - (a.evaluations ? a.evaluations[elem] : -1));
newScoresSorted[metricIndex] = false;
setScoresSorted(newScoresSorted);
} else {
newEntries = newEntries.sort((a, b) => (a.evaluations ? a.evaluations[elem] : -1) - (b.evaluations ? b.evaluations[elem] : -1));
newScoresSorted[metricIndex] = true;
setScoresSorted(newScoresSorted);
}
break;
}
setMyEntries(newEntries);
};
const desktopRender = () => {
return (
<FlexColumn padding='24px' as='section' width='100%' maxWidth='1400px'>
<H2 as='h2' margin='0 0 32px 0'>
My entries
</H2>
{myEntries && !loading ?
<>
<Search searchQueryHandler={searchQueryHandler}/>
<Table challengeName={props.challengeName} headerElements={getMyEntriesHeader()}
possibleMetrics={getPossibleMetrics()}
gridTemplateColumns={'1fr ' + '4fr '.repeat(getMyEntriesHeader().length - 1)}
staticColumnElements={
[
{name: 'id', format: null, order: 1, align: 'left'},
{name: 'when', format: RENDER_WHEN, order: 3, align: 'right'}
]
}
iterableColumnElement={{
name: 'evaluations',
format: EVALUATIONS_FORMAT,
order: 2,
align: 'left'
}}
pageNr={pageNr} elements={myEntries}
sortByUpdate={sortByUpdate}/>
<Pager pageNr={pageNr} width='72px' borderRadius='64px'
pages={CALC_PAGES(myEntries, 2)}
nextPage={nextPage} previousPage={previousPage}
number={`${pageNr} / ${CALC_PAGES(myEntries, 2)}`}/>
</>
: <Loading/>}
</FlexColumn>
);
};
return (
<>
<Media query={theme.mobile}>
{mobileRender()}
</Media>
<Media query={theme.desktop}>
{desktopRender()}
</Media>
</>
const challengesRequest = () => {
getMyEntries(
props.challengeName,
setMyEntriesFromAPI,
setMyEntriesAll,
setMyEntries,
setLoading,
setScoresSorted
);
};
const mobileRender = () => {};
const sortByUpdate = (elem, i) => {
let newEntries = myEntries;
switch (elem) {
case '#':
break;
case 'when':
if (whenSorted) {
newEntries = newEntries.sort((a, b) =>
a.when < b.when ? 1 : b.when < a.when ? -1 : 0
);
setWhenSorted(false);
} else {
newEntries = newEntries.sort((a, b) =>
a.when > b.when ? 1 : b.when > a.when ? -1 : 0
);
setWhenSorted(true);
}
break;
default:
// eslint-disable-next-line no-case-declarations
let metricIndex = getPossibleMetrics().indexOf(elem);
// eslint-disable-next-line no-case-declarations
let newScoresSorted = scoresSorted;
if (scoresSorted[metricIndex]) {
newEntries = newEntries.sort(
(a, b) =>
(b.evaluations ? b.evaluations[elem] : -1) -
(a.evaluations ? a.evaluations[elem] : -1)
);
newScoresSorted[metricIndex] = false;
setScoresSorted(newScoresSorted);
} else {
newEntries = newEntries.sort(
(a, b) =>
(a.evaluations ? a.evaluations[elem] : -1) -
(b.evaluations ? b.evaluations[elem] : -1)
);
newScoresSorted[metricIndex] = true;
setScoresSorted(newScoresSorted);
}
break;
}
setMyEntries(newEntries);
};
const desktopRender = () => {
return (
<FlexColumn padding="24px" as="section" width="100%" maxWidth="1400px">
<H2 as="h2" margin="0 0 32px 0">
My entries
</H2>
{myEntries && !loading ? (
<>
<Search searchQueryHandler={searchQueryHandler} />
<Table
challengeName={props.challengeName}
headerElements={getMyEntriesHeader()}
possibleMetrics={getPossibleMetrics()}
gridTemplateColumns={
'1fr ' + '4fr '.repeat(getMyEntriesHeader().length - 1)
}
staticColumnElements={[
{ name: 'id', format: null, order: 1, align: 'left' },
{ name: 'when', format: RENDER_WHEN, order: 3, align: 'right' },
]}
iterableColumnElement={{
name: 'evaluations',
format: EVALUATIONS_FORMAT,
order: 2,
align: 'left',
}}
pageNr={pageNr}
elements={myEntries}
sortByUpdate={sortByUpdate}
/>
<Pager
pageNr={pageNr}
width="72px"
borderRadius="64px"
pages={CALC_PAGES(myEntries, 2)}
nextPage={nextPage}
previousPage={previousPage}
number={`${pageNr} / ${CALC_PAGES(myEntries, 2)}`}
/>
</>
) : (
<Loading />
)}
</FlexColumn>
);
};
return (
<>
<Media query={theme.mobile}>{mobileRender()}</Media>
<Media query={theme.desktop}>{desktopRender()}</Media>
</>
);
};
export default MyEntries;
export default MyEntries;

View File

@ -31,8 +31,7 @@ const LandingPageStyle = styled(FlexColumn)`
const LandingPage = () => {
return (
<LandingPageStyle as='main' alignmentY='flex-start' width='100%'
minHeight='100vh' padding='90px 0 32px 0'>
<LandingPageStyle as='main'>
<FlexColumn className='main-container'>
<Hero/>
<Motivation/>

223
src/pages/PolicyPrivacy.js Normal file
View File

@ -0,0 +1,223 @@
import { FlexColumn, FlexRow } from '../utils/containers';
import React from 'react';
import styled from 'styled-components';
import { Body, H1, H2, Medium } from '../utils/fonts';
import CircleNumber from '../components/generic/CircleNumber';
import Button from '../components/generic/Button';
import theme from '../utils/theme';
import KeyCloakService from '../services/KeyCloakService';
import { ROOT_URL } from '../utils/globals';
const PolicyPrivacyStyle = styled(FlexColumn)`
justify-content: flex-start;
width: 100%;
min-height: 100vh;
padding: 90px 0 32px;
.main-container {
align-items: flex-start;
max-width: 452px;
gap: 16px;
width: 80%;
}
h1 {
font-size: 32px;
}
h2 {
font-size: 24px;
}
@media (min-width: ${({ theme }) => theme.overMobile}) {
padding: 172px 0 124px;
.main-container {
max-width: 680px;
gap: 24px;
}
}
`;
const PolicyPrivacy = () => {
const listItemsContent = [
'prawo dostępu do danych osobowych, w tym prawo do uzyskania kopii tych danych przysługuje w ramach przesłanek i na warunkach określonych w art. 15 RODO,',
'prawo do żądania sprostowania (poprawienia) danych osobowych przysługuje w ramach przesłanek i na warunkach określonych w art. 16 RODO,',
'prawo do usunięcia danych - przysługuje w ram${POLICY_PRIVACY_PAGE}ach przesłanek i na warunkach określonych w art. 17 RODO,',
'prawo ograniczenia przetwarzania - przysługuje w ramach przesłanek i na warunkach określonych w art. 18 RODO,',
'prawo wniesienia sprzeciwu wobec przetwarzania - przysługuje w ramach przesłanek i na warunkach określonych w art. 21 RODO,',
'prawo do przenoszenia danych osobowych - przysługuje w ramach przesłanek i na warunkach określonych w art. 20 RODO,',
'prawo wniesienia skargi do organu nadzorczego (Prezes Urzędu Ochrony Danych Osobowych),',
];
const renderButtons = () => {
return (
<FlexRow margin="32px 0 0 0" gap="48px" width="90%">
<Button
handler={() => {
localStorage.setItem('privacyPolicy', 'accept');
KeyCloakService.doLogin();
}}
width="72px"
height="32px"
>
Accept
</Button>
<Button
width="72px"
height="32px"
handler={() => {
localStorage.removeItem('privacyPolicy');
window.location.replace(ROOT_URL);
}}
backgroundColor={theme.colors.dark}
>
Reject
</Button>
</FlexRow>
);
};
return (
<PolicyPrivacyStyle as="main">
<FlexColumn className="main-container">
<H1 as="h1">Klauzula informacyjna</H1>
<Body as="p">
Zgodnie z art. 13 Rozporządzenia Parlamentu Europejskiego i Rady (UE)
2016/679 z dnia 27 kwietnia 2016 r. w sprawie ochrony osób fizycznych
w związku z przetwarzaniem danych osobowych i w sprawie swobodnego
przepływu takich danych oraz uchylenia dyrektywy 95/46/WE (ogólne
rozporządzenie o ochronie danych), Uniwersytet im. Adama Mickiewicza w
Poznaniu informuje, :
</Body>
<FlexColumn as="section" alignmentX="flex-start" gap="16px">
<H2 as="h2">1. Administrator</H2>
<Body>
Administratorem Pani/Pana danych osobowych jest Uniwersytet im.
Adama Mickiewicza w Poznaniu z siedzibą przy ul. H. Wieniawskiego 1,
61-712 Poznań.
</Body>
</FlexColumn>
<FlexColumn as="section" alignmentX="flex-start" gap="16px">
<H2 as="h2">2. Inspektor Ochrony Danych</H2>
<Body as="p">
Administrator danych wyznaczył Inspektora Ochrony Danych - kontakt
mailowy&nbsp;
<Medium as="a" cursor="pointer" href="mailto:iod@amu.edu.pl">
iod@amu.edu.pl
</Medium>
</Body>
</FlexColumn>
<FlexColumn as="section" alignmentX="flex-start" gap="16px">
<H2 as="h2">3. Cel i podstawa prawna przetwarzania</H2>
<Body as="p">
Pani/Pana dane osobowe przetwarzane będą w celu założenia konta
użytkownika i umożliwienia korzystania z platformy gonito, a także w
celu kontaktowania się ze zwycięzcami konkursów, na podstawie
wyrażonej przez Panią/Pana zgody, stosownie do art. 6 ust. 1 lit. a
RODO.
</Body>
</FlexColumn>
<FlexColumn as="section" alignmentX="flex-start" gap="16px">
<H2 as="h2">4. Okres przechowywania danych</H2>
<Body as="p">
Pani/Pana dane osobowe przetwarzane będą przez okres niezbędny do
czasu realizacji celu dla jakiego zostały zebrane lub do momentu
cofnięcia zgody na przetwarzanie danych osobowych/wniesienia
sprzeciwu wobec przetwarzania, w zależności od tego co nastąpi
wcześniej.
</Body>
</FlexColumn>
<FlexColumn as="section" alignmentX="flex-start" gap="16px">
<H2 as="h2">5. Odbiorcy danych</H2>
<Body as="p">
Odbiorcami Pani/Pana danych osobowych mogą być podmioty, którym
Administrator zleca wykonanie określonych czynności, z którymi wiąże
się konieczność przetwarzania danych osobowych (podmioty
przetwarzające), w szczególności operatorzy systemów
informatycznych, operatorzy systemów e-mail, kancelarie prawne i
audytorskie.
</Body>
<Body as="p">
Pani/Pana dane osobowe mogą być także udostępnione podmiotom
uprawnionym na podstawie przepisów prawa.
</Body>
</FlexColumn>
<FlexColumn as="section" alignmentX="flex-start" gap="16px">
<H2 as="h2">6. Prawa związane z przetwarzaniem danych</H2>
<FlexColumn
as="ol"
margin="0"
padding="0"
gap="12px"
alignmentX="flex-start"
>
{listItemsContent.map((item, index) => {
return (
<FlexRow
alignmentX="flex-start"
alignmentY="flex-start"
key={`privacy-policy-item-${index}`}
width="100%"
privacyPolicy
gap="16px"
>
<CircleNumber
margin="6px 0 0 0"
fontSize="16px"
width="24px"
height="24px"
number={String(index + 1)}
/>
<Body width="80%" as="li">
{item}
</Body>
</FlexRow>
);
})}
</FlexColumn>
</FlexColumn>
<FlexColumn as="section" alignmentX="flex-start" gap="16px">
<H2 as="h2">7. Cofnięcie zgody na przetwarzanie danych</H2>
<Body as="p">
Prawo do cofnięcia zgody na przetwarzanie danych osobowych (w
stosunku do danych osobowych które przetwarzane na podstawie
Pani/Pana zgody - ma Pan/Pani prawo w dowolnym momencie wycofać
zgodę na przetwarzanie danych osobowych. Wycofanie zgody nie wpływa
na zgodność z prawem przetwarzania, którego dokonano na podstawie
zgody przed jej wycofaniem. Wycofać zgodę może Pani/Pan poprzez
przesłanie wiadomości na skrzynkę mailową:&nbsp;
<Medium
as="a"
cursor="pointer"
href="mailto:gonito-rodo@wmi.amu.edu.pl"
>
gonito-rodo@wmi.amu.edu.pl
</Medium>
</Body>
</FlexColumn>
<FlexColumn as="section" alignmentX="flex-start" gap="16px">
<H2 as="h2">8. Obowiązek podania danych i konsekwencje niepodania</H2>
<Body as="p">
Podanie danych osobowych zbieranych na podstawie zgody jest
dobrowolne, ale niezbędne do realizacji celu do jakiego zostały
zebrane.
</Body>
</FlexColumn>
<FlexColumn as="section" alignmentX="flex-start" gap="16px">
<H2 as="h2">
9. Profilowanie i zautomatyzowane podejmowanie decyzji
</H2>
<Body as="p">
W odniesieniu do Pani/Pana danych osobowych, decyzje nie będą
podejmowane w sposób zautomatyzowany i nie będą poddawane
profilowaniu, stosownie do art. 22 RODO.
</Body>
</FlexColumn>
{renderButtons()}
</FlexColumn>
</PolicyPrivacyStyle>
);
};
export default PolicyPrivacy;

View File

@ -1,32 +1,42 @@
import Keycloak from 'keycloak-js';
import { POLICY_PRIVACY_PAGE, ROOT_URL } from '../utils/globals';
const _kc = new Keycloak({
url: process.env.REACT_APP_KC_URL,
realm: process.env.REACT_APP_KC_REALM,
clientId: process.env.REACT_APP_KC_CLIENT_ID
url: process.env.REACT_APP_KC_URL,
realm: process.env.REACT_APP_KC_REALM,
clientId: process.env.REACT_APP_KC_CLIENT_ID,
});
const initKeycloak = (onAuthenticatedCallback) => {
_kc.init({
onLoad: 'check-sso',
silentCheckSsoRedirectUri: window.location.origin + '/silent-check-sso.html',
pkceMethod: 'S256',
checkLoginIframe: false
_kc
.init({
onLoad: 'check-sso',
silentCheckSsoRedirectUri:
window.location.origin + '/silent-check-sso.html',
pkceMethod: 'S256',
checkLoginIframe: false,
})
.then((authenticated) => {
if (!authenticated) {
console.log('user is NOT authenticated..!');
}
onAuthenticatedCallback();
})
.catch(console.error);
.then((authenticated) => {
if (!authenticated) {
console.log('user is NOT authenticated..!');
}
onAuthenticatedCallback();
})
.catch(console.error);
};
const doLogin = _kc.login;
const doLogin = () => {
const privacyPolicyAccept = localStorage.getItem('privacyPolicy');
if (privacyPolicyAccept !== 'accept') {
window.location.replace(`${ROOT_URL}${POLICY_PRIVACY_PAGE}`);
} else {
_kc.login();
}
};
const doLogout = () => {
sessionStorage.clear();
_kc.logout();
sessionStorage.clear();
_kc.logout();
};
const getToken = () => _kc.token;
@ -36,24 +46,22 @@ const doRegister = _kc.register;
const isLoggedIn = () => !!_kc.token;
const updateToken = (successCallback) =>
_kc.updateToken(5)
.then(successCallback)
.catch(doLogin);
_kc.updateToken(5).then(successCallback).catch(doLogin);
const getUsername = () => _kc.tokenParsed?.preferred_username;
const hasRole = (roles) => roles.some((role) => _kc.hasRealmRole(role));
const KeyCloakService = {
initKeycloak,
doLogin,
doLogout,
isLoggedIn,
getToken,
updateToken,
getUsername,
hasRole,
doRegister
initKeycloak,
doLogin,
doLogout,
isLoggedIn,
getToken,
updateToken,
getUsername,
hasRole,
doRegister,
};
export default KeyCloakService;
export default KeyCloakService;

View File

@ -1,80 +1,100 @@
import styled from 'styled-components';
const Container = styled.div`
position: ${({position}) => position ? position : 'static'};
top: ${({top}) => top ? top : 'auto'};
left: ${({left}) => left ? left : 'auto'};
right: ${({right}) => right ? right : 'auto'};
bottom: ${({bottom}) => bottom ? bottom : 'auto'};
padding: ${({padding}) => padding ? padding : '0'};
margin: ${({margin}) => margin ? margin : '0'};
width: ${({width}) => width ? width : 'auto'};
height: ${({height}) => height ? height : 'auto'};
text-align: ${({textAlign}) => textAlign ? textAlign : 'left'};
max-width: ${({maxWidth}) => maxWidth ? maxWidth : 'auto'};
min-width: ${({minWidth}) => minWidth ? minWidth : 'auto'};
max-height: ${({maxHeight}) => maxHeight ? maxHeight : 'auto'};
min-height: ${({minHeight}) => minHeight ? minHeight : 'auto'};
background-color: ${({backgroundColor}) => backgroundColor ? backgroundColor : 'transparent'};
color: ${({theme, color}) => color ? color : theme.colors.dark};
border-radius: ${({borderRadius}) => borderRadius ? borderRadius : '0'};
box-shadow: ${({shadow}) => shadow ? shadow : 'none'};
border: ${({border}) => border ? border : 'none'};
cursor: ${({cursor}) => cursor ? cursor : 'auto'};
display: ${({display}) => display ? display : 'block'};
text-decoration: ${({textDecoration}) => textDecoration ? textDecoration : 'none'};
text-transform: ${({textTransform}) => textTransform ? textTransform : 'none'};
opacity: ${({opacity}) => opacity ? opacity : '1'};
transform: translate(${({translateX}) => translateX ? translateX : 0}, ${({translateY}) => translateY ? translateY : 0});
order: ${({order}) => order ? order : '0'};
z-index: ${({zIndex}) => zIndex ? zIndex : '0'};
position: ${({ position }) => (position ? position : 'static')};
top: ${({ top }) => (top ? top : 'auto')};
left: ${({ left }) => (left ? left : 'auto')};
right: ${({ right }) => (right ? right : 'auto')};
bottom: ${({ bottom }) => (bottom ? bottom : 'auto')};
padding: ${({ padding }) => (padding ? padding : '0')};
margin: ${({ margin }) => (margin ? margin : '0')};
width: ${({ width }) => (width ? width : 'auto')};
height: ${({ height }) => (height ? height : 'auto')};
text-align: ${({ textAlign }) => (textAlign ? textAlign : 'left')};
max-width: ${({ maxWidth }) => (maxWidth ? maxWidth : 'auto')};
min-width: ${({ minWidth }) => (minWidth ? minWidth : 'auto')};
max-height: ${({ maxHeight }) => (maxHeight ? maxHeight : 'auto')};
min-height: ${({ minHeight }) => (minHeight ? minHeight : 'auto')};
background-color: ${({ backgroundColor }) =>
backgroundColor ? backgroundColor : 'transparent'};
color: ${({ theme, color }) => (color ? color : theme.colors.dark)};
border-radius: ${({ borderRadius }) => (borderRadius ? borderRadius : '0')};
box-shadow: ${({ shadow }) => (shadow ? shadow : 'none')};
border: ${({ border }) => (border ? border : 'none')};
cursor: ${({ cursor }) => (cursor ? cursor : 'auto')};
display: ${({ display }) => (display ? display : 'block')};
text-decoration: ${({ textDecoration }) =>
textDecoration ? textDecoration : 'none'};
text-transform: ${({ textTransform }) =>
textTransform ? textTransform : 'none'};
opacity: ${({ opacity }) => (opacity ? opacity : '1')};
transform: translate(
${({ translateX }) => (translateX ? translateX : 0)},
${({ translateY }) => (translateY ? translateY : 0)}
);
order: ${({ order }) => (order ? order : '0')};
z-index: ${({ zIndex }) => (zIndex ? zIndex : '0')};
list-style: ${({ listStyle }) => (listStyle ? listStyle : 'none')};
`;
const FlexRow = styled(Container)`
display: ${({display}) => display ? display : 'flex'};
justify-content: ${({alignmentX}) => alignmentX ? alignmentX : 'center'};
align-items: ${({alignmentY}) => alignmentY ? alignmentY : 'center'};
gap: ${({gap}) => gap ? gap : '0'};
display: ${({ display }) => (display ? display : 'flex')};
justify-content: ${({ alignmentX }) => (alignmentX ? alignmentX : 'center')};
align-items: ${({ alignmentY }) => (alignmentY ? alignmentY : 'center')};
gap: ${({ gap }) => (gap ? gap : '0')};
`;
const FlexColumn = styled(FlexRow)`
flex-direction: column;
justify-content: ${({alignmentY}) => alignmentY ? alignmentY : 'center'};
align-items: ${({alignmentX}) => alignmentX ? alignmentX : 'center'};
gap: ${({gap}) => gap ? gap : '0'};
justify-content: ${({ alignmentY }) => (alignmentY ? alignmentY : 'center')};
align-items: ${({ alignmentX }) => (alignmentX ? alignmentX : 'center')};
gap: ${({ gap }) => (gap ? gap : '0')};
`;
const Grid = styled(Container)`
display: grid;
grid-template-columns: ${({gridTemplateColumns}) => gridTemplateColumns ? gridTemplateColumns : 'auto'};
grid-template-rows: ${({gridTemplateRows}) => gridTemplateRows ? gridTemplateRows : 'auto'};
grid-gap: ${({gridGap}) => gridGap ? gridGap : '0'};
grid-template-columns: ${({ gridTemplateColumns }) =>
gridTemplateColumns ? gridTemplateColumns : 'auto'};
grid-template-rows: ${({ gridTemplateRows }) =>
gridTemplateRows ? gridTemplateRows : 'auto'};
grid-gap: ${({ gridGap }) => (gridGap ? gridGap : '0')};
`;
const Svg = styled(Container)`
background-color: ${({backgroundColor, theme}) => backgroundColor ? backgroundColor : theme.colors.dark};
-webkit-mask: url(${({src}) => src}) no-repeat center;
mask: url(${({src}) => src}) no-repeat center;
width: ${({width}) => width ? width : '16px'};
height: ${({height}) => height ? height : '16px'};
transform: rotate(${({rotate}) => rotate ? rotate : '0'});
mask-size: ${({size}) => size ? size : 'auto'};
background-color: ${({ backgroundColor, theme }) =>
backgroundColor ? backgroundColor : theme.colors.dark};
-webkit-mask: url(${({ src }) => src}) no-repeat center;
mask: url(${({ src }) => src}) no-repeat center;
width: ${({ width }) => (width ? width : '16px')};
height: ${({ height }) => (height ? height : '16px')};
transform: rotate(${({ rotate }) => (rotate ? rotate : '0')});
mask-size: ${({ size }) => (size ? size : 'auto')};
`;
const TransBack = styled(FlexRow)`
position: fixed;
width: 100%;
height: 100vh;
transition: ${({transition}) => transition ? transition : 'opacity'} ${({animTime}) => animTime ? animTime : '0.3s'} ease-in-out;
background-color: ${({backgroundColor}) => backgroundColor ? backgroundColor : 'transparent'};
transition: ${({ transition }) => (transition ? transition : 'opacity')}
${({ animTime }) => (animTime ? animTime : '0.3s')} ease-in-out;
background-color: ${({ backgroundColor }) =>
backgroundColor ? backgroundColor : 'transparent'};
z-index: 4;
`;
const ImageBackground = styled(FlexColumn)`
background-size: ${({size}) => size ? size : 'cover'};
background-size: ${({ size }) => (size ? size : 'cover')};
background-position: center;
background-image: url(${({image}) => image});
background-image: url(${({ image }) => image});
background-repeat: no-repeat;
`;
export {Container, FlexRow, FlexColumn, Grid, Svg, TransBack, ImageBackground};
export {
Container,
FlexRow,
FlexColumn,
Grid,
Svg,
TransBack,
ImageBackground,
};

View File

@ -12,80 +12,82 @@ const MINI_DESCRIPTION_LENGTH = 70;
const API = 'https://gonito.net/api';
const CHALLENGES_PAGE = '/challenges';
const CHALLENGE_PAGE = '/challenge';
const POLICY_PRIVACY_PAGE = '/policy-privacy';
const CSI_LINK = 'https://csi.amu.edu.pl/';
const ROOT_URL = window.location.origin;
const MINI_DESCRIPTION_RENDER = (description) => {
if (description) {
if (description.length <= MINI_DESCRIPTION_LENGTH)
return description;
return `${description.slice(0, MINI_DESCRIPTION_LENGTH)}...`;
}
return 'xxx';
if (description) {
if (description.length <= MINI_DESCRIPTION_LENGTH) return description;
return `${description.slice(0, MINI_DESCRIPTION_LENGTH)}...`;
}
return 'xxx';
};
const RENDER_ICO = (type) => {
switch (type) {
case 'metric':
return metricIco;
case 'prize':
return coinsIco;
case 'baseline':
return baselineIco;
case 'deadline':
return clockIco;
case 'bestScore':
return cupIco;
case 'text':
return textIco;
case 'image':
return imageIco;
case 'tabular':
return tabularIco;
default:
return '';
}
switch (type) {
case 'metric':
return metricIco;
case 'prize':
return coinsIco;
case 'baseline':
return baselineIco;
case 'deadline':
return clockIco;
case 'bestScore':
return cupIco;
case 'text':
return textIco;
case 'image':
return imageIco;
case 'tabular':
return tabularIco;
default:
return '';
}
};
const CALC_PAGES = (objects, n = 1) => {
if (objects.length === 0) return 1;
return Math.ceil(objects.length / (ELEMENTS_PER_PAGE * n));
if (objects.length === 0) return 1;
return Math.ceil(objects.length / (ELEMENTS_PER_PAGE * n));
};
const RENDER_DEADLINE_TIME = (time) => {
if (time) {
const date = time.slice(0, 10);
const hour = time.slice(11, 16);
return `${date} ${hour}`;
}
return '';
if (time) {
const date = time.slice(0, 10);
const hour = time.slice(11, 16);
return `${date} ${hour}`;
}
return '';
};
const RENDER_WHEN = (when) => {
return `${when.slice(0, 10)} ${when.slice(11, 16)}`;
return `${when.slice(0, 10)} ${when.slice(11, 16)}`;
};
const EVALUATIONS_FORMAT = (evaluate) => {
if (Object.hasOwn(evaluate, 'score'))
return evaluate.score.slice(0, 7);
return evaluate.slice(0, 7);
if (Object.hasOwn(evaluate, 'score')) return evaluate.score.slice(0, 7);
return evaluate.slice(0, 7);
};
const IS_MOBILE = () => {
return document.body.clientWidth <= 1024;
return document.body.clientWidth <= 1024;
};
export {
ELEMENTS_PER_PAGE,
API,
CHALLENGES_PAGE,
CHALLENGE_PAGE,
MINI_DESCRIPTION_LENGTH,
CSI_LINK,
MINI_DESCRIPTION_RENDER,
RENDER_ICO,
CALC_PAGES,
RENDER_DEADLINE_TIME,
IS_MOBILE,
RENDER_WHEN,
EVALUATIONS_FORMAT
};
ELEMENTS_PER_PAGE,
API,
CHALLENGES_PAGE,
CHALLENGE_PAGE,
MINI_DESCRIPTION_LENGTH,
CSI_LINK,
POLICY_PRIVACY_PAGE,
ROOT_URL,
MINI_DESCRIPTION_RENDER,
RENDER_ICO,
CALC_PAGES,
RENDER_DEADLINE_TIME,
IS_MOBILE,
RENDER_WHEN,
EVALUATIONS_FORMAT,
};