diff --git a/src/components/introduce/modals/ApplicationViewModal.jsx b/src/components/introduce/modals/ApplicationViewModal.jsx new file mode 100644 index 0000000..181d076 --- /dev/null +++ b/src/components/introduce/modals/ApplicationViewModal.jsx @@ -0,0 +1,137 @@ +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 ApplicationViewModalWrapper = 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: auto; + 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; + } +`; + +const ContentViewerWrapper = styled.textarea` + display: block; + padding: 5px; + resize: none; + outline: none; + border: 2px solid #D7E2EB; + border-radius: 3px; + font-weight: bold; + color: rgb(33, 37, 41); + margin-bottom: 0.7rem; + transition-duration: 0.08s; + transition-property: all; + transition-timing-function: ease-in-out; + transition-delay: initial; + cursor: unset; + &:focus { + border: 2px solid ${palette.gray[5]}; + } +`; + +const StyledButton = styled(Button)` + &:last-of-type { + margin-left: .7rem; + } +`; + +const ApplicationViewModal = ({ + visible, onClose, participant, +}) => { + const { reason, wantToGet, id } = participant; + + if (!visible) { + return null; + } + + return ( + + +

{`${id} 신청서 📚`}

+ + + + + + + + +
+ 닫기 +
+
+
+ ); +}; + +export default ApplicationViewModal; diff --git a/src/components/introduce/modals/ApplicationViewModal.test.jsx b/src/components/introduce/modals/ApplicationViewModal.test.jsx new file mode 100644 index 0000000..a8bb77f --- /dev/null +++ b/src/components/introduce/modals/ApplicationViewModal.test.jsx @@ -0,0 +1,68 @@ +import React from 'react'; + +import { fireEvent, render } from '@testing-library/react'; + +import ApplicationViewModal from './ApplicationViewModal'; + +describe('ApplicationViewModal', () => { + const handleClose = jest.fn(); + + beforeEach(() => { + jest.clearAllMocks(); + }); + + const renderApplicationViewModal = ({ visible, participant }) => render(( + + )); + + context('with visible', () => { + const modal = { + visible: true, + participant: { + id: 'test', + reason: 'reason', + wantToGet: 'wantToGet', + }, + }; + + it('renders Modal text', () => { + const { container } = renderApplicationViewModal(modal); + + const { participant } = modal; + + expect(container).toHaveTextContent(`${participant.id} 신청서 📚`); + expect(container).toHaveTextContent('신청하게 된 이유'); + expect(container).toHaveTextContent('스터디를 통해 얻고 싶은 것은 무엇인가요?'); + }); + + it('calls confirm event action', () => { + const { getByText } = renderApplicationViewModal(modal); + + const button = getByText('닫기'); + + fireEvent.click(button); + + expect(handleClose).toBeCalled(); + }); + }); + + context('without visible', () => { + const modal = { + visible: false, + participant: { + reason: '', + wantToGet: '', + }, + }; + + it("doesn't renders Modal text", () => { + const { container } = renderApplicationViewModal(modal); + + expect(container).toBeEmptyDOMElement(); + }); + }); +}); diff --git a/src/components/introduce/modals/ParticipantList.jsx b/src/components/introduce/modals/ParticipantList.jsx index c5768c8..fd7a7d1 100644 --- a/src/components/introduce/modals/ParticipantList.jsx +++ b/src/components/introduce/modals/ParticipantList.jsx @@ -1,8 +1,9 @@ -import React from 'react'; +import React, { useState } from 'react'; import styled from '@emotion/styled'; import ParticipantListButton from '../../../styles/ParticipantListButton'; +import ApplicationViewModal from './ApplicationViewModal'; const ParticipantListWrapper = styled.div` display: grid; @@ -14,26 +15,50 @@ const ParticipantListWrapper = styled.div` min-width: 0; `; -const ParticipantList = ({ id, confirm }) => ( - -
{id}
-
- - 신청서 보기 - -
-
- {confirm === true ? ( - - 취소하기 - - ) : ( - - 승인하기 - - )} -
-
-); +const ParticipantList = ({ participant }) => { + const [viewApplyModal, setViewApplyModal] = useState(false); + + const { id, confirm } = participant; + + const handleApplyFormClick = () => { + setViewApplyModal(true); + }; + + const handelApplyFormClose = () => { + setViewApplyModal(false); + }; + + return ( + <> + +
{id}
+
+ + 신청서 보기 + +
+
+ {confirm === true ? ( + + 취소하기 + + ) : ( + + 승인하기 + + )} +
+
+ + + ); +}; export default ParticipantList; diff --git a/src/components/introduce/modals/ParticipantList.test.jsx b/src/components/introduce/modals/ParticipantList.test.jsx index 72c3d8d..4797e6f 100644 --- a/src/components/introduce/modals/ParticipantList.test.jsx +++ b/src/components/introduce/modals/ParticipantList.test.jsx @@ -1,14 +1,13 @@ import React from 'react'; -import { render } from '@testing-library/react'; +import { fireEvent, render } from '@testing-library/react'; import ParticipantList from './ParticipantList'; describe('ParticipantList', () => { - const renderParticipantList = ({ id, confirm }) => render(( + const renderParticipantList = (participant) => render(( )); @@ -39,4 +38,41 @@ describe('ParticipantList', () => { expect(container).toHaveTextContent('승인하기'); }); }); + + describe('click "View application" button', () => { + const participant = { + id: 'test', + reason: 'reason', + wantToGet: 'wantToGet', + confirm: false, + }; + + it("renders Applicant's application", () => { + const { container, getByText } = renderParticipantList(participant); + + const button = getByText('신청서 보기'); + + fireEvent.click(button); + + const { reason, wantToGet } = participant; + + expect(container).toHaveTextContent(reason); + expect(container).toHaveTextContent(wantToGet); + }); + + it('close button click', () => { + const { container, getByText } = renderParticipantList(participant); + + const button = getByText('신청서 보기'); + + fireEvent.click(button); + + fireEvent.click(getByText('닫기')); + + const { reason, wantToGet } = participant; + + expect(container).not.toHaveTextContent(reason); + expect(container).not.toHaveTextContent(wantToGet); + }); + }); }); diff --git a/src/components/introduce/modals/ParticipantListModal.jsx b/src/components/introduce/modals/ParticipantListModal.jsx index a84ebdb..394c1fd 100644 --- a/src/components/introduce/modals/ParticipantListModal.jsx +++ b/src/components/introduce/modals/ParticipantListModal.jsx @@ -103,11 +103,10 @@ const ParticipantListModal = ({ visible, onClose, participants }) => {
승인 여부
- {participants.length && participants.map(({ id, confirm }) => ( + {participants.length && participants.map((participant) => ( ))}