diff --git a/src/components/introduce/IntroduceActionButtons.jsx b/src/components/introduce/IntroduceActionButtons.jsx index ab2809d..8057157 100644 --- a/src/components/introduce/IntroduceActionButtons.jsx +++ b/src/components/introduce/IntroduceActionButtons.jsx @@ -37,10 +37,15 @@ const ActionButton = styled.button` `}; `; -const IntroduceActionButtons = () => ( +const IntroduceActionButtons = ({ onRemove }) => ( 수정 - 삭제 + + 삭제 + ); diff --git a/src/components/introduce/IntroduceForm.jsx b/src/components/introduce/IntroduceForm.jsx index bfca9d2..4bc074f 100644 --- a/src/components/introduce/IntroduceForm.jsx +++ b/src/components/introduce/IntroduceForm.jsx @@ -86,13 +86,14 @@ const IntroduceFooter = styled.div` `; const IntroduceForm = ({ - group, realTime, + user, group, realTime, onRemove, }) => { const { - contents, tags, moderatorId, personnel, participants, applyEndDate, createDate, + contents, tags, moderatorId, personnel, participants, applyEndDate, createDate, id, } = group; const applyEndTime = changeDateToTime(applyEndDate); + const isCheckOwnGroupPost = (user && user) === moderatorId; return ( <> @@ -125,7 +126,11 @@ const IntroduceForm = ({ - + {isCheckOwnGroupPost && ( + onRemove(id)} + /> + )} ); diff --git a/src/components/introduce/IntroduceForm.test.jsx b/src/components/introduce/IntroduceForm.test.jsx index 0c9618c..c3e5dbf 100644 --- a/src/components/introduce/IntroduceForm.test.jsx +++ b/src/components/introduce/IntroduceForm.test.jsx @@ -2,18 +2,22 @@ import React from 'react'; import { MemoryRouter } from 'react-router-dom'; -import { render } from '@testing-library/react'; +import { fireEvent, render } from '@testing-library/react'; import IntroduceForm from './IntroduceForm'; import STUDY_GROUP from '../../../fixtures/study-group'; describe('IntroduceForm', () => { - const renderIntroduceForm = ({ group, time }) => render(( + const handleRemove = jest.fn(); + + const renderIntroduceForm = ({ group, time, user = 'user2' }) => render(( )); @@ -30,4 +34,30 @@ describe('IntroduceForm', () => { expect(container.innerHTML).toContain(' { + it('renders delete button and revise button', () => { + const { container } = renderIntroduceForm({ group: STUDY_GROUP }); + + expect(container).toHaveTextContent('수정'); + expect(container).toHaveTextContent('삭제'); + }); + + it('click to delete button call event', () => { + const { getByText } = renderIntroduceForm({ group: STUDY_GROUP }); + + fireEvent.click(getByText('삭제')); + + expect(handleRemove).toBeCalled(); + }); + }); + + context('without moderator', () => { + it("doesn't renders delete button and revise button", () => { + const { container } = renderIntroduceForm({ group: STUDY_GROUP, user: 'user' }); + + expect(container).not.toHaveTextContent('수정'); + expect(container).not.toHaveTextContent('삭제'); + }); + }); }); diff --git a/src/containers/introduce/IntroduceFormContainer.jsx b/src/containers/introduce/IntroduceFormContainer.jsx index 6babdd5..84b8b62 100644 --- a/src/containers/introduce/IntroduceFormContainer.jsx +++ b/src/containers/introduce/IntroduceFormContainer.jsx @@ -1,29 +1,43 @@ import React, { useState } from 'react'; import { useInterval } from 'react-use'; -import { useSelector } from 'react-redux'; +import { useHistory } from 'react-router-dom'; +import { useDispatch, useSelector } from 'react-redux'; -import { getGroup } from '../../util/utils'; +import { getAuth, getGroup } from '../../util/utils'; import IntroduceForm from '../../components/introduce/IntroduceForm'; +import { deleteGroup } from '../../reducers/groupSlice'; const IntroduceFormContainer = () => { const [realTime, setRealTime] = useState(Date.now()); + const history = useHistory(); + const dispatch = useDispatch(); + const group = useSelector(getGroup('group')); + const user = useSelector(getAuth('user')); useInterval(() => { setRealTime(Date.now()); }, 1000); + const onRemove = (id) => { + dispatch(deleteGroup(id)); + + history.push('/'); + }; + if (!group) { return null; } return ( ); }; diff --git a/src/containers/introduce/IntroduceFormContainer.test.jsx b/src/containers/introduce/IntroduceFormContainer.test.jsx index 507fbcc..6f38994 100644 --- a/src/containers/introduce/IntroduceFormContainer.test.jsx +++ b/src/containers/introduce/IntroduceFormContainer.test.jsx @@ -1,20 +1,39 @@ import React from 'react'; -import { useSelector } from 'react-redux'; +import { useDispatch, useSelector } from 'react-redux'; -import { render } from '@testing-library/react'; +import { fireEvent, render } from '@testing-library/react'; import { MemoryRouter } from 'react-router-dom'; import IntroduceFormContainer from './IntroduceFormContainer'; +const mockPush = jest.fn(); + +jest.mock('react-router-dom', () => ({ + ...jest.requireActual('react-router-dom'), + useHistory() { + return { push: mockPush }; + }, +})); + describe('IntroduceFormContainer', () => { + const dispatch = jest.fn(); + beforeEach(() => { + dispatch.mockClear(); + mockPush.mockClear(); + + useDispatch.mockImplementation(() => dispatch); + useSelector.mockImplementation((state) => state({ groupReducer: { group: given.group, applyFields: given.applyFields, }, + authReducer: { + user: 'user1', + }, })); }); @@ -44,6 +63,20 @@ describe('IntroduceFormContainer', () => { expect(container).toHaveTextContent('우리는 이것저것 합니다.1'); }); + + it('click delete button call dispatch action', () => { + const { getByText } = renderIntroduceContainer(1); + + const button = getByText('삭제'); + + expect(button).not.toBeNull(); + + fireEvent.click(button); + + expect(dispatch).toBeCalled(); + + expect(mockPush).toBeCalledWith('/'); + }); }); context('without group ', () => { diff --git a/src/reducers/groupSlice.js b/src/reducers/groupSlice.js index 0667055..23ddd28 100644 --- a/src/reducers/groupSlice.js +++ b/src/reducers/groupSlice.js @@ -9,6 +9,7 @@ import { updatePostParticipant, deletePostParticipant, updateConfirmPostParticipant, + deletePostGroup, } from '../services/api'; const writeInitialState = { @@ -204,4 +205,8 @@ export const updateConfirmParticipant = (userEmail) => async (dispatch, getState })); }; +export const deleteGroup = (groupId) => async () => { + await deletePostGroup(groupId); +}; + export default reducer; diff --git a/src/reducers/groupSlice.test.js b/src/reducers/groupSlice.test.js index f663f60..f19681b 100644 --- a/src/reducers/groupSlice.test.js +++ b/src/reducers/groupSlice.test.js @@ -17,6 +17,7 @@ import reducer, { changeApplyFields, clearApplyFields, updateConfirmParticipant, + deleteGroup, } from './groupSlice'; import STUDY_GROUPS from '../../fixtures/study-groups'; @@ -368,4 +369,20 @@ describe('async actions', () => { }); }); }); + + describe('deleteGroup', () => { + beforeEach(() => { + store = mockStore({}); + }); + + it('dispatches setStudyGroup', async () => { + const groupId = '1'; + + await store.dispatch(deleteGroup(groupId)); + + const actions = store.getActions(); + + expect(actions[0]).toEqual(); + }); + }); }); diff --git a/src/services/__mocks__/api.js b/src/services/__mocks__/api.js index d554f20..506fc3d 100644 --- a/src/services/__mocks__/api.js +++ b/src/services/__mocks__/api.js @@ -15,3 +15,5 @@ export const updatePostParticipant = jest.fn(); export const deletePostParticipant = jest.fn(); export const updateConfirmPostParticipant = jest.fn(); + +export const deletePostGroup = jest.fn(); diff --git a/src/services/api.js b/src/services/api.js index 0b70dc9..6dba732 100644 --- a/src/services/api.js +++ b/src/services/api.js @@ -79,6 +79,12 @@ export const deletePostParticipant = async ({ id, participants }) => { }); }; +export const deletePostGroup = async (id) => { + const groups = db.collection('groups').doc(id); + + await groups.delete(); +}; + export const updateConfirmPostParticipant = async ({ id, participants }) => { const groups = db.collection('groups').doc(id);