Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions src/components/common/Header.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@ import { Link } from 'react-router-dom';

import styled from '@emotion/styled';

import Responsive from '../../styles/Responsive';
import palette from '../../styles/palette';
import Button from '../../styles/Button';
import palette from '../../styles/palette';
import Responsive from '../../styles/Responsive';

import { LOGOUT, LOGIN, REGISTER } from '../../util/constants/constants';

const HeaderWrapper = styled.div`
Expand Down
93 changes: 93 additions & 0 deletions src/components/introduce/AverageReview.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import React from 'react';

import StarRatings from 'react-star-ratings';

import styled from '@emotion/styled';

import palette from '../../styles/palette';

const AverageReviewWrapper = styled.div`
display: flex;
flex-direction: column;
align-items: center;
padding: 1.5rem 0 1rem 0;
border: 1px solid ${palette.gray[3]};
border-radius: 5px;
`;

const AverageReviewTitle = styled.div`
line-height: 40px;
color: ${palette.gray[7]};
font-size: 1.6rem;
font-weight: bold;

span {
font-size: 1.8rem;
color: ${palette.teal[5]};
}
`;

const AverageRatingWrapper = styled.div`
line-height: 50px;

em {
margin-left: .5rem;
}

.average-rating {
font-size: 2rem;
font-weight: bold;
color: ${palette.gray[7]};
}

.total-rating {
font-size: 1.5rem;
font-weight: bold;
color: ${palette.gray[5]};
}
`;

const averageReviews = (reviews) => (reviews
.reduce((acc, { rating }) => acc + rating, 0) / reviews.length).toFixed(1) * 2;

const convertToRating = (rating) => {
if (Number.isInteger(rating)) {
return `${rating}.0`;
}

return rating;
};

const AverageReview = ({ reviews }) => {
const averageRating = averageReviews(reviews);

return (
<AverageReviewWrapper>
<AverageReviewTitle>
스터디를 참여한&nbsp;
<span>
{reviews.length}
</span>
명의 회원 평균평점
</AverageReviewTitle>
<AverageRatingWrapper>
<StarRatings
rating={averageRating / 2}
starRatedColor="#ffc816"
numberOfStars={5}
starDimension="40px"
starSpacing="0"
name="rating"
/>
<em className="average-rating">
{convertToRating(averageRating)}
</em>
<em className="total-rating">
/ 10.0
</em>
</AverageRatingWrapper>
</AverageReviewWrapper>
);
};

export default AverageReview;
40 changes: 40 additions & 0 deletions src/components/introduce/AverageReview.test.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import React from 'react';

import { render } from '@testing-library/react';

import AverageReview from './AverageReview';

describe('AverageReview', () => {
const renderAverageReview = (reviews) => render((
<AverageReview
reviews={reviews}
/>
));

context('When the average rating is integer', () => {
const reviews = [
{ rating: 3 },
{ rating: 3 },
];
it('Renders average reviews contents', () => {
const { container } = renderAverageReview(reviews);

expect(container).toHaveTextContent(`스터디를 참여한 ${reviews.length}명의 회원 평균평점`);
expect(container).toHaveTextContent(6.0);
});
});

context("When the average rating isn't integer", () => {
const reviews = [
{ rating: 3 },
{ rating: 4 },
{ rating: 4 },
];
it('Renders average reviews contents', () => {
const { container } = renderAverageReview(reviews);

expect(container).toHaveTextContent(`스터디를 참여한 ${reviews.length}명의 회원 평균평점`);
expect(container).toHaveTextContent(7.4);
});
});
});
27 changes: 10 additions & 17 deletions src/components/introduce/IntroduceForm.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,10 @@ import styled from '@emotion/styled';
import { INTRODUCE_FORM_TITLE } from '../../util/constants/constants';
import { authorizedUsersNumber, changeDateToTime } from '../../util/utils';

import Tags from '../common/Tags';
import palette from '../../styles/palette';
import SubTitle from '../../styles/SubTitle';

import Tags from '../common/Tags';
import DateTimeChange from '../common/DateTimeChange';
import IntroduceActionButtons from './IntroduceActionButtons';

Expand All @@ -20,6 +22,10 @@ const mq = facepaint([
'@media(min-width: 1150px)',
]);

const IntroduceFormWrapper = styled.div`
margin-bottom: 3rem;
`;

const IntroduceReferenceWrapper = styled.div`

${mq({
Expand Down Expand Up @@ -69,17 +75,6 @@ ${mq({
border-right: 0.1rem solid ${palette.gray[3]};
`;

const IntroduceContentTitle = styled.div`
font-size: 1.4rem;
font-weight: bold;
text-align: center;
margin-bottom: 0;
margin-top: 1rem;
padding: 7px 2rem 7px 2rem;
border-bottom: 2px solid ${palette.violet[3]};
width: 17%;
`;

const IntroduceContent = styled.div`
position: relative;
margin-top: 2rem;
Expand All @@ -104,7 +99,7 @@ const IntroduceForm = ({
const isCheckOwnGroupPost = user && (user === moderatorId);

return (
<>
<IntroduceFormWrapper>
<ModeratorWrapper>
<div>
{`🙋‍♂️${moderatorId}`}
Expand All @@ -128,9 +123,7 @@ const IntroduceForm = ({
page="introduce"
/>
</IntroduceReferenceWrapper>
<IntroduceContentTitle>
{INTRODUCE}
</IntroduceContentTitle>
<SubTitle title={INTRODUCE} />
<IntroduceContent dangerouslySetInnerHTML={{ __html: contents }} />
<IntroduceFooter>
<Tags tags={tags} />
Expand All @@ -141,7 +134,7 @@ const IntroduceForm = ({
/>
)}
</IntroduceFooter>
</>
</IntroduceFormWrapper>
);
};

Expand Down
57 changes: 49 additions & 8 deletions src/components/introduce/Review.jsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,36 @@
import React from 'react';

import Moment from 'react-moment';

import StarRatings from 'react-star-ratings';

import styled from '@emotion/styled';

import palette from '../../styles/palette';

import { changeDateToTime } from '../../util/utils';

const ReviewWrapper = styled.div`
background-color: #f8f8f8;
display: flex;
flex-direction: column;
margin: 1rem 0 1rem 0;
padding: 20px 35px 20px 35px;
border: 1px solid ${palette.gray[3]};
border-radius: 5px;
`;

const ReviewContent = styled.div`
font-size: 1.1rem;
color: ${palette.gray[8]};
margin: .7rem 0 .8rem 0;
`;

const ReviewContentInfo = styled.div`
font-size: 0.9rem;
color: ${palette.gray[5]};
display: flex;
justify-content: space-between;
`;

const Review = ({ review }) => {
Expand All @@ -13,15 +40,29 @@ const Review = ({ review }) => {

return (
<ReviewWrapper>
<div>
{rating}
</div>
<div>
<StarRatings
rating={rating}
starRatedColor="#ffc816"
numberOfStars={5}
starDimension="20px"
starSpacing="0"
starHoverColor="#ffc816"
name="rating"
/>
<ReviewContent>
{content}
</div>
<div>
{`${id} | ${createDate}`}
</div>
</ReviewContent>
<ReviewContentInfo>
<div>
{id}
</div>
<Moment
interval={0}
format="YYYY-MM-DD"
>
{changeDateToTime(createDate)}
</Moment>
</ReviewContentInfo>
</ReviewWrapper>
);
};
Expand Down
1 change: 0 additions & 1 deletion src/components/introduce/Review.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ describe('Review', () => {
const { container } = renderReview(mockReview);

expect(container).toHaveTextContent('review');
expect(container).toHaveTextContent(3);
expect(container).toHaveTextContent('test@test.com');
});
});
2 changes: 1 addition & 1 deletion src/components/introduce/ReviewForm.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ const mq = facepaint([
const StudyReviewFormWrapper = styled.div`
display: flex;
flex-direction: column;
margin: 3rem 0 3rem 0;
margin: 2rem 0 3rem 0;
padding: 20px 20px 20px 20px;
border: 1px solid ${palette.gray[3]};
border-radius: 5px;
Expand Down
34 changes: 31 additions & 3 deletions src/components/introduce/ReviewList.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,52 @@ import React from 'react';

import _ from 'lodash';

import styled from '@emotion/styled';

import palette from '../../styles/palette';

import Review from './Review';
import AverageReview from './AverageReview';

const ReviewWrapper = styled.div`
margin: 2rem 0 3rem 0;
`;

const EmptyReviewWrapper = styled.div`
background-color: #f8f8f8;
font-size: 1.1rem;
font-weight: bold;
color: ${palette.gray[6]};
display: flex;
align-items: center;
flex-direction: column;
margin: 2rem 0 3rem 0;
padding: 45px;
border: 1px solid ${palette.gray[3]};
border-radius: 5px;
`;

const ReviewList = ({ reviews }) => {
if (_.isEmpty(reviews)) {
return (
<div>아직 리뷰가 존재하지 않습니다!</div>
<EmptyReviewWrapper>
등록된 리뷰가 존재하지 않습니다!
</EmptyReviewWrapper>
);
}

return (
<>
<ReviewWrapper>
<AverageReview
reviews={reviews}
/>
{reviews.map((review) => (
<Review
key={review.id}
review={review}
/>
))}
</>
</ReviewWrapper>
);
};

Expand Down
5 changes: 3 additions & 2 deletions src/components/introduce/ReviewList.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,17 +22,18 @@ describe('ReviewList', () => {
it('Render reviews', () => {
const { container } = renderReviewList(mockReviews);

expect(container).toHaveTextContent('스터디를 참여한 1명의 회원 평균평점');
expect(container).toHaveTextContent('6.0');
expect(container).toHaveTextContent('review');
expect(container).toHaveTextContent('test@test.com');
expect(container).toHaveTextContent(3);
});
});

context('Without reviews', () => {
it('Render nothing review message', () => {
const { container } = renderReviewList([]);

expect(container).toHaveTextContent('아직 리뷰가 존재하지 않습니다!');
expect(container).toHaveTextContent('등록된 리뷰가 존재하지 않습니다!');
});
});
});
Loading