| import React from 'react'; | |||||
| import { Redirect, Route, Switch } from 'react-router-dom'; | |||||
| import React from "react"; | |||||
| import { Redirect, Route, Switch } from "react-router-dom"; | |||||
| import { | import { | ||||
| LOGIN_PAGE, | LOGIN_PAGE, | ||||
| HOME_PAGE, | HOME_PAGE, | ||||
| ADS_PAGE, | |||||
| FORGOT_PASSWORD_PAGE, | FORGOT_PASSWORD_PAGE, | ||||
| NOT_FOUND_PAGE, | NOT_FOUND_PAGE, | ||||
| ERROR_PAGE, | ERROR_PAGE, | ||||
| BASE_PAGE, | BASE_PAGE, | ||||
| } from './constants/pages'; | |||||
| } from "./constants/pages"; | |||||
| // import LoginPage from './pages/LoginPage/LoginPage'; | // import LoginPage from './pages/LoginPage/LoginPage'; | ||||
| import LoginPage from './pages/LoginPage/LoginPageMUI'; | |||||
| import LoginPage from "./pages/LoginPage/LoginPageMUI"; | |||||
| // import HomePage from './pages/HomePage/HomePage'; | // import HomePage from './pages/HomePage/HomePage'; | ||||
| import HomePage from './pages/HomePage/HomePageMUI'; | |||||
| import NotFoundPage from './pages/ErrorPages/NotFoundPage'; | |||||
| import ErrorPage from './pages/ErrorPages/ErrorPage'; | |||||
| import HomePage from "./pages/HomePage/HomePageMUI"; | |||||
| import AdsPage from "./pages/AdsPage/AdsPage"; | |||||
| import NotFoundPage from "./pages/ErrorPages/NotFoundPage"; | |||||
| import ErrorPage from "./pages/ErrorPages/ErrorPage"; | |||||
| // import ForgotPasswordPage from './pages/ForgotPasswordPage/ForgotPasswordPage'; | // import ForgotPasswordPage from './pages/ForgotPasswordPage/ForgotPasswordPage'; | ||||
| import ForgotPasswordPage from './pages/ForgotPasswordPage/ForgotPasswordPageMUI'; | |||||
| import PrivateRoute from './components/Router/PrivateRoute'; | |||||
| import ForgotPasswordPage from "./pages/ForgotPasswordPage/ForgotPasswordPageMUI"; | |||||
| import PrivateRoute from "./components/Router/PrivateRoute"; | |||||
| const AppRoutes = () => ( | const AppRoutes = () => ( | ||||
| <Switch> | <Switch> | ||||
| <Route path={NOT_FOUND_PAGE} component={NotFoundPage} /> | <Route path={NOT_FOUND_PAGE} component={NotFoundPage} /> | ||||
| <Route path={ERROR_PAGE} component={ErrorPage} /> | <Route path={ERROR_PAGE} component={ErrorPage} /> | ||||
| <Route path={FORGOT_PASSWORD_PAGE} component={ForgotPasswordPage} /> | <Route path={FORGOT_PASSWORD_PAGE} component={ForgotPasswordPage} /> | ||||
| <PrivateRoute | |||||
| exact | |||||
| path={HOME_PAGE} | |||||
| component={HomePage} | |||||
| /> | |||||
| <PrivateRoute exact path={HOME_PAGE} component={HomePage} /> | |||||
| <PrivateRoute exact path={ADS_PAGE} component={AdsPage} /> | |||||
| <Redirect from="*" to={NOT_FOUND_PAGE} /> | <Redirect from="*" to={NOT_FOUND_PAGE} /> | ||||
| </Switch> | </Switch> | ||||
| ); | ); | ||||
| export default AppRoutes; | export default AppRoutes; |
| h1, | |||||
| h3 { | |||||
| margin: 0; | |||||
| padding: 0; | |||||
| } | |||||
| .ads { | |||||
| margin-top: 36px; | |||||
| padding-left: 72px; | |||||
| } | |||||
| .active-ads-header { | |||||
| padding-left: 81px; | |||||
| display: flex; | |||||
| justify-content: space-between; | |||||
| align-items: center; | |||||
| padding-right: 5rem; | |||||
| } | |||||
| .filter-vector { | |||||
| margin-left: 0.5rem !important; | |||||
| } | |||||
| .active-ads-ads { | |||||
| display: flex; | |||||
| margin-top: 39px; | |||||
| position: relative; | |||||
| } | |||||
| .active-ads-ads-a { | |||||
| position: absolute; | |||||
| top: 50%; | |||||
| transform: translate(0, -50%); | |||||
| } | |||||
| .active-ads-ads-arrows { | |||||
| display: flex; | |||||
| flex-direction: column; | |||||
| align-items: center; | |||||
| justify-content: center; | |||||
| } | |||||
| .active-ads-ads-arrows button { | |||||
| margin: 9px 0; | |||||
| box-sizing: border-box; | |||||
| width: 45px; | |||||
| height: 45px; | |||||
| background: #ffffff; | |||||
| border: 1px solid #e4e4e4; | |||||
| border-radius: 9px; | |||||
| cursor: pointer; | |||||
| } | |||||
| .active-ads-ads-ad { | |||||
| padding-left: 81px; | |||||
| display: flex; | |||||
| } | |||||
| .archived-ads { | |||||
| margin-top: 56px; | |||||
| } | |||||
| .archived-ads-header { | |||||
| padding-left: 81px; | |||||
| } | |||||
| .archived-ads-ads { | |||||
| display: flex; | |||||
| margin-top: 27px; | |||||
| position: relative; | |||||
| } | |||||
| .archived-ads-ads-a { | |||||
| position: absolute; | |||||
| top: 50%; | |||||
| transform: translate(0, -50%); | |||||
| } | |||||
| .archived-ads-ads-arrows { | |||||
| display: flex; | |||||
| flex-direction: column; | |||||
| align-items: center; | |||||
| justify-content: center; | |||||
| } | |||||
| .archived-ads-ads-arrows button { | |||||
| margin: 9px 0; | |||||
| box-sizing: border-box; | |||||
| width: 45px; | |||||
| height: 45px; | |||||
| background: #ffffff; | |||||
| border: 1px solid #e4e4e4; | |||||
| border-radius: 9px; | |||||
| cursor: pointer; | |||||
| } | |||||
| .archived-ads-ads-ad { | |||||
| padding-left: 81px; | |||||
| display: flex; | |||||
| } | |||||
| .archive-ad { | |||||
| box-sizing: border-box; | |||||
| display: flex; | |||||
| flex-direction: column; | |||||
| justify-content: center; | |||||
| align-items: center; | |||||
| padding: 36px; | |||||
| gap: 18px; | |||||
| width: 247px; | |||||
| height: 215px; | |||||
| left: 1px; | |||||
| top: 0px; | |||||
| background: #ffffff; | |||||
| border: 1px solid #e4e4e4; | |||||
| border-radius: 12px; | |||||
| margin-right: 27px; | |||||
| } | |||||
| .archive-ad-date p { | |||||
| font-family: "Source Sans Pro"; | |||||
| font-style: normal; | |||||
| font-weight: 400; | |||||
| font-size: 12px; | |||||
| line-height: 15px; | |||||
| color: #272727; | |||||
| flex: none; | |||||
| order: 0; | |||||
| flex-grow: 0; | |||||
| } | |||||
| .archive-ad-title h3 { | |||||
| font-family: "Source Sans Pro"; | |||||
| font-style: normal; | |||||
| font-weight: 600; | |||||
| font-size: 16px; | |||||
| line-height: 20px; | |||||
| color: #226cb0; | |||||
| flex: none; | |||||
| order: 1; | |||||
| flex-grow: 0; | |||||
| } | |||||
| .archive-ad-image img { | |||||
| width: 49px; | |||||
| height: 39px; | |||||
| flex: none; | |||||
| order: 2; | |||||
| flex-grow: 0; | |||||
| } | |||||
| .archive-ad-experience p { | |||||
| font-family: "Source Sans Pro"; | |||||
| font-style: normal; | |||||
| font-weight: 400; | |||||
| font-size: 12px; | |||||
| line-height: 15px; | |||||
| color: #272727; | |||||
| flex: none; | |||||
| order: 3; | |||||
| flex-grow: 0; | |||||
| } | |||||
| .ad-card { | |||||
| display: flex; | |||||
| flex-direction: column; | |||||
| justify-content: center; | |||||
| align-items: center; | |||||
| width: 425px; | |||||
| height: 370px; | |||||
| padding: 72px; | |||||
| background: #ffffff; | |||||
| border: 1px solid #e4e4e4; | |||||
| border-radius: 18px; | |||||
| gap: 18px; | |||||
| margin-right: 36px; | |||||
| } | |||||
| .ad-card-date p { | |||||
| font-family: "Source Sans Pro"; | |||||
| font-style: normal; | |||||
| font-weight: 400; | |||||
| font-size: 12px; | |||||
| line-height: 15px; | |||||
| color: #272727; | |||||
| flex: none; | |||||
| order: 0; | |||||
| flex-grow: 0; | |||||
| } | |||||
| .ad-card-title h3 { | |||||
| font-family: "Source Sans Pro"; | |||||
| font-style: normal; | |||||
| font-weight: 600; | |||||
| font-size: 24px; | |||||
| line-height: 32px; | |||||
| letter-spacing: 0.02em; | |||||
| color: #226cb0; | |||||
| flex: none; | |||||
| order: 1; | |||||
| flex-grow: 0; | |||||
| } | |||||
| .ad-card-logo img { | |||||
| width: 61px; | |||||
| height: 49px; | |||||
| flex: none; | |||||
| order: 2; | |||||
| flex-grow: 0; | |||||
| } | |||||
| .ad-card-experience p { | |||||
| font-family: "Source Sans Pro"; | |||||
| font-style: normal; | |||||
| font-weight: 400; | |||||
| font-size: 16px; | |||||
| line-height: 20px; | |||||
| color: #272727; | |||||
| flex: none; | |||||
| order: 3; | |||||
| flex-grow: 0; | |||||
| } | |||||
| .ad-card-buttons { | |||||
| display: flex; | |||||
| flex-direction: row; | |||||
| align-items: flex-start; | |||||
| justify-content: center; | |||||
| padding: 0px; | |||||
| gap: 18px; | |||||
| width: 281px; | |||||
| height: 38px; | |||||
| flex: none; | |||||
| order: 4; | |||||
| flex-grow: 0; | |||||
| } | |||||
| .ad-card-buttons button { | |||||
| box-sizing: border-box; | |||||
| display: flex; | |||||
| flex-direction: row; | |||||
| justify-content: center; | |||||
| align-items: center; | |||||
| padding: 9px; | |||||
| gap: 10px; | |||||
| width: 76px; | |||||
| height: 38px; | |||||
| border: 1px solid #e4e4e4; | |||||
| border-radius: 9px; | |||||
| flex: none; | |||||
| order: 0; | |||||
| flex-grow: 0; | |||||
| } | |||||
| .add-ad { | |||||
| margin-top: 49px; | |||||
| display: flex; | |||||
| justify-content: flex-end; | |||||
| align-items: center; | |||||
| padding-right: 5rem !important; | |||||
| padding-bottom: 49px; | |||||
| } | |||||
| .add-ad-btn { | |||||
| display: flex; | |||||
| flex-direction: row; | |||||
| justify-content: center; | |||||
| align-items: center; | |||||
| padding: 18px 72px; | |||||
| gap: 10px; | |||||
| width: 201px; | |||||
| height: 51px; | |||||
| background: #226cb0; | |||||
| border-radius: 9px; | |||||
| } |
| import React from "react"; | |||||
| import logoReact from "../../assets/images/logo_react.png"; | |||||
| const Ad = () => { | |||||
| return ( | |||||
| <div className="ad-card"> | |||||
| <div className="ad-card-date"> | |||||
| <p>30.09.22 - 30.10.22</p> | |||||
| </div> | |||||
| <div className="ad-card-title"> | |||||
| <h3>React Developer</h3> | |||||
| </div> | |||||
| <div className="ad-card-logo"> | |||||
| <img src={logoReact} alt="logo-react" /> | |||||
| </div> | |||||
| <div className="ad-card-experience"> | |||||
| <p>3+ years of experience</p> | |||||
| </div> | |||||
| <div className="ad-card-buttons"> | |||||
| <button>LinkedIn</button> | |||||
| <button>Facebook</button> | |||||
| <button disabled>Instagram</button> | |||||
| </div> | |||||
| </div> | |||||
| ); | |||||
| }; | |||||
| export default Ad; |
| import React from 'react' | |||||
| const AdFilters = () => { | |||||
| return ( | |||||
| <div>AdFilter</div> | |||||
| ) | |||||
| } | |||||
| export default AdFilters |
| import React from "react"; | |||||
| import PropType from "prop-types"; | |||||
| import Box from "@mui/material/Box"; | |||||
| import Modal from "@mui/material/Modal"; | |||||
| const style = { | |||||
| position: "absolute", | |||||
| top: "50%", | |||||
| left: "50%", | |||||
| transform: "translate(-50%, -50%)", | |||||
| width: 400, | |||||
| bgcolor: "background.paper", | |||||
| border: "2px solid #000", | |||||
| boxShadow: 24, | |||||
| pt: 2, | |||||
| px: 4, | |||||
| pb: 3, | |||||
| }; | |||||
| const AddAdModal = ({ open, handleClose }) => { | |||||
| return ( | |||||
| <Modal | |||||
| open={open} | |||||
| onClose={handleClose} | |||||
| aria-labelledby="parent-modal-title" | |||||
| aria-describedby="parent-modal-description" | |||||
| > | |||||
| <Box sx={{ ...style, width: 400 }}> | |||||
| <h2 id="parent-modal-title">Text in a modal</h2> | |||||
| <p id="parent-modal-description"> | |||||
| Duis mollis, est non commodo luctus, nisi erat porttitor ligula. | |||||
| </p> | |||||
| </Box> | |||||
| </Modal> | |||||
| ); | |||||
| }; | |||||
| AddAdModal.propTypes = { | |||||
| open: PropType.any, | |||||
| handleClose: PropType.func | |||||
| }; | |||||
| export default AddAdModal; |
| import React from "react"; | |||||
| import net_icon from "../../assets/images/.net_icon.png"; | |||||
| const ArchiveAd = () => { | |||||
| return ( | |||||
| <div className="archive-ad"> | |||||
| <div className="archive-ad-date"> | |||||
| <p>05.07.22 - 20.08.22</p> | |||||
| </div> | |||||
| <div className="archive-ad-title"> | |||||
| <h3>.NET Intern</h3> | |||||
| </div> | |||||
| <div className="archive-ad-image"> | |||||
| <img src={net_icon} alt=".net icon" /> | |||||
| </div> | |||||
| <div className="archive-ad-experience"> | |||||
| <p>No experience needed</p> | |||||
| </div> | |||||
| </div> | |||||
| ); | |||||
| }; | |||||
| export default ArchiveAd; |
| import UserProfile from "../Profile/UserProfile"; | import UserProfile from "../Profile/UserProfile"; | ||||
| import { useSelector } from "react-redux"; | import { useSelector } from "react-redux"; | ||||
| import { userSelector } from "../../store/selectors/userSelectors"; | import { userSelector } from "../../store/selectors/userSelectors"; | ||||
| import { Link } from "react-router-dom"; | |||||
| const NavbarComponent = () => { | const NavbarComponent = () => { | ||||
| const navItems = [ | const navItems = [ | ||||
| let btnRef = useRef(); | let btnRef = useRef(); | ||||
| // get authenticated user | // get authenticated user | ||||
| const user = useSelector(userSelector) | |||||
| const user = useSelector(userSelector); | |||||
| const { t } = useTranslation(); | const { t } = useTranslation(); | ||||
| useEffect(() => { | useEffect(() => { | ||||
| let handler = (e) => { | let handler = (e) => { | ||||
| if (userRef.current) { | if (userRef.current) { | ||||
| if (!userRef.current.contains(e.target) && !btnRef.current.contains(e.target)) { | |||||
| if ( | |||||
| !userRef.current.contains(e.target) && | |||||
| !btnRef.current.contains(e.target) | |||||
| ) { | |||||
| setPreview(false); | setPreview(false); | ||||
| } | } | ||||
| } | } | ||||
| // color: "text.primary", | // color: "text.primary", | ||||
| marginY: "0", | marginY: "0", | ||||
| padding: "0", | padding: "0", | ||||
| textDecoration: "none" | |||||
| }} | }} | ||||
| className="text-black" | className="text-black" | ||||
| as={Link} | |||||
| to={n} | |||||
| > | > | ||||
| {t("nav." + n)} | {t("nav." + n)} | ||||
| </Typography> | </Typography> | ||||
| </div> | </div> | ||||
| </Box> | </Box> | ||||
| )} | )} | ||||
| {!matches && <UserProfile innerRef={userRef} show={preview}/>} | |||||
| {!matches && <UserProfile innerRef={userRef} show={preview} />} | |||||
| {/* <Box> | {/* <Box> | ||||
| <MenuList /> | <MenuList /> | ||||
| </Box> */} | </Box> */} |
| export const LOGIN_PAGE = '/login'; | export const LOGIN_PAGE = '/login'; | ||||
| export const FORGOT_PASSWORD_PAGE = '/forgot-password'; | export const FORGOT_PASSWORD_PAGE = '/forgot-password'; | ||||
| export const HOME_PAGE = '/home'; | export const HOME_PAGE = '/home'; | ||||
| export const ADS_PAGE = '/ads'; | |||||
| export const ERROR_PAGE = '/error-page'; | export const ERROR_PAGE = '/error-page'; | ||||
| export const NOT_FOUND_PAGE = '/not-found'; | export const NOT_FOUND_PAGE = '/not-found'; |
| stats: 'Statistika', | stats: 'Statistika', | ||||
| users: 'Korisnici', | users: 'Korisnici', | ||||
| signOut: 'Izloguj se' | signOut: 'Izloguj se' | ||||
| }, | |||||
| ads: { | |||||
| activeAds: "Aktivni Oglasi", | |||||
| archiveAds: "Arhiva" | |||||
| } | } | ||||
| }; | }; |
| @import './assets/styles/components/error-page'; | @import './assets/styles/components/error-page'; | ||||
| @import './assets/styles/components/rules'; | @import './assets/styles/components/rules'; | ||||
| @import './assets/styles/components/nav'; | @import './assets/styles/components/nav'; | ||||
| @import './assets/styles/components/ads'; | |||||
| @import './assets/styles/layout'; | @import './assets/styles/layout'; | ||||
| @import './assets/styles/overwrite'; | @import './assets/styles/overwrite'; | ||||
| @import './assets/styles/utility'; | @import './assets/styles/utility'; | ||||
| .h-withHeader{ | .h-withHeader{ | ||||
| height: calc(100vh - $navHeight); | height: calc(100vh - $navHeight); | ||||
| // remove css line below, just for showcase | // remove css line below, just for showcase | ||||
| background-color: $mainBlue; | |||||
| } | } | ||||
| // ================= mui overrides | // ================= mui overrides |
| import React, { useState } from "react"; | |||||
| import Ad from "../../components/Ads/Ad"; | |||||
| import ArchiveAd from "../../components/Ads/ArchiveAd"; | |||||
| import IconButton from "../../components/IconButton/IconButton"; | |||||
| import filterVector from "../../assets/images/filter_vector.png"; | |||||
| import arrow_left from "../../assets/images/arrow_left.png"; | |||||
| import arrow_right from "../../assets/images/arrow_right.png"; | |||||
| import { useTranslation } from "react-i18next"; | |||||
| import AddAdModal from "../../components/Ads/AddAdModal"; | |||||
| import AdFilters from "../../components/Ads/AdFilters"; | |||||
| const AdsPage = () => { | |||||
| const [showFilterComponent, setShowFilterComponent] = useState(false); | |||||
| const [toggleModal, setToggleModal] = useState(false); | |||||
| const { t } = useTranslation(); | |||||
| const handleToggleModal = () => { | |||||
| setToggleModal((oldState) => !oldState); | |||||
| }; | |||||
| return ( | |||||
| <> | |||||
| <div className="l-t-rectangle"></div> | |||||
| <div className="r-b-rectangle"></div> | |||||
| {showFilterComponent && <AdFilters />} | |||||
| <AddAdModal open={toggleModal} handleClose={handleToggleModal} /> | |||||
| <div className="ads"> | |||||
| <div className="active-ads"> | |||||
| <div className="active-ads-header"> | |||||
| <h1>{t("ads.activeAds")}</h1> | |||||
| <IconButton | |||||
| sx={{ marginLeft: "15px" }} | |||||
| className="c-btn c-btn--primary-outlined" | |||||
| onClick={() => setShowFilterComponent((oldState) => !oldState)} | |||||
| > | |||||
| Filteri{" "} | |||||
| <img src={filterVector} alt="filter" className="filter-vector" /> | |||||
| </IconButton> | |||||
| </div> | |||||
| <div className="active-ads-ads"> | |||||
| <div className="active-ads-ads-a"> | |||||
| <div className="active-ads-ads-arrows"> | |||||
| <button> | |||||
| <img src={arrow_left} alt="arrow-left" /> | |||||
| </button> | |||||
| <button> | |||||
| <img src={arrow_right} alt="arrow-right" /> | |||||
| </button> | |||||
| </div> | |||||
| </div> | |||||
| <div className="active-ads-ads-ad"> | |||||
| <Ad /> | |||||
| <Ad /> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| <div className="archived-ads"> | |||||
| <div className="archived-ads-header"> | |||||
| <h2>{t("ads.archiveAds")}</h2> | |||||
| </div> | |||||
| <div className="archived-ads-ads"> | |||||
| <div className="archived-ads-ads-a"> | |||||
| <div className="archived-ads-ads-arrows"> | |||||
| <button> | |||||
| <img src={arrow_left} alt="arrow-left" /> | |||||
| </button> | |||||
| <button> | |||||
| <img src={arrow_right} alt="arrow-right" /> | |||||
| </button> | |||||
| </div> | |||||
| </div> | |||||
| <div className="archived-ads-ads-ad"> | |||||
| <ArchiveAd /> | |||||
| <ArchiveAd /> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| <div className="add-ad"> | |||||
| <IconButton | |||||
| className="c-btn c-btn--primary add-ad-btn" | |||||
| onClick={handleToggleModal} | |||||
| > | |||||
| + Oglas | |||||
| </IconButton> | |||||
| </div> | |||||
| </> | |||||
| ); | |||||
| }; | |||||
| export default AdsPage; |