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
17 changes: 5 additions & 12 deletions fake-server/db.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
"contents": "우리는 이것저것 합니다.1",
"tags": [
"JavaScript",
"React",
"Algorithm"
]
},
Expand All @@ -34,8 +33,7 @@
"contents": "우리는 이것저것 합니다.2",
"tags": [
"JavaScript",
"React",
"Algorithm"
"React"
]
},
{
Expand All @@ -52,7 +50,6 @@
"contents": "우리는 이것저것 합니다.3",
"tags": [
"JavaScript",
"React",
"Algorithm"
]
},
Expand Down Expand Up @@ -97,7 +94,6 @@
"personnel": 9,
"contents": "우리는 이것저것 합니다.5",
"tags": [
"JavaScript",
"React",
"Algorithm"
]
Expand Down Expand Up @@ -137,8 +133,7 @@
"contents": "우리는 이것저것 합니다.7",
"tags": [
"JavaScript",
"React",
"Algorithm"
"React"
]
},
{
Expand Down Expand Up @@ -343,7 +338,7 @@
"tags": [
"JavaScript",
"React",
"Algorithm"
"C"
]
},
{
Expand All @@ -364,7 +359,7 @@
"tags": [
"JavaScript",
"React",
"Algorithm"
"C"
]
},
{
Expand All @@ -379,7 +374,6 @@
"contents": "우리는 이것저것 합니다.19",
"tags": [
"JavaScript",
"React",
"Algorithm"
]
},
Expand Down Expand Up @@ -416,9 +410,8 @@
"personnel": 8,
"contents": "우리는 이것저것 합니다.21",
"tags": [
"JavaScript",
"React",
"Algorithm"
"Java"
]
}
],
Expand Down
1 change: 0 additions & 1 deletion fixtures/study-groups.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ const studyGroups = [
personnel: 2,
contents: '우리는 이것저것 합니다.2',
tags: [
'JavaScript',
'React',
'Algorithm',
],
Expand Down
13 changes: 9 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
"axios": "^0.21.0",
"moment": "^2.29.1",
"moment-timezone": "^0.5.32",
"qs": "^6.9.4",
"react": "^17.0.1",
"react-dom": "^17.0.1",
"react-moment": "^1.0.0",
Expand Down
6 changes: 3 additions & 3 deletions src/components/common/Tags.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import palette from '../../styles/palette';

const TagsWrapper = styled.div`
margin-top: 1rem;
.lang {
.tag {
display: inline-flex;
align-items: center;
padding-left: .6em;
Expand Down Expand Up @@ -36,8 +36,8 @@ const Tags = ({ tags }) => {
{tags.map((tag) => (
<Link
key={tag}
to="/#"
className="lang"
to={`/?tag=${tag}`}
className="tag"
>
{`#${tag}`}
</Link>
Expand Down
5 changes: 3 additions & 2 deletions src/components/common/Tags.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,14 @@ describe('Tags', () => {
));

context('with tags', () => {
const tags = ['JavaScript', 'C', 'Python'];
it('renders tags name', () => {
const tags = ['JavaScript', 'C', 'Python'];

const { container } = renderTags(tags);

tags.forEach((tag) => {
expect(container).toHaveTextContent(tag);

expect(container.innerHTML).toContain('<a');
});
});
});
Expand Down
21 changes: 18 additions & 3 deletions src/containers/groups/StudyGroupsContainer.jsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,28 @@
import React from 'react';
import React, { useEffect } from 'react';

import { useSelector } from 'react-redux';
import { useLocation } from 'react-router-dom';
import { useSelector, useDispatch } from 'react-redux';

import qs from 'qs';

import StudyGroups from '../../components/main/StudyGroups';
import { get } from '../../../utils';
import { loadStudyGroups } from '../../reducers/slice';
import StudyGroups from '../../components/main/StudyGroups';

const StudyGroupsContainer = () => {
const { search } = useLocation();

const dispatch = useDispatch();
const groups = useSelector(get('groups'));

useEffect(() => {
const { tag } = qs.parse(search, {
ignoreQueryPrefix: true,
});

dispatch(loadStudyGroups(tag));
}, [dispatch, search]);

if (!groups || !groups.length) {
return <div>스터디가 존재하지 않습니다.</div>;
}
Expand Down
20 changes: 19 additions & 1 deletion src/containers/groups/StudyGroupsContainer.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,19 @@ import React from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { MemoryRouter } from 'react-router-dom';

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

import StudyGroupsContainer from './StudyGroupsContainer';

const mockSearch = jest.fn();

jest.mock('react-router-dom', () => ({
...jest.requireActual('react-router-dom'),
useLocation() {
return { search: mockSearch };
},
}));

describe('StudyGroupsContainer', () => {
const dispatch = jest.fn();

Expand All @@ -31,13 +40,22 @@ describe('StudyGroupsContainer', () => {
moderatorId: 'user1',
title: '소개합니다.',
participants: [],
tags: ['JavaScript'],
}]));

it('renders groups title', () => {
const { container } = renderStudyGroupsContainer();

expect(container).toHaveTextContent('소개합니다.');
});

it('click event calls dispatch', () => {
const { getByText } = renderStudyGroupsContainer();

fireEvent.click(getByText('#JavaScript'));

expect(dispatch).toBeCalled();
});
});

context('without groups', () => {
Expand Down
25 changes: 7 additions & 18 deletions src/pages/MainPage.jsx
Original file line number Diff line number Diff line change
@@ -1,30 +1,19 @@
import React, { useEffect } from 'react';

import { useDispatch } from 'react-redux';
import React from 'react';

import styled from '@emotion/styled';

import { loadStudyGroups } from '../reducers/slice';
import StudyGroupsContainer from '../containers/groups/StudyGroupsContainer';
import Responsive from '../styles/Responsive';

const MainPageWrapper = styled(Responsive)`

`;

const MainPage = () => {
const dispatch = useDispatch();

useEffect(() => {
dispatch(loadStudyGroups());
}, []);

return (
<MainPageWrapper>
<h2>지금 바로 시작하세요!</h2>
<StudyGroupsContainer />
</MainPageWrapper>
);
};
const MainPage = () => (
<MainPageWrapper>
<h2>지금 바로 시작하세요!</h2>
<StudyGroupsContainer />
</MainPageWrapper>
);

export default MainPage;
30 changes: 22 additions & 8 deletions src/pages/MainPage.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@ import React from 'react';

import { useDispatch, useSelector } from 'react-redux';

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

import MainPage from './MainPage';
import { MemoryRouter } from 'react-router-dom';

jest.mock('react-redux');
import MainPage from './MainPage';
import STUDY_GROUPS from '../../fixtures/study-groups';

describe('MainPage', () => {
const dispatch = jest.fn();
Expand All @@ -16,13 +17,15 @@ describe('MainPage', () => {
useDispatch.mockImplementation(() => dispatch);

useSelector.mockImplementation((selector) => selector({
groups: [],
groups: STUDY_GROUPS,
}));
});

const renderMainPage = () => render(
<MainPage />,
);
const renderMainPage = () => render((
<MemoryRouter initialEntries={['/?tag=JavaScript']}>
<MainPage />
</MemoryRouter>
));

it('renders Main Page Title', () => {
const { container } = renderMainPage();
Expand All @@ -31,7 +34,18 @@ describe('MainPage', () => {
});

it('calls dispatch with loadStudyGroups action', () => {
renderMainPage();
const { container } = renderMainPage();

expect(dispatch).toBeCalled();

expect(container).toHaveTextContent('스터디를 소개합니다.1');
expect(container).toHaveTextContent('스터디를 소개합니다.2');
});

it('Click event to calls dispatch', () => {
const { getByText } = renderMainPage();

fireEvent.click(getByText('#JavaScript'));

expect(dispatch).toBeCalled();
});
Expand Down
14 changes: 10 additions & 4 deletions src/reducers/slice.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,16 @@ const { actions, reducer } = createSlice({
group: null,
},
reducers: {
setStudyGroups(state, { payload: groups }) {
setStudyGroups(state, { payload: { groups, tag } }) {
return {
...state,
groups,
groups: tag ? groups.reduce((studies, group) => {
if (group.tags.includes(tag)) {
return [...studies, group];
}

return studies;
}, []) : groups,
};
},
setStudyGroup(state, { payload: group }) {
Expand All @@ -32,10 +38,10 @@ export const {
setStudyGroup,
} = actions;

export const loadStudyGroups = () => async (dispatch) => {
export const loadStudyGroups = (tag) => async (dispatch) => {
const groups = await getStudyGroups();

dispatch(setStudyGroups(groups));
dispatch(setStudyGroups({ groups, tag }));
};

export const loadStudyGroup = (id) => async (dispatch) => {
Expand Down
Loading