| "redux-saga": "^1.1.3", | "redux-saga": "^1.1.3", | ||||
| "rive-react": "^3.0.23", | "rive-react": "^3.0.23", | ||||
| "sass": "^1.34.1", | "sass": "^1.34.1", | ||||
| "slate": "^0.86.0", | |||||
| "slate-react": "^0.86.0", | |||||
| "socket.io": "^4.5.1", | "socket.io": "^4.5.1", | ||||
| "socket.io-client": "^4.5.1", | "socket.io-client": "^4.5.1", | ||||
| "styled-components": "^5.3.5", | "styled-components": "^5.3.5", |
| href="https://fonts.googleapis.com/css?family=Poppins&display=swap" | href="https://fonts.googleapis.com/css?family=Poppins&display=swap" | ||||
| onload="this.onload=null;this.rel='stylesheet';this.type='text/css'" | onload="this.onload=null;this.rel='stylesheet';this.type='text/css'" | ||||
| /> | /> | ||||
| <link | |||||
| rel="preload" | |||||
| as="style" | |||||
| href="https://fonts.googleapis.com/css?family=Source+Code+Pro:400,700&display=swap" | |||||
| onload="this.onload=null;this.rel='stylesheet';this.type='text/css'" | |||||
| /> | |||||
| <link | <link | ||||
| style | style | ||||
| rel="preload" | rel="preload" |
| 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} /> |
| <svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg"> | |||||
| <path d="M6 4.5H15.75" stroke="#667080" stroke-width="1.24" stroke-linecap="round" stroke-linejoin="round"/> | |||||
| <path d="M6 9H15.75" stroke="#667080" stroke-width="1.24" stroke-linecap="round" stroke-linejoin="round"/> | |||||
| <path d="M6 13.5H15.75" stroke="#667080" stroke-width="1.24" stroke-linecap="round" stroke-linejoin="round"/> | |||||
| <path d="M2.25 4.5H2.2575" stroke="#667080" stroke-width="1.24" stroke-linecap="round" stroke-linejoin="round"/> | |||||
| <path d="M2.25 9H2.2575" stroke="#667080" stroke-width="1.24" stroke-linecap="round" stroke-linejoin="round"/> | |||||
| <path d="M2.25 13.5H2.2575" stroke="#667080" stroke-width="1.24" stroke-linecap="round" stroke-linejoin="round"/> | |||||
| </svg> |
| 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"; | |||||
| 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 ? ( | |||||
| <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 | |||||
| multiline | |||||
| minRows={4} | |||||
| height={"100px"} | |||||
| /> | |||||
| ) : ( | |||||
| <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 styled from "styled-components"; | import styled from "styled-components"; | ||||
| import selectedTheme from "../../../../../themes"; | |||||
| import { TextField } from "../../../../TextFields/TextField/TextField"; | import { TextField } from "../../../../TextFields/TextField/TextField"; | ||||
| export const DescriptionField = styled(TextField)` | export const DescriptionField = styled(TextField)` | ||||
| } | } | ||||
| } | } | ||||
| `; | `; | ||||
| export const Element = styled.p` | |||||
| background-color: ${selectedTheme.colors.primaryBackgroundColor}; | |||||
| padding: 0; | |||||
| box-sizing: border-box; | |||||
| overflow-y: auto; | |||||
| width: 100%; | |||||
| margin: 16px 0; | |||||
| padding-left: 0; | |||||
| height: 100px; | |||||
| font-size: 16px; | |||||
| padding: 8px 14px; | |||||
| border: 1px solid rgba(0, 0, 0, 0.23); | |||||
| border-radius: 4px; | |||||
| `; |
| 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 React from "react"; | |||||
| 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", "link"]; | |||||
| const TEXT_ALIGN_TYPES = ["left", "center", "right", "justify"]; | |||||
| const BlockButton = ({ format, icon }) => { | |||||
| const editor = useSlate(); | |||||
| return ( | |||||
| <BlockButtonContainer | |||||
| active={isBlockActive( | |||||
| editor, | |||||
| format, | |||||
| TEXT_ALIGN_TYPES.includes(format) ? "align" : "type" | |||||
| )} | |||||
| onMouseDown={(event) => { | |||||
| event.preventDefault(); | |||||
| toggleBlock(editor, format); | |||||
| }} | |||||
| > | |||||
| <BlockButtonIcon>{icon}</BlockButtonIcon> | |||||
| </BlockButtonContainer> | |||||
| ); | |||||
| }; | |||||
| const isBlockActive = (editor, format, blockType = "type") => { | |||||
| const { selection } = editor; | |||||
| if (!selection) return false; | |||||
| const [match] = Array.from( | |||||
| Editor.nodes(editor, { | |||||
| at: Editor.unhangRange(editor, selection), | |||||
| match: (n) => | |||||
| !Editor.isEditor(n) && | |||||
| SlateElement.isElement(n) && | |||||
| n[blockType] === format, | |||||
| }) | |||||
| ); | |||||
| return !!match; | |||||
| }; | |||||
| const toggleBlock = (editor, format) => { | |||||
| const isActive = isBlockActive( | |||||
| editor, | |||||
| format, | |||||
| TEXT_ALIGN_TYPES.includes(format) ? "align" : "type" | |||||
| ); | |||||
| const isList = LIST_TYPES.includes(format); | |||||
| Transforms.unwrapNodes(editor, { | |||||
| match: (n) => | |||||
| !Editor.isEditor(n) && | |||||
| SlateElement.isElement(n) && | |||||
| LIST_TYPES.includes(n.type) && | |||||
| !TEXT_ALIGN_TYPES.includes(format), | |||||
| split: true, | |||||
| }); | |||||
| let newProperties; | |||||
| if (TEXT_ALIGN_TYPES.includes(format)) { | |||||
| newProperties = { | |||||
| align: isActive ? undefined : format, | |||||
| }; | |||||
| } else { | |||||
| newProperties = { | |||||
| type: isActive ? "paragraph" : isList ? "list-item" : format, | |||||
| }; | |||||
| } | |||||
| Transforms.setNodes < SlateElement > (editor, newProperties); | |||||
| if (!isActive && isList) { | |||||
| const block = { type: format, children: [] }; | |||||
| Transforms.wrapNodes(editor, block); | |||||
| } | |||||
| }; | |||||
| BlockButton.propTypes = { | |||||
| format: PropTypes.any, | |||||
| icon: PropTypes.any, | |||||
| }; | |||||
| export default BlockButton; |
| import { Box } from "@mui/system"; | |||||
| import styled, { css } from "styled-components"; | |||||
| import selectedTheme from "../../../themes"; | |||||
| export const BlockButtonContainer = styled(Box)` | |||||
| display: inline; | |||||
| cursor: pointer; | |||||
| `; | |||||
| export const BlockButtonIcon = 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 { useSlate } from "slate-react"; | |||||
| import { Editor } from "slate"; | |||||
| import { ColorButtonContainer, ColorButtonIcon } from "./ColorButton.styled"; | |||||
| import { useState } from "react"; | |||||
| import ColorIcon from "../ColorIcon/ColorIcon"; | |||||
| import ColorPicker from "../../Popovers/ColorPicker/ColorPicker"; | |||||
| // const colorMarks = ["darkGray", "gray", "purple", "pink", "yellow"]; | |||||
| 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 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 ( | |||||
| <> | |||||
| <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; |
| 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 from "react"; | |||||
| import PropTypes from "prop-types"; | |||||
| import { useSlate } from "slate-react"; | |||||
| import { Editor } from "slate"; | |||||
| import { MarkButtonContainer, MarkButtonIcon } from "./MarkButton.styled"; | |||||
| const toggleMark = (editor, format) => { | |||||
| const isActive = isMarkActive(editor, format); | |||||
| if (isActive) { | |||||
| Editor.removeMark(editor, format); | |||||
| } else { | |||||
| Editor.addMark(editor, format, true); | |||||
| } | |||||
| }; | |||||
| const isMarkActive = (editor, format) => { | |||||
| const marks = Editor.marks(editor); | |||||
| return marks ? marks[format] === true : false; | |||||
| }; | |||||
| const MarkButton = ({ format, icon }) => { | |||||
| const editor = useSlate(); | |||||
| 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> | |||||
| ); | |||||
| }; | |||||
| MarkButton.propTypes = { | |||||
| format: PropTypes.any, | |||||
| icon: PropTypes.any, | |||||
| }; | |||||
| export default MarkButton; |
| import { Box } from "@mui/material"; | |||||
| import styled, { css } from "styled-components"; | |||||
| import selectedTheme from "../../../themes"; | |||||
| export const MarkButtonContainer = styled(Box)` | |||||
| display: inline; | |||||
| cursor: pointer; | |||||
| `; | |||||
| export const MarkButtonIcon = 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, { 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"; | |||||
| import RichTextLeaf from "./RichTextLeaf/RichTextLeaf"; | |||||
| import { ReactComponent as BulletedList } from "../../assets/images/svg/bulleted-list.svg"; | |||||
| import { | |||||
| EditableContainer, | |||||
| EditableInnerContainer, | |||||
| RichTextComponentContainer, | |||||
| SlateButtonsContainer, | |||||
| } from "./RichTextComponent.styled"; | |||||
| 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 RichTextComponent = (props) => { | |||||
| const { isMobile } = useIsMobile(); | |||||
| const { t } = useTranslation(); | |||||
| const [selectedColor, setSelectedColor] = useState({ | |||||
| color: selectedTheme.colors.colorPicker.darkGray, | |||||
| 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()), [props?.value]); | |||||
| return ( | |||||
| <RichTextComponentContainer | |||||
| offerCard={props?.offerCard} | |||||
| readOnly={props?.readOnly} | |||||
| itemDetails={props?.itemDetails} | |||||
| > | |||||
| <Slate | |||||
| editor={editor} | |||||
| value={isJsonString(props?.value) ? JSON.parse(props?.value) : value} | |||||
| onChange={(newValue) => { | |||||
| if (props?.onChange) props?.onChange(JSON.stringify(newValue)); | |||||
| else setValue(newValue); | |||||
| }} | |||||
| > | |||||
| {!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> | |||||
| </Slate> | |||||
| </RichTextComponentContainer> | |||||
| ); | |||||
| }; | |||||
| // const initialValue = [ | |||||
| // { | |||||
| // type: "paragraph", | |||||
| // 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; |
| import { Box } from "@mui/material"; | |||||
| import styled, { css } from "styled-components"; | |||||
| import selectedTheme from "../../themes"; | |||||
| export const SlateButtonsContainer = styled(Box)` | |||||
| display: ${(props) => (props.readOnly ? "none" : "flex")}; | |||||
| flex-direction: row; | |||||
| height: 36px; | |||||
| background-color: ${selectedTheme.colors.stylingTextBackground}; | |||||
| padding: 8px 16px; | |||||
| border-radius: 4px; | |||||
| gap: 20px; | |||||
| `; | |||||
| export const RichTextComponentContainer = styled(Box)` | |||||
| width: 100%; | |||||
| position: relative; | |||||
| top: 14px; | |||||
| 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)` | |||||
| ${(props) => !props?.itemDetails && "max-height: 104px;"} | |||||
| ${(props) => !props?.offerCard && "overflow: auto;"} | |||||
| &::-webkit-scrollbar { | |||||
| width: 5px; | |||||
| height: 5px; | |||||
| } | |||||
| &::-webkit-scrollbar-track { | |||||
| background: #ddd; | |||||
| } | |||||
| &::-webkit-scrollbar-thumb { | |||||
| background: #777; | |||||
| } | |||||
| scrollbar-width: thin; | |||||
| scrollbar-color: #ddd; | |||||
| @media (max-width: 600px) { | |||||
| /* max-height: 39px; */ | |||||
| } | |||||
| `; | |||||
| export const EditableInnerContainer = styled(Box)` | |||||
| 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; | |||||
| } | |||||
| } | |||||
| `; |
| 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 }; | |||||
| switch (element.type) { | |||||
| case "block-quote": | |||||
| return ( | |||||
| <blockquote style={style} {...attributes}> | |||||
| {children} | |||||
| </blockquote> | |||||
| ); | |||||
| case "bulleted-list": | |||||
| return ( | |||||
| <ListContainer style={style} {...attributes}> | |||||
| {children} | |||||
| </ListContainer> | |||||
| ); | |||||
| case "link": | |||||
| return ( | |||||
| <a href="" style={style} {...attributes}> | |||||
| {children} | |||||
| </a> | |||||
| ); | |||||
| case "heading-one": | |||||
| return ( | |||||
| <h1 style={style} {...attributes}> | |||||
| {children} | |||||
| </h1> | |||||
| ); | |||||
| case "heading-two": | |||||
| return ( | |||||
| <h2 style={style} {...attributes}> | |||||
| {children} | |||||
| </h2> | |||||
| ); | |||||
| case "list-item": | |||||
| return ( | |||||
| <li style={style} {...attributes}> | |||||
| {children} | |||||
| </li> | |||||
| ); | |||||
| case "numbered-list": | |||||
| return ( | |||||
| <ol style={style} {...attributes}> | |||||
| {children} | |||||
| </ol> | |||||
| ); | |||||
| default: | |||||
| return ( | |||||
| <div | |||||
| style={style} | |||||
| {...attributes} | |||||
| color={selectedTheme.colors.colorPicker.darkGray} | |||||
| > | |||||
| {children} | |||||
| </div> | |||||
| ); | |||||
| } | |||||
| }; | |||||
| RichTextElement.propTypes = { | |||||
| attributes: PropTypes.any, | |||||
| children: PropTypes.any, | |||||
| element: PropTypes.any, | |||||
| }; | |||||
| export default RichTextElement; |
| import { Box } from "@mui/material"; | |||||
| import styled from "styled-components"; | |||||
| export const ListContainer = styled(Box)` | |||||
| color: green; | |||||
| padding-left: 18px; | |||||
| & > div { | |||||
| display: list-item; | |||||
| } | |||||
| `; |
| import React from "react"; | |||||
| import PropTypes from "prop-types"; | |||||
| const RichTextLeaf = ({ attributes, children, leaf }) => { | |||||
| if (leaf.bold) { | |||||
| children = <strong>{children}</strong>; | |||||
| } | |||||
| if (leaf.code) { | |||||
| children = <code>{children}</code>; | |||||
| } | |||||
| if (leaf.italic) { | |||||
| children = <i>{children}</i>; | |||||
| } | |||||
| if (leaf.underline) { | |||||
| children = <u>{children}</u>; | |||||
| } | |||||
| if (leaf.color) { | |||||
| children = <span style={{ color: leaf.color }}>{children}</span>; | |||||
| } | |||||
| return <span {...attributes}>{children}</span>; | |||||
| }; | |||||
| RichTextLeaf.propTypes = { | |||||
| attributes: PropTypes.any, | |||||
| children: PropTypes.any, | |||||
| leaf: PropTypes.any, | |||||
| selectedColor: PropTypes.any, | |||||
| }; | |||||
| export default RichTextLeaf; |
| setIsFieldEmpty(false); | setIsFieldEmpty(false); | ||||
| } | } | ||||
| }, [props.value]); | }, [props.value]); | ||||
| console.log(props); | |||||
| return ( | return ( | ||||
| <TextFieldContainer | <TextFieldContainer | ||||
| style={props.containerStyle} | style={props.containerStyle} | ||||
| height={props.height} | height={props.height} | ||||
| > | > | ||||
| <TextFieldStyled | <TextFieldStyled | ||||
| {...props.attributes} | |||||
| inputRef={ref} | inputRef={ref} | ||||
| inputProps={props.inputProps} | inputProps={props.inputProps} | ||||
| placeholder={props.placeholder} | placeholder={props.placeholder} | ||||
| endAdornment: PropTypes.node, | endAdornment: PropTypes.node, | ||||
| style: PropTypes.any, | style: PropTypes.any, | ||||
| }), | }), | ||||
| attributes: PropTypes.any, | |||||
| }; | }; | ||||
| TextField.defaultProps = { | TextField.defaultProps = { | ||||
| italicPlaceholder: false, | italicPlaceholder: false, | ||||
| showAnimation: false, | showAnimation: false, | ||||
| height: "48px", | height: "48px", | ||||
| font: selectedTheme.fonts.textFont | |||||
| font: selectedTheme.fonts.textFont, | |||||
| }; | }; |
| 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; |
| prevPage: "Previous page", | prevPage: "Previous page", | ||||
| nextPage: "Next page", | nextPage: "Next page", | ||||
| }, | }, | ||||
| colorPicker: { | |||||
| label: "Boja: ", | |||||
| darkGray: "Tamno Siva", | |||||
| gray: "Siva", | |||||
| yellow: "Žuta", | |||||
| purple: "Ljubičasta", | |||||
| pink: "Roze" | |||||
| } | |||||
| }; | }; |
| 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) { |
| skeletonItemColor: "#F4F4F4", | skeletonItemColor: "#F4F4F4", | ||||
| chatHeaderColor: "#F4F4F4", | chatHeaderColor: "#F4F4F4", | ||||
| messageBackground: "#F4F4F4", | messageBackground: "#F4F4F4", | ||||
| stylingTextBackground: "#F4F4F4", | |||||
| messageText: "#1D1D1D", | messageText: "#1D1D1D", | ||||
| messageDate: "#949494", | messageDate: "#949494", | ||||
| messageMyDate: "#C4C4C4", | messageMyDate: "#C4C4C4", | ||||
| blockedColor: "#E4E4E4", | blockedColor: "#E4E4E4", | ||||
| blockedTextColor: "#D13333", | blockedTextColor: "#D13333", | ||||
| errorColor: "#d32f2f", | errorColor: "#d32f2f", | ||||
| colorPicker: { | |||||
| darkGray: "#4D4D4D", | |||||
| gray: "#B4B4B4", | |||||
| yellow: "#FEB005", | |||||
| purple: "#5A3984", | |||||
| pink: "#E5D0FF", | |||||
| border: "#818181", | |||||
| }, | |||||
| }; | }; |
| export const isJsonString = (stringToCheck) => { | |||||
| try { | |||||
| JSON.parse(stringToCheck); | |||||
| } catch (e) { | |||||
| return false; | |||||
| } | |||||
| return true; | |||||
| }; |
| "resolved" "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-5.1.1.tgz" | "resolved" "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-5.1.1.tgz" | ||||
| "version" "5.1.1" | "version" "5.1.1" | ||||
| "@types/is-hotkey@^0.1.1": | |||||
| "integrity" "sha512-yB5C7zcOM7idwYZZ1wKQ3pTfjA9BbvFqRWvKB46GFddxnJtHwi/b9y84ykQtxQPg5qhdpg4Q/kWU3EGoCTmLzQ==" | |||||
| "resolved" "https://registry.npmjs.org/@types/is-hotkey/-/is-hotkey-0.1.7.tgz" | |||||
| "version" "0.1.7" | |||||
| "@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0", "@types/istanbul-lib-coverage@^2.0.1": | "@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0", "@types/istanbul-lib-coverage@^2.0.1": | ||||
| "integrity" "sha512-sz7iLqvVUg1gIedBOvlkxPlc8/uVzyS5OwGz1cKjXzkl3FpL3al0crU8YGU1WoHkxn0Wxbw5tyi6hvzJKNzFsw==" | "integrity" "sha512-sz7iLqvVUg1gIedBOvlkxPlc8/uVzyS5OwGz1cKjXzkl3FpL3al0crU8YGU1WoHkxn0Wxbw5tyi6hvzJKNzFsw==" | ||||
| "resolved" "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz" | "resolved" "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz" | ||||
| "resolved" "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz" | "resolved" "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz" | ||||
| "version" "0.0.29" | "version" "0.0.29" | ||||
| "@types/lodash@^4.14.175": | |||||
| "@types/lodash@^4.14.149", "@types/lodash@^4.14.175": | |||||
| "integrity" "sha512-/THyiqyQAP9AfARo4pF+aCGcyiQ94tX/Is2I7HofNRqoYLgN1PBoOWu2/zTA5zMxzP5EFutMtWtGAFRKUe961Q==" | "integrity" "sha512-/THyiqyQAP9AfARo4pF+aCGcyiQ94tX/Is2I7HofNRqoYLgN1PBoOWu2/zTA5zMxzP5EFutMtWtGAFRKUe961Q==" | ||||
| "resolved" "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.182.tgz" | "resolved" "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.182.tgz" | ||||
| "version" "4.14.182" | "version" "4.14.182" | ||||
| "safe-buffer" "5.1.2" | "safe-buffer" "5.1.2" | ||||
| "vary" "~1.1.2" | "vary" "~1.1.2" | ||||
| "compute-scroll-into-view@^1.0.17": | |||||
| "integrity" "sha512-j4dx+Fb0URmzbwwMUrhqWM2BEWHdFGx+qZ9qqASHRPqvTYdqvWnHg0H1hIbcyLnvgnoNAVMlwkepyqM3DaIFUg==" | |||||
| "resolved" "https://registry.npmjs.org/compute-scroll-into-view/-/compute-scroll-into-view-1.0.17.tgz" | |||||
| "version" "1.0.17" | |||||
| "concat-map@0.0.1": | "concat-map@0.0.1": | ||||
| "integrity" "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" | "integrity" "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" | ||||
| "resolved" "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz" | "resolved" "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz" | ||||
| dependencies: | dependencies: | ||||
| "path-type" "^4.0.0" | "path-type" "^4.0.0" | ||||
| "direction@^1.0.3": | |||||
| "integrity" "sha512-GYqKi1aH7PJXxdhTeZBFrg8vUBeKXi+cNprXsC1kpJcbcVnV9wBsrOu1cQEdG0WeQwlfHiy3XvnKfIrJ2R0NzQ==" | |||||
| "resolved" "https://registry.npmjs.org/direction/-/direction-1.0.4.tgz" | |||||
| "version" "1.0.4" | |||||
| "dns-equal@^1.0.0": | "dns-equal@^1.0.0": | ||||
| "integrity" "sha1-s55/HabrCnW6nBcySzR1PEfgZU0=" | "integrity" "sha1-s55/HabrCnW6nBcySzR1PEfgZU0=" | ||||
| "resolved" "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz" | "resolved" "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz" | ||||
| "resolved" "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz" | "resolved" "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz" | ||||
| "version" "5.1.8" | "version" "5.1.8" | ||||
| "immer@^9.0.6": | |||||
| "integrity" "sha512-qenGE7CstVm1NrHQbMh8YaSzTZTFNP3zPqr3YU0S0UY441j4bJTg4A2Hh5KAhwgaiU6ZZ1Ar6y/2f4TblnMReQ==" | |||||
| "resolved" "https://registry.npmjs.org/immer/-/immer-9.0.16.tgz" | |||||
| "version" "9.0.16" | |||||
| "immer@^9.0.7": | "immer@^9.0.7": | ||||
| "integrity" "sha512-ubBeqQutOSLIFCUBN03jGeOS6a3DoYlSYwYJTa+gSKEZKU5redJIqkIdZ3JVv/4RZpfcXdAWH5zCNLWPRv2WDw==" | "integrity" "sha512-ubBeqQutOSLIFCUBN03jGeOS6a3DoYlSYwYJTa+gSKEZKU5redJIqkIdZ3JVv/4RZpfcXdAWH5zCNLWPRv2WDw==" | ||||
| "resolved" "https://registry.npmjs.org/immer/-/immer-9.0.14.tgz" | "resolved" "https://registry.npmjs.org/immer/-/immer-9.0.14.tgz" | ||||
| dependencies: | dependencies: | ||||
| "is-extglob" "^2.1.1" | "is-extglob" "^2.1.1" | ||||
| "is-hotkey@^0.1.6": | |||||
| "integrity" "sha512-qs3NZ1INIS+H+yeo7cD9pDfwYV/jqRh1JG9S9zYrNudkoUQg7OL7ziXqRKu+InFjUIDoP2o6HIkLYMh1pcWgyQ==" | |||||
| "resolved" "https://registry.npmjs.org/is-hotkey/-/is-hotkey-0.1.8.tgz" | |||||
| "version" "0.1.8" | |||||
| "is-installed-globally@^0.4.0": | "is-installed-globally@^0.4.0": | ||||
| "integrity" "sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==" | "integrity" "sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==" | ||||
| "resolved" "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.4.0.tgz" | "resolved" "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.4.0.tgz" | ||||
| dependencies: | dependencies: | ||||
| "isobject" "^3.0.1" | "isobject" "^3.0.1" | ||||
| "is-plain-object@^5.0.0": | |||||
| "integrity" "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==" | |||||
| "resolved" "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz" | |||||
| "version" "5.0.0" | |||||
| "is-potential-custom-element-name@^1.0.1": | "is-potential-custom-element-name@^1.0.1": | ||||
| "integrity" "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==" | "integrity" "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==" | ||||
| "resolved" "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz" | "resolved" "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz" | ||||
| "resolved" "https://registry.npmjs.org/lodash.unset/-/lodash.unset-4.5.2.tgz" | "resolved" "https://registry.npmjs.org/lodash.unset/-/lodash.unset-4.5.2.tgz" | ||||
| "version" "4.5.2" | "version" "4.5.2" | ||||
| "lodash@^4.17.11", "lodash@^4.17.14", "lodash@^4.17.15", "lodash@^4.17.19", "lodash@^4.17.20", "lodash@^4.17.21", "lodash@^4.17.5", "lodash@^4.7.0", "lodash@>=3.5 <5", "lodash@4": | |||||
| "lodash@^4.17.11", "lodash@^4.17.14", "lodash@^4.17.15", "lodash@^4.17.19", "lodash@^4.17.20", "lodash@^4.17.21", "lodash@^4.17.4", "lodash@^4.17.5", "lodash@^4.7.0", "lodash@>=3.5 <5", "lodash@4": | |||||
| "integrity" "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" | "integrity" "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" | ||||
| "resolved" "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz" | "resolved" "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz" | ||||
| "version" "4.17.21" | "version" "4.17.21" | ||||
| "strip-ansi" "6.0.0" | "strip-ansi" "6.0.0" | ||||
| "text-table" "0.2.0" | "text-table" "0.2.0" | ||||
| "react-dom@*", "react-dom@^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0", "react-dom@^16.6.0 || ^17.0.0 || ^18.0.0", "react-dom@^16.8.0 || ^17.0.0", "react-dom@^17.0.0 || ^18.0.0", "react-dom@^17.0.2", "react-dom@>= 16.8.0", "react-dom@>=16", "react-dom@>=16.6.0": | |||||
| "react-dom@*", "react-dom@^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0", "react-dom@^16.6.0 || ^17.0.0 || ^18.0.0", "react-dom@^16.8.0 || ^17.0.0", "react-dom@^17.0.0 || ^18.0.0", "react-dom@^17.0.2", "react-dom@>= 16.8.0", "react-dom@>=16", "react-dom@>=16.6.0", "react-dom@>=16.8.0": | |||||
| "integrity" "sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==" | "integrity" "sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==" | ||||
| "resolved" "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz" | "resolved" "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz" | ||||
| "version" "17.0.2" | "version" "17.0.2" | ||||
| "ajv" "^6.12.5" | "ajv" "^6.12.5" | ||||
| "ajv-keywords" "^3.5.2" | "ajv-keywords" "^3.5.2" | ||||
| "scroll-into-view-if-needed@^2.2.20": | |||||
| "integrity" "sha512-hxpAR6AN+Gh53AdAimHM6C8oTN1ppwVZITihix+WqalywBeFcQ6LdQP5ABNl26nX8GTEL7VT+b8lKpdqq65wXg==" | |||||
| "resolved" "https://registry.npmjs.org/scroll-into-view-if-needed/-/scroll-into-view-if-needed-2.2.29.tgz" | |||||
| "version" "2.2.29" | |||||
| dependencies: | |||||
| "compute-scroll-into-view" "^1.0.17" | |||||
| "section-iterator@^2.0.0": | "section-iterator@^2.0.0": | ||||
| "integrity" "sha512-xvTNwcbeDayXotnV32zLb3duQsP+4XosHpb/F+tu6VzEZFmIjzPdNk6/O+QOOx5XTh08KL2ufdXeCO33p380pQ==" | "integrity" "sha512-xvTNwcbeDayXotnV32zLb3duQsP+4XosHpb/F+tu6VzEZFmIjzPdNk6/O+QOOx5XTh08KL2ufdXeCO33p380pQ==" | ||||
| "resolved" "https://registry.npmjs.org/section-iterator/-/section-iterator-2.0.0.tgz" | "resolved" "https://registry.npmjs.org/section-iterator/-/section-iterator-2.0.0.tgz" | ||||
| "resolved" "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz" | "resolved" "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz" | ||||
| "version" "3.0.0" | "version" "3.0.0" | ||||
| "slate-react@^0.86.0": | |||||
| "integrity" "sha512-FlzG0CL1MtpZk7DRH6a101FdqdhTi+vZ23SbY5hQudIdgLo7QnUBv97BRe30VctqsL9L+Z2OsFHSCmWpIIxJAw==" | |||||
| "resolved" "https://registry.npmjs.org/slate-react/-/slate-react-0.86.0.tgz" | |||||
| "version" "0.86.0" | |||||
| dependencies: | |||||
| "@types/is-hotkey" "^0.1.1" | |||||
| "@types/lodash" "^4.14.149" | |||||
| "direction" "^1.0.3" | |||||
| "is-hotkey" "^0.1.6" | |||||
| "is-plain-object" "^5.0.0" | |||||
| "lodash" "^4.17.4" | |||||
| "scroll-into-view-if-needed" "^2.2.20" | |||||
| "tiny-invariant" "1.0.6" | |||||
| "slate@^0.86.0", "slate@>=0.65.3": | |||||
| "integrity" "sha512-aexL720Tpqx6St5oz0jo0/wZWCT7z8lChKkVJo2eiFkSNmoSnCGR62d2itAvmse7dEXkl4DbfAxRQPj8JDuGTg==" | |||||
| "resolved" "https://registry.npmjs.org/slate/-/slate-0.86.0.tgz" | |||||
| "version" "0.86.0" | |||||
| dependencies: | |||||
| "immer" "^9.0.6" | |||||
| "is-plain-object" "^5.0.0" | |||||
| "tiny-warning" "^1.0.3" | |||||
| "slice-ansi@^4.0.0": | "slice-ansi@^4.0.0": | ||||
| "integrity" "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==" | "integrity" "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==" | ||||
| "resolved" "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz" | "resolved" "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz" | ||||
| "resolved" "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.2.0.tgz" | "resolved" "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.2.0.tgz" | ||||
| "version" "1.2.0" | "version" "1.2.0" | ||||
| "tiny-invariant@1.0.6": | |||||
| "integrity" "sha512-FOyLWWVjG+aC0UqG76V53yAWdXfH8bO6FNmyZOuUrzDzK8DI3/JRY25UD7+g49JWM1LXwymsKERB+DzI0dTEQA==" | |||||
| "resolved" "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.0.6.tgz" | |||||
| "version" "1.0.6" | |||||
| "tiny-warning@^1.0.0", "tiny-warning@^1.0.2", "tiny-warning@^1.0.3": | "tiny-warning@^1.0.0", "tiny-warning@^1.0.2", "tiny-warning@^1.0.3": | ||||
| "integrity" "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==" | "integrity" "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==" | ||||
| "resolved" "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz" | "resolved" "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz" |