{`🙋♂️${moderatorId}`}
@@ -128,9 +123,7 @@ const IntroduceForm = ({
page="introduce"
/>
-
- {INTRODUCE}
-
+
@@ -141,7 +134,7 @@ const IntroduceForm = ({
/>
)}
- >
+
);
};
diff --git a/src/components/introduce/Review.jsx b/src/components/introduce/Review.jsx
index ffdff1e..12e2e30 100644
--- a/src/components/introduce/Review.jsx
+++ b/src/components/introduce/Review.jsx
@@ -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 }) => {
@@ -13,15 +40,29 @@ const Review = ({ review }) => {
return (
-
- {rating}
-
-
+
+
{content}
-
-
- {`${id} | ${createDate}`}
-
+
+
+
+ {id}
+
+
+ {changeDateToTime(createDate)}
+
+
);
};
diff --git a/src/components/introduce/Review.test.jsx b/src/components/introduce/Review.test.jsx
index c98ea3c..93926b3 100644
--- a/src/components/introduce/Review.test.jsx
+++ b/src/components/introduce/Review.test.jsx
@@ -22,7 +22,6 @@ describe('Review', () => {
const { container } = renderReview(mockReview);
expect(container).toHaveTextContent('review');
- expect(container).toHaveTextContent(3);
expect(container).toHaveTextContent('test@test.com');
});
});
diff --git a/src/components/introduce/ReviewForm.jsx b/src/components/introduce/ReviewForm.jsx
index 76c4f57..e0f13fe 100644
--- a/src/components/introduce/ReviewForm.jsx
+++ b/src/components/introduce/ReviewForm.jsx
@@ -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;
diff --git a/src/components/introduce/ReviewList.jsx b/src/components/introduce/ReviewList.jsx
index 379405a..720baef 100644
--- a/src/components/introduce/ReviewList.jsx
+++ b/src/components/introduce/ReviewList.jsx
@@ -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 (
-
아직 리뷰가 존재하지 않습니다!
+
+ 등록된 리뷰가 존재하지 않습니다!
+
);
}
return (
- <>
+
+
{reviews.map((review) => (
))}
- >
+
);
};
diff --git a/src/components/introduce/ReviewList.test.jsx b/src/components/introduce/ReviewList.test.jsx
index 3c8ce7f..346624e 100644
--- a/src/components/introduce/ReviewList.test.jsx
+++ b/src/components/introduce/ReviewList.test.jsx
@@ -22,9 +22,10 @@ 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);
});
});
@@ -32,7 +33,7 @@ describe('ReviewList', () => {
it('Render nothing review message', () => {
const { container } = renderReviewList([]);
- expect(container).toHaveTextContent('아직 리뷰가 존재하지 않습니다!');
+ expect(container).toHaveTextContent('등록된 리뷰가 존재하지 않습니다!');
});
});
});
diff --git a/src/containers/introduce/ReviewContainer.jsx b/src/containers/introduce/ReviewContainer.jsx
index dac6b53..2d9ad34 100644
--- a/src/containers/introduce/ReviewContainer.jsx
+++ b/src/containers/introduce/ReviewContainer.jsx
@@ -8,6 +8,8 @@ import {
} from '../../util/utils';
import { changeStudyReviewFields, setStudyReview } from '../../reducers/groupSlice';
+import SubTitle from '../../styles/SubTitle';
+
import ReviewForm from '../../components/introduce/ReviewForm';
import ReviewList from '../../components/introduce/ReviewList';
@@ -37,9 +39,7 @@ const ReviewFormContainer = () => {
return null;
}
- const {
- participants, personnel, applyEndDate,
- } = group;
+ const { participants, personnel, applyEndDate } = group;
const isApplyTime = isCheckedTimeStatus({
applyEndTime: changeDateToTime(applyEndDate),
@@ -54,6 +54,7 @@ const ReviewFormContainer = () => {
return (
<>
+
{
const { container } = renderReviewContainer();
- expect(container).toHaveTextContent('아직 리뷰가 존재하지 않습니다!');
+ expect(container).toHaveTextContent('등록된 리뷰가 존재하지 않습니다!');
});
context('with login and group', () => {
diff --git a/src/reducers/groupSlice.js b/src/reducers/groupSlice.js
index 03ac9d1..934c997 100644
--- a/src/reducers/groupSlice.js
+++ b/src/reducers/groupSlice.js
@@ -137,6 +137,39 @@ const { actions, reducer } = createSlice({
studyReviewFields: studyReviewInitialState,
};
},
+
+ setGroupReview(state, { payload: review }) {
+ const { group } = state;
+
+ if (group.reviews) {
+ return {
+ ...state,
+ group: {
+ ...group,
+ reviews: [
+ {
+ ...review,
+ createDate: new Date().toString(),
+ },
+ ...group.reviews,
+ ],
+ },
+ };
+ }
+
+ return {
+ ...state,
+ group: {
+ ...group,
+ reviews: [
+ {
+ ...review,
+ createDate: new Date().toString(),
+ },
+ ],
+ },
+ };
+ },
},
});
@@ -152,6 +185,7 @@ export const {
setOriginalArticle,
changeStudyReviewFields,
clearStudyReviewFields,
+ setGroupReview,
} = actions;
export const loadStudyGroups = (tag) => async (dispatch) => {
@@ -298,6 +332,7 @@ export const setStudyReview = (review) => async (dispatch, getState) => {
review,
});
+ dispatch(setGroupReview(review));
dispatch(clearStudyReviewFields());
};
diff --git a/src/reducers/groupSlice.test.js b/src/reducers/groupSlice.test.js
index 043c8fc..4aac8b3 100644
--- a/src/reducers/groupSlice.test.js
+++ b/src/reducers/groupSlice.test.js
@@ -24,6 +24,7 @@ import reducer, {
changeStudyReviewFields,
clearStudyReviewFields,
setStudyReview,
+ setGroupReview,
} from './groupSlice';
import STUDY_GROUPS from '../../fixtures/study-groups';
@@ -268,6 +269,46 @@ describe('reducer', () => {
expect(content).toBe('');
});
});
+
+ describe('setGroupReview', () => {
+ const review = {
+ id: 'test',
+ content: 'test',
+ rating: 3,
+ };
+
+ context('When the group reviews field is exists', () => {
+ const initialState = {
+ group: {
+ reviews: [],
+ },
+ };
+
+ it('Set in the group review field', () => {
+ const state = reducer(initialState, setGroupReview(review));
+
+ const { group: { reviews } } = state;
+
+ expect(reviews[0].id).toBe('test');
+ expect(reviews[0].rating).toBe(3);
+ });
+ });
+
+ context("When the group reviews field isn't exists", () => {
+ const initialState = {
+ group: {},
+ };
+
+ it('Set in the group review field', () => {
+ const state = reducer(initialState, setGroupReview(review));
+
+ const { group: { reviews } } = state;
+
+ expect(reviews[0].id).toBe('test');
+ expect(reviews[0].rating).toBe(3);
+ });
+ });
+ });
});
describe('async actions', () => {
@@ -592,9 +633,9 @@ describe('async actions', () => {
});
});
- it('dispatches clearStudyReviewFields', async () => {
+ it('dispatches setGroupReview and clearStudyReviewFields', async () => {
await store.dispatch(setStudyReview({
- user: 'user',
+ id: 'user',
review: 'test',
rating: 5,
}));
@@ -602,6 +643,14 @@ describe('async actions', () => {
const actions = store.getActions();
expect(actions[0]).toEqual({
+ type: 'group/setGroupReview',
+ payload: {
+ rating: 5,
+ review: 'test',
+ id: 'user',
+ },
+ });
+ expect(actions[1]).toEqual({
type: 'group/clearStudyReviewFields',
});
});
diff --git a/src/styles/SubTitle.jsx b/src/styles/SubTitle.jsx
new file mode 100644
index 0000000..22e515b
--- /dev/null
+++ b/src/styles/SubTitle.jsx
@@ -0,0 +1,24 @@
+import React from 'react';
+
+import styled from '@emotion/styled';
+
+import palette from './palette';
+
+const SubTitleWrapper = 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 SubTitle = ({ title }) => (
+
+ {title}
+
+);
+
+export default SubTitle;