| <head> | <head> | ||||
| <meta charset="utf-8" /> | <meta charset="utf-8" /> | ||||
| <link rel="icon" href="%PUBLIC_URL%/favicon.png" /> | <link rel="icon" href="%PUBLIC_URL%/favicon.png" /> | ||||
| <link | |||||
| <!-- <link | |||||
| rel="stylesheet" | rel="stylesheet" | ||||
| type="text/css" | type="text/css" | ||||
| href="https://fonts.googleapis.com/css?family=Open+Sans:wght@700;600;500;400;300" | |||||
| /> | |||||
| href="https://fonts.googleapis.com/css?family=Open+Sans:wght@700;600;500;400;300&display=swap" | |||||
| /> --> | |||||
| <link | <link | ||||
| rel="stylesheet" | |||||
| type="text/css" | |||||
| href="https://fonts.googleapis.com/css?family=Poppins" | |||||
| rel="preload" | |||||
| as="style" | |||||
| href="https://fonts.googleapis.com/css?family=Poppins&display=swap" | |||||
| onload="this.onload=null;this.rel='stylesheet';this.type='text/css'" | |||||
| /> | /> | ||||
| <link | <link | ||||
| rel="stylesheet" | |||||
| type="text/css" | |||||
| href="https://fonts.googleapis.com/css?family=Mulish" | |||||
| style | |||||
| rel="preload" | |||||
| as="style" | |||||
| href="https://fonts.googleapis.com/css?family=Mulish&display=swap" | |||||
| onload="this.onload=null;this.rel='stylesheet';this.type='text/css'" | |||||
| /> | /> | ||||
| <link | <link | ||||
| rel="stylesheet" | |||||
| type="text/css" | |||||
| href="https://fonts.googleapis.com/css?family=DM+Sans:300,400,500,600,700,800" | |||||
| style | |||||
| rel="preload" | |||||
| as="style" | |||||
| href="https://fonts.googleapis.com/css?family=DM+Sans:300,400,500,600,700,800&display=swap" | |||||
| onload="this.onload=null;this.rel='stylesheet';this.type='text/css'" | |||||
| /> | /> | ||||
| <meta name="viewport" content="width=device-width, initial-scale=1" /> | <meta name="viewport" content="width=device-width, initial-scale=1" /> | ||||
| <meta name="theme-color" content="#000000" /> | <meta name="theme-color" content="#000000" /> |
| /*eslint-disable*/ | |||||
| import React, { useState, useEffect } from "react"; | |||||
| import React, { useEffect } from "react"; | |||||
| import { Router } from "react-router-dom"; | import { Router } from "react-router-dom"; | ||||
| import { Helmet } from "react-helmet-async"; | import { Helmet } from "react-helmet-async"; | ||||
| import { ToastContainer } from "react-toastify"; | |||||
| import { StyledEngineProvider } from "@mui/material"; | |||||
| import { useSelector } from "react-redux"; | |||||
| import i18next from "i18next"; | import i18next from "i18next"; | ||||
| import { selectUserId } from "./store/selectors/loginSelectors"; | |||||
| import history from "./store/utils/history"; | import history from "./store/utils/history"; | ||||
| import AppRoutes from "./AppRoutes"; | import AppRoutes from "./AppRoutes"; | ||||
| import { socketInit } from "./socket/socket"; | |||||
| import Header from "./components/Header/Header"; | import Header from "./components/Header/Header"; | ||||
| import { StyledEngineProvider } from "@mui/material"; | |||||
| import GlobalStyle from "./components/Styles/globalStyles"; | import GlobalStyle from "./components/Styles/globalStyles"; | ||||
| import { ToastContainer } from "react-toastify"; | |||||
| import "react-toastify/dist/ReactToastify.css"; | |||||
| import { socketInit } from "./socket/socket"; | |||||
| import { useSelector } from "react-redux"; | |||||
| import { selectUserId } from "./store/selectors/loginSelectors"; | |||||
| import Modal from "./components/Modals/Modal"; | import Modal from "./components/Modals/Modal"; | ||||
| import "react-toastify/dist/ReactToastify.css"; | |||||
| const App = () => { | const App = () => { | ||||
| const userId = useSelector(selectUserId); | const userId = useSelector(selectUserId); |
| /* eslint-disable */ | |||||
| import React from "react"; | import React from "react"; | ||||
| import { Redirect, Route, Switch, useLocation } from "react-router-dom"; | |||||
| import { Redirect, Route, Switch } from "react-router-dom"; | |||||
| import { | import { | ||||
| LOGIN_PAGE, | LOGIN_PAGE, | ||||
| ADMIN_LOGIN_PAGE, | ADMIN_LOGIN_PAGE, | ||||
| ITEM_DETAILS_PAGE, | ITEM_DETAILS_PAGE, | ||||
| FORGOT_PASSWORD_PAGE, | FORGOT_PASSWORD_PAGE, | ||||
| PROFILE_PAGE, | PROFILE_PAGE, | ||||
| CHAT_MESSAGE_PAGE, | |||||
| CHAT_PAGE, | |||||
| MY_OFFERS_PAGE, | MY_OFFERS_PAGE, | ||||
| // PRICES_PAGE, | |||||
| ABOUT_PAGE, | ABOUT_PAGE, | ||||
| ADMIN_HOME_PAGE, | ADMIN_HOME_PAGE, | ||||
| ADMIN_USERS_PAGE, | |||||
| ADMIN_CATEGORIES_PAGE, | |||||
| ADMIN_SUBCATEGORIES_PAGE, | |||||
| // POLICY_PRIVACY_PAGE, | |||||
| MESSAGES_LIST_PAGE, | |||||
| DIRECT_CHAT_PAGE, | |||||
| } from "./constants/pages"; | } from "./constants/pages"; | ||||
| // import SlideRoutes from "react-slide-routes"; | |||||
| 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 HomePage from "./pages/HomePage/HomePageMUI"; | |||||
| import HomePage from "./pages/HomePage/HomePage"; | |||||
| import NotFoundPage from "./pages/ErrorPages/NotFoundPage"; | import NotFoundPage from "./pages/ErrorPages/NotFoundPage"; | ||||
| import ErrorPage from "./pages/ErrorPages/ErrorPage"; | import ErrorPage from "./pages/ErrorPages/ErrorPage"; | ||||
| import ForgotPasswordPage from "./pages/ForgotPasswordPage/ForgotPasswordPage"; | import ForgotPasswordPage from "./pages/ForgotPasswordPage/ForgotPasswordPage"; | ||||
| import CreateOffer from "./pages/CreateOffer/CreateOffer"; | import CreateOffer from "./pages/CreateOffer/CreateOffer"; | ||||
| import ItemDetailsPage from "./pages/ItemDetailsPage/ItemDetailsPageMUI"; | import ItemDetailsPage from "./pages/ItemDetailsPage/ItemDetailsPageMUI"; | ||||
| import ProfilePage from "./pages/ProfilePage/ProfilePage"; | import ProfilePage from "./pages/ProfilePage/ProfilePage"; | ||||
| import ChatMessagesPage from "./pages/ChatMessages/ChatMessages"; | |||||
| import ChatPage from "./pages/Chat/Chat"; | |||||
| import DirectChatPage from "./pages/DirectChatPage/DirectChatPage"; | |||||
| import MessagesListPage from "./pages/MessagesListPage/MessagesListPage"; | |||||
| import MyOffers from "./pages/MyOffers/MyOffers"; | import MyOffers from "./pages/MyOffers/MyOffers"; | ||||
| // import PricesPage from "./pages/Prices/PricesPage"; | |||||
| import AboutPage from "./pages/About/AboutPage"; | import AboutPage from "./pages/About/AboutPage"; | ||||
| 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 PrivacyPolicyPage from "./pages/PrivacyPolicy/PrivacyPolicyPage"; | |||||
| const AppRoutes = () => { | const AppRoutes = () => { | ||||
| // const location = useLocation(); | |||||
| return ( | return ( | ||||
| <Switch> | <Switch> | ||||
| <Route exact path={BASE_PAGE} component={HomePage} /> | <Route exact path={BASE_PAGE} component={HomePage} /> | ||||
| <AuthRoute exact path={LOGIN_PAGE} component={LoginPage} /> | <AuthRoute exact path={LOGIN_PAGE} component={LoginPage} /> | ||||
| <AuthRoute exact path={ADMIN_LOGIN_PAGE} component={AdminLoginPage} /> | <AuthRoute exact path={ADMIN_LOGIN_PAGE} component={AdminLoginPage} /> | ||||
| <AdminRoute path={ADMIN_HOME_PAGE} component={AdminHomePage} /> | |||||
| <Route path={NOT_FOUND_PAGE} component={NotFoundPage} /> | |||||
| <Route path={ERROR_PAGE} component={ErrorPage} /> | |||||
| <Route path={REGISTER_SUCCESSFUL_PAGE} component={RegisterSuccessful} /> | |||||
| <AuthRoute path={REGISTER_PAGE} component={Register} /> | <AuthRoute path={REGISTER_PAGE} component={Register} /> | ||||
| <AuthRoute path={FORGOT_PASSWORD_MAIL_SENT} component={MailSent} /> | <AuthRoute path={FORGOT_PASSWORD_MAIL_SENT} component={MailSent} /> | ||||
| <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={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={PRICES_PAGE} component={PricesPage} /> */} | |||||
| <Route path={ABOUT_PAGE} component={AboutPage} /> | <Route path={ABOUT_PAGE} component={AboutPage} /> | ||||
| {/* <Route path={POLICY_PRIVACY_PAGE} component={PrivacyPolicyPage} /> */} | |||||
| <Route | |||||
| path={HOME_PAGE} | |||||
| component={(props) => { | |||||
| return <HomePage key={props.match.params.id} />; | |||||
| }} | |||||
| /> | |||||
| {/* <SlideRoutes location={location}> */} | |||||
| <PrivateRoute exact path={CHAT_PAGE} component={ChatPage} /> | |||||
| <PrivateRoute path={CHAT_MESSAGE_PAGE} component={ChatMessagesPage} /> | |||||
| {/* </SlideRoutes> */} | |||||
| <Route path={HOME_PAGE} component={HomePage} /> | |||||
| <PrivateRoute exact path={MESSAGES_LIST_PAGE} component={MessagesListPage} /> | |||||
| <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} /> | |||||
| <Route path={ERROR_PAGE} component={ErrorPage} /> | |||||
| <Route path={NOT_FOUND_PAGE} component={NotFoundPage} /> | |||||
| <Redirect from="*" to={NOT_FOUND_PAGE} /> | <Redirect from="*" to={NOT_FOUND_PAGE} /> | ||||
| </Switch> | </Switch> | ||||
| ); | ); |
| onClick={props.onClick} | onClick={props.onClick} | ||||
| sx={props.style} | sx={props.style} | ||||
| iconcolor={props.iconColor} | iconcolor={props.iconColor} | ||||
| {...props} | |||||
| > | > | ||||
| {props.children} | {props.children} | ||||
| </IconButtonStyled> | </IconButtonStyled> |
| myOffers={props.myOffers} | myOffers={props.myOffers} | ||||
| skeleton={props.skeleton} | skeleton={props.skeleton} | ||||
| > | > | ||||
| <SkeletonFilterCard skeleton={props.skeleton} /> | |||||
| {props?.skeleton && <SkeletonFilterCard skeleton={props.skeleton} />} | |||||
| {/* Header title for my offers */} | {/* Header title for my offers */} | ||||
| {props.myOffers && <HeaderBack />} | {props.myOffers && <HeaderBack />} | ||||
| setItemsSelected={props.setItemsSelected} | setItemsSelected={props.setItemsSelected} | ||||
| companies={props.companies} | companies={props.companies} | ||||
| > | > | ||||
| {dataToShow.map((item) => { | |||||
| return ( | |||||
| <DropdownItem key={item.city}> | |||||
| <Checkbox | |||||
| item={item} | |||||
| filters={props.filters} | |||||
| onChange={() => handleChange(item)} | |||||
| companies={props.companies} | |||||
| /> | |||||
| </DropdownItem> | |||||
| ); | |||||
| })} | |||||
| {(isOpened || props?.open) && | |||||
| dataToShow.map((item) => { | |||||
| return ( | |||||
| <DropdownItem key={item.city}> | |||||
| <Checkbox | |||||
| item={item} | |||||
| filters={props.filters} | |||||
| onChange={() => handleChange(item)} | |||||
| companies={props.companies} | |||||
| /> | |||||
| </DropdownItem> | |||||
| ); | |||||
| })} | |||||
| </CheckboxDropdownList> | </CheckboxDropdownList> | ||||
| ); | ); | ||||
| }; | }; |
| setItemsSelected={props.setItemsSelected} | setItemsSelected={props.setItemsSelected} | ||||
| companies={props.companies} | companies={props.companies} | ||||
| > | > | ||||
| <FilterSmallDropdown | |||||
| letters={t("filters.company.firstSort")} | |||||
| dataToShow={dataToShow} | |||||
| filters={props.filters} | |||||
| setItemsSelected={props.setItemsSelected} | |||||
| companies={props.companies} | |||||
| /> | |||||
| <FilterSmallDropdown | |||||
| letters={t("filters.company.secondSort")} | |||||
| dataToShow={dataToShow} | |||||
| filters={props.filters} | |||||
| setItemsSelected={props.setItemsSelected} | |||||
| companies={props.companies} | |||||
| /> | |||||
| <FilterSmallDropdown | |||||
| letters={t("filters.company.thirdSort")} | |||||
| dataToShow={dataToShow} | |||||
| filters={props.filters} | |||||
| setItemsSelected={props.setItemsSelected} | |||||
| companies={props.companies} | |||||
| /> | |||||
| {(isOpened || props?.open) && ( | |||||
| <> | |||||
| <FilterSmallDropdown | |||||
| letters={t("filters.company.firstSort")} | |||||
| dataToShow={dataToShow} | |||||
| filters={props.filters} | |||||
| setItemsSelected={props.setItemsSelected} | |||||
| companies={props.companies} | |||||
| /> | |||||
| <FilterSmallDropdown | |||||
| letters={t("filters.company.secondSort")} | |||||
| dataToShow={dataToShow} | |||||
| filters={props.filters} | |||||
| setItemsSelected={props.setItemsSelected} | |||||
| companies={props.companies} | |||||
| /> | |||||
| <FilterSmallDropdown | |||||
| letters={t("filters.company.thirdSort")} | |||||
| dataToShow={dataToShow} | |||||
| filters={props.filters} | |||||
| setItemsSelected={props.setItemsSelected} | |||||
| companies={props.companies} | |||||
| /> | |||||
| </> | |||||
| )} | |||||
| </CheckboxDropdownList> | </CheckboxDropdownList> | ||||
| ); | ); | ||||
| }; | }; |
| if ( | if ( | ||||
| props.selected?._id !== 0 && | props.selected?._id !== 0 && | ||||
| props.selected !== null && | props.selected !== null && | ||||
| props.selected !== undefined | |||||
| props.selected !== undefined && | |||||
| Object.keys(props.selected).length !== 0 | |||||
| ) { | ) { | ||||
| setIsOpened(true); | setIsOpened(true); | ||||
| } | } | ||||
| </React.Fragment> | </React.Fragment> | ||||
| } | } | ||||
| > | > | ||||
| <RadioGroup> | |||||
| {props.firstOption && ( | |||||
| <DropdownItem> | |||||
| <RadioButton | |||||
| value={props.firstOption.value} | |||||
| label={props.firstOption.label} | |||||
| // number={item.numberOfProducts} | |||||
| fullWidth | |||||
| checked={!props.selected || props.selected._id === 0} | |||||
| onChange={props.setSelected} | |||||
| /> | |||||
| </DropdownItem> | |||||
| )} | |||||
| {dataToShow.map((item) => { | |||||
| return ( | |||||
| <DropdownItem | |||||
| key={item.name} | |||||
| onClick={() => props.setSelected(item)} | |||||
| > | |||||
| {(isOpened || props?.open) && ( | |||||
| <RadioGroup> | |||||
| {props.firstOption && ( | |||||
| <DropdownItem> | |||||
| <RadioButton | <RadioButton | ||||
| value={item} | |||||
| label={item?.name ? item?.name : item?.length > 0 ? item : ""} | |||||
| number={item.offerCount} | |||||
| value={props.firstOption.value} | |||||
| label={props.firstOption.label} | |||||
| // number={item.numberOfProducts} | |||||
| fullWidth | fullWidth | ||||
| checked={ | |||||
| JSON.stringify(props.selected) === JSON.stringify(item) | |||||
| } | |||||
| checked={!props.selected || props.selected._id === 0} | |||||
| onChange={props.setSelected} | onChange={props.setSelected} | ||||
| /> | /> | ||||
| </DropdownItem> | </DropdownItem> | ||||
| ); | |||||
| })} | |||||
| </RadioGroup> | |||||
| )} | |||||
| {dataToShow.map((item) => { | |||||
| return ( | |||||
| <DropdownItem | |||||
| key={item.name} | |||||
| onClick={() => props.setSelected(item)} | |||||
| > | |||||
| <RadioButton | |||||
| value={item} | |||||
| label={item?.name ? item?.name : item?.length > 0 ? item : ""} | |||||
| number={item.offerCount} | |||||
| fullWidth | |||||
| checked={ | |||||
| JSON.stringify(props.selected) === JSON.stringify(item) | |||||
| } | |||||
| onChange={props.setSelected} | |||||
| /> | |||||
| </DropdownItem> | |||||
| ); | |||||
| })} | |||||
| </RadioGroup> | |||||
| )} | |||||
| </DropdownList> | </DropdownList> | ||||
| ); | ); | ||||
| }; | }; |
| ); | ); | ||||
| }; | }; | ||||
| const showPinOfferModalHandler = () => { | const showPinOfferModalHandler = () => { | ||||
| console.log(offer); | |||||
| dispatch( | dispatch( | ||||
| toggleDeleteOfferModal({ | toggleDeleteOfferModal({ | ||||
| offer: offer?.offer, | offer: offer?.offer, |
| ? images[index] | ? images[index] | ||||
| : getImageUrl(item, variants.offerCard, isMobile) | : getImageUrl(item, variants.offerCard, isMobile) | ||||
| } | } | ||||
| alt={t("offer.imageAlt")} | |||||
| key={item} | key={item} | ||||
| previewCard={props.previewCard} | previewCard={props.previewCard} | ||||
| onClick={() => | onClick={() => |
| import { getImageUrl, variants } from "../../../util/helpers/imageUrlGetter"; | import { getImageUrl, variants } from "../../../util/helpers/imageUrlGetter"; | ||||
| import history from "../../../store/utils/history"; | import history from "../../../store/utils/history"; | ||||
| import { replaceInRoute } from "../../../util/helpers/routeHelpers"; | import { replaceInRoute } from "../../../util/helpers/routeHelpers"; | ||||
| import { CHAT_MESSAGE_PAGE } from "../../../constants/pages"; | |||||
| import { DIRECT_CHAT_PAGE } from "../../../constants/pages"; | |||||
| import BlockedProfile from "../ProfileCard/BlockedProfile/BlockedProfile"; | import BlockedProfile from "../ProfileCard/BlockedProfile/BlockedProfile"; | ||||
| const MiniChatCard = (props) => { | const MiniChatCard = (props) => { | ||||
| const { isMobile } = useIsMobile(); | const { isMobile } = useIsMobile(); | ||||
| const changeChat = () => { | const changeChat = () => { | ||||
| history.push( | history.push( | ||||
| replaceInRoute(CHAT_MESSAGE_PAGE, { | |||||
| replaceInRoute(DIRECT_CHAT_PAGE, { | |||||
| idChat: props?.chat?.chat?._id, | idChat: props?.chat?.chat?._id, | ||||
| }) | }) | ||||
| ); | ); |
| const acceptExchange = (event) => { | const acceptExchange = (event) => { | ||||
| event.stopPropagation(); | event.stopPropagation(); | ||||
| console.log("props exchange"); | |||||
| props.acceptExchange(); | props.acceptExchange(); | ||||
| }; | }; | ||||
| return true; | return true; | ||||
| }, [userId, props.offer]); | }, [userId, props.offer]); | ||||
| console.log("props", props); | |||||
| return ( | return ( | ||||
| <React.Fragment> | <React.Fragment> | ||||
| <OfferCardContainer | <OfferCardContainer | ||||
| ) | ) | ||||
| : "" | : "" | ||||
| } | } | ||||
| alt={t("offer.imageAlt")} | |||||
| vertical={props.vertical} | vertical={props.vertical} | ||||
| ></OfferImage> | ></OfferImage> | ||||
| </OfferImageContainer> | </OfferImageContainer> | ||||
| <Tooltip title={t("messages.tooltip")}> | <Tooltip title={t("messages.tooltip")}> | ||||
| <TooltipInnerContainer> | <TooltipInnerContainer> | ||||
| <MessageIcon | <MessageIcon | ||||
| aria-label={t("labels.messageUser")} | |||||
| showMessageIcon={showMessageIcon} | showMessageIcon={showMessageIcon} | ||||
| vertical={props.vertical} | vertical={props.vertical} | ||||
| onClick={messageUser} | onClick={messageUser} |
| const SkeletonOfferCard = (props) => { | const SkeletonOfferCard = (props) => { | ||||
| const { isMobile } = useIsMobile(); | const { isMobile } = useIsMobile(); | ||||
| return ( | return ( | ||||
| <SkeletonOfferCardsContainer> | |||||
| <SkeletonOfferCardContainer | |||||
| vertical={props.vertical} | |||||
| skeleton={props.skeleton} | |||||
| > | |||||
| <SkeletonOfferCardsContainer skeleton={props.skeleton}> | |||||
| <SkeletonOfferCardContainer vertical={props.vertical}> | |||||
| <SkeletonTitleAboveImage vertical={props.vertical} /> | <SkeletonTitleAboveImage vertical={props.vertical} /> | ||||
| <LeftPart vertical={props.vertical}> | <LeftPart vertical={props.vertical}> | ||||
| <SkeletonImage vertical={props.vertical} /> | <SkeletonImage vertical={props.vertical} /> | ||||
| vertical: PropTypes.bool, | vertical: PropTypes.bool, | ||||
| aboveChat: PropTypes.bool, | aboveChat: PropTypes.bool, | ||||
| }; | }; | ||||
| SkeletonOfferCard.defaultProps = { | |||||
| skeleton: false, | |||||
| vertical: false, | |||||
| aboveChat: false, | |||||
| }; | |||||
| export default SkeletonOfferCard; | export default SkeletonOfferCard; |
| } from "../../../Styles/globalStyleComponents"; | } from "../../../Styles/globalStyleComponents"; | ||||
| export const SkeletonOfferCardsContainer = styled(Box)` | export const SkeletonOfferCardsContainer = styled(Box)` | ||||
| display: flex; | |||||
| display: ${props => props.skeleton ? "flex" : "none"}; | |||||
| `; | `; | ||||
| export const SkeletonOfferCardContainer = styled(BackgroundTransition)` | export const SkeletonOfferCardContainer = styled(BackgroundTransition)` |
| () => exchange?.buyer?.userId === userId, | () => exchange?.buyer?.userId === userId, | ||||
| [exchange, userId] | [exchange, userId] | ||||
| ); | ); | ||||
| console.log("requester", requester); | |||||
| console.log("exchange: ", exchange); | |||||
| const haveIAccepted = useMemo( | const haveIAccepted = useMemo( | ||||
| () => (amIBuyer ? exchange?.buyer?.accepted : exchange?.seller?.accepted), | () => (amIBuyer ? exchange?.buyer?.accepted : exchange?.seller?.accepted), | ||||
| [amIBuyer, exchange] | [amIBuyer, exchange] | ||||
| ); | ); | ||||
| console.log(haveIAccepted) | |||||
| const interlucatorUserId = useMemo( | const interlucatorUserId = useMemo( | ||||
| () => (amIBuyer ? exchange?.seller?.userId : exchange?.buyer?.userId), | () => (amIBuyer ? exchange?.seller?.userId : exchange?.buyer?.userId), | ||||
| [exchange, amIBuyer] | [exchange, amIBuyer] |
| ToggleContainer, | ToggleContainer, | ||||
| } from "./DropdownList.styled"; | } from "./DropdownList.styled"; | ||||
| import PropTypes from "prop-types"; | import PropTypes from "prop-types"; | ||||
| import { useTranslation } from "react-i18next"; | |||||
| const DropdownList = (props) => { | const DropdownList = (props) => { | ||||
| const [listShown, setListShown] = useState(props.defaultOpen); | const [listShown, setListShown] = useState(props.defaultOpen); | ||||
| const { t } = useTranslation(); | |||||
| useEffect(() => { | useEffect(() => { | ||||
| if (props.open !== null || props.open !== undefined) | if (props.open !== null || props.open !== undefined) | ||||
| setListShown(props.open); | setListShown(props.open); | ||||
| }, [props.open]); | }, [props.open]); | ||||
| const handleShow = () => { | const handleShow = () => { | ||||
| if (props.setIsOpened) | |||||
| props.setIsOpened(!listShown); | |||||
| if (!props.disabled) | |||||
| setListShown((prevState) => !prevState); | |||||
| if (props.setIsOpened) props.setIsOpened(!listShown); | |||||
| if (!props.disabled) setListShown((prevState) => !prevState); | |||||
| if (!(props.open !== null || props.open !== undefined)) | if (!(props.open !== null || props.open !== undefined)) | ||||
| setListShown((prevState) => !prevState); | setListShown((prevState) => !prevState); | ||||
| }; | }; | ||||
| return ( | return ( | ||||
| <DropdownListContainer fullwidth={props.fullWidth ? 1 : 0}> | <DropdownListContainer fullwidth={props.fullWidth ? 1 : 0}> | ||||
| <DropdownHeader> | <DropdownHeader> | ||||
| {props.dropdownIcon && ( | {props.dropdownIcon && ( | ||||
| <DropdownIcon | <DropdownIcon | ||||
| aria-label={t("labels.dropdownIcon")} | |||||
| onClick={!props.disabled ? () => handleShow() : () => {}} | onClick={!props.disabled ? () => handleShow() : () => {}} | ||||
| disabled={props.disabled} | disabled={props.disabled} | ||||
| > | > | ||||
| : listShown | : listShown | ||||
| ) ? ( | ) ? ( | ||||
| <ToggleIconOpened | <ToggleIconOpened | ||||
| aria-label={t("labels.dropdownClose")} | |||||
| style={props.toggleIconStyles} | style={props.toggleIconStyles} | ||||
| onClick={!props.disabled ? () => handleShow() : () => {}} | onClick={!props.disabled ? () => handleShow() : () => {}} | ||||
| > | > | ||||
| </ToggleIconOpened> | </ToggleIconOpened> | ||||
| ) : ( | ) : ( | ||||
| <ToggleIconClosed | <ToggleIconClosed | ||||
| aria-label={t("labels.dropdownOpen")} | |||||
| style={props.toggleIconStyles} | style={props.toggleIconStyles} | ||||
| onClick={!props.disabled ? () => handleShow() : () => {}} | onClick={!props.disabled ? () => handleShow() : () => {}} | ||||
| disabled={props.disabled} | disabled={props.disabled} |
| import { useTranslation } from "react-i18next"; | import { useTranslation } from "react-i18next"; | ||||
| import { MailIcon } from "./MyMessagesButton.styled"; | import { MailIcon } from "./MyMessagesButton.styled"; | ||||
| import history from "../../../../../store/utils/history"; | import history from "../../../../../store/utils/history"; | ||||
| import { CHAT_PAGE } from "../../../../../constants/pages"; | |||||
| import { MESSAGES_LIST_PAGE } from "../../../../../constants/pages"; | |||||
| const MyMessagesButton = (props) => { | const MyMessagesButton = (props) => { | ||||
| const { t } = useTranslation(); | const { t } = useTranslation(); | ||||
| const handleClick = () => { | const handleClick = () => { | ||||
| props.toggleDrawer(); | props.toggleDrawer(); | ||||
| history.push(CHAT_PAGE); | |||||
| history.push(MESSAGES_LIST_PAGE); | |||||
| }; | }; | ||||
| return ( | return ( | ||||
| <DrawerButton onClick={handleClick}> | <DrawerButton onClick={handleClick}> |
| import { MyMessages } from "../../Popovers/MyMessages/MyMessages"; | import { MyMessages } from "../../Popovers/MyMessages/MyMessages"; | ||||
| import { useLocation } from "react-router-dom"; | import { useLocation } from "react-router-dom"; | ||||
| import { useEffect } from "react"; | import { useEffect } from "react"; | ||||
| import { useTranslation } from "react-i18next"; | |||||
| const MyMessagesButton = () => { | const MyMessagesButton = () => { | ||||
| const location = useLocation(); | const location = useLocation(); | ||||
| const { t } = useTranslation(); | |||||
| const [msgPopoverOpen, setMsgPopoverOpen] = useState(false); | const [msgPopoverOpen, setMsgPopoverOpen] = useState(false); | ||||
| const [msgAnchorEl, setMsgAnchorEl] = useState(null); | const [msgAnchorEl, setMsgAnchorEl] = useState(null); | ||||
| useEffect(() => { | useEffect(() => { | ||||
| return ( | return ( | ||||
| <> | <> | ||||
| <IconButton | <IconButton | ||||
| aria-label={t("header.myMessages")} | |||||
| onClick={openMsgPopover} | onClick={openMsgPopover} | ||||
| style={{ | style={{ | ||||
| background: selectedTheme.colors.primaryIconBackgroundColor, | background: selectedTheme.colors.primaryIconBackgroundColor, |
| import { useState } from "react"; | import { useState } from "react"; | ||||
| import { useEffect } from "react"; | import { useEffect } from "react"; | ||||
| import { useLocation } from "react-router-dom"; | import { useLocation } from "react-router-dom"; | ||||
| import { useTranslation } from "react-i18next"; | |||||
| const MySwapsButton = (props) => { | const MySwapsButton = (props) => { | ||||
| const {t} = useTranslation(); | |||||
| const location = useLocation(); | const location = useLocation(); | ||||
| const [postsPopoverOpen, setPostsPopoverOpen] = useState(false); | const [postsPopoverOpen, setPostsPopoverOpen] = useState(false); | ||||
| const [postsAnchorEl, setPostsAnchorEl] = useState(null); | const [postsAnchorEl, setPostsAnchorEl] = useState(null); | ||||
| return ( | return ( | ||||
| <> | <> | ||||
| <IconButton | <IconButton | ||||
| aria-label={t("header.myOffers")} | |||||
| onClick={openPostsPopover} | onClick={openPostsPopover} | ||||
| style={{ | style={{ | ||||
| background: selectedTheme.colors.primaryIconBackgroundColor, | background: selectedTheme.colors.primaryIconBackgroundColor, |
| }; | }; | ||||
| const listener = useCallback( | const listener = useCallback( | ||||
| (event) => { | (event) => { | ||||
| console.log(event); | |||||
| console.log(ref); | |||||
| if (event.keyCode === 13) { | if (event.keyCode === 13) { | ||||
| event.preventDefault(); | event.preventDefault(); | ||||
| handleManualSearch(); | handleManualSearch(); |
| import { useState } from "react"; | import { useState } from "react"; | ||||
| import { useEffect } from "react"; | import { useEffect } from "react"; | ||||
| import { useLocation } from "react-router-dom"; | import { useLocation } from "react-router-dom"; | ||||
| import { useTranslation } from "react-i18next"; | |||||
| const UserButton = (props) => { | const UserButton = (props) => { | ||||
| const location = useLocation(); | const location = useLocation(); | ||||
| const {t} = useTranslation(); | |||||
| const [userPopoverOpen, setUserPopoverOpen] = useState(false); | const [userPopoverOpen, setUserPopoverOpen] = useState(false); | ||||
| const [userAnchorEl, setUserAnchorEl] = useState(null); | const [userAnchorEl, setUserAnchorEl] = useState(null); | ||||
| <UserButtonContainer onClick={openUserPopover}> | <UserButtonContainer onClick={openUserPopover}> | ||||
| <UserName>{props.name}</UserName> | <UserName>{props.name}</UserName> | ||||
| <IconButton | <IconButton | ||||
| aria-label={t("header.myProfile")} | |||||
| style={{ | style={{ | ||||
| background: selectedTheme.colors.primaryIconBackgroundColor, | background: selectedTheme.colors.primaryIconBackgroundColor, | ||||
| color: selectedTheme.colors.primaryPurple, | color: selectedTheme.colors.primaryPurple, |
| import React from "react"; | |||||
| import PropTypes from "prop-types"; | |||||
| import { | |||||
| GridButton, | |||||
| GridButtonsContainer, | |||||
| GridLineIcon, | |||||
| GridSquareIcon, | |||||
| } from "./GridButtons.styled"; | |||||
| import selectedTheme from "../../../../themes"; | |||||
| const GridButtons = (props) => { | |||||
| return ( | |||||
| <GridButtonsContainer hideGrid={props?.hideGrid}> | |||||
| {/* Setting display of offer cards to full width */} | |||||
| <GridButton | |||||
| iconColor={ | |||||
| props?.isGrid | |||||
| ? selectedTheme.colors.iconStrokeColor | |||||
| : selectedTheme.colors.primaryPurple | |||||
| } | |||||
| onClick={() => props?.setIsGrid(false)} | |||||
| > | |||||
| <GridLineIcon /> | |||||
| </GridButton> | |||||
| {/* ^^^^^^ */} | |||||
| {/* Setting display of offer cards to half width (Grid) */} | |||||
| <GridButton | |||||
| iconColor={ | |||||
| props?.isGrid | |||||
| ? selectedTheme.colors.primaryPurple | |||||
| : selectedTheme.colors.iconStrokeColor | |||||
| } | |||||
| onClick={() => props?.setIsGrid(true)} | |||||
| > | |||||
| <GridSquareIcon /> | |||||
| </GridButton> | |||||
| {/* ^^^^^^ */} | |||||
| </GridButtonsContainer> | |||||
| ); | |||||
| }; | |||||
| GridButtons.propTypes = { | |||||
| isGrid: PropTypes.bool, | |||||
| setIsGrid: PropTypes.func, | |||||
| hideGrid: PropTypes.bool, | |||||
| }; | |||||
| GridButtons.defaultProps = { | |||||
| isGrid: false, | |||||
| setIsGrid: () => {}, | |||||
| hideGrid: false, | |||||
| }; | |||||
| export default GridButtons; |
| import { Box } from "@mui/material"; | |||||
| import styled from "styled-components"; | |||||
| import { IconButton } from "../../../Buttons/IconButton/IconButton"; | |||||
| import { ReactComponent as GridSquare } from "../../../../assets/images/svg/offer-grid-square.svg"; | |||||
| import { ReactComponent as GridLine } from "../../../../assets/images/svg/offer-grid-line.svg"; | |||||
| export const GridButton = styled(IconButton)` | |||||
| padding: 2px 10px; | |||||
| @media (max-width: 1500px) { | |||||
| display: none; | |||||
| } | |||||
| `; | |||||
| export const GridButtonsContainer = styled(Box)` | |||||
| flex-direction: row; | |||||
| display: ${(props) => (props.hideGrid ? "none" : "flex")}; | |||||
| justify-content: space-between; | |||||
| margin-right: 40px; | |||||
| `; | |||||
| export const GridSquareIcon = styled(GridSquare)``; | |||||
| export const GridLineIcon = styled(GridLine)``; |
| import React, { useMemo } from "react"; | import React, { useMemo } from "react"; | ||||
| import PropTypes from "prop-types"; | import PropTypes from "prop-types"; | ||||
| import { | import { | ||||
| ButtonContainer, | |||||
| CategoryHeaderIcon, | |||||
| CategoryIcon, | CategoryIcon, | ||||
| HeaderAltLocation, | |||||
| HeaderButton, | |||||
| HeaderButtons, | |||||
| HeaderCategoryString, | |||||
| HeaderCompanyString, | |||||
| HeaderContainer, | HeaderContainer, | ||||
| HeaderLocation, | |||||
| HeaderLocationsMainString, | |||||
| HeaderLocationsString, | |||||
| HeaderOptions, | HeaderOptions, | ||||
| HeaderSelect, | |||||
| HeaderSubcategoryString, | |||||
| HeaderText, | |||||
| HeaderTitleContainer, | |||||
| HeaderTitleText, | |||||
| HeaderWrapperContainer, | HeaderWrapperContainer, | ||||
| IconStyled, | |||||
| LocationIcon, | LocationIcon, | ||||
| PageTitleContainer, | PageTitleContainer, | ||||
| SelectOption, | |||||
| SubcategoryIcon, | SubcategoryIcon, | ||||
| SwapsHeaderIcon, | SwapsHeaderIcon, | ||||
| SwapsIcon, | SwapsIcon, | ||||
| SwapsTitle, | SwapsTitle, | ||||
| TooltipInnerContainer, | |||||
| UserIcon, | UserIcon, | ||||
| } from "./Header.styled"; | } from "./Header.styled"; | ||||
| import { ReactComponent as GridSquare } from "../../../assets/images/svg/offer-grid-square.svg"; | |||||
| import { ReactComponent as GridLine } from "../../../assets/images/svg/offer-grid-line.svg"; | |||||
| import { ReactComponent as Down } from "../../../assets/images/svg/down-arrow.svg"; | |||||
| import selectedTheme from "../../../themes"; | |||||
| import { sortEnum } from "../../../enums/sortEnum"; | import { sortEnum } from "../../../enums/sortEnum"; | ||||
| import { useTranslation } from "react-i18next"; | import { useTranslation } from "react-i18next"; | ||||
| import { Tooltip } from "@mui/material"; | |||||
| import SkeletonHeader from "./SkeletonHeader/SkeletonHeader"; | import SkeletonHeader from "./SkeletonHeader/SkeletonHeader"; | ||||
| import { useSelector } from "react-redux"; | |||||
| import { selectHeaderString } from "../../../store/selectors/filtersSelectors"; | |||||
| import useIsMobile from "../../../hooks/useIsMobile"; | import useIsMobile from "../../../hooks/useIsMobile"; | ||||
| import { ArrowButton } from "../../Buttons/ArrowButton/ArrowButton"; | |||||
| // import { ArrowButton } from "../../Buttons/ArrowButton/ArrowButton"; | |||||
| import history from "../../../store/utils/history"; | |||||
| const DownArrow = (props) => ( | |||||
| <IconStyled {...props}> | |||||
| <Down /> | |||||
| </IconStyled> | |||||
| ); | |||||
| // import { ArrowButton } from "../../Buttons/ArrowButton/ArrowButton"; | |||||
| import TooltipHeader from "./TooltipHeader/TooltipHeader"; | |||||
| import GridButtons from "./GridButtons/GridButtons"; | |||||
| import HeaderSelect from "./HeaderSelect/HeaderSelect"; | |||||
| const Header = (props) => { | const Header = (props) => { | ||||
| const { t } = useTranslation(); | const { t } = useTranslation(); | ||||
| const sorting = props?.sorting; | const sorting = props?.sorting; | ||||
| const headerString = useSelector(selectHeaderString); | |||||
| const { isMobile } = useIsMobile(); | const { isMobile } = useIsMobile(); | ||||
| // Changing header string on refresh or on load | // Changing header string on refresh or on load | ||||
| ); | ); | ||||
| }); | }); | ||||
| const handleChangeSelect = (event) => { | |||||
| sorting?.changeSorting(event.target.value); | |||||
| }; | |||||
| const handleClickCategory = () => { | |||||
| props?.offers?.filters?.locations.clear(); | |||||
| props?.offers?.filters?.subcategory.clear(); | |||||
| props?.offers?.applyFilters(); | |||||
| }; | |||||
| const handleClickSubcategory = () => { | |||||
| props?.offers?.filters?.locations.clear(); | |||||
| props?.offers?.applyFilters(); | |||||
| }; | |||||
| const goBack = () => { | |||||
| history.goBack(); | |||||
| }; | |||||
| return ( | return ( | ||||
| <> | <> | ||||
| <SkeletonHeader skeleton={props?.skeleton} myOffers={props?.myOffers} /> | |||||
| {props?.skeleton && ( | |||||
| <SkeletonHeader skeleton={props?.skeleton} myOffers={props?.myOffers} /> | |||||
| )} | |||||
| <HeaderWrapperContainer | <HeaderWrapperContainer | ||||
| className={props.className} | className={props.className} | ||||
| skeleton={props?.skeleton} | skeleton={props?.skeleton} | ||||
| > | > | ||||
| <HeaderContainer> | <HeaderContainer> | ||||
| {/* Setting appropriate header title if page is market place or my offers */} | {/* Setting appropriate header title if page is market place or my offers */} | ||||
| <Tooltip title={headerString.text}> | |||||
| <TooltipInnerContainer> | |||||
| {!props?.myOffers ? ( | |||||
| <> | |||||
| <CategoryHeaderIcon /> | |||||
| <HeaderLocation> | |||||
| {/* {headerString} */} | |||||
| <HeaderCategoryString | |||||
| component="span" | |||||
| onClick={handleClickCategory} | |||||
| > | |||||
| {headerString.categoryString} | |||||
| {/* {headerString.subcategoryString && <> </>} */} | |||||
| </HeaderCategoryString> | |||||
| <HeaderSubcategoryString | |||||
| component="span" | |||||
| onClick={handleClickSubcategory} | |||||
| > | |||||
| {headerString.subcategoryString} | |||||
| {/* {headerString.locationsString && <> </>} */} | |||||
| </HeaderSubcategoryString> | |||||
| <HeaderLocationsString component="span"> | |||||
| <HeaderLocationsMainString component="span"> | |||||
| {headerString.locationsString} | |||||
| </HeaderLocationsMainString> | |||||
| <HeaderCompanyString> | |||||
| {headerString.companiesString} | |||||
| </HeaderCompanyString> | |||||
| <HeaderAltLocation component="span"> | |||||
| {altString} | |||||
| </HeaderAltLocation> | |||||
| </HeaderLocationsString> | |||||
| </HeaderLocation> | |||||
| </> | |||||
| ) : ( | |||||
| <> | |||||
| {!isMobile ? ( | |||||
| <HeaderTitleContainer> | |||||
| {headerIcon} | |||||
| <HeaderTitleText>{headerTitle}</HeaderTitleText> | |||||
| </HeaderTitleContainer> | |||||
| ) : ( | |||||
| !props.hideBackButton && ( | |||||
| <ButtonContainer onClick={goBack}> | |||||
| <ArrowButton side={"left"}></ArrowButton> | |||||
| <HeaderText>{t("messages.goBack")}</HeaderText> | |||||
| </ButtonContainer> | |||||
| ) | |||||
| )} | |||||
| </> | |||||
| )} | |||||
| </TooltipInnerContainer> | |||||
| </Tooltip> | |||||
| <TooltipHeader | |||||
| altText={altString} | |||||
| headerTitle={headerTitle} | |||||
| headerIcon={headerIcon} | |||||
| offers={props?.offers} | |||||
| hideBackButton={props?.hideBackButton} | |||||
| /> | |||||
| {/* ^^^^^^ */} | {/* ^^^^^^ */} | ||||
| <HeaderOptions> | <HeaderOptions> | ||||
| {!props.hideGrid && ( | |||||
| <HeaderButtons> | |||||
| {/* Setting display of offer cards to full width */} | |||||
| <HeaderButton | |||||
| iconColor={ | |||||
| props?.isGrid | |||||
| ? selectedTheme.colors.iconStrokeColor | |||||
| : selectedTheme.colors.primaryPurple | |||||
| } | |||||
| onClick={() => props?.setIsGrid(false)} | |||||
| > | |||||
| <GridLine /> | |||||
| </HeaderButton> | |||||
| {/* ^^^^^^ */} | |||||
| {/* Setting display of offer cards to half width (Grid) */} | |||||
| <HeaderButton | |||||
| iconColor={ | |||||
| props?.isGrid | |||||
| ? selectedTheme.colors.primaryPurple | |||||
| : selectedTheme.colors.iconStrokeColor | |||||
| } | |||||
| onClick={() => props?.setIsGrid(true)} | |||||
| > | |||||
| <GridSquare /> | |||||
| </HeaderButton> | |||||
| {/* ^^^^^^ */} | |||||
| </HeaderButtons> | |||||
| )} | |||||
| <GridButtons | |||||
| hideGrid={props?.hideGrid} | |||||
| isGrid={props?.isGrid} | |||||
| setIsGrid={props?.setIsGrid} | |||||
| /> | |||||
| {/* Select option to choose sorting */} | {/* Select option to choose sorting */} | ||||
| {!props.hideSorting && ( | |||||
| <HeaderSelect | |||||
| value={ | |||||
| sorting?.selectedSortOption?.value | |||||
| ? sorting?.selectedSortOption | |||||
| : "default" | |||||
| } | |||||
| IconComponent={DownArrow} | |||||
| onChange={handleChangeSelect} | |||||
| myOffers={props?.myOffers} | |||||
| > | |||||
| <SelectOption style={{ display: "none" }} value="default"> | |||||
| {t("reviews.sortBy")} | |||||
| </SelectOption> | |||||
| {Object.keys(sorting?.sortOptions).map((property) => { | |||||
| if (sorting?.sortOptions[property].value === 0) return; | |||||
| return ( | |||||
| <SelectOption | |||||
| value={sorting?.sortOptions[property]} | |||||
| key={sorting?.sortOptions[property].value} | |||||
| > | |||||
| {sorting?.sortOptions[property].mainText} | |||||
| </SelectOption> | |||||
| ); | |||||
| })} | |||||
| </HeaderSelect> | |||||
| )} | |||||
| <HeaderSelect | |||||
| myOffers={props?.myOffers} | |||||
| sorting={sorting} | |||||
| hideSorting={props?.hideSorting} | |||||
| /> | |||||
| {/* ^^^^^^ */} | {/* ^^^^^^ */} | ||||
| </HeaderOptions> | </HeaderOptions> | ||||
| </HeaderContainer> | </HeaderContainer> |
| import { Box, Link, MenuItem, Typography } from "@mui/material"; | |||||
| import { Box, Typography } from "@mui/material"; | |||||
| import styled from "styled-components"; | import styled from "styled-components"; | ||||
| import selectedTheme from "../../../themes"; | import selectedTheme from "../../../themes"; | ||||
| import { IconButton } from "../../Buttons/IconButton/IconButton"; | |||||
| import Option from "../../Select/Option/Option"; | |||||
| import Select from "../../Select/Select"; | |||||
| import { ReactComponent as Swaps } from "../../../assets/images/svg/swaps.svg"; | import { ReactComponent as Swaps } from "../../../assets/images/svg/swaps.svg"; | ||||
| import { ReactComponent as CategoryHeader } from "../../../assets/images/svg/category-header.svg"; | |||||
| import { ReactComponent as User } from "../../../assets/images/svg/user.svg"; | import { ReactComponent as User } from "../../../assets/images/svg/user.svg"; | ||||
| import { ReactComponent as Category } from "../../../assets/images/svg/category.svg"; | import { ReactComponent as Category } from "../../../assets/images/svg/category.svg"; | ||||
| import { ReactComponent as Subcategory } from "../../../assets/images/svg/subcategory.svg"; | import { ReactComponent as Subcategory } from "../../../assets/images/svg/subcategory.svg"; | ||||
| justify-content: space-between; | justify-content: space-between; | ||||
| align-items: center; | align-items: center; | ||||
| `; | `; | ||||
| export const TooltipInnerContainer = styled(Box)` | |||||
| width: 100%; | |||||
| white-space: nowrap; | |||||
| overflow: hidden; | |||||
| text-overflow: ellipsis; | |||||
| & * { | |||||
| display: inline; | |||||
| } | |||||
| `; | |||||
| export const HeaderLocation = styled(Typography)` | |||||
| font-family: ${selectedTheme.fonts.textFont}; | |||||
| color: ${selectedTheme.colors.primaryPurple}; | |||||
| font-weight: 700; | |||||
| line-height: 22px; | |||||
| font-size: 16px; | |||||
| flex: 2; | |||||
| margin-left: 9px; | |||||
| max-width: 50%; | |||||
| position: relative; | |||||
| top: -2px; | |||||
| &:after { | |||||
| content: ${(props) => (props.initial ? `":"` : `""`)}; | |||||
| @media (max-width: 600px) { | |||||
| content: ""; | |||||
| } | |||||
| } | |||||
| @media (max-width: 600px) { | |||||
| font-size: 12px; | |||||
| padding-top: 3px; | |||||
| } | |||||
| `; | |||||
| export const HeaderCategoryString = styled(Typography)` | |||||
| font-family: ${selectedTheme.fonts.textFont}; | |||||
| color: ${selectedTheme.colors.primaryPurple}; | |||||
| font-weight: 700; | |||||
| line-height: 22px; | |||||
| font-size: 16px; | |||||
| /* position: relative; | |||||
| bottom: 2px; */ | |||||
| cursor: pointer; | |||||
| @media (max-width: 600px) { | |||||
| font-size: 12px; | |||||
| padding-top: 3px; | |||||
| } | |||||
| `; | |||||
| export const HeaderSubcategoryString = styled(Typography)` | |||||
| font-family: ${selectedTheme.fonts.textFont}; | |||||
| color: ${selectedTheme.colors.primaryPurple}; | |||||
| font-weight: 700; | |||||
| line-height: 22px; | |||||
| font-size: 16px; | |||||
| /* position: relative; | |||||
| bottom: 2px; */ | |||||
| cursor: pointer; | |||||
| @media (max-width: 600px) { | |||||
| font-size: 12px; | |||||
| padding-top: 3px; | |||||
| } | |||||
| `; | |||||
| export const HeaderLocationsString = styled(Typography)` | |||||
| /* position: relative; | |||||
| bottom: 2px; */ | |||||
| white-space: nowrap; | |||||
| overflow: hidden; | |||||
| text-overflow: ellipsis; | |||||
| @media (max-width: 600px) { | |||||
| font-size: 12px; | |||||
| padding-top: 3px; | |||||
| } | |||||
| max-width: 100%; | |||||
| `; | |||||
| export const HeaderLocationsMainString = styled(Typography)` | |||||
| font-family: ${selectedTheme.fonts.textFont}; | |||||
| max-width: 200px; | |||||
| color: ${selectedTheme.colors.primaryPurple}; | |||||
| font-weight: 700; | |||||
| line-height: 22px; | |||||
| font-size: 16px; | |||||
| @media (max-width: 600px) { | |||||
| font-size: 12px; | |||||
| padding-top: 3px; | |||||
| } | |||||
| `; | |||||
| export const HeaderCompanyString = styled(Typography)` | |||||
| font-family: ${selectedTheme.fonts.textFont}; | |||||
| max-width: 200px; | |||||
| color: ${selectedTheme.colors.primaryPurple}; | |||||
| font-weight: 700; | |||||
| line-height: 22px; | |||||
| font-size: 16px; | |||||
| @media (max-width: 600px) { | |||||
| font-size: 12px; | |||||
| padding-top: 3px; | |||||
| } | |||||
| `; | |||||
| export const HeaderButton = styled(IconButton)` | |||||
| padding: 2px 10px; | |||||
| @media (max-width: 1500px) { | |||||
| display: none; | |||||
| } | |||||
| `; | |||||
| export const HeaderOptions = styled(Box)` | export const HeaderOptions = styled(Box)` | ||||
| display: flex; | display: flex; | ||||
| flex-direction: row; | flex-direction: row; | ||||
| flex: 1; | flex: 1; | ||||
| justify-content: end; | justify-content: end; | ||||
| `; | `; | ||||
| export const HeaderSelect = styled(Select)` | |||||
| width: 210px; | |||||
| height: 35px; | |||||
| font-family: ${selectedTheme.fonts.textFont}; | |||||
| margin-top: 3px; | |||||
| font-weight: 400; | |||||
| position: relative; | |||||
| left: -5px; | |||||
| background-color: white; | |||||
| & div:first-child { | |||||
| padding-left: 8px; | |||||
| } | |||||
| @media (max-width: 650px) { | |||||
| width: 144px; | |||||
| height: 30px; | |||||
| font-size: 14px; | |||||
| top: 60px; | |||||
| left: ${(props) => (props.myOffers ? "-7px" : "0")}; | |||||
| } | |||||
| `; | |||||
| export const SelectItem = styled(MenuItem)` | |||||
| font-family: ${selectedTheme.fonts.textFont}; | |||||
| `; | |||||
| export const SelectOption = styled(Option)` | |||||
| @media (max-width: 600px) { | |||||
| height: 20px !important; | |||||
| min-height: 35px; | |||||
| margin: 2px; | |||||
| } | |||||
| `; | |||||
| export const IconStyled = styled(Box)` | export const IconStyled = styled(Box)` | ||||
| position: relative; | position: relative; | ||||
| top: 0; | top: 0; | ||||
| right: 10px; | right: 10px; | ||||
| `; | `; | ||||
| export const HeaderButtons = styled(Box)` | |||||
| flex-direction: row; | |||||
| display: flex; | |||||
| justify-content: space-between; | |||||
| margin-right: 40px; | |||||
| `; | |||||
| export const HeaderAltLocation = styled(Typography)` | |||||
| font-family: ${selectedTheme.fonts.textFont}; | |||||
| font-size: 16px; | |||||
| color: ${selectedTheme.colors.primaryText}; | |||||
| position: relative; | |||||
| top: 0.5px; | |||||
| @media (max-width: 600px) { | |||||
| display: none; | |||||
| } | |||||
| `; | |||||
| export const RefreshIcon = styled(Swaps)` | export const RefreshIcon = styled(Swaps)` | ||||
| width: 18px; | width: 18px; | ||||
| height: 18px; | height: 18px; | ||||
| position: relative; | position: relative; | ||||
| left: 9px; | left: 9px; | ||||
| `; | `; | ||||
| export const CategoryHeaderIcon = styled(CategoryHeader)` | |||||
| position: relative; | |||||
| top: 4px; | |||||
| @media (max-width: 600px) { | |||||
| width: 12px; | |||||
| height: 12px; | |||||
| top: 1px; | |||||
| } | |||||
| `; | |||||
| export const CategoryIcon = styled(Category)` | export const CategoryIcon = styled(Category)` | ||||
| position: relative; | position: relative; | ||||
| top: 4px; | top: 4px; | ||||
| line-height: 16px; | line-height: 16px; | ||||
| color: ${selectedTheme.colors.primaryText}; | color: ${selectedTheme.colors.primaryText}; | ||||
| `; | `; | ||||
| export const ButtonContainer = styled(Link)` | |||||
| width: fit-content; | |||||
| cursor: pointer; | |||||
| display: flex; | |||||
| justify-content: start; | |||||
| align-items: center; | |||||
| gap: 12px; | |||||
| text-decoration: none; | |||||
| min-width: 200px; | |||||
| `; | |||||
| export const HeaderText = styled(Typography)` | |||||
| font-family: ${selectedTheme.fonts.textFont}; | |||||
| line-height: 22px; | |||||
| font-size: 16px; | |||||
| color: ${selectedTheme.colors.primaryPurple}; | |||||
| border-bottom: 1px dotted ${selectedTheme.colors.primaryPurple}; | |||||
| @media (max-width: 600px) { | |||||
| font-size: 14px; | |||||
| } | |||||
| `; | |||||
| export const SwapsHeaderIcon = styled(SwapsIcon)` | export const SwapsHeaderIcon = styled(SwapsIcon)` | ||||
| width: 18px; | width: 18px; | ||||
| height: 18px; | height: 18px; | ||||
| `; | `; | ||||
| export const HeaderTitleContainer = styled(Box)` | |||||
| position: relative; | |||||
| left: 5px; | |||||
| `; | |||||
| export const HeaderTitleText = styled(Typography)` | |||||
| font-family: ${selectedTheme.fonts.textFont}; | |||||
| color: ${selectedTheme.colors.primaryText}; | |||||
| font-size: 16px; | |||||
| position: relative; | |||||
| bottom: 2px; | |||||
| left: 2px; | |||||
| `; | |||||
| export const UserIcon = styled(User)` | export const UserIcon = styled(User)` | ||||
| position: relative; | position: relative; | ||||
| top: 3px; | top: 3px; |
| import React from "react"; | |||||
| import PropTypes from "prop-types"; | |||||
| import { useTranslation } from "react-i18next"; | |||||
| import { HeaderSelectContainer, SelectOption } from "./HeaderSelect.styled"; | |||||
| const HeaderSelect = (props) => { | |||||
| const sorting = props?.sorting; | |||||
| const { t } = useTranslation(); | |||||
| const handleChangeSelect = (event) => { | |||||
| sorting?.changeSorting(event.target.value); | |||||
| }; | |||||
| return ( | |||||
| <HeaderSelectContainer | |||||
| hideSorting={props?.hideSorting} | |||||
| value={ | |||||
| sorting?.selectedSortOption?.value | |||||
| ? sorting?.selectedSortOption | |||||
| : "default" | |||||
| } | |||||
| onChange={handleChangeSelect} | |||||
| myOffers={props?.myOffers} | |||||
| > | |||||
| <SelectOption style={{ display: "none" }} value="default"> | |||||
| {t("reviews.sortBy")} | |||||
| </SelectOption> | |||||
| {Object.keys(sorting?.sortOptions).map((property) => { | |||||
| if (sorting?.sortOptions[property].value === 0) return; | |||||
| return ( | |||||
| <SelectOption | |||||
| value={sorting?.sortOptions[property]} | |||||
| key={sorting?.sortOptions[property].value} | |||||
| > | |||||
| {sorting?.sortOptions[property].mainText} | |||||
| </SelectOption> | |||||
| ); | |||||
| })} | |||||
| </HeaderSelectContainer> | |||||
| ); | |||||
| }; | |||||
| HeaderSelect.propTypes = { | |||||
| sorting: PropTypes.any, | |||||
| myOffers: PropTypes.bool, | |||||
| hideSorting: PropTypes.bool, | |||||
| }; | |||||
| HeaderSelect.defaultProps = { | |||||
| myOffers: false, | |||||
| hideSorting: false, | |||||
| }; | |||||
| export default HeaderSelect; |
| import { MenuItem } from "@mui/material"; | |||||
| import styled from "styled-components"; | |||||
| import selectedTheme from "../../../../themes"; | |||||
| import Option from "../../../Select/Option/Option"; | |||||
| import Select from "../../../Select/Select"; | |||||
| export const HeaderSelectContainer = styled(Select)` | |||||
| width: 210px; | |||||
| height: 35px; | |||||
| font-family: ${selectedTheme.fonts.textFont}; | |||||
| margin-top: 3px; | |||||
| font-weight: 400; | |||||
| position: relative; | |||||
| left: -5px; | |||||
| background-color: white; | |||||
| display: ${(props) => props.hideSorting && "none"}; | |||||
| & div:first-child { | |||||
| padding-left: 8px; | |||||
| } | |||||
| @media (max-width: 650px) { | |||||
| width: 144px; | |||||
| height: 30px; | |||||
| font-size: 14px; | |||||
| top: 60px; | |||||
| left: ${(props) => (props.myOffers ? "-7px" : "0")}; | |||||
| } | |||||
| `; | |||||
| export const SelectItem = styled(MenuItem)` | |||||
| font-family: ${selectedTheme.fonts.textFont}; | |||||
| `; | |||||
| export const SelectOption = styled(Option)` | |||||
| @media (max-width: 600px) { | |||||
| height: 20px !important; | |||||
| min-height: 35px; | |||||
| margin: 2px; | |||||
| } | |||||
| `; |
| import React from "react"; | |||||
| import PropTypes from "prop-types"; | |||||
| import { Tooltip } from "@mui/material"; | |||||
| import { | |||||
| ButtonContainer, | |||||
| CategoryHeaderIcon, | |||||
| HeaderAltLocation, | |||||
| HeaderCategoryString, | |||||
| HeaderCompanyString, | |||||
| HeaderLocation, | |||||
| HeaderLocationsMainString, | |||||
| HeaderLocationsString, | |||||
| HeaderSubcategoryString, | |||||
| HeaderText, | |||||
| HeaderTitleContainer, | |||||
| HeaderTitleText, | |||||
| TooltipInnerContainer, | |||||
| } from "./TooltipHeader.styled"; | |||||
| import { useSelector } from "react-redux"; | |||||
| import { selectHeaderString } from "../../../../store/selectors/filtersSelectors"; | |||||
| import useIsMobile from "../../../../hooks/useIsMobile"; | |||||
| import { ArrowButton } from "../../../Buttons/ArrowButton/ArrowButton"; | |||||
| import { useTranslation } from "react-i18next"; | |||||
| import history from "../../../../store/utils/history"; | |||||
| const TooltipHeader = (props) => { | |||||
| const headerString = useSelector(selectHeaderString); | |||||
| const { isMobile } = useIsMobile(); | |||||
| const { t } = useTranslation(); | |||||
| const handleClickCategory = () => { | |||||
| props?.offers?.filters?.locations.clear(); | |||||
| props?.offers?.filters?.subcategory.clear(); | |||||
| props?.offers?.applyFilters(); | |||||
| }; | |||||
| const handleClickSubcategory = () => { | |||||
| props?.offers?.filters?.locations.clear(); | |||||
| props?.offers?.applyFilters(); | |||||
| }; | |||||
| const goBack = () => { | |||||
| history.goBack(); | |||||
| }; | |||||
| return ( | |||||
| <Tooltip title={headerString.text}> | |||||
| <TooltipInnerContainer> | |||||
| {!props?.myOffers ? ( | |||||
| <> | |||||
| <CategoryHeaderIcon /> | |||||
| <HeaderLocation> | |||||
| <HeaderCategoryString | |||||
| component="span" | |||||
| onClick={handleClickCategory} | |||||
| > | |||||
| {headerString.categoryString} | |||||
| </HeaderCategoryString> | |||||
| <HeaderSubcategoryString | |||||
| component="span" | |||||
| onClick={handleClickSubcategory} | |||||
| > | |||||
| {headerString.subcategoryString} | |||||
| </HeaderSubcategoryString> | |||||
| <HeaderLocationsString component="span"> | |||||
| <HeaderLocationsMainString component="span"> | |||||
| {headerString.locationsString} | |||||
| </HeaderLocationsMainString> | |||||
| <HeaderCompanyString> | |||||
| {headerString.companiesString} | |||||
| </HeaderCompanyString> | |||||
| <HeaderAltLocation component="span"> | |||||
| {props?.altText} | |||||
| </HeaderAltLocation> | |||||
| </HeaderLocationsString> | |||||
| </HeaderLocation> | |||||
| </> | |||||
| ) : ( | |||||
| <> | |||||
| {!isMobile ? ( | |||||
| <HeaderTitleContainer> | |||||
| {props?.headerIcon} | |||||
| <HeaderTitleText>{props?.headerTitle}</HeaderTitleText> | |||||
| </HeaderTitleContainer> | |||||
| ) : ( | |||||
| !props.hideBackButton && ( | |||||
| <ButtonContainer onClick={goBack}> | |||||
| <ArrowButton side={"left"}></ArrowButton> | |||||
| <HeaderText>{t("messages.goBack")}</HeaderText> | |||||
| </ButtonContainer> | |||||
| ) | |||||
| )} | |||||
| </> | |||||
| )} | |||||
| </TooltipInnerContainer> | |||||
| </Tooltip> | |||||
| ); | |||||
| }; | |||||
| TooltipHeader.propTypes = { | |||||
| myOffers: PropTypes.bool, | |||||
| altText: PropTypes.string, | |||||
| headerIcon: PropTypes.node, | |||||
| headerTitle: PropTypes.string, | |||||
| hideBackButton: PropTypes.bool, | |||||
| offers: PropTypes.any, | |||||
| }; | |||||
| TooltipHeader.defaultProps = { | |||||
| myOffers: false, | |||||
| altText: "", | |||||
| headerIcon: <></>, | |||||
| headerString: "", | |||||
| hideBackButton: false, | |||||
| }; | |||||
| export default TooltipHeader; |
| import { Box, Link, Typography } from "@mui/material"; | |||||
| import styled from "styled-components"; | |||||
| import { ReactComponent as CategoryHeader } from "../../../../assets/images/svg/category-header.svg"; | |||||
| import selectedTheme from "../../../../themes"; | |||||
| export const TooltipInnerContainer = styled(Box)` | |||||
| width: 100%; | |||||
| white-space: nowrap; | |||||
| overflow: hidden; | |||||
| text-overflow: ellipsis; | |||||
| & * { | |||||
| display: inline; | |||||
| } | |||||
| `; | |||||
| export const CategoryHeaderIcon = styled(CategoryHeader)` | |||||
| position: relative; | |||||
| top: 4px; | |||||
| @media (max-width: 600px) { | |||||
| width: 12px; | |||||
| height: 12px; | |||||
| top: 1px; | |||||
| } | |||||
| `; | |||||
| export const HeaderLocation = styled(Typography)` | |||||
| font-family: ${selectedTheme.fonts.textFont}; | |||||
| color: ${selectedTheme.colors.primaryPurple}; | |||||
| font-weight: 700; | |||||
| line-height: 22px; | |||||
| font-size: 16px; | |||||
| flex: 2; | |||||
| margin-left: 9px; | |||||
| max-width: 50%; | |||||
| position: relative; | |||||
| top: -2px; | |||||
| &:after { | |||||
| content: ${(props) => (props.initial ? `":"` : `""`)}; | |||||
| @media (max-width: 600px) { | |||||
| content: ""; | |||||
| } | |||||
| } | |||||
| @media (max-width: 600px) { | |||||
| font-size: 12px; | |||||
| padding-top: 3px; | |||||
| } | |||||
| `; | |||||
| export const HeaderCategoryString = styled(Typography)` | |||||
| font-family: ${selectedTheme.fonts.textFont}; | |||||
| color: ${selectedTheme.colors.primaryPurple}; | |||||
| font-weight: 700; | |||||
| line-height: 22px; | |||||
| font-size: 16px; | |||||
| /* position: relative; | |||||
| bottom: 2px; */ | |||||
| cursor: pointer; | |||||
| @media (max-width: 600px) { | |||||
| font-size: 12px; | |||||
| padding-top: 3px; | |||||
| } | |||||
| `; | |||||
| export const HeaderSubcategoryString = styled(Typography)` | |||||
| font-family: ${selectedTheme.fonts.textFont}; | |||||
| color: ${selectedTheme.colors.primaryPurple}; | |||||
| font-weight: 700; | |||||
| line-height: 22px; | |||||
| font-size: 16px; | |||||
| /* position: relative; | |||||
| bottom: 2px; */ | |||||
| cursor: pointer; | |||||
| @media (max-width: 600px) { | |||||
| font-size: 12px; | |||||
| padding-top: 3px; | |||||
| } | |||||
| `; | |||||
| export const HeaderLocationsString = styled(Typography)` | |||||
| /* position: relative; | |||||
| bottom: 2px; */ | |||||
| white-space: nowrap; | |||||
| overflow: hidden; | |||||
| text-overflow: ellipsis; | |||||
| @media (max-width: 600px) { | |||||
| font-size: 12px; | |||||
| padding-top: 3px; | |||||
| } | |||||
| max-width: 100%; | |||||
| `; | |||||
| export const HeaderLocationsMainString = styled(Typography)` | |||||
| font-family: ${selectedTheme.fonts.textFont}; | |||||
| max-width: 200px; | |||||
| color: ${selectedTheme.colors.primaryPurple}; | |||||
| font-weight: 700; | |||||
| line-height: 22px; | |||||
| font-size: 16px; | |||||
| @media (max-width: 600px) { | |||||
| font-size: 12px; | |||||
| padding-top: 3px; | |||||
| } | |||||
| `; | |||||
| export const HeaderCompanyString = styled(Typography)` | |||||
| font-family: ${selectedTheme.fonts.textFont}; | |||||
| max-width: 200px; | |||||
| color: ${selectedTheme.colors.primaryPurple}; | |||||
| font-weight: 700; | |||||
| line-height: 22px; | |||||
| font-size: 16px; | |||||
| @media (max-width: 600px) { | |||||
| font-size: 12px; | |||||
| padding-top: 3px; | |||||
| } | |||||
| `; | |||||
| export const HeaderAltLocation = styled(Typography)` | |||||
| font-family: ${selectedTheme.fonts.textFont}; | |||||
| font-size: 16px; | |||||
| color: ${selectedTheme.colors.primaryText}; | |||||
| position: relative; | |||||
| top: 0.5px; | |||||
| @media (max-width: 600px) { | |||||
| display: none; | |||||
| } | |||||
| `; | |||||
| export const HeaderTitleContainer = styled(Box)` | |||||
| position: relative; | |||||
| left: 5px; | |||||
| `; | |||||
| export const HeaderTitleText = styled(Typography)` | |||||
| font-family: ${selectedTheme.fonts.textFont}; | |||||
| color: ${selectedTheme.colors.primaryText}; | |||||
| font-size: 16px; | |||||
| position: relative; | |||||
| bottom: 2px; | |||||
| left: 2px; | |||||
| `; | |||||
| export const ButtonContainer = styled(Link)` | |||||
| width: fit-content; | |||||
| cursor: pointer; | |||||
| display: flex; | |||||
| justify-content: start; | |||||
| align-items: center; | |||||
| gap: 12px; | |||||
| text-decoration: none; | |||||
| min-width: 200px; | |||||
| `; | |||||
| export const HeaderText = styled(Typography)` | |||||
| font-family: ${selectedTheme.fonts.textFont}; | |||||
| line-height: 22px; | |||||
| font-size: 16px; | |||||
| color: ${selectedTheme.colors.primaryPurple}; | |||||
| border-bottom: 1px dotted ${selectedTheme.colors.primaryPurple}; | |||||
| @media (max-width: 600px) { | |||||
| font-size: 14px; | |||||
| } | |||||
| `; |
| import React, { useRef } from "react"; | |||||
| import React from "react"; | |||||
| import PropTypes from "prop-types"; | import PropTypes from "prop-types"; | ||||
| import { FilterContainer, FilterIcon, OffersContainer } from "./Offers.styled"; | |||||
| import OfferCard from "../../Cards/OfferCard/OfferCard"; | |||||
| import { useSelector } from "react-redux"; | |||||
| import Paging from "../../Paging/Paging"; | |||||
| import { selectLatestChats } from "../../../store/selectors/chatSelectors"; | |||||
| import { selectUserId } from "../../../store/selectors/loginSelectors"; | |||||
| import { startChat } from "../../../util/helpers/chatHelper"; | |||||
| import OffersNotFound from "./OffersNotFound"; | |||||
| // import HeadersMyOffers from "./SearchBar/SearchBar"; | |||||
| import SkeletonOfferCard from "../../Cards/OfferCard/SkeletonOfferCard/SkeletonOfferCard"; | import SkeletonOfferCard from "../../Cards/OfferCard/SkeletonOfferCard/SkeletonOfferCard"; | ||||
| import BigProfileCard from "../../Cards/ProfileCard/BigProfileCard/BigProfileCard"; | |||||
| import SearchField from "../../TextFields/SearchField/SearchField"; | |||||
| import { useTranslation } from "react-i18next"; | |||||
| import OffersList from "./OffersList/OffersList"; | |||||
| import OffersFilterButton from "./OffersFilterButton/OffersFilterButton"; | |||||
| import OffersSearchField from "./OffersSearchField/OffersSearchField"; | |||||
| import OffersNotFound from "./OffersNotFound/OffersNotFound"; | |||||
| const Offers = (props) => { | const Offers = (props) => { | ||||
| const chats = useSelector(selectLatestChats); | |||||
| const offersRef = useRef(null); | |||||
| const userId = useSelector(selectUserId); | |||||
| const { t } = useTranslation(); | |||||
| const offers = props?.offers; | const offers = props?.offers; | ||||
| // For skeleton screen | |||||
| const arrayForMapping = Array.apply(null, Array(4)).map(() => {}); | const arrayForMapping = Array.apply(null, Array(4)).map(() => {}); | ||||
| const messageOneUser = (offer) => { | |||||
| startChat(chats, offer, userId); | |||||
| }; | |||||
| const toggleFilters = () => { | |||||
| props?.toggleFilters(); | |||||
| }; | |||||
| return ( | return ( | ||||
| <> | <> | ||||
| {!props?.skeleton ? ( | |||||
| <> | |||||
| <FilterContainer | |||||
| isAdmin={props?.isAdmin} | |||||
| onClick={toggleFilters} | |||||
| number={offers?.filters?.numOfFiltersChosen} | |||||
| myOffers={props?.myOffers} | |||||
| > | |||||
| <FilterIcon /> | |||||
| </FilterContainer> | |||||
| {(props?.myOffers || props?.isAdmin) && ( | |||||
| // <HeadersMyOffers | |||||
| <SearchField | |||||
| searchMyOffers={offers?.search?.searchOffers} | |||||
| handleSearch={offers?.apply} | |||||
| isAdmin={props?.isAdmin} | |||||
| offers={offers} | |||||
| isUsers={props.isUsers} | |||||
| placeholder={ | |||||
| props.isUsers | |||||
| ? t("admin.users.searchPlaceholder") | |||||
| : t("header.searchOffers") | |||||
| } | |||||
| /> | |||||
| )} | |||||
| {offers?.allOffersToShow?.length === 0 ? ( | |||||
| <OffersNotFound /> | |||||
| ) : ( | |||||
| <OffersContainer ref={offersRef}> | |||||
| {props.isUsers | |||||
| ? props.users?.map((item) => ( | |||||
| <BigProfileCard | |||||
| key={item._id} | |||||
| profile={item} | |||||
| halfwidth={props?.isGrid} | |||||
| /> | |||||
| )) | |||||
| : offers?.allOffersToShow?.map((item) => { | |||||
| return ( | |||||
| <OfferCard | |||||
| key={item._id} | |||||
| offer={item} | |||||
| halfwidth={props?.isGrid} | |||||
| messageUser={messageOneUser} | |||||
| isMyOffer={item?.userId === userId || props?.isAdmin} | |||||
| isAdmin={props?.isAdmin} | |||||
| /> | |||||
| ); | |||||
| })} | |||||
| <Paging | |||||
| totalElements={offers?.totalOffers} | |||||
| elementsPerPage={10} | |||||
| current={parseInt(offers?.paging?.currentPage)} | |||||
| changePage={offers?.paging?.changePage} | |||||
| /> | |||||
| </OffersContainer> | |||||
| )} | |||||
| </> | |||||
| ) : ( | |||||
| <> | |||||
| {arrayForMapping.map((item, index) => ( | |||||
| <SkeletonOfferCard key={index} skeleton /> | |||||
| ))} | |||||
| </> | |||||
| )} | |||||
| <OffersFilterButton /> | |||||
| <OffersSearchField /> | |||||
| <OffersNotFound /> | |||||
| <OffersList | |||||
| loading={props?.skeleton} | |||||
| offers={offers} | |||||
| isAdmin={props.isAdmin} | |||||
| isGrid={props?.isGrid} | |||||
| isUsers={props?.isUsers} | |||||
| users={props?.users} | |||||
| /> | |||||
| {props?.skeleton && | |||||
| arrayForMapping.map((item, index) => ( | |||||
| <SkeletonOfferCard key={index} skeleton={props?.skeleton} /> | |||||
| ))} | |||||
| </> | </> | ||||
| ); | ); | ||||
| }; | }; | ||||
| isGrid: PropTypes.bool, | isGrid: PropTypes.bool, | ||||
| myOffers: PropTypes.bool, | myOffers: PropTypes.bool, | ||||
| skeleton: PropTypes.bool, | skeleton: PropTypes.bool, | ||||
| offers: PropTypes.any, | |||||
| offers: PropTypes.shape({ | |||||
| apply: PropTypes.func, | |||||
| search: PropTypes.shape({ | |||||
| searchOffers: PropTypes.func, | |||||
| }), | |||||
| filters: PropTypes.shape({ | |||||
| numOfFiltersChosen: PropTypes.number, | |||||
| }), | |||||
| }), | |||||
| toggleFilters: PropTypes.func, | toggleFilters: PropTypes.func, | ||||
| isAdmin: PropTypes.bool, | isAdmin: PropTypes.bool, | ||||
| isUsers: PropTypes.bool, | isUsers: PropTypes.bool, | ||||
| Offers.defaultProps = { | Offers.defaultProps = { | ||||
| myOffers: false, | myOffers: false, | ||||
| users: [], | users: [], | ||||
| isAdmin: false, | |||||
| isUsers: false, | |||||
| isGrid: false, | |||||
| skeleton: false, | |||||
| toggleFilters: () => {}, | |||||
| offers: { | |||||
| apply: () => {}, | |||||
| search: { | |||||
| searchOffers: () => {}, | |||||
| }, | |||||
| filters: { | |||||
| numOfFiltersChosen: 0, | |||||
| }, | |||||
| }, | |||||
| }; | }; | ||||
| export default Offers; | export default Offers; |
| import { Box } from "@mui/material"; | |||||
| import styled from "styled-components"; | |||||
| import selectedTheme from "../../../themes"; | |||||
| import IconWithNumber from "../../Icon/IconWithNumber/IconWithNumber"; | |||||
| import { ReactComponent as Filter } from "../../../assets/images/svg/filter.svg"; | |||||
| export const OffersContainer = styled(Box)` | |||||
| display: flex; | |||||
| flex-direction: row; | |||||
| flex-wrap: wrap; | |||||
| justify-content: space-between; | |||||
| margin-top: 5px; | |||||
| position: relative; | |||||
| padding-bottom: 60px; | |||||
| `; | |||||
| export const FilterContainer = styled(IconWithNumber)` | |||||
| position: absolute; | |||||
| top: 93px; | |||||
| right: 24px; | |||||
| cursor: pointer; | |||||
| background-color: ${selectedTheme.colors.primaryBackgroundColor} !important; | |||||
| & div { | |||||
| width: 16px; | |||||
| height: 16px; | |||||
| background-color: ${selectedTheme.colors.primaryPurple}; | |||||
| position: absolute; | |||||
| top: -5px; | |||||
| right: -5px; | |||||
| line-height: 15px; | |||||
| text-align: center; | |||||
| } | |||||
| @media (min-width: 600px) { | |||||
| display: none; | |||||
| } | |||||
| `; | |||||
| export const FilterIcon = styled(Filter)` | |||||
| background-color: ${selectedTheme.colors.primaryBackgroundColor}; | |||||
| `; |
| import React from "react"; | |||||
| import PropTypes from "prop-types"; | |||||
| import { FilterContainer, FilterIcon } from "./OffersFilterButton.styled"; | |||||
| const OffersFilterButton = (props) => { | |||||
| const toggleFilters = () => { | |||||
| props?.toggleFilters(); | |||||
| }; | |||||
| return ( | |||||
| <FilterContainer | |||||
| isAdmin={props?.isAdmin} | |||||
| onClick={toggleFilters} | |||||
| number={props?.offers?.filters?.numOfFiltersChosen} | |||||
| myOffers={props?.myOffers} | |||||
| > | |||||
| <FilterIcon /> | |||||
| </FilterContainer> | |||||
| ); | |||||
| }; | |||||
| OffersFilterButton.propTypes = { | |||||
| isAdmin: PropTypes.bool, | |||||
| offers: PropTypes.shape({ | |||||
| filters: PropTypes.shape({ | |||||
| numOfFiltersChosen: PropTypes.number, | |||||
| }), | |||||
| }), | |||||
| myOffers: PropTypes.bool, | |||||
| toggleFilters: PropTypes.func, | |||||
| }; | |||||
| OffersFilterButton.defaultProps = { | |||||
| isAdmin: false, | |||||
| offers: { | |||||
| filters: { | |||||
| numOfFiltersChosen: 0, | |||||
| }, | |||||
| }, | |||||
| myOffers: false, | |||||
| toggleFilters: () => {}, | |||||
| }; | |||||
| export default OffersFilterButton; |
| import styled from "styled-components"; | |||||
| import selectedTheme from "../../../../themes"; | |||||
| import IconWithNumber from "../../../Icon/IconWithNumber/IconWithNumber"; | |||||
| import { ReactComponent as Filter } from "../../../../assets/images/svg/filter.svg"; | |||||
| export const FilterContainer = styled(IconWithNumber)` | |||||
| position: absolute; | |||||
| top: 93px; | |||||
| right: 24px; | |||||
| cursor: pointer; | |||||
| background-color: ${selectedTheme.colors.primaryBackgroundColor} !important; | |||||
| & div { | |||||
| width: 16px; | |||||
| height: 16px; | |||||
| background-color: ${selectedTheme.colors.primaryPurple}; | |||||
| position: absolute; | |||||
| top: -5px; | |||||
| right: -5px; | |||||
| line-height: 15px; | |||||
| text-align: center; | |||||
| } | |||||
| @media (min-width: 600px) { | |||||
| display: none; | |||||
| } | |||||
| `; | |||||
| export const FilterIcon = styled(Filter)` | |||||
| background-color: ${selectedTheme.colors.primaryBackgroundColor}; | |||||
| `; |
| import React from "react"; | |||||
| import PropTypes from "prop-types"; | |||||
| import { useSelector } from "react-redux"; | |||||
| import { selectTotalOffers } from "../../../../store/selectors/offersSelectors"; | |||||
| import { OffersContainer } from "./OffersList.styled"; | |||||
| import BigProfileCard from "../../../Cards/ProfileCard/BigProfileCard/BigProfileCard"; | |||||
| import OfferCard from "../../../Cards/OfferCard/OfferCard"; | |||||
| import Paging from "../../../Paging/Paging"; | |||||
| import { startChat } from "../../../../util/helpers/chatHelper"; | |||||
| import { selectLatestChats } from "../../../../store/selectors/chatSelectors"; | |||||
| import { selectUserId } from "../../../../store/selectors/loginSelectors"; | |||||
| const OffersList = (props) => { | |||||
| const totalOffers = useSelector(selectTotalOffers); | |||||
| const chats = useSelector(selectLatestChats); | |||||
| const userId = useSelector(selectUserId); | |||||
| const offers = props?.offers; | |||||
| const messageOneUser = (offer) => { | |||||
| startChat(chats, offer, userId); | |||||
| }; | |||||
| return ( | |||||
| <OffersContainer show={!props?.loading && totalOffers !== 0}> | |||||
| {props.isUsers | |||||
| ? props.users?.map((item) => ( | |||||
| <BigProfileCard | |||||
| key={item._id} | |||||
| profile={item} | |||||
| halfwidth={props?.isGrid} | |||||
| /> | |||||
| )) | |||||
| : offers?.allOffersToShow?.map((item) => { | |||||
| return ( | |||||
| <OfferCard | |||||
| key={item._id} | |||||
| offer={item} | |||||
| halfwidth={props?.isGrid} | |||||
| messageUser={messageOneUser} | |||||
| isMyOffer={item?.userId === userId || props?.isAdmin} | |||||
| isAdmin={props?.isAdmin} | |||||
| /> | |||||
| ); | |||||
| })} | |||||
| <Paging | |||||
| totalElements={offers?.totalOffers} | |||||
| elementsPerPage={10} | |||||
| current={parseInt(offers?.paging?.currentPage)} | |||||
| changePage={offers?.paging?.changePage} | |||||
| /> | |||||
| </OffersContainer> | |||||
| ); | |||||
| }; | |||||
| OffersList.propTypes = { | |||||
| offers: PropTypes.any, | |||||
| isGrid: PropTypes.bool, | |||||
| isUsers: PropTypes.bool, | |||||
| users: PropTypes.array, | |||||
| isAdmin: PropTypes.bool, | |||||
| loading: PropTypes.bool, | |||||
| }; | |||||
| OffersList.defaultProps = { | |||||
| isGrid: false, | |||||
| isUsers: false, | |||||
| users: [], | |||||
| isAdmin: false, | |||||
| offers: { | |||||
| allOffersToShow: [], | |||||
| }, | |||||
| loading: false, | |||||
| }; | |||||
| export default OffersList; |
| import { Box } from "@mui/material"; | |||||
| import styled from "styled-components"; | |||||
| export const OffersContainer = styled(Box)` | |||||
| display: ${props => props.show ? "flex" : "none"}; | |||||
| flex-direction: row; | |||||
| flex-wrap: wrap; | |||||
| justify-content: space-between; | |||||
| margin-top: 5px; | |||||
| position: relative; | |||||
| padding-bottom: 60px; | |||||
| `; |
| import React from "react"; | |||||
| import { ReactComponent as LogoBroken } from "../../../assets/images/svg/logo-broken.svg"; | |||||
| import { | |||||
| Button, | |||||
| OffersNotFoundContainer, | |||||
| OffersNotFoundLogo, | |||||
| OffersNotFoundDescription, | |||||
| OffersNotFoundHeading, | |||||
| } from "./OffersNotFound.styled"; | |||||
| import selectedTheme from "../../../themes"; | |||||
| import { Trans, useTranslation } from "react-i18next"; | |||||
| import { useHistory } from "react-router-dom"; | |||||
| import { HOME_PAGE } from "../../../constants/pages"; | |||||
| import { useDispatch } from "react-redux"; | |||||
| import { fetchOffers } from "../../../store/actions/offers/offersActions"; | |||||
| const OffersNotFound = () => { | |||||
| const dispatch = useDispatch(); | |||||
| const history = useHistory(); | |||||
| const { t } = useTranslation(); | |||||
| const showAllOffersHandler = () => { | |||||
| dispatch(fetchOffers({ queryString: "" })); | |||||
| history.replace({ | |||||
| pathname: HOME_PAGE, | |||||
| state: { | |||||
| from: history.location.pathname, | |||||
| }, | |||||
| }); | |||||
| }; | |||||
| return ( | |||||
| <OffersNotFoundContainer> | |||||
| <OffersNotFoundLogo> | |||||
| <LogoBroken /> | |||||
| </OffersNotFoundLogo> | |||||
| <OffersNotFoundHeading> | |||||
| {t("offersNotFound.notFound")} | |||||
| </OffersNotFoundHeading> | |||||
| <OffersNotFoundDescription> | |||||
| <Trans i18nKey="offersNotFound.errorMessage" /> | |||||
| </OffersNotFoundDescription> | |||||
| <Button | |||||
| variant="contained" | |||||
| buttoncolor={selectedTheme.colors.primaryYellow} | |||||
| textcolor="black" | |||||
| onClick={showAllOffersHandler} | |||||
| > | |||||
| {t("offersNotFound.showAllOffers")} | |||||
| </Button> | |||||
| </OffersNotFoundContainer> | |||||
| ); | |||||
| }; | |||||
| export default OffersNotFound; |
| import React from "react"; | |||||
| import PropTypes from "prop-types"; | |||||
| import { ReactComponent as LogoBroken } from "../../../../assets/images/svg/logo-broken.svg"; | |||||
| import { | |||||
| Button, | |||||
| OffersNotFoundContainer, | |||||
| OffersNotFoundLogo, | |||||
| OffersNotFoundDescription, | |||||
| OffersNotFoundHeading, | |||||
| } from "./OffersNotFound.styled"; | |||||
| import selectedTheme from "../../../../themes"; | |||||
| import { Trans, useTranslation } from "react-i18next"; | |||||
| import { useHistory } from "react-router-dom"; | |||||
| import { HOME_PAGE } from "../../../../constants/pages"; | |||||
| import { useDispatch, useSelector } from "react-redux"; | |||||
| import { fetchOffers } from "../../../../store/actions/offers/offersActions"; | |||||
| import { selectTotalOffers } from "../../../../store/selectors/offersSelectors"; | |||||
| const OffersNotFound = () => { | |||||
| const dispatch = useDispatch(); | |||||
| const history = useHistory(); | |||||
| const totalOffers = useSelector(selectTotalOffers); | |||||
| const { t } = useTranslation(); | |||||
| const showAllOffersHandler = () => { | |||||
| dispatch(fetchOffers({ queryString: "" })); | |||||
| history.replace({ | |||||
| pathname: HOME_PAGE, | |||||
| state: { | |||||
| from: history.location.pathname, | |||||
| }, | |||||
| }); | |||||
| }; | |||||
| return ( | |||||
| <> | |||||
| <OffersNotFoundContainer show={totalOffers === 0}> | |||||
| <OffersNotFoundLogo> | |||||
| <LogoBroken /> | |||||
| </OffersNotFoundLogo> | |||||
| <OffersNotFoundHeading> | |||||
| {t("offersNotFound.notFound")} | |||||
| </OffersNotFoundHeading> | |||||
| <OffersNotFoundDescription> | |||||
| <Trans i18nKey="offersNotFound.errorMessage" /> | |||||
| </OffersNotFoundDescription> | |||||
| <Button | |||||
| variant="contained" | |||||
| buttoncolor={selectedTheme.colors.primaryYellow} | |||||
| textcolor="black" | |||||
| onClick={showAllOffersHandler} | |||||
| > | |||||
| {t("offersNotFound.showAllOffers")} | |||||
| </Button> | |||||
| </OffersNotFoundContainer> | |||||
| </> | |||||
| ); | |||||
| }; | |||||
| OffersNotFound.propTypes = { | |||||
| skeleton: PropTypes.bool, | |||||
| }; | |||||
| OffersNotFound.defaultProps = { | |||||
| skeleton: false, | |||||
| }; | |||||
| export default OffersNotFound; |
| import styled from "styled-components"; | import styled from "styled-components"; | ||||
| import { Typography } from "@mui/material"; | import { Typography } from "@mui/material"; | ||||
| import { Box } from "@mui/system"; | import { Box } from "@mui/system"; | ||||
| import selectedTheme from "../../../themes"; | |||||
| import { PrimaryButton } from "../../Buttons/PrimaryButton/PrimaryButton"; | |||||
| import selectedTheme from "../../../../themes"; | |||||
| import { PrimaryButton } from "../../../Buttons/PrimaryButton/PrimaryButton"; | |||||
| export const OffersNotFoundContainer = styled(Box)` | export const OffersNotFoundContainer = styled(Box)` | ||||
| display: flex; | |||||
| display: ${props => props.show ? "flex" : "none"}; | |||||
| flex-direction: column; | flex-direction: column; | ||||
| align-items: center; | align-items: center; | ||||
| justify-content: center; | justify-content: center; |
| import React from "react"; | |||||
| import PropTypes from "prop-types"; | |||||
| import SearchField from "../../../TextFields/SearchField/SearchField"; | |||||
| import { useTranslation } from "react-i18next"; | |||||
| const OffersSearchField = (props) => { | |||||
| const offers = props?.offers; | |||||
| const { t } = useTranslation(); | |||||
| if (props?.myOffers || props?.isAdmin) | |||||
| return ( | |||||
| <SearchField | |||||
| searchMyOffers={offers?.search?.searchOffers} | |||||
| handleSearch={offers?.apply} | |||||
| isAdmin={props?.isAdmin} | |||||
| offers={offers} | |||||
| isUsers={props.isUsers} | |||||
| placeholder={ | |||||
| props.isUsers | |||||
| ? t("admin.users.searchPlaceholder") | |||||
| : t("header.searchOffers") | |||||
| } | |||||
| /> | |||||
| ); | |||||
| return <></>; | |||||
| }; | |||||
| OffersSearchField.propTypes = { | |||||
| offers: PropTypes.shape({ | |||||
| apply: PropTypes.func, | |||||
| search: PropTypes.shape({ | |||||
| searchOffers: PropTypes.func, | |||||
| }), | |||||
| }), | |||||
| isUsers: PropTypes.bool, | |||||
| isAdmin: PropTypes.bool, | |||||
| myOffers: PropTypes.bool, | |||||
| }; | |||||
| OffersSearchField.defaultProps = { | |||||
| offers: { | |||||
| apply: () => {}, | |||||
| search: { | |||||
| searchOffers: () => {}, | |||||
| }, | |||||
| }, | |||||
| isUsers: false, | |||||
| isAdmin: false, | |||||
| myOffers: false, | |||||
| }; | |||||
| export default OffersSearchField; |
| } else { | } else { | ||||
| document.body.style.overflow = "auto"; | document.body.style.overflow = "auto"; | ||||
| } | } | ||||
| console.log("MODALS: ", modals); | |||||
| return ( | return ( | ||||
| <> | <> | ||||
| {modals?.createOfferModal && <CreateOffer {...modals?.props} />} | {modals?.createOfferModal && <CreateOffer {...modals?.props} />} |
| PagingContainer, | PagingContainer, | ||||
| ThreeDots, | ThreeDots, | ||||
| } from "./Paging.styled"; | } from "./Paging.styled"; | ||||
| import { useTranslation } from "react-i18next"; | |||||
| const Paging = (props) => { | const Paging = (props) => { | ||||
| const {t} = useTranslation(); | |||||
| // Determining total pages | // Determining total pages | ||||
| const pages = props.pages | const pages = props.pages | ||||
| ? props.pages | ? props.pages | ||||
| <PagingContainer className={props.className}> | <PagingContainer className={props.className}> | ||||
| {/* Left arrow */} | {/* Left arrow */} | ||||
| <Arrow | <Arrow | ||||
| aria-label={t("labels.prevPage")} | |||||
| onClick={() => props.changePage(props.current - 1)} | onClick={() => props.changePage(props.current - 1)} | ||||
| disabled={props.current - 1 < 1} | disabled={props.current - 1 < 1} | ||||
| > | > | ||||
| {/* Right arrow */} | {/* Right arrow */} | ||||
| <Arrow | <Arrow | ||||
| aria-label={t("labels.nextPage")} | |||||
| onClick={() => props.changePage(props.current + 1)} | onClick={() => props.changePage(props.current + 1)} | ||||
| disabled={props.current + 1 > pages} | disabled={props.current + 1 > pages} | ||||
| > | > |
| export const REGISTER_SUCCESSFUL_PAGE = "/register/success"; | export const REGISTER_SUCCESSFUL_PAGE = "/register/success"; | ||||
| export const RESET_PASSWORD_PAGE = "/reset-password/:token"; | export const RESET_PASSWORD_PAGE = "/reset-password/:token"; | ||||
| export const CREATE_OFFER_PAGE = "/create-offer"; | export const CREATE_OFFER_PAGE = "/create-offer"; | ||||
| export const ITEM_DETAILS_PAGE = "/proizvodi/:idProizvod"; | |||||
| export const PROFILE_PAGE = "/profile/:idProfile"; | |||||
| export const CHAT_PAGE = "/messages"; | |||||
| export const CHAT_MESSAGE_PAGE = "/messages/:idChat"; | |||||
| export const ITEM_DETAILS_PAGE = "/offers/:offerId"; | |||||
| export const PROFILE_PAGE = "/profiles/:profileId"; | |||||
| export const MESSAGES_LIST_PAGE = "/messages"; | |||||
| export const DIRECT_CHAT_PAGE = "/messages/:chatId"; | |||||
| export const MY_OFFERS_PAGE = "/myoffers"; | export const MY_OFFERS_PAGE = "/myoffers"; | ||||
| export const ABOUT_PAGE = "/about"; | export const ABOUT_PAGE = "/about"; | ||||
| export const PRICES_PAGE = "/prices"; | export const PRICES_PAGE = "/prices"; | ||||
| export const POLICY_PRIVACY_PAGE = "/policy"; | export const POLICY_PRIVACY_PAGE = "/policy"; | ||||
| export const ADMIN_HOME_PAGE = "/admin"; | export const ADMIN_HOME_PAGE = "/admin"; | ||||
| export const ADMIN_USERS_PAGE = "/admin/users"; | export const ADMIN_USERS_PAGE = "/admin/users"; | ||||
| export const ADMIN_SINGLE_USER_PAGE = "/admin/users/:idProfile"; | |||||
| export const ADMIN_ITEM_DETAILS_PAGE = "/admin/proizvodi/:idProizvod"; | |||||
| export const ADMIN_SINGLE_USER_PAGE = "/admin/profiles/:profileId"; | |||||
| export const ADMIN_ITEM_DETAILS_PAGE = "/admin/offers/:offerId"; | |||||
| export const ADMIN_CATEGORIES_PAGE = "/admin/categories"; | export const ADMIN_CATEGORIES_PAGE = "/admin/categories"; | ||||
| 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"; |
| checkButtonLabel: "Pogledaj proizvod", | checkButtonLabel: "Pogledaj proizvod", | ||||
| offers: "Objave", | offers: "Objave", | ||||
| tooltip: "Izmeni objavu", | tooltip: "Izmeni objavu", | ||||
| imageAlt: "Offer image", | |||||
| }, | }, | ||||
| apiErrors: { | apiErrors: { | ||||
| somethingWentWrong: "Greška sa serverom!", | somethingWentWrong: "Greška sa serverom!", | ||||
| tooltip: "Pošalji poruku", | tooltip: "Pošalji poruku", | ||||
| requestSent: "Uspešno ste ponudili trampu kompaniji.", | requestSent: "Uspešno ste ponudili trampu kompaniji.", | ||||
| requestAccepted: "Kompanija je prihvatila trampu sa Vama.", | requestAccepted: "Kompanija je prihvatila trampu sa Vama.", | ||||
| requestReceived: "Da li želite da prihvatite trampu sa nama za gorenavedeni proizvod?", | |||||
| requestReceived: | |||||
| "Da li želite da prihvatite trampu sa nama za gorenavedeni proizvod?", | |||||
| acceptRequest: "Prihvati", | acceptRequest: "Prihvati", | ||||
| acceptedRequest: "Prihvaćeno", | acceptedRequest: "Prihvaćeno", | ||||
| declineRequest: "Odbij", | declineRequest: "Odbij", | ||||
| requestSuccessfulLong: "Uspešno ste ostvarili trampu sa ovom kompanijom.", | requestSuccessfulLong: "Uspešno ste ostvarili trampu sa ovom kompanijom.", | ||||
| requestSentLong: "Ponudili ste trampu kompaniji. Čeka se odgovor..." | |||||
| requestSentLong: "Ponudili ste trampu kompaniji. Čeka se odgovor...", | |||||
| }, | }, | ||||
| editProfile: { | editProfile: { | ||||
| website: "Web Sajt", | website: "Web Sajt", | ||||
| confirm: "Obriši komentar", | confirm: "Obriši komentar", | ||||
| }, | }, | ||||
| }, | }, | ||||
| labels: { | |||||
| dropdownIcon: "Dropdown icon", | |||||
| dropdownOpen: "Open dropdown", | |||||
| dropdownClose: "Close dropdown", | |||||
| messageUser: "Message user", | |||||
| prevPage: "Previous page", | |||||
| nextPage: "Next page", | |||||
| }, | |||||
| }; | }; |
| .ToastBody * { | .ToastBody * { | ||||
| font-family: "DM Sans"; | font-family: "DM Sans"; | ||||
| } | |||||
| * { | |||||
| font-display: swap; | |||||
| } | } |
| <Provider store={store}> | <Provider store={store}> | ||||
| <ColorModeProvider> | <ColorModeProvider> | ||||
| <PersistGate loading={null} persistor={persistor}> | <PersistGate loading={null} persistor={persistor}> | ||||
| <GlobalStyle/> | |||||
| <GlobalStyle /> | |||||
| <App /> | <App /> | ||||
| </PersistGate> | </PersistGate> | ||||
| </ColorModeProvider> | </ColorModeProvider> |
| import ChatGridLayout from "../../layouts/ChatGridLayout/ChatGridLayout"; | import ChatGridLayout from "../../layouts/ChatGridLayout/ChatGridLayout"; | ||||
| import { useSwipeable } from "react-swipeable"; | import { useSwipeable } from "react-swipeable"; | ||||
| import { | import { | ||||
| ChatMessagesPageContainer, | |||||
| DirectChatPageContainer, | |||||
| SwiperContainer, | SwiperContainer, | ||||
| } from "./ChatMessages.styled"; | |||||
| } from "./DirectChatPage.styled"; | |||||
| import { useHistory } from "react-router-dom"; | import { useHistory } from "react-router-dom"; | ||||
| export const ChatMessagesPage = () => { | |||||
| export const DirectChatPage = () => { | |||||
| const history = useHistory(); | const history = useHistory(); | ||||
| const goBack = () => { | const goBack = () => { | ||||
| history.goBack(); | history.goBack(); | ||||
| }; | }; | ||||
| const handlersBox = useSwipeable({ | const handlersBox = useSwipeable({ | ||||
| onSwipedRight: () => setTimeout(goBack, 0), | onSwipedRight: () => setTimeout(goBack, 0), | ||||
| trackMouse: false, | trackMouse: false, | ||||
| // preventDefaultTouchmoveEvent: true | |||||
| }); | }); | ||||
| return ( | return ( | ||||
| <SwiperContainer {...handlersBox}> | <SwiperContainer {...handlersBox}> | ||||
| <ChatMessagesPageContainer> | |||||
| <DirectChatPageContainer> | |||||
| <ChatGridLayout | <ChatGridLayout | ||||
| content={<DirectChat />} | content={<DirectChat />} | ||||
| leftCard={<MiniChatColumn />} | leftCard={<MiniChatColumn />} | ||||
| /> | /> | ||||
| </ChatMessagesPageContainer> | |||||
| </DirectChatPageContainer> | |||||
| </SwiperContainer> | </SwiperContainer> | ||||
| ); | ); | ||||
| }; | }; | ||||
| ChatMessagesPage.propTypes = {}; | |||||
| DirectChatPage.propTypes = {}; | |||||
| export default ChatMessagesPage; | |||||
| export default DirectChatPage; |
| import styled from "styled-components"; | import styled from "styled-components"; | ||||
| import { transitionOnLoadFromRight } from "../../components/Styles/globalStyleComponents"; | import { transitionOnLoadFromRight } from "../../components/Styles/globalStyleComponents"; | ||||
| export const ChatMessagesPageContainer = styled(Container)` | |||||
| export const DirectChatPageContainer = styled(Container)` | |||||
| max-width: none; | max-width: none; | ||||
| @media (max-width: 600px) { | @media (max-width: 600px) { | ||||
| animation: 0.2s ease 0s 1 ${transitionOnLoadFromRight}; | animation: 0.2s ease 0s 1 ${transitionOnLoadFromRight}; |
| import React from 'react'; | |||||
| import React, { useState } from "react"; | |||||
| import { HomePageContainer } from "./HomePage.styled"; | |||||
| import FilterCard from "../../components/Cards/FilterCard/FilterCard"; | |||||
| import MainLayout from "../../layouts/MainLayout/MainLayout"; | |||||
| import MarketPlace from "../../components/MarketPlace/MarketPlace"; | |||||
| import { selectIsLoadingByActionType } from "../../store/selectors/loadingSelectors"; | |||||
| import { useSelector } from "react-redux"; | |||||
| import { OFFERS_SCOPE } from "../../store/actions/offers/offersActionConstants"; | |||||
| import useOffers from "../../hooks/useOffers/useOffers"; | |||||
| const HomePage = () => { | const HomePage = () => { | ||||
| const isLoadingOffers = useSelector( | |||||
| selectIsLoadingByActionType(OFFERS_SCOPE) | |||||
| ); | |||||
| const [filtersOpened, setFiltersOpened] = useState(false); | |||||
| const offers = useOffers(); | |||||
| const toggleFilters = () => { | |||||
| setFiltersOpened((prevFiltersOpened) => !prevFiltersOpened); | |||||
| }; | |||||
| return ( | return ( | ||||
| <div className="c-error-page"> | |||||
| <div className="c-error-page__content"> | |||||
| <h1 className="c-error-page__title">Home page</h1> | |||||
| </div> | |||||
| </div> | |||||
| <HomePageContainer> | |||||
| <MainLayout | |||||
| leftCard={ | |||||
| <FilterCard | |||||
| offers={offers} | |||||
| filtersOpened={filtersOpened} | |||||
| skeleton={isLoadingOffers} | |||||
| toggleFilters={toggleFilters} | |||||
| /> | |||||
| } | |||||
| content={ | |||||
| <MarketPlace | |||||
| offers={offers} | |||||
| skeleton={isLoadingOffers} | |||||
| toggleFilters={toggleFilters} | |||||
| /> | |||||
| } | |||||
| /> | |||||
| </HomePageContainer> | |||||
| ); | ); | ||||
| }; | }; | ||||
| HomePage.propTypes = {}; | |||||
| export default HomePage; | export default HomePage; |
| import React, { useState } from "react"; | |||||
| import { HomePageContainer } from "./HomePage.styled"; | |||||
| import FilterCard from "../../components/Cards/FilterCard/FilterCard"; | |||||
| import MainLayout from "../../layouts/MainLayout/MainLayout"; | |||||
| import MarketPlace from "../../components/MarketPlace/MarketPlace"; | |||||
| import { selectIsLoadingByActionType } from "../../store/selectors/loadingSelectors"; | |||||
| import { useSelector } from "react-redux"; | |||||
| import { OFFERS_SCOPE } from "../../store/actions/offers/offersActionConstants"; | |||||
| import useOffers from "../../hooks/useOffers/useOffers"; | |||||
| const HomePage = () => { | |||||
| const isLoadingOffers = useSelector( | |||||
| selectIsLoadingByActionType(OFFERS_SCOPE) | |||||
| ); | |||||
| const [filtersOpened, setFiltersOpened] = useState(false); | |||||
| const offers = useOffers(); | |||||
| 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> | |||||
| ); | |||||
| }; | |||||
| export default HomePage; |
| import React from "react"; | import React from "react"; | ||||
| import { useHistory } from "react-router-dom"; | import { useHistory } from "react-router-dom"; | ||||
| import { ChatColumn } from "../../components/ChatColumn/ChatColumn"; | import { ChatColumn } from "../../components/ChatColumn/ChatColumn"; | ||||
| import { CHAT_MESSAGE_PAGE } from "../../constants/pages"; | |||||
| import { DIRECT_CHAT_PAGE } from "../../constants/pages"; | |||||
| import ChatLayout from "../../layouts/ChatLayout/ChatLayout"; | import ChatLayout from "../../layouts/ChatLayout/ChatLayout"; | ||||
| import { replaceInRoute } from "../../util/helpers/routeHelpers"; | import { replaceInRoute } from "../../util/helpers/routeHelpers"; | ||||
| import { ChatPageContainer } from "./Chat.styled"; | |||||
| import { MessagesListPageContainer } from "./MessagesListPage.styled"; | |||||
| export const ChatPage = () => { | |||||
| export const MessagesListPage = () => { | |||||
| const history = useHistory(); | const history = useHistory(); | ||||
| const navigateToChat = (chatId) => { | const navigateToChat = (chatId) => { | ||||
| setTimeout(() => { | setTimeout(() => { | ||||
| history.push( | history.push( | ||||
| replaceInRoute(CHAT_MESSAGE_PAGE, { | |||||
| replaceInRoute(DIRECT_CHAT_PAGE, { | |||||
| idChat: chatId, | idChat: chatId, | ||||
| }) | }) | ||||
| ); | ); | ||||
| }, 120); | }, 120); | ||||
| }; | }; | ||||
| return ( | return ( | ||||
| <ChatPageContainer> | |||||
| <MessagesListPageContainer> | |||||
| <ChatLayout content={<ChatColumn navigateToChat={navigateToChat} />} /> | <ChatLayout content={<ChatColumn navigateToChat={navigateToChat} />} /> | ||||
| </ChatPageContainer> | |||||
| </MessagesListPageContainer> | |||||
| ); | ); | ||||
| }; | }; | ||||
| ChatPage.propTypes = {}; | |||||
| MessagesListPage.propTypes = {}; | |||||
| export default ChatPage; | |||||
| export default MessagesListPage; |
| import styled from "styled-components"; | import styled from "styled-components"; | ||||
| import { transitionOnLoadFromLeft } from "../../components/Styles/globalStyleComponents"; | import { transitionOnLoadFromLeft } from "../../components/Styles/globalStyleComponents"; | ||||
| export const ChatPageContainer = styled(Container)` | |||||
| export const MessagesListPageContainer = styled(Container)` | |||||
| padding: 0; | padding: 0; | ||||
| margin: 0; | margin: 0; | ||||
| animation: 0.2s ease 0s 1 ${transitionOnLoadFromLeft}; | animation: 0.2s ease 0s 1 ${transitionOnLoadFromLeft}; |
| function* fetchCategories() { | function* fetchCategories() { | ||||
| try { | try { | ||||
| const data = yield call(attemptFetchCategories); | const data = yield call(attemptFetchCategories); | ||||
| console.log("ASDFASDF", data); | |||||
| if (!data?.data) throw new Error(); | if (!data?.data) throw new Error(); | ||||
| yield put(setCategories(data.data)); | yield put(setCategories(data.data)); | ||||
| yield put(fetchCategoriesSuccess()); | yield put(fetchCategoriesSuccess()); |
| import { CHAT_MESSAGE_PAGE } from "../../constants/pages"; | |||||
| import { DIRECT_CHAT_PAGE } from "../../constants/pages"; | |||||
| import history from "../../store/utils/history"; | import history from "../../store/utils/history"; | ||||
| import { replaceInRoute } from "./routeHelpers"; | import { replaceInRoute } from "./routeHelpers"; | ||||
| ); | ); | ||||
| if (chatItem !== undefined) { | if (chatItem !== undefined) { | ||||
| history.push( | history.push( | ||||
| replaceInRoute(CHAT_MESSAGE_PAGE, { idChat: chatItem.chat._id }) | |||||
| replaceInRoute(DIRECT_CHAT_PAGE, { idChat: chatItem.chat._id }) | |||||
| ); | ); | ||||
| } else { | } else { | ||||
| if (offer?.offer?.userId !== userId) { | if (offer?.offer?.userId !== userId) { | ||||
| history.push( | history.push( | ||||
| replaceInRoute(CHAT_MESSAGE_PAGE, { idChat: "newMessage" }), | |||||
| replaceInRoute(DIRECT_CHAT_PAGE, { idChat: "newMessage" }), | |||||
| { | { | ||||
| offerId: offer?.offer?._id, | offerId: offer?.offer?._id, | ||||
| } | } |
| export const sortReviews = (reviews = [], positive = false) => { | export const sortReviews = (reviews = [], positive = false) => { | ||||
| let newReviews; | let newReviews; | ||||
| console.log(reviews); | |||||
| if (!Array.isArray(reviews)) return []; | if (!Array.isArray(reviews)) return []; | ||||
| if (positive) { | if (positive) { | ||||
| newReviews = [ | newReviews = [ |