From 2b98f5b8f88c57a54616f51ef3241ae3bbd59459 Mon Sep 17 00:00:00 2001 From: saseungmin Date: Sun, 13 Dec 2020 01:51:55 +0900 Subject: [PATCH 1/2] Npm install sanitize-html --- package-lock.json | 116 ++++++++++++++++++++++++++++++++++++++++------ package.json | 3 +- 2 files changed, 103 insertions(+), 16 deletions(-) diff --git a/package-lock.json b/package-lock.json index 4ead7cb..f586155 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4217,8 +4217,7 @@ "colorette": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.2.1.tgz", - "integrity": "sha512-puCDz0CzydiSYOrnXpz/PKd69zRrribezjtE9yd4zvytoRc8+RY/KJPvtPFKZS3E3wP6neGyMe0vOTlHO5L3Pw==", - "dev": true + "integrity": "sha512-puCDz0CzydiSYOrnXpz/PKd69zRrribezjtE9yd4zvytoRc8+RY/KJPvtPFKZS3E3wP6neGyMe0vOTlHO5L3Pw==" }, "combined-stream": { "version": "1.0.8", @@ -4832,8 +4831,7 @@ "deepmerge": { "version": "4.2.2", "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", - "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", - "dev": true + "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==" }, "default-gateway": { "version": "4.2.0", @@ -5294,8 +5292,7 @@ "entities": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/entities/-/entities-2.1.0.tgz", - "integrity": "sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w==", - "dev": true + "integrity": "sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w==" }, "errno": { "version": "0.1.7", @@ -9568,6 +9565,11 @@ "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", "dev": true }, + "klona": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.4.tgz", + "integrity": "sha512-ZRbnvdg/NxqzC7L9Uyqzf4psi1OM4Cuc+sJAkQPjO6XkQIJTNbfK2Rsmbw8fx1p2mkZdp2FZYo2+LwXYY/uwIA==" + }, "language-subtag-registry": { "version": "0.3.21", "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.21.tgz", @@ -9609,7 +9611,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/line-column/-/line-column-1.0.2.tgz", "integrity": "sha1-0lryk2tvSEkXKzEuR5LR2Ye8NKI=", - "dev": true, "requires": { "isarray": "^1.0.0", "isobject": "^2.0.0" @@ -9618,14 +9619,12 @@ "isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" }, "isobject": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", - "dev": true, "requires": { "isarray": "1.0.0" } @@ -10096,8 +10095,7 @@ "nanoid": { "version": "3.1.16", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.16.tgz", - "integrity": "sha512-+AK8MN0WHji40lj8AEuwLOvLSbWYApQpre/aFJZD71r43wVRLrOYS4FmJOPQYon1TqB462RzrrxlfA74XRES8w==", - "dev": true + "integrity": "sha512-+AK8MN0WHji40lj8AEuwLOvLSbWYApQpre/aFJZD71r43wVRLrOYS4FmJOPQYon1TqB462RzrrxlfA74XRES8w==" }, "nanomatch": { "version": "1.2.13", @@ -10657,6 +10655,11 @@ "integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=", "dev": true }, + "parse-srcset": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/parse-srcset/-/parse-srcset-1.0.2.tgz", + "integrity": "sha1-8r0iH2zJcKk42IVWq8WJyqqiveE=" + }, "parse5": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.1.tgz", @@ -10880,7 +10883,6 @@ "version": "8.1.7", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.1.7.tgz", "integrity": "sha512-llCQW1Pz4MOPwbZLmOddGM9eIJ8Bh7SZ2Oj5sxZva77uVaotYDsYTch1WBTNu7fUY0fpWp0fdt7uW40D4sRiiQ==", - "dev": true, "requires": { "colorette": "^1.2.1", "line-column": "^1.0.2", @@ -10891,8 +10893,7 @@ "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" } } }, @@ -12222,6 +12223,91 @@ } } }, + "sanitize-html": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/sanitize-html/-/sanitize-html-2.2.0.tgz", + "integrity": "sha512-UXd7Rjb5qJHixoUtBLZflfEsJ2kzFsLaKBcWUBTr3G0gXRpZqkzqhIxY79Kl4oju7N4YHTM5TnBtw4scsxyj8A==", + "requires": { + "deepmerge": "^4.2.2", + "escape-string-regexp": "^4.0.0", + "htmlparser2": "^4.1.0", + "is-plain-object": "^5.0.0", + "klona": "^2.0.3", + "parse-srcset": "^1.0.2", + "postcss": "^8.0.2" + }, + "dependencies": { + "dom-serializer": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.2.0.tgz", + "integrity": "sha512-n6kZFH/KlCrqs/1GHMOd5i2fd/beQHuehKdWvNNffbGHTr/almdhuVvTVFb3V7fglz+nC50fFusu3lY33h12pA==", + "requires": { + "domelementtype": "^2.0.1", + "domhandler": "^4.0.0", + "entities": "^2.0.0" + }, + "dependencies": { + "domhandler": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.0.0.tgz", + "integrity": "sha512-KPTbnGQ1JeEMQyO1iYXoagsI6so/C96HZiFyByU3T6iAzpXn8EGEvct6unm1ZGoed8ByO2oirxgwxBmqKF9haA==", + "requires": { + "domelementtype": "^2.1.0" + } + } + } + }, + "domelementtype": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.1.0.tgz", + "integrity": "sha512-LsTgx/L5VpD+Q8lmsXSHW2WpA+eBlZ9HPf3erD1IoPF00/3JKHZ3BknUVA2QGDNu69ZNmyFmCWBSO45XjYKC5w==" + }, + "domhandler": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-3.3.0.tgz", + "integrity": "sha512-J1C5rIANUbuYK+FuFL98650rihynUOEzRLxW+90bKZRWB6A1X1Tf82GxR1qAWLyfNPRvjqfip3Q5tdYlmAa9lA==", + "requires": { + "domelementtype": "^2.0.1" + } + }, + "domutils": { + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.4.4.tgz", + "integrity": "sha512-jBC0vOsECI4OMdD0GC9mGn7NXPLb+Qt6KW1YDQzeQYRUFKmNG8lh7mO5HiELfr+lLQE7loDVI4QcAxV80HS+RA==", + "requires": { + "dom-serializer": "^1.0.1", + "domelementtype": "^2.0.1", + "domhandler": "^4.0.0" + }, + "dependencies": { + "domhandler": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.0.0.tgz", + "integrity": "sha512-KPTbnGQ1JeEMQyO1iYXoagsI6so/C96HZiFyByU3T6iAzpXn8EGEvct6unm1ZGoed8ByO2oirxgwxBmqKF9haA==", + "requires": { + "domelementtype": "^2.1.0" + } + } + } + }, + "htmlparser2": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-4.1.0.tgz", + "integrity": "sha512-4zDq1a1zhE4gQso/c5LP1OtrhYTncXNSpvJYtWJBtXAETPlMfi3IFNjGuQbYLuVY4ZR0QMqRVvo4Pdy9KLyP8Q==", + "requires": { + "domelementtype": "^2.0.1", + "domhandler": "^3.0.0", + "domutils": "^2.0.0", + "entities": "^2.0.0" + } + }, + "is-plain-object": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", + "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==" + } + } + }, "saxes": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz", diff --git a/package.json b/package.json index 05eb15b..e1cbcda 100644 --- a/package.json +++ b/package.json @@ -47,7 +47,8 @@ "react-use": "^15.3.4", "redux": "^4.0.5", "redux-devtools-extension": "^2.13.8", - "redux-logger": "^3.0.6" + "redux-logger": "^3.0.6", + "sanitize-html": "^2.2.0" }, "devDependencies": { "@babel/core": "^7.12.3", From 0f513b4500b30194dc64ad809dca7e6e56b601e1 Mon Sep 17 00:00:00 2001 From: saseungmin Date: Sun, 13 Dec 2020 01:53:19 +0900 Subject: [PATCH 2/2] [Imporve] write page error message - Add validation check logic --- fixtures/write-form.js | 2 +- src/components/write/WriteButtons.jsx | 107 +++++++++--- src/components/write/WriteButtons.test.jsx | 157 ++++++++++++++++-- .../write/WriteButtonsContainer.jsx | 34 +--- .../write/WriteButtonsContainer.test.jsx | 68 -------- src/util/messages.js | 4 + 6 files changed, 233 insertions(+), 139 deletions(-) diff --git a/fixtures/write-form.js b/fixtures/write-form.js index 1ce7831..7e1bda8 100644 --- a/fixtures/write-form.js +++ b/fixtures/write-form.js @@ -1,6 +1,6 @@ const writeForm = { title: '스터디를 소개합니다.1', - contents: '우리는 이것저것 합니다.1', + contents: '

우리는 이것저것 합니다.1

', moderatorId: 'user1', applyEndDate: '2020-12-24 11:00', participants: [], diff --git a/src/components/write/WriteButtons.jsx b/src/components/write/WriteButtons.jsx index 01b8d47..e7e4b38 100644 --- a/src/components/write/WriteButtons.jsx +++ b/src/components/write/WriteButtons.jsx @@ -1,9 +1,12 @@ -import React from 'react'; +import React, { useState } from 'react'; + +import sanitizeHtml from 'sanitize-html'; import styled from '@emotion/styled'; import { css } from '@emotion/react'; import palette from '../../styles/palette'; +import { ERROR_MESSAGE } from '../../util/messages'; import Button from '../../styles/Button'; @@ -42,30 +45,82 @@ const SubmitButton = styled(Button)` padding: 0.45rem 5rem; `; -const WriteButtons = ({ error, onSubmit, onCancel }) => ( - <> - {error && ( - {error} - )} - - - - 등록하기 - - - 취소 - - - - -); +const { + NO_TAG, FAST_APPLY_DEADLINE, NO_CONTENTS, NO_TITLE, NO_APPLY_DATE, ERROR_PERSONNEL, +} = ERROR_MESSAGE; + +const isCheckApplyEndDate = (applyDate) => Date.now() - applyDate >= 0; +const removeHtml = (body) => sanitizeHtml(body, { allowedTags: [] }).trim(); +const isCheckPersonnel = (personnel) => !Number.isInteger(personnel) || personnel < 1; + +const WriteButtons = ({ fields, onSubmit, onCancel }) => { + const [error, setError] = useState(null); + + const { + title, applyEndDate, personnel, contents, tags, + } = fields; + + const applyEndTime = new Date(applyEndDate).getTime(); + + const handleSubmit = () => { + if (!title.trim()) { + setError(NO_TITLE); + return; + } + + if (!applyEndDate.trim()) { + setError(NO_APPLY_DATE); + return; + } + + if (isCheckApplyEndDate(applyEndTime)) { + setError(FAST_APPLY_DEADLINE); + return; + } + + if (isCheckPersonnel(parseInt(personnel, 10))) { + setError(ERROR_PERSONNEL); + return; + } + + if (!removeHtml(contents)) { + setError(NO_CONTENTS); + return; + } + + if (!tags.length) { + setError(NO_TAG); + return; + } + + onSubmit(); + }; + + return ( + <> + {error && ( + {error} + )} + + + + 등록하기 + + + 취소 + + + + + ); +}; export default WriteButtons; diff --git a/src/components/write/WriteButtons.test.jsx b/src/components/write/WriteButtons.test.jsx index 67c18a2..9fff210 100644 --- a/src/components/write/WriteButtons.test.jsx +++ b/src/components/write/WriteButtons.test.jsx @@ -1,35 +1,166 @@ import React from 'react'; -import { render } from '@testing-library/react'; +import { fireEvent, render } from '@testing-library/react'; import WriteButtons from './WriteButtons'; +import WRITE_FROM from '../../../fixtures/write-form'; + describe('WriteButtons', () => { - const renderWriteButtons = (error) => render(( - + const handleSubmit = jest.fn(); + const handleCancel = jest.fn(); + + beforeEach(() => { + jest.clearAllMocks(); + }); + + const renderWriteButtons = (fields) => render(( + )); it('render Write buttons', () => { - const { container } = renderWriteButtons(); + const { container } = renderWriteButtons(WRITE_FROM); expect(container).toHaveTextContent('등록하기'); expect(container).toHaveTextContent('취소'); }); - context('with error message', () => { - const error = 'error'; - it('renders error message', () => { - const { container } = renderWriteButtons(error); + context('with input value', () => { + it('call event submit action', () => { + const { getByText } = renderWriteButtons(WRITE_FROM); + + const button = getByText('등록하기'); + + fireEvent.click(button); + + expect(handleSubmit).toBeCalled(); + }); + + it('call event cancel action', () => { + const { getByText } = renderWriteButtons(WRITE_FROM); + + const button = getByText('취소'); + + fireEvent.click(button); - expect(container).toHaveTextContent(error); + expect(handleCancel).toBeCalled(); }); }); - context('without error message', () => { - it("doesn't renders error message", () => { - const { container } = renderWriteButtons(); + context('with input value null', () => { + describe('When the title is blank', () => { + const fields = { + ...WRITE_FROM, + title: '', + }; + + it('renders error message "Please enter the subject."', () => { + const { container, getByText } = renderWriteButtons(fields); + + fireEvent.click(getByText('등록하기')); + + expect(container).toHaveTextContent('제목을 입력해주세요.'); + }); + }); + + describe('When the applyEndDate is blank', () => { + const fields = { + ...WRITE_FROM, + applyEndDate: '', + }; + + it('renders error message "Please enter the application deadline."', () => { + const { container, getByText } = renderWriteButtons(fields); + + fireEvent.click(getByText('등록하기')); + + expect(container).toHaveTextContent('모집 마감 일자를 입력해주세요.'); + }); + }); + + describe('when personnel error', () => { + const ERROR_PERSONNEL = '참여 인원 수를 입력하지 않았거나, 잘못된 값을 입력하였습니다.'; + + describe("When the personnel isn't number", () => { + const fields = { + ...WRITE_FROM, + personnel: 'e', + }; + + it(`renders error message "You did not enter the number of participants, + or you entered an incorrect value."`, () => { + const { container, getByText } = renderWriteButtons(fields); + + fireEvent.click(getByText('등록하기')); + + expect(container).toHaveTextContent(ERROR_PERSONNEL); + }); + }); + + describe('When personnel is less than 1', () => { + const fields = { + ...WRITE_FROM, + personnel: '-1', + }; + + it(`renders error message "You did not enter the number of participants, + or you entered an incorrect value."`, () => { + const { container, getByText } = renderWriteButtons(fields); + + fireEvent.click(getByText('등록하기')); + + expect(container).toHaveTextContent(ERROR_PERSONNEL); + }); + }); + }); + + describe('When there is no content', () => { + const fields = { + ...WRITE_FROM, + contents: '', + }; + + it('renders error message "Please enter your details."', () => { + const { container, getByText } = renderWriteButtons(fields); + + fireEvent.click(getByText('등록하기')); + + expect(container).toHaveTextContent('내용을 입력해주세요.'); + }); + }); + + describe('When the length of tags is 0', () => { + const fields = { + ...WRITE_FROM, + tags: [], + }; + + it('renders error message "Please enter a tag."', () => { + const { container, getByText } = renderWriteButtons(fields); + + fireEvent.click(getByText('등록하기')); + + expect(container).toHaveTextContent('태그를 입력하세요.'); + }); + }); + + describe('When the application deadline is earlier than the current time', () => { + const fields = { + ...WRITE_FROM, + applyEndDate: '2020-10-01', + }; + + it('renders error message "The application deadline is earlier than the current time."', () => { + const { container, getByText } = renderWriteButtons(fields); + + fireEvent.click(getByText('등록하기')); - expect(container).not.toHaveTextContent('error'); + expect(container).toHaveTextContent('접수 마감날짜가 현재 시간보다 빠릅니다.'); + }); }); }); }); diff --git a/src/containers/write/WriteButtonsContainer.jsx b/src/containers/write/WriteButtonsContainer.jsx index f59be4a..47d4fc0 100644 --- a/src/containers/write/WriteButtonsContainer.jsx +++ b/src/containers/write/WriteButtonsContainer.jsx @@ -1,21 +1,14 @@ -import React, { useEffect, useCallback, useState } from 'react'; +import React, { useEffect, useCallback } from 'react'; import { useDispatch, useSelector } from 'react-redux'; import { useHistory } from 'react-router-dom'; -import { ERROR_MESSAGE } from '../../util/messages'; -import { getAuth, getGroup, isCheckValidate } from '../../util/utils'; +import { getAuth, getGroup } from '../../util/utils'; import { writeStudyGroup } from '../../reducers/groupSlice'; import WriteButtons from '../../components/write/WriteButtons'; -const isCheckApplyEndDate = (applyDate) => Date.now() - applyDate >= 0; - -const { NO_INPUT, NO_TAG, FAST_APPLY_DEADLINE } = ERROR_MESSAGE; - const WriteButtonsContainer = () => { - const [error, setError] = useState(null); - const history = useHistory(); const dispatch = useDispatch(); @@ -23,12 +16,6 @@ const WriteButtonsContainer = () => { const groupId = useSelector(getGroup('groupId')); const user = useSelector(getAuth('user')); - const { - title, applyEndDate, personnel, tags, - } = writeField; - - const applyEndTime = new Date(applyEndDate).getTime(); - useEffect(() => { if (!user) { history.push('/'); @@ -36,21 +23,6 @@ const WriteButtonsContainer = () => { }, [user, history]); const onSubmit = () => { - if (isCheckValidate([title, applyEndDate, personnel])) { - setError(NO_INPUT); - return; - } - - if (!tags.length) { - setError(NO_TAG); - return; - } - - if (isCheckApplyEndDate(applyEndTime)) { - setError(FAST_APPLY_DEADLINE); - return; - } - dispatch(writeStudyGroup()); }; @@ -66,7 +38,7 @@ const WriteButtonsContainer = () => { return ( diff --git a/src/containers/write/WriteButtonsContainer.test.jsx b/src/containers/write/WriteButtonsContainer.test.jsx index f67528d..4beaf7c 100644 --- a/src/containers/write/WriteButtonsContainer.test.jsx +++ b/src/containers/write/WriteButtonsContainer.test.jsx @@ -99,74 +99,6 @@ describe('WriteButtonsContainer', () => { }); }); }); - - context('with input value null, so validation check failure', () => { - describe('When the title and applyEndDate, personnel are blank', () => { - given('writeField', () => ({ - title: '', - contents: '우리는 이것저것 합니다.1', - moderatorId: 'user1', - applyEndDate: '', - participants: [], - personnel: '', - tags: [ - 'JavaScript', - 'Algorithm', - ], - })); - - it('renders error message "There are some items that have not been entered."', () => { - const { container, getByText } = renderWriteButtonsContainer(); - - fireEvent.click(getByText('등록하기')); - - expect(container).toHaveTextContent('입력이 안된 사항이 있습니다.'); - }); - }); - - describe('When the length of tags is 0', () => { - given('writeField', () => ({ - title: '123', - contents: '우리는 이것저것 합니다.1', - moderatorId: 'user1', - applyEndDate: new Date().toString(), - participants: [], - personnel: '1', - tags: [], - })); - - it('renders error message "Please enter a tag."', () => { - const { container, getByText } = renderWriteButtonsContainer(); - - fireEvent.click(getByText('등록하기')); - - expect(container).toHaveTextContent('태그를 입력하세요.'); - }); - }); - - describe('When the application deadline is earlier than the current time', () => { - given('writeField', () => ({ - title: '123', - contents: '우리는 이것저것 합니다.1', - moderatorId: 'user1', - applyEndDate: '2020-10-01', - participants: [], - personnel: '1', - tags: [ - 'javascript', - 'react', - ], - })); - - it('renders error message "The application deadline is earlier than the current time."', () => { - const { container, getByText } = renderWriteButtonsContainer(); - - fireEvent.click(getByText('등록하기')); - - expect(container).toHaveTextContent('접수 마감날짜가 현재 시간보다 빠릅니다.'); - }); - }); - }); }); context('without user', () => { diff --git a/src/util/messages.js b/src/util/messages.js index cf5f7f6..63eec9d 100644 --- a/src/util/messages.js +++ b/src/util/messages.js @@ -6,6 +6,10 @@ export const ERROR_MESSAGE = { FAILURE_REGISTER: '회원가입에 실패하였습니다.', FAILURE_LOGIN: '로그인에 실패하였습니다.', NO_LOGGED_IN: '로그인 후 이용하세요.', + NO_CONTENTS: '내용을 입력해주세요.', + NO_TITLE: '제목을 입력해주세요.', + NO_APPLY_DATE: '모집 마감 일자를 입력해주세요.', + ERROR_PERSONNEL: '참여 인원 수를 입력하지 않았거나, 잘못된 값을 입력하였습니다.', }; export const FIREBASE_AUTH_ERROR_MESSAGE = {