Djordje Mitrovic пре 3 година
родитељ
комит
c1316c9e06
35 измењених фајлова са 503 додато и 114 уклоњено
  1. 6
    6
      src/AppRoutes.js
  2. 8
    5
      src/components/About/AboutComponent.js
  3. 6
    0
      src/components/About/AboutComponent.styled.js
  4. 1
    1
      src/components/About/CheckOffersButton/CheckOffersButton.styled.js
  5. 32
    0
      src/components/Footer/AboutFooter.js
  6. 49
    0
      src/components/Footer/AboutFooter.styled.js
  7. 68
    0
      src/components/Header/AboutHeader/AboutHeader.js
  8. 21
    0
      src/components/Header/AboutHeader/AboutHeader.styled.js
  9. 80
    66
      src/components/Header/Header.js
  10. 4
    4
      src/components/Header/Header.styled.js
  11. 0
    1
      src/components/MarketPlace/Offers/Offers.js
  12. 11
    2
      src/components/Popovers/MyProfile/AboutButton/AboutButton.js
  13. 12
    4
      src/components/Popovers/MyProfile/MyProfile.js
  14. 12
    3
      src/components/Popovers/MyProfile/PrivacyPolicyButton/PrivacyPolicyButton.js
  15. 1
    0
      src/components/Prices/Plan/Plan.styled.js
  16. 7
    4
      src/components/Prices/PricesComponent.js
  17. 4
    1
      src/components/Prices/PricesComponent.styled.js
  18. 3
    0
      src/components/Prices/PricesHeader/PricesHeader.styled.js
  19. 7
    4
      src/components/PrivacyPolicy/PrivacyPolicyComponent.js
  20. 1
    0
      src/components/UserReviews/UserReviews.styled.js
  21. 7
    0
      src/constants/scrollConstants.js
  22. 6
    0
      src/hooks/useOffers/useOffers.js
  23. 24
    0
      src/hooks/useOffers/useSearch.js
  24. 7
    0
      src/i18n/resources/rs.js
  25. 2
    1
      src/layouts/ItemDetailsLayout/ItemDetailsLayout.js
  26. 1
    1
      src/layouts/ItemDetailsLayout/ItemDetailsLayout.styled.js
  27. 2
    5
      src/layouts/ProfileLayout/ProfileLayout.js
  28. 82
    2
      src/pages/About/AboutPage.js
  29. 1
    1
      src/pages/About/AboutPage.styled.js
  30. 1
    1
      src/pages/ProfilePage/ProfilePage.js
  31. 2
    1
      src/store/actions/app/appActionConstants.js
  32. 5
    1
      src/store/actions/app/appActions.js
  33. 20
    0
      src/store/reducers/app/appReducer.js
  34. 2
    0
      src/store/reducers/index.js
  35. 8
    0
      src/store/selectors/appSelectors.js

+ 6
- 6
src/AppRoutes.js Прегледај датотеку

@@ -19,9 +19,9 @@ import {
CHAT_MESSAGE_PAGE,
CHAT_PAGE,
MY_OFFERS_PAGE,
PRICES_PAGE,
// PRICES_PAGE,
ABOUT_PAGE,
POLICY_PRIVACY_PAGE,
// POLICY_PRIVACY_PAGE,
} from "./constants/pages";
import LoginPage from "./pages/LoginPage/LoginPage";
import HomePage from "./pages/HomePage/HomePageMUI";
@@ -39,9 +39,9 @@ import ProfilePage from "./pages/ProfilePage/ProfilePage";
import ChatMessagesPage from "./pages/ChatMessages/ChatMessages";
import ChatPage from "./pages/Chat/Chat";
import MyOffers from "./pages/MyOffers/MyOffers";
import PricesPage from "./pages/Prices/PricesPage";
// import PricesPage from "./pages/Prices/PricesPage";
import AboutPage from "./pages/About/AboutPage";
import PrivacyPolicyPage from "./pages/PrivacyPolicy/PrivacyPolicyPage";
// import PrivacyPolicyPage from "./pages/PrivacyPolicy/PrivacyPolicyPage";

const AppRoutes = () => {
return (
@@ -58,9 +58,9 @@ const AppRoutes = () => {
<Route path={CREATE_OFFER_PAGE} component={CreateOffer} />
<Route path={ITEM_DETAILS_PAGE} component={ItemDetailsPage} />
<Route path={PROFILE_PAGE} component={ProfilePage} />
<Route path={PRICES_PAGE} component={PricesPage} />
{/* <Route path={PRICES_PAGE} component={PricesPage} /> */}
<Route path={ABOUT_PAGE} component={AboutPage} />
<Route path={POLICY_PRIVACY_PAGE} component={PrivacyPolicyPage} />
{/* <Route path={POLICY_PRIVACY_PAGE} component={PrivacyPolicyPage} /> */}
<Route
path={HOME_PAGE}
component={(props) => {

+ 8
- 5
src/components/About/AboutComponent.js Прегледај датотеку

@@ -1,4 +1,4 @@
import React from "react";
import React, { forwardRef } from "react";
import PropTypes from "prop-types";
import AboutHeader from "./AboutHeader/AboutHeader";
import AboutSection from "./AboutSection/AboutSection";
@@ -6,11 +6,12 @@ import { useTranslation } from "react-i18next";
import SectionImage1 from "../../assets/images/about/about-1.png";
import SectionImage2 from "../../assets/images/about/about-2.png";
import CheckOffersButton from "./CheckOffersButton/CheckOffersButton";
import { AboutComponentContainer } from "./AboutComponent.styled";

const AboutComponent = () => {
const AboutComponent = forwardRef((props, ref) => {
const { t } = useTranslation();
return (
<>
<AboutComponentContainer ref={ref}>
<AboutHeader />
<AboutSection
title={t("about.history.title")}
@@ -24,9 +25,11 @@ const AboutComponent = () => {
reverse
/>
<CheckOffersButton />
</>
</AboutComponentContainer>
);
};
});

AboutComponent.displayName = "AboutComponent";

AboutComponent.propTypes = {
children: PropTypes.node,

+ 6
- 0
src/components/About/AboutComponent.styled.js Прегледај датотеку

@@ -0,0 +1,6 @@
import { Box } from "@mui/material";
import styled from "styled-components";

export const AboutComponentContainer = styled(Box)`
position: relative;
`

+ 1
- 1
src/components/About/CheckOffersButton/CheckOffersButton.styled.js Прегледај датотеку

@@ -4,7 +4,7 @@ import { PrimaryButton } from "../../Buttons/PrimaryButton/PrimaryButton";

export const CheckOffersButtonContainer = styled(PrimaryButton)`
position: absolute;
bottom: 44px;
bottom: 8px;
right: 36px;
width: 180px;
height: 49px;

+ 32
- 0
src/components/Footer/AboutFooter.js Прегледај датотеку

@@ -0,0 +1,32 @@
import React from "react";
import PropTypes from "prop-types";
import {
AboutFooterContainer,
AboutFooterText,
Arrow,
ButtonContainer,
LinkText,
} from "./AboutFooter.styled";
import { useTranslation } from "react-i18next";

const AboutFooter = () => {
const { t } = useTranslation();
const handleGoStart = () => {
window.scrollTo({ top: 0, behavior: "smooth" });
};
return (
<AboutFooterContainer>
<AboutFooterText>{t("aboutFooter.middleText")}</AboutFooterText>
<ButtonContainer onClick={handleGoStart}>
<LinkText>{t("aboutFooter.goStart")}</LinkText>
<Arrow />
</ButtonContainer>
</AboutFooterContainer>
);
};

AboutFooter.propTypes = {
children: PropTypes.node,
};

export default AboutFooter;

+ 49
- 0
src/components/Footer/AboutFooter.styled.js Прегледај датотеку

@@ -0,0 +1,49 @@
import { Box, Link, Typography } from "@mui/material";
import styled from "styled-components";
import selectedTheme from "../../themes";
import { ArrowButton } from "../Buttons/ArrowButton/ArrowButton";

export const AboutFooterContainer = styled(Box)`
height: 144px;
background-color: white;
display: flex;
flex-direction: column;
padding: 0 72px;
`;
export const AboutFooterText = styled(Typography)`
font-family: "Open Sans";
font-weight: 400;
font-size: 16px;
line-height: 22px;
color: ${selectedTheme.primaryGrayText};
width: 100%;
text-align: center;
position: relative;
top: 61px;
`;
export const ButtonContainer = styled(Link)`
width: fit-content;
cursor: pointer;
display: flex;
flex-direction: row;
justify-content: flex-end;
gap: 12px;
text-decoration: none;
color: ${selectedTheme.primaryPurple};
width: 100%;
text-align: right;
position: relative;
top: 29px;
`;
export const LinkText = styled(Typography)`
font-family: "Open Sans";
line-height: 22px;
font-size: 16px;
color: ${selectedTheme.primaryGrayText};
position: relative;
top: 8px;
`;

export const Arrow = styled(ArrowButton)`
transform: rotate(-90deg);
`;

+ 68
- 0
src/components/Header/AboutHeader/AboutHeader.js Прегледај датотеку

@@ -0,0 +1,68 @@
import React from "react";
import PropTypes from "prop-types";
import { AboutHeaderContainer, LinkRoute } from "./AboutHeader.styled";
import { useTranslation } from "react-i18next";
import scrollConstants from "../../../constants/scrollConstants";
import { useSelector } from "react-redux";
import { selectAboutRouteSelected } from "../../../store/selectors/appSelectors";
import { useHistory } from "react-router-dom";

const AboutHeader = () => {
console.log("about header");
const history = useHistory();
const { t } = useTranslation();
const aboutRouteSelected = useSelector(selectAboutRouteSelected);
const navigateAbout = () => {
history.replace({
state: {
clicked: true,
navigation: scrollConstants.about.aboutPage,
},
});
};
const navigatePrices = () => {
history.replace({
state: {
clicked: true,
navigation: scrollConstants.about.pricesPage,
},
});
};
const navigatePrivacyPolicy = () => {
history.replace({
state: {
clicked: true,
navigation: scrollConstants.about.privacyPolicyPage,
},
});
};
return (
<AboutHeaderContainer>
<LinkRoute
selected={aboutRouteSelected === scrollConstants.about.aboutPage}
onClick={navigateAbout}
>
{t("about.header.navigation")}
</LinkRoute>
<LinkRoute
selected={aboutRouteSelected === scrollConstants.about.pricesPage}
onClick={navigatePrices}
>
{t("prices.header.navigation")}
</LinkRoute>
<LinkRoute
selected={aboutRouteSelected === scrollConstants.about.privacyPolicyPage}
onClick={navigatePrivacyPolicy}
>
{t("privacyPolicy.header.navigation")}
</LinkRoute>
</AboutHeaderContainer>
);
};

AboutHeader.propTypes = {
children: PropTypes.node,
selected: PropTypes.string,
};

export default AboutHeader;

+ 21
- 0
src/components/Header/AboutHeader/AboutHeader.styled.js Прегледај датотеку

@@ -0,0 +1,21 @@
import { Box } from "@mui/material";
import styled from "styled-components";
import Link from "../../Link/Link";

export const AboutHeaderContainer = styled(Box)`
flex: 5;
z-index: 3000;
display: flex;
color: black;
flex-direction: row;
justify-content: center;
gap: 36px;
`;
export const LinkRoute = styled(Link)`
text-decoration: none;
font-family: "Open Sans";
font-weight: ${props => props.selected ? "600" : "400"};
font-size: 16px;
line-height: 22px;
letter-spacing: 0.02em;
`;

+ 80
- 66
src/components/Header/Header.js Прегледај датотеку

@@ -39,6 +39,7 @@ import { selectUserId } from "../../store/selectors/loginSelectors";
import { selectProfileName } from "../../store/selectors/profileSelectors";
import { useHistory, useRouteMatch } from "react-router-dom";
import {
ABOUT_PAGE,
BASE_PAGE,
FORGOT_PASSWORD_MAIL_SENT,
FORGOT_PASSWORD_PAGE,
@@ -54,6 +55,7 @@ import CreateOffer from "../Cards/CreateOfferCard/CreateOffer";
import { Drawer as HeaderDrawer } from "./Drawer/Drawer";
import useSearch from "../../hooks/useOffers/useSearch";
import { routeMatches } from "../../util/helpers/routeHelpers";
import AboutHeader from "./AboutHeader/AboutHeader";
// import useQueryString from "../../hooks/useOffers/useQueryString";

const Header = () => {
@@ -87,7 +89,9 @@ const Header = () => {
};
}, []);
useEffect(() => {
searchRef.current.value = search.searchString ?? "";
if (searchRef.current) {
searchRef.current.value = search.searchString ?? "";
}
}, [search.searchString]);
useEffect(() => {
if (history.location.pathname !== "/home") {
@@ -173,10 +177,7 @@ const Header = () => {
searchRef.current.removeEventListener("keyup", listener);
};
const handleSearch = (value) => {
if (
!routeMatches(HOME_PAGE) &&
!routeMatches(BASE_PAGE)
) {
if (!routeMatches(HOME_PAGE) && !routeMatches(BASE_PAGE)) {
const newQueryString = new URLSearchParams({ search: value });
history.push({
pathname: HOME_PAGE,
@@ -205,15 +206,15 @@ const Header = () => {
const closePostsPopover = () => {
setPostsPopoverOpen(false);
setPostsAnchorEl(null);
}
};
const closeMsgPopover = () => {
setMsgPopoverOpen(false);
setMsgAnchorEl(null);
}
};
const closeUserPopover = () => {
setUserPopoverOpen(false);
setUserAnchorEl(null);
}
};

return (
<HeaderContainer style={{ display: shouldShow ? "block" : "none" }}>
@@ -239,24 +240,31 @@ const Header = () => {
}
/>
)}
<SearchInput
fullWidth
InputProps={{
endAdornment: (
<EndIcon size="36px">
<SearchIcon
onClick={() => handleSearch(searchRef.current.value)}
/>
</EndIcon>
),
}}
placeholder={t("header.searchOffers")}
onFocus={handleFocusSearch}
onBlur={handleBlurSearch}
ref={searchRef}
/>
{!routeMatches(ABOUT_PAGE) && (
<SearchInput
fullWidth
InputProps={{
endAdornment: (
<EndIcon size="36px">
<SearchIcon
onClick={() => handleSearch(searchRef.current.value)}
/>
</EndIcon>
),
}}
placeholder={t("header.searchOffers")}
onFocus={handleFocusSearch}
onBlur={handleBlurSearch}
ref={searchRef}
/>
)}
{routeMatches(ABOUT_PAGE) && <AboutHeader />}

{user ? (
<ToolsButtonsContainer mobile={matches}>
<ToolsButtonsContainer
mobile={matches}
shrink={routeMatches(ABOUT_PAGE)}
>
{matches ? (
<ToggleDrawerButton>
<IconButton onClick={handleToggleDrawer}>
@@ -265,46 +273,52 @@ const Header = () => {
</ToggleDrawerButton>
) : (
<React.Fragment>
<AddOfferButton
type="submit"
variant="contained"
fullWidth
buttoncolor={selectedTheme.primaryYellow}
textcolor={selectedTheme.primaryDarkText}
onClick={() => {
setUserPopoverOpen(false);
setUserAnchorEl(null);
setShowCreateOfferModal(true);
}}
>
{t("header.addOffer")}
</AddOfferButton>
<IconButton
onClick={(e) => {
setPostsPopoverOpen(true);
setPostsAnchorEl(e.currentTarget);
}}
style={{
background: selectedTheme.primaryIconBackgroundColor,
color: selectedTheme.primaryPurple,
}}
>
<SwapsIcon />
</IconButton>
<IconButton
onClick={(e) => {
setMsgPopoverOpen(true);
setMsgAnchorEl(e.currentTarget);
}}
style={{
background: selectedTheme.primaryIconBackgroundColor,
color: selectedTheme.primaryPurple,
}}
>
<Badge badgeContent={3} color="primary">
<MailIcon />
</Badge>
</IconButton>
{!routeMatches(ABOUT_PAGE) && (
<>
<AddOfferButton
type="submit"
variant="contained"
fullWidth
buttoncolor={selectedTheme.primaryYellow}
textcolor={selectedTheme.primaryDarkText}
onClick={() => {
setUserPopoverOpen(false);
setUserAnchorEl(null);
setShowCreateOfferModal(true);
}}
>
{t("header.addOffer")}
</AddOfferButton>
<IconButton
onClick={(e) => {
setPostsPopoverOpen(true);
setPostsAnchorEl(e.currentTarget);
}}
style={{
background:
selectedTheme.primaryIconBackgroundColor,
color: selectedTheme.primaryPurple,
}}
>
<SwapsIcon />
</IconButton>
<IconButton
onClick={(e) => {
setMsgPopoverOpen(true);
setMsgAnchorEl(e.currentTarget);
}}
style={{
background:
selectedTheme.primaryIconBackgroundColor,
color: selectedTheme.primaryPurple,
}}
>
<Badge badgeContent={3} color="primary">
<MailIcon />
</Badge>
</IconButton>
</>
)}
<UserButton
onClick={(e) => {
setUserPopoverOpen(true);
@@ -378,7 +392,7 @@ const Header = () => {
setMsgPopoverOpen(false);
setMsgAnchorEl(null);
}}
content={<MyMessages closePopover={closeMsgPopover}/>}
content={<MyMessages closePopover={closeMsgPopover} />}
/>
<PopoverComponent
anchorEl={userAnchorEl}

+ 4
- 4
src/components/Header/Header.styled.js Прегледај датотеку

@@ -55,17 +55,17 @@ export const LogoContainer = styled(Box)`
`;
export const ToolsButtonsContainer = styled(Box)`
display: flex;
flex: 4;
flex: ${props => props.shrink ? "none" : "4"};;
justify-content: space-between;
min-width: ${(props) => (props.mobile ? "40px" : "600px")};
min-width: ${(props) => (props.mobile ? "40px" : props.shrink ? "0" : "600px")};
max-width: 600px;
align-items: center;
flex-wrap: nowrap;
@media (max-width: 1400px) {
min-width: 450px;
min-width: ${props => props.shrink ? "0" : "450px"};
}
@media (max-width: 1200px) {
min-width: 400px;
min-width: ${props => props.shrink ? "0" : "400px"};
}
@media (max-width: 900px) {
flex: 0.35;

+ 0
- 1
src/components/MarketPlace/Offers/Offers.js Прегледај датотеку

@@ -47,7 +47,6 @@ const Offers = (props) => {
) : (
<OffersContainer ref={offersRef}>
{offers.allOffersToShow.map((item) => {
console.log(item);
return (
<OfferCard
key={item._id}

+ 11
- 2
src/components/Popovers/MyProfile/AboutButton/AboutButton.js Прегледај датотеку

@@ -6,12 +6,20 @@ import { GrayButton } from "../MyProfile.styled";
import { PopoverButton } from "../../HeaderPopover/HeaderPopover.styled";
import { InfoIcon } from "./AboutButton.styled";
import { useHistory } from "react-router-dom";
import scrollConstants from "../../../../constants/scrollConstants";

const AboutButton = () => {
const AboutButton = (props) => {
const { t } = useTranslation();
const history = useHistory();
const seeAbout = () => {
history.push(ABOUT_PAGE);
history.push({
pathname: ABOUT_PAGE,
state: {
navigation: scrollConstants.about.aboutPage,
clicked: true,
}
});
props.closePopover();
};
return (
<GrayButton>
@@ -32,6 +40,7 @@ const AboutButton = () => {

AboutButton.propTypes = {
children: PropTypes.node,
closePopover: PropTypes.func,
};

export default AboutButton;

+ 12
- 4
src/components/Popovers/MyProfile/MyProfile.js Прегледај датотеку

@@ -14,10 +14,11 @@ import selectedTheme from "../../../themes";
import { EyeIcon } from "../HeaderPopover/HeaderPopover.styled";
import { useHistory } from "react-router-dom";
import PropTypes from "prop-types";
import { PRICES_PAGE } from "../../../constants/pages";
import { ABOUT_PAGE } from "../../../constants/pages";
import LogoutButton from "./LogoutButton/LogoutButton";
import AboutButton from "./AboutButton/AboutButton";
import PrivacyPolicyButton from "./PrivacyPolicyButton/PrivacyPolicyButton";
import scrollConstants from "../../../constants/scrollConstants";

export const MyProfile = (props) => {
const { t } = useTranslation();
@@ -53,7 +54,14 @@ export const MyProfile = (props) => {
props.closePopover();
};
const seePrices = () => {
history.push(PRICES_PAGE);
history.push({
pathname: ABOUT_PAGE,
state: {
clicked: true,
navigation: scrollConstants.about.pricesPage
}
});
props.closePopover();
};


@@ -71,8 +79,8 @@ export const MyProfile = (props) => {
>
<LogoutButton />
<GrayButtonsContainer>
<AboutButton />
<PrivacyPolicyButton />
<AboutButton closePopover={props.closePopover}/>
<PrivacyPolicyButton closePopover={props.closePopover} />
</GrayButtonsContainer>
</HeaderPopover>
);

+ 12
- 3
src/components/Popovers/MyProfile/PrivacyPolicyButton/PrivacyPolicyButton.js Прегледај датотеку

@@ -3,15 +3,23 @@ import PropTypes from "prop-types";
import { GrayButton } from "../MyProfile.styled";
import { PopoverButton } from "../../HeaderPopover/HeaderPopover.styled";
import { BuildingShieldIcon } from "./PrivacyPolicyButton.styled";
import { POLICY_PRIVACY_PAGE } from "../../../../constants/pages";
import { ABOUT_PAGE } from "../../../../constants/pages";
import { useTranslation } from "react-i18next";
import { useHistory } from "react-router-dom";
import scrollConstants from "../../../../constants/scrollConstants";

const PrivacyPolicyButton = () => {
const PrivacyPolicyButton = (props) => {
const { t } = useTranslation();
const history = useHistory();
const seePrivacy = () => {
history.push(POLICY_PRIVACY_PAGE);
history.push({
pathname: ABOUT_PAGE,
state: {
clicked: true,
navigation: scrollConstants.about.privacyPolicyPage,
},
});
props.closePopover();
};
return (
<GrayButton>
@@ -32,6 +40,7 @@ const PrivacyPolicyButton = () => {

PrivacyPolicyButton.propTypes = {
children: PropTypes.node,
closePopover: PropTypes.func,
};

export default PrivacyPolicyButton;

+ 1
- 0
src/components/Prices/Plan/Plan.styled.js Прегледај датотеку

@@ -10,6 +10,7 @@ export const PlanContainer = styled(Box)`
border-radius: 4px;
position: relative;
padding: 36px;
min-width: 408px;
background-color: ${(props) =>
props.highlighted ? selectedTheme.primaryPurple : "white"};


+ 7
- 4
src/components/Prices/PricesComponent.js Прегледај датотеку

@@ -1,4 +1,4 @@
import React from "react";
import React, { forwardRef } from "react";
import PropTypes from "prop-types";
import {
CartIcon,
@@ -12,10 +12,10 @@ import PricesHeader from "./PricesHeader/PricesHeader";
import Plan from "./Plan/Plan";
import { useTranslation } from "react-i18next";

const PricesComponent = () => {
const PricesComponent = forwardRef((props, ref) => {
const { t } = useTranslation();
return (
<PricesComponentContainer>
<PricesComponentContainer id={props.id} ref={ref}>
<PricesHeader />
<PlansContainer>
<Plan
@@ -38,10 +38,13 @@ const PricesComponent = () => {
<PricesAltText>{t("prices.altText")}</PricesAltText>
</PricesComponentContainer>
);
};
});

PricesComponent.displayName = "PricesComponent";

PricesComponent.propTypes = {
children: PropTypes.node,
id: PropTypes.string,
};

export default PricesComponent;

+ 4
- 1
src/components/Prices/PricesComponent.styled.js Прегледај датотеку

@@ -6,11 +6,14 @@ import { ReactComponent as Cart } from "../../assets/images/svg/shopping-cart.sv
import selectedTheme from "../../themes";

export const PricesComponentContainer = styled(Box)`
margin: 72px;
padding: 72px;
background: white;
`;
export const PlansContainer = styled(Box)`
display: flex;
width: 100%;
flex-direction: row;
justify-content: space-between;
gap: 50px;
margin-top: 46px;
margin-bottom: 36px;

+ 3
- 0
src/components/Prices/PricesHeader/PricesHeader.styled.js Прегледај датотеку

@@ -19,6 +19,8 @@ export const PricesHeaderContainer = styled(Box)`
width: 100%;
justify-content: space-between;
`;
// Below is display set to none because there is no currently function for this button,
// but it function may be added in future
export const ButtonContainer = styled(Link)`
width: fit-content;
cursor: pointer;
@@ -28,6 +30,7 @@ export const ButtonContainer = styled(Link)`
gap: 12px;
text-decoration: none;
color: ${selectedTheme.primaryPurple};
display: none;
`;
export const LinkText = styled(Typography)`
border-bottom: 1px dotted ${selectedTheme.primaryPurple};

+ 7
- 4
src/components/PrivacyPolicy/PrivacyPolicyComponent.js Прегледај датотеку

@@ -1,14 +1,14 @@
import React from "react";
import React, { forwardRef } from "react";
import PropTypes from "prop-types";
import PrivacyPolicyHeader from "./PrivacyPolicyHeader/PrivacyPolicyHeader";
import { PrivacyPolicyContainer } from "./PrivacyPolicyComponent.styled";
import PrivacyPolicySection from "./PrivacyPolicySection/PrivacyPolicySection";
import { useTranslation } from "react-i18next";

const PrivacyPolicyComponent = () => {
const PrivacyPolicyComponent = forwardRef((props, ref) => {
const { t } = useTranslation();
return (
<PrivacyPolicyContainer>
<PrivacyPolicyContainer id={props.id} ref={ref}>
<PrivacyPolicyHeader />
<PrivacyPolicySection
title={t("privacyPolicy.firstSection.title")}
@@ -28,10 +28,13 @@ const PrivacyPolicyComponent = () => {
/>
</PrivacyPolicyContainer>
);
};
});

PrivacyPolicyComponent.displayName = "PrivacyPolicyComponent";

PrivacyPolicyComponent.propTypes = {
children: PropTypes.node,
id: PropTypes.string,
};

export default PrivacyPolicyComponent;

+ 1
- 0
src/components/UserReviews/UserReviews.styled.js Прегледај датотеку

@@ -12,6 +12,7 @@ export const ReviewsBox = styled(Box)`
? props.numOfReviews * 185 + 82 + "px"
: `calc(100% - 90px)`}; */
/* max-height: 100vh; */
min-width: 320px;
@media (max-width: 1200px) {
padding: 0 50px;
}

+ 7
- 0
src/constants/scrollConstants.js Прегледај датотеку

@@ -0,0 +1,7 @@
export default {
about: {
aboutPage: "about",
pricesPage: "prices",
privacyPolicyPage: "privacyPolicy"
}
}

+ 6
- 0
src/hooks/useOffers/useOffers.js Прегледај датотеку

@@ -93,6 +93,11 @@ const useOffers = () => {
if (queryObject[KEY_PAGE] !== 1)
paging.changePage(queryObject[KEY_PAGE]);
}
if (KEY_SEARCH in queryObject) {
search.searchOffers(queryObject[KEY_SEARCH]);
} else {
search.clear();
}
dispatch(setSearchString(queryObject[KEY_SEARCH]));
}
}, [queryStringHook.isInitiallyLoaded]);
@@ -140,6 +145,7 @@ const useOffers = () => {
filters.clear();
sorting.clear();
paging.changePage(1);
search.clear();
};

return {

+ 24
- 0
src/hooks/useOffers/useSearch.js Прегледај датотеку

@@ -1,13 +1,18 @@
import { useEffect, useState } from "react";
import { useDispatch, useSelector } from "react-redux";
import { useHistory } from "react-router-dom";
import { BASE_PAGE, HOME_PAGE } from "../../constants/pages";
import { KEY_SEARCH } from "../../constants/queryStringConstants";
import { setSearchString } from "../../store/actions/filters/filtersActions";
import { selectSearchString } from "../../store/selectors/filtersSelectors";
import { routeMatches } from "../../util/helpers/routeHelpers";

const useSearch = (applyAllFilters) => {
const [searchStringLocally, setSearchStringLocally] = useState("");
const [isInitallyLoaded, setIsInitiallyLoaded] = useState(false);
const dispatch = useDispatch();
const searchString = useSelector(selectSearchString);
const history = useHistory();

// On every global change of search string, new request to backend should be sent
useEffect(() => {
@@ -19,8 +24,26 @@ const useSearch = (applyAllFilters) => {
}
}, [searchString]);

// Empty search string when user navigates to other page
useEffect(() => {
if (
(!routeMatches(HOME_PAGE) || !routeMatches(BASE_PAGE)) &&
isInitallyLoaded
) {
clear();
}
const queryObject = new URLSearchParams(history.location.search);
console.log(queryObject.toString())
if (queryObject.has(KEY_SEARCH)) {
searchOffers(queryObject.get(KEY_SEARCH));
} else {
clear();
}
}, [history.location.pathname]);

// On every local change of search string, global state of search string should be also updated
useEffect(() => {
console.log('ovde')
if (isInitallyLoaded && applyAllFilters) {
dispatch(setSearchString(searchStringLocally));
}
@@ -32,6 +55,7 @@ const useSearch = (applyAllFilters) => {
};

const clear = () => {
console.log('ovde2')
setSearchStringLocally("");
};


+ 7
- 0
src/i18n/resources/rs.js Прегледај датотеку

@@ -263,6 +263,7 @@ export default {
about: {
header: {
title: "O Trampi",
navigation: 'O nama',
paragraph:
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec ac augue tortor. Nulla facilisi. Cras vestibulum risus eget tincidunt egestas. Duis blandit enim sit amet dui vehicula luctus. Suspendisse id blandit arcu, vitae consequat nisi. Duis ut vestibulum tellus. Curabitur eu fringilla nisi.",
},
@@ -279,6 +280,7 @@ export default {
privacyPolicy: {
header: {
title: "Politika Privatnosti",
navigation: "Uslovi korišćenja",
paragraph:
"Aenean ut risus faucibus, tempor urna id, luctus urna. Nam placerat scelerisque hendrerit. Nam tortor augue, porta sed nulla vitae, rutrum rhoncus arcu. Ut in leo turpis. Pellentesque eu laoreet orci. Nam id nisi mauris.",
},
@@ -302,6 +304,7 @@ export default {
prices: {
header: {
title: "Cenovnik",
navigation: 'Cenovnik',
link: "Pročitajte opširnije o našim ponudama",
},
altText:
@@ -353,4 +356,8 @@ export default {
fifthQuantity: "",
},
},
aboutFooter: {
goStart: "Početak stranice",
middleText: "Diligent Software © 2022 | Sva prava zadržana"
}
};

+ 2
- 1
src/layouts/ItemDetailsLayout/ItemDetailsLayout.js Прегледај датотеку

@@ -13,7 +13,7 @@ const ItemDetailsLayout = (props) => {
{props.children}
<ContentRightCardContainer>
<Content item>{props.content}</Content>
<RightCard item singleOffer={props.singleOffer}>
<RightCard item singleOffer={props.singleOffer} profile={props.profile}>
{props.rightCard}
</RightCard>
</ContentRightCardContainer>
@@ -27,6 +27,7 @@ ItemDetailsLayout.propTypes = {
content: PropTypes.node,
rightCard: PropTypes.node,
singleOffer: PropTypes.bool,
profile: PropTypes.bool,
};

export default ItemDetailsLayout;

+ 1
- 1
src/layouts/ItemDetailsLayout/ItemDetailsLayout.styled.js Прегледај датотеку

@@ -35,7 +35,7 @@ export const RightCard = styled(Grid)`

@media screen and (min-width: 600px) {
margin-top: 34px;
margin-left: 36px;
margin-left: ${props => props.profile ? "0" : "36px"};
padding-left: ${(props) => (props.singleOffer ? "36px" : 0)};
border-top-right-radius: 4px;
${(props) => props.singleOffer && `width: 100%`}

+ 2
- 5
src/layouts/ProfileLayout/ProfileLayout.js Прегледај датотеку

@@ -1,6 +1,6 @@
import React from "react";
import PropTypes from "prop-types";
import { Content, LeftCard, RightCard, ProfileLayoutContainer, HeaderCard, MiddleCard } from "./ProfileLayout.styled";
import { Content, RightCard, ProfileLayoutContainer, HeaderCard, MiddleCard } from "./ProfileLayout.styled";
import { Grid } from "@mui/material";

const ProfileLayout = (props) => {
@@ -8,10 +8,7 @@ const ProfileLayout = (props) => {
<ProfileLayoutContainer>
{props.children}
<Grid container maxHeight maxWidth={1900}>
<LeftCard item xs={2} lg={2.5} xl={2.4} md={3}>
{props.leftCard}
</LeftCard>
<MiddleCard item xs={7.5} lg={6.5} xl={6.6} md={6}>
<MiddleCard item xs={9.5} lg={6.5} xl={6.6} md={6}>
<HeaderCard>
{props.headerCard}
</HeaderCard>

+ 82
- 2
src/pages/About/AboutPage.js Прегледај датотеку

@@ -1,12 +1,92 @@
import React from "react";
import React, { useEffect, useRef } from "react";
import PropTypes from "prop-types";
import AboutComponent from "../../components/About/AboutComponent";
import { AboutPageContainer } from "./AboutPage.styled";
// import PricesComponent from "../../components/Prices/PricesComponent";
import PrivacyPolicyComponent from "../../components/PrivacyPolicy/PrivacyPolicyComponent";
import PricesComponent from "../../components/Prices/PricesComponent";
import { useLocation } from "react-router-dom";
import scrollConstants from "../../constants/scrollConstants";
import { useDispatch, useSelector } from "react-redux";
import { selectAboutRouteSelected } from "../../store/selectors/appSelectors";
import { setAboutRouteSelected } from "../../store/actions/app/appActions";
import AboutFooter from "../../components/Footer/AboutFooter";

const AboutPage = () => {
const aboutRef = useRef(null);
const pricesRef = useRef(null);
const privacyPolicyRef = useRef(null);
const dispatch = useDispatch();
const aboutRouteSelected = useSelector(selectAboutRouteSelected);
const location = useLocation();
useEffect(() => {
if (location.state && location.state?.clicked) {
if (location.state.navigation === scrollConstants.about.aboutPage) {
window.scrollTo({ top: 0, behavior: "smooth" });
if (aboutRouteSelected !== scrollConstants.about.aboutPage) {
dispatch(setAboutRouteSelected(scrollConstants.about.aboutPage));
}
}
if (location.state.navigation === scrollConstants.about.pricesPage) {
const yAxis = pricesRef.current.offsetTop;
window.scrollTo({ top: yAxis, behavior: "smooth" });
if (aboutRouteSelected !== scrollConstants.about.pricesPage) {
dispatch(setAboutRouteSelected(scrollConstants.about.pricesPage));
}
}
if (
location.state.navigation === scrollConstants.about.privacyPolicyPage
) {
const yAxis = privacyPolicyRef.current.offsetTop - 64;
window.scrollTo({ top: yAxis, behavior: "smooth" });
if (aboutRouteSelected !== scrollConstants.about.privacyPolicyPage) {
dispatch(setAboutRouteSelected(scrollConstants.about.privacyPolicyPage));
}
}
location.state = {};
}
return () => {
console.log(location);
};
}, [location]);

useEffect(() => {
const listener = () => {
if (
window.scrollY >
pricesRef.current.offsetTop - window.innerHeight / 2
) {
console.log(true);
if (
window.scrollY >
privacyPolicyRef.current.offsetTop - window.innerHeight / 2
) {
if (aboutRouteSelected !== scrollConstants.about.privacyPolicyPage) {
dispatch(
setAboutRouteSelected(scrollConstants.about.privacyPolicyPage)
);
}
} else if (aboutRouteSelected !== scrollConstants.about.pricesPage) {
dispatch(setAboutRouteSelected(scrollConstants.about.pricesPage));
}
} else {
if (aboutRouteSelected !== scrollConstants.about.aboutPage) {
dispatch(setAboutRouteSelected(scrollConstants.about.aboutPage));
}
}
};
window.addEventListener("scroll", listener);
return () => window.removeEventListener("scroll", listener);
}, [aboutRouteSelected]);
return (
<AboutPageContainer>
<AboutComponent />
<AboutComponent ref={aboutRef} id={scrollConstants.about.aboutPage} />
<PricesComponent ref={pricesRef} id={scrollConstants.about.pricesPage} />
<PrivacyPolicyComponent
ref={privacyPolicyRef}
id={scrollConstants.about.privacyPolicyPage}
/>
<AboutFooter />
</AboutPageContainer>
);
};

+ 1
- 1
src/pages/About/AboutPage.styled.js Прегледај датотеку

@@ -3,7 +3,7 @@ import styled from "styled-components";
import selectedTheme from "../../themes";

export const AboutPageContainer = styled(Box)`
margin-top: 80px;
margin-top: 64px;
background-color: ${selectedTheme.staticBackgroundColor};
position: relative;
@media (max-width: 600px) {

+ 1
- 1
src/pages/ProfilePage/ProfilePage.js Прегледај датотеку

@@ -7,7 +7,7 @@ import UserReviews from "../../components/UserReviews/UserReviews";
const ProfilePage = () => {
return (
<ProfilePageContainer>
<ItemDetailsLayout content={<Profile/>} rightCard={<UserReviews isProfileReviews/>} />
<ItemDetailsLayout content={<Profile/>} rightCard={<UserReviews isProfileReviews/>} profile />
</ProfilePageContainer>
);
};

+ 2
- 1
src/store/actions/app/appActionConstants.js Прегледај датотеку

@@ -1,5 +1,6 @@
import { createLoadingType } from '../actionHelpers';
import { createLoadingType, createSetType } from '../actionHelpers';

export const APP_LOADING = createLoadingType('APP_LOADING');
export const ADD_LOADER = createLoadingType("ADD_LOADER");
export const REMOVE_LOADER = createLoadingType("REMOVE_LOADER");
export const ABOUT_ROUTE_SELECTED = createSetType("ABOUT_ROUTE_SELECTED");

+ 5
- 1
src/store/actions/app/appActions.js Прегледај датотеку

@@ -1,4 +1,4 @@
import { ADD_LOADER, REMOVE_LOADER } from "./appActionConstants";
import { ABOUT_ROUTE_SELECTED, ADD_LOADER, REMOVE_LOADER } from "./appActionConstants";

export const addLoader = (payload) => ({
type: ADD_LOADER,
@@ -8,3 +8,7 @@ export const removeLoader = (payload) => ({
type: REMOVE_LOADER,
payload
})
export const setAboutRouteSelected = (payload) => ({
type: ABOUT_ROUTE_SELECTED,
payload
})

+ 20
- 0
src/store/reducers/app/appReducer.js Прегледај датотеку

@@ -0,0 +1,20 @@
import scrollConstants from "../../../constants/scrollConstants";
import { ABOUT_ROUTE_SELECTED } from "../../actions/app/appActionConstants";
import createReducer from "../../utils/createReducer";

const initialState = {
aboutRouteSelected: scrollConstants.about.aboutPage,
};

export default createReducer(
{
[ABOUT_ROUTE_SELECTED]: setAboutRouteSelected,
},
initialState
);
function setAboutRouteSelected(state, { payload }) {
return {
...state,
aboutRouteSelected: payload,
};
}

+ 2
- 0
src/store/reducers/index.js Прегледај датотеку

@@ -14,6 +14,7 @@ import chatReducer from "./chat/chatReducer";
import queryStringReducer from "./queryString/queryStringReducer";
import exchangeReducer from "./exchange/exchangeReducer";
import reviewReducer from "./review/reviewReducer";
import appReducer from "./app/appReducer";

const loginPersistConfig = {
key: "login",
@@ -62,4 +63,5 @@ export default combineReducers({
queryString: queryStringReducer,
exchange: exchangeReducer,
review: reviewReducer,
app: appReducer,
});

+ 8
- 0
src/store/selectors/appSelectors.js Прегледај датотеку

@@ -0,0 +1,8 @@
import { createSelector } from "reselect";

const appSelector = (state) => state.app;

export const selectAboutRouteSelected = createSelector(
appSelector,
(state) => state.aboutRouteSelected
)

Loading…
Откажи
Сачувај