App component structure refactor

This commit is contained in:
Mateusz Tylka 2023-06-02 12:13:05 +02:00
parent e442179718
commit fccedac8f2
15 changed files with 439 additions and 298 deletions

View File

@ -1,232 +0,0 @@
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 NavBar from './components/navigation/NavBar';
import {
CHALLENGE_PAGE,
CHALLENGES_PAGE,
IS_MOBILE,
POLICY_PRIVACY_PAGE,
LOGIN_REQUIRED_PAGES,
ROOT_URL,
CHALLENGE_SECTIONS,
} from './utils/globals';
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 PopupMessage from './components/generic/PopupMessage';
import PolicyPrivacy from './pages/PolicyPrivacy';
import Challenge from './pages/Challenge';
import SESSION_STORAGE from './utils/sessionStorage';
const App = () => {
const [loggedBarVisible, setLoggedBarVisible] = React.useState('100vw');
const [loggedBarHover, setLoggedBarHover] = React.useState(false);
const [popUpHeader, setPopUpHeader] = React.useState('');
const [popUpMessage, setPopUpMessage] = React.useState('');
const [confirmPopUpHandler, setConfirmPopUpHandler] = React.useState(null);
React.useMemo(() => {
if (
sessionStorage.getItem(SESSION_STORAGE.LOGOUT) ===
SESSION_STORAGE.STATIC_VALUE.YES
) {
const pageName = window.location.pathname.split('/').at(-1);
if (LOGIN_REQUIRED_PAGES.includes(pageName)) {
window.location.replace(`${ROOT_URL}/challenges`);
}
}
if (
sessionStorage.getItem(SESSION_STORAGE.LOGGED) !==
SESSION_STORAGE.STATIC_VALUE.YES
) {
if (KeyCloakService.isLoggedIn()) {
sessionStorage.setItem(
SESSION_STORAGE.LOGGED,
SESSION_STORAGE.STATIC_VALUE.YES
);
addUser();
}
}
if (
sessionStorage.getItem(SESSION_STORAGE.LOGGED) ===
SESSION_STORAGE.STATIC_VALUE.YES &&
(window.location.pathname === `${POLICY_PRIVACY_PAGE}/login` ||
window.location.pathname === `${POLICY_PRIVACY_PAGE}/register`)
) {
window.location.replace(`${ROOT_URL}/challenges`);
}
setTimeout(() => {
if (
sessionStorage.getItem(SESSION_STORAGE.LOGGED) ===
SESSION_STORAGE.STATIC_VALUE.YES
) {
if (!KeyCloakService.isLoggedIn()) {
KeyCloakService.doLogin();
}
}
}, 1500);
}, []);
const popUpMessageHandler = (header, message, confirmHandler) => {
setPopUpHeader(header);
setPopUpMessage(message);
if (confirmHandler !== null && confirmHandler !== undefined) {
setConfirmPopUpHandler(() => confirmHandler());
} else {
setConfirmPopUpHandler(null);
}
};
const popUpMessageRender = () => {
if (popUpHeader !== '' || popUpMessage !== '') {
return (
<PopupMessage
header={popUpHeader}
message={popUpMessage}
confirmHandler={confirmPopUpHandler}
popUpMessageHandler={popUpMessageHandler}
/>
);
}
};
const loggedBarVisibleHandler = React.useCallback(() => {
if (loggedBarVisible === '0' && !loggedBarHover)
setLoggedBarVisible('100vw');
else setLoggedBarVisible('0');
}, [loggedBarHover, loggedBarVisible]);
const renderApp = () => {
return (
<BrowserRouter>
<ThemeProvider theme={theme}>
{popUpMessageRender()}
<NavBar
loggedBarVisibleHandler={loggedBarVisibleHandler}
popUpMessageHandler={popUpMessageHandler}
/>
{!IS_MOBILE() && (
<LoggedBar
visible={loggedBarVisible}
loggedBarVisibleHandler={loggedBarVisibleHandler}
loggedBarHoverTrue={() => setLoggedBarHover(true)}
loggedBarHoverFalse={() => setLoggedBarHover(false)}
username={KeyCloakService.getUsername()}
/>
)}
<Routes>
<Route
path={`${CHALLENGE_PAGE}/:challengeId`}
element={<Challenge section={CHALLENGE_SECTIONS.LEADERBOARD} />}
/>
<Route
path={`${CHALLENGE_PAGE}/:challengeId/leaderboard`}
element={<Challenge section={CHALLENGE_SECTIONS.LEADERBOARD} />}
/>
<Route
path={`${CHALLENGE_PAGE}/:challengeId/allentries`}
element={<Challenge section={CHALLENGE_SECTIONS.ALL_ENTRIES} />}
/>
<Route
path={`${CHALLENGE_PAGE}/:challengeId/readme`}
element={<Challenge section={CHALLENGE_SECTIONS.README} />}
/>
<Route
path={`${CHALLENGE_PAGE}/:challengeId/howto`}
element={
<Challenge
popUpMessageHandler={popUpMessageHandler}
section={CHALLENGE_SECTIONS.HOW_TO}
/>
}
/>
<Route
path={`${CHALLENGE_PAGE}/:challengeId/myentries`}
element={<Challenge section={CHALLENGE_SECTIONS.MY_ENTRIES} />}
/>
<Route
path={`${CHALLENGE_PAGE}/:challengeId/submit`}
element={<Challenge section={CHALLENGE_SECTIONS.SUBMIT} />}
/>
<Route path={CHALLENGES_PAGE} element={<Challenges />} />
<Route
path={POLICY_PRIVACY_PAGE}
element={
<PolicyPrivacy popUpMessageHandler={popUpMessageHandler} />
}
/>
<Route
path={`${POLICY_PRIVACY_PAGE}/login`}
element={
<PolicyPrivacy
popUpMessageHandler={popUpMessageHandler}
beforeLogin
/>
}
/>
<Route
path={`${POLICY_PRIVACY_PAGE}/register`}
element={
<PolicyPrivacy
popUpMessageHandler={popUpMessageHandler}
beforeRegister
/>
}
/>
{KeyCloakService.isLoggedIn() ? (
<>
<Route exact path="/" element={<Challenges />} />
<Route element={<Challenges />} />
</>
) : (
<>
<Route
exact
path="/"
element={
<LandingPage popUpMessageHandler={popUpMessageHandler} />
}
/>
<Route
element={
<LandingPage popUpMessageHandler={popUpMessageHandler} />
}
/>
</>
)}
</Routes>
</ThemeProvider>
</BrowserRouter>
);
};
if (
sessionStorage.getItem(SESSION_STORAGE.LOGGED) ===
SESSION_STORAGE.STATIC_VALUE.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;

33
src/App/App.js Normal file
View File

@ -0,0 +1,33 @@
import React from 'react';
import { ThemeProvider } from 'styled-components';
import theme from '../utils/theme';
import PopUpMessageManager from './components/PopUpMessageManager';
import RoutingManager from './components/RoutingManager';
import NavigationManager from './components/NavigationManager';
import { BrowserRouter } from 'react-router-dom';
import startManage from './functions/startManage';
import startApp from './functions/startApp';
const App = () => {
React.useMemo(() => {
startManage();
}, []);
const renderApp = React.useCallback(() => {
return (
<ThemeProvider theme={theme}>
<PopUpMessageManager>
<BrowserRouter>
<NavigationManager>
<RoutingManager />
</NavigationManager>
</BrowserRouter>
</PopUpMessageManager>
</ThemeProvider>
);
}, []);
return startApp(renderApp);
};
export default App;

View File

@ -0,0 +1,47 @@
import React from 'react';
import NavBar from '../../components/navigation/NavBar/NavBar';
import LoggedBar from '../../components/navigation/LoggedBar';
import KeyCloakService from '../../services/KeyCloakService';
import { CHILDREN_WITH_PROPS, IS_MOBILE } from '../../utils/globals';
const NavigationManager = (props) => {
const [loggedBarVisible, setLoggedBarVisible] = React.useState('100vw');
const [loggedBarHover, setLoggedBarHover] = React.useState(false);
const [navOptions, setNavOptions] = React.useState(true);
const loggedBarVisibleHandler = React.useCallback(() => {
if (loggedBarVisible === '0' && !loggedBarHover)
setLoggedBarVisible('100vw');
else setLoggedBarVisible('0');
}, [loggedBarHover, loggedBarVisible]);
const hideNavOptions = React.useCallback(() => {
setNavOptions(false);
}, []);
const showNavOptions = React.useCallback(() => {
setNavOptions(true);
}, []);
return (
<>
<NavBar
loggedBarVisibleHandler={loggedBarVisibleHandler}
popUpMessageHandler={props.popUpMessageHandler}
navOptions={navOptions}
/>
{!IS_MOBILE() && (
<LoggedBar
visible={loggedBarVisible}
loggedBarVisibleHandler={loggedBarVisibleHandler}
loggedBarHoverTrue={() => setLoggedBarHover(true)}
loggedBarHoverFalse={() => setLoggedBarHover(false)}
username={KeyCloakService.getUsername()}
/>
)}
{CHILDREN_WITH_PROPS(props.children, { hideNavOptions, showNavOptions })}
</>
);
};
export default NavigationManager;

View File

@ -0,0 +1,41 @@
import React from 'react';
import PopupMessage from '../../components/generic/PopupMessage';
import { CHILDREN_WITH_PROPS } from '../../utils/globals';
const PopUpMessageManager = (props) => {
const [popUpHeader, setPopUpHeader] = React.useState('');
const [popUpMessage, setPopUpMessage] = React.useState('');
const [confirmPopUpHandler, setConfirmPopUpHandler] = React.useState(null);
const popUpMessageHandler = (header, message, confirmHandler) => {
setPopUpHeader(header);
setPopUpMessage(message);
if (confirmHandler !== null && confirmHandler !== undefined) {
setConfirmPopUpHandler(() => confirmHandler());
} else {
setConfirmPopUpHandler(null);
}
};
const popUpMessageRender = () => {
if (popUpHeader !== '' || popUpMessage !== '') {
return (
<PopupMessage
header={popUpHeader}
message={popUpMessage}
confirmHandler={confirmPopUpHandler}
popUpMessageHandler={popUpMessageHandler}
/>
);
}
};
return (
<>
{popUpMessageRender()}
{CHILDREN_WITH_PROPS(props.children, { popUpMessageHandler })}
</>
);
};
export default PopUpMessageManager;

View File

@ -0,0 +1,108 @@
import { Route, Routes } from 'react-router-dom';
import {
CHALLENGES_PAGE,
CHALLENGE_PAGE,
CHALLENGE_SECTIONS,
POLICY_PRIVACY_PAGE,
} from '../../utils/globals';
import Challenge from '../../pages/Challenge';
import Challenges from '../../pages/Challanges';
import PolicyPrivacy from '../../pages/PolicyPrivacy';
import LandingPage from '../../pages/LandingPage';
import KeyCloakService from '../../services/KeyCloakService';
const RoutingManager = (props) => {
return (
<Routes>
<Route
path={`${CHALLENGE_PAGE}/:challengeId`}
element={<Challenge section={CHALLENGE_SECTIONS.LEADERBOARD} />}
/>
<Route
path={`${CHALLENGE_PAGE}/:challengeId/leaderboard`}
element={<Challenge section={CHALLENGE_SECTIONS.LEADERBOARD} />}
/>
<Route
path={`${CHALLENGE_PAGE}/:challengeId/allentries`}
element={<Challenge section={CHALLENGE_SECTIONS.ALL_ENTRIES} />}
/>
<Route
path={`${CHALLENGE_PAGE}/:challengeId/readme`}
element={<Challenge section={CHALLENGE_SECTIONS.README} />}
/>
<Route
path={`${CHALLENGE_PAGE}/:challengeId/howto`}
element={
<Challenge
popUpMessageHandler={props.popUpMessageHandler}
section={CHALLENGE_SECTIONS.HOW_TO}
/>
}
/>
<Route
path={`${CHALLENGE_PAGE}/:challengeId/myentries`}
element={<Challenge section={CHALLENGE_SECTIONS.MY_ENTRIES} />}
/>
<Route
path={`${CHALLENGE_PAGE}/:challengeId/submit`}
element={<Challenge section={CHALLENGE_SECTIONS.SUBMIT} />}
/>
<Route path={CHALLENGES_PAGE} element={<Challenges />} />
<Route
path={POLICY_PRIVACY_PAGE}
element={
<PolicyPrivacy popUpMessageHandler={props.popUpMessageHandler} />
}
/>
<Route
path={`${POLICY_PRIVACY_PAGE}/login`}
element={
<PolicyPrivacy
popUpMessageHandler={props.popUpMessageHandler}
beforeLogin
/>
}
/>
<Route
path={`${POLICY_PRIVACY_PAGE}/register`}
element={
<PolicyPrivacy
popUpMessageHandler={props.popUpMessageHandler}
beforeRegister
/>
}
/>
{KeyCloakService.isLoggedIn() ? (
<>
<Route exact path="/" element={<Challenges />} />
<Route element={<Challenges />} />
</>
) : (
<>
<Route
exact
path="/"
element={
<LandingPage
popUpMessageHandler={props.popUpMessageHandler}
showNavOptions={props.showNavOptions}
hideNavOptions={props.hideNavOptions}
/>
}
/>
<Route
element={
<LandingPage
popUpMessageHandler={props.popUpMessageHandler}
showNavOptions={props.showNavOptions}
hideNavOptions={props.hideNavOptions}
/>
}
/>
</>
)}
</Routes>
);
};
export default RoutingManager;

View File

@ -0,0 +1,29 @@
import Loading from '../../components/generic/Loading';
import { FlexColumn } from '../../utils/containers';
import SESSION_STORAGE from '../../utils/sessionStorage';
import KeyCloakService from '../../services/KeyCloakService';
import { ThemeProvider } from 'styled-components';
import theme from '../../utils/theme';
const startApp = (renderApp) => {
if (
sessionStorage.getItem(SESSION_STORAGE.LOGGED) ===
SESSION_STORAGE.STATIC_VALUE.YES
) {
if (KeyCloakService.isLoggedIn()) {
return renderApp();
} else {
return (
<ThemeProvider theme={theme}>
<FlexColumn width="100vw" height="100vh">
<Loading />
</FlexColumn>
</ThemeProvider>
);
}
} else {
return renderApp();
}
};
export default startApp;

View File

@ -0,0 +1,55 @@
import {
POLICY_PRIVACY_PAGE,
LOGIN_REQUIRED_PAGES,
ROOT_URL,
} from '../../utils/globals';
import addUser from '../../api/addUser';
import SESSION_STORAGE from '../../utils/sessionStorage';
import KeyCloakService from '../../services/KeyCloakService';
const startManage = () => {
if (
sessionStorage.getItem(SESSION_STORAGE.LOGOUT) ===
SESSION_STORAGE.STATIC_VALUE.YES
) {
const pageName = window.location.pathname.split('/').at(-1);
if (LOGIN_REQUIRED_PAGES.includes(pageName)) {
window.location.replace(`${ROOT_URL}/challenges`);
}
}
if (
sessionStorage.getItem(SESSION_STORAGE.LOGGED) !==
SESSION_STORAGE.STATIC_VALUE.YES
) {
if (KeyCloakService.isLoggedIn()) {
sessionStorage.setItem(
SESSION_STORAGE.LOGGED,
SESSION_STORAGE.STATIC_VALUE.YES
);
addUser();
}
}
if (
sessionStorage.getItem(SESSION_STORAGE.LOGGED) ===
SESSION_STORAGE.STATIC_VALUE.YES &&
(window.location.pathname === `${POLICY_PRIVACY_PAGE}/login` ||
window.location.pathname === `${POLICY_PRIVACY_PAGE}/register`)
) {
window.location.replace(`${ROOT_URL}/challenges`);
}
setTimeout(() => {
if (
sessionStorage.getItem(SESSION_STORAGE.LOGGED) ===
SESSION_STORAGE.STATIC_VALUE.YES
) {
if (!KeyCloakService.isLoggedIn()) {
KeyCloakService.doLogin();
}
}
}, 1500);
};
export default startManage;

1
src/App/index.js Normal file
View File

@ -0,0 +1 @@
export { default } from './App';

View File

@ -0,0 +1,14 @@
import styled from 'styled-components';
import { FlexColumn } from '../../../utils/containers';
const EntireScreenLoadingStyle = styled(FlexColumn)`
width: 100%;
height: 100vh;
z-index: 1000;
position: fixed;
top: 0;
left: 0;
background-color: ${({ theme }) => theme.colors.white};
`;
export default EntireScreenLoadingStyle;

View File

@ -0,0 +1,13 @@
import React from 'react';
import EntireScreenLoadingStyle from './EntireScreenLoadingStyle';
import Loading from '../Loading';
const EntireScreenLoading = () => {
return (
<EntireScreenLoadingStyle>
<Loading />
</EntireScreenLoadingStyle>
);
};
export default EntireScreenLoading;

View File

@ -1,24 +1,29 @@
import React from 'react';
import {H1} from '../../utils/fonts';
import { H1 } from '../../utils/fonts';
import theme from '../../utils/theme';
import {Link} from 'react-router-dom';
import { Link } from 'react-router-dom';
import styled from 'styled-components';
const LogoStyle = styled(H1)`
font-size: 24px;
@media (min-width: ${({theme}) => theme.overMobile}) {
@media (min-width: ${({ theme }) => theme.overMobile}) {
font-size: 32px;
line-height: 32px;
}
`;
const Logo = () => {
return (
<LogoStyle as={Link} cursor='pointer' to='/' color={theme.colors.green}>
Gonito
</LogoStyle>
);
const Logo = (props) => {
return (
<LogoStyle
as={props.navOptions ? Link : 'span'}
cursor="pointer"
to="/"
color={theme.colors.green}
>
Gonito
</LogoStyle>
);
};
export default Logo;

View File

@ -43,6 +43,7 @@ const NavBar = (props) => {
const mobileMenuHoverFalse = () => {
setMobileMenuHover(false);
};
const toggleNavMenu = () => {
if (navMenuTranslateY === 'calc(-100vh - 42px)') setNavMenuTranslateY('0');
else if (!mobileMenuHover) setNavMenuTranslateY('calc(-100vh - 42px)');
@ -51,51 +52,57 @@ const NavBar = (props) => {
return (
<NavBarStyle as="header">
<FlexRow height="100%" alignmentX="space-between" as="nav">
<Logo />
<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={() =>
props.popUpMessageHandler(
'Reminder',
'Remember to check your spam mailbox to confirm your account.',
() => KeyCloakService.doRegister
)
}
gap="16px"
>
<Svg width="16px" height="16px" src={registerIco} />
<Menu as="li">Register</Menu>
<Logo navOptions={props.navOptions} />
{props.navOptions && (
<>
<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={() =>
props.popUpMessageHandler(
'Reminder',
'Remember to check your spam mailbox to confirm your account.',
() => 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>
) : (
''
)}
{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}

View File

@ -6,20 +6,30 @@ import Commercial from './components/Commercial/Commercial';
import Hero from './components/Hero/Hero';
import Partnerships from './components/Partnerships/Partnerships';
import LandingPageStyle from './LandingPageStyle';
// import MadeByCsi from './components/MadeByCsi/MadeByCsi';
import EntireScreenLoading from '../../components/generic/EntireScreenLoading/EntrieScreenLoading';
const LandingPage = (props) => {
return (
<LandingPageStyle as="main">
<Hero popUpMessageHandler={props.popUpMessageHandler} />
<FlexColumn className="LandingPageStyle__main-container">
<Motivation />
<Csi />
<Commercial />
<Partnerships />
</FlexColumn>
</LandingPageStyle>
);
const [show, setShow] = React.useState(false);
React.useEffect(() => {
setTimeout(() => {
setShow(true);
}, 1000);
}, []);
if (show) {
return (
<LandingPageStyle as="main">
<Hero popUpMessageHandler={props.popUpMessageHandler} />
<FlexColumn className="LandingPageStyle__main-container">
<Motivation />
<Csi />
<Commercial />
<Partnerships />
</FlexColumn>
</LandingPageStyle>
);
} else return <EntireScreenLoading />;
};
export default LandingPage;

View File

@ -6,6 +6,7 @@ import cupIco from '../assets/cup_ico.svg';
import textIco from '../assets/text_ico.svg';
import imageIco from '../assets/image_ico.svg';
import tabularIco from '../assets/tabular_ico.svg';
import React from 'react';
const ELEMENTS_PER_PAGE = 12;
const MINI_DESCRIPTION_LENGTH = 70;
@ -119,6 +120,14 @@ const IS_MOBILE = () => {
return document.body.clientWidth <= 1024;
};
const CHILDREN_WITH_PROPS = (propsChildren, props) =>
React.Children.map(propsChildren, (child) => {
if (React.isValidElement(child)) {
return React.cloneElement(child, props);
}
return child;
});
export {
ELEMENTS_PER_PAGE,
API,
@ -142,4 +151,5 @@ export {
EVALUATIONS_FORMAT,
PREVIOUS_PAGE,
NEXT_PAGE,
CHILDREN_WITH_PROPS,
};