Djordje Mitrovic 3 anni fa
parent
commit
0c548a3fb8

+ 11
- 3
src/components/Cards/ProfileCard/ProfileCard.js Vedi File

@@ -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,22 @@ const ProfileCard = () => {
return companyData;
}, [profileFromRedux]);


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

useEffect(() => {
console.log(userId === idProfile);
console.log(idProfile);
if (userId === idProfile) setIsMyProfile(true);
else setIsMyProfile(false);
}, [userId, idProfile]);

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

let percentOfSucceededExchanges;

+ 1
- 1
src/components/Cards/UserReviewsCard/ReviewDetails/ReviewDetails.js Vedi File

@@ -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 Vedi File

@@ -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 Vedi File

@@ -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 Vedi File

@@ -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 Vedi File

@@ -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 Vedi File

@@ -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 Vedi File

@@ -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 Vedi File

@@ -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 Vedi File

@@ -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;
}
`;

+ 1
- 1
src/components/DirectChat/DirectChatNewMessage/DirectChatNewMessage.js Vedi File

@@ -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));
}
}

+ 1
- 1
src/components/MarketPlace/Header/Header.js Vedi File

@@ -124,7 +124,7 @@ const Header = (props) => {
onChange={handleChangeSelect}
>
<SelectOption style={{ display: "none" }} value="default">
Sortiraj po
{t("reviews.sortBy")}
</SelectOption>
{Object.keys(sortEnum).map((property) => {
if (sortEnum[property].value === 0) return;

+ 6
- 3
src/components/Profile/Profile.js Vedi File

@@ -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,14 @@ const Profile = () => {
}
}, [idProfile]);
const isMyProfile = useMemo(() => {
if (userId === idProfile) {
console.log(routeMatch.params.idProfile === userId);
console.log(userId);
console.log("rerender");
if (userId === routeMatch.params.idProfile) {
return true;
}
return false;
}, [userId, idProfile]);
}, [userId, routeMatch]);
return (
<ProfileContainer>
<Header />

+ 58
- 0
src/components/UserReviews/ReviewsSorting/ReviewsSorting.js Vedi File

@@ -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 Vedi File

@@ -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 Vedi File

@@ -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 Vedi File

@@ -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 Vedi File

@@ -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"
}
}
}

+ 2
- 1
src/i18n/resources/rs.js Vedi File

@@ -207,6 +207,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 +218,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*",

+ 2
- 1
src/store/saga/offersSaga.js Vedi File

@@ -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 Vedi File

@@ -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…
Annulla
Salva