jovan.cirkovic 3 년 전
부모
커밋
f48bb6aa8c
33개의 변경된 파일414개의 추가작업 그리고 127개의 파일을 삭제
  1. 16
    12
      src/components/Cards/OfferCard/OfferCard.styled.js
  2. 8
    3
      src/components/Cards/ProfileCard/ProfileCard.js
  3. 11
    6
      src/components/Cards/ProfileCard/ProfileCard.styled.js
  4. 1
    1
      src/components/Cards/UserReviewsCard/ReviewDetails/ReviewDetails.js
  5. 6
    1
      src/components/Cards/UserReviewsCard/ReviewDetails/ReviewDetails.styled.js
  6. 0
    1
      src/components/Cards/UserReviewsCard/ReviewOffer/ReviewOffer.styled.js
  7. 1
    7
      src/components/Cards/UserReviewsCard/ReviewQuote/ReviewQuote.js
  8. 12
    7
      src/components/Cards/UserReviewsCard/ReviewQuote/ReviewQuote.styled.js
  9. 11
    1
      src/components/Cards/UserReviewsCard/ReviewerProfile/ReviewerProfile.js
  10. 5
    1
      src/components/Cards/UserReviewsCard/ReviewerProfile/ReviewerProfile.styled.js
  11. 6
    2
      src/components/Cards/UserReviewsCard/UserReviewsCard.js
  12. 12
    2
      src/components/Cards/UserReviewsCard/UserReviewsCard.styled.js
  13. 0
    2
      src/components/ChatColumn/ChatColumn.js
  14. 1
    1
      src/components/ChatColumn/ChatColumn.styled.js
  15. 10
    0
      src/components/DirectChat/DirectChatContent/DirectChatContentHeader/DirectChatContentHeader.styled.js
  16. 1
    1
      src/components/DirectChat/DirectChatNewMessage/DirectChatNewMessage.js
  17. 27
    16
      src/components/MarketPlace/Header/Header.js
  18. 49
    4
      src/components/MarketPlace/Header/Header.styled.js
  19. 2
    0
      src/components/MarketPlace/MarketPlace.styled.js
  20. 9
    3
      src/components/MarketPlace/Offers/HeaderMyOffers.js/HeadersMyOffers.styled.js
  21. 8
    11
      src/components/MarketPlace/Offers/Offers.js
  22. 2
    2
      src/components/MarketPlace/Offers/Offers.styled.js
  23. 3
    6
      src/components/Profile/Profile.js
  24. 2
    0
      src/components/Profile/ProfileOffers/ProfileOffers.styled.js
  25. 58
    0
      src/components/UserReviews/ReviewsSorting/ReviewsSorting.js
  26. 35
    0
      src/components/UserReviews/ReviewsSorting/ReviewsSorting.styled.js
  27. 22
    17
      src/components/UserReviews/UserReviews.js
  28. 3
    2
      src/components/UserReviews/UserReviews.styled.js
  29. 34
    15
      src/enums/reviewEnum.js
  30. 3
    1
      src/i18n/resources/rs.js
  31. 1
    1
      src/layouts/ItemDetailsLayout/ItemDetailsLayout.styled.js
  32. 2
    1
      src/store/saga/offersSaga.js
  33. 53
    0
      src/util/helpers/reviewsHelper.js

+ 16
- 12
src/components/Cards/OfferCard/OfferCard.styled.js 파일 보기

@@ -98,6 +98,7 @@ export const OfferTitle = styled(Typography)`
display: -webkit-box;
-webkit-line-clamp: 1;
-webkit-box-orient: vertical;
text-overflow: ellipsis;
max-height: 33px;
margin-bottom: 28px;
@media (max-width: 550px) {
@@ -109,10 +110,12 @@ export const OfferTitle = styled(Typography)`
`
display: flex;
flex: none;
max-height: 44px;
position: relative;
line-height: 22px;
margin-top: 5px;
font-size: 18px;
margin-bottom: 0px;

`}
}
@@ -134,8 +137,6 @@ export const OfferAuthorName = styled(Typography)`
`
line-height: 19px;
font-size: 14px;
position: absolute;
bottom: 125px;
`}
}
`;
@@ -148,9 +149,7 @@ export const OfferLocation = styled(Typography)`
props.vertical &&
`
font-size: 12px;
margin-top: 5px;
position: absolute;
bottom: 105px;
margin-top: -17px;
`}
`;
export const OfferDetails = styled(Box)`
@@ -173,8 +172,8 @@ export const OfferCategory = styled(Box)`
${(props) =>
props.vertical &&
`
position: absolute;
bottom: 60px;
// position: absolute;
// bottom: 60px;
`}
`;
export const OfferPackage = styled(Box)`
@@ -303,9 +302,9 @@ export const RemoveIconContainer = styled(MessageIcon)`

@media screen and (max-width: 600px) {
display: block;
position: absolute;
left: 59px;
top: 325px;
position: ${props => props.vertical && "absolute"};
top: ${props => props.vertical && "325px"};
left: ${props => props.vertical && "59px"};
}
`;
export const RemoveIcon = styled(Remove)``;
@@ -317,8 +316,9 @@ export const EditIconContainer = styled(MessageIcon)`
@media screen and (max-width: 600px) {
position: absolute;
display: block;
top: 325px;
left: 18px;
right: ${props => !props.vertical && "64px"};
top: ${props => props.vertical && "325px"};
left: ${props => props.vertical && "18px"};
}
`;
export const EditIcon = styled(Edit)``;
@@ -341,6 +341,10 @@ export const LikeIcon = styled(Like)`
? selectedTheme.colors.primaryPurpleDisabled
: selectedTheme.colors.primaryPurple};
}
@media (max-width: 600px) {
position: relative;
top: -1px;
}
`;
export const PinIcon = styled(Pin)`
position: absolute;

+ 8
- 3
src/components/Cards/ProfileCard/ProfileCard.js 파일 보기

@@ -39,7 +39,10 @@ const ProfileCard = () => {
const dispatch = useDispatch();
const profileFromRedux = useSelector(selectProfile);
const userId = useSelector(selectUserId);
const idProfile = routeMatch.params.idProfile;
const idProfile = useMemo(() => {
console.log("routematch", routeMatch);
return routeMatch.params.idProfile;
}, [routeMatch.params.idProfile]);
const { t } = useTranslation();

const profile = useMemo(() => {
@@ -51,17 +54,19 @@ const ProfileCard = () => {
return companyData;
}, [profileFromRedux]);


useEffect(() => {
if (idProfile?.length > 0) {
reFetchProfile();
}
}, [idProfile]);

useEffect(() => {
setIsMyProfile(userId === idProfile);
}, [userId, idProfile]);

const reFetchProfile = () => {
dispatch(fetchProfile(idProfile));
dispatch(fetchProfileOffers(idProfile));
if (userId === idProfile) setIsMyProfile(true);
};

let percentOfSucceededExchanges;

+ 11
- 6
src/components/Cards/ProfileCard/ProfileCard.styled.js 파일 보기

@@ -44,6 +44,10 @@ export const MessageButton = styled(EditButton)`
background: ${selectedTheme.colors.primaryPurple};
width: 40px;
height: 40px;
@media (max-width: 600px) {
width: 32px;
height: 32px;
}
`;

export const ProfileCardWrapper = styled(Card)`
@@ -247,16 +251,17 @@ export const MessageIcon = styled(Mail)`
width: 19.5px;
height: 19.5px;
position: relative;
left: 2.5px;
top: 3.5px;
left: 1px;
top: 3px;
& path {
stroke: ${selectedTheme.colors.primaryYellow};
}
@media (max-width: 600px) {
width: 14px;
height: 14px;
right: 0.5px;
}
width: 16px;
height: 16px;
left: -1px;
top: 1px;
}
`;

export const ProfileInfoContainer = styled(Grid)`

+ 1
- 1
src/components/Cards/UserReviewsCard/ReviewDetails/ReviewDetails.js 파일 보기

@@ -10,7 +10,7 @@ import { useTranslation } from "react-i18next";
const ReviewDetails = (props) => {
const { t } = useTranslation();
return (
<ReviewDetailsContainer sx={{ pl: 2, pb: 2 }}>
<ReviewDetailsContainer>
<ReviewDetailsText variant="body2" sx={{ display: "block" }}>
{t("reviews.isCorrectCommunication") + ": "}
<ReviewDetailsValue>

+ 6
- 1
src/components/Cards/UserReviewsCard/ReviewDetails/ReviewDetails.styled.js 파일 보기

@@ -2,16 +2,21 @@ import { Grid, Typography } from "@mui/material";
import styled from "styled-components";
import selectedTheme from "../../../../themes";

export const ReviewDetailsContainer = styled(Grid)``;
export const ReviewDetailsContainer = styled(Grid)`
padding-bottom: 1rem;
`;
export const ReviewDetailsText = styled(Typography)`
font-family: ${selectedTheme.fonts.textFont};
font-size: 12px;
color: ${selectedTheme.colors.primaryDarkText};
font-style: italic;
letter-spacing: 0.02em;
line-height: 16px;
`;
export const ReviewDetailsValue = styled(Typography)`
color: ${selectedTheme.colors.primaryPurple};
font-style: normal;
line-height: 16px;
font-size: 12px;
font-weight: 600;
`;

+ 0
- 1
src/components/Cards/UserReviewsCard/ReviewOffer/ReviewOffer.styled.js 파일 보기

@@ -6,7 +6,6 @@ export const ReviewOfferContainer = styled(Box)`
display: flex;
flex-direction: row;
gap: 18px;
padding-left: 16px;
`;
export const ReviewOfferImage = styled.img`
width: 54px;

+ 1
- 7
src/components/Cards/UserReviewsCard/ReviewQuote/ReviewQuote.js 파일 보기

@@ -12,13 +12,7 @@ import { reviewEnum } from "../../../../enums/reviewEnum";

const ReviewQuote = (props) => {
return (
<ReviewQuoteContainer
container
direction="row"
justifyContent="start"
alignItems="center"
spacing={2}
>
<ReviewQuoteContainer>
<ThumbContainer item>
{props.isSuccessfulSwap.toLowerCase() ===
reviewEnum.YES.mainText.toLowerCase() ? (

+ 12
- 7
src/components/Cards/UserReviewsCard/ReviewQuote/ReviewQuote.styled.js 파일 보기

@@ -1,15 +1,20 @@
import { Grid, Typography } from "@mui/material";
import { Box, Grid, Typography } from "@mui/material";
import styled from "styled-components";
import selectedTheme from "../../../../themes";
import ThumbUpIcon from "@mui/icons-material/ThumbUp";
import ThumbDownIcon from "@mui/icons-material/ThumbDown";

export const ReviewQuoteContainer = styled(Grid)`
export const ReviewQuoteContainer = styled(Box)`
position: relative;
left: 8px;
padding-left: 2px;
padding-top: 2px;
padding-bottom: 2px;
margin: 0;
display: flex;
flex-direction: row;
margin-top: 18px;
align-items: center;
justify-content: start;
margin-bottom: 15px;
`;
export const ThumbContainer = styled(Grid)`
max-width: 20px;
@@ -17,15 +22,15 @@ export const ThumbContainer = styled(Grid)`
export const ReviewQuoteTextContainer = styled(Grid)``;
export const ReviewQuoteText = styled(Typography)`
font-family: ${selectedTheme.fonts.textFont};
font-size: 12px;
font-size: 16px;
color: ${selectedTheme.colors.primaryDarkText};
position: relative;
left: 10px;
`;
export const ThumbUp = styled(ThumbUpIcon)`
position: relative;
left: -8px;
`;
export const ThumbDown = styled(ThumbDownIcon)`
position: relative;
left: -8px;
top: 3px;
`;

+ 11
- 1
src/components/Cards/UserReviewsCard/ReviewerProfile/ReviewerProfile.js 파일 보기

@@ -8,17 +8,26 @@ import {
ProfileImageContainer,
ProfileName,
} from "./ReviewerProfile.styled";
import history from "../../../../store/utils/history";
import { replaceInRoute } from "../../../../util/helpers/routeHelpers";
import { PROFILE_PAGE } from "../../../../constants/pages";

const ReviewerProfile = (props) => {
const { isMobile } = useIsMobile();
const routeToUser = () => {
history.push(replaceInRoute(PROFILE_PAGE, {
idProfile: props.userId
}))
}
return (
<ProfileContainer>
<ProfileImageContainer>
<ProfileImage
onClick={routeToUser}
src={getImageUrl(props.profileImage, variants.reviewCard, isMobile)}
/>
</ProfileImageContainer>
<ProfileName>{props.profileName}</ProfileName>
<ProfileName onClick={routeToUser}>{props.profileName}</ProfileName>
</ProfileContainer>
);
};
@@ -26,6 +35,7 @@ const ReviewerProfile = (props) => {
ReviewerProfile.propTypes = {
profileName: PropTypes.string,
profileImage: PropTypes.string,
userId: PropTypes.string,
};

export default ReviewerProfile;

+ 5
- 1
src/components/Cards/UserReviewsCard/ReviewerProfile/ReviewerProfile.styled.js 파일 보기

@@ -6,6 +6,7 @@ export const ProfileImage = styled.img`
width: 54px;
height: 54px;
border-radius: 100%;
cursor: pointer;
`
export const ProfileImageContainer = styled(Box)`
width: 54px;
@@ -16,10 +17,13 @@ export const ProfileImageContainer = styled(Box)`
export const ProfileName = styled(Typography)`
font-weight: 600;
font-size: 16px;
position: relative;
top: 12px;
cursor: pointer;
font-family: ${selectedTheme.fonts.textFont};
color: ${selectedTheme.colors.primaryPurple};
`
export const ProfileContainer = styled(ListItem)`
align-items: flex-start;
margin-top: 2px;
padding: 0;
`

+ 6
- 2
src/components/Cards/UserReviewsCard/UserReviewsCard.js 파일 보기

@@ -8,7 +8,6 @@ import ReviewQuote from "./ReviewQuote/ReviewQuote";
import ReviewDetails from "./ReviewDetails/ReviewDetails";

const UserReviewsCard = (props) => {

const review = useMemo(() => {
if (props.givingReview) {
return {
@@ -35,6 +34,7 @@ const UserReviewsCard = (props) => {
return {
name: props.review.userWhoGaveReview.name,
image: props.review.userWhoGaveReview.image,
userId: props.review.userId,
isGoodCommunication,
isSuccessfulSwap,
quote: props?.review?.message,
@@ -45,7 +45,11 @@ const UserReviewsCard = (props) => {

return (
<ReviewContainer key={review?.image}>
<ReviewerProfile profileName={review.name} profileImage={review.image} />
<ReviewerProfile
profileName={review.name}
profileImage={review.image}
userId={review.userId}
/>
<ReviewQuote
isSuccessfulSwap={review?.isSuccessfulSwap}
quote={review?.quote}

+ 12
- 2
src/components/Cards/UserReviewsCard/UserReviewsCard.styled.js 파일 보기

@@ -7,7 +7,7 @@ export const ReviewsBox = styled(Box)`
width: 100%;
height: calc(100% - 90px);
max-height: 100vh;
padding-bottom: 20px;
padding-top: 20px;
@media (max-width: 1200px) {
padding: 0;
}
@@ -75,5 +75,15 @@ export const NoReviewsAltText = styled(Typography)`
`;

export const ReviewContainer = styled(Box)`
padding-bottom: 20px;
padding-top: 18px;
&::after {
content: "";
display: block;
border-bottom: 1px solid ${selectedTheme.colors.primaryIconBackgroundColor};
width: calc(100% + 24.4px);
height: 1px;
position: relative;
left: -18px;
margin-top: 18px;
}
`;

+ 0
- 2
src/components/ChatColumn/ChatColumn.js 파일 보기

@@ -5,7 +5,6 @@ import {
HeaderBack,
HeaderSelect,
ListContainer,
ListHeader,
SelectOption,
TitleSortContainer,
} from "./ChatColumn.styled";
@@ -102,7 +101,6 @@ export const ChatColumn = () => {
})}
</HeaderSelect>
</TitleSortContainer>
<ListHeader enableSort={true} />
<ListContainer>
{chats.map((item, index) => (
<ChatCard key={index} chat={item} />

+ 1
- 1
src/components/ChatColumn/ChatColumn.styled.js 파일 보기

@@ -16,7 +16,7 @@ export const ListContainer = styled(Box)`
gap: 12px;
@media (max-width: 600px) {
gap: 18px;
margin-top: 20px;
margin-top: 10px;
}
`;


+ 10
- 0
src/components/DirectChat/DirectChatContent/DirectChatContentHeader/DirectChatContentHeader.styled.js 파일 보기

@@ -60,6 +60,12 @@ export const PhoneIcon = styled(Phone)`
position: relative;
top: 2.5px;
left: 1.5px;
@media (max-width: 600px) {
width: 14px;
height: 14px;
top: -2px;
left: -2px;
}
`
export const PhoneIconContainer = styled(IconButton)`
background-color: white;
@@ -74,4 +80,8 @@ export const PhoneIconContainer = styled(IconButton)`
background-color: ${selectedTheme.colors.primaryIconBackgroundColor};
cursor: pointer;
}
@media (max-width: 600px) {
width: 32px;
height: 32px;
}
`

+ 1
- 1
src/components/DirectChat/DirectChatNewMessage/DirectChatNewMessage.js 파일 보기

@@ -45,7 +45,7 @@ const DirectChatNewMessage = (props) => {
})
);
if (props.chat?.chat?._id) {
if (!exchange.valid && props.chat?.offer?.offer?.userId === userId) {
if (!exchange.valid && exchange.seller.userId === userId) {
dispatch(validateExchange(exchange._id));
}
}

+ 27
- 16
src/components/MarketPlace/Header/Header.js 파일 보기

@@ -1,6 +1,7 @@
import React, { useMemo } from "react";
import PropTypes from "prop-types";
import {
ButtonContainer,
CategoryHeaderIcon,
HeaderAltLocation,
HeaderButton,
@@ -9,10 +10,12 @@ import {
HeaderLocation,
HeaderOptions,
HeaderSelect,
HeaderText,
IconStyled,
MySwapsTitle,
RefreshIcon,
PageTitleContainer,
SelectOption,
SwapsIcon,
SwapsTitle,
} from "./Header.styled";
import { ReactComponent as GridSquare } from "../../../assets/images/svg/offer-grid-square.svg";
import { ReactComponent as GridLine } from "../../../assets/images/svg/offer-grid-line.svg";
@@ -24,6 +27,9 @@ import { Tooltip } from "@mui/material";
import SkeletonHeader from "./SkeletonHeader/SkeletonHeader";
import { useSelector } from "react-redux";
import { selectHeaderString } from "../../../store/selectors/filtersSelectors";
import useIsMobile from "../../../hooks/useIsMobile";
import { ArrowButton } from "../../Buttons/ArrowButton/ArrowButton";
import history from "../../../store/utils/history";

const DownArrow = (props) => (
<IconStyled {...props}>
@@ -35,6 +41,7 @@ const Header = (props) => {
const { t } = useTranslation();
const sorting = props.sorting;
const headerString = useSelector(selectHeaderString);
const { isMobile } = useIsMobile();
// Changing header string on refresh or on load

const showAltString = useMemo(() => {
@@ -46,21 +53,15 @@ const Header = (props) => {
}, [sorting.selectedSortOption]);

const handleChangeSelect = (event) => {
// let chosenOption;
sorting.changeSorting(event.target.value);
// for (const sortOption in sortEnum) {
// if (sortEnum[sortOption].value === event.target.value) {
// chosenOption = sortEnum[sortOption];
// sorting.changeSorting(chosenOption);
// }
// }
};
const goBack = () => {
history.goBack();
};

return (
<>
<SkeletonHeader
skeleton={props.skeleton}
/>
<SkeletonHeader skeleton={props.skeleton} />
<HeaderContainer skeleton={props.skeleton}>
{/* Setting appropriate header title if page is market place or my offers */}
<Tooltip title={headerString}>
@@ -76,9 +77,10 @@ const Header = (props) => {
)}
</>
) : (
<MySwapsTitle>
<RefreshIcon /> {t("header.myOffers")}
</MySwapsTitle>
<ButtonContainer onClick={goBack}>
<ArrowButton side={"left"}></ArrowButton>
<HeaderText>{t("profile.backToHome")}</HeaderText>
</ButtonContainer>
)}
</>
</Tooltip>
@@ -122,9 +124,10 @@ const Header = (props) => {
}
IconComponent={DownArrow}
onChange={handleChangeSelect}
myOffers={props.myOffers}
>
<SelectOption style={{ display: "none" }} value="default">
Sortiraj po
{t("reviews.sortBy")}
</SelectOption>
{Object.keys(sortEnum).map((property) => {
if (sortEnum[property].value === 0) return;
@@ -141,6 +144,14 @@ const Header = (props) => {
{/* ^^^^^^ */}
</HeaderOptions>
</HeaderContainer>
{isMobile && (
<PageTitleContainer>
<SwapsIcon />
<SwapsTitle>
{props.myOffers ? t("header.myOffers") : t("offer.offers")}
</SwapsTitle>
</PageTitleContainer>
)}
</>
);
};

+ 49
- 4
src/components/MarketPlace/Header/Header.styled.js 파일 보기

@@ -1,4 +1,4 @@
import { Box, MenuItem, Typography } from "@mui/material";
import { Box, Link, MenuItem, Typography } from "@mui/material";
import styled from "styled-components";
import selectedTheme from "../../../themes";
import { IconButton } from "../../Buttons/IconButton/IconButton";
@@ -9,7 +9,7 @@ import { ReactComponent as CategoryHeader } from "../../../assets/images/svg/cat

export const HeaderContainer = styled(Box)`
margin-top: 20px;
display: ${props => props.skeleton ? "none" : "flex"};
display: ${(props) => (props.skeleton ? "none" : "flex")};
justify-content: space-between;
align-items: center;
`;
@@ -32,7 +32,7 @@ export const HeaderLocation = styled(Box)`
}
}
@media (max-width: 600px) {
font-size: 14px;
font-size: 12px;
padding-top: 3px;
}
`;
@@ -65,6 +65,8 @@ export const HeaderSelect = styled(Select)`
width: 144px;
height: 30px;
font-size: 14px;
top: 60px;
left: ${props => props.myOffers ? "-7px" : "0"};
}
`;
export const SelectItem = styled(MenuItem)`
@@ -115,4 +117,47 @@ export const MySwapsTitle = styled(Typography)`
left: 9px;
`;
export const CategoryHeaderIcon = styled(CategoryHeader)`
`
@media (max-width: 600px) {
width: 12px;
height: 12px;
position: relative;
top: 1px;
}
`;
export const PageTitleContainer = styled(Box)`
position: relative;
left: 6px;
margin-top: 36px;
width: 100px;
`;
export const SwapsIcon = styled(RefreshIcon)`
width: 12px;
height: 12px;
top: 1px;
`;
export const SwapsTitle = styled(Typography)`
font-family: ${selectedTheme.fonts.textFont};
font-size: 12px;
line-height: 16px;
color: ${selectedTheme.colors.primaryText};
`;
export const ButtonContainer = styled(Link)`
width: fit-content;
cursor: pointer;
display: flex;
justify-content: start;
align-items: center;
gap: 12px;
text-decoration: none;
min-width: 200px;
`;
export const HeaderText = styled(Typography)`
font-family: ${selectedTheme.fonts.textFont};
line-height: 22px;
font-size: 16px;
color: ${selectedTheme.colors.primaryPurple};
border-bottom: 1px dotted ${selectedTheme.colors.primaryPurple};
@media (max-width: 600px) {
font-size: 14px;
}
`;

+ 2
- 0
src/components/MarketPlace/MarketPlace.styled.js 파일 보기

@@ -6,5 +6,7 @@ export const MarketPlaceContainer = styled(Box)`
margin: 0 70px;
@media (max-width: 550px) {
margin: -30px 1.8rem;
margin-left: 18px;
margin-right: 18px;
}
`;

+ 9
- 3
src/components/MarketPlace/Offers/HeaderMyOffers.js/HeadersMyOffers.styled.js 파일 보기

@@ -9,7 +9,7 @@ export const HeadersMyOffersContainer = styled(Box)``;
export const EndIcon = styled(Icon)``;
export const SearchIcon = styled(Search)`
position: relative;
top: 11px;
top: 10px;
left: 4px;
cursor: pointer;
color: ${selectedTheme.colors.primaryPurple};
@@ -25,11 +25,17 @@ export const SearchIcon = styled(Search)`
`;
export const SearchInput = styled(TextField)`
& div {
height: 40px;
height: 46px;
background-color: white;
}
& div div input::placeholder {
font-style: italic;
font-size: 14px;
position: relative;
top: -2px;
}
@media (max-width: 600px) {
width: 90%;
width: 100%;
height: 36px;
}
`;

+ 8
- 11
src/components/MarketPlace/Offers/Offers.js 파일 보기

@@ -28,15 +28,15 @@ const Offers = (props) => {

return (
<>
<FilterContainer
onClick={toggleFilters}
number={offers.filters.numOfFiltersChosen}
myOffers={props.myOffers}
>
<FilterIcon />
</FilterContainer>
{!props.skeleton ? (
<>
<FilterContainer
onClick={toggleFilters}
number={offers.filters.numOfFiltersChosen}
myOffers={props.myOffers}
>
<FilterIcon />
</FilterContainer>
{props.myOffers && (
<HeadersMyOffers
searchMyOffers={offers.search.searchOffers}
@@ -70,10 +70,7 @@ const Offers = (props) => {
) : (
<>
{arrayForMapping.map((item, index) => (
<SkeletonOfferCard
key={index}
skeleton
/>
<SkeletonOfferCard key={index} skeleton />
))}
</>
)}

+ 2
- 2
src/components/MarketPlace/Offers/Offers.styled.js 파일 보기

@@ -16,8 +16,8 @@ export const OffersContainer = styled(Box)`
`;
export const FilterContainer = styled(IconWithNumber)`
position: absolute;
top: ${props => props.myOffers ? "143px" : "93px"};
right: 18px;
top: 93px;
right: 24px;
cursor: pointer;
background-color: ${selectedTheme.colors.primaryBackgroundColor} !important;
& div {

+ 3
- 6
src/components/Profile/Profile.js 파일 보기

@@ -14,7 +14,7 @@ const Profile = () => {
const userId = useSelector(selectUserId);
const dispatch = useDispatch();
const routeMatch = useRouteMatch();
const idProfile = routeMatch.params.idProfile;
const idProfile = useMemo(() => routeMatch.params.idProfile, [routeMatch]);
useEffect(() => {
if (idProfile?.length > 0) {
dispatch(fetchProfile(idProfile));
@@ -22,11 +22,8 @@ const Profile = () => {
}
}, [idProfile]);
const isMyProfile = useMemo(() => {
if (userId === idProfile) {
return true;
}
return false;
}, [userId, idProfile]);
return userId === routeMatch.params.idProfile;
}, [userId, routeMatch]);
return (
<ProfileContainer>
<Header />

+ 2
- 0
src/components/Profile/ProfileOffers/ProfileOffers.styled.js 파일 보기

@@ -20,9 +20,11 @@ export const OffersContainer = styled(Box)`
`;
export const OffersScroller = styled(HorizontalScroller)`
height: 373px;
width: 100%;
margin-left: 0;
& div {
margin-left: 0;
margin-right: 0;
gap: 18px;
}
`;

+ 58
- 0
src/components/UserReviews/ReviewsSorting/ReviewsSorting.js 파일 보기

@@ -0,0 +1,58 @@
import React from "react";
import PropTypes from "prop-types";
import {
DownArrowIcon,
HeaderSelect,
SelectOption,
} from "./ReviewsSorting.styled";
import { useState } from "react";
import { useDispatch, useSelector } from "react-redux";
import { selectSelectedReviews } from "../../../store/selectors/reviewSelector";
import { sortReviews } from "../../../util/helpers/reviewsHelper";
import { reviewSortEnum } from "../../../enums/reviewEnum";
import { setReviews } from "../../../store/actions/review/reviewActions";

const ReviewsSorting = () => {
const reviews = useSelector(selectSelectedReviews);
const dispatch = useDispatch();
const [value, setValue] = useState();
const changeValue = (event) => {
dispatch(
setReviews(
sortReviews(
reviews,
event.target.value.value === reviewSortEnum.POSITIVE.value
)
)
);
setValue(event.target.value);
};
return (
<HeaderSelect
value={value || reviewSortEnum.INITIAL}
IconComponent={DownArrowIcon}
onChange={changeValue}
>
<SelectOption style={{ display: "none" }} value={reviewSortEnum.INITIAL}>
{reviewSortEnum.INITIAL.mainText}
</SelectOption>
{Object.keys(reviewSortEnum).map((property) => {
if (reviewSortEnum[property].value === 0) return;
return (
<SelectOption
value={reviewSortEnum[property]}
key={reviewSortEnum[property].value}
>
{reviewSortEnum[property].mainText}
</SelectOption>
);
})}
</HeaderSelect>
);
};

ReviewsSorting.propTypes = {
children: PropTypes.node,
};

export default ReviewsSorting;

+ 35
- 0
src/components/UserReviews/ReviewsSorting/ReviewsSorting.styled.js 파일 보기

@@ -0,0 +1,35 @@
import styled from "styled-components";
import selectedTheme from "../../../themes";
import Option from "../../Select/Option/Option";
import Select from "../../Select/Select";
import { ReactComponent as DownArrow } from "../../../assets/images/svg/down-arrow.svg";

export const HeaderSelect = styled(Select)`
width: 133px;
height: 35px;
font-family: ${selectedTheme.fonts.textFont};
margin-top: 3px;
font-weight: 400;
position: relative;
left: -5px;
background-color: white;
& div:first-child {
padding-right: 0 !important;
padding-left: 8px;
}

@media (max-width: 650px) {
width: 144px;
height: 30px;
font-size: 14px;
}
`;
export const SelectOption = styled(Option)`
@media (max-width: 600px) {
height: 36px !important;
min-height: 35px;
margin: 4px;
font-size: 14px;
}
`;
export const DownArrowIcon = styled(DownArrow)``;

+ 22
- 17
src/components/UserReviews/UserReviews.js 파일 보기

@@ -5,11 +5,6 @@ import {
ReviewsBox,
ReviewsHeader,
ReviewsHeaderTitle,
ReviewSortContainer,
ReviewSortDescription,
ReviewSortIcon,
ReviewSortOption,
ReviewSortOptionContainer,
ReviewsTitle,
} from "./UserReviews.styled";

@@ -21,11 +16,16 @@ import { useDispatch, useSelector } from "react-redux";
import { selectOffer } from "../../store/selectors/offersSelectors";
import { selectSelectedReviews } from "../../store/selectors/reviewSelector";
import { useRouteMatch } from "react-router-dom";
import { fetchReviews } from "../../store/actions/review/reviewActions";
import {
fetchReviews,
setReviews,
} from "../../store/actions/review/reviewActions";
import { selectIsLoadingByActionType } from "../../store/selectors/loadingSelectors";
import SkeletonUserReviews from "./SkeletonUserReviews/SkeletonUserReviews";
import { ONE_OFFER_SCOPE } from "../../store/actions/offers/offersActionConstants";
import { REVIEW_GET_SCOPE } from "../../store/actions/review/reviewActionConstants";
import ReviewsSorting from "./ReviewsSorting/ReviewsSorting";
import { sortReviews } from "../../util/helpers/reviewsHelper";

const UserReviews = (props) => {
const { t } = useTranslation();
@@ -35,7 +35,9 @@ const UserReviews = (props) => {
const dispatch = useDispatch();

const isLoadingReview = useSelector(
selectIsLoadingByActionType(props.isProfileReviews ? REVIEW_GET_SCOPE : ONE_OFFER_SCOPE)
selectIsLoadingByActionType(
props.isProfileReviews ? REVIEW_GET_SCOPE : ONE_OFFER_SCOPE
)
);

useEffect(() => {
@@ -52,14 +54,23 @@ const UserReviews = (props) => {
return [...reviews];
}
if (offer?.companyData?.lastThreeReviews) {
return [...offer?.companyData.lastThreeReviews];
// Making array of reviews in same order(sorting) so when comparing
// them, I can make valid condition
if (
JSON.stringify(sortReviews(reviews)) !==
JSON.stringify(sortReviews(offer?.companyData?.lastThreeReviews))
) {
dispatch(setReviews([...offer?.companyData.lastThreeReviews]));
}
return [...reviews];
}
return [];
}, [props.profileReviews, offer, props.isProfileReviews, reviews]);

return (
<>
{isLoadingReview || isLoadingReview === undefined ? (
{!props.givingReview &&
(isLoadingReview || isLoadingReview === undefined) ? (
<SkeletonUserReviews />
) : (
<ReviewsBox
@@ -82,16 +93,10 @@ const UserReviews = (props) => {
/>
<ReviewsTitle>{t("reviews.rates")}</ReviewsTitle>
</ReviewsHeaderTitle>
<ReviewSortContainer>
<ReviewSortDescription>Sortiraj po: </ReviewSortDescription>
<ReviewSortOptionContainer>
<ReviewSortOption>Pozitivne</ReviewSortOption>
<ReviewSortIcon />
</ReviewSortOptionContainer>
</ReviewSortContainer>
<ReviewsSorting />
</ReviewsHeader>
)}
<ReviewList>
<ReviewList isProfileReviews={props.isProfileReviews}>
{lastThreeReviews?.length > 0 ? (
lastThreeReviews?.map((review, index) => (
<UserReviewsCard

+ 3
- 2
src/components/UserReviews/UserReviews.styled.js 파일 보기

@@ -51,13 +51,14 @@ export const ReviewsTitle = styled(Typography)`

export const ReviewList = styled(List)`
background: white;
padding: 2rem;
padding-top: 6px;
padding: 0 18px;
border-radius: 4px 0 0 4px;
padding-right: 0.4rem;
height: 100%;
width: 100%;
border: 1px solid ${selectedTheme.colors.borderNormal};
overflow-y: auto;
max-height: ${(props) => (props.isProfileReviews ? "70vh" : "43vh")};

/* overflow-y: auto; */
&::-webkit-scrollbar {

+ 34
- 15
src/enums/reviewEnum.js 파일 보기

@@ -1,20 +1,39 @@
export const reviewEnum = {
YES: {
YES: {
value: 1,
mainText: "Da",
// Unsuccessful swap
backendText: "succeeded",
// Not good communication
backendTextSecond: "yes",
},
NO: {
value: 2,
mainText: "Ne",
// Unsuccessful swap
backendText: "failed",
// Not good communication
backendTextSecond: "no",
},
NOT_BAD: {
value: 3,
mainText: "Može bolje",
backendText: "could be better",
},
};

export const reviewSortEnum = {
INITIAL: {
value: 0,
mainText: "Sortiraj po",
queryString: ""
},
POSITIVE: {
value: 1,
mainText: "Da",
backendText: "succeeded"
mainText: "Pozitivne",
},
NO: {
NEGATIVE: {
value: 2,
mainText: "Ne",
// Unsuccessful swap
backendText: "failed",
// Not good communication
backendTextSecond: "no"
mainText: "Negativne",
},
NOT_BAD: {
value: 3,
mainText: "Može bolje",
backendText: "could be better"
}
}
}

+ 3
- 1
src/i18n/resources/rs.js 파일 보기

@@ -173,6 +173,7 @@ export default {
product: "Proizvod",
descriptionLabel: "Opis:",
checkButtonLabel: "Pogledaj proizvod",
offers: "Objave"
},
apiErrors: {
somethingWentWrong: "Greška sa serverom!",
@@ -207,6 +208,7 @@ export default {
rates: "Ocene kompanije",
finishedReviewTitle: "Hvala vam",
finishedReviewAltTitle: "na izdvojenom vremenu i datoj oceni!",
sortBy: "Sortiraj po",
},
messages: {
headerTitle: "Moje Ćaskanje",
@@ -217,7 +219,7 @@ export default {
seeChats: "Pogledaj ćaskanje",
noMessagesToast: "Nemate ni jednu poruku!",
notAllowedChat: "Trampa za ovaj proizvod je završena.",
goBack: "Nazad na sve poruke"
goBack: "Nazad na sve poruke",
},
editProfile: {
website: "Web Sajt*",

+ 1
- 1
src/layouts/ItemDetailsLayout/ItemDetailsLayout.styled.js 파일 보기

@@ -16,7 +16,7 @@ export const ItemDetailsLayoutContainer = styled(Container)`
}
@media (max-width: 600px) {
padding-left: 18px;
padding-right: ${(props) => (props.profile ? 0 : "18px")};
padding-right: 18px;
}
`;


+ 2
- 1
src/store/saga/offersSaga.js 파일 보기

@@ -152,7 +152,8 @@ function* fetchMoreOffers(payload) {

function* createOffer(payload) {
try {
const offerData = payload.payload.values.offerData;
console.log(payload);
const offerData = payload.payload.offerData;
const formData = new FormData();
formData.append("category[name]", offerData.category.name);
formData.append("condition", offerData.condition);

+ 53
- 0
src/util/helpers/reviewsHelper.js 파일 보기

@@ -0,0 +1,53 @@
import { reviewEnum } from "../../enums/reviewEnum";

export const sortReviews = (reviews, positive = false) => {
let newReviews;
if (positive) {
newReviews = [
...reviews.filter(
(review) =>
review.succeeded === reviewEnum.YES.backendText &&
review.communication === reviewEnum.YES.backendTextSecond
),
...reviews.filter(
(review) =>
review.succeeded === reviewEnum.YES.backendText &&
review.communication === reviewEnum.NOT_BAD.backendText
),
...reviews.filter(
(review) =>
review.succeeded === reviewEnum.YES.backendText &&
review.communication === reviewEnum.NO.backendTextSecond
),
...reviews.filter(
(review) => review.succeeded === reviewEnum.NO.backendText
),
];
} else {
newReviews = [
...reviews.filter(
// 4
(review) => review.succeeded === reviewEnum.NO.backendText
),
...reviews.filter(
// 3
(review) =>
review.succeeded === reviewEnum.YES.backendText &&
review.communication === reviewEnum.NO.backendTextSecond
),
...reviews.filter(
// 2
(review) =>
review.succeeded === reviewEnum.YES.backendText &&
review.communication === reviewEnum.NOT_BAD.backendText
),
...reviews.filter(
// prvo
(review) =>
review.succeeded === reviewEnum.YES.backendText &&
review.communication === reviewEnum.YES.backendTextSecond
),
];
}
return newReviews;
};

Loading…
취소
저장