diff --git a/src/components/introduce/ApplicantViewButton.jsx b/src/components/introduce/ApplicantViewButton.jsx index 41b850b..42e6743 100644 --- a/src/components/introduce/ApplicantViewButton.jsx +++ b/src/components/introduce/ApplicantViewButton.jsx @@ -1,5 +1,7 @@ import React, { useState } from 'react'; +import styled from '@emotion/styled'; + import { changeDateToTime, isCheckedTimeStatus } from '../../util/utils'; import ApplyStatusButton from './ApplyStatusButton'; @@ -7,6 +9,11 @@ import ApplicationFormModal from './modals/ApplicationFormModal'; import AskApplyCancelModal from './modals/AskApplyCancelModal'; import AskLoginModal from './modals/AskLoginModal'; +const ParticipantsStatus = styled.div` + display: flex; + flex-direction: row; +`; + const ApplicantViewButton = ({ group, onApply, user, realTime, onApplyCancel, onChangeApplyFields, applyFields, clearForm, }) => { @@ -54,19 +61,30 @@ const ApplicantViewButton = ({ clearForm(); }; + const isCheckedUserStatus = (applicant) => (userEmail) => applicant + .find(({ id }) => id === userEmail); + + const status = { + ...group, + time: realTime, + applyEndTime, + }; + if (moderatorId === user) { return null; } return ( <> - id === user)} - timeStatus={isCheckedTimeStatus({ ...group, time: realTime, applyEndTime })} - /> + + + { applyEndDate: tomorrow, participants: [ { id: 'user2' }, - { id: 'user' }, + { id: 'user', confirm: false }, ], personnel: 3, }; @@ -110,13 +110,13 @@ describe('ApplicantViewButton', () => { ...STUDY_GROUP, applyEndDate: yesterday, participants: [ - { id: 'user2' }, + { id: 'user1', confirm: false }, ], personnel: 2, }; it('renders recruitment closed text', () => { - const { container } = renderApplicantViewButton({ group, time }); + const { container } = renderApplicantViewButton({ group, time, user: 'user1' }); expect(container).toHaveTextContent('모집 마감'); }); @@ -131,13 +131,13 @@ describe('ApplicantViewButton', () => { applyEndDate: tomorrow, participants: [ { id: 'user2' }, - { id: 'user3' }, + { id: 'user3', confirm: false }, ], - personnel: 2, + personnel: 1, }; it('renders recruitment closed text', () => { - const { container } = renderApplicantViewButton({ group, time }); + const { container } = renderApplicantViewButton({ group, time, user: 'user3' }); expect(container).toHaveTextContent('모집 마감'); }); diff --git a/src/components/introduce/ApplyStatusButton.jsx b/src/components/introduce/ApplyStatusButton.jsx index 7719b06..e7a5e60 100644 --- a/src/components/introduce/ApplyStatusButton.jsx +++ b/src/components/introduce/ApplyStatusButton.jsx @@ -1,40 +1,67 @@ import React from 'react'; +import ApproveStatus from '../../styles/ApproveStatus'; + import StyledApplyStatusButton from '../../styles/StyledApplyStatusButton'; +const checkConfirm = (confirm) => confirm === true; + const ApplyStatusButton = ({ - timeStatus, onApply, applyStatus, onCancel, + timeStatus, onApply, userStatus, onCancel, }) => { - if (!timeStatus && applyStatus) { + if (!timeStatus && !userStatus) { return ( - 신청 취소 + 신청하기 ); } - if (applyStatus) { + if (!timeStatus && !checkConfirm(userStatus.confirm)) { return ( - - 신청 완료 - + <> + + 승인 대기중.. + + + 신청 취소 + + ); } - if (timeStatus) { + if (!timeStatus && checkConfirm(userStatus.confirm)) { + return ( + <> + + 승인 완료! + + + 신청 취소 + + + ); + } + + if (timeStatus && checkConfirm(userStatus.confirm)) { return ( - 모집 마감 + 신청 완료 ); } @@ -42,10 +69,9 @@ const ApplyStatusButton = ({ return ( - 신청하기 + 모집 마감 ); }; diff --git a/src/components/introduce/ApplyStatusButton.test.jsx b/src/components/introduce/ApplyStatusButton.test.jsx index 47591b9..fbb73b2 100644 --- a/src/components/introduce/ApplyStatusButton.test.jsx +++ b/src/components/introduce/ApplyStatusButton.test.jsx @@ -8,27 +8,46 @@ describe('ApplyStatusButton', () => { const handleApply = jest.fn(); const renderApplyStatusButton = ({ - applyStatus = false, + userStatus, timeStatus = false, }) => render(( )); context('When the applicant applies before the application deadline', () => { - it('renders Cancel application', () => { - const { container } = renderApplyStatusButton({ applyStatus: true }); + context('Before approval', () => { + it('renders cancel application and Pending approval', () => { + const { container } = renderApplyStatusButton({ + userStatus: { confirm: false }, + }); - expect(container).toHaveTextContent('신청 취소'); + expect(container).toHaveTextContent('신청 취소'); + expect(container).toHaveTextContent('승인 대기중..'); + }); + }); + + context('After approval', () => { + it('renders Cancel application and Approved', () => { + const { container } = renderApplyStatusButton({ + userStatus: { confirm: true }, + }); + + expect(container).toHaveTextContent('신청 취소'); + expect(container).toHaveTextContent('승인 완료!'); + }); }); }); context('When the study application is completed', () => { it('renders application completed', () => { - const { container } = renderApplyStatusButton({ applyStatus: true, timeStatus: true }); + const { container } = renderApplyStatusButton({ + userStatus: { confirm: true }, + timeStatus: true, + }); expect(container).toHaveTextContent('신청 완료'); }); @@ -36,7 +55,10 @@ describe('ApplyStatusButton', () => { context('When the study application deadline', () => { it('renders application deadline', () => { - const { container } = renderApplyStatusButton({ timeStatus: true }); + const { container } = renderApplyStatusButton({ + userStatus: { confirm: false }, + timeStatus: true, + }); expect(container).toHaveTextContent('모집 마감'); }); diff --git a/src/containers/introduce/IntroduceHeaderContainer.test.jsx b/src/containers/introduce/IntroduceHeaderContainer.test.jsx index 50c6dd9..a38d36d 100644 --- a/src/containers/introduce/IntroduceHeaderContainer.test.jsx +++ b/src/containers/introduce/IntroduceHeaderContainer.test.jsx @@ -146,7 +146,7 @@ describe('IntroduceHeaderContainer', () => { applyEndDate: tomorrow, participants: [ { id: 'user2' }, - { id: 'user' }, + { id: 'user', confirm: false }, ], personnel: 3, }; diff --git a/src/styles/ApproveStatus.jsx b/src/styles/ApproveStatus.jsx new file mode 100644 index 0000000..d9b5e40 --- /dev/null +++ b/src/styles/ApproveStatus.jsx @@ -0,0 +1,42 @@ +/* eslint-disable react/jsx-props-no-spreading */ +import React from 'react'; + +import styled from '@emotion/styled'; + +import palette from './palette'; + +const ApproveStatusWrapper = styled.div` + display: inline-flex; + align-items: center; + font-weight: bold; + line-height: 0; + font-size: 1rem; + color: ${palette.violet[4]}; + padding: 0.8rem 1rem; +`; + +const LoadingContent = styled.span` + margin-left: .3rem; + width: 12px; + height: 12px; + border-top: 3px solid ${palette.violet[2]}; + border-bottom: 3px solid ${palette.violet[2]}; + border-right: 3px solid ${palette.violet[4]}; + border-left: 3px solid ${palette.violet[4]}; + animation: load 0.75s ease infinite; + border-radius: 100%; + + @keyframes load { + 0% { transform: rotate( 0deg ); } + 100% { transform: rotate(180deg); } + } +`; + +const ApproveStatus = ({ children, ...props }) => ( + + {children} + + +); + +export default ApproveStatus; diff --git a/src/util/utils.js b/src/util/utils.js index 1487c70..4edbf02 100644 --- a/src/util/utils.js +++ b/src/util/utils.js @@ -6,9 +6,16 @@ export function equal(key, value) { return (obj) => obj[key] === value; } +export const authorizedUsersNumber = (participants) => participants + .filter(({ confirm }) => confirm && confirm === true) + .length + 1; + export const isCheckedTimeStatus = ({ time, applyEndTime, participants, personnel, -}) => (!!((time - applyEndTime >= 0 || participants.length === parseInt(personnel, 10)))); +}) => (!!(( + time - applyEndTime >= 0 + || authorizedUsersNumber(participants) >= parseInt(personnel, 10) +))); export const isCheckedOnlyTimeStatus = ({ time, applyEndTime }) => (time - applyEndTime >= 0); @@ -18,10 +25,6 @@ export const isCheckValidate = (values) => values.map(checkTrim).includes(''); export const changeDateToTime = (date) => new Date(date).getTime(); -export const authorizedUsersNumber = (participants) => participants - .filter(({ confirm }) => confirm && confirm === true) - .length + 1; - export const applyDateToString = (response) => response .data() .applyEndDate