diff --git a/src/components/common/ModalWindow.jsx b/src/components/common/ModalWindow.jsx index e6aeb84..22418fe 100644 --- a/src/components/common/ModalWindow.jsx +++ b/src/components/common/ModalWindow.jsx @@ -4,6 +4,7 @@ import styled from '@emotion/styled'; import { css } from '@emotion/react'; import Button from '../../styles/Button'; +import palette from '../../styles/palette'; const ModalWindowWrapper = styled.div` position: fixed; @@ -57,10 +58,13 @@ const ModalBoxWrapper = styled.div` `; const StyledButton = styled(Button)` - height: 2rem; - & + & { - margin-left: 0.75rem; + &:last-of-type { + margin-left: .7rem; } + + ${(props) => props.cancel && css` + border: 2px solid ${palette.gray[7]}; + `} `; const ModalWindow = ({ @@ -82,7 +86,7 @@ const ModalWindow = ({

{title}

{description}

- {cancelText} + {cancelText} {onConfirm && ( {confirmText} )} diff --git a/src/components/introduce/IntroduceHeader.jsx b/src/components/introduce/IntroduceHeader.jsx index 940303a..53808ae 100644 --- a/src/components/introduce/IntroduceHeader.jsx +++ b/src/components/introduce/IntroduceHeader.jsx @@ -7,6 +7,7 @@ import { changeDateToTime, isCheckedTimeStatus } from '../../util/utils'; import ApplyStatusButton from './ApplyStatusButton'; import AskLoginModal from './modals/AskLoginModal'; +import AskApplyCancelModal from './modals/AskApplyCancelModal'; const IntroduceHeaderWrapper = styled.div` border-bottom: 2px solid ${palette.gray[4]}; @@ -24,7 +25,8 @@ const IntroduceHeaderWrapper = styled.div` const IntroduceHeader = ({ group, onApply, user, realTime, onApplyCancel, }) => { - const [modal, setModal] = useState(false); + const [loginCheckModal, setLoginCheckModal] = useState(false); + const [applyCancelModal, setApplyCancelModal] = useState(false); const { title, moderatorId, participants, applyEndDate, @@ -32,17 +34,26 @@ const IntroduceHeader = ({ const applyEndTime = changeDateToTime(applyEndDate); - const onApplyClick = () => { - setModal(true); + const handleApplyCancelConfirmClick = () => { + setApplyCancelModal(true); }; - const handleCancel = () => { - setModal(false); + const handleLoginCheckCancel = () => { + setLoginCheckModal(false); + }; + + const handleApplyCancel = () => { + setApplyCancelModal(false); + }; + + const handleApplyCancelConfirm = () => { + setApplyCancelModal(false); + onApplyCancel(); }; const handleApply = () => { if (!user) { - onApplyClick(); + setLoginCheckModal(true); return; } @@ -56,12 +67,20 @@ const IntroduceHeader = ({ <> - + + )} diff --git a/src/components/introduce/IntroduceHeader.test.jsx b/src/components/introduce/IntroduceHeader.test.jsx index e6d9678..e6b3dc5 100644 --- a/src/components/introduce/IntroduceHeader.test.jsx +++ b/src/components/introduce/IntroduceHeader.test.jsx @@ -47,16 +47,36 @@ describe('IntroduceHeader', () => { personnel: 3, }; - it('Call the cancel application button.', () => { - const { getByText } = renderIntroduceHeader({ group, user: 'user', time }); + context('click confirm', () => { + it('Call the cancel application button.', () => { + const { getByText } = renderIntroduceHeader({ group, user: 'user', time }); - const button = getByText('신청 취소'); + const button = getByText('신청 취소'); - expect(button).not.toBeNull(); + expect(button).not.toBeNull(); + + fireEvent.click(button); + + fireEvent.click(getByText('확인')); + + expect(handleApplyCancel).toBeCalled(); + }); + }); - fireEvent.click(button); + context('click cancel', () => { + it("doesn't call the cancel application button.", () => { + const { getByText } = renderIntroduceHeader({ group, user: 'user', time }); - expect(handleApplyCancel).toBeCalled(); + const button = getByText('신청 취소'); + + expect(button).not.toBeNull(); + + fireEvent.click(button); + + fireEvent.click(getByText('취소')); + + expect(handleApplyCancel).not.toBeCalled(); + }); }); }); diff --git a/src/components/introduce/modals/AskApplyCancelModal.jsx b/src/components/introduce/modals/AskApplyCancelModal.jsx new file mode 100644 index 0000000..455b656 --- /dev/null +++ b/src/components/introduce/modals/AskApplyCancelModal.jsx @@ -0,0 +1,15 @@ +import React from 'react'; + +import ModalWindow from '../../common/ModalWindow'; + +const AskApplyCancelModal = ({ visible, onCancel, onConfirm }) => ( + +); + +export default AskApplyCancelModal; diff --git a/src/components/introduce/modals/AskApplyCancelModal.test.jsx b/src/components/introduce/modals/AskApplyCancelModal.test.jsx new file mode 100644 index 0000000..75d8f78 --- /dev/null +++ b/src/components/introduce/modals/AskApplyCancelModal.test.jsx @@ -0,0 +1,63 @@ +import React from 'react'; + +import { fireEvent, render } from '@testing-library/react'; + +import AskApplyCancelModal from './AskApplyCancelModal'; + +describe('AskApplyCancelModal', () => { + const handleCancel = jest.fn(); + const handleConfirm = jest.fn(); + + const renderAskApplyCancelModal = ({ visible }) => render(( + + )); + + context('with visible', () => { + const modal = { + visible: true, + }; + + it('renders Modal text', () => { + const { container } = renderAskApplyCancelModal(modal); + + expect(container).toHaveTextContent('신청 취소'); + expect(container).toHaveTextContent('스터디 그룹 신청을 취소하시겠습니까?'); + }); + + it('calls confirm event action', () => { + const { getByText } = renderAskApplyCancelModal(modal); + + const button = getByText('확인'); + + fireEvent.click(button); + + expect(handleConfirm).toBeCalled(); + }); + + it('calls cancel event action', () => { + const { getByText } = renderAskApplyCancelModal(modal); + + const button = getByText('취소'); + + fireEvent.click(button); + + expect(handleCancel).toBeCalled(); + }); + }); + + context('without visible', () => { + const modal = { + visible: false, + }; + + it("doesn't renders Modal text", () => { + const { container } = renderAskApplyCancelModal(modal); + + expect(container).toBeEmptyDOMElement(); + }); + }); +}); diff --git a/src/containers/introduce/IntroduceContainer.test.jsx b/src/containers/introduce/IntroduceContainer.test.jsx index 6e3e9c9..334b521 100644 --- a/src/containers/introduce/IntroduceContainer.test.jsx +++ b/src/containers/introduce/IntroduceContainer.test.jsx @@ -110,18 +110,40 @@ describe('IntroduceContainer', () => { given('group', () => (group)); given('user', () => ('user')); - it('click event dispatches action call deleteParticipant', () => { - const { getByText } = renderIntroduceContainer(1); + context('click confirm', () => { + it('click event dispatches action call deleteParticipant', () => { + const { getByText } = renderIntroduceContainer(1); - expect(dispatch).toBeCalledTimes(1); + expect(dispatch).toBeCalledTimes(1); - const button = getByText('신청 취소'); + const button = getByText('신청 취소'); - expect(button).not.toBeNull(); + expect(button).not.toBeNull(); - fireEvent.click(button); + fireEvent.click(button); - expect(dispatch).toBeCalledTimes(2); + fireEvent.click(getByText('확인')); + + expect(dispatch).toBeCalledTimes(2); + }); + }); + + context('click cancel', () => { + it("doesn't click event dispatches action call deleteParticipant", () => { + const { getByText } = renderIntroduceContainer(1); + + expect(dispatch).toBeCalledTimes(1); + + const button = getByText('신청 취소'); + + expect(button).not.toBeNull(); + + fireEvent.click(button); + + fireEvent.click(getByText('취소')); + + expect(dispatch).toBeCalledTimes(1); + }); }); }); });