diff --git a/src/components/introduce/IntroduceHeader.jsx b/src/components/introduce/IntroduceHeader.jsx
index 6909f17..0c0de51 100644
--- a/src/components/introduce/IntroduceHeader.jsx
+++ b/src/components/introduce/IntroduceHeader.jsx
@@ -24,7 +24,7 @@ const IntroduceHeaderWrapper = styled.div`
`;
const IntroduceHeader = ({
- group, onApply, user, realTime, onApplyCancel, onChangeApplyFields, applyFields,
+ group, onApply, user, realTime, onApplyCancel, onChangeApplyFields, applyFields, clearForm,
}) => {
const [loginCheckModal, setLoginCheckModal] = useState(false);
const [applyCancelModal, setApplyCancelModal] = useState(false);
@@ -69,6 +69,7 @@ const IntroduceHeader = ({
const handleFormCancel = () => {
setModalForm(false);
+ clearForm();
};
return (
diff --git a/src/components/introduce/IntroduceHeader.test.jsx b/src/components/introduce/IntroduceHeader.test.jsx
index 2260338..124c174 100644
--- a/src/components/introduce/IntroduceHeader.test.jsx
+++ b/src/components/introduce/IntroduceHeader.test.jsx
@@ -9,6 +9,7 @@ import STUDY_GROUP from '../../../fixtures/study-group';
describe('IntroduceHeader', () => {
const handleApply = jest.fn();
const handleApplyCancel = jest.fn();
+ const handleClearForm = jest.fn();
beforeEach(() => {
jest.clearAllMocks();
@@ -18,10 +19,11 @@ describe('IntroduceHeader', () => {
));
@@ -214,7 +216,6 @@ describe('IntroduceHeader', () => {
fireEvent.click(button);
- // TODO: 이 부분은 추후 변경해야된다 현재 스터디 참여 신청서 모달창이 나타남.
fireEvent.click(getByText('확인'));
expect(handleApply).toBeCalled();
diff --git a/src/components/introduce/modals/ApplicationFormModal.jsx b/src/components/introduce/modals/ApplicationFormModal.jsx
index 37c6947..9aa16cb 100644
--- a/src/components/introduce/modals/ApplicationFormModal.jsx
+++ b/src/components/introduce/modals/ApplicationFormModal.jsx
@@ -1,4 +1,4 @@
-import React from 'react';
+import React, { useState } from 'react';
import styled from '@emotion/styled';
@@ -96,6 +96,13 @@ const ContentTextareaWrapper = styled.textarea`
&:focus {
border: 2px solid ${palette.teal[5]};
}
+
+ ${({ error }) => error && css`
+ &::placeholder {
+ color: ${palette.warn[1]};
+ }
+ border: 2px solid ${palette.warn[1]};
+ `};
`;
const StyledButton = styled(Button)`
@@ -107,14 +114,37 @@ const StyledButton = styled(Button)`
const ApplicationFormModal = ({
visible, onCancel, onConfirm, onChangeApply, fields,
}) => {
+ const [error, setError] = useState(null);
+
const { reason, wantToGet } = fields;
const handleChange = (e) => {
const { name, value } = e.target;
+ setError(null);
onChangeApply({ name, value });
};
+ const handleCancel = () => {
+ setError(null);
+ onCancel();
+ };
+
+ const handleConfirm = () => {
+ if (!reason.trim()) {
+ setError('reason');
+ return;
+ }
+
+ if (!wantToGet.trim()) {
+ setError('wantToGet');
+ return;
+ }
+
+ setError(null);
+ onConfirm();
+ };
+
if (!visible) {
return null;
}
@@ -126,6 +156,7 @@ const ApplicationFormModal = ({
- 취소
- 확인
+ 취소
+ 확인
diff --git a/src/components/introduce/modals/ApplicationFormModal.test.jsx b/src/components/introduce/modals/ApplicationFormModal.test.jsx
index bb9479a..7f023ad 100644
--- a/src/components/introduce/modals/ApplicationFormModal.test.jsx
+++ b/src/components/introduce/modals/ApplicationFormModal.test.jsx
@@ -9,6 +9,10 @@ describe('ApplicationFormModal', () => {
const handleConfirm = jest.fn();
const handleChange = jest.fn();
+ beforeEach(() => {
+ jest.clearAllMocks();
+ });
+
const renderApplicationFormModal = ({ visible, fields }) => render((
{
));
context('with visible', () => {
- const modal = {
- visible: true,
- fields: {
- reason: '',
- wantToGet: '',
- },
- };
+ context('with applyFields value', () => {
+ const modal = {
+ visible: true,
+ fields: {
+ reason: 'reason',
+ wantToGet: 'wantToGet',
+ },
+ };
- it('renders Modal text', () => {
- const { container } = renderApplicationFormModal(modal);
+ it('renders Modal text', () => {
+ const { container } = renderApplicationFormModal(modal);
- expect(container).toHaveTextContent('스터디 참여 신청서 📚');
- expect(container).toHaveTextContent('신청하게 된 이유');
- expect(container).toHaveTextContent('스터디를 통해 얻고 싶은 것은 무엇인가요?');
- });
+ expect(container).toHaveTextContent('스터디 참여 신청서 📚');
+ expect(container).toHaveTextContent('신청하게 된 이유');
+ expect(container).toHaveTextContent('스터디를 통해 얻고 싶은 것은 무엇인가요?');
+ });
- it('calls confirm event action', () => {
- const { getByText } = renderApplicationFormModal(modal);
+ it('calls confirm event action', () => {
+ const { getByText } = renderApplicationFormModal(modal);
- const button = getByText('확인');
+ const button = getByText('확인');
- fireEvent.click(button);
+ fireEvent.click(button);
- expect(handleConfirm).toBeCalled();
- });
+ expect(handleConfirm).toBeCalled();
+ });
+
+ it('calls cancel event action', () => {
+ const { getByText } = renderApplicationFormModal(modal);
- it('calls cancel event action', () => {
- const { getByText } = renderApplicationFormModal(modal);
+ const button = getByText('취소');
- const button = getByText('취소');
+ fireEvent.click(button);
- fireEvent.click(button);
+ expect(handleCancel).toBeCalled();
+ });
- expect(handleCancel).toBeCalled();
+ it('change apply form fields', () => {
+ const { getByLabelText } = renderApplicationFormModal(modal);
+
+ const input = getByLabelText('신청하게 된 이유');
+
+ fireEvent.change(input, { target: { name: 'reason', value: '내용' } });
+
+ expect(handleChange).toBeCalled();
+ });
});
- it('change apply form fields', () => {
- const { getByLabelText } = renderApplicationFormModal(modal);
+ context('without applyFields value', () => {
+ it("doesn't reason value", () => {
+ const modal = {
+ visible: true,
+ fields: {
+ reason: '',
+ wantToGet: 'wantToGet',
+ },
+ };
+
+ const { getByText, getByLabelText } = renderApplicationFormModal(modal);
+
+ const button = getByText('확인');
+
+ fireEvent.click(button);
+
+ expect(handleConfirm).not.toBeCalled();
+
+ expect(getByLabelText('신청하게 된 이유')).toHaveStyle('border: 2px solid #ff8787;');
+ });
+
+ it("doesn't wantToGet value", () => {
+ const modal = {
+ visible: true,
+ fields: {
+ reason: 'reason',
+ wantToGet: '',
+ },
+ };
+
+ const { getByText, getByLabelText } = renderApplicationFormModal(modal);
+
+ const button = getByText('확인');
- const input = getByLabelText('신청하게 된 이유');
+ fireEvent.click(button);
- fireEvent.change(input, { target: { name: 'reason', value: '내용' } });
+ expect(handleConfirm).not.toBeCalled();
- expect(handleChange).toBeCalled();
+ expect(getByLabelText('스터디를 통해 얻고 싶은 것은 무엇인가요?')).toHaveStyle('border: 2px solid #ff8787;');
+ });
});
});
diff --git a/src/containers/introduce/IntroduceContainer.jsx b/src/containers/introduce/IntroduceContainer.jsx
index 856f6d4..472a274 100644
--- a/src/containers/introduce/IntroduceContainer.jsx
+++ b/src/containers/introduce/IntroduceContainer.jsx
@@ -5,7 +5,7 @@ import { useDispatch, useSelector } from 'react-redux';
import { getAuth, getGroup } from '../../util/utils';
import {
- changeApplyFields, deleteParticipant, loadStudyGroup, updateParticipant,
+ changeApplyFields, clearApplyFields, deleteParticipant, loadStudyGroup, updateParticipant,
} from '../../reducers/groupSlice';
import StudyIntroduceForm from '../../components/introduce/StudyIntroduceForm';
@@ -41,6 +41,10 @@ const IntroduceContainer = ({ groupId }) => {
dispatch(changeApplyFields({ name, value }));
}, [dispatch]);
+ const clearApplyForm = useCallback(() => {
+ dispatch(clearApplyFields());
+ }, [dispatch]);
+
if (!group) {
return (
@@ -56,6 +60,7 @@ const IntroduceContainer = ({ groupId }) => {
applyFields={applyFields}
onApply={onApplyStudy}
onApplyCancel={onApplyCancel}
+ clearForm={clearApplyForm}
onChangeApplyFields={onChangeApplyFields}
/>
{
given('group', () => (STUDY_GROUP));
given('user', () => ('user'));
given('applyFields', () => ({
- reason: '',
- wantToGet: '',
+ reason: 'reason',
+ wantToGet: 'wantToGet',
}));
it('click event dispatches action call updateParticipant', () => {
@@ -101,7 +101,6 @@ describe('IntroduceContainer', () => {
fireEvent.click(button);
- // TODO: 이 부분은 추후 수정해야된다. 현재 스터디 참여 신청서 모달창으로 인해 테스트 fail되기 때문에 변경해놈
fireEvent.click(getByText('확인'));
expect(dispatch).toBeCalledTimes(2);
diff --git a/src/reducers/groupSlice.js b/src/reducers/groupSlice.js
index a052471..7cf5185 100644
--- a/src/reducers/groupSlice.js
+++ b/src/reducers/groupSlice.js
@@ -76,6 +76,13 @@ const { actions, reducer } = createSlice({
draft.applyFields[name] = value;
});
},
+
+ clearApplyFields(state) {
+ return {
+ ...state,
+ applyFields: applyInitialState,
+ };
+ },
},
});
@@ -86,6 +93,7 @@ export const {
clearWriteFields,
successWrite,
changeApplyFields,
+ clearApplyFields,
} = actions;
export const loadStudyGroups = (tag) => async (dispatch) => {
@@ -142,6 +150,7 @@ export const updateParticipant = ({ reason, wantToGet }) => async (dispatch, get
});
dispatch(setStudyGroup(newGroup));
+ dispatch(clearApplyFields());
};
export const deleteParticipant = () => async (dispatch, getState) => {
diff --git a/src/reducers/groupSlice.test.js b/src/reducers/groupSlice.test.js
index 501007d..51262db 100644
--- a/src/reducers/groupSlice.test.js
+++ b/src/reducers/groupSlice.test.js
@@ -15,6 +15,7 @@ import reducer, {
updateParticipant,
deleteParticipant,
changeApplyFields,
+ clearApplyFields,
} from './groupSlice';
import STUDY_GROUPS from '../../fixtures/study-groups';
@@ -151,6 +152,24 @@ describe('reducer', () => {
expect(state.applyFields.reason).toBe('참여합니다.');
});
});
+
+ describe('clearApplyFields', () => {
+ const initialState = {
+ applyFields: {
+ reason: '타이틀',
+ wantToGet: '내용',
+ },
+ };
+
+ it('clears fields of application', () => {
+ const state = reducer(initialState, clearApplyFields());
+
+ const { applyFields: { reason, wantToGet } } = state;
+
+ expect(reason).toBe('');
+ expect(wantToGet).toBe('');
+ });
+ });
});
describe('async actions', () => {
@@ -237,7 +256,7 @@ describe('async actions', () => {
wantToGet: '원하는 것',
};
- it('dispatches setStudyGroup', async () => {
+ it('dispatches setStudyGroup and clearApplyFields', async () => {
await store.dispatch(updateParticipant(applyFields));
const actions = store.getActions();
@@ -250,6 +269,7 @@ describe('async actions', () => {
confirm: false,
}],
}));
+ expect(actions[1]).toEqual(clearApplyFields());
});
});