| ADMIN_HOME_PAGE, | ADMIN_HOME_PAGE, | ||||
| MESSAGES_LIST_PAGE, | MESSAGES_LIST_PAGE, | ||||
| DIRECT_CHAT_PAGE, | DIRECT_CHAT_PAGE, | ||||
| MARKETPLACE_PAGE, | |||||
| } from "./constants/pages"; | } from "./constants/pages"; | ||||
| import LoginPage from "./pages/LoginPage/LoginPage"; | import LoginPage from "./pages/LoginPage/LoginPage"; | ||||
| import AdminLoginPage from "./pages/AdminLoginPage/AdminLoginPage"; | import AdminLoginPage from "./pages/AdminLoginPage/AdminLoginPage"; | ||||
| import AuthRoute from "./components/Router/AuthRoute"; | import AuthRoute from "./components/Router/AuthRoute"; | ||||
| import AdminRoute from "./components/Router/AdminRoute"; | import AdminRoute from "./components/Router/AdminRoute"; | ||||
| import AdminHomePage from "./pages/AdminHomePage/AdminHomePage"; | import AdminHomePage from "./pages/AdminHomePage/AdminHomePage"; | ||||
| import MarketplacePage from "./pages/Marketplace/MarketplacePage"; | |||||
| const AppRoutes = () => { | const AppRoutes = () => { | ||||
| return ( | return ( | ||||
| <AuthRoute path={FORGOT_PASSWORD_PAGE} component={ForgotPasswordPage} /> | <AuthRoute path={FORGOT_PASSWORD_PAGE} component={ForgotPasswordPage} /> | ||||
| <AuthRoute path={RESET_PASSWORD_PAGE} component={ResetPasswordPage} /> | <AuthRoute path={RESET_PASSWORD_PAGE} component={ResetPasswordPage} /> | ||||
| <Route path={REGISTER_SUCCESSFUL_PAGE} component={RegisterSuccessful} /> | <Route path={REGISTER_SUCCESSFUL_PAGE} component={RegisterSuccessful} /> | ||||
| <Route path={MARKETPLACE_PAGE} component={MarketplacePage} /> | |||||
| <Route path={CREATE_OFFER_PAGE} component={CreateOffer} /> | <Route path={CREATE_OFFER_PAGE} component={CreateOffer} /> | ||||
| <Route path={ITEM_DETAILS_PAGE} component={ItemDetailsPage} /> | <Route path={ITEM_DETAILS_PAGE} component={ItemDetailsPage} /> | ||||
| <Route path={PROFILE_PAGE} component={ProfilePage} /> | <Route path={PROFILE_PAGE} component={ProfilePage} /> | ||||
| <Route path={ABOUT_PAGE} component={AboutPage} /> | <Route path={ABOUT_PAGE} component={AboutPage} /> | ||||
| <Route path={HOME_PAGE} component={HomePage} /> | <Route path={HOME_PAGE} component={HomePage} /> | ||||
| <PrivateRoute exact path={MESSAGES_LIST_PAGE} component={MessagesListPage} /> | |||||
| <PrivateRoute | |||||
| exact | |||||
| path={MESSAGES_LIST_PAGE} | |||||
| component={MessagesListPage} | |||||
| /> | |||||
| <PrivateRoute path={DIRECT_CHAT_PAGE} component={DirectChatPage} /> | <PrivateRoute path={DIRECT_CHAT_PAGE} component={DirectChatPage} /> | ||||
| <PrivateRoute path={MY_OFFERS_PAGE} component={MyOffers} /> | <PrivateRoute path={MY_OFFERS_PAGE} component={MyOffers} /> | ||||
| <AdminRoute path={ADMIN_HOME_PAGE} component={AdminHomePage} /> | <AdminRoute path={ADMIN_HOME_PAGE} component={AdminHomePage} /> |
| import React, { useEffect, useRef } from "react"; | |||||
| import PropTypes from "prop-types"; | |||||
| import { useLocation } from "react-router-dom"; | |||||
| import { useDispatch, useSelector } from "react-redux"; | |||||
| import { selectAboutRouteSelected } from "../../store/selectors/appSelectors"; | |||||
| import scrollConstants from "../../constants/scrollConstants"; | |||||
| import { setAboutRouteSelected } from "../../store/actions/app/appActions"; | |||||
| import { AboutPageContainer } from "./AboutPageContent.styled"; | |||||
| import AboutComponent from "./AboutComponent"; | |||||
| import PricesComponent from "../Prices/PricesComponent"; | |||||
| import PrivacyPolicyComponent from "../PrivacyPolicy/PrivacyPolicyComponent"; | |||||
| import AboutFooter from "../Footer/AboutFooter"; | |||||
| const AboutPageContent = () => { | |||||
| 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 = {}; | |||||
| } | |||||
| }, [location]); | |||||
| useEffect(() => { | |||||
| const listener = () => { | |||||
| if ( | |||||
| window.scrollY > | |||||
| pricesRef.current.offsetTop - window.innerHeight / 2 | |||||
| ) { | |||||
| 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 ref={aboutRef} id={scrollConstants.about.aboutPage} /> | |||||
| <PricesComponent ref={pricesRef} id={scrollConstants.about.pricesPage} /> | |||||
| <PrivacyPolicyComponent | |||||
| ref={privacyPolicyRef} | |||||
| id={scrollConstants.about.privacyPolicyPage} | |||||
| /> | |||||
| <AboutFooter /> | |||||
| </AboutPageContainer> | |||||
| ); | |||||
| }; | |||||
| AboutPageContent.propTypes = { | |||||
| children: PropTypes.node, | |||||
| }; | |||||
| export default AboutPageContent; |
| import { Box } from "@mui/system"; | |||||
| import styled from "styled-components"; | |||||
| import selectedTheme from "../../themes"; | |||||
| export const AboutPageContainer = styled(Box)` | |||||
| margin-top: 64px; | |||||
| background-color: ${selectedTheme.colors.staticBackgroundColor}; | |||||
| position: relative; | |||||
| @media (max-width: 600px) { | |||||
| margin-top: 53px; | |||||
| } | |||||
| ` |
| import { CheckOffersButtonContainer } from "./CheckOffersButton.styled"; | import { CheckOffersButtonContainer } from "./CheckOffersButton.styled"; | ||||
| import selectedTheme from "../../../themes"; | import selectedTheme from "../../../themes"; | ||||
| import { useTranslation } from "react-i18next"; | import { useTranslation } from "react-i18next"; | ||||
| import { HOME_PAGE } from "../../../constants/pages"; | |||||
| import { MARKETPLACE_PAGE } from "../../../constants/pages"; | |||||
| import history from "../../../store/utils/history"; | import history from "../../../store/utils/history"; | ||||
| const CheckOffersButton = () => { | const CheckOffersButton = () => { | ||||
| const { t } = useTranslation(); | const { t } = useTranslation(); | ||||
| const handleClick = () => { | const handleClick = () => { | ||||
| history.push(HOME_PAGE); | |||||
| history.push(MARKETPLACE_PAGE); | |||||
| }; | }; | ||||
| return ( | return ( | ||||
| <CheckOffersButtonContainer | <CheckOffersButtonContainer |
| } | } | ||||
| @media screen and (max-width: 600px) { | @media screen and (max-width: 600px) { | ||||
| position: absolute; | |||||
| bottom: 18px; | |||||
| /* position: absolute; */ | |||||
| /* bottom: 18px; */ | |||||
| height: 44px; | height: 44px; | ||||
| width: 339px; | width: 339px; | ||||
| /* left: 9px; */ | /* left: 9px; */ |
| import React from "react"; | import React from "react"; | ||||
| import PropTypes from "prop-types"; | import PropTypes from "prop-types"; | ||||
| import { useTranslation } from "react-i18next"; | import { useTranslation } from "react-i18next"; | ||||
| import useIsMobile from "../../../../../hooks/useIsMobile"; | |||||
| import { FieldLabel } from "../FirstPartCreateOffer.styled"; | import { FieldLabel } from "../FirstPartCreateOffer.styled"; | ||||
| import { DescriptionField } from "./OfferDescriptionField.styled"; | |||||
| import RichTextComponent from "../../../../RichTextComponent/RichTextComponent"; | import RichTextComponent from "../../../../RichTextComponent/RichTextComponent"; | ||||
| const OfferDescriptionField = (props) => { | const OfferDescriptionField = (props) => { | ||||
| const formik = props.formik; | const formik = props.formik; | ||||
| const { t } = useTranslation(); | const { t } = useTranslation(); | ||||
| const { isMobile } = useIsMobile(); | |||||
| const handleChange = (newValue) => { | |||||
| formik.setFieldValue("description", newValue); | |||||
| }; | |||||
| return ( | return ( | ||||
| <> | <> | ||||
| <FieldLabel leftText={t("offer.productDescription")} /> | <FieldLabel leftText={t("offer.productDescription")} /> | ||||
| {!isMobile ? ( | |||||
| <RichTextComponent /> | |||||
| ) : ( | |||||
| <DescriptionField | |||||
| name="description" | |||||
| placeholder={t("offer.description")} | |||||
| margin="normal" | |||||
| italicPlaceholder | |||||
| value={formik.values.description} | |||||
| onChange={formik.handleChange} | |||||
| error={formik.touched.description && formik.errors.description} | |||||
| helperText={formik.touched.description && formik.errors.description} | |||||
| fullWidth | |||||
| /> | |||||
| )} | |||||
| <RichTextComponent | |||||
| onChange={handleChange} | |||||
| value={formik.values.description} | |||||
| /> | |||||
| </> | </> | ||||
| ); | ); | ||||
| }; | }; |
| import { TextField } from "../../../../TextFields/TextField/TextField"; | import { TextField } from "../../../../TextFields/TextField/TextField"; | ||||
| export const TitleField = styled(TextField)` | export const TitleField = styled(TextField)` | ||||
| & input { | |||||
| background-color: white; | |||||
| } | |||||
| @media (max-width: 600px) { | @media (max-width: 600px) { | ||||
| margin-bottom: 0; | margin-bottom: 0; | ||||
| & div div input { | & div div input { | ||||
| height: 40px; | height: 40px; | ||||
| } | } | ||||
| } | } | ||||
| `; | |||||
| `; |
| import React from "react"; | |||||
| import PropTypes from "prop-types"; | |||||
| import { EditableContainer } from "./OfferDescription.styled"; | |||||
| import RichTextComponent from "../../../../RichTextComponent/RichTextComponent"; | |||||
| import { isJsonString } from "../../../../../util/helpers/jsonHelper"; | |||||
| import { useMemo } from "react"; | |||||
| const OfferDescription = (props) => { | |||||
| const description = useMemo( | |||||
| () => | |||||
| isJsonString(props?.value) ? ( | |||||
| <RichTextComponent itemDetails value={props?.value || ""} readOnly /> | |||||
| ) : ( | |||||
| <></> | |||||
| ), | |||||
| [props?.value] | |||||
| ); | |||||
| return <EditableContainer>{description}</EditableContainer>; | |||||
| }; | |||||
| OfferDescription.propTypes = { | |||||
| value: PropTypes.string, | |||||
| }; | |||||
| export default OfferDescription; |
| import { Box } from "@mui/material"; | |||||
| import styled from "styled-components"; | |||||
| export const EditableContainer = styled(Box)` | |||||
| font-size: 16px; | |||||
| line-height: 22px; | |||||
| white-space: pre-line; | |||||
| max-width: 100%; | |||||
| @media (max-width: 600px) { | |||||
| font-size: 14px; | |||||
| max-width: 100%; | |||||
| } | |||||
| `; |
| import PropTypes from "prop-types"; | import PropTypes from "prop-types"; | ||||
| import { | import { | ||||
| Details, | Details, | ||||
| OfferDescriptionText, | |||||
| OfferDescriptionTitle, | OfferDescriptionTitle, | ||||
| OfferImage, | OfferImage, | ||||
| OfferLittleDetails, | OfferLittleDetails, | ||||
| import { useEffect } from "react"; | import { useEffect } from "react"; | ||||
| import { useState } from "react"; | import { useState } from "react"; | ||||
| import ImagesCarousel from "../ImagesCarousel/ImagesCarousel"; | import ImagesCarousel from "../ImagesCarousel/ImagesCarousel"; | ||||
| import OfferDescription from "./OfferDescription/OfferDescription"; | |||||
| const OfferDetails = (props) => { | const OfferDetails = (props) => { | ||||
| const offer = props.offer; | const offer = props.offer; | ||||
| <OfferDescriptionTitle> | <OfferDescriptionTitle> | ||||
| {t("itemDetailsCard.description")} | {t("itemDetailsCard.description")} | ||||
| </OfferDescriptionTitle> | </OfferDescriptionTitle> | ||||
| <OfferDescriptionText showBarterButton={props.showExchangeButton}> | |||||
| {offer?.description} | |||||
| </OfferDescriptionText> | |||||
| <OfferDescription value={offer?.description} /> | |||||
| <DesciprtionPostDate previewCard={props.previewCard}> | <DesciprtionPostDate previewCard={props.previewCard}> | ||||
| {date} | {date} | ||||
| </DesciprtionPostDate> | </DesciprtionPostDate> |
| line-height: 22px; | line-height: 22px; | ||||
| white-space: pre-line; | white-space: pre-line; | ||||
| max-width: 100%; | max-width: 100%; | ||||
| /* max-width: ${(props) => | |||||
| props.showBarterButton ? "calc(100% - 230px)" : "100%"}; */ | |||||
| @media (max-width: 600px) { | @media (max-width: 600px) { | ||||
| font-size: 14px; | font-size: 14px; | ||||
| max-width: 100%; | max-width: 100%; | ||||
| } | } | ||||
| /* max-width: calc(100% - 230px); */ | |||||
| /* overflow: hidden; */ | |||||
| /* display: -webkit-box; | |||||
| -webkit-line-clamp: 5; | |||||
| -webkit-box-orient: vertical; */ | |||||
| `; | `; | ||||
| export const DesciprtionPostDate = styled(Typography)` | export const DesciprtionPostDate = styled(Typography)` | ||||
| display: none; | display: none; |
| OfferDescriptionTitle, | OfferDescriptionTitle, | ||||
| } from "./OfferDescription.styled"; | } from "./OfferDescription.styled"; | ||||
| import { useTranslation } from "react-i18next"; | import { useTranslation } from "react-i18next"; | ||||
| import RichTextComponent from "../../../RichTextComponent/RichTextComponent"; | |||||
| import { isJsonString } from "../../../../util/helpers/jsonHelper"; | |||||
| const OfferDescription = (props) => { | const OfferDescription = (props) => { | ||||
| const { t } = useTranslation(); | const { t } = useTranslation(); | ||||
| <OfferDescriptionTitle> | <OfferDescriptionTitle> | ||||
| {t("offer.descriptionLabel")} | {t("offer.descriptionLabel")} | ||||
| </OfferDescriptionTitle> | </OfferDescriptionTitle> | ||||
| <OfferDescriptionText>{props.description}</OfferDescriptionText> | |||||
| <OfferDescriptionText> | |||||
| {isJsonString(props?.description) ? ( | |||||
| <RichTextComponent readOnly offerCard value={props?.description} /> | |||||
| ) : ( | |||||
| "" | |||||
| )} | |||||
| </OfferDescriptionText> | |||||
| </OfferDescriptionContainer> | </OfferDescriptionContainer> | ||||
| ); | ); | ||||
| }; | }; |
| `; | `; | ||||
| export const Arrow = styled(ArrowButton)` | export const Arrow = styled(ArrowButton)` | ||||
| transform: rotate(-45deg); | |||||
| transform: rotate(-90deg); | |||||
| `; | `; |
| ADMIN_HOME_PAGE, | ADMIN_HOME_PAGE, | ||||
| BASE_PAGE, | BASE_PAGE, | ||||
| HOME_PAGE, | HOME_PAGE, | ||||
| MARKETPLACE_PAGE, | |||||
| } from "../../constants/pages"; | } from "../../constants/pages"; | ||||
| import { fetchMineProfile } from "../../store/actions/profile/profileActions"; | import { fetchMineProfile } from "../../store/actions/profile/profileActions"; | ||||
| import useSearch from "../../hooks/useOffers/useSearch"; | import useSearch from "../../hooks/useOffers/useSearch"; | ||||
| }, | }, | ||||
| }); | }); | ||||
| } else { | } else { | ||||
| history.push({ | |||||
| pathname: HOME_PAGE, | |||||
| state: { | |||||
| logo: true, | |||||
| }, | |||||
| }); | |||||
| if (user) { | |||||
| history.push({ | |||||
| pathname: HOME_PAGE, | |||||
| state: { | |||||
| logo: true, | |||||
| }, | |||||
| }); | |||||
| } else { | |||||
| history.push({ | |||||
| pathname: MARKETPLACE_PAGE, | |||||
| state: { | |||||
| logo: true, | |||||
| }, | |||||
| }); | |||||
| } | |||||
| if (searchRef?.current) searchRef.current.value = ""; | if (searchRef?.current) searchRef.current.value = ""; | ||||
| } | } | ||||
| }; | }; | ||||
| handleSearch={handleSearch} | handleSearch={handleSearch} | ||||
| user={user} | user={user} | ||||
| /> | /> | ||||
| {routeMatches(ABOUT_PAGE) && <AboutHeader />} | |||||
| {(routeMatches(ABOUT_PAGE) || | |||||
| (!user && | |||||
| (routeMatches(HOME_PAGE) || routeMatches(BASE_PAGE)))) && ( | |||||
| <AboutHeader /> | |||||
| )} | |||||
| {user ? ( | {user ? ( | ||||
| <ToolsButtonsContainer | <ToolsButtonsContainer | ||||
| /> | /> | ||||
| ) : ( | ) : ( | ||||
| <React.Fragment> | <React.Fragment> | ||||
| {routeMatches(ABOUT_PAGE) ? ( | |||||
| {routeMatches(ABOUT_PAGE) || | |||||
| routeMatches(HOME_PAGE) || | |||||
| routeMatches(BASE_PAGE) ? ( | |||||
| <MarketplaceLinkRouteContainer> | <MarketplaceLinkRouteContainer> | ||||
| <MarketplaceLinkRoute onClick={() => handleLogoClick()}> | <MarketplaceLinkRoute onClick={() => handleLogoClick()}> | ||||
| {t("admin.navigation.marketplace")} | {t("admin.navigation.marketplace")} |
| import { routeMatches } from "../../../util/helpers/routeHelpers"; | import { routeMatches } from "../../../util/helpers/routeHelpers"; | ||||
| import { ABOUT_PAGE, BASE_PAGE, HOME_PAGE } from "../../../constants/pages"; | import { ABOUT_PAGE, BASE_PAGE, HOME_PAGE } from "../../../constants/pages"; | ||||
| import { debounceHelper } from "../../../util/helpers/debounceHelper"; | import { debounceHelper } from "../../../util/helpers/debounceHelper"; | ||||
| import useIsLoggedIn from "../../../hooks/useIsLoggedIn"; | |||||
| const SearchInput = forwardRef((props, ref) => { | const SearchInput = forwardRef((props, ref) => { | ||||
| const { t } = useTranslation(); | const { t } = useTranslation(); | ||||
| const { isLoggedIn } = useIsLoggedIn(); | |||||
| const handleSearch = () => { | const handleSearch = () => { | ||||
| if (routeMatches(HOME_PAGE) || routeMatches(BASE_PAGE)) { | if (routeMatches(HOME_PAGE) || routeMatches(BASE_PAGE)) { | ||||
| console.log("uslo unutra") | |||||
| console.log("uslo unutra"); | |||||
| debounceHelper(() => props.handleSearch(ref.current.value), 500); | debounceHelper(() => props.handleSearch(ref.current.value), 500); | ||||
| } | } | ||||
| }; | }; | ||||
| console.log(routeMatches(HOME_PAGE)) | |||||
| console.log(routeMatches(HOME_PAGE)); | |||||
| const handleManualSearch = () => { | const handleManualSearch = () => { | ||||
| debounceHelper(() => {}, 500); | debounceHelper(() => {}, 500); | ||||
| props.handleSearch(ref.current.value); | props.handleSearch(ref.current.value); | ||||
| const handleBlurSearch = () => { | const handleBlurSearch = () => { | ||||
| ref.current.removeEventListener("keyup", listener); | ref.current.removeEventListener("keyup", listener); | ||||
| }; | }; | ||||
| if (routeMatches(ABOUT_PAGE)) { | |||||
| if ( | |||||
| routeMatches(ABOUT_PAGE) || | |||||
| (!isLoggedIn && (routeMatches(HOME_PAGE) || routeMatches(BASE_PAGE))) | |||||
| ) { | |||||
| return <></>; | return <></>; | ||||
| } | } | ||||
| return ( | return ( |
| import React from "react"; | |||||
| import PropTypes from "prop-types"; | |||||
| import { | |||||
| ColorPickerContainer, | |||||
| ColorPickerLabel, | |||||
| ColorPickerName, | |||||
| ColorPickerNameContainer, | |||||
| ColorsContainer, | |||||
| } from "./ColorPicker.styled"; | |||||
| import { useTranslation } from "react-i18next"; | |||||
| import selectedTheme from "../../../themes"; | |||||
| import ColorIcon from "../../RichTextComponent/ColorIcon/ColorIcon"; | |||||
| const ColorPicker = (props) => { | |||||
| const { t } = useTranslation(); | |||||
| const handleClickColor = (singleColor) => { | |||||
| props?.handleClickColor({ | |||||
| color: selectedTheme.colors.colorPicker[singleColor], | |||||
| colorName: singleColor, | |||||
| }); | |||||
| }; | |||||
| return ( | |||||
| <ColorPickerContainer> | |||||
| <ColorPickerNameContainer> | |||||
| <ColorPickerLabel>{t("colorPicker.label")}</ColorPickerLabel> | |||||
| <ColorPickerName> | |||||
| {t(`colorPicker.${props.selectedColorName}`)} | |||||
| </ColorPickerName> | |||||
| </ColorPickerNameContainer> | |||||
| <ColorsContainer> | |||||
| {Object.keys(selectedTheme.colors.colorPicker).map((singleColor) => { | |||||
| if (singleColor === "border") return; | |||||
| return ( | |||||
| <ColorIcon | |||||
| selected={singleColor === props?.selectedColorName} | |||||
| selectedInPopover={singleColor === props?.selectedColorName} | |||||
| color={selectedTheme.colors.colorPicker[singleColor]} | |||||
| key={singleColor} | |||||
| onClick={() => handleClickColor(singleColor)} | |||||
| /> | |||||
| ); | |||||
| })} | |||||
| </ColorsContainer> | |||||
| </ColorPickerContainer> | |||||
| ); | |||||
| }; | |||||
| ColorPicker.propTypes = { | |||||
| selectedColorName: PropTypes.string, | |||||
| selectedColor: PropTypes.string, | |||||
| handleClickColor: PropTypes.func, | |||||
| }; | |||||
| export default ColorPicker; |
| import { Box, Typography } from "@mui/material"; | |||||
| import styled from "styled-components"; | |||||
| import selectedTheme from "../../../themes"; | |||||
| export const ColorPickerContainer = styled(Box)` | |||||
| padding: 9px 18px; | |||||
| isolation: isolate; | |||||
| width: 178px; | |||||
| height: 74px; | |||||
| background: white; | |||||
| box-shadow: 4px 4px 9px rgba(0, 0, 0, 0.12); | |||||
| border-radius: 4px; | |||||
| display: flex; | |||||
| flex-direction: column; | |||||
| gap: 9px; | |||||
| z-index: 1000; | |||||
| `; | |||||
| export const ColorPickerNameContainer = styled(Box)` | |||||
| display: flex; | |||||
| flex-direction: row; | |||||
| gap: 3px; | |||||
| align-items: flex-end; | |||||
| `; | |||||
| export const ColorPickerLabel = styled(Typography)` | |||||
| color: ${selectedTheme.colors.primaryTextDisabled}; | |||||
| font-family: ${selectedTheme.fonts.textFont}; | |||||
| font-size: 12px; | |||||
| line-height: 15.5px; | |||||
| letter-spacing: 1px; | |||||
| `; | |||||
| export const ColorPickerName = styled(Typography)` | |||||
| color: ${selectedTheme.colors.primaryText}; | |||||
| font-family: ${selectedTheme.fonts.textFont}; | |||||
| font-size: 16px; | |||||
| line-height: 18.5px; | |||||
| `; | |||||
| export const ColorsContainer = styled(Box)` | |||||
| display: flex; | |||||
| flex-direction: row; | |||||
| gap: 14px; | |||||
| padding: 4px; | |||||
| align-items: flex-end; | |||||
| `; |
| import { useSlate } from "slate-react"; | import { useSlate } from "slate-react"; | ||||
| import { Editor, Transforms, Element as SlateElement } from "slate"; | import { Editor, Transforms, Element as SlateElement } from "slate"; | ||||
| import { BlockButtonContainer, BlockButtonIcon } from "./BlockButton.styled"; | import { BlockButtonContainer, BlockButtonIcon } from "./BlockButton.styled"; | ||||
| const LIST_TYPES = ["numbered-list", "bulleted-list"]; | |||||
| const LIST_TYPES = ["numbered-list", "bulleted-list", "link"]; | |||||
| const TEXT_ALIGN_TYPES = ["left", "center", "right", "justify"]; | const TEXT_ALIGN_TYPES = ["left", "center", "right", "justify"]; | ||||
| const BlockButton = ({ format, icon }) => { | const BlockButton = ({ format, icon }) => { | ||||
| const editor = useSlate(); | const editor = useSlate(); |
| import PropTypes from "prop-types"; | import PropTypes from "prop-types"; | ||||
| import { useSlate } from "slate-react"; | import { useSlate } from "slate-react"; | ||||
| import { Editor } from "slate"; | import { Editor } from "slate"; | ||||
| import { MarkButtonContainer, MarkButtonIcon } from "../MarkButton/MarkButton.styled"; | |||||
| import { ColorButtonContainer, ColorButtonIcon } from "./ColorButton.styled"; | |||||
| import { useState } from "react"; | |||||
| import ColorIcon from "../ColorIcon/ColorIcon"; | |||||
| import ColorPicker from "../../Popovers/ColorPicker/ColorPicker"; | |||||
| const toggleMark = (editor, format) => { | |||||
| const isActive = isMarkActive(editor, format); | |||||
| // const colorMarks = ["darkGray", "gray", "purple", "pink", "yellow"]; | |||||
| if (isActive) { | |||||
| Editor.removeMark(editor, format); | |||||
| } else { | |||||
| Editor.addMark(editor, format, true); | |||||
| } | |||||
| const toggleMark = (editor, format, newColor) => { | |||||
| Editor.addMark(editor, format, newColor); | |||||
| }; | }; | ||||
| const isMarkActive = (editor, format) => { | |||||
| const marks = Editor.marks(editor); | |||||
| return marks ? marks[format] === true : false; | |||||
| }; | |||||
| // const isMarkActive = (editor, format) => { | |||||
| // const marks = Editor.marks(editor); | |||||
| // return marks ? marks[format] === true : false; | |||||
| // }; | |||||
| const ColorButton = ({ format, icon }) => { | |||||
| const ColorButton = (props) => { | |||||
| const editor = useSlate(); | const editor = useSlate(); | ||||
| const [isColorPickerPopoverShowing, setIsColorPickerPopoverShowing] = | |||||
| useState(false); | |||||
| const callbackFunction = (newColor) => { | |||||
| setIsColorPickerPopoverShowing(false); | |||||
| props?.setSelectedColor(newColor); | |||||
| toggleMark(editor, "color", newColor.color); | |||||
| }; | |||||
| console.log(); | |||||
| return ( | return ( | ||||
| <MarkButtonContainer | |||||
| active={isMarkActive(editor, format)} | |||||
| format={format} | |||||
| onMouseDown={(event) => { | |||||
| event.preventDefault(); | |||||
| toggleMark(editor, format); | |||||
| }} | |||||
| > | |||||
| <MarkButtonIcon format={format} active={isMarkActive(editor, format)}> | |||||
| {icon} | |||||
| </MarkButtonIcon> | |||||
| </MarkButtonContainer> | |||||
| <> | |||||
| <ColorButtonContainer | |||||
| format={props?.format} | |||||
| onMouseDown={() => setIsColorPickerPopoverShowing(true)} | |||||
| > | |||||
| <ColorButtonIcon format={props?.format}> | |||||
| <ColorIcon selected color={props?.selectedColor.color} /> | |||||
| </ColorButtonIcon> | |||||
| </ColorButtonContainer> | |||||
| {isColorPickerPopoverShowing && ( | |||||
| <ColorPicker | |||||
| selectedColor={props?.selectedColor.color} | |||||
| selectedColorName={props?.selectedColor.colorName} | |||||
| handleClickColor={callbackFunction} | |||||
| /> | |||||
| )} | |||||
| </> | |||||
| ); | ); | ||||
| }; | }; | ||||
| ColorButton.propTypes = { | ColorButton.propTypes = { | ||||
| format: PropTypes.any, | format: PropTypes.any, | ||||
| icon: PropTypes.any, | icon: PropTypes.any, | ||||
| selectedColor: PropTypes.any, | |||||
| setSelectedColor: PropTypes.func, | |||||
| }; | }; | ||||
| export default ColorButton; | export default ColorButton; |
| import { Box } from "@mui/material"; | |||||
| import styled, { css } from "styled-components"; | |||||
| import selectedTheme from "../../../themes"; | |||||
| export const ColorButtonContainer = styled(Box)` | |||||
| display: inline; | |||||
| cursor: pointer; | |||||
| position: relative; | |||||
| top: 2px; | |||||
| `; | |||||
| export const ColorButtonIcon = styled(Box)` | |||||
| font-size: 16px; | |||||
| font-family: "Source Code Pro"; | |||||
| ${(props) => | |||||
| props.format === "bold" | |||||
| ? `font-weight: bold;` | |||||
| : props.format === "italic" | |||||
| ? "font-style: italic;" | |||||
| : props.format === "underline" | |||||
| ? `text-decoration: underline;` | |||||
| : ""} | |||||
| color: ${selectedTheme.colors.primaryGrayText}; | |||||
| line-height: 20px; | |||||
| ${(props) => | |||||
| props.active && | |||||
| css` | |||||
| color: ${selectedTheme.colors.primaryText}; | |||||
| `} | |||||
| `; |
| import React from "react"; | |||||
| import PropTypes from "prop-types"; | |||||
| import { ColorIconContainer } from "./ColorIcon.styled"; | |||||
| const ColorIcon = (props) => { | |||||
| return ( | |||||
| <ColorIconContainer | |||||
| selected={props?.selected} | |||||
| backgroundColor={props?.color} | |||||
| aboveEditor={props?.aboveEditor} | |||||
| selectedInPopover={props?.selectedInPopover} | |||||
| onClick={props?.onClick} | |||||
| /> | |||||
| ); | |||||
| }; | |||||
| ColorIcon.propTypes = { | |||||
| children: PropTypes.node, | |||||
| color: PropTypes.string, | |||||
| selected: PropTypes.bool, | |||||
| aboveEditor: PropTypes.bool, | |||||
| selectedInPopover: PropTypes.bool, | |||||
| onClick: PropTypes.func, | |||||
| }; | |||||
| export default ColorIcon; |
| import { Box } from "@mui/material"; | |||||
| import styled from "styled-components"; | |||||
| import selectedTheme from "../../../themes"; | |||||
| export const ColorIconContainer = styled(Box)` | |||||
| cursor: pointer; | |||||
| width: ${(props) => | |||||
| props.aboveEditor ? "13.5px" : props.selectedInPopover ? "17px" : "15px"}; | |||||
| height: ${(props) => | |||||
| props.aboveEditor ? "13.5px" : props.selectedInPopover ? "17px" : "15px"}; | |||||
| background-color: ${(props) => props.backgroundColor}; | |||||
| border: 1.24px solid | |||||
| ${(props) => | |||||
| props.selected ? selectedTheme.colors.colorPicker.border : "transparent"}; | |||||
| `; |
| import React, { useCallback, useMemo } from "react"; | import React, { useCallback, useMemo } from "react"; | ||||
| import { Editable, withReact, Slate } from "slate-react"; | import { Editable, withReact, Slate } from "slate-react"; | ||||
| import { createEditor } from "slate"; | import { createEditor } from "slate"; | ||||
| import PropTypes from "prop-types"; | |||||
| import RichTextElement from "./RichTextElement/RichTextElement"; | import RichTextElement from "./RichTextElement/RichTextElement"; | ||||
| import MarkButton from "./MarkButton/MarkButton"; | import MarkButton from "./MarkButton/MarkButton"; | ||||
| import BlockButton from "./BlockButton/BlockButton"; | import BlockButton from "./BlockButton/BlockButton"; | ||||
| import ColorButton from "./ColorButton/ColorButton"; | import ColorButton from "./ColorButton/ColorButton"; | ||||
| import selectedTheme from "../../themes"; | import selectedTheme from "../../themes"; | ||||
| import useIsMobile from "../../hooks/useIsMobile"; | |||||
| import { useTranslation } from "react-i18next"; | |||||
| import { isJsonString } from "../../util/helpers/jsonHelper"; | |||||
| import { useEffect } from "react"; | |||||
| const COLORS = [ | |||||
| { | |||||
| const RichTextComponent = (props) => { | |||||
| const { isMobile } = useIsMobile(); | |||||
| const { t } = useTranslation(); | |||||
| const [selectedColor, setSelectedColor] = useState({ | |||||
| color: selectedTheme.colors.colorPicker.darkGray, | color: selectedTheme.colors.colorPicker.darkGray, | ||||
| i18key: "colorPicker.darkGray", | |||||
| }, | |||||
| { | |||||
| color: selectedTheme.colors.colorPicker.gray, | |||||
| i18key: "colorPicker.gray", | |||||
| }, | |||||
| { | |||||
| color: selectedTheme.colors.colorPicker.yellow, | |||||
| i18key: "colorPicker.yellow", | |||||
| }, | |||||
| { | |||||
| color: selectedTheme.colors.colorPicker.purple, | |||||
| i18key: "colorPicker.purple", | |||||
| }, | |||||
| { | |||||
| color: selectedTheme.colors.colorPicker.pink, | |||||
| i18key: "colorPicker.pink", | |||||
| }, | |||||
| ]; | |||||
| const RichTextComponent = () => { | |||||
| const [color, setColor] = useState(COLORS[0]); | |||||
| colorName: "darkGray", | |||||
| }); | |||||
| const [value, setValue] = useState([ | const [value, setValue] = useState([ | ||||
| { | { | ||||
| type: "paragraph", | type: "paragraph", | ||||
| children: [{ text: "" }], | children: [{ text: "" }], | ||||
| }, | }, | ||||
| ]); | ]); | ||||
| useEffect(() => { | |||||
| setValue(props?.value); | |||||
| editor.children = isJsonString(props?.value) | |||||
| ? JSON.parse(props?.value) | |||||
| : value; | |||||
| }, [props?.value]); | |||||
| const renderElement = useCallback( | const renderElement = useCallback( | ||||
| (props) => <RichTextElement {...props} />, | (props) => <RichTextElement {...props} />, | ||||
| [] | [] | ||||
| ); | ); | ||||
| const renderLeaf = useCallback((props) => <RichTextLeaf {...props} />, []); | const renderLeaf = useCallback((props) => <RichTextLeaf {...props} />, []); | ||||
| const editor = useMemo(() => withReact(createEditor()), []); | |||||
| const editor = useMemo(() => withReact(createEditor()), [props?.value]); | |||||
| return ( | return ( | ||||
| <RichTextComponentContainer> | |||||
| <RichTextComponentContainer | |||||
| offerCard={props?.offerCard} | |||||
| readOnly={props?.readOnly} | |||||
| itemDetails={props?.itemDetails} | |||||
| > | |||||
| <Slate | <Slate | ||||
| editor={editor} | editor={editor} | ||||
| value={value} | |||||
| value={isJsonString(props?.value) ? JSON.parse(props?.value) : value} | |||||
| onChange={(newValue) => { | onChange={(newValue) => { | ||||
| console.log(newValue); | |||||
| setValue(newValue); | |||||
| if (props?.onChange) props?.onChange(JSON.stringify(newValue)); | |||||
| else setValue(newValue); | |||||
| }} | }} | ||||
| > | > | ||||
| <SlateButtonsContainer> | |||||
| <MarkButton format="bold" icon="B" /> | |||||
| <MarkButton format="italic" icon="I" /> | |||||
| <MarkButton format="underline" icon="U" /> | |||||
| <BlockButton format="bulleted-list" icon={<BulletedList />} /> | |||||
| <ColorButton | |||||
| format="color" | |||||
| currentColor={color} | |||||
| setCurrentColor={setColor} | |||||
| colorValues={COLORS} | |||||
| /> | |||||
| </SlateButtonsContainer> | |||||
| <EditableContainer> | |||||
| <EditableInnerContainer> | |||||
| {!isMobile && ( | |||||
| <SlateButtonsContainer readOnly={props?.readOnly}> | |||||
| <MarkButton format="bold" icon="B" /> | |||||
| <MarkButton format="italic" icon="I" /> | |||||
| <MarkButton format="underline" icon="U" /> | |||||
| <BlockButton format="bulleted-list" icon={<BulletedList />} /> | |||||
| <ColorButton | |||||
| selectedColor={selectedColor} | |||||
| setSelectedColor={setSelectedColor} | |||||
| /> | |||||
| </SlateButtonsContainer> | |||||
| )} | |||||
| <EditableContainer | |||||
| offerCard={props?.offerCard} | |||||
| itemDetails={props?.itemDetails} | |||||
| > | |||||
| <EditableInnerContainer readOnly={props?.readOnly}> | |||||
| <Editable | <Editable | ||||
| placeholder={t("offer.description")} | |||||
| renderElement={renderElement} | renderElement={renderElement} | ||||
| renderLeaf={renderLeaf} | renderLeaf={renderLeaf} | ||||
| spellCheck | spellCheck | ||||
| autoFocus | autoFocus | ||||
| readOnly={props?.readOnly} | |||||
| /> | /> | ||||
| </EditableInnerContainer> | </EditableInnerContainer> | ||||
| </EditableContainer> | </EditableContainer> | ||||
| // children: [{ text: "" }], | // children: [{ text: "" }], | ||||
| // }, | // }, | ||||
| // ]; | // ]; | ||||
| RichTextComponent.propTypes = { | |||||
| children: PropTypes.node, | |||||
| onChange: PropTypes.func, | |||||
| value: PropTypes.any, | |||||
| readOnly: PropTypes.bool, | |||||
| offerCard: PropTypes.bool, | |||||
| itemDetails: PropTypes.bool, | |||||
| }; | |||||
| export default RichTextComponent; | export default RichTextComponent; |
| import { Box } from "@mui/material"; | import { Box } from "@mui/material"; | ||||
| import styled from "styled-components"; | |||||
| import styled, { css } from "styled-components"; | |||||
| import selectedTheme from "../../themes"; | import selectedTheme from "../../themes"; | ||||
| export const SlateButtonsContainer = styled(Box)` | export const SlateButtonsContainer = styled(Box)` | ||||
| display: flex; | |||||
| display: ${(props) => (props.readOnly ? "none" : "flex")}; | |||||
| flex-direction: row; | flex-direction: row; | ||||
| height: 36px; | height: 36px; | ||||
| background-color: ${selectedTheme.colors.stylingTextBackground}; | background-color: ${selectedTheme.colors.stylingTextBackground}; | ||||
| width: 100%; | width: 100%; | ||||
| position: relative; | position: relative; | ||||
| top: 14px; | top: 14px; | ||||
| height: 140px; | |||||
| border: 1px solid ${selectedTheme.colors.borderNormal}; | |||||
| height: ${(props) => | |||||
| props?.offerCard || props?.itemDetails ? "auto" : "140px"}; | |||||
| ${(props) => | |||||
| props?.offerCard && | |||||
| css` | |||||
| max-height: 100px; | |||||
| display: -webkit-box; | |||||
| -webkit-line-clamp: 4; | |||||
| -webkit-box-orient: vertical; | |||||
| `} | |||||
| border-radius: 4px; | |||||
| border: ${(props) => | |||||
| props.readOnly ? "0" : `1px solid ${selectedTheme.colors.borderNormal}`}; | |||||
| margin-bottom: 14px; | margin-bottom: 14px; | ||||
| @media (max-width: 600px) { | |||||
| /* height: 40px; */ | |||||
| height: auto; | |||||
| } | |||||
| `; | `; | ||||
| export const EditableContainer = styled(Box)` | export const EditableContainer = styled(Box)` | ||||
| max-height: 104px; | |||||
| overflow: auto; | |||||
| ${(props) => !props?.itemDetails && "max-height: 104px;"} | |||||
| ${(props) => !props?.offerCard && "overflow: auto;"} | |||||
| &::-webkit-scrollbar { | &::-webkit-scrollbar { | ||||
| width: 5px; | width: 5px; | ||||
| height: 5px; | height: 5px; | ||||
| } | } | ||||
| scrollbar-width: thin; | scrollbar-width: thin; | ||||
| scrollbar-color: #ddd; | scrollbar-color: #ddd; | ||||
| @media (max-width: 600px) { | |||||
| /* max-height: 39px; */ | |||||
| } | |||||
| `; | `; | ||||
| export const EditableInnerContainer = styled(Box)` | export const EditableInnerContainer = styled(Box)` | ||||
| padding: 10px 16px; | |||||
| padding: ${(props) => (props?.readOnly ? "0" : "10px 16px")}; | |||||
| & > div { | & > div { | ||||
| min-height: 84px; | min-height: 84px; | ||||
| } | } | ||||
| & * { | & * { | ||||
| font-family: ${selectedTheme.fonts.textFont}; | font-family: ${selectedTheme.fonts.textFont}; | ||||
| } | } | ||||
| & span[data-slate-placeholder="true"] { | |||||
| font-style: italic; | |||||
| color: ${selectedTheme.colors.colorPicker.darkGray}; | |||||
| } | |||||
| @media (max-width: 600px) { | |||||
| & > div { | |||||
| min-height: 0; | |||||
| } | |||||
| & * { | |||||
| font-size: 12px; | |||||
| } | |||||
| } | |||||
| `; | `; |
| import React from "react"; | import React from "react"; | ||||
| import PropTypes from "prop-types"; | import PropTypes from "prop-types"; | ||||
| import { ListContainer } from "./RichTextElement.styled"; | import { ListContainer } from "./RichTextElement.styled"; | ||||
| import selectedTheme from "../../../themes"; | |||||
| const RichTextElement = ({ attributes, children, element }) => { | const RichTextElement = ({ attributes, children, element }) => { | ||||
| const style = { textAlign: element.align }; | const style = { textAlign: element.align }; | ||||
| {children} | {children} | ||||
| </ListContainer> | </ListContainer> | ||||
| ); | ); | ||||
| case "link": | |||||
| return ( | |||||
| <a href="" style={style} {...attributes}> | |||||
| {children} | |||||
| </a> | |||||
| ); | |||||
| case "heading-one": | case "heading-one": | ||||
| return ( | return ( | ||||
| <h1 style={style} {...attributes}> | <h1 style={style} {...attributes}> | ||||
| ); | ); | ||||
| default: | default: | ||||
| return ( | return ( | ||||
| <div style={style} {...attributes}> | |||||
| <div | |||||
| style={style} | |||||
| {...attributes} | |||||
| color={selectedTheme.colors.colorPicker.darkGray} | |||||
| > | |||||
| {children} | {children} | ||||
| </div> | </div> | ||||
| ); | ); |
| import styled from "styled-components"; | import styled from "styled-components"; | ||||
| export const ListContainer = styled(Box)` | export const ListContainer = styled(Box)` | ||||
| padding-left: | |||||
| & > div { | |||||
| display: list-item; | |||||
| } | |||||
| ` | |||||
| color: green; | |||||
| padding-left: 18px; | |||||
| & > div { | |||||
| display: list-item; | |||||
| } | |||||
| `; |
| if (leaf.underline) { | if (leaf.underline) { | ||||
| children = <u>{children}</u>; | children = <u>{children}</u>; | ||||
| } | } | ||||
| if (leaf.color) { | |||||
| children = <span style={{ color: leaf.color }}>{children}</span>; | |||||
| } | |||||
| return <span {...attributes}>{children}</span>; | return <span {...attributes}>{children}</span>; | ||||
| }; | }; | ||||
| attributes: PropTypes.any, | attributes: PropTypes.any, | ||||
| children: PropTypes.any, | children: PropTypes.any, | ||||
| leaf: PropTypes.any, | leaf: PropTypes.any, | ||||
| selectedColor: PropTypes.any, | |||||
| }; | }; | ||||
| export default RichTextLeaf; | export default RichTextLeaf; |
| export const ADMIN_LOCATIONS_PAGE = "/admin/locations"; | export const ADMIN_LOCATIONS_PAGE = "/admin/locations"; | ||||
| export const ADMIN_PAYMENT_PAGE = "/admin/payment"; | export const ADMIN_PAYMENT_PAGE = "/admin/payment"; | ||||
| export const ADMIN_SUBCATEGORIES_PAGE = "/admin/categories/:categoryId"; | export const ADMIN_SUBCATEGORIES_PAGE = "/admin/categories/:categoryId"; | ||||
| export const MARKETPLACE_PAGE = "/marketplace"; |
| import { useSelector } from "react-redux"; | |||||
| import { selectUserId } from "../store/selectors/loginSelectors"; | |||||
| const useIsLoggedIn = () => { | |||||
| const userId = useSelector(selectUserId); | |||||
| const isLoggedIn = userId ? true : false; | |||||
| return { | |||||
| isLoggedIn | |||||
| } | |||||
| }; | |||||
| export default useIsLoggedIn; |
| nextPage: "Next page", | nextPage: "Next page", | ||||
| }, | }, | ||||
| colorPicker: { | colorPicker: { | ||||
| label: "Boja: ", | |||||
| darkGray: "Tamno Siva", | darkGray: "Tamno Siva", | ||||
| gray: "Siva", | gray: "Siva", | ||||
| yellow: "Žuta", | yellow: "Žuta", |
| import React, { useEffect, useRef } from "react"; | |||||
| import React from "react"; | |||||
| import PropTypes from "prop-types"; | 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"; | |||||
| import AboutPageContent from "../../components/About/AboutPageContent"; | |||||
| const AboutPage = () => { | 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 = {}; | |||||
| } | |||||
| }, [location]); | |||||
| useEffect(() => { | |||||
| const listener = () => { | |||||
| if ( | |||||
| window.scrollY > | |||||
| pricesRef.current.offsetTop - window.innerHeight / 2 | |||||
| ) { | |||||
| 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 ref={aboutRef} id={scrollConstants.about.aboutPage} /> | |||||
| <PricesComponent ref={pricesRef} id={scrollConstants.about.pricesPage} /> | |||||
| <PrivacyPolicyComponent | |||||
| ref={privacyPolicyRef} | |||||
| id={scrollConstants.about.privacyPolicyPage} | |||||
| /> | |||||
| <AboutFooter /> | |||||
| </AboutPageContainer> | |||||
| ); | |||||
| return <AboutPageContent /> | |||||
| }; | }; | ||||
| AboutPage.propTypes = { | AboutPage.propTypes = { |
| import { Box } from "@mui/system"; | |||||
| import styled from "styled-components"; | |||||
| import selectedTheme from "../../themes"; | |||||
| export const AboutPageContainer = styled(Box)` | |||||
| margin-top: 64px; | |||||
| background-color: ${selectedTheme.colors.staticBackgroundColor}; | |||||
| position: relative; | |||||
| @media (max-width: 600px) { | |||||
| margin-top: 53px; | |||||
| } | |||||
| ` |
| import React, { useState } from "react"; | import React, { useState } from "react"; | ||||
| import PropTypes from "prop-types"; | |||||
| import { HomePageContainer } from "./HomePage.styled"; | import { HomePageContainer } from "./HomePage.styled"; | ||||
| import FilterCard from "../../components/Cards/FilterCard/FilterCard"; | import FilterCard from "../../components/Cards/FilterCard/FilterCard"; | ||||
| import MainLayout from "../../layouts/MainLayout/MainLayout"; | import MainLayout from "../../layouts/MainLayout/MainLayout"; | ||||
| import { useSelector } from "react-redux"; | import { useSelector } from "react-redux"; | ||||
| import { OFFERS_SCOPE } from "../../store/actions/offers/offersActionConstants"; | import { OFFERS_SCOPE } from "../../store/actions/offers/offersActionConstants"; | ||||
| import useOffers from "../../hooks/useOffers/useOffers"; | import useOffers from "../../hooks/useOffers/useOffers"; | ||||
| import useIsLoggedIn from "../../hooks/useIsLoggedIn"; | |||||
| import AboutPageContent from "../../components/About/AboutPageContent"; | |||||
| const HomePage = () => { | |||||
| const HomePage = (props) => { | |||||
| const { isLoggedIn } = useIsLoggedIn(); | |||||
| const isLoadingOffers = useSelector( | const isLoadingOffers = useSelector( | ||||
| selectIsLoadingByActionType(OFFERS_SCOPE) | selectIsLoadingByActionType(OFFERS_SCOPE) | ||||
| ); | ); | ||||
| const toggleFilters = () => { | const toggleFilters = () => { | ||||
| setFiltersOpened((prevFiltersOpened) => !prevFiltersOpened); | setFiltersOpened((prevFiltersOpened) => !prevFiltersOpened); | ||||
| }; | }; | ||||
| return ( | |||||
| <HomePageContainer> | |||||
| <MainLayout | |||||
| leftCard={ | |||||
| <FilterCard | |||||
| offers={offers} | |||||
| filtersOpened={filtersOpened} | |||||
| skeleton={isLoadingOffers} | |||||
| toggleFilters={toggleFilters} | |||||
| /> | |||||
| } | |||||
| content={ | |||||
| <MarketPlace | |||||
| offers={offers} | |||||
| skeleton={isLoadingOffers} | |||||
| toggleFilters={toggleFilters} | |||||
| /> | |||||
| } | |||||
| /> | |||||
| </HomePageContainer> | |||||
| ); | |||||
| if (isLoggedIn || props?.isMarketplacePage) { | |||||
| return ( | |||||
| <HomePageContainer> | |||||
| <MainLayout | |||||
| leftCard={ | |||||
| <FilterCard | |||||
| offers={offers} | |||||
| filtersOpened={filtersOpened} | |||||
| skeleton={isLoadingOffers} | |||||
| toggleFilters={toggleFilters} | |||||
| /> | |||||
| } | |||||
| content={ | |||||
| <MarketPlace | |||||
| offers={offers} | |||||
| skeleton={isLoadingOffers} | |||||
| toggleFilters={toggleFilters} | |||||
| /> | |||||
| } | |||||
| /> | |||||
| </HomePageContainer> | |||||
| ); | |||||
| } | |||||
| return <AboutPageContent />; | |||||
| }; | |||||
| HomePage.propTypes = { | |||||
| isMarketplacePage: PropTypes.bool, | |||||
| }; | }; | ||||
| export default HomePage; | export default HomePage; |
| import React from "react"; | |||||
| import HomePage from "../HomePage/HomePage"; | |||||
| const MarketplacePage = () => { | |||||
| return <HomePage isMarketplacePage />; | |||||
| }; | |||||
| export default MarketplacePage; |
| pinOfferSuccess, | pinOfferSuccess, | ||||
| pinOfferError, | pinOfferError, | ||||
| addProfileOffers, | addProfileOffers, | ||||
| clearSelectedOffer, | |||||
| // fetchAllOffersSuccess, | // fetchAllOffersSuccess, | ||||
| // fetchAllOffersError, | // fetchAllOffersError, | ||||
| // setFeaturedOfferPage, | // setFeaturedOfferPage, | ||||
| queryObject, | queryObject, | ||||
| }); | }); | ||||
| if (!data?.data) throw new Error(); | if (!data?.data) throw new Error(); | ||||
| yield put(clearSelectedOffer()); | |||||
| yield put(fetchOneOfferSuccess(data?.data)); | yield put(fetchOneOfferSuccess(data?.data)); | ||||
| } catch (e) { | } catch (e) { | ||||
| console.log(e?.response?.status); | console.log(e?.response?.status); | ||||
| } else { | } else { | ||||
| queryString = yield select(selectQueryString); | queryString = yield select(selectQueryString); | ||||
| } | } | ||||
| console.log(queryString.toString()); | console.log(queryString.toString()); | ||||
| let data; | let data; | ||||
| if (payload.payload.isAdmin) { | if (payload.payload.isAdmin) { |
| export const isJsonString = (stringToCheck) => { | |||||
| try { | |||||
| JSON.parse(stringToCheck); | |||||
| } catch (e) { | |||||
| return false; | |||||
| } | |||||
| return true; | |||||
| }; |