| @@ -20,6 +20,7 @@ import { | |||
| ADMIN_HOME_PAGE, | |||
| MESSAGES_LIST_PAGE, | |||
| DIRECT_CHAT_PAGE, | |||
| MARKETPLACE_PAGE, | |||
| } from "./constants/pages"; | |||
| import LoginPage from "./pages/LoginPage/LoginPage"; | |||
| import AdminLoginPage from "./pages/AdminLoginPage/AdminLoginPage"; | |||
| @@ -42,6 +43,7 @@ import AboutPage from "./pages/About/AboutPage"; | |||
| import AuthRoute from "./components/Router/AuthRoute"; | |||
| import AdminRoute from "./components/Router/AdminRoute"; | |||
| import AdminHomePage from "./pages/AdminHomePage/AdminHomePage"; | |||
| import MarketplacePage from "./pages/Marketplace/MarketplacePage"; | |||
| const AppRoutes = () => { | |||
| return ( | |||
| @@ -54,12 +56,17 @@ const AppRoutes = () => { | |||
| <AuthRoute path={FORGOT_PASSWORD_PAGE} component={ForgotPasswordPage} /> | |||
| <AuthRoute path={RESET_PASSWORD_PAGE} component={ResetPasswordPage} /> | |||
| <Route path={REGISTER_SUCCESSFUL_PAGE} component={RegisterSuccessful} /> | |||
| <Route path={MARKETPLACE_PAGE} component={MarketplacePage} /> | |||
| <Route path={CREATE_OFFER_PAGE} component={CreateOffer} /> | |||
| <Route path={ITEM_DETAILS_PAGE} component={ItemDetailsPage} /> | |||
| <Route path={PROFILE_PAGE} component={ProfilePage} /> | |||
| <Route path={ABOUT_PAGE} component={AboutPage} /> | |||
| <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={MY_OFFERS_PAGE} component={MyOffers} /> | |||
| <AdminRoute path={ADMIN_HOME_PAGE} component={AdminHomePage} /> | |||
| @@ -0,0 +1,95 @@ | |||
| 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; | |||
| @@ -0,0 +1,12 @@ | |||
| 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; | |||
| } | |||
| ` | |||
| @@ -3,13 +3,13 @@ import PropTypes from "prop-types"; | |||
| import { CheckOffersButtonContainer } from "./CheckOffersButton.styled"; | |||
| import selectedTheme from "../../../themes"; | |||
| import { useTranslation } from "react-i18next"; | |||
| import { HOME_PAGE } from "../../../constants/pages"; | |||
| import { MARKETPLACE_PAGE } from "../../../constants/pages"; | |||
| import history from "../../../store/utils/history"; | |||
| const CheckOffersButton = () => { | |||
| const { t } = useTranslation(); | |||
| const handleClick = () => { | |||
| history.push(HOME_PAGE); | |||
| history.push(MARKETPLACE_PAGE); | |||
| }; | |||
| return ( | |||
| <CheckOffersButtonContainer | |||
| @@ -231,8 +231,8 @@ export const NextButtonContainer = styled(PrimaryButton)` | |||
| } | |||
| @media screen and (max-width: 600px) { | |||
| position: absolute; | |||
| bottom: 18px; | |||
| /* position: absolute; */ | |||
| /* bottom: 18px; */ | |||
| height: 44px; | |||
| width: 339px; | |||
| /* left: 9px; */ | |||
| @@ -1,33 +1,22 @@ | |||
| import React from "react"; | |||
| import PropTypes from "prop-types"; | |||
| import { useTranslation } from "react-i18next"; | |||
| import useIsMobile from "../../../../../hooks/useIsMobile"; | |||
| import { FieldLabel } from "../FirstPartCreateOffer.styled"; | |||
| import { DescriptionField } from "./OfferDescriptionField.styled"; | |||
| import RichTextComponent from "../../../../RichTextComponent/RichTextComponent"; | |||
| const OfferDescriptionField = (props) => { | |||
| const formik = props.formik; | |||
| const { t } = useTranslation(); | |||
| const { isMobile } = useIsMobile(); | |||
| const handleChange = (newValue) => { | |||
| formik.setFieldValue("description", newValue); | |||
| }; | |||
| return ( | |||
| <> | |||
| <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} | |||
| /> | |||
| </> | |||
| ); | |||
| }; | |||
| @@ -2,6 +2,9 @@ import styled from "styled-components"; | |||
| import { TextField } from "../../../../TextFields/TextField/TextField"; | |||
| export const TitleField = styled(TextField)` | |||
| & input { | |||
| background-color: white; | |||
| } | |||
| @media (max-width: 600px) { | |||
| margin-bottom: 0; | |||
| & div div input { | |||
| @@ -11,4 +14,4 @@ export const TitleField = styled(TextField)` | |||
| height: 40px; | |||
| } | |||
| } | |||
| `; | |||
| `; | |||
| @@ -0,0 +1,25 @@ | |||
| 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; | |||
| @@ -0,0 +1,13 @@ | |||
| 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%; | |||
| } | |||
| `; | |||
| @@ -2,7 +2,6 @@ import React from "react"; | |||
| import PropTypes from "prop-types"; | |||
| import { | |||
| Details, | |||
| OfferDescriptionText, | |||
| OfferDescriptionTitle, | |||
| OfferImage, | |||
| OfferLittleDetails, | |||
| @@ -19,6 +18,7 @@ import { getImageUrl, variants } from "../../../../util/helpers/imageUrlGetter"; | |||
| import { useEffect } from "react"; | |||
| import { useState } from "react"; | |||
| import ImagesCarousel from "../ImagesCarousel/ImagesCarousel"; | |||
| import OfferDescription from "./OfferDescription/OfferDescription"; | |||
| const OfferDetails = (props) => { | |||
| const offer = props.offer; | |||
| @@ -110,9 +110,7 @@ const OfferDetails = (props) => { | |||
| <OfferDescriptionTitle> | |||
| {t("itemDetailsCard.description")} | |||
| </OfferDescriptionTitle> | |||
| <OfferDescriptionText showBarterButton={props.showExchangeButton}> | |||
| {offer?.description} | |||
| </OfferDescriptionText> | |||
| <OfferDescription value={offer?.description} /> | |||
| <DesciprtionPostDate previewCard={props.previewCard}> | |||
| {date} | |||
| </DesciprtionPostDate> | |||
| @@ -135,17 +135,10 @@ export const OfferDescriptionText = styled(Box)` | |||
| line-height: 22px; | |||
| white-space: pre-line; | |||
| max-width: 100%; | |||
| /* max-width: ${(props) => | |||
| props.showBarterButton ? "calc(100% - 230px)" : "100%"}; */ | |||
| @media (max-width: 600px) { | |||
| font-size: 14px; | |||
| 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)` | |||
| display: none; | |||
| @@ -6,6 +6,8 @@ import { | |||
| OfferDescriptionTitle, | |||
| } from "./OfferDescription.styled"; | |||
| import { useTranslation } from "react-i18next"; | |||
| import RichTextComponent from "../../../RichTextComponent/RichTextComponent"; | |||
| import { isJsonString } from "../../../../util/helpers/jsonHelper"; | |||
| const OfferDescription = (props) => { | |||
| const { t } = useTranslation(); | |||
| @@ -14,7 +16,13 @@ const OfferDescription = (props) => { | |||
| <OfferDescriptionTitle> | |||
| {t("offer.descriptionLabel")} | |||
| </OfferDescriptionTitle> | |||
| <OfferDescriptionText>{props.description}</OfferDescriptionText> | |||
| <OfferDescriptionText> | |||
| {isJsonString(props?.description) ? ( | |||
| <RichTextComponent readOnly offerCard value={props?.description} /> | |||
| ) : ( | |||
| "" | |||
| )} | |||
| </OfferDescriptionText> | |||
| </OfferDescriptionContainer> | |||
| ); | |||
| }; | |||
| @@ -67,5 +67,5 @@ export const LinkText = styled(Typography)` | |||
| `; | |||
| export const Arrow = styled(ArrowButton)` | |||
| transform: rotate(-45deg); | |||
| transform: rotate(-90deg); | |||
| `; | |||
| @@ -21,6 +21,7 @@ import { | |||
| ADMIN_HOME_PAGE, | |||
| BASE_PAGE, | |||
| HOME_PAGE, | |||
| MARKETPLACE_PAGE, | |||
| } from "../../constants/pages"; | |||
| import { fetchMineProfile } from "../../store/actions/profile/profileActions"; | |||
| import useSearch from "../../hooks/useOffers/useSearch"; | |||
| @@ -106,12 +107,21 @@ const Header = () => { | |||
| }, | |||
| }); | |||
| } 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 = ""; | |||
| } | |||
| }; | |||
| @@ -143,7 +153,11 @@ const Header = () => { | |||
| handleSearch={handleSearch} | |||
| user={user} | |||
| /> | |||
| {routeMatches(ABOUT_PAGE) && <AboutHeader />} | |||
| {(routeMatches(ABOUT_PAGE) || | |||
| (!user && | |||
| (routeMatches(HOME_PAGE) || routeMatches(BASE_PAGE)))) && ( | |||
| <AboutHeader /> | |||
| )} | |||
| {user ? ( | |||
| <ToolsButtonsContainer | |||
| @@ -177,7 +191,9 @@ const Header = () => { | |||
| /> | |||
| ) : ( | |||
| <React.Fragment> | |||
| {routeMatches(ABOUT_PAGE) ? ( | |||
| {routeMatches(ABOUT_PAGE) || | |||
| routeMatches(HOME_PAGE) || | |||
| routeMatches(BASE_PAGE) ? ( | |||
| <MarketplaceLinkRouteContainer> | |||
| <MarketplaceLinkRoute onClick={() => handleLogoClick()}> | |||
| {t("admin.navigation.marketplace")} | |||
| @@ -11,16 +11,18 @@ import { useTranslation } from "react-i18next"; | |||
| import { routeMatches } from "../../../util/helpers/routeHelpers"; | |||
| import { ABOUT_PAGE, BASE_PAGE, HOME_PAGE } from "../../../constants/pages"; | |||
| import { debounceHelper } from "../../../util/helpers/debounceHelper"; | |||
| import useIsLoggedIn from "../../../hooks/useIsLoggedIn"; | |||
| const SearchInput = forwardRef((props, ref) => { | |||
| const { t } = useTranslation(); | |||
| const { isLoggedIn } = useIsLoggedIn(); | |||
| const handleSearch = () => { | |||
| if (routeMatches(HOME_PAGE) || routeMatches(BASE_PAGE)) { | |||
| console.log("uslo unutra") | |||
| console.log("uslo unutra"); | |||
| debounceHelper(() => props.handleSearch(ref.current.value), 500); | |||
| } | |||
| }; | |||
| console.log(routeMatches(HOME_PAGE)) | |||
| console.log(routeMatches(HOME_PAGE)); | |||
| const handleManualSearch = () => { | |||
| debounceHelper(() => {}, 500); | |||
| props.handleSearch(ref.current.value); | |||
| @@ -40,7 +42,10 @@ const SearchInput = forwardRef((props, ref) => { | |||
| const handleBlurSearch = () => { | |||
| ref.current.removeEventListener("keyup", listener); | |||
| }; | |||
| if (routeMatches(ABOUT_PAGE)) { | |||
| if ( | |||
| routeMatches(ABOUT_PAGE) || | |||
| (!isLoggedIn && (routeMatches(HOME_PAGE) || routeMatches(BASE_PAGE))) | |||
| ) { | |||
| return <></>; | |||
| } | |||
| return ( | |||
| @@ -0,0 +1,54 @@ | |||
| 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; | |||
| @@ -0,0 +1,43 @@ | |||
| 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; | |||
| `; | |||
| @@ -3,7 +3,7 @@ import PropTypes from "prop-types"; | |||
| import { useSlate } from "slate-react"; | |||
| import { Editor, Transforms, Element as SlateElement } from "slate"; | |||
| 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 BlockButton = ({ format, icon }) => { | |||
| const editor = useSlate(); | |||
| @@ -2,42 +2,57 @@ import React from "react"; | |||
| import PropTypes from "prop-types"; | |||
| import { useSlate } from "slate-react"; | |||
| 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 [isColorPickerPopoverShowing, setIsColorPickerPopoverShowing] = | |||
| useState(false); | |||
| const callbackFunction = (newColor) => { | |||
| setIsColorPickerPopoverShowing(false); | |||
| props?.setSelectedColor(newColor); | |||
| toggleMark(editor, "color", newColor.color); | |||
| }; | |||
| console.log(); | |||
| 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 = { | |||
| format: PropTypes.any, | |||
| icon: PropTypes.any, | |||
| selectedColor: PropTypes.any, | |||
| setSelectedColor: PropTypes.func, | |||
| }; | |||
| export default ColorButton; | |||
| @@ -0,0 +1,29 @@ | |||
| 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}; | |||
| `} | |||
| `; | |||
| @@ -0,0 +1,26 @@ | |||
| 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; | |||
| @@ -0,0 +1,15 @@ | |||
| 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"}; | |||
| `; | |||
| @@ -1,6 +1,7 @@ | |||
| import React, { useCallback, useMemo } from "react"; | |||
| import { Editable, withReact, Slate } from "slate-react"; | |||
| import { createEditor } from "slate"; | |||
| import PropTypes from "prop-types"; | |||
| import RichTextElement from "./RichTextElement/RichTextElement"; | |||
| import MarkButton from "./MarkButton/MarkButton"; | |||
| @@ -16,74 +17,77 @@ import { useState } from "react"; | |||
| import BlockButton from "./BlockButton/BlockButton"; | |||
| import ColorButton from "./ColorButton/ColorButton"; | |||
| 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, | |||
| 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([ | |||
| { | |||
| type: "paragraph", | |||
| children: [{ text: "" }], | |||
| }, | |||
| ]); | |||
| useEffect(() => { | |||
| setValue(props?.value); | |||
| editor.children = isJsonString(props?.value) | |||
| ? JSON.parse(props?.value) | |||
| : value; | |||
| }, [props?.value]); | |||
| const renderElement = useCallback( | |||
| (props) => <RichTextElement {...props} />, | |||
| [] | |||
| ); | |||
| const renderLeaf = useCallback((props) => <RichTextLeaf {...props} />, []); | |||
| const editor = useMemo(() => withReact(createEditor()), []); | |||
| const editor = useMemo(() => withReact(createEditor()), [props?.value]); | |||
| return ( | |||
| <RichTextComponentContainer> | |||
| <RichTextComponentContainer | |||
| offerCard={props?.offerCard} | |||
| readOnly={props?.readOnly} | |||
| itemDetails={props?.itemDetails} | |||
| > | |||
| <Slate | |||
| editor={editor} | |||
| value={value} | |||
| value={isJsonString(props?.value) ? JSON.parse(props?.value) : value} | |||
| 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 | |||
| placeholder={t("offer.description")} | |||
| renderElement={renderElement} | |||
| renderLeaf={renderLeaf} | |||
| spellCheck | |||
| autoFocus | |||
| readOnly={props?.readOnly} | |||
| /> | |||
| </EditableInnerContainer> | |||
| </EditableContainer> | |||
| @@ -98,5 +102,13 @@ const RichTextComponent = () => { | |||
| // 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; | |||
| @@ -1,9 +1,9 @@ | |||
| import { Box } from "@mui/material"; | |||
| import styled from "styled-components"; | |||
| import styled, { css } from "styled-components"; | |||
| import selectedTheme from "../../themes"; | |||
| export const SlateButtonsContainer = styled(Box)` | |||
| display: flex; | |||
| display: ${(props) => (props.readOnly ? "none" : "flex")}; | |||
| flex-direction: row; | |||
| height: 36px; | |||
| background-color: ${selectedTheme.colors.stylingTextBackground}; | |||
| @@ -15,13 +15,28 @@ export const RichTextComponentContainer = styled(Box)` | |||
| width: 100%; | |||
| position: relative; | |||
| 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; | |||
| @media (max-width: 600px) { | |||
| /* height: 40px; */ | |||
| height: auto; | |||
| } | |||
| `; | |||
| export const EditableContainer = styled(Box)` | |||
| max-height: 104px; | |||
| overflow: auto; | |||
| ${(props) => !props?.itemDetails && "max-height: 104px;"} | |||
| ${(props) => !props?.offerCard && "overflow: auto;"} | |||
| &::-webkit-scrollbar { | |||
| width: 5px; | |||
| height: 5px; | |||
| @@ -34,13 +49,28 @@ export const EditableContainer = styled(Box)` | |||
| } | |||
| scrollbar-width: thin; | |||
| scrollbar-color: #ddd; | |||
| @media (max-width: 600px) { | |||
| /* max-height: 39px; */ | |||
| } | |||
| `; | |||
| export const EditableInnerContainer = styled(Box)` | |||
| padding: 10px 16px; | |||
| padding: ${(props) => (props?.readOnly ? "0" : "10px 16px")}; | |||
| & > div { | |||
| min-height: 84px; | |||
| } | |||
| & * { | |||
| 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; | |||
| } | |||
| } | |||
| `; | |||
| @@ -1,6 +1,7 @@ | |||
| import React from "react"; | |||
| import PropTypes from "prop-types"; | |||
| import { ListContainer } from "./RichTextElement.styled"; | |||
| import selectedTheme from "../../../themes"; | |||
| const RichTextElement = ({ attributes, children, element }) => { | |||
| const style = { textAlign: element.align }; | |||
| @@ -17,6 +18,12 @@ const RichTextElement = ({ attributes, children, element }) => { | |||
| {children} | |||
| </ListContainer> | |||
| ); | |||
| case "link": | |||
| return ( | |||
| <a href="" style={style} {...attributes}> | |||
| {children} | |||
| </a> | |||
| ); | |||
| case "heading-one": | |||
| return ( | |||
| <h1 style={style} {...attributes}> | |||
| @@ -43,7 +50,11 @@ const RichTextElement = ({ attributes, children, element }) => { | |||
| ); | |||
| default: | |||
| return ( | |||
| <div style={style} {...attributes}> | |||
| <div | |||
| style={style} | |||
| {...attributes} | |||
| color={selectedTheme.colors.colorPicker.darkGray} | |||
| > | |||
| {children} | |||
| </div> | |||
| ); | |||
| @@ -2,8 +2,9 @@ import { Box } from "@mui/material"; | |||
| import styled from "styled-components"; | |||
| export const ListContainer = styled(Box)` | |||
| padding-left: | |||
| & > div { | |||
| display: list-item; | |||
| } | |||
| ` | |||
| color: green; | |||
| padding-left: 18px; | |||
| & > div { | |||
| display: list-item; | |||
| } | |||
| `; | |||
| @@ -16,7 +16,9 @@ const RichTextLeaf = ({ attributes, children, leaf }) => { | |||
| if (leaf.underline) { | |||
| children = <u>{children}</u>; | |||
| } | |||
| if (leaf.color) { | |||
| children = <span style={{ color: leaf.color }}>{children}</span>; | |||
| } | |||
| return <span {...attributes}>{children}</span>; | |||
| }; | |||
| @@ -24,5 +26,6 @@ RichTextLeaf.propTypes = { | |||
| attributes: PropTypes.any, | |||
| children: PropTypes.any, | |||
| leaf: PropTypes.any, | |||
| selectedColor: PropTypes.any, | |||
| }; | |||
| export default RichTextLeaf; | |||
| @@ -26,3 +26,4 @@ export const ADMIN_CATEGORIES_PAGE = "/admin/categories"; | |||
| export const ADMIN_LOCATIONS_PAGE = "/admin/locations"; | |||
| export const ADMIN_PAYMENT_PAGE = "/admin/payment"; | |||
| export const ADMIN_SUBCATEGORIES_PAGE = "/admin/categories/:categoryId"; | |||
| export const MARKETPLACE_PAGE = "/marketplace"; | |||
| @@ -0,0 +1,12 @@ | |||
| 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; | |||
| @@ -603,6 +603,7 @@ export default { | |||
| nextPage: "Next page", | |||
| }, | |||
| colorPicker: { | |||
| label: "Boja: ", | |||
| darkGray: "Tamno Siva", | |||
| gray: "Siva", | |||
| yellow: "Žuta", | |||
| @@ -1,92 +1,9 @@ | |||
| import React, { useEffect, useRef } from "react"; | |||
| import React 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"; | |||
| import AboutPageContent from "../../components/About/AboutPageContent"; | |||
| 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 = { | |||
| @@ -1,12 +0,0 @@ | |||
| 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; | |||
| } | |||
| ` | |||
| @@ -1,4 +1,5 @@ | |||
| import React, { useState } from "react"; | |||
| import PropTypes from "prop-types"; | |||
| import { HomePageContainer } from "./HomePage.styled"; | |||
| import FilterCard from "../../components/Cards/FilterCard/FilterCard"; | |||
| import MainLayout from "../../layouts/MainLayout/MainLayout"; | |||
| @@ -7,8 +8,11 @@ import { selectIsLoadingByActionType } from "../../store/selectors/loadingSelect | |||
| import { useSelector } from "react-redux"; | |||
| import { OFFERS_SCOPE } from "../../store/actions/offers/offersActionConstants"; | |||
| 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( | |||
| selectIsLoadingByActionType(OFFERS_SCOPE) | |||
| ); | |||
| @@ -17,26 +21,33 @@ const HomePage = () => { | |||
| const toggleFilters = () => { | |||
| 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; | |||
| @@ -0,0 +1,8 @@ | |||
| import React from "react"; | |||
| import HomePage from "../HomePage/HomePage"; | |||
| const MarketplacePage = () => { | |||
| return <HomePage isMarketplacePage />; | |||
| }; | |||
| export default MarketplacePage; | |||
| @@ -48,6 +48,7 @@ import { | |||
| pinOfferSuccess, | |||
| pinOfferError, | |||
| addProfileOffers, | |||
| clearSelectedOffer, | |||
| // fetchAllOffersSuccess, | |||
| // fetchAllOffersError, | |||
| // setFeaturedOfferPage, | |||
| @@ -215,6 +216,7 @@ function* fetchOneOffer(payload) { | |||
| queryObject, | |||
| }); | |||
| if (!data?.data) throw new Error(); | |||
| yield put(clearSelectedOffer()); | |||
| yield put(fetchOneOfferSuccess(data?.data)); | |||
| } catch (e) { | |||
| console.log(e?.response?.status); | |||
| @@ -274,7 +276,7 @@ function* fetchProfileOffers(payload) { | |||
| } else { | |||
| queryString = yield select(selectQueryString); | |||
| } | |||
| console.log(queryString.toString()); | |||
| let data; | |||
| if (payload.payload.isAdmin) { | |||
| @@ -0,0 +1,8 @@ | |||
| export const isJsonString = (stringToCheck) => { | |||
| try { | |||
| JSON.parse(stringToCheck); | |||
| } catch (e) { | |||
| return false; | |||
| } | |||
| return true; | |||
| }; | |||