From a865d4e0c0fd8153873eac640504d65af0ff9233 Mon Sep 17 00:00:00 2001 From: saseungmin Date: Wed, 9 Dec 2020 01:25:59 +0900 Subject: [PATCH] [Feature] Application form for study participation - Implementation of the study participation application form as a modal window --- src/components/introduce/IntroduceHeader.jsx | 16 +++ .../introduce/IntroduceHeader.test.jsx | 3 + .../introduce/modals/ApplicationFormModal.jsx | 129 ++++++++++++++++++ .../modals/ApplicationFormModal.test.jsx | 64 +++++++++ .../introduce/IntroduceContainer.test.jsx | 3 + 5 files changed, 215 insertions(+) create mode 100644 src/components/introduce/modals/ApplicationFormModal.jsx create mode 100644 src/components/introduce/modals/ApplicationFormModal.test.jsx diff --git a/src/components/introduce/IntroduceHeader.jsx b/src/components/introduce/IntroduceHeader.jsx index 53808ae..29328a2 100644 --- a/src/components/introduce/IntroduceHeader.jsx +++ b/src/components/introduce/IntroduceHeader.jsx @@ -8,6 +8,7 @@ import { changeDateToTime, isCheckedTimeStatus } from '../../util/utils'; import ApplyStatusButton from './ApplyStatusButton'; import AskLoginModal from './modals/AskLoginModal'; import AskApplyCancelModal from './modals/AskApplyCancelModal'; +import ApplicationFormModal from './modals/ApplicationFormModal'; const IntroduceHeaderWrapper = styled.div` border-bottom: 2px solid ${palette.gray[4]}; @@ -27,6 +28,7 @@ const IntroduceHeader = ({ }) => { const [loginCheckModal, setLoginCheckModal] = useState(false); const [applyCancelModal, setApplyCancelModal] = useState(false); + const [modalForm, setModalForm] = useState(false); const { title, moderatorId, participants, applyEndDate, @@ -57,9 +59,18 @@ const IntroduceHeader = ({ return; } + setModalForm(true); + }; + + const handleFormSubmit = () => { + setModalForm(false); onApply(); }; + const handleFormCancel = () => { + setModalForm(false); + }; + return (

{title}

@@ -81,6 +92,11 @@ const IntroduceHeader = ({ onCancel={handleApplyCancel} onConfirm={handleApplyCancelConfirm} /> + )}
diff --git a/src/components/introduce/IntroduceHeader.test.jsx b/src/components/introduce/IntroduceHeader.test.jsx index e6b3dc5..a3ba9aa 100644 --- a/src/components/introduce/IntroduceHeader.test.jsx +++ b/src/components/introduce/IntroduceHeader.test.jsx @@ -212,6 +212,9 @@ describe('IntroduceHeader', () => { fireEvent.click(button); + // TODO: 이 부분은 추후 변경해야된다 현재 스터디 참여 신청서 모달창이 나타남. + fireEvent.click(getByText('확인')); + expect(handleApply).toBeCalled(); expect(container).not.toHaveTextContent('로그인 후 신청 가능합니다.'); diff --git a/src/components/introduce/modals/ApplicationFormModal.jsx b/src/components/introduce/modals/ApplicationFormModal.jsx new file mode 100644 index 0000000..4f65519 --- /dev/null +++ b/src/components/introduce/modals/ApplicationFormModal.jsx @@ -0,0 +1,129 @@ +import React from 'react'; + +import styled from '@emotion/styled'; + +import { css } from '@emotion/react'; + +import Button from '../../../styles/Button'; +import palette from '../../../styles/palette'; + +const ApplicationFormModalWrapper = styled.div` + position: fixed; + z-index: 101; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: rgba(0, 0, 0, 0.25); + display: flex; + justify-content: center; + align-items: center; + + ${(props) => props.visible && css` + &.animation { + animation-name: fade-in; + animation-fill-mode: both; + animation-duration: 0.3s; + } + + @keyframes fade-in { + 0% { + opacity: 0; + } + 100% { + opacity: 1; + } + } + `}; +`; + +const ModalBoxWrapper = styled.div` + display: flex; + flex-direction: column; + height: 570px; + width: 400px; + background: white; + padding: 1.5rem; + border-radius: 6px; + box-shadow: 0px 0px 8px rgba(0, 0, 0, 0.125); + h2 { + margin-top: 0; + margin-bottom: 1rem; + text-align: center; + } + .buttons { + display: flex; + justify-content: flex-end; + } +`; + +const ContentBoxWrapper = styled.div` + display: flex; + flex-direction: column; + margin-bottom: 0.2rem; + + label { + font-size: 1.1rem; + font-weight: bold; + margin-bottom: 0.3rem; + ::before { + content: '*'; + display: inline-block; + vertical-align: top; + font-weight: 400; + color: ${palette.warn[1]}; + margin: 0 0.125rem 0 0; + font-size: 1.25rem; + line-height: 1.25rem; + } + } +`; + +const ContentTextareaWrapper = styled.textarea` + display: block; + padding: 5px; + resize: none; + outline: none; + border: 1px solid ${palette.gray[3]}; + border-radius: 3px; + font-weight: bold; + color: rgb(33, 37, 41); + margin-bottom: 0.7rem; + &:hover, &:focus { + border: 2px solid ${palette.gray[4]}; + } +`; + +const StyledButton = styled(Button)` + &:last-of-type { + margin-left: .7rem; + } +`; + +const ApplicationFormModal = ({ visible, onCancel, onConfirm }) => { + if (!visible) { + return null; + } + + return ( + + +

스터디 참여 신청서 📚

+ + + + + + + + +
+ 취소 + 확인 +
+
+
+ ); +}; + +export default ApplicationFormModal; diff --git a/src/components/introduce/modals/ApplicationFormModal.test.jsx b/src/components/introduce/modals/ApplicationFormModal.test.jsx new file mode 100644 index 0000000..cdb1f00 --- /dev/null +++ b/src/components/introduce/modals/ApplicationFormModal.test.jsx @@ -0,0 +1,64 @@ +import React from 'react'; + +import { fireEvent, render } from '@testing-library/react'; + +import ApplicationFormModal from './ApplicationFormModal'; + +describe('ApplicationFormModal', () => { + const handleCancel = jest.fn(); + const handleConfirm = jest.fn(); + + const renderApplicationFormModal = ({ visible }) => render(( + + )); + + context('with visible', () => { + const modal = { + visible: true, + }; + + it('renders Modal text', () => { + const { container } = renderApplicationFormModal(modal); + + expect(container).toHaveTextContent('스터디 참여 신청서 📚'); + expect(container).toHaveTextContent('신청하게 된 이유'); + expect(container).toHaveTextContent('스터디를 통해 얻고 싶은 것은 무엇인가요?'); + }); + + it('calls confirm event action', () => { + const { getByText } = renderApplicationFormModal(modal); + + const button = getByText('확인'); + + fireEvent.click(button); + + expect(handleConfirm).toBeCalled(); + }); + + it('calls cancel event action', () => { + const { getByText } = renderApplicationFormModal(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 } = renderApplicationFormModal(modal); + + expect(container).toBeEmptyDOMElement(); + }); + }); +}); diff --git a/src/containers/introduce/IntroduceContainer.test.jsx b/src/containers/introduce/IntroduceContainer.test.jsx index 334b521..57e41f3 100644 --- a/src/containers/introduce/IntroduceContainer.test.jsx +++ b/src/containers/introduce/IntroduceContainer.test.jsx @@ -88,6 +88,9 @@ describe('IntroduceContainer', () => { fireEvent.click(button); + // TODO: 이 부분은 추후 수정해야된다. 현재 스터디 참여 신청서 모달창으로 인해 테스트 fail되기 때문에 변경해놈 + fireEvent.click(getByText('확인')); + expect(dispatch).toBeCalledTimes(2); }); });