diff --git a/fake-server/db.json b/fake-server/db.json index 38d45b9..7b2202c 100644 --- a/fake-server/db.json +++ b/fake-server/db.json @@ -40,7 +40,7 @@ "id": 2, "title": "스터디를 소개합니다.3", "moderatorId": "user3", - "applyEndDate": "2020-11-22 18:08", + "applyEndDate": "2020-11-22 20:49", "participants": [ "user1", "user2", diff --git a/src/components/common/DateTimeChange.jsx b/src/components/common/DateTimeChange.jsx index 4ae874f..bb43a5e 100644 --- a/src/components/common/DateTimeChange.jsx +++ b/src/components/common/DateTimeChange.jsx @@ -1,4 +1,4 @@ -import React, { useState } from 'react'; +import React from 'react'; import styled from '@emotion/styled'; @@ -6,7 +6,7 @@ import 'moment/locale/ko'; import moment from 'moment'; import Moment from 'react-moment'; -import useInterval from '../../util/useInterval'; +import { isCheckedTimeStatus } from '../../util/utils'; import DateTimeStatus from '../../styles/DateTimeStatus'; @@ -16,22 +16,13 @@ const DateTimeChangeWrapper = styled.div` margin-top: .2rem; `; -const isCheckedTimeStatus = ({ - realTime, applyEndTime, participants, personnel, -}) => (!!((realTime - applyEndTime >= 0 || participants.length === personnel))); - -const DateTimeChange = ({ group, page }) => { +const DateTimeChange = ({ group, page, time }) => { const { participants, personnel, applyEndDate } = group; - const applyEndTime = new Date(applyEndDate).getTime(); - const [realTime, setRealTime] = useState(Date.now()); - - useInterval(() => { - setRealTime(Date.now()); - }, 1000); + const applyEndTime = new Date(applyEndDate).getTime(); const valid = { - realTime, applyEndTime, participants, personnel, + time, applyEndTime, participants, personnel, }; const mainTimeStatus = () => { diff --git a/src/components/common/DateTimeChange.test.jsx b/src/components/common/DateTimeChange.test.jsx index 0d08ff0..74a2e61 100644 --- a/src/components/common/DateTimeChange.test.jsx +++ b/src/components/common/DateTimeChange.test.jsx @@ -5,15 +5,17 @@ import { render } from '@testing-library/react'; import DateTimeChange from './DateTimeChange'; describe('DateTimeChange', () => { - const renderDateTimeChange = ({ group, page }) => render(( + const renderDateTimeChange = ({ group, page, time }) => render(( )); context('When on the main page', () => { const page = 'main'; + const time = Date.now(); it('renders Recruitment number text', () => { const group = { @@ -26,32 +28,33 @@ describe('DateTimeChange', () => { const { participants, personnel } = group; - const { container } = renderDateTimeChange({ group, page }); + const { container } = renderDateTimeChange({ group, page, time }); expect(container).toHaveTextContent(`모집 인원: ${participants.length} / ${personnel}`); }); - describe('current time is before the application deadline', () => { + describe(`current time is before the recruitment deadline + when the number of study group participants is less than the maximum number of participants`, () => { it('renders Recruiting text', () => { const nowDate = new Date(); const tomorrow = nowDate.setDate(nowDate.getDate() + 1); const group = { - applyEndDate: tomorrow, + applyEndTime: tomorrow, participants: [ 'user2', ], personnel: 2, }; - const { container } = renderDateTimeChange({ group, page }); + const { container } = renderDateTimeChange({ group, page, time }); expect(container).toHaveTextContent('모집중'); }); }); - describe('current time is after the application deadline', () => { - it('renders Application deadline text', () => { + describe('current time is after the recruitment deadline', () => { + it('renders recruitment deadline text', () => { const nowDate = new Date(); const yesterday = nowDate.setDate(nowDate.getDate() - 1); @@ -63,14 +66,14 @@ describe('DateTimeChange', () => { personnel: 2, }; - const { container } = renderDateTimeChange({ group, page }); + const { container } = renderDateTimeChange({ group, page, time }); expect(container).toHaveTextContent('모집마감'); }); }); describe('When the number of study group participants equals the maximum number of participants', () => { - it('renders Application deadline text', () => { + it('renders recruitment deadline text', () => { const nowDate = new Date(); const tomorrow = nowDate.setDate(nowDate.getDate() - 1); @@ -83,7 +86,7 @@ describe('DateTimeChange', () => { personnel: 2, }; - const { container } = renderDateTimeChange({ group, page }); + const { container } = renderDateTimeChange({ group, page, time }); expect(container).toHaveTextContent('모집마감'); }); @@ -92,9 +95,11 @@ describe('DateTimeChange', () => { context('When on the introduce page', () => { const page = 'introduce'; + const time = Date.now(); - describe('current time is before the application deadline', () => { - it('renders Application deadline one day later text', () => { + describe(`current time is before the recruitment deadline + when the number of study group participants is less than the maximum number of participants`, () => { + it('renders recruitment deadline one day later text', () => { const nowDate = new Date(); const tomorrow = nowDate.setDate(nowDate.getDate() + 1); @@ -106,14 +111,14 @@ describe('DateTimeChange', () => { personnel: 2, }; - const { container } = renderDateTimeChange({ group, page }); + const { container } = renderDateTimeChange({ group, page, time }); expect(container).toHaveTextContent('하루 후 모집 마감'); }); }); - describe('current time is after the application deadline', () => { - it('renders Application deadline text', () => { + describe('current time is after the recruitment deadline', () => { + it('renders recruitment deadline text', () => { const nowDate = new Date(); const yesterday = nowDate.setDate(nowDate.getDate() - 1); @@ -125,14 +130,14 @@ describe('DateTimeChange', () => { personnel: 2, }; - const { container } = renderDateTimeChange({ group, page }); + const { container } = renderDateTimeChange({ group, page, time }); expect(container).toHaveTextContent('모집마감'); }); }); describe('When the number of study group participants equals the maximum number of participants', () => { - it('renders Application deadline text', () => { + it('renders recruitment deadline text', () => { const nowDate = new Date(); const tomorrow = nowDate.setDate(nowDate.getDate() - 1); @@ -145,7 +150,7 @@ describe('DateTimeChange', () => { personnel: 2, }; - const { container } = renderDateTimeChange({ group, page }); + const { container } = renderDateTimeChange({ group, page, time }); expect(container).toHaveTextContent('모집마감'); }); diff --git a/src/components/introduce/StudyIntroduceForm.jsx b/src/components/introduce/StudyIntroduceForm.jsx index c9e49ef..6fb7199 100644 --- a/src/components/introduce/StudyIntroduceForm.jsx +++ b/src/components/introduce/StudyIntroduceForm.jsx @@ -2,6 +2,10 @@ import React from 'react'; import styled from '@emotion/styled'; +import Moment from 'react-moment'; + +import { isCheckedTimeStatus } from '../../util/utils'; + import Tags from '../common/Tags'; import palette from '../../styles/palette'; import DateTimeChange from '../common/DateTimeChange'; @@ -32,9 +36,17 @@ const IntroduceHeaderWrapper = styled.div` font-family: 'Gamja Flower', cursive; border-radius: 0.4rem; border: none; - background: ${palette.teal[5]}; + outline: none; + } + .deadline{ + cursor: not-allowed; + background: ${palette.gray[3]}; + color: ${palette.gray[5]}; + } + .apply{ color: white; cursor: pointer; + background: ${palette.teal[5]}; &:hover{ background: ${palette.teal[4]}; } @@ -87,16 +99,32 @@ const IntroduceContent = styled.div` padding: 1.5rem; `; -const StudyIntroduceForm = ({ group }) => { +const StudyIntroduceForm = ({ group, realTime }) => { const { title, contents, tags, moderatorId, personnel, participants, applyEndDate, } = group; + const applyEndTime = new Date(applyEndDate).getTime(); + return (

{title}

- + {isCheckedTimeStatus({ ...group, time: realTime, applyEndTime }) ? ( + + ) : ( + + )}
{`🙋‍♂️ ${moderatorId}`} @@ -110,10 +138,11 @@ const StudyIntroduceForm = ({ group }) => { - {applyEndDate} + {applyEndTime} diff --git a/src/components/introduce/StudyIntroduceForm.test.jsx b/src/components/introduce/StudyIntroduceForm.test.jsx index 99d576e..72b8647 100644 --- a/src/components/introduce/StudyIntroduceForm.test.jsx +++ b/src/components/introduce/StudyIntroduceForm.test.jsx @@ -9,10 +9,11 @@ import StudyIntroduceForm from './StudyIntroduceForm'; import STUDY_GROUP from '../../../fixtures/study-group'; describe('StudyIntroduceForm', () => { - const renderStudyIntroduceForm = ({ group }) => render(( + const renderStudyIntroduceForm = ({ group, time }) => render(( )); @@ -29,4 +30,77 @@ describe('StudyIntroduceForm', () => { expect(container.innerHTML).toContain(' { + const time = Date.now(); + + describe('current time is after the recruitment deadline', () => { + const nowDate = new Date(); + const yesterday = nowDate.setDate(nowDate.getDate() - 1); + + const group = { + ...STUDY_GROUP, + applyEndDate: yesterday, + participants: [ + 'user2', + ], + personnel: 2, + }; + + it('renders recruitment closed text', () => { + const { container } = renderStudyIntroduceForm({ group, time }); + + expect(container).toHaveTextContent('모집마감'); + expect(container).not.toHaveTextContent('신청하기'); + }); + }); + + describe('When the number of study group participants equals the maximum number of participants', () => { + const nowDate = new Date(); + const tomorrow = nowDate.setDate(nowDate.getDate() + 1); + + const group = { + ...STUDY_GROUP, + applyEndDate: tomorrow, + participants: [ + 'user2', + 'user3', + ], + personnel: 2, + }; + + it('renders recruitment closed text', () => { + const { container } = renderStudyIntroduceForm({ group, time }); + + expect(container).toHaveTextContent('모집마감'); + expect(container).not.toHaveTextContent('신청하기'); + }); + }); + }); + + context('When the study recruitment is opened', () => { + const time = Date.now(); + + describe(`current time is before the recruitment deadline and + when the number of study group participants is less than the maximum number of participants`, () => { + const nowDate = new Date(); + const tomorrow = nowDate.setDate(nowDate.getDate() + 1); + + const group = { + ...STUDY_GROUP, + applyEndDate: tomorrow, + participants: [ + 'user2', + ], + personnel: 2, + }; + + it('renders recruitment apply text', () => { + const { container } = renderStudyIntroduceForm({ group, time }); + + expect(container).toHaveTextContent('신청하기'); + expect(container).not.toHaveTextContent('모집마감'); + }); + }); + }); }); diff --git a/src/components/main/StudyGroup.jsx b/src/components/main/StudyGroup.jsx index f72312c..0a3a56b 100644 --- a/src/components/main/StudyGroup.jsx +++ b/src/components/main/StudyGroup.jsx @@ -39,7 +39,7 @@ const StudyInfoWrapper = styled.div` } `; -const StudyGroup = ({ group }) => { +const StudyGroup = ({ group, realTime }) => { const { id, moderatorId, title, applyEndDate, tags, } = group; @@ -57,6 +57,7 @@ const StudyGroup = ({ group }) => {
diff --git a/src/components/main/StudyGroups.jsx b/src/components/main/StudyGroups.jsx index f608ea2..53eb1d1 100644 --- a/src/components/main/StudyGroups.jsx +++ b/src/components/main/StudyGroups.jsx @@ -11,12 +11,13 @@ const StudyGroupsWrapper = styled.div` align-content: space-between; `; -const StudyGroups = ({ groups }) => ( +const StudyGroups = ({ groups, realTime }) => ( {groups.map((group) => ( ))} diff --git a/src/containers/groups/StudyGroupsContainer.jsx b/src/containers/groups/StudyGroupsContainer.jsx index e9f5730..d6c1ae6 100644 --- a/src/containers/groups/StudyGroupsContainer.jsx +++ b/src/containers/groups/StudyGroupsContainer.jsx @@ -1,4 +1,4 @@ -import React, { useEffect } from 'react'; +import React, { useEffect, useState } from 'react'; import { useLocation } from 'react-router-dom'; import { useSelector, useDispatch } from 'react-redux'; @@ -6,15 +6,23 @@ import { useSelector, useDispatch } from 'react-redux'; import qs from 'qs'; import { get } from '../../util/utils'; +import useInterval from '../../util/useInterval'; import { loadStudyGroups } from '../../reducers/slice'; + import StudyGroups from '../../components/main/StudyGroups'; const StudyGroupsContainer = () => { const { search } = useLocation(); + const [realTime, setRealTime] = useState(Date.now()); const dispatch = useDispatch(); + const groups = useSelector(get('groups')); + useInterval(() => { + setRealTime(Date.now()); + }, 1000); + useEffect(() => { const { tag } = qs.parse(search, { ignoreQueryPrefix: true, @@ -28,7 +36,10 @@ const StudyGroupsContainer = () => { } return ( - + ); }; diff --git a/src/containers/introduce/IntroduceContainer.jsx b/src/containers/introduce/IntroduceContainer.jsx index a6bc7d6..d17c8a9 100644 --- a/src/containers/introduce/IntroduceContainer.jsx +++ b/src/containers/introduce/IntroduceContainer.jsx @@ -1,13 +1,16 @@ -import React, { useEffect } from 'react'; +import React, { useEffect, useState } from 'react'; import { useDispatch, useSelector } from 'react-redux'; import { get } from '../../util/utils'; +import useInterval from '../../util/useInterval'; import { loadStudyGroup } from '../../reducers/slice'; import StudyIntroduceForm from '../../components/introduce/StudyIntroduceForm'; const IntroduceContainer = ({ groupId }) => { + const [realTime, setRealTime] = useState(Date.now()); + const dispatch = useDispatch(); useEffect(() => { @@ -16,6 +19,10 @@ const IntroduceContainer = ({ groupId }) => { const group = useSelector(get('group')); + useInterval(() => { + setRealTime(Date.now()); + }, 1000); + if (!group) { return (
로딩중..
@@ -23,7 +30,10 @@ const IntroduceContainer = ({ groupId }) => { } return ( - + ); }; diff --git a/src/util/utils.js b/src/util/utils.js index bdb0a13..748c582 100644 --- a/src/util/utils.js +++ b/src/util/utils.js @@ -5,3 +5,7 @@ export function get(key) { export function equal(key, value) { return (obj) => obj[key] === value; } + +export const isCheckedTimeStatus = ({ + time, applyEndTime, participants, personnel, +}) => (!!((time - applyEndTime >= 0 || participants.length === personnel)));