| @@ -1 +0,0 @@ | |||
| REACT_APP_BASE_API_URL=http://localhost:3001/ | |||
| @@ -13,6 +13,7 @@ | |||
| # misc | |||
| .DS_Store | |||
| .env | |||
| .env.local | |||
| .env.development.local | |||
| .env.test.local | |||
| @@ -1,6 +1,6 @@ | |||
| { | |||
| "name": "web", | |||
| "version": "4.0.9", | |||
| "version": "4.0.10", | |||
| "private": true, | |||
| "dependencies": { | |||
| "@emotion/react": "^11.5.0", | |||
| @@ -14,6 +14,12 @@ | |||
| href="https://fonts.googleapis.com/css?family=Poppins&display=swap" | |||
| onload="this.onload=null;this.rel='stylesheet';this.type='text/css'" | |||
| /> | |||
| <link | |||
| rel="preload" | |||
| as="style" | |||
| href="https://fonts.googleapis.com/css?family=Source+Code+Pro:400,700&display=swap" | |||
| onload="this.onload=null;this.rel='stylesheet';this.type='text/css'" | |||
| /> | |||
| <link | |||
| style | |||
| rel="preload" | |||
| @@ -6,7 +6,7 @@ import { StyledEngineProvider } from "@mui/material"; | |||
| import { useSelector } from "react-redux"; | |||
| import i18next from "i18next"; | |||
| import { selectUserId } from "./store/selectors/loginSelectors"; | |||
| import { selectJwtToken, selectUserId } from "./store/selectors/loginSelectors"; | |||
| import history from "./store/utils/history"; | |||
| import AppRoutes from "./AppRoutes"; | |||
| import { socketInit } from "./socket/socket"; | |||
| @@ -18,11 +18,11 @@ import "react-toastify/dist/ReactToastify.css"; | |||
| const App = () => { | |||
| const userId = useSelector(selectUserId); | |||
| const token = useSelector(selectJwtToken); | |||
| useEffect(() => { | |||
| socketInit(userId); | |||
| }, [userId]); | |||
| socketInit(userId, token); | |||
| }, [userId, token]); | |||
| return ( | |||
| <Router history={history}> | |||
| <Helmet> | |||
| @@ -0,0 +1,8 @@ | |||
| <svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg"> | |||
| <path d="M6 4.5H15.75" stroke="#667080" stroke-width="1.24" stroke-linecap="round" stroke-linejoin="round"/> | |||
| <path d="M6 9H15.75" stroke="#667080" stroke-width="1.24" stroke-linecap="round" stroke-linejoin="round"/> | |||
| <path d="M6 13.5H15.75" stroke="#667080" stroke-width="1.24" stroke-linecap="round" stroke-linejoin="round"/> | |||
| <path d="M2.25 4.5H2.2575" stroke="#667080" stroke-width="1.24" stroke-linecap="round" stroke-linejoin="round"/> | |||
| <path d="M2.25 9H2.2575" stroke="#667080" stroke-width="1.24" stroke-linecap="round" stroke-linejoin="round"/> | |||
| <path d="M2.25 13.5H2.2575" stroke="#667080" stroke-width="1.24" stroke-linecap="round" stroke-linejoin="round"/> | |||
| </svg> | |||
| @@ -5,12 +5,12 @@ import AboutSection from "./AboutSection/AboutSection"; | |||
| import { useTranslation } from "react-i18next"; | |||
| import SectionImage1 from "../../assets/images/about/about-1.png"; | |||
| import SectionImage2 from "../../assets/images/about/about-2.png"; | |||
| import CheckOffersButton from "./CheckOffersButton/CheckOffersButton"; | |||
| // import CheckOffersButton from "./CheckOffersButton/CheckOffersButton"; | |||
| import { AboutComponentContainer } from "./AboutComponent.styled"; | |||
| import useIsMobile from "../../hooks/useIsMobile"; | |||
| // import useIsMobile from "../../hooks/useIsMobile"; | |||
| const AboutComponent = forwardRef((props, ref) => { | |||
| const { isMobile } = useIsMobile(); | |||
| // const { isMobile } = useIsMobile(); | |||
| const { t } = useTranslation(); | |||
| return ( | |||
| <AboutComponentContainer ref={ref}> | |||
| @@ -26,7 +26,7 @@ const AboutComponent = forwardRef((props, ref) => { | |||
| image={SectionImage2} | |||
| reverse | |||
| /> | |||
| {!isMobile && <CheckOffersButton />} | |||
| {/* <CheckOffersButton /> */} | |||
| </AboutComponentContainer> | |||
| ); | |||
| }); | |||
| @@ -4,6 +4,10 @@ import selectedTheme from "../../../themes"; | |||
| export const AboutHeaderContainer = styled(Box)` | |||
| margin: 72px; | |||
| @media (max-width: 1430px) { | |||
| margin: 45px; | |||
| } | |||
| @media (max-width: 1200px) { | |||
| margin: 36px; | |||
| } | |||
| @@ -14,9 +14,20 @@ export const AboutSectionContainer = styled(Box)` | |||
| flex-direction: ${(props) => (props.reverse ? "row-reverse" : "row")}; | |||
| gap: 144px; | |||
| margin-bottom: 72px; | |||
| ${(props) => props.reverse && `text-align: right;`} | |||
| @media (max-width: 1430px) { | |||
| ${(props) => | |||
| props.reverse | |||
| ? ` | |||
| margin-right: 45px | |||
| ` | |||
| : `margin-left: 45px`}; | |||
| } | |||
| @media (max-width: 1069px) { | |||
| flex-direction: column; | |||
| margin-bottom: 41px; | |||
| } | |||
| @media (max-width: 1200px) { | |||
| @@ -29,7 +40,7 @@ export const AboutSectionContainer = styled(Box)` | |||
| } | |||
| @media (max-width: 1319px) { | |||
| gap: 54px; | |||
| gap: 40px; | |||
| } | |||
| @media (max-width: 600px) { | |||
| @@ -66,12 +77,12 @@ export const AboutSectionText = styled(Typography)` | |||
| line-height: 22px; | |||
| color: ${selectedTheme.colors.primaryGrayText}; | |||
| @media (max-width: 1069px) { | |||
| ${(props) => props.reverse && `margin-left: 36px;`} | |||
| @media (min-width: 1069px) and (max-width: 1230px) { | |||
| ${(props) => props.reverse && `padding-bottom: 50px;`} | |||
| } | |||
| @media (max-width: 1160px) { | |||
| ${(props) => props.reverse && `padding-bottom: 20px;`} | |||
| @media (max-width: 1069px) { | |||
| ${(props) => props.reverse && `margin-left: 36px;`} | |||
| } | |||
| @media (max-width: 600px) { | |||
| @@ -87,8 +98,8 @@ export const AboutSectionImage = styled.img` | |||
| object-fit: cover; | |||
| @media (max-width: 1069px) { | |||
| width: 100%; | |||
| ${(props) => props.reverse && `padding-bottom: 36px`} | |||
| width: 80%; | |||
| ${(props) => !props.reverse && `align-self: end;`} | |||
| } | |||
| @media (max-width: 600px) { | |||
| @@ -23,12 +23,23 @@ export const CheckOffersButtonContainer = styled(PrimaryButton)` | |||
| background-color: ${selectedTheme.colors.primaryPurple} !important; | |||
| } | |||
| @media (max-width: 1160px) { | |||
| bottom: -16px; | |||
| @media (max-width: 1430px) { | |||
| right: 22px; | |||
| } | |||
| @media (max-width: 1230px) { | |||
| bottom: 0; | |||
| } | |||
| @media (max-width: 1200px) { | |||
| right: 16px; | |||
| bottom: 0; | |||
| right: 18px; | |||
| } | |||
| @media (max-width: 1069px) { | |||
| position: relative; | |||
| right: 0; | |||
| align-self: flex-end; | |||
| } | |||
| @media (max-width: 600px) { | |||
| @@ -7,6 +7,7 @@ import { | |||
| MarketplaceIcon, | |||
| } from "./MarketplaceButton.styled"; | |||
| import { useTranslation } from "react-i18next"; | |||
| import history from "../../../../store/utils/history"; | |||
| const MarketplaceButton = () => { | |||
| const { t } = useTranslation(); | |||
| @@ -11,6 +11,7 @@ import { useTranslation } from "react-i18next"; | |||
| import { isInRoute, routeMatches } from "../../../../util/helpers/routeHelpers"; | |||
| import { ADMIN_HOME_PAGE, ADMIN_USERS_PAGE } from "../../../../constants/pages"; | |||
| import { ADMIN_NAVIGATION } from "../../../../constants/adminNavigation"; | |||
| import history from "../../../../store/utils/history"; | |||
| const SidebarNavigation = () => { | |||
| const { t } = useTranslation(); | |||
| @@ -1,5 +1,5 @@ | |||
| import { ReactComponent as DownArrow } from "../../../assets/images/svg/arrow-down.svg"; | |||
| import styled from "styled-components"; | |||
| import styled, { css } from "styled-components"; | |||
| import selectedTheme from "../../../themes"; | |||
| import { IconButton } from "../IconButton/IconButton"; | |||
| @@ -11,9 +11,9 @@ export const ArrowIcon = styled(DownArrow)` | |||
| `} | |||
| width: 18px; | |||
| height: 18px; | |||
| /* position: relative; | |||
| position: relative; | |||
| top: 1px; | |||
| left: 1px; */ | |||
| left: 1px; | |||
| & path { | |||
| ${(props) => | |||
| props.disabled && | |||
| @@ -46,7 +46,7 @@ export const ArrowContainer = styled(IconButton)` | |||
| } | |||
| ${(props) => | |||
| props.disabled && | |||
| ` | |||
| css` | |||
| border 1px solid ${selectedTheme.colors.iconStrokeDisabledColor} !important; | |||
| &:hover { | |||
| background-color: inherit; | |||
| @@ -18,7 +18,7 @@ export const IconButton = (props) => { | |||
| onClick={props.onClick} | |||
| sx={props.style} | |||
| iconcolor={props.iconColor} | |||
| {...props} | |||
| // {...props} | |||
| > | |||
| {props.children} | |||
| </IconButtonStyled> | |||
| @@ -12,42 +12,48 @@ import MobileOfferDetails from "./MobileOfferDetails/MobileOfferDetails"; | |||
| import useIsMobile from "../../../hooks/useIsMobile"; | |||
| import { getImageUrl, variants } from "../../../util/helpers/imageUrlGetter"; | |||
| import BlockedProfile from "../ProfileCard/BlockedProfile/BlockedProfile"; | |||
| import { useSelector } from "react-redux"; | |||
| import { selectUserId } from "../../../store/selectors/loginSelectors"; | |||
| // Chat card is shown only on mobile phones (route /messages) | |||
| const ChatCard = (props) => { | |||
| const { isMobile } = useIsMobile(); | |||
| const userId = useSelector(selectUserId); | |||
| const chat = useMemo(() => { | |||
| return props.chat; | |||
| }, [props.chat]); | |||
| const routeToItem = () => { | |||
| props.navigateToChat(chat?.chat?._id); | |||
| props.navigateToChat(chat?._id); | |||
| }; | |||
| const interlocutor = useMemo(() => { | |||
| return userId === chat?.participants[0]._id ? 1 : 0; | |||
| }, [userId, chat]); | |||
| return ( | |||
| <ChatCardContainer onClick={routeToItem}> | |||
| <UserImgWrapper> | |||
| <UserImage | |||
| src={getImageUrl( | |||
| chat?.interlocutorData?.image, | |||
| chat?.participants[interlocutor].image, | |||
| variants.chatCard, | |||
| isMobile | |||
| )} | |||
| /> | |||
| </UserImgWrapper> | |||
| <ChatInfo isBlocked={props.chat.interlocutorData?._blocked}> | |||
| <ChatInfo isBlocked={props.chat.participants[interlocutor]?._blocked}> | |||
| <ProfileNameContainer> | |||
| <UserName>{chat?.interlocutorData?.name}</UserName> | |||
| {(props.chat.interlocutorData?._blocked || | |||
| props.chat.interlocutorData?._deleted) && ( | |||
| <UserName>{chat?.participants[interlocutor]?.company?.name}</UserName> | |||
| {(props.chat?.participants[interlocutor]?._blocked || | |||
| props.chat?.participants[interlocutor]?._deleted) && ( | |||
| <BlockedProfile | |||
| redText | |||
| chatCard | |||
| shortText | |||
| aboveTitle | |||
| hideIcon | |||
| deleted={props.chat.interlocutorData?._deleted} | |||
| deleted={props.chat?.participants[interlocutor]?._deleted} | |||
| /> | |||
| )} | |||
| </ProfileNameContainer> | |||
| @@ -12,7 +12,7 @@ const MobileOfferDetails = (props) => { | |||
| return ( | |||
| <OfferCardContainerMobile> | |||
| <OfferTextMobile>{t("messages.cardProduct")}</OfferTextMobile> | |||
| <OfferTitleMobile>{props.chat?.offerData?.name}</OfferTitleMobile> | |||
| <OfferTitleMobile>{props.chat?.offer?.name}</OfferTitleMobile> | |||
| </OfferCardContainerMobile> | |||
| ); | |||
| }; | |||
| @@ -35,7 +35,10 @@ import { | |||
| ITEM_DETAILS_PAGE, | |||
| PROFILE_PAGE, | |||
| } from "../../../constants/pages"; | |||
| import { dynamicRouteMatches, replaceInRoute } from "../../../util/helpers/routeHelpers"; | |||
| import { | |||
| dynamicRouteMatches, | |||
| replaceInRoute, | |||
| } from "../../../util/helpers/routeHelpers"; | |||
| import { selectIsLoadingByActionType } from "../../../store/selectors/loadingSelectors"; | |||
| import { | |||
| OFFER_ADD_SCOPE, | |||
| @@ -64,8 +67,12 @@ const CreateOffer = ({ editOffer, offer, isAdmin, customUserId }) => { | |||
| if (editOffer) { | |||
| if (routeMatches(BASE_PAGE) || routeMatches(HOME_PAGE)) | |||
| dispatch(fetchOffers({ queryString })); | |||
| if (dynamicRouteMatches(PROFILE_PAGE) || dynamicRouteMatches(ADMIN_SINGLE_USER_PAGE)) | |||
| if (isAdmin) dispatch(fetchProfileOffers(customUserId)); | |||
| if ( | |||
| dynamicRouteMatches(PROFILE_PAGE) || | |||
| dynamicRouteMatches(ADMIN_SINGLE_USER_PAGE) | |||
| ) | |||
| if (isAdmin) | |||
| dispatch(fetchProfileOffers({ idProfile: customUserId, isAdmin })); | |||
| else dispatch(fetchProfileOffers(userId)); | |||
| if ( | |||
| @@ -21,6 +21,7 @@ const CategoryChoser = forwardRef((props, ref) => { | |||
| const handleSelectCategory = (category) => { | |||
| filters.category.setSelectedCategory(category); | |||
| filters.subcategory.setSelectedSubcategory({}); | |||
| props.offers.applyFilters(); | |||
| }; | |||
| useImperativeHandle(ref, () => ({ | |||
| closeSection: () => { | |||
| @@ -31,7 +32,8 @@ const CategoryChoser = forwardRef((props, ref) => { | |||
| useEffect(() => { | |||
| if ( | |||
| !filters.category.selectedCategoryLocally || | |||
| (filters.category.selectedCategoryLocally && | |||
| !("_id" in filters.category.selectedCategoryLocally)) || | |||
| (filters.category.selectedCategoryLocally?._id === 0 && !isOpened) | |||
| ) { | |||
| setIsOpened(false); | |||
| @@ -60,6 +62,7 @@ const CategoryChoser = forwardRef((props, ref) => { | |||
| setSelected={handleSelectCategory} | |||
| selected={filters.category.selectedCategoryLocally} | |||
| firstOption={firstCategoryOption} | |||
| offers={props.offers} | |||
| /> | |||
| ); | |||
| }); | |||
| @@ -68,6 +71,7 @@ CategoryChoser.displayName = "CategoryChoser"; | |||
| CategoryChoser.propTypes = { | |||
| filters: PropTypes.any, | |||
| offers: PropTypes.any, | |||
| }; | |||
| export default CategoryChoser; | |||
| @@ -11,6 +11,7 @@ import FilterSubDropdown from "../../FilterDropdown/Checkbox/FilterSubDropdown/F | |||
| const CompanyChoser = forwardRef((props, ref) => { | |||
| const [isOpened, setIsOpened] = useState(false); | |||
| const [appliedFilters, setAppliedFilters] = useState(false); | |||
| const filters = props.filters; | |||
| const { t } = useTranslation(); | |||
| @@ -26,6 +27,18 @@ const CompanyChoser = forwardRef((props, ref) => { | |||
| } | |||
| }, [filters.companies.selectedCompaniesLocally]); | |||
| useEffect(() => { | |||
| if (appliedFilters) { | |||
| props?.offers?.apply(); | |||
| setAppliedFilters(false); | |||
| } | |||
| }, [filters.companies.selectedCompaniesLocally]); | |||
| const handleSetItemsSelected = (items) => { | |||
| filters.companies.setSelectedCompanies(items); | |||
| setAppliedFilters(true); | |||
| }; | |||
| return ( | |||
| <FilterSubDropdown | |||
| searchPlaceholder={t("filters.company.placeholder")} | |||
| @@ -35,8 +48,9 @@ const CompanyChoser = forwardRef((props, ref) => { | |||
| handleOpen={() => setIsOpened((prevIsOpened) => !prevIsOpened)} | |||
| icon={<CompanyIcon />} | |||
| title={t("filters.company.title")} | |||
| setItemsSelected={filters.companies.setSelectedCompanies} | |||
| setItemsSelected={handleSetItemsSelected} | |||
| companies | |||
| offers={props.offers} | |||
| /> | |||
| ); | |||
| }); | |||
| @@ -45,6 +59,7 @@ CompanyChoser.displayName = "CompanyChoser"; | |||
| CompanyChoser.propTypes = { | |||
| filters: PropTypes.any, | |||
| offers: PropTypes.any, | |||
| }; | |||
| export default CompanyChoser; | |||
| @@ -1,4 +1,10 @@ | |||
| import React, { forwardRef, useEffect, useImperativeHandle, useMemo, useState } from "react"; | |||
| import React, { | |||
| forwardRef, | |||
| useEffect, | |||
| useImperativeHandle, | |||
| useMemo, | |||
| useState, | |||
| } from "react"; | |||
| import PropTypes from "prop-types"; | |||
| import FilterCheckboxDropdown from "../../FilterDropdown/Checkbox/FilterCheckboxDropdown"; | |||
| import { LocationIcon } from "./LocationChoser.styled"; | |||
| @@ -6,10 +12,14 @@ import { useTranslation } from "react-i18next"; | |||
| const LocationChoser = forwardRef((props, ref) => { | |||
| const { t } = useTranslation(); | |||
| const [appliedFilters, setAppliedFilters] = useState(false); | |||
| const [isOpened, setIsOpened] = useState(false); | |||
| const filters = props.filters; | |||
| const allLocations = useMemo(() => filters.locations.allLocations || [], [filters.locations]) | |||
| const allLocations = useMemo( | |||
| () => filters.locations.allLocations || [], | |||
| [filters.locations] | |||
| ); | |||
| useImperativeHandle(ref, () => ({ | |||
| closeSection: () => { | |||
| @@ -21,7 +31,19 @@ const LocationChoser = forwardRef((props, ref) => { | |||
| if (filters.locations.selectedLocationsLocally.length > 0 && !isOpened) { | |||
| setIsOpened(true); | |||
| } | |||
| }, [filters.locations.selectedLocationsLocally]) | |||
| }, [filters.locations.selectedLocationsLocally]); | |||
| useEffect(() => { | |||
| if (appliedFilters) { | |||
| props?.offers?.apply(); | |||
| setAppliedFilters(false); | |||
| } | |||
| }, [appliedFilters]); | |||
| const handleSetItemsSelected = (items) => { | |||
| filters.locations.setSelectedLocations(items); | |||
| setAppliedFilters(true); | |||
| }; | |||
| return ( | |||
| <FilterCheckboxDropdown | |||
| searchPlaceholder={t("filters.location.placeholder")} | |||
| @@ -31,7 +53,8 @@ const LocationChoser = forwardRef((props, ref) => { | |||
| handleOpen={() => setIsOpened((prevIsOpened) => !prevIsOpened)} | |||
| icon={<LocationIcon />} | |||
| title={t("filters.location.title")} | |||
| setItemsSelected={filters.locations.setSelectedLocations} | |||
| setItemsSelected={handleSetItemsSelected} | |||
| offers={props.offers} | |||
| /> | |||
| ); | |||
| }); | |||
| @@ -40,6 +63,7 @@ LocationChoser.displayName = "LocationChoser"; | |||
| LocationChoser.propTypes = { | |||
| filters: PropTypes.any, | |||
| offers: PropTypes.any, | |||
| }; | |||
| export default LocationChoser; | |||
| @@ -32,11 +32,18 @@ const SubcategoryChoser = forwardRef((props, ref) => { | |||
| }, | |||
| })); | |||
| const handleSelectSubcategory = (subcategory) => { | |||
| filters.subcategory.setSelectedSubcategory(subcategory, !props.myOffers); | |||
| // if (props.myOffers) props.offers?.applyFilters(); | |||
| }; | |||
| useEffect(() => { | |||
| if (props?.queryStringHook?.isInitiallyLoaded || props.isMyOffers) { | |||
| if (props?.queryStringHook?.isInitiallyLoaded || props.myOffers) { | |||
| if ( | |||
| !filters.category.selectedCategoryLocally || | |||
| filters.category.selectedCategoryLocally?._id === 0 | |||
| (filters.category.selectedCategoryLocally && | |||
| !("_id" in filters.category.selectedCategoryLocally)) || | |||
| filters.category.selectedCategoryLocally?._id === 0 || | |||
| !filters.category.selectedCategoryLocally | |||
| ) { | |||
| setIsOpened(false); | |||
| setIsDisabled(true); | |||
| @@ -46,12 +53,14 @@ const SubcategoryChoser = forwardRef((props, ref) => { | |||
| } | |||
| } else { | |||
| if ( | |||
| !filters.subcategory.selectedSubcategoryLocally || | |||
| (filters.subcategory.selectedSubcategoryLocally && | |||
| !("_id" in filters.subcategory.selectedSubcategoryLocally)) || | |||
| filters.subcategory.selectedSubcategoryLocally?._id === 0 | |||
| ) { | |||
| setIsOpened(false); | |||
| if ( | |||
| !filters.category.selectedCategoryLocally || | |||
| (filters.category.selectedCategoryLocally && | |||
| !("_id" in filters.category.selectedCategoryLocally)) || | |||
| filters.category.selectedCategoryLocally?._id === 0 | |||
| ) { | |||
| setIsDisabled(true); | |||
| @@ -74,12 +83,13 @@ const SubcategoryChoser = forwardRef((props, ref) => { | |||
| : t("filters.subcategories.title") | |||
| } | |||
| searchPlaceholder={t("filters.subcategories.placeholder")} | |||
| setSelected={filters.subcategory.setSelectedSubcategory} | |||
| setSelected={handleSelectSubcategory} | |||
| selected={filters.subcategory.selectedSubcategoryLocally} | |||
| open={isOpened} | |||
| disabled={isDisabled} | |||
| handleOpen={handleOpen} | |||
| firstOption={filters.subcategory.initialOption} | |||
| offers={props.offers} | |||
| /> | |||
| ); | |||
| }); | |||
| @@ -90,7 +100,8 @@ SubcategoryChoser.propTypes = { | |||
| filters: PropTypes.any, | |||
| categoryOpened: PropTypes.bool, | |||
| queryStringHook: PropTypes.any, | |||
| isMyOffers: PropTypes.bool, | |||
| myOffers: PropTypes.bool, | |||
| offers: PropTypes.any, | |||
| }; | |||
| export default SubcategoryChoser; | |||
| @@ -3,7 +3,7 @@ import PropTypes from "prop-types"; | |||
| import { ContentContainer, FilterCardContainer } from "./FilterCard.styled"; | |||
| import HeaderBack from "../../ItemDetails/Header/Header"; | |||
| import FilterHeader from "./FilterHeader/FilterHeader"; | |||
| import FilterFooter from "./FilterFooter/FilterFooter"; | |||
| // import FilterFooter from "./FilterFooter/FilterFooter"; | |||
| import CategoryChoser from "./Choser/CategoryChoser/CategoryChoser"; | |||
| import SubcategoryChoser from "./Choser/SubcategoryChoser/SubcategoryChoser"; | |||
| import LocationChoser from "./Choser/LocationChoser/LocationChoser"; | |||
| @@ -42,7 +42,7 @@ const FilterCard = (props) => { | |||
| <ContentContainer> | |||
| {/* Categories */} | |||
| <CategoryChoser filters={filters} ref={categoryRef} /> | |||
| <CategoryChoser filters={filters} ref={categoryRef} offers={offers} /> | |||
| {/* Subcategories */} | |||
| <SubcategoryChoser | |||
| @@ -50,26 +50,27 @@ const FilterCard = (props) => { | |||
| queryStringHook={offers.queryStringHook} | |||
| ref={subcategoryRef} | |||
| categoryOpened={categoryRef.current?.isOpened} | |||
| isMyOffers={props.myOffers} | |||
| myOffers={props.myOffers} | |||
| offers={offers} | |||
| /> | |||
| {/* Locations */} | |||
| {!props.myOffers && ( | |||
| <LocationChoser filters={filters} ref={locationRef} /> | |||
| <LocationChoser filters={filters} ref={locationRef} offers={offers} /> | |||
| )} | |||
| {/* Companies */} | |||
| {!props.myOffers && ( | |||
| <CompanyChoser filters={filters} ref={companyRef} /> | |||
| <CompanyChoser filters={filters} ref={companyRef} offers={offers} /> | |||
| )} | |||
| </ContentContainer> | |||
| <FilterFooter | |||
| {/* <FilterFooter | |||
| toggleFilters={props.toggleFilters} | |||
| filters={offers} | |||
| closeAllSections={closeAllSections} | |||
| isMyOffers={props.myOffers} | |||
| /> | |||
| /> */} | |||
| </FilterCardContainer> | |||
| ); | |||
| }; | |||
| @@ -16,7 +16,9 @@ const CheckboxDropdownList = (props) => { | |||
| const data = props.data; | |||
| const [isOpened, setIsOpened] = useState(false); | |||
| const handleDelete = (item) => { | |||
| props.setItemsSelected([...props.filters.filter((p) => p !== item)]); | |||
| console.log(item); | |||
| console.log(props.filters) | |||
| props.setItemsSelected([...props.filters.filter((p) => p?._id !== item?._id)]); | |||
| }; | |||
| const handleOpen = () => { | |||
| setIsOpened((prevState) => !prevState); | |||
| @@ -92,6 +94,7 @@ CheckboxDropdownList.propTypes = { | |||
| open: PropTypes.bool, | |||
| handleOpen: PropTypes.func, | |||
| companies: PropTypes.bool, | |||
| offers: PropTypes.any, | |||
| }; | |||
| export default CheckboxDropdownList; | |||
| @@ -49,8 +49,10 @@ const FilterCheckboxDropdown = (props) => { | |||
| (p) => p?.city?.toString() !== item?.city?.toString() | |||
| ), | |||
| ]); | |||
| props.offers.applyFilters(); | |||
| } else { | |||
| props.setItemsSelected([...props.filters, item]); | |||
| props.offers.applyFilters(); | |||
| } | |||
| } | |||
| }; | |||
| @@ -72,6 +74,7 @@ const FilterCheckboxDropdown = (props) => { | |||
| handleOpen={handleOpen} | |||
| setItemsSelected={props.setItemsSelected} | |||
| companies={props.companies} | |||
| offers={props.offers} | |||
| > | |||
| {(isOpened || props?.open) && | |||
| dataToShow.map((item) => { | |||
| @@ -102,6 +105,7 @@ FilterCheckboxDropdown.propTypes = { | |||
| open: PropTypes.bool, | |||
| handleOpen: PropTypes.func, | |||
| companies: PropTypes.bool, | |||
| offers: PropTypes.any, | |||
| }; | |||
| FilterCheckboxDropdown.defaultProps = { | |||
| oneValueAllowed: false, | |||
| @@ -49,8 +49,10 @@ const FilterSmallDropdown = (props) => { | |||
| (p) => p?.companyName?.toString() !== item?.companyName?.toString() | |||
| ), | |||
| ]); | |||
| props.offers.applyFilters(); | |||
| } else { | |||
| props.setItemsSelected([...props.filters, item]); | |||
| props.offers.applyFilters(); | |||
| } | |||
| } | |||
| }; | |||
| @@ -97,6 +99,7 @@ FilterSmallDropdown.propTypes = { | |||
| companies: PropTypes.bool, | |||
| letters: PropTypes.any, | |||
| dataToShow: PropTypes.array, | |||
| offers: PropTypes.any, | |||
| }; | |||
| FilterSmallDropdown.defaultProps = { | |||
| oneValueAllowed: false, | |||
| @@ -48,6 +48,7 @@ const FilterSubDropdown = (props) => { | |||
| filters={props.filters} | |||
| icon={props.icon} | |||
| data={data} | |||
| offers={props?.offers} | |||
| searchPlaceholder={props.searchPlaceholder} | |||
| open={props?.open !== undefined ? props.open : isOpened} | |||
| handleOpen={handleOpen} | |||
| @@ -62,6 +63,7 @@ const FilterSubDropdown = (props) => { | |||
| filters={props.filters} | |||
| setItemsSelected={props.setItemsSelected} | |||
| companies={props.companies} | |||
| offers={props.offers} | |||
| /> | |||
| <FilterSmallDropdown | |||
| letters={t("filters.company.secondSort")} | |||
| @@ -69,6 +71,7 @@ const FilterSubDropdown = (props) => { | |||
| filters={props.filters} | |||
| setItemsSelected={props.setItemsSelected} | |||
| companies={props.companies} | |||
| offers={props.offers} | |||
| /> | |||
| <FilterSmallDropdown | |||
| letters={t("filters.company.thirdSort")} | |||
| @@ -76,6 +79,7 @@ const FilterSubDropdown = (props) => { | |||
| filters={props.filters} | |||
| setItemsSelected={props.setItemsSelected} | |||
| companies={props.companies} | |||
| offers={props.offers} | |||
| /> | |||
| </> | |||
| )} | |||
| @@ -95,6 +99,7 @@ FilterSubDropdown.propTypes = { | |||
| open: PropTypes.bool, | |||
| handleOpen: PropTypes.func, | |||
| companies: PropTypes.bool, | |||
| offers: PropTypes.any, | |||
| }; | |||
| FilterSubDropdown.defaultProps = { | |||
| oneValueAllowed: false, | |||
| @@ -111,7 +111,10 @@ const FilterRadioDropdown = (props) => { | |||
| label={props.firstOption.label} | |||
| // number={item.numberOfProducts} | |||
| fullWidth | |||
| checked={!props.selected || props.selected._id === 0} | |||
| checked={ | |||
| (props?.selected && !("_id" in props?.selected)) || | |||
| props?.selected?._id === 0 || !props?.selected | |||
| } | |||
| onChange={props.setSelected} | |||
| /> | |||
| </DropdownItem> | |||
| @@ -37,7 +37,7 @@ const ImagesCarousel = (props) => { | |||
| <CloseButtonIcon /> | |||
| </CloseButton> | |||
| <Scroller isCarousel> | |||
| {props?.offer?.offer?.images.map((image) => { | |||
| {props?.images.map((image) => { | |||
| if (!image) return; | |||
| return ( | |||
| <OfferImage | |||
| @@ -48,7 +48,7 @@ const ImagesCarousel = (props) => { | |||
| })} | |||
| </Scroller> | |||
| <Offer> | |||
| {t("carousel.offer")} <OfferSpan>{props.offer.offer.name}</OfferSpan> | |||
| {t("carousel.offer")} <OfferSpan>{props.offer.name}</OfferSpan> | |||
| </Offer> | |||
| </ImagesCarouselContainer> | |||
| </> | |||
| @@ -59,6 +59,7 @@ ImagesCarousel.propTypes = { | |||
| offer: PropTypes.any, | |||
| onModalClose: PropTypes.any, | |||
| createOffer: PropTypes.bool, | |||
| images: PropTypes.array | |||
| }; | |||
| export default ImagesCarousel; | |||
| @@ -50,11 +50,12 @@ const ItemDetailsCard = (props) => { | |||
| const offer = useMemo(() => { | |||
| if (props.offer) { | |||
| if ( | |||
| props.offer.offer._id === routeMatch.params?.offerId || | |||
| props.createOffer | |||
| props.offer._id === routeMatch.params?.offerId && | |||
| !props?.createOffer | |||
| ) { | |||
| return props.offer; | |||
| } | |||
| if (props.createOffer) return props.offer.offer; | |||
| } | |||
| return itemDetailsData; | |||
| }, [props.offer, props.createOffer, routeMatch.params]); | |||
| @@ -66,21 +67,21 @@ const ItemDetailsCard = (props) => { | |||
| }, []); | |||
| useEffect(() => { | |||
| if (offer?.offer?._id) { | |||
| increaseOfferCounter(offer?.offer?._id); | |||
| if (offer?._id) { | |||
| increaseOfferCounter(offer?._id); | |||
| } | |||
| }, [offer]); | |||
| const date = formatDateLocale(new Date(offer?.offer?._created)); | |||
| const date = formatDateLocale(new Date(offer?._created)); | |||
| const startExchange = () => { | |||
| startChat(chats, offer?.offer, userId); | |||
| startChat(chats, offer, userId); | |||
| }; | |||
| const showDeleteOfferModalHandler = () => { | |||
| dispatch( | |||
| toggleDeleteOfferModal({ | |||
| offer: offer.offer, | |||
| offer: offer, | |||
| isAdmin: props.isAdmin, | |||
| }) | |||
| ); | |||
| @@ -90,23 +91,24 @@ const ItemDetailsCard = (props) => { | |||
| dispatch( | |||
| toggleEditOfferModal({ | |||
| editOffer: true, | |||
| offer: offer?.offer, | |||
| offer: offer, | |||
| isAdmin: props.isAdmin, | |||
| customUserId: offer?.offer?.userId, | |||
| customUserId: offer?.user?._id, | |||
| }) | |||
| ); | |||
| }; | |||
| const showPinOfferModalHandler = () => { | |||
| dispatch( | |||
| toggleDeleteOfferModal({ | |||
| offer: offer?.offer, | |||
| offer: offer, | |||
| pin: true, | |||
| pinnedOffer: offer?.offer?.pinned, | |||
| pinnedOffer: offer?.pinned, | |||
| deleteOffer: false, | |||
| }) | |||
| ); | |||
| }; | |||
| console.log(props) | |||
| return ( | |||
| <> | |||
| <ItemDetailsCardContainer | |||
| @@ -120,21 +122,15 @@ const ItemDetailsCard = (props) => { | |||
| <Info> | |||
| <Information | |||
| icon={<CategoryIcon />} | |||
| value={offer?.offer?.category?.name} | |||
| value={offer?.category?.name} | |||
| /> | |||
| <Information | |||
| icon={<SubcategoryIcon />} | |||
| value={offer?.offer?.subcategory} | |||
| /> | |||
| <Information | |||
| icon={<QuantityIcon />} | |||
| value={offer?.offer?.condition} | |||
| value={offer?.subcategory} | |||
| /> | |||
| <Information icon={<QuantityIcon />} value={offer?.condition} /> | |||
| {!props.hideViews && ( | |||
| <Information | |||
| icon={<EyeIcon />} | |||
| value={offer?.offer?.views?.count} | |||
| /> | |||
| <Information icon={<EyeIcon />} value={offer?.views?.count} /> | |||
| )} | |||
| </Info> | |||
| <PostDate previewCard={props.previewCard}>{date}</PostDate> | |||
| @@ -153,9 +149,11 @@ const ItemDetailsCard = (props) => { | |||
| <DateButtonsContainer> | |||
| {props.isMyOffer && ( | |||
| <ButtonsContainer> | |||
| <PinIconContainer onClick={showPinOfferModalHandler}> | |||
| {offer?.offer?.pinned ? <UnpinIcon /> : <PinIcon />} | |||
| </PinIconContainer> | |||
| {props?.isAdmin && ( | |||
| <PinIconContainer onClick={showPinOfferModalHandler}> | |||
| {offer?.pinned ? <UnpinIcon /> : <PinIcon />} | |||
| </PinIconContainer> | |||
| )} | |||
| <EditIconContainer onClick={showEditOfferModalHandler}> | |||
| <EditIcon /> | |||
| </EditIconContainer> | |||
| @@ -28,8 +28,8 @@ const OfferDetails = (props) => { | |||
| const [imagesCarouselModal, setImagesCarouselModal] = useState(false); | |||
| useEffect(() => { | |||
| if (props?.offer?.offer?.images) { | |||
| props.offer.offer.images.map((file) => { | |||
| if (props?.offer?.images) { | |||
| props.offer.images.map((file) => { | |||
| if (file) { | |||
| if (typeof file !== "string") { | |||
| var reader = new FileReader(); | |||
| @@ -49,11 +49,15 @@ const OfferDetails = (props) => { | |||
| } | |||
| }); | |||
| } | |||
| }, [props?.offer?.offer?.images]); | |||
| const date = formatDateLocale(new Date(offer?.offer?._created)); | |||
| return () => { | |||
| setImages([]); | |||
| }; | |||
| }, [props?.offer?.images]); | |||
| const date = formatDateLocale(new Date(offer?._created)); | |||
| const onModalClose = () => { | |||
| setImagesCarouselModal(false); | |||
| }; | |||
| console.log(props); | |||
| return ( | |||
| <> | |||
| <Details | |||
| @@ -64,13 +68,9 @@ const OfferDetails = (props) => { | |||
| > | |||
| {!isMobile && props.singleOffer && ( | |||
| <ScrollerVertical> | |||
| {props?.offer?.offer?.images.map((item, index) => ( | |||
| {images.map((item, index) => ( | |||
| <OfferImage | |||
| src={ | |||
| props.createOffer | |||
| ? images[index] | |||
| : getImageUrl(item, variants.offerCard, isMobile) | |||
| } | |||
| src={images[index]} | |||
| alt={t("offer.imageAlt")} | |||
| key={item} | |||
| previewCard={props.previewCard} | |||
| @@ -85,20 +85,14 @@ const OfferDetails = (props) => { | |||
| singleOffer={props.singleOffer} | |||
| previewCard={props.previewCard} | |||
| > | |||
| <OfferTitle singleOffer={props.singleOffer}> | |||
| {offer?.offer?.name} | |||
| </OfferTitle> | |||
| <OfferTitle singleOffer={props.singleOffer}>{offer?.name}</OfferTitle> | |||
| {isMobile && ( | |||
| <ScrollerHorizontal> | |||
| {props?.offer?.offer?.images.map((item, index) => { | |||
| {images.map((item, index) => { | |||
| if (!item) return; | |||
| return ( | |||
| <OfferImage | |||
| src={ | |||
| props.createOffer | |||
| ? images[index] | |||
| : getImageUrl(item, variants.offerCard, isMobile) | |||
| } | |||
| src={images[index]} | |||
| key={item} | |||
| previewCard={props.previewCard} | |||
| onClick={() => | |||
| @@ -117,7 +111,7 @@ const OfferDetails = (props) => { | |||
| {t("itemDetailsCard.description")} | |||
| </OfferDescriptionTitle> | |||
| <OfferDescriptionText showBarterButton={props.showExchangeButton}> | |||
| {offer?.offer?.description} | |||
| {offer?.description} | |||
| </OfferDescriptionText> | |||
| <DesciprtionPostDate previewCard={props.previewCard}> | |||
| {date} | |||
| @@ -126,7 +120,11 @@ const OfferDetails = (props) => { | |||
| </OfferInfoContainer> | |||
| </Details> | |||
| {imagesCarouselModal && ( | |||
| <ImagesCarousel offer={props.offer} onModalClose={onModalClose} /> | |||
| <ImagesCarousel | |||
| offer={props.offer} | |||
| images={images} | |||
| onModalClose={onModalClose} | |||
| /> | |||
| )} | |||
| </> | |||
| ); | |||
| @@ -17,6 +17,9 @@ export const LittleOfferCardContainer = styled(Box)` | |||
| display: flex; | |||
| flex-direction: row; | |||
| position: relative; | |||
| @media (max-width: 600px) { | |||
| width: 211px; | |||
| } | |||
| ` | |||
| export const OfferImage = styled.img` | |||
| width: 54px; | |||
| @@ -28,6 +31,7 @@ export const OfferImage = styled.img` | |||
| ` | |||
| export const OfferDetails = styled(Box)` | |||
| display: flex; | |||
| text-align: left; | |||
| flex-direction: column; | |||
| margin-top: 25px; | |||
| margin-left: 9px; | |||
| @@ -50,6 +54,9 @@ export const OfferCategoryIcon = styled(Category)` | |||
| position: relative; | |||
| top: 1.5px; | |||
| right: 2px; | |||
| & path { | |||
| stroke-width: 1; | |||
| } | |||
| ` | |||
| export const OfferSwapsIconContainer = styled(Icon)` | |||
| width: 40px; | |||
| @@ -63,10 +70,22 @@ export const OfferSwapsIconContainer = styled(Icon)` | |||
| width: 40px; | |||
| height: 40px; | |||
| } | |||
| @media (max-width: 600px) { | |||
| width: 32px; | |||
| height: 32px; | |||
| top: -15px; | |||
| right: -15px; | |||
| } | |||
| ` | |||
| export const OfferSwapsIcon = styled(Swaps)` | |||
| width: 18px; | |||
| height: 18px; | |||
| position: relative; | |||
| top: 10px; | |||
| @media (max-width: 600px) { | |||
| width: 14px; | |||
| height: 14px; | |||
| top: 2px; | |||
| left: -4px; | |||
| } | |||
| ` | |||
| @@ -14,7 +14,9 @@ export const ProfileImage = styled.img` | |||
| overflow: hidden; | |||
| border-radius: 100%; | |||
| @media (max-width: 600px) { | |||
| display: none; | |||
| width: 18px; | |||
| height: 18px; | |||
| min-width: 18px; | |||
| } | |||
| `; | |||
| export const MessageContent = styled(Box)` | |||
| @@ -29,6 +31,8 @@ export const MessageContent = styled(Box)` | |||
| min-width: 110px; | |||
| @media (max-width: 600px) { | |||
| width: 100%; | |||
| margin: 0; | |||
| ${props => props.ismymessage ? "margin-right: 9px;" : "margin-left: 9px;"} | |||
| } | |||
| `; | |||
| export const MessageText = styled(Typography)` | |||
| @@ -16,40 +16,46 @@ import history from "../../../store/utils/history"; | |||
| import { replaceInRoute } from "../../../util/helpers/routeHelpers"; | |||
| import { DIRECT_CHAT_PAGE } from "../../../constants/pages"; | |||
| import BlockedProfile from "../ProfileCard/BlockedProfile/BlockedProfile"; | |||
| import { useMemo } from "react"; | |||
| import { useSelector } from "react-redux"; | |||
| import { selectUserId } from "../../../store/selectors/loginSelectors"; | |||
| const MiniChatCard = (props) => { | |||
| const { t } = useTranslation(); | |||
| const { isMobile } = useIsMobile(); | |||
| const userId = useSelector(selectUserId); | |||
| const changeChat = () => { | |||
| history.push( | |||
| replaceInRoute(DIRECT_CHAT_PAGE, { | |||
| chatId: props?.chat?.chat?._id, | |||
| chatId: props?.chat?._id, | |||
| }) | |||
| ); | |||
| }; | |||
| const interlocutorData = useMemo(() => { | |||
| if (props?.chat?.participants) { | |||
| let interlocutor = props?.chat?.participants[0]._id === userId ? 1 : 0; | |||
| return props?.chat?.participants[interlocutor]; | |||
| } | |||
| return {}; | |||
| }, [props?.chat]); | |||
| return ( | |||
| <MiniChatCardContainer selected={props.selected} onClick={changeChat}> | |||
| <ProfileImage | |||
| src={getImageUrl( | |||
| props?.chat?.interlocutorData?.image, | |||
| variants.chatCard, | |||
| isMobile | |||
| )} | |||
| src={getImageUrl(interlocutorData?.image, variants.chatCard, isMobile)} | |||
| /> | |||
| <ProfileDetails isBlocked={props.chat.interlocutorData?._blocked}> | |||
| <ProfileDetails isBlocked={interlocutorData?._blocked}> | |||
| <ProfileNameContainer> | |||
| <ProfileName selected={props.selected}> | |||
| {props?.chat?.interlocutorData?.name} | |||
| {interlocutorData?.company?.name} | |||
| </ProfileName> | |||
| {(props.chat.interlocutorData?._blocked || | |||
| props.chat.interlocutorData?._deleted) && ( | |||
| {(interlocutorData?._blocked || interlocutorData?._deleted) && ( | |||
| <BlockedProfile | |||
| redText | |||
| chatCard | |||
| shortText | |||
| aboveTitle | |||
| hideIcon | |||
| deleted={props.chat.interlocutorData?._deleted} | |||
| deleted={interlocutorData?._deleted} | |||
| /> | |||
| )} | |||
| </ProfileNameContainer> | |||
| @@ -57,7 +63,7 @@ const MiniChatCard = (props) => { | |||
| {t("messages.cardProduct")} | |||
| </ProfileProduct> | |||
| <ProfileProductName selected={props.selected}> | |||
| {props?.chat?.offerData?.name} | |||
| {props?.chat?.offer?.name} | |||
| </ProfileProductName> | |||
| </ProfileDetails> | |||
| </MiniChatCardContainer> | |||
| @@ -26,12 +26,12 @@ import { useHistory } from "react-router-dom"; | |||
| import useIsMobile from "../../../../hooks/useIsMobile"; | |||
| import { getImageUrl, variants } from "../../../../util/helpers/imageUrlGetter"; | |||
| import { selectQueryString } from "../../../../store/selectors/queryStringSelectors"; | |||
| import OfferDescription from "./OfferDescription/OfferDescription"; | |||
| import CancelButton from "./CancelButton/CancelButton"; | |||
| import SaveButton from "./SaveButton/SaveButton"; | |||
| import { closeModal } from "../../../../store/actions/modal/modalActions"; | |||
| import { | |||
| dynamicRouteMatches, | |||
| replaceInRoute, | |||
| routeMatches, | |||
| } from "../../../../util/helpers/routeHelpers"; | |||
| import { | |||
| @@ -42,13 +42,14 @@ import { | |||
| ITEM_DETAILS_PAGE, | |||
| PROFILE_PAGE, | |||
| } from "../../../../constants/pages"; | |||
| import { OfferDescriptionContainer } from "./DeleteOfferLabeledCard/DeleteOfferLabeledCard.styled"; | |||
| const DeleteOffer = (props) => { | |||
| const dispatch = useDispatch(); | |||
| const { t } = useTranslation(); | |||
| const queryString = useSelector(selectQueryString); | |||
| const history = useHistory(); | |||
| const userId = props.offer.userId; | |||
| const userId = props.offer.user._id; | |||
| const { isMobile } = useIsMobile(); | |||
| const offerId = props.offer._id; | |||
| const closeDeleteModalHandler = () => { | |||
| @@ -60,15 +61,22 @@ const DeleteOffer = (props) => { | |||
| dynamicRouteMatches(PROFILE_PAGE) || | |||
| dynamicRouteMatches(ADMIN_SINGLE_USER_PAGE) | |||
| ) | |||
| dispatch(fetchProfileOffers(userId)); | |||
| dispatch(fetchProfileOffers({ idProfile: userId, isAdmin: true })); | |||
| if (routeMatches(HOME_PAGE) || routeMatches(BASE_PAGE)) | |||
| dispatch(fetchOffers({ queryString })); | |||
| if ( | |||
| dynamicRouteMatches(ITEM_DETAILS_PAGE) || | |||
| dynamicRouteMatches(ADMIN_ITEM_DETAILS_PAGE) | |||
| ) { | |||
| if (dynamicRouteMatches(ITEM_DETAILS_PAGE)) { | |||
| history.push( | |||
| replaceInRoute(PROFILE_PAGE, { | |||
| profileId: userId, | |||
| }) | |||
| ); | |||
| } | |||
| if (dynamicRouteMatches(ADMIN_ITEM_DETAILS_PAGE)) { | |||
| if (props.pin) dispatch(fetchOneOffer(props.offer?._id)); | |||
| else history.goBack(); | |||
| else | |||
| history.push( | |||
| replaceInRoute(ADMIN_SINGLE_USER_PAGE, { profileId: userId }) | |||
| ); | |||
| } | |||
| }; | |||
| @@ -110,7 +118,7 @@ const DeleteOffer = (props) => { | |||
| )} | |||
| /> | |||
| </OfferImageContainer> | |||
| <OfferDescription | |||
| <OfferDescriptionContainer | |||
| offerName={props.offer.name} | |||
| categoryName={props.offer.category.name} | |||
| /> | |||
| @@ -53,7 +53,7 @@ export const OfferImageContainer = styled(Box)` | |||
| border-radius: 2px; | |||
| @media screen and (max-width: 600px) { | |||
| margin-right: 13px; | |||
| /* margin-right: 13px; */ | |||
| } | |||
| `; | |||
| @@ -1,6 +1,7 @@ | |||
| import React from "react"; | |||
| import PropTypes from "prop-types"; | |||
| import { | |||
| OfferDescriptionContainer, | |||
| OfferImage, | |||
| OfferImageContainer, | |||
| OfferInfo, | |||
| @@ -11,7 +12,6 @@ import { | |||
| getImageUrl, | |||
| variants, | |||
| } from "../../../../../util/helpers/imageUrlGetter"; | |||
| import OfferDescription from "../OfferDescription/OfferDescription"; | |||
| import useIsMobile from "../../../../../hooks/useIsMobile"; | |||
| const DeleteOfferLabeledCard = (props) => { | |||
| @@ -27,7 +27,7 @@ const DeleteOfferLabeledCard = (props) => { | |||
| )} | |||
| /> | |||
| </OfferImageContainer> | |||
| <OfferDescription | |||
| <OfferDescriptionContainer | |||
| offerName={props.offer.name} | |||
| categoryName={props.offer.category.name} | |||
| /> | |||
| @@ -3,6 +3,7 @@ import styled from "styled-components"; | |||
| import selectedTheme from "../../../../../themes"; | |||
| import { ReactComponent as Remove } from "../../../../../assets/images/svg/trash-gold.svg"; | |||
| import { IconButton } from "../../../../Buttons/IconButton/IconButton"; | |||
| import OfferDescription from "../OfferDescription/OfferDescription"; | |||
| export const OfferInfo = styled(Box)` | |||
| width: 211px; | |||
| height: 90px; | |||
| @@ -23,7 +24,7 @@ export const OfferImageContainer = styled(Box)` | |||
| border-radius: 2px; | |||
| @media screen and (max-width: 600px) { | |||
| margin-right: 13px; | |||
| /* margin-right: 13px; */ | |||
| } | |||
| `; | |||
| @@ -56,3 +57,6 @@ export const RemoveIconContainer = styled(RemoveIconBorder)` | |||
| export const RemoveIcon = styled(Remove)` | |||
| cursor: default; | |||
| `; | |||
| export const OfferDescriptionContainer = styled(OfferDescription)` | |||
| margin-left: 0; | |||
| ` | |||
| @@ -3,6 +3,7 @@ import PropTypes from "prop-types"; | |||
| import { | |||
| CategoryIcon, | |||
| CategoryIconContainer, | |||
| OfferCategoryContainer, | |||
| OfferDescriptionCategory, | |||
| OfferDescriptionContainer, | |||
| OfferDescriptionTitle, | |||
| @@ -11,9 +12,9 @@ import selectedTheme from "../../../../../themes"; | |||
| const OfferDescription = (props) => { | |||
| return ( | |||
| <OfferDescriptionContainer> | |||
| <OfferDescriptionContainer className={props?.className}> | |||
| <OfferDescriptionTitle>{props.offerName}</OfferDescriptionTitle> | |||
| <OfferDescriptionCategory> | |||
| <OfferCategoryContainer> | |||
| <CategoryIconContainer | |||
| color={selectedTheme.colors.iconStrokeDisabledColor} | |||
| component="span" | |||
| @@ -21,8 +22,10 @@ const OfferDescription = (props) => { | |||
| > | |||
| <CategoryIcon /> | |||
| </CategoryIconContainer> | |||
| {props.categoryName} | |||
| </OfferDescriptionCategory> | |||
| <OfferDescriptionCategory> | |||
| {props.categoryName} | |||
| </OfferDescriptionCategory> | |||
| </OfferCategoryContainer> | |||
| </OfferDescriptionContainer> | |||
| ); | |||
| }; | |||
| @@ -30,6 +33,7 @@ const OfferDescription = (props) => { | |||
| OfferDescription.propTypes = { | |||
| offerName: PropTypes.string, | |||
| categoryName: PropTypes.string, | |||
| className: PropTypes.string, | |||
| }; | |||
| export default OfferDescription; | |||
| @@ -35,15 +35,21 @@ export const OfferDescriptionCategory = styled(Typography)` | |||
| font-family: ${selectedTheme.fonts.textFont}; | |||
| color: ${selectedTheme.colors.primaryDarkText}; | |||
| `; | |||
| export const OfferCategoryContainer = styled(Box)` | |||
| display: flex; | |||
| flex-direction: row; | |||
| white-space: nowrap; | |||
| ` | |||
| export const CategoryIconContainer = styled(Icon)` | |||
| margin-right: 4px; | |||
| position: relative; | |||
| top: 2px; | |||
| display: inline; | |||
| & svg { | |||
| width: 14px; | |||
| position: relative; | |||
| top: -6px; | |||
| top: -4px; | |||
| } | |||
| `; | |||
| export const CategoryIcon = styled(Category)``; | |||
| @@ -87,11 +87,14 @@ const OfferCard = (props) => { | |||
| }) | |||
| ); | |||
| } else { | |||
| history.push( | |||
| replaceInRoute(ITEM_DETAILS_PAGE, { | |||
| history.push({ | |||
| pathname: replaceInRoute(ITEM_DETAILS_PAGE, { | |||
| offerId: itemId, | |||
| }) | |||
| ); | |||
| }), | |||
| state: { | |||
| view: true, | |||
| }, | |||
| }); | |||
| } | |||
| } | |||
| }; | |||
| @@ -112,7 +115,7 @@ const OfferCard = (props) => { | |||
| editOffer: true, | |||
| offer: props.offer, | |||
| isAdmin: props.isAdmin, | |||
| customUserId: props?.offer?.userId, | |||
| customUserId: props?.offer?.user._id, | |||
| }) | |||
| ); | |||
| }; | |||
| @@ -54,7 +54,10 @@ const ProfileControl = (props) => { | |||
| ); | |||
| }; | |||
| const handleEditProfile = () => { | |||
| if (!props.profile?._blocked) { | |||
| console.log("edit") | |||
| console.log(props) | |||
| if (!props.profile?._blocked || props?.isAdmin) { | |||
| console.log("edit2") | |||
| dispatch( | |||
| toggleEditProfileModal({ | |||
| userId: props.profile._id, | |||
| @@ -67,9 +70,10 @@ const ProfileControl = (props) => { | |||
| ); | |||
| } | |||
| }; | |||
| console.log(props) | |||
| return ( | |||
| <ButtonsContainer> | |||
| {props.profile?._blocked && !props.isMobile && <BlockedProfile />} | |||
| {props.profile?._blocked && !props.isMobile && !props?.isAdmin && <BlockedProfile />} | |||
| {props.isAdmin && ( | |||
| <> | |||
| {props.profile?._blocked ? ( | |||
| @@ -26,15 +26,15 @@ const RequestExchangeCard = (props) => { | |||
| const requester = useSelector(selectRequester); | |||
| const exchange = useSelector(selectExchange); | |||
| const amIBuyer = useMemo( | |||
| () => exchange?.buyer?.userId === userId, | |||
| () => exchange?.buyer?.user?._id === userId, | |||
| [exchange, userId] | |||
| ); | |||
| const haveIAccepted = useMemo( | |||
| () => (amIBuyer ? exchange?.buyer?.accepted : exchange?.seller?.accepted), | |||
| [amIBuyer, exchange] | |||
| ); | |||
| const interlucatorUserId = useMemo( | |||
| () => (amIBuyer ? exchange?.seller?.userId : exchange?.buyer?.userId), | |||
| const interlocutorUserId = useMemo( | |||
| () => (amIBuyer ? exchange?.seller?.user?._id : exchange?.buyer?.user?._id), | |||
| [exchange, amIBuyer] | |||
| ); | |||
| const message = useMemo(() => { | |||
| @@ -52,18 +52,18 @@ const RequestExchangeCard = (props) => { | |||
| </MessageText> | |||
| ); | |||
| } | |||
| } else if (requester === requesterStatus.INTERLUCATOR) { | |||
| } else if (requester === requesterStatus.interlocutor) { | |||
| return ( | |||
| <RequestExchangeMessage | |||
| haveIAccepted={haveIAccepted} | |||
| chatId={props.chatId} | |||
| userId={userId} | |||
| interlucatorUserId={interlucatorUserId} | |||
| interlocutorUserId={interlocutorUserId} | |||
| /> | |||
| ); | |||
| } | |||
| return ""; | |||
| }, [requester, t, haveIAccepted, interlucatorUserId, userId, exchange]); | |||
| }, [requester, t, haveIAccepted, interlocutorUserId, userId, exchange]); | |||
| return ( | |||
| <RequestExchangeCardContainer ismymessage={props.isMyMessage}> | |||
| <InfoIcon /> | |||
| @@ -20,6 +20,8 @@ export const MessageContent = styled(Box)` | |||
| min-width: 110px; | |||
| @media (max-width: 600px) { | |||
| width: 100%; | |||
| margin: 0; | |||
| ${props => props.ismymessage ? "margin-right: 9px;" : "margin-left: 9px;"} | |||
| } | |||
| `; | |||
| export const MessageText = styled(Typography)` | |||
| @@ -9,34 +9,42 @@ import { | |||
| import { useTranslation } from "react-i18next"; | |||
| import { acceptExchangeSocket } from "../../../../socket/socket"; | |||
| import { useDispatch, useSelector } from "react-redux"; | |||
| import { selectExchange, selectRequester } from "../../../../store/selectors/exchangeSelector"; | |||
| import { acceptExchange, setRequester } from "../../../../store/actions/exchange/exchangeActions"; | |||
| import { | |||
| selectExchange, | |||
| selectRequester, | |||
| } from "../../../../store/selectors/exchangeSelector"; | |||
| import { | |||
| acceptExchange, | |||
| setRequester, | |||
| } from "../../../../store/actions/exchange/exchangeActions"; | |||
| import { addNewMessage } from "../../../../store/actions/chat/chatActions"; | |||
| import { convertLocalDateToUTCDate } from "../../../../util/helpers/dateHelpers"; | |||
| import requesterStatus from "../../../../constants/requesterStatus"; | |||
| import { selectJwtToken } from "../../../../store/selectors/loginSelectors"; | |||
| const RequestExchangeMessage = (props) => { | |||
| const { t } = useTranslation(); | |||
| const dispatch = useDispatch(); | |||
| const exchange = useSelector(selectExchange); | |||
| const requester = useSelector(selectRequester); | |||
| const token = useSelector(selectJwtToken) | |||
| const handleAcceptExchange = () => { | |||
| const handleAcceptExchangeSuccess = () => { | |||
| console.log("accept salje i prima 3 POZVANA RESPONSE FUNKCIJA"); | |||
| acceptExchangeSocket( | |||
| props.chatId, | |||
| props.userId, | |||
| props.interlucatorUserId, | |||
| props.interlocutorUserId, | |||
| token, | |||
| () => { | |||
| dispatch( | |||
| acceptExchange({ | |||
| exchangeId: exchange._id, | |||
| }) | |||
| ); | |||
| console.log("accept salje i prima 4 SOCKET FUNKCIJA"); | |||
| dispatch( | |||
| addNewMessage({ | |||
| _id: props.chatId, | |||
| message: { | |||
| userId: props.userId, | |||
| user: { | |||
| _id: props.userId, | |||
| }, | |||
| text: "", | |||
| isAcceptRequest: true, | |||
| _created: convertLocalDateToUTCDate(new Date()), | |||
| @@ -49,6 +57,15 @@ const RequestExchangeMessage = (props) => { | |||
| } | |||
| ); | |||
| }; | |||
| const handleAcceptExchange = () => { | |||
| console.log("accept salje i prima 1 POZVANA FUNKCIJA"); | |||
| dispatch( | |||
| acceptExchange({ | |||
| exchangeId: exchange._id, | |||
| handleApiResponseSuccess: handleAcceptExchangeSuccess, | |||
| }) | |||
| ); | |||
| }; | |||
| return ( | |||
| <RequestExchangeMessageContainer> | |||
| <RequestExchangeMessageText> | |||
| @@ -65,7 +82,9 @@ const RequestExchangeMessage = (props) => { | |||
| onClick={handleAcceptExchange} | |||
| disabled={props.haveIAccepted} | |||
| > | |||
| {props.haveIAccepted ? t("messages.acceptedRequest") : t("messages.acceptRequest")} | |||
| {props.haveIAccepted | |||
| ? t("messages.acceptedRequest") | |||
| : t("messages.acceptRequest")} | |||
| </RequestExchangeMessageButton> | |||
| </RequestExchangeMessageButtonsContainer> | |||
| </RequestExchangeMessageContainer> | |||
| @@ -76,7 +95,7 @@ RequestExchangeMessage.propTypes = { | |||
| children: PropTypes.node, | |||
| chatId: PropTypes.string, | |||
| userId: PropTypes.string, | |||
| interlucatorUserId: PropTypes.string, | |||
| interlocutorUserId: PropTypes.string, | |||
| haveIAccepted: PropTypes.any, | |||
| }; | |||
| @@ -13,6 +13,12 @@ const UserReviewsCard = (props) => { | |||
| ...props.review, | |||
| }; | |||
| } | |||
| let userWhoGaveReview = | |||
| props?.review?.exchange?.buyer?.user?._id === props?.review?.user?._id | |||
| ? "buyer" | |||
| : "seller"; | |||
| let userWhoRevievedReview = | |||
| userWhoGaveReview === "buyer" ? "seller" : "buyer"; | |||
| let isSuccessfulSwap = reviewEnum.YES.mainText.toUpperCase(); | |||
| if ( | |||
| props.review.succeeded === reviewEnum.NO.backendText || | |||
| @@ -32,24 +38,16 @@ const UserReviewsCard = (props) => { | |||
| isGoodCommunication = reviewEnum.NO.mainText.toUpperCase(); | |||
| return { | |||
| _id: props.review._id, | |||
| name: | |||
| props.review?.reviewAdditionalData?.userWhoGave?.company?.name || | |||
| props.review?.offer?.name, | |||
| image: | |||
| props.review?.reviewAdditionalData?.userWhoGave?.image || | |||
| props.review?.offer?.image, | |||
| userId: props.review.userId, | |||
| name: props?.review?.exchange[userWhoGaveReview]?.user?.company?.name, | |||
| image: props?.review?.exchange[userWhoGaveReview]?.user?.image, | |||
| userId: props.review.user?._id, | |||
| isGoodCommunication, | |||
| isSuccessfulSwap, | |||
| quote: props?.review?.message, | |||
| offerName: | |||
| props?.review?.reviewAdditionalData?.offerData?.name || | |||
| props?.review?.userWhoGaveReview?.name, | |||
| offerImage: | |||
| props?.review?.reviewAdditionalData?.offerData?.firstImage || | |||
| props?.review?.userWhoGaveReview?.image, | |||
| offerName: props?.review?.exchange?.offer?.name, | |||
| offerImage: props?.review?.exchange?.offer?.images[0], | |||
| userWhoReceived: | |||
| props?.review?.reviewAdditionalData?.userWhoReceived?.company?.name, | |||
| props?.review?.exchange[userWhoRevievedReview]?.user?.company?.name, | |||
| _deleted: props?.review?._deleted, | |||
| }; | |||
| }, [props.review]); | |||
| @@ -67,6 +65,7 @@ const UserReviewsCard = (props) => { | |||
| handleRemove={handleRemove} | |||
| hasGivenReview={props.hasGivenReview} | |||
| rightReviews={props.rightReviews} | |||
| isProfileReviews={props?.isProfileReviews} | |||
| isAdmin={props.isAdmin} | |||
| /> | |||
| ); | |||
| @@ -84,6 +83,7 @@ UserReviewsCard.propTypes = { | |||
| hasGivenReview: PropTypes.bool, | |||
| rightReviews: PropTypes.bool, | |||
| isAdmin: PropTypes.bool, | |||
| userId: PropTypes.string, | |||
| }; | |||
| UserReviewsCard.defaultProps = { | |||
| isProfileReviews: false, | |||
| @@ -3,11 +3,13 @@ import PropTypes from "prop-types"; | |||
| import { RemoveButtonContainer, RemoveIcon } from "./RemoveButton.styled"; | |||
| const RemoveButton = (props) => { | |||
| console.log(props) | |||
| return ( | |||
| <RemoveButtonContainer | |||
| isRemoved={props.isRemoved} | |||
| onClick={props.onClick} | |||
| hasGivenReview={props.hasGivenReview} | |||
| isProfileReviews={props?.isProfileReviews} | |||
| > | |||
| <RemoveIcon isRemoved={props.isRemoved} /> | |||
| </RemoveButtonContainer> | |||
| @@ -19,6 +21,7 @@ RemoveButton.propTypes = { | |||
| onClick: PropTypes.func, | |||
| hasGivenReview: PropTypes.bool, | |||
| isRemoved: PropTypes.bool, | |||
| isProfileReviews: PropTypes.any | |||
| }; | |||
| export default RemoveButton; | |||
| @@ -6,18 +6,24 @@ import { IconButton } from "../../../../Buttons/IconButton/IconButton"; | |||
| export const RemoveButtonContainer = styled(IconButton)` | |||
| position: absolute; | |||
| top: ${(props) => (props.hasGivenReview ? "79px" : "16px")}; | |||
| top: ${(props) => | |||
| props.hasGivenReview && props.isProfileReviews ? "79px" : "16px"}; | |||
| right: 16px; | |||
| background-color: ${props => props.isRemoved ? "transparent" : selectedTheme.colors.primaryIconBackgroundColor}; | |||
| background-color: ${(props) => | |||
| props.isRemoved | |||
| ? "transparent" | |||
| : selectedTheme.colors.primaryIconBackgroundColor}; | |||
| border-radius: 100%; | |||
| width: 32px; | |||
| height: 32px; | |||
| ${props => props.isRemoved && css` | |||
| & button:hover { | |||
| background-color: transparent; | |||
| cursor: auto; | |||
| } | |||
| `} | |||
| ${(props) => | |||
| props.isRemoved && | |||
| css` | |||
| & button:hover { | |||
| background-color: transparent; | |||
| cursor: auto; | |||
| } | |||
| `} | |||
| & button { | |||
| width: 32px; | |||
| height: 32px; | |||
| @@ -25,6 +31,6 @@ export const RemoveButtonContainer = styled(IconButton)` | |||
| `; | |||
| export const RemoveIcon = styled(Remove)` | |||
| & path { | |||
| stroke: ${props => props.isRemoved && selectedTheme.colors.blockedColor}; | |||
| stroke: ${(props) => props.isRemoved && selectedTheme.colors.blockedColor}; | |||
| } | |||
| `; | |||
| @@ -19,7 +19,9 @@ export const ReviewQuoteContainer = styled(Box)` | |||
| export const ThumbContainer = styled(Grid)` | |||
| max-width: 20px; | |||
| `; | |||
| export const ReviewQuoteTextContainer = styled(Grid)``; | |||
| export const ReviewQuoteTextContainer = styled(Box)` | |||
| flex: 1; | |||
| `; | |||
| export const ReviewQuoteText = styled(Typography)` | |||
| font-family: ${selectedTheme.fonts.textFont}; | |||
| font-size: 16px; | |||
| @@ -41,6 +41,7 @@ const UserReviewsSingleCard = (props) => { | |||
| <RemoveButton | |||
| review={props.review} | |||
| onClick={handleRemove} | |||
| isProfileReviews={props?.isProfileReviews} | |||
| hasGivenReview={props.hasGivenReview} | |||
| isRemoved={props.review?._deleted} | |||
| /> | |||
| @@ -63,6 +64,7 @@ UserReviewsSingleCard.propTypes = { | |||
| isAdmin: PropTypes.bool, | |||
| className: PropTypes.string, | |||
| lastReview: PropTypes.bool, | |||
| isProfileReviews: PropTypes.any, | |||
| }; | |||
| UserReviewsSingleCard.defaultProps = { | |||
| lastReview: false, | |||
| @@ -24,7 +24,7 @@ import { | |||
| fetchChats, | |||
| } from "../../store/actions/chat/chatActions"; | |||
| import useSorting from "../../hooks/useOffers/useSorting"; | |||
| import { addMesageListener, removeMessageListener } from "../../socket/socket"; | |||
| import { addMessageListener, removeMessageListener } from "../../socket/socket"; | |||
| import { selectIsLoadingByActionType } from "../../store/selectors/loadingSelectors"; | |||
| import { CHAT_SCOPE } from "../../store/actions/chat/chatActionConstants"; | |||
| import SkeletonChatColumn from "./SkeletonChatColumn/SkeletonChatColumn"; | |||
| @@ -60,7 +60,8 @@ export const ChatColumn = (props) => { | |||
| history.goBack(); | |||
| return; | |||
| } | |||
| addMesageListener(({ succeed, data }) => { | |||
| addMessageListener(({ succeed, data }) => { | |||
| if (succeed) { | |||
| dispatch( | |||
| addNewMessage({ | |||
| @@ -10,9 +10,8 @@ import { | |||
| import FirstStepCreateReview from "./FirstStep/FirstStepCreateReview"; | |||
| import SecondStepCreateReview from "./SecondStep/SecondStepCreateReview"; | |||
| import ThirdStepCreateReview from "./ThirdStep/ThirdStepCreateReview"; | |||
| import { useDispatch, useSelector } from "react-redux"; | |||
| import { useDispatch } from "react-redux"; | |||
| import { giveReview } from "../../store/actions/review/reviewActions"; | |||
| import { selectUserId } from "../../store/selectors/loginSelectors"; | |||
| import { reviewEnum } from "../../enums/reviewEnum"; | |||
| import { fetchExchange } from "../../store/actions/exchange/exchangeActions"; | |||
| import { closeModal } from "../../store/actions/modal/modalActions"; | |||
| @@ -23,13 +22,9 @@ const CreateReview = (props) => { | |||
| const [informations, setInformations] = useState({}); | |||
| const [currentStep, setCurrentStep] = useState(1); | |||
| const dispatch = useDispatch(); | |||
| const userId = useSelector(selectUserId); | |||
| const closeModalHandler = () => { | |||
| dispatch(closeModal()); | |||
| }; | |||
| setTimeout(() => { | |||
| dispatch(closeModal()); | |||
| }, 3000); | |||
| const handleApiResponseSuccess = () => { | |||
| dispatch(fetchExchange(props.exchange._id)); | |||
| }; | |||
| @@ -45,8 +40,9 @@ const CreateReview = (props) => { | |||
| dispatch( | |||
| giveReview({ | |||
| review: { | |||
| exchangeId: props.exchange._id, | |||
| userId: userId, | |||
| exchange: { | |||
| _id: props.exchange._id, | |||
| }, | |||
| succeeded, | |||
| communication, | |||
| message: informations.comment, | |||
| @@ -38,17 +38,17 @@ export const CreateReviewContainer = styled(Box)` | |||
| max-width: 100vw; | |||
| left: 0; | |||
| top: 0; | |||
| padding: 0 30px; | |||
| padding: 0 18px; | |||
| } | |||
| `; | |||
| export const NextButton = styled(PrimaryButton)` | |||
| @media (max-width: 600px) { | |||
| height: 42px; | |||
| position: absolute; | |||
| bottom: 15px; | |||
| width: calc(100% - 48px); | |||
| bottom: 9px; | |||
| width: calc(100vw - 36px); | |||
| left: 0; | |||
| margin-left: 24px; | |||
| margin-left: 9px; | |||
| } | |||
| `; | |||
| export const CloseButton = styled(IconButton)` | |||
| @@ -56,8 +56,8 @@ export const CloseButton = styled(IconButton)` | |||
| top: 36px; | |||
| right: 36px; | |||
| @media (max-width: 600px) { | |||
| top: 24px; | |||
| right: 24px; | |||
| top: 32px; | |||
| right: 22px; | |||
| } | |||
| `; | |||
| export const CloseIcon = styled(Close)` | |||
| @@ -76,7 +76,7 @@ export const BackIcon = styled(Box)` | |||
| left: 36px; | |||
| @media (max-width: 600px) { | |||
| top: 24px; | |||
| top: 40px; | |||
| left: 24px; | |||
| width: 18px; | |||
| height: 18px; | |||
| @@ -101,3 +101,11 @@ export const CreateReviewTitle = styled(Typography)` | |||
| margin-bottom: 24px; | |||
| } | |||
| `; | |||
| export const CreateReviewFlexContainer = styled(Box)` | |||
| @media (max-width: 600px) { | |||
| width: 100vw; | |||
| height: 100vh; | |||
| display: flex; | |||
| flex-direction: column; | |||
| } | |||
| ` | |||
| @@ -22,6 +22,7 @@ import NextButton from "./NextButton/NextButton"; | |||
| const FirstStepCreateReview = (props) => { | |||
| const offer = props.offer; | |||
| const interlocutor = props.interlocutor; | |||
| console.log(props); | |||
| const { t } = useTranslation(); | |||
| const handleSubmit = (values) => { | |||
| props.goToNextStep(values); | |||
| @@ -54,7 +55,7 @@ const FirstStepCreateReview = (props) => { | |||
| )} | |||
| /> | |||
| </ProfileImageContainer> | |||
| <ProfileName>{interlocutor.name}</ProfileName> | |||
| <ProfileName>{interlocutor.company.name}</ProfileName> | |||
| <LittleOfferCard | |||
| image={offer?.images[0]} | |||
| name={offer?.name} | |||
| @@ -9,7 +9,9 @@ export const FirstStepCreateReviewContainer = styled(Box)` | |||
| text-align: center; | |||
| padding: 36px; | |||
| @media (max-width: 600px) { | |||
| padding: 18px; | |||
| padding: 0; | |||
| padding-top: 36px; | |||
| flex: 1; | |||
| } | |||
| `; | |||
| export const CreateReviewTitle = styled(Typography)` | |||
| @@ -71,9 +73,9 @@ export const SelectField = styled(Select)` | |||
| text-align: left; | |||
| ${props => props.exchange && `background-color: ${selectedTheme.colors.backgroundSponsoredColor};`} | |||
| @media (max-width: 600px) { | |||
| height: 33px; | |||
| height: 40px; | |||
| font-size: 14px; | |||
| margin-bottom: 12px; | |||
| margin-bottom: 18px; | |||
| } | |||
| `; | |||
| export const SelectOption = styled(Option)` | |||
| @@ -27,20 +27,20 @@ const SecondStepCreateReview = (props) => { | |||
| : t("reviews.modalTitle")} | |||
| </CreateReviewTitle> | |||
| <ReviewCard | |||
| givingReview | |||
| profileReviews={[ | |||
| { | |||
| name: mineProfile?.company?.name, | |||
| image: mineProfile?.image, | |||
| offerName: props?.offer?.name, | |||
| offerImage: props?.offer?.images[0], | |||
| isGoodCommunication: props.review?.correctCommunication, | |||
| isSuccessfulSwap: props.review?.exchangeSucceed, | |||
| quote: props.review.comment, | |||
| }, | |||
| ]} | |||
| givingReview={{ | |||
| name: mineProfile?.company?.name, | |||
| image: mineProfile?.image, | |||
| offerName: props?.offer?.name, | |||
| offerImage: props?.offer?.images[0], | |||
| isGoodCommunication: props.review?.correctCommunication, | |||
| isSuccessfulSwap: props.review?.exchangeSucceed, | |||
| quote: props.review.comment, | |||
| }} | |||
| /> | |||
| <NextButton | |||
| removingReview={props.removingReview} | |||
| onClick={goToNextStep} | |||
| /> | |||
| <NextButton removingReview={props.removingReview} onClick={goToNextStep} /> | |||
| </SecondStepCreateReviewContainer> | |||
| ); | |||
| }; | |||
| @@ -6,7 +6,8 @@ import UserReviews from "../../UserReviews/UserReviews"; | |||
| export const SecondStepCreateReviewContainer = styled(Box)` | |||
| padding: 36px; | |||
| @media (max-width: 600px) { | |||
| padding: 18px; | |||
| padding: 0; | |||
| padding-top: 36px; | |||
| } | |||
| `; | |||
| export const ReviewCard = styled(UserReviews)` | |||
| @@ -21,4 +22,15 @@ export const ReviewCard = styled(UserReviews)` | |||
| margin: 0; | |||
| } | |||
| } | |||
| & * { | |||
| overflow:hidden; | |||
| } | |||
| @media (max-width: 600px) { | |||
| position: relative; | |||
| top: -24px; | |||
| & > div { | |||
| position: static; | |||
| margin-top: 0px; | |||
| } | |||
| } | |||
| `; | |||
| @@ -7,9 +7,15 @@ import { | |||
| ThirdStepCreateReviewContainer, | |||
| } from "./ThirdStepCreateReview.styled"; | |||
| import { useTranslation } from "react-i18next"; | |||
| import { useDispatch } from "react-redux"; | |||
| import { closeModal } from "../../../store/actions/modal/modalActions"; | |||
| const ThirdStepCreateReview = () => { | |||
| const { t } = useTranslation(); | |||
| const dispatch = useDispatch(); | |||
| setTimeout(() => { | |||
| dispatch(closeModal()); | |||
| }, 3000); | |||
| return ( | |||
| <ThirdStepCreateReviewContainer> | |||
| <LogoImage /> | |||
| @@ -21,10 +21,13 @@ import { fetchOneOffer } from "../../store/actions/offers/offersActions"; | |||
| import SkeletonDirectChat from "./SkeletonDirectChat/SkeletonDirectChat"; | |||
| import { selectIsLoadingByActionType } from "../../store/selectors/loadingSelectors"; | |||
| import { CHAT_SCOPE } from "../../store/actions/chat/chatActionConstants"; | |||
| import { selectUserId } from "../../store/selectors/loginSelectors"; | |||
| import { | |||
| selectJwtToken, | |||
| selectUserId, | |||
| } from "../../store/selectors/loginSelectors"; | |||
| import { | |||
| acceptExchangeSocket, | |||
| addMesageListener, | |||
| addMessageListener, | |||
| removeMessageListener, | |||
| } from "../../socket/socket"; | |||
| import { makeErrorToastMessage } from "../../store/utils/makeToastMessage"; | |||
| @@ -35,11 +38,13 @@ import { | |||
| } from "../../store/selectors/exchangeSelector"; | |||
| import { | |||
| acceptExchange, | |||
| fetchExchange, | |||
| setRequester, | |||
| } from "../../store/actions/exchange/exchangeActions"; | |||
| import { convertLocalDateToUTCDate } from "../../util/helpers/dateHelpers"; | |||
| import requesterStatus from "../../constants/requesterStatus"; | |||
| import exchangeStatus from "../../constants/exchangeStatus"; | |||
| import { NEW_CHAT } from "../../constants/chatConstants"; | |||
| const DirectChat = () => { | |||
| const chat = useSelector(selectSelectedChat); | |||
| @@ -49,6 +54,7 @@ const DirectChat = () => { | |||
| const location = useLocation(); | |||
| const dispatch = useDispatch(); | |||
| const { t } = useTranslation(); | |||
| const token = useSelector(selectJwtToken); | |||
| const exchange = useSelector(selectExchange); | |||
| const requester = useSelector(selectRequester); | |||
| @@ -59,9 +65,9 @@ const DirectChat = () => { | |||
| const offerObject = useMemo(() => { | |||
| if (location?.state?.offerId) { | |||
| return offer?.offer; | |||
| return offer; | |||
| } | |||
| return chat?.offer?.offer; | |||
| return chat?.offer; | |||
| }, [chat, location.state, offer]); | |||
| const chatObject = useMemo(() => { | |||
| @@ -72,7 +78,7 @@ const DirectChat = () => { | |||
| }, [chat, location.state]); | |||
| const amIBuyer = useMemo( | |||
| () => exchange.buyer?.userId === userId, | |||
| () => exchange.buyer?.user?._id === userId, | |||
| [exchange, userId] | |||
| ); | |||
| @@ -81,14 +87,14 @@ const DirectChat = () => { | |||
| let haveIAccepted = amIBuyer | |||
| ? exchange.buyer?.accepted | |||
| : exchange.seller?.accepted; | |||
| let haveInterlucatorAccepted = amIBuyer | |||
| let haveinterlocutorAccepted = amIBuyer | |||
| ? exchange.seller?.accepted | |||
| : exchange.buyer?.accepted; | |||
| let haveIReviewed = amIBuyer | |||
| ? exchange.buyer.givenReview | |||
| : exchange.seller.givenReview; | |||
| if (haveIAccepted) { | |||
| if (haveInterlucatorAccepted) { | |||
| if (haveinterlocutorAccepted) { | |||
| if (haveIReviewed) { | |||
| return exchangeStatus.REVIEWED; | |||
| } else { | |||
| @@ -98,7 +104,7 @@ const DirectChat = () => { | |||
| return exchangeStatus.I_OFFERED; | |||
| } | |||
| } else { | |||
| if (haveInterlucatorAccepted) { | |||
| if (haveinterlocutorAccepted) { | |||
| return exchangeStatus.I_AM_OFFERED; | |||
| } else { | |||
| return exchangeStatus.INITIAL; | |||
| @@ -110,21 +116,13 @@ const DirectChat = () => { | |||
| const interlocutorObject = useMemo(() => { | |||
| if (location?.state?.offerId) { | |||
| return { | |||
| image: offer?.companyData?.image, | |||
| name: offer?.companyData?.company?.name, | |||
| location: offer?.companyData?.company?.contacts?.location, | |||
| userId: offer?.offer?.userId, | |||
| telephone: offer?.companyData?.company?.contacts?.telephone, | |||
| }; | |||
| return offer?.user; | |||
| } | |||
| if (chat?.participants) { | |||
| let interlocutor = userId === chat?.participants[0]._id ? 1 : 0; | |||
| return chat?.participants[interlocutor]; | |||
| } | |||
| return { | |||
| ...chat?.interlocutor, | |||
| userId: | |||
| chat?.chat?.participants[0] === userId | |||
| ? chat?.chat?.participants[1] | |||
| : chat?.chat?.participants[0], | |||
| }; | |||
| return {}; | |||
| }, [chat, location.state, offer]); | |||
| // Fetch chat after it is created | |||
| @@ -137,11 +135,11 @@ const DirectChat = () => { | |||
| // Listener to socket.IO chat | |||
| useEffect(() => { | |||
| addMesageListener(({ succeed, data }) => { | |||
| addMessageListener(({ succeed, data }) => { | |||
| if (succeed) { | |||
| if ( | |||
| [...allChats].find((item) => { | |||
| return item.chat._id === data.chatId; | |||
| return item._id === data.chatId; | |||
| }) | |||
| ) { | |||
| dispatch( | |||
| @@ -150,11 +148,11 @@ const DirectChat = () => { | |||
| message: data.message, | |||
| }) | |||
| ); | |||
| if ( | |||
| data.message?.isAcceptRequest && | |||
| requester === requesterStatus.NOONE | |||
| ) { | |||
| dispatch(setRequester(requesterStatus.INTERLUCATOR)); | |||
| if (data.message?.isAcceptRequest) { | |||
| dispatch(fetchExchange(exchange?._id)); | |||
| if (requester === requesterStatus.NOONE) { | |||
| dispatch(setRequester(requesterStatus.interlocutor)); | |||
| } | |||
| } | |||
| } else { | |||
| dispatch(fetchChats()); | |||
| @@ -166,33 +164,31 @@ const DirectChat = () => { | |||
| } | |||
| }); | |||
| return () => removeMessageListener(); | |||
| }, [allChats, routeMatch]); | |||
| }, [allChats, routeMatch, requester]); | |||
| const refreshChat = () => { | |||
| if (routeMatch.params?.chatId === "newMessage") { | |||
| if (routeMatch.params?.chatId === NEW_CHAT) { | |||
| dispatch(fetchOneOffer(location.state.offerId)); | |||
| dispatch(setOneChat({})); | |||
| } else { | |||
| dispatch(fetchOneChat(routeMatch.params?.chatId)); | |||
| } | |||
| }; | |||
| const handleAcceptExchange = () => { | |||
| const handleAcceptExchangeSuccess = () => { | |||
| let interlocutor = userId === chat?.participants[0]._id ? 1 : 0; | |||
| acceptExchangeSocket( | |||
| chat?.chat?._id, | |||
| chat?._id, | |||
| userId, | |||
| chat?.interlocutor?._id, | |||
| chat?.participants[interlocutor]._id, | |||
| token, | |||
| () => { | |||
| dispatch( | |||
| acceptExchange({ | |||
| exchangeId: exchange._id, | |||
| }) | |||
| ); | |||
| dispatch( | |||
| addNewMessage({ | |||
| _id: chat?.chat?._id, | |||
| _id: chat?._id, | |||
| message: { | |||
| userId, | |||
| user: { | |||
| _id: userId, | |||
| }, | |||
| isAcceptRequest: true, | |||
| text: "", | |||
| _created: convertLocalDateToUTCDate(new Date()), | |||
| @@ -205,6 +201,15 @@ const DirectChat = () => { | |||
| } | |||
| ); | |||
| }; | |||
| const handleAcceptExchange = () => { | |||
| console.log("accept salje i prima 1 POZVANA FUNKCIJA"); | |||
| dispatch( | |||
| acceptExchange({ | |||
| exchangeId: exchange._id, | |||
| handleApiResponseSuccess: handleAcceptExchangeSuccess, | |||
| }) | |||
| ); | |||
| }; | |||
| return ( | |||
| <DirectChatContainer> | |||
| {isLoadingDirectChat || isLoadingDirectChat === undefined ? ( | |||
| @@ -224,7 +229,7 @@ const DirectChat = () => { | |||
| <DirectChatContent | |||
| chat={chatObject} | |||
| exchangeState={exchangeState} | |||
| interlucator={interlocutorObject} | |||
| interlocutor={interlocutorObject} | |||
| refreshChat={refreshChat} | |||
| /> | |||
| </DirectChatContainer> | |||
| @@ -23,18 +23,18 @@ const DirectChatContent = (props) => { | |||
| const myProfileImage = useSelector(selectMineProfilePicture); | |||
| const messagesRef = useRef(null); | |||
| const requester = useSelector(selectRequester); | |||
| const interlucatorProfileImage = props?.interlucator?.image; | |||
| const interlocutorProfileImage = props?.interlocutor?.image; | |||
| const isLoadingChatContent = useSelector( | |||
| selectIsLoadingByActionType(CHAT_SCOPE) | |||
| ); | |||
| const messages = props?.chat?.chat?.messages; | |||
| const messages = props?.chat?.messages; | |||
| useEffect(() => { | |||
| messagesRef.current?.scrollTo({ | |||
| top: messagesRef.current.scrollHeight, | |||
| behaviour: "smooth", | |||
| }); | |||
| window.scrollTo({ top: document.body.scrollHeight, behavior: "smooth" }); | |||
| }, [props?.chat?.chat?.messages, messagesRef, isLoadingChatContent]); | |||
| }, [props?.chat?.messages, messagesRef, isLoadingChatContent]); | |||
| const handleRefresh = () => { | |||
| props.refreshChat(); | |||
| @@ -46,16 +46,20 @@ const DirectChatContent = (props) => { | |||
| ) : ( | |||
| <DirectChatContentContainer> | |||
| <DirectChatContentHeader | |||
| interlucator={props?.interlucator} | |||
| interlocutor={props?.interlocutor} | |||
| exchangeState={props.exchangeState} | |||
| /> | |||
| <MessagesList ref={messagesRef} exchangeState={props?.exchangeState}> | |||
| {messages?.map((item) => { | |||
| const isMyMessage = userId === item.userId; | |||
| const isMyMessage = userId === item.user?._id; | |||
| const image = isMyMessage | |||
| ? myProfileImage | |||
| : interlucatorProfileImage; | |||
| if (requester === requesterStatus.INTERLUCATOR && isMyMessage && item?.isAcceptRequest) | |||
| : interlocutorProfileImage; | |||
| if ( | |||
| requester === requesterStatus.interlocutor && | |||
| isMyMessage && | |||
| item?.isAcceptRequest | |||
| ) | |||
| return; | |||
| return ( | |||
| <MessageContainer key={item?._id || item?._created}> | |||
| @@ -63,7 +67,7 @@ const DirectChatContent = (props) => { | |||
| <RequestExchangeCard | |||
| isMyMessage={isMyMessage} | |||
| message={item} | |||
| chatId={props?.chat?.chat?._id} | |||
| chatId={props?.chat?._id} | |||
| /> | |||
| ) : ( | |||
| <MessageCard | |||
| @@ -79,7 +83,7 @@ const DirectChatContent = (props) => { | |||
| <DirectChatNewMessage | |||
| chat={props?.chat} | |||
| refreshChat={handleRefresh} | |||
| interlucator={props.interlucator} | |||
| interlocutor={props.interlocutor} | |||
| /> | |||
| </DirectChatContentContainer> | |||
| )} | |||
| @@ -90,7 +94,7 @@ const DirectChatContent = (props) => { | |||
| DirectChatContent.propTypes = { | |||
| children: PropTypes.node, | |||
| chat: PropTypes.any, | |||
| interlucator: PropTypes.any, | |||
| interlocutor: PropTypes.any, | |||
| refreshChat: PropTypes.func, | |||
| exchangeState: PropTypes.any, | |||
| }; | |||
| @@ -27,7 +27,7 @@ export const MessagesList = styled(Box)` | |||
| /* justify-content: flex-end; */ | |||
| /* align-items: flex-end; */ | |||
| @media (max-width: 600px) { | |||
| padding: 18px 0; | |||
| padding: 18px 18px; | |||
| } | |||
| &::-webkit-scrollbar { | |||
| width: 5px; | |||
| @@ -32,9 +32,8 @@ const DirectChatContentHeader = (props) => { | |||
| const [phonePopoverAnchorEl, setPhonePopoverAnchorEl] = useState(null); | |||
| const { isMobile } = useIsMobile(); | |||
| const mineProfileBlocked = useSelector(selectAmIBlocked); | |||
| const togglePhonePopover = (event) => { | |||
| if (props.interlucator?.telephone) { | |||
| if (props.interlocutor?.company?.contacts?.telephone) { | |||
| setShowPhonePopover((prevState) => !prevState); | |||
| setPhonePopoverAnchorEl((prevState) => { | |||
| if (prevState) return null; | |||
| @@ -43,10 +42,10 @@ const DirectChatContentHeader = (props) => { | |||
| } | |||
| }; | |||
| const routeToUser = () => { | |||
| if (!props?.interlucator?._blocked) | |||
| if (!props?.interlocutor?._blocked) | |||
| history.push( | |||
| replaceInRoute(PROFILE_PAGE, { | |||
| profileId: props?.interlucator?.userId, | |||
| profileId: props?.interlocutor?._id, | |||
| }) | |||
| ); | |||
| }; | |||
| @@ -57,19 +56,19 @@ const DirectChatContentHeader = (props) => { | |||
| <ProfileImage | |||
| onClick={routeToUser} | |||
| src={getImageUrl( | |||
| props?.interlucator?.image, | |||
| props?.interlocutor?.image, | |||
| variants.chatHeader, | |||
| isMobile | |||
| )} | |||
| /> | |||
| <ProfileDetails> | |||
| <ProfileName onClick={routeToUser}> | |||
| {props?.interlucator?.name} | |||
| {props?.interlocutor?.company?.name} | |||
| </ProfileName> | |||
| <ProfileLocation> | |||
| <ProfileLocationIcon /> | |||
| <ProfileLocationText> | |||
| {props?.interlucator?.location} | |||
| {props?.interlocutor?.company?.contacts?.location} | |||
| </ProfileLocationText> | |||
| </ProfileLocation> | |||
| </ProfileDetails> | |||
| @@ -78,8 +77,8 @@ const DirectChatContentHeader = (props) => { | |||
| <PhoneIconContainer | |||
| disabled={ | |||
| mineProfileBlocked || | |||
| props?.interlucator?._blocked || | |||
| !props.interlucator?.telephone | |||
| props?.interlocutor?._blocked || | |||
| !props.interlocutor?.company?.contacts?.telephone | |||
| } | |||
| onClick={togglePhonePopover} | |||
| > | |||
| @@ -91,7 +90,11 @@ const DirectChatContentHeader = (props) => { | |||
| open={showPhonePopover} | |||
| anchorRight | |||
| onClose={togglePhonePopover} | |||
| content={<PhonePopover phoneNumber={props.interlucator?.telephone} />} | |||
| content={ | |||
| <PhonePopover | |||
| phoneNumber={props.interlocutor?.company?.contacts?.telephone} | |||
| /> | |||
| } | |||
| /> | |||
| </DirectChatContentHeaderContainer> | |||
| {(props.exchangeState === exchangeStatus.I_OFFERED || | |||
| @@ -100,7 +103,11 @@ const DirectChatContentHeader = (props) => { | |||
| <DirectChatHeaderStatusContainer> | |||
| <DirectChatHeaderStatusText> | |||
| {props.exchangeState === exchangeStatus.I_OFFERED | |||
| ? t("messages.requestSentLong") | |||
| ? isMobile | |||
| ? t("messages.requestSentShort") | |||
| : t("messages.requestSentLong") | |||
| : isMobile | |||
| ? t("messages.requestSuccessfulShort") | |||
| : t("messages.requestSuccessfulLong")} | |||
| </DirectChatHeaderStatusText> | |||
| </DirectChatHeaderStatusContainer> | |||
| @@ -111,7 +118,7 @@ const DirectChatContentHeader = (props) => { | |||
| DirectChatContentHeader.propTypes = { | |||
| children: PropTypes.node, | |||
| interlucator: PropTypes.any, | |||
| interlocutor: PropTypes.any, | |||
| exchangeState: PropTypes.bool, | |||
| }; | |||
| @@ -96,6 +96,10 @@ export const DirectChatHeaderStatusContainer = styled(Box)` | |||
| height: 39px; | |||
| width: 100%; | |||
| padding: 9px 36px; | |||
| @media (max-width: 600px) { | |||
| height: 36px; | |||
| padding: 8px 18px; | |||
| } | |||
| `; | |||
| export const DirectChatHeaderStatusText = styled(Typography)` | |||
| font-family: ${selectedTheme.fonts.textFont}; | |||
| @@ -103,4 +107,7 @@ export const DirectChatHeaderStatusText = styled(Typography)` | |||
| font-size: 16px; | |||
| line-height: 21px; | |||
| color: white; | |||
| @media (max-width: 600px) { | |||
| font-size: 14px; | |||
| } | |||
| `; | |||
| @@ -5,10 +5,14 @@ import OfferCard from "../../Cards/OfferCard/OfferCard"; | |||
| import { useSelector } from "react-redux"; | |||
| import { selectExchange } from "../../../store/selectors/exchangeSelector"; | |||
| import { useDispatch } from "react-redux"; | |||
| import { fetchExchange } from "../../../store/actions/exchange/exchangeActions"; | |||
| import { | |||
| fetchExchange, | |||
| setExchange, | |||
| } from "../../../store/actions/exchange/exchangeActions"; | |||
| import { selectSelectedChat } from "../../../store/selectors/chatSelectors"; | |||
| import { selectUserId } from "../../../store/selectors/loginSelectors"; | |||
| import { toggleCreateReviewModal } from "../../../store/actions/modal/modalActions"; | |||
| import { setOneChat } from "../../../store/actions/chat/chatActions"; | |||
| const DirectChatHeader = (props) => { | |||
| const exchange = useSelector(selectExchange); | |||
| @@ -17,17 +21,32 @@ const DirectChatHeader = (props) => { | |||
| const chat = useSelector(selectSelectedChat); | |||
| useEffect(() => { | |||
| if (chat?.chat?.exchangeId) refetchExchange(); | |||
| }, [chat]); | |||
| return () => { | |||
| dispatch(setExchange({})); | |||
| dispatch(setOneChat({})); | |||
| }; | |||
| }, []); | |||
| useEffect(() => { | |||
| if (chat?.exchange?._id) refetchExchange(); | |||
| }, [chat?.exchange]); | |||
| const isDisabledReviews = useMemo(() => { | |||
| if (!exchange.valid) return true; | |||
| if (exchange.seller?.userId === userId && exchange.seller?.givenReview) | |||
| if (exchange.seller?.user._id === userId && exchange.seller?.givenReview) | |||
| return true; | |||
| if (exchange.buyer?.userId === userId && exchange.buyer?.givenReview) | |||
| if (exchange.buyer?.user._id === userId && exchange.buyer?.givenReview) | |||
| return true; | |||
| if (chat?.offer?._deleted) return true; | |||
| if (props.interlocutor?._blocked) return true; | |||
| return false; | |||
| }, [exchange, userId, props.interlocutor, chat]); | |||
| const isDisabledCheckButton = useMemo(() => { | |||
| if (props?.interlocutor?._blocked) return true; | |||
| if (chat?.offer?._deleted) return true; | |||
| return false; | |||
| }, [exchange, userId]); | |||
| }, [props.interlocutor, chat]); | |||
| const showReviewModal = () => { | |||
| dispatch( | |||
| @@ -40,7 +59,7 @@ const DirectChatHeader = (props) => { | |||
| }; | |||
| const refetchExchange = () => { | |||
| dispatch(fetchExchange(chat.chat.exchangeId)); | |||
| dispatch(fetchExchange(chat.exchange?._id)); | |||
| }; | |||
| const acceptExchange = () => { | |||
| @@ -51,14 +70,12 @@ const DirectChatHeader = (props) => { | |||
| <OfferCard | |||
| offer={props.offer} | |||
| aboveChat | |||
| disabledReviews={props.interlocutor?._blocked || isDisabledReviews} | |||
| disabledReviews={isDisabledReviews} | |||
| makeReview={showReviewModal} | |||
| acceptExchange={acceptExchange} | |||
| exchangeState={props?.exchangeState} | |||
| dontShowViews | |||
| disabledCheckButton={ | |||
| props.interlocutor?._blocked || props?.offer?._deleted | |||
| } | |||
| disabledCheckButton={isDisabledCheckButton} | |||
| /> | |||
| </DirectChatHeaderContainer> | |||
| ); | |||
| @@ -10,7 +10,7 @@ import selectedTheme from "../../../themes"; | |||
| import { useDispatch } from "react-redux"; | |||
| import { sendMessage } from "../../../socket/socket"; | |||
| import { useSelector } from "react-redux"; | |||
| import { selectUserId } from "../../../store/selectors/loginSelectors"; | |||
| import { selectJwtToken, selectUserId } from "../../../store/selectors/loginSelectors"; | |||
| import { | |||
| addNewMessage, | |||
| startNewChat, | |||
| @@ -31,24 +31,28 @@ const DirectChatNewMessage = (props) => { | |||
| const { t } = useTranslation(); | |||
| const location = useLocation(); | |||
| const history = useHistory(); | |||
| const token = useSelector(selectJwtToken) | |||
| const userId = useSelector(selectUserId); | |||
| const handleSend = useCallback( | |||
| (newChatId = undefined) => { | |||
| if (props.chat?.chat?._id) { | |||
| const chatId = props.chat?.chat?._id || newChatId; | |||
| sendMessage(chatId, userId, typedValue, props.interlucator.userId); | |||
| if (typedValue?.length === 0) return; | |||
| if (props?.chat?._id) { | |||
| const chatId = props.chat?._id || newChatId; | |||
| sendMessage(chatId, userId, typedValue, props.interlocutor._id, token); | |||
| dispatch( | |||
| addNewMessage({ | |||
| _id: chatId, | |||
| message: { | |||
| userId, | |||
| user: { | |||
| _id: userId, | |||
| }, | |||
| text: typedValue, | |||
| _created: convertLocalDateToUTCDate(new Date()), | |||
| }, | |||
| }) | |||
| ); | |||
| if (props.chat?.chat?._id) { | |||
| if (!exchange.valid && exchange.seller.userId === userId) { | |||
| if (props.chat?._id) { | |||
| if (!exchange.valid && exchange.seller.user._id === userId) { | |||
| dispatch(validateExchange(exchange._id)); | |||
| } | |||
| } | |||
| @@ -57,7 +61,7 @@ const DirectChatNewMessage = (props) => { | |||
| } | |||
| setTypedValue(""); | |||
| }, | |||
| [typedValue, props.chat?.chat?._id, userId, props.interlucator.userId] | |||
| [typedValue, props.chat?._id, userId, props.interlocutor] | |||
| ); | |||
| const handleMessageSendSuccess = (newChatId) => { | |||
| history.replace(`${newChatId}`); | |||
| @@ -82,23 +86,24 @@ const DirectChatNewMessage = (props) => { | |||
| startNewChat({ | |||
| offerId, | |||
| message: typedValue, | |||
| interlucatorUserId: props.interlucator.userId, | |||
| interlocutorUserId: props.interlocutor._id, | |||
| handleMessageSendSuccess, | |||
| }) | |||
| ); | |||
| }; | |||
| console.log(props) | |||
| if (mineProfileBlocked) { | |||
| return <NotAllowedChat mineProfileBlocked />; | |||
| } | |||
| if (props?.chat?.interlocutor?._deleted) { | |||
| if (props?.interlocutor?._deleted) { | |||
| return <NotAllowedChat deleted />; | |||
| } | |||
| if (props?.chat?.offer?.offer?._deleted) { | |||
| if (props?.chat?.offer?._deleted) { | |||
| return <NotAllowedChat />; | |||
| } | |||
| if (props?.chat?.interlocutor?._blocked) { | |||
| return <NotAllowedChat blocked />; | |||
| } | |||
| // if (props?.interlocutor?._blocked) { | |||
| // return <NotAllowedChat blocked />; | |||
| // } | |||
| return ( | |||
| <> | |||
| <DirectChatNewMessageContainer> | |||
| @@ -127,7 +132,7 @@ DirectChatNewMessage.propTypes = { | |||
| children: PropTypes.node, | |||
| chatId: PropTypes.any, | |||
| refreshChat: PropTypes.func, | |||
| interlucator: PropTypes.any, | |||
| interlocutor: PropTypes.any, | |||
| chat: PropTypes.any, | |||
| }; | |||
| @@ -36,12 +36,16 @@ const MiniChatColumn = () => { | |||
| const newChat = useMemo(() => { | |||
| if (location.state?.offerId) { | |||
| return { | |||
| interlocutorData: { | |||
| image: offer?.companyData?.image, | |||
| name: offer?.companyData?.company?.name, | |||
| }, | |||
| offerData: { | |||
| name: offer?.offer?.name, | |||
| participants: [ | |||
| { | |||
| image: offer?.user?.image, | |||
| company: { | |||
| name: offer?.user?.company?.name, | |||
| }, | |||
| }, | |||
| ], | |||
| offer: { | |||
| name: offer?.name, | |||
| }, | |||
| }; | |||
| } | |||
| @@ -72,7 +76,7 @@ const MiniChatColumn = () => { | |||
| <MiniChatCard | |||
| key={Date.now() * Math.random()} | |||
| chat={item} | |||
| selected={item?.chat?._id === selectedChat?.chat?._id} | |||
| selected={item?._id === selectedChat?._id} | |||
| /> | |||
| ); | |||
| })} | |||
| @@ -26,6 +26,10 @@ export const AboutFooterText = styled(Typography)` | |||
| position: relative; | |||
| top: 61px; | |||
| @media (max-width: 1194px) { | |||
| text-align: left; | |||
| } | |||
| @media (max-width: 600px) { | |||
| font-size: 14px; | |||
| top: 30px; | |||
| @@ -57,11 +61,11 @@ export const LinkText = styled(Typography)` | |||
| position: relative; | |||
| top: 8px; | |||
| @media (max-width: 600px) { | |||
| @media (max-width: 700px) { | |||
| display: none; | |||
| } | |||
| `; | |||
| export const Arrow = styled(ArrowButton)` | |||
| transform: rotate(-90deg); | |||
| transform: rotate(-45deg); | |||
| `; | |||
| @@ -11,6 +11,10 @@ export const AboutHeaderContainer = styled(Box)` | |||
| flex-direction: row; | |||
| justify-content: center; | |||
| gap: 36px; | |||
| @media (min-width: 900px) and (max-width: 1200px) { | |||
| margin-right: -250px; | |||
| } | |||
| `; | |||
| export const LinkRoute = styled(Link)` | |||
| text-decoration: none; | |||
| @@ -8,6 +8,8 @@ import { useSelector } from "react-redux"; | |||
| import { selectProfileName } from "../../../../../store/selectors/profileSelectors"; | |||
| import { selectUserId } from "../../../../../store/selectors/loginSelectors"; | |||
| import history from "../../../../../store/utils/history"; | |||
| import { PROFILE_PAGE } from "../../../../../constants/pages"; | |||
| import { replaceInRoute } from "../../../../../util/helpers/routeHelpers"; | |||
| const MyProfileButton = (props) => { | |||
| const name = useSelector(selectProfileName); | |||
| @@ -15,7 +17,11 @@ const MyProfileButton = (props) => { | |||
| const { t } = useTranslation(); | |||
| const handleClick = () => { | |||
| props.toggleDrawer(); | |||
| history.push(`/profile/${userId}`); | |||
| history.push( | |||
| replaceInRoute(PROFILE_PAGE, { | |||
| profileId: userId, | |||
| }) | |||
| ); | |||
| }; | |||
| return ( | |||
| <DrawerButton onClick={handleClick}> | |||
| @@ -3,6 +3,8 @@ import { | |||
| AuthButtonsContainer, | |||
| HeaderContainer, | |||
| LogoContainer, | |||
| MarketplaceLinkRoute, | |||
| MarketplaceLinkRouteContainer, | |||
| ToolsButtonsContainer, | |||
| ToolsContainer, | |||
| } from "./Header.styled"; | |||
| @@ -39,6 +41,8 @@ import LoginButton from "./LoginButton/LoginButton"; | |||
| import RegisterButton from "./RegisterButton/RegisterButton"; | |||
| import useIsMobile from "../../hooks/useIsMobile"; | |||
| import { toggleCreateOfferModal } from "../../store/actions/modal/modalActions"; | |||
| import { ReactComponent as Marketplace } from "../../assets/images/svg/package.svg"; | |||
| import { useTranslation } from "react-i18next"; | |||
| const Header = () => { | |||
| const theme = useTheme(); | |||
| @@ -53,6 +57,7 @@ const Header = () => { | |||
| const [shouldShow, setShouldShow] = useState(true); | |||
| const routeMatch = useRouteMatch(); | |||
| const { isMobile } = useIsMobile(); | |||
| const { t } = useTranslation(); | |||
| // Dont show header on auth routes(login, register, etc.) and admin routes | |||
| useEffect(() => { | |||
| @@ -107,7 +112,7 @@ const Header = () => { | |||
| logo: true, | |||
| }, | |||
| }); | |||
| searchRef.current.value = ""; | |||
| if (searchRef?.current) searchRef.current.value = ""; | |||
| } | |||
| }; | |||
| @@ -118,6 +123,7 @@ const Header = () => { | |||
| if (!shouldShow) { | |||
| return <></>; | |||
| } | |||
| console.log(history); | |||
| return ( | |||
| <HeaderContainer> | |||
| @@ -171,8 +177,19 @@ const Header = () => { | |||
| /> | |||
| ) : ( | |||
| <React.Fragment> | |||
| <LoginButton /> | |||
| <RegisterButton /> | |||
| {routeMatches(ABOUT_PAGE) ? ( | |||
| <MarketplaceLinkRouteContainer> | |||
| <MarketplaceLinkRoute onClick={() => handleLogoClick()}> | |||
| {t("admin.navigation.marketplace")} | |||
| </MarketplaceLinkRoute> | |||
| <Marketplace /> | |||
| </MarketplaceLinkRouteContainer> | |||
| ) : ( | |||
| <> | |||
| <LoginButton /> | |||
| <RegisterButton /> | |||
| </> | |||
| )} | |||
| </React.Fragment> | |||
| )} | |||
| </AuthButtonsContainer> | |||
| @@ -1,5 +1,7 @@ | |||
| import { Box } from "@mui/material"; | |||
| import styled from "styled-components"; | |||
| import selectedTheme from "../../themes"; | |||
| import Link from "../Link/Link"; | |||
| export const DrawerContainer = styled(Box)` | |||
| display: flex; | |||
| @@ -95,3 +97,30 @@ export const AuthButtonsDrawerContainer = styled(Box)` | |||
| justify-content: space-around; | |||
| `; | |||
| export const HeaderContainer = styled(Box)``; | |||
| export const MarketplaceLinkRouteContainer = styled(Box)` | |||
| display: flex; | |||
| @media (max-width: 1200px) { | |||
| position: relative; | |||
| right: -200px; | |||
| } | |||
| `; | |||
| export const MarketplaceLinkRoute = styled(Link)` | |||
| text-decoration: none; | |||
| font-family: ${selectedTheme.fonts.textFont}; | |||
| font-size: 16px; | |||
| line-height: 22px; | |||
| margin-right: 10px; | |||
| letter-spacing: 0.02em; | |||
| margin-left: 70px; | |||
| border-bottom: 1px dashed ${selectedTheme.colors.primaryPurple}; | |||
| &:hover { | |||
| border-bottom: 1px solid ${selectedTheme.colors.iconYellowColor}; | |||
| } | |||
| @media (max-width: 600px) { | |||
| display: none; | |||
| } | |||
| `; | |||
| @@ -16,9 +16,11 @@ const SearchInput = forwardRef((props, ref) => { | |||
| const { t } = useTranslation(); | |||
| const handleSearch = () => { | |||
| if (routeMatches(HOME_PAGE) || routeMatches(BASE_PAGE)) { | |||
| console.log("uslo unutra") | |||
| debounceHelper(() => props.handleSearch(ref.current.value), 500); | |||
| } | |||
| }; | |||
| console.log(routeMatches(HOME_PAGE)) | |||
| const handleManualSearch = () => { | |||
| debounceHelper(() => {}, 500); | |||
| props.handleSearch(ref.current.value); | |||
| @@ -25,10 +25,7 @@ const ItemDetails = (props) => { | |||
| selectIsLoadingByActionType(ONE_OFFER_SCOPE) | |||
| ); | |||
| let isMyProfile = useMemo(() => { | |||
| if ( | |||
| offer?.offer?.userId?.toString() === userId?.toString() || | |||
| props.isAdmin | |||
| ) | |||
| if (offer?.user?._id?.toString() === userId?.toString() || props.isAdmin) | |||
| return true; | |||
| return false; | |||
| }, [offer, userId, props.isAdmin]); | |||
| @@ -41,7 +38,11 @@ const ItemDetails = (props) => { | |||
| ) : ( | |||
| <> | |||
| {!props.singleOffer && ( | |||
| <ItemDetailsHeaderCard offer={offer} isMyProfile={isMyProfile} /> | |||
| <ItemDetailsHeaderCard | |||
| offer={offer} | |||
| isMyProfile={isMyProfile} | |||
| isAdmin={props?.isAdmin} | |||
| /> | |||
| )} | |||
| {props.singleOffer && ( | |||
| <OfferIconContainer> | |||
| @@ -49,7 +50,12 @@ const ItemDetails = (props) => { | |||
| <OfferIconText>{t("offer.product")}</OfferIconText> | |||
| </OfferIconContainer> | |||
| )} | |||
| <ItemDetailsCard offer={offer} isMyOffer={isMyProfile} isAdmin={props.isAdmin} singleOffer /> | |||
| <ItemDetailsCard | |||
| offer={offer} | |||
| isMyOffer={isMyProfile} | |||
| isAdmin={props.isAdmin} | |||
| singleOffer | |||
| /> | |||
| </> | |||
| )} | |||
| </ItemDetailsContainer> | |||
| @@ -25,6 +25,13 @@ import { useMemo } from "react"; | |||
| import itemDetailsData from "../../../notFoundData/itemDetailsData"; | |||
| import { Tooltip } from "@mui/material"; | |||
| import { useTranslation } from "react-i18next"; | |||
| import { replaceInRoute } from "../../../util/helpers/routeHelpers"; | |||
| import { | |||
| ADMIN_SINGLE_USER_PAGE, | |||
| DIRECT_CHAT_PAGE, | |||
| PROFILE_PAGE, | |||
| } from "../../../constants/pages"; | |||
| import { NEW_CHAT } from "../../../constants/chatConstants"; | |||
| const ItemDetailsHeaderCard = (props) => { | |||
| const history = useHistory(); | |||
| @@ -33,7 +40,7 @@ const ItemDetailsHeaderCard = (props) => { | |||
| const { t } = useTranslation(); | |||
| const offer = useMemo(() => { | |||
| if (props.offer) { | |||
| if (props.offer.offer._id === routeMatch.params.offerId) { | |||
| if (props.offer._id === routeMatch.params.offerId) { | |||
| return props.offer; | |||
| } | |||
| } | |||
| @@ -43,18 +50,35 @@ const ItemDetailsHeaderCard = (props) => { | |||
| const { isMobile } = useIsMobile(); | |||
| const handleGoProfile = () => { | |||
| history.push(`/profile/${offer?.offer?.userId}`); | |||
| if (props?.isAdmin) { | |||
| history.push( | |||
| replaceInRoute(ADMIN_SINGLE_USER_PAGE, { | |||
| profileId: props?.offer?.user?._id, | |||
| }) | |||
| ); | |||
| } else { | |||
| history.push( | |||
| replaceInRoute(PROFILE_PAGE, { | |||
| profileId: props?.offer?.user?._id, | |||
| }) | |||
| ); | |||
| } | |||
| }; | |||
| const messageUser = (offer) => { | |||
| const chatItem = chats.find( | |||
| (item) => item.chat.offerId === offer?.offer?._id | |||
| ); | |||
| const chatItem = chats.find((item) => item.offer._id === offer?._id); | |||
| if (chatItem !== undefined) { | |||
| history.push(`/messages/${chatItem.chat._id}`); | |||
| history.push(DIRECT_CHAT_PAGE, { | |||
| chatId: chatItem._id, | |||
| }); | |||
| } else { | |||
| if (offer?.offer?.userId !== userId) { | |||
| history.push(`/messages/newMessage`, { | |||
| offerId: offer?.offer?._id, | |||
| if (offer?.user?._id !== userId) { | |||
| history.push({ | |||
| pathname: replaceInRoute(DIRECT_CHAT_PAGE, { | |||
| chatId: NEW_CHAT, | |||
| }), | |||
| state: { | |||
| offerId: offer?._id, | |||
| }, | |||
| }); | |||
| } | |||
| } | |||
| @@ -67,14 +91,14 @@ const ItemDetailsHeaderCard = (props) => { | |||
| <HeaderTop> | |||
| <OfferImage | |||
| src={getImageUrl( | |||
| offer?.companyData?.image ? offer.companyData.image : "", | |||
| offer?.user?.image ? offer.user.image : "", | |||
| variants.profileImage, | |||
| isMobile | |||
| )} | |||
| /> | |||
| <OfferDetails> | |||
| <OfferTitle isMyProfile={props.isMyProfile} onClick={handleGoProfile}> | |||
| {offer?.companyData?.company?.name} | |||
| {offer?.user?.company?.name} | |||
| </OfferTitle> | |||
| <PIBDetail offer={offer} isMyProfile={props.isMyProfile} /> | |||
| <CategoryDetail offer={offer} isMyProfile={props.isMyProfile} /> | |||
| @@ -115,6 +139,7 @@ ItemDetailsHeaderCard.propTypes = { | |||
| offer: PropTypes.any, | |||
| isMyProfile: PropTypes.bool, | |||
| singleOffer: PropTypes.bool, | |||
| isAdmin: PropTypes.bool, | |||
| }; | |||
| ItemDetailsHeaderCard.defaultProps = { | |||
| halfwidth: false, | |||
| @@ -16,7 +16,7 @@ const CategoryDetail = (props) => { | |||
| <LocationIcon /> | |||
| </DetailIcon> | |||
| <DetailText ismyprofile={props.isMyProfile}> | |||
| {offer.offer?.location?.city} | |||
| {offer?.location?.city} | |||
| </DetailText> | |||
| </DetailContainer> | |||
| ); | |||
| @@ -15,7 +15,7 @@ const PIBDetail = (props) => { | |||
| <PIB /> | |||
| </PIBIcon> | |||
| <DetailText isMyProfile={props.isMyProfile}> | |||
| {`${t("itemDetailsCard.PIB")}${offer?.companyData?.company?.PIB}`} | |||
| {`${t("itemDetailsCard.PIB")}${offer?.user?.company?.PIB}`} | |||
| </DetailText> | |||
| </DetailContainer> | |||
| ); | |||
| @@ -12,13 +12,13 @@ const StatisticDetails = (props) => { | |||
| const { t } = useTranslation(); | |||
| const offer = props.offer; | |||
| const percentOfSucceededExchanges = useMemo(() => { | |||
| if (offer?.companyData?.statistics?.exchanges?.succeeded === 0) { | |||
| if (offer?.user?.statistics?.exchanges?.succeeded === 0) { | |||
| return 0 + "%"; | |||
| } else { | |||
| return ( | |||
| Math.ceil( | |||
| (offer?.companyData?.statistics?.exchanges?.total / | |||
| offer?.companyData?.statistics?.exchanges?.succeeded) * | |||
| (offer?.user?.statistics?.exchanges?.total / | |||
| offer?.user?.statistics?.exchanges?.succeeded) * | |||
| 100 | |||
| ) + "%" | |||
| ); | |||
| @@ -30,13 +30,13 @@ const StatisticDetails = (props) => { | |||
| <BottomDetails> | |||
| <StatusText> | |||
| <StatusValue> | |||
| {offer?.companyData?.statistics?.publishes?.count} | |||
| {offer?.user?.statistics?.publishes?.count} | |||
| </StatusValue> | |||
| {t("itemDetailsCard.offers")} | |||
| </StatusText> | |||
| <StatusText> | |||
| <StatusValue> | |||
| {offer?.companyData?.statistics?.views?.count} | |||
| {offer?.user?.statistics?.views?.count} | |||
| </StatusValue> | |||
| {t("itemDetailsCard.totalViews")} | |||
| </StatusText> | |||
| @@ -91,6 +91,7 @@ const Header = (props) => { | |||
| headerTitle={headerTitle} | |||
| headerIcon={headerIcon} | |||
| offers={props?.offers} | |||
| myOffers={props?.myOffers} | |||
| hideBackButton={props?.hideBackButton} | |||
| /> | |||
| {/* ^^^^^^ */} | |||
| @@ -103,11 +104,13 @@ const Header = (props) => { | |||
| /> | |||
| {/* Select option to choose sorting */} | |||
| <HeaderSelect | |||
| myOffers={props?.myOffers} | |||
| sorting={sorting} | |||
| hideSorting={props?.hideSorting} | |||
| /> | |||
| {!props?.hideSorting && ( | |||
| <HeaderSelect | |||
| myOffers={props?.myOffers} | |||
| sorting={sorting} | |||
| hideSorting={props?.hideSorting} | |||
| /> | |||
| )} | |||
| {/* ^^^^^^ */} | |||
| </HeaderOptions> | |||
| </HeaderContainer> | |||
| @@ -31,15 +31,18 @@ const TooltipHeader = (props) => { | |||
| const handleClickCategory = () => { | |||
| props?.offers?.filters?.locations.clear(); | |||
| props?.offers?.filters?.subcategory.clear(); | |||
| props?.offers?.filters?.companies?.clear(); | |||
| props?.offers?.applyFilters(); | |||
| }; | |||
| const handleClickSubcategory = () => { | |||
| props?.offers?.filters?.locations.clear(); | |||
| props?.offers?.filters?.companies?.clear(); | |||
| props?.offers?.applyFilters(); | |||
| }; | |||
| const goBack = () => { | |||
| history.goBack(); | |||
| }; | |||
| console.log(props) | |||
| return ( | |||
| <Tooltip title={headerString.text}> | |||
| <TooltipInnerContainer> | |||
| @@ -9,11 +9,18 @@ import OffersNotFound from "./OffersNotFound/OffersNotFound"; | |||
| const Offers = (props) => { | |||
| const offers = props?.offers; | |||
| const arrayForMapping = Array.apply(null, Array(4)).map(() => {}); | |||
| console.log("rerender"); | |||
| return ( | |||
| <> | |||
| <OffersFilterButton /> | |||
| <OffersFilterButton | |||
| offers={props?.offers} | |||
| isAdmin={props?.isAdmin} | |||
| myOffers={props?.myOffers} | |||
| toggleFilters={props?.toggleFilters} | |||
| /> | |||
| <OffersSearchField /> | |||
| <OffersNotFound /> | |||
| {!props?.skeleton && <OffersNotFound />} | |||
| <OffersList | |||
| loading={props?.skeleton} | |||
| offers={offers} | |||
| @@ -21,6 +28,7 @@ const Offers = (props) => { | |||
| isGrid={props?.isGrid} | |||
| isUsers={props?.isUsers} | |||
| users={props?.users} | |||
| myOffers={props?.myOffers} | |||
| /> | |||
| {props?.skeleton && | |||
| arrayForMapping.map((item, index) => ( | |||
| @@ -1,6 +1,6 @@ | |||
| import React from "react"; | |||
| import PropTypes from "prop-types"; | |||
| import { useSelector } from "react-redux"; | |||
| import { useDispatch, useSelector } from "react-redux"; | |||
| import { selectTotalOffers } from "../../../../store/selectors/offersSelectors"; | |||
| import { OffersContainer } from "./OffersList.styled"; | |||
| import BigProfileCard from "../../../Cards/ProfileCard/BigProfileCard/BigProfileCard"; | |||
| @@ -9,13 +9,17 @@ import Paging from "../../../Paging/Paging"; | |||
| import { startChat } from "../../../../util/helpers/chatHelper"; | |||
| import { selectLatestChats } from "../../../../store/selectors/chatSelectors"; | |||
| import { selectUserId } from "../../../../store/selectors/loginSelectors"; | |||
| import { setRequester } from "../../../../store/actions/exchange/exchangeActions"; | |||
| import requesterStatus from "../../../../constants/requesterStatus"; | |||
| const OffersList = (props) => { | |||
| const totalOffers = useSelector(selectTotalOffers); | |||
| const chats = useSelector(selectLatestChats); | |||
| const userId = useSelector(selectUserId); | |||
| const dispatch = useDispatch(); | |||
| const offers = props?.offers; | |||
| const messageOneUser = (offer) => { | |||
| dispatch(setRequester(requesterStatus.NOONE)); | |||
| startChat(chats, offer, userId); | |||
| }; | |||
| return ( | |||
| @@ -35,7 +39,7 @@ const OffersList = (props) => { | |||
| offer={item} | |||
| halfwidth={props?.isGrid} | |||
| messageUser={messageOneUser} | |||
| isMyOffer={item?.userId === userId || props?.isAdmin} | |||
| isMyOffer={item?.user._id === userId || props?.isAdmin} | |||
| isAdmin={props?.isAdmin} | |||
| /> | |||
| ); | |||
| @@ -56,7 +56,7 @@ const EditCategory = (props) => { | |||
| }; | |||
| const handleApiResponseSuccess = () => { | |||
| if (clickedOnNext) { | |||
| if (clickedOnNext && props?.showSecondButton) { | |||
| formik.resetForm(); | |||
| inputRef.current.focus(); | |||
| } else closeModalHandler(); | |||
| @@ -9,6 +9,8 @@ import HeaderPopover from "../HeaderPopover/HeaderPopover"; | |||
| import PropTypes from "prop-types"; | |||
| import { makeErrorToastMessage } from "../../../store/utils/makeToastMessage"; | |||
| import { EyeIcon } from "./MyMessages.styled"; | |||
| import { DIRECT_CHAT_PAGE } from "../../../constants/pages"; | |||
| import { replaceInRoute } from "../../../util/helpers/routeHelpers"; | |||
| export const MyMessages = (props) => { | |||
| const { t } = useTranslation(); | |||
| @@ -20,13 +22,16 @@ export const MyMessages = (props) => { | |||
| const convertMessages = (messages) => { | |||
| return messages | |||
| .map((item) => ({ | |||
| src: item.interlocutorData.image, | |||
| title: item.interlocutorData.name, | |||
| onClick: () => goToMessage(item?.chat?._id), | |||
| text: "Proizvod: ", | |||
| bigText: item.offerData.name, | |||
| })) | |||
| .map((item) => { | |||
| let interlocutor = userId === item.participants[0]._id ? 1 : 0; | |||
| return { | |||
| src: item.participants[interlocutor]?.image, | |||
| title: item.participants[interlocutor]?.company?.name, | |||
| onClick: () => goToMessage(item?._id), | |||
| text: "Proizvod: ", | |||
| bigText: item.offer.name, | |||
| }; | |||
| }) | |||
| .slice(0, 2); | |||
| }; | |||
| @@ -42,7 +47,12 @@ export const MyMessages = (props) => { | |||
| }, [chats]); | |||
| const goToMessages = () => { | |||
| if (lastChats.length !== 0) { | |||
| history.push(`/messages/${chats[0].chat?._id}`); | |||
| console.log(chats); | |||
| history.push({ | |||
| pathname: replaceInRoute(DIRECT_CHAT_PAGE, { | |||
| chatId: chats[0]._id, | |||
| }), | |||
| }); | |||
| props.closePopover(); | |||
| } else { | |||
| makeErrorToastMessage(t("messages.noMessagesToast")); | |||
| @@ -50,7 +60,11 @@ export const MyMessages = (props) => { | |||
| } | |||
| }; | |||
| const goToMessage = (chatId) => { | |||
| history.push(`/messages/${chatId}`); | |||
| history.push( | |||
| replaceInRoute(DIRECT_CHAT_PAGE, { | |||
| chatId, | |||
| }) | |||
| ); | |||
| props.closePopover(); | |||
| }; | |||
| return ( | |||
| @@ -8,8 +8,9 @@ import { selectMineHeaderOffers } from "../../../store/selectors/offersSelectors | |||
| import { fetchMineHeaderOffers } from "../../../store/actions/offers/offersActions"; | |||
| import { selectProfileName } from "../../../store/selectors/profileSelectors"; | |||
| import { useHistory } from "react-router-dom"; | |||
| import { MY_OFFERS_PAGE } from "../../../constants/pages"; | |||
| import { ITEM_DETAILS_PAGE, MY_OFFERS_PAGE } from "../../../constants/pages"; | |||
| import { useMemo } from "react"; | |||
| import { replaceInRoute } from "../../../util/helpers/routeHelpers"; | |||
| export const MyPosts = (props) => { | |||
| const { t } = useTranslation(); | |||
| @@ -59,7 +60,11 @@ export const MyPosts = (props) => { | |||
| }, [arrayOfMineOffers, mineOffers]); | |||
| const goToOffer = (id) => { | |||
| history.push(`/proizvodi/${id}`); | |||
| history.push( | |||
| replaceInRoute(ITEM_DETAILS_PAGE, { | |||
| offerId: id, | |||
| }) | |||
| ); | |||
| props.closePopover(); | |||
| }; | |||
| const goToMySwaps = () => { | |||
| @@ -18,9 +18,21 @@ export const PlanContainer = styled(Box)` | |||
| ${(props) => | |||
| props.highlighted && `box-shadow: 4px 4px 9px rgba(0, 0, 0, 0.12);`} | |||
| @media (min-width: 1194px) and (max-width: 1430px) { | |||
| width: 346px; | |||
| height: 100%; | |||
| min-width: 346px; | |||
| } | |||
| @media (max-width: 600px) { | |||
| min-width: 303px; | |||
| width: 100%; | |||
| width: 267px; | |||
| height: fit-content; | |||
| padding: 36px 18px; | |||
| margin-top: 0; | |||
| } | |||
| @media (max-width: 428px) { | |||
| min-width: 100%; | |||
| height: fit-content; | |||
| padding: 36px 18px; | |||
| margin-top: 0; | |||
| @@ -39,6 +51,10 @@ export const PlanTitle = styled(Typography)` | |||
| props.highlighted | |||
| ? selectedTheme.colors.primaryYellow | |||
| : selectedTheme.colors.primaryPurple}; | |||
| @media (min-width: 1194px) and (max-width: 1430px) { | |||
| margin-top: 42px; | |||
| } | |||
| `; | |||
| export const PlanTitleDescription = styled(Typography)` | |||
| font-family: ${selectedTheme.fonts.textFont}; | |||
| @@ -74,6 +90,10 @@ export const PlanPrice = styled(Typography)` | |||
| color: ${(props) => | |||
| props.highlighted ? "white" : selectedTheme.colors.primaryPurple}; | |||
| @media (max-width: 1430px) { | |||
| font-size: 22px; | |||
| } | |||
| @media (max-width: 600px) { | |||
| font-size: 18px; | |||
| } | |||
| @@ -111,8 +131,19 @@ export const PlanDetailTitle = styled(Typography)` | |||
| ? selectedTheme.colors.primaryYellow | |||
| : selectedTheme.colors.primaryPurple}; | |||
| @media (max-width: 1430px) { | |||
| max-width: 34px; | |||
| max-height: 20px; | |||
| white-space: nowrap; | |||
| overflow: hidden; | |||
| } | |||
| @media (max-width: 600px) { | |||
| font-size: 14px; | |||
| max-width: 30px; | |||
| max-height: 20px; | |||
| white-space: nowrap; | |||
| overflow: hidden; | |||
| } | |||
| `; | |||
| export const PlanDetailDescription = styled(Typography)` | |||
| @@ -161,6 +192,10 @@ export const PlanIcon = styled(Box)` | |||
| } | |||
| } | |||
| @media (min-width: 1194px) and (max-width: 1430px) { | |||
| left: calc(50% - 12px); | |||
| } | |||
| @media (max-width: 600px) { | |||
| svg { | |||
| width: 18px; | |||
| @@ -9,6 +9,10 @@ export const PricesComponentContainer = styled(Box)` | |||
| padding: 72px; | |||
| background: white; | |||
| @media (max-width: 1430px) { | |||
| padding: 51px; | |||
| } | |||
| @media (max-width: 600px) { | |||
| padding: 36px; | |||
| } | |||
| @@ -22,6 +26,15 @@ export const PlansContainer = styled(Box)` | |||
| margin-top: 46px; | |||
| margin-bottom: 36px; | |||
| @media (max-width: 1430px) { | |||
| gap: 27px; | |||
| } | |||
| @media (max-width: 1193px) { | |||
| flex-direction: column; | |||
| align-items: center; | |||
| } | |||
| @media (max-width: 600px) { | |||
| flex-direction: column; | |||
| gap: 27px; | |||
| @@ -4,6 +4,10 @@ import styled from "styled-components"; | |||
| export const PrivacyPolicyContainer = styled(Box)` | |||
| margin: 72px; | |||
| @media (max-width: 834px) { | |||
| margin: 45px; | |||
| } | |||
| @media (max-width: 600px) { | |||
| margin: 36px 36px 69px 36px; | |||
| } | |||
| @@ -54,6 +54,12 @@ const ProfileOffers = (props) => { | |||
| const dispatch = useDispatch(); | |||
| const searchRef = useRef(null); | |||
| useEffect(() => { | |||
| return () => { | |||
| dispatch(setProfileOffers([])); | |||
| }; | |||
| }, []); | |||
| useEffect(() => { | |||
| dispatch( | |||
| fetchProfileOffers({ | |||
| @@ -62,6 +68,7 @@ const ProfileOffers = (props) => { | |||
| sortOption: sortOption, | |||
| append: isMobile && append, | |||
| page: paging.currentPage, | |||
| isAdmin: props?.isAdmin, | |||
| }) | |||
| ); | |||
| setAppend(true); | |||
| @@ -107,14 +114,14 @@ const ProfileOffers = (props) => { | |||
| <ProfileOffersHeaderSkeleton /> | |||
| {isMobile ? ( | |||
| <SkeletonContainer> | |||
| <SkeletonOfferCard vertical /> | |||
| <SkeletonOfferCard vertical /> | |||
| <SkeletonOfferCard vertical /> | |||
| <SkeletonOfferCard vertical skeleton /> | |||
| <SkeletonOfferCard vertical skeleton /> | |||
| <SkeletonOfferCard vertical skeleton /> | |||
| </SkeletonContainer> | |||
| ) : ( | |||
| <> | |||
| {arrayForMapping.map((item, index) => ( | |||
| <SkeletonOfferCard key={index} /> | |||
| <SkeletonOfferCard key={index} skeleton /> | |||
| ))} | |||
| </> | |||
| )} | |||
| @@ -1,14 +1,14 @@ | |||
| import React from "react"; | |||
| import PropTypes from "prop-types"; | |||
| import { Button, Icon } from "@mui/material"; | |||
| import { useSlate } from "slate-react"; | |||
| import { Editor, Transforms, Element as SlateElement } from "slate"; | |||
| import { BlockButtonContainer, BlockButtonIcon } from "./BlockButton.styled"; | |||
| const LIST_TYPES = ["numbered-list", "bulleted-list"]; | |||
| const TEXT_ALIGN_TYPES = ["left", "center", "right", "justify"]; | |||
| const BlockButton = ({ format, icon }) => { | |||
| const editor = useSlate(); | |||
| return ( | |||
| <Button | |||
| <BlockButtonContainer | |||
| active={isBlockActive( | |||
| editor, | |||
| format, | |||
| @@ -19,8 +19,8 @@ const BlockButton = ({ format, icon }) => { | |||
| toggleBlock(editor, format); | |||
| }} | |||
| > | |||
| <Icon>{icon}</Icon> | |||
| </Button> | |||
| <BlockButtonIcon>{icon}</BlockButtonIcon> | |||
| </BlockButtonContainer> | |||
| ); | |||
| }; | |||
| const isBlockActive = (editor, format, blockType = "type") => { | |||
| @@ -0,0 +1,27 @@ | |||
| import { Box } from "@mui/system"; | |||
| import styled, { css } from "styled-components"; | |||
| import selectedTheme from "../../../themes"; | |||
| export const BlockButtonContainer = styled(Box)` | |||
| display: inline; | |||
| cursor: pointer; | |||
| `; | |||
| export const BlockButtonIcon = styled(Box)` | |||
| font-size: 16px; | |||
| font-family: "Source Code Pro"; | |||
| ${(props) => | |||
| props.format === "bold" | |||
| ? `font-weight: bold;` | |||
| : props.format === "italic" | |||
| ? "font-style: italic;" | |||
| : props.format === "underline" | |||
| ? `text-decoration: underline;` | |||
| : ""} | |||
| color: ${selectedTheme.colors.primaryGrayText}; | |||
| line-height: 20px; | |||
| ${(props) => | |||
| props.active && | |||
| css` | |||
| color: ${selectedTheme.colors.primaryText}; | |||
| `} | |||
| `; | |||
| @@ -0,0 +1,43 @@ | |||
| import React from "react"; | |||
| import PropTypes from "prop-types"; | |||
| import { useSlate } from "slate-react"; | |||
| import { Editor } from "slate"; | |||
| import { MarkButtonContainer, MarkButtonIcon } from "../MarkButton/MarkButton.styled"; | |||
| const toggleMark = (editor, format) => { | |||
| const isActive = isMarkActive(editor, format); | |||
| if (isActive) { | |||
| Editor.removeMark(editor, format); | |||
| } else { | |||
| Editor.addMark(editor, format, true); | |||
| } | |||
| }; | |||
| const isMarkActive = (editor, format) => { | |||
| const marks = Editor.marks(editor); | |||
| return marks ? marks[format] === true : false; | |||
| }; | |||
| const ColorButton = ({ format, icon }) => { | |||
| const editor = useSlate(); | |||
| return ( | |||
| <MarkButtonContainer | |||
| active={isMarkActive(editor, format)} | |||
| format={format} | |||
| onMouseDown={(event) => { | |||
| event.preventDefault(); | |||
| toggleMark(editor, format); | |||
| }} | |||
| > | |||
| <MarkButtonIcon format={format} active={isMarkActive(editor, format)}> | |||
| {icon} | |||
| </MarkButtonIcon> | |||
| </MarkButtonContainer> | |||
| ); | |||
| }; | |||
| ColorButton.propTypes = { | |||
| format: PropTypes.any, | |||
| icon: PropTypes.any, | |||
| }; | |||
| export default ColorButton; | |||
| @@ -1,8 +1,8 @@ | |||
| import React from "react"; | |||
| import PropTypes from "prop-types"; | |||
| import { Button, Icon } from "@mui/material"; | |||
| import { useSlate } from "slate-react"; | |||
| import { Editor } from "slate"; | |||
| import { MarkButtonContainer, MarkButtonIcon } from "./MarkButton.styled"; | |||
| const toggleMark = (editor, format) => { | |||
| const isActive = isMarkActive(editor, format); | |||
| @@ -22,15 +22,18 @@ const isMarkActive = (editor, format) => { | |||
| const MarkButton = ({ format, icon }) => { | |||
| const editor = useSlate(); | |||
| return ( | |||
| <Button | |||
| <MarkButtonContainer | |||
| active={isMarkActive(editor, format)} | |||
| format={format} | |||
| onMouseDown={(event) => { | |||
| event.preventDefault(); | |||
| toggleMark(editor, format); | |||
| }} | |||
| > | |||
| <Icon>{`${icon} ${isMarkActive(editor, format)}`}</Icon> | |||
| </Button> | |||
| <MarkButtonIcon format={format} active={isMarkActive(editor, format)}> | |||
| {icon} | |||
| </MarkButtonIcon> | |||
| </MarkButtonContainer> | |||
| ); | |||
| }; | |||
| MarkButton.propTypes = { | |||
| @@ -0,0 +1,27 @@ | |||
| import { Box } from "@mui/material"; | |||
| import styled, { css } from "styled-components"; | |||
| import selectedTheme from "../../../themes"; | |||
| export const MarkButtonContainer = styled(Box)` | |||
| display: inline; | |||
| cursor: pointer; | |||
| `; | |||
| export const MarkButtonIcon = styled(Box)` | |||
| font-size: 16px; | |||
| font-family: "Source Code Pro"; | |||
| ${(props) => | |||
| props.format === "bold" | |||
| ? `font-weight: bold;` | |||
| : props.format === "italic" | |||
| ? "font-style: italic;" | |||
| : props.format === "underline" | |||
| ? `text-decoration: underline;` | |||
| : ""} | |||
| color: ${selectedTheme.colors.primaryGrayText}; | |||
| line-height: 20px; | |||
| ${(props) => | |||
| props.active && | |||
| css` | |||
| color: ${selectedTheme.colors.primaryText}; | |||
| `} | |||
| `; | |||
| @@ -3,11 +3,51 @@ import { Editable, withReact, Slate } from "slate-react"; | |||
| import { createEditor } from "slate"; | |||
| import RichTextElement from "./RichTextElement/RichTextElement"; | |||
| import BlockButton from "./BlockButton/BlockButton"; | |||
| import MarkButton from "./MarkButton/MarkButton"; | |||
| import RichTextLeaf from "./RichTextLeaf/RichTextLeaf"; | |||
| import { ReactComponent as BulletedList } from "../../assets/images/svg/bulleted-list.svg"; | |||
| import { | |||
| EditableContainer, | |||
| EditableInnerContainer, | |||
| RichTextComponentContainer, | |||
| SlateButtonsContainer, | |||
| } from "./RichTextComponent.styled"; | |||
| import { useState } from "react"; | |||
| import BlockButton from "./BlockButton/BlockButton"; | |||
| import ColorButton from "./ColorButton/ColorButton"; | |||
| import selectedTheme from "../../themes"; | |||
| const COLORS = [ | |||
| { | |||
| color: selectedTheme.colors.colorPicker.darkGray, | |||
| i18key: "colorPicker.darkGray", | |||
| }, | |||
| { | |||
| color: selectedTheme.colors.colorPicker.gray, | |||
| i18key: "colorPicker.gray", | |||
| }, | |||
| { | |||
| color: selectedTheme.colors.colorPicker.yellow, | |||
| i18key: "colorPicker.yellow", | |||
| }, | |||
| { | |||
| color: selectedTheme.colors.colorPicker.purple, | |||
| i18key: "colorPicker.purple", | |||
| }, | |||
| { | |||
| color: selectedTheme.colors.colorPicker.pink, | |||
| i18key: "colorPicker.pink", | |||
| }, | |||
| ]; | |||
| const RichTextComponent = () => { | |||
| const [color, setColor] = useState(COLORS[0]); | |||
| const [value, setValue] = useState([ | |||
| { | |||
| type: "paragraph", | |||
| children: [{ text: "" }], | |||
| }, | |||
| ]); | |||
| const renderElement = useCallback( | |||
| (props) => <RichTextElement {...props} />, | |||
| [] | |||
| @@ -16,67 +56,47 @@ const RichTextComponent = () => { | |||
| const editor = useMemo(() => withReact(createEditor()), []); | |||
| return ( | |||
| <Slate editor={editor} value={initialValue}> | |||
| <div> | |||
| <MarkButton format="bold" icon="format_bold" /> | |||
| <MarkButton format="italic" icon="format_italic" /> | |||
| <MarkButton format="underline" icon="format_underlined" /> | |||
| <MarkButton format="code" icon="code" /> | |||
| <BlockButton format="heading-one" icon="looks_one" /> | |||
| <BlockButton format="heading-two" icon="looks_two" /> | |||
| <BlockButton format="block-quote" icon="format_quote" /> | |||
| <BlockButton format="numbered-list" icon="format_list_numbered" /> | |||
| <BlockButton format="bulleted-list" icon="format_list_bulleted" /> | |||
| <BlockButton format="left" icon="format_align_left" /> | |||
| <BlockButton format="center" icon="format_align_center" /> | |||
| <BlockButton format="right" icon="format_align_right" /> | |||
| <BlockButton format="justify" icon="format_align_justify" /> | |||
| </div> | |||
| <Editable | |||
| renderElement={renderElement} | |||
| renderLeaf={renderLeaf} | |||
| placeholder="Enter some rich text…" | |||
| spellCheck | |||
| autoFocus | |||
| /> | |||
| </Slate> | |||
| <RichTextComponentContainer> | |||
| <Slate | |||
| editor={editor} | |||
| value={value} | |||
| onChange={(newValue) => { | |||
| console.log(newValue); | |||
| setValue(newValue); | |||
| }} | |||
| > | |||
| <SlateButtonsContainer> | |||
| <MarkButton format="bold" icon="B" /> | |||
| <MarkButton format="italic" icon="I" /> | |||
| <MarkButton format="underline" icon="U" /> | |||
| <BlockButton format="bulleted-list" icon={<BulletedList />} /> | |||
| <ColorButton | |||
| format="color" | |||
| currentColor={color} | |||
| setCurrentColor={setColor} | |||
| colorValues={COLORS} | |||
| /> | |||
| </SlateButtonsContainer> | |||
| <EditableContainer> | |||
| <EditableInnerContainer> | |||
| <Editable | |||
| renderElement={renderElement} | |||
| renderLeaf={renderLeaf} | |||
| spellCheck | |||
| autoFocus | |||
| /> | |||
| </EditableInnerContainer> | |||
| </EditableContainer> | |||
| </Slate> | |||
| </RichTextComponentContainer> | |||
| ); | |||
| }; | |||
| const initialValue = [ | |||
| { | |||
| type: "paragraph", | |||
| children: [ | |||
| { text: "This is editable " }, | |||
| { text: "rich", bold: true }, | |||
| { text: " text, " }, | |||
| { text: "much", italic: true }, | |||
| { text: " better than a " }, | |||
| { text: "<textarea>", code: true }, | |||
| { text: "!" }, | |||
| ], | |||
| }, | |||
| { | |||
| type: "paragraph", | |||
| children: [ | |||
| { | |||
| text: "Since it's rich text, you can do things like turn a selection of text ", | |||
| }, | |||
| { text: "bold", bold: true }, | |||
| { | |||
| text: ", or add a semantically rendered block quote in the middle of the page, like this:", | |||
| }, | |||
| ], | |||
| }, | |||
| { | |||
| type: "block-quote", | |||
| children: [{ text: "A wise quote." }], | |||
| }, | |||
| { | |||
| type: "paragraph", | |||
| align: "center", | |||
| children: [{ text: "Try it out for yourself!" }], | |||
| }, | |||
| ]; | |||
| // const initialValue = [ | |||
| // { | |||
| // type: "paragraph", | |||
| // children: [{ text: "" }], | |||
| // }, | |||
| // ]; | |||
| export default RichTextComponent; | |||
| @@ -0,0 +1,46 @@ | |||
| import { Box } from "@mui/material"; | |||
| import styled from "styled-components"; | |||
| import selectedTheme from "../../themes"; | |||
| export const SlateButtonsContainer = styled(Box)` | |||
| display: flex; | |||
| flex-direction: row; | |||
| height: 36px; | |||
| background-color: ${selectedTheme.colors.stylingTextBackground}; | |||
| padding: 8px 16px; | |||
| border-radius: 4px; | |||
| gap: 20px; | |||
| `; | |||
| export const RichTextComponentContainer = styled(Box)` | |||
| width: 100%; | |||
| position: relative; | |||
| top: 14px; | |||
| height: 140px; | |||
| border: 1px solid ${selectedTheme.colors.borderNormal}; | |||
| margin-bottom: 14px; | |||
| `; | |||
| export const EditableContainer = styled(Box)` | |||
| max-height: 104px; | |||
| overflow: auto; | |||
| &::-webkit-scrollbar { | |||
| width: 5px; | |||
| height: 5px; | |||
| } | |||
| &::-webkit-scrollbar-track { | |||
| background: #ddd; | |||
| } | |||
| &::-webkit-scrollbar-thumb { | |||
| background: #777; | |||
| } | |||
| scrollbar-width: thin; | |||
| scrollbar-color: #ddd; | |||
| `; | |||
| export const EditableInnerContainer = styled(Box)` | |||
| padding: 10px 16px; | |||
| & > div { | |||
| min-height: 84px; | |||
| } | |||
| & * { | |||
| font-family: ${selectedTheme.fonts.textFont}; | |||
| } | |||
| `; | |||
| @@ -1,5 +1,6 @@ | |||
| import React from "react"; | |||
| import PropTypes from "prop-types"; | |||
| import { ListContainer } from "./RichTextElement.styled"; | |||
| const RichTextElement = ({ attributes, children, element }) => { | |||
| const style = { textAlign: element.align }; | |||
| @@ -12,9 +13,9 @@ const RichTextElement = ({ attributes, children, element }) => { | |||
| ); | |||
| case "bulleted-list": | |||
| return ( | |||
| <ul style={style} {...attributes}> | |||
| <ListContainer style={style} {...attributes}> | |||
| {children} | |||
| </ul> | |||
| </ListContainer> | |||
| ); | |||
| case "heading-one": | |||
| return ( | |||
| @@ -42,9 +43,9 @@ const RichTextElement = ({ attributes, children, element }) => { | |||
| ); | |||
| default: | |||
| return ( | |||
| <p style={style} {...attributes}> | |||
| <div style={style} {...attributes}> | |||
| {children} | |||
| </p> | |||
| </div> | |||
| ); | |||
| } | |||
| }; | |||
| @@ -0,0 +1,9 @@ | |||
| import { Box } from "@mui/material"; | |||
| import styled from "styled-components"; | |||
| export const ListContainer = styled(Box)` | |||
| padding-left: | |||
| & > div { | |||
| display: list-item; | |||
| } | |||
| ` | |||
| @@ -10,7 +10,7 @@ const RichTextLeaf = ({ attributes, children, leaf }) => { | |||
| } | |||
| if (leaf.italic) { | |||
| children = <em>{children}</em>; | |||
| children = <i>{children}</i>; | |||
| } | |||
| if (leaf.underline) { | |||
| @@ -19,13 +19,11 @@ const ReviewsSorting = forwardRef((props, ref) => { | |||
| const [value, setValue] = useState(); | |||
| const changeValue = (event) => { | |||
| if (props.isAdmin) { | |||
| // if(event.target.value.value === 1) { | |||
| // dispatch(setReviews(reviews.givenReviews)); | |||
| // } else { | |||
| // dispatch(setReviews(reviews.receivedReviews)); | |||
| // } | |||
| // if(event.target.value.value === 1) { | |||
| // dispatch(setReviews(reviews.givenReviews)); | |||
| // } else { | |||
| // dispatch(setReviews(reviews.receivedReviews)); | |||
| // } | |||
| } else { | |||
| dispatch( | |||
| setReviews( | |||
| @@ -42,19 +40,25 @@ const ReviewsSorting = forwardRef((props, ref) => { | |||
| const sortEnum = useMemo(() => { | |||
| if (props.isAdmin) return sortAdminEnum; | |||
| return reviewSortEnum; | |||
| }); | |||
| }, [props.isAdmin]); | |||
| const initialSortOption = useMemo(() => { | |||
| if (props.isAdmin) return sortAdminEnum.GIVEN; | |||
| return reviewSortEnum.INITIAL; | |||
| }, [props.isAdmin]); | |||
| useImperativeHandle(ref, () => ({ | |||
| sortValue: value, | |||
| hasGivenReview: value?.value === sortAdminEnum.GIVEN.value | |||
| })) | |||
| hasGivenReview: value?.value === sortAdminEnum.GIVEN.value, | |||
| })); | |||
| return ( | |||
| <HeaderSelect | |||
| value={value || sortEnum.INITIAL} | |||
| value={value || initialSortOption} | |||
| IconComponent={DownArrowIcon} | |||
| onChange={changeValue} | |||
| > | |||
| <SelectOption style={{ display: "none" }} value={sortEnum.INITIAL}> | |||
| {sortEnum.INITIAL.mainText} | |||
| <SelectOption style={{ display: "none" }} value={initialSortOption}> | |||
| {initialSortOption.mainText} | |||
| </SelectOption> | |||
| {Object.keys(sortEnum).map((property) => { | |||
| if (sortEnum[property].value === 0) return; | |||