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) => (
))}