From 1d9c60781e5ee7ff091103ccd2c3a6f750210bd3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EC=A7=84=ED=98=B8?= Date: Fri, 16 Aug 2024 15:51:38 +0900 Subject: [PATCH 1/6] =?UTF-8?q?refactor:=20errorMessage=20=ED=83=80?= =?UTF-8?q?=EC=9E=85=EC=9D=84=20string=20|=20undefined=EC=97=90=EC=84=9C?= =?UTF-8?q?=20string=20|=20null=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/utils/validate/type.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/utils/validate/type.ts b/client/src/utils/validate/type.ts index ba8b0953b..df81f1644 100644 --- a/client/src/utils/validate/type.ts +++ b/client/src/utils/validate/type.ts @@ -1,5 +1,5 @@ export interface ValidateResult { isValid: boolean; - errorMessage?: string; + errorMessage: string | null; errorInfo?: Record; } From a7afaa1b3ac718463cc934315b797c81720fcf29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EC=A7=84=ED=98=B8?= Date: Fri, 16 Aug 2024 15:51:59 +0900 Subject: [PATCH 2/6] =?UTF-8?q?refactor:=20=EC=97=90=EB=9F=AC=EA=B0=80=20?= =?UTF-8?q?=EC=95=84=EB=8B=90=20=EB=95=8C=20errorMessage=EB=A5=BC=20null?= =?UTF-8?q?=EB=A1=9C=20=EB=A6=AC=ED=84=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/utils/validate/validateEventName.ts | 4 ++-- client/src/utils/validate/validateEventPassword.ts | 4 ++-- client/src/utils/validate/validateMemberName.ts | 2 +- client/src/utils/validate/validatePurchase.ts | 6 +++--- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/client/src/utils/validate/validateEventName.ts b/client/src/utils/validate/validateEventName.ts index b390f12b9..93f4ecef1 100644 --- a/client/src/utils/validate/validateEventName.ts +++ b/client/src/utils/validate/validateEventName.ts @@ -1,4 +1,4 @@ -import ERROR_MESSAGE from '@constants/errorMessage'; +import {ERROR_MESSAGE} from '@constants/errorMessage'; import RULE from '@constants/rule'; import {ValidateResult} from './type'; @@ -7,7 +7,7 @@ const validateEventName = (name: string): ValidateResult => { if (name.length > RULE.maxEventNameLength) { return {isValid: false, errorMessage: ERROR_MESSAGE.eventName}; } - return {isValid: true}; + return {isValid: true, errorMessage: null}; }; export default validateEventName; diff --git a/client/src/utils/validate/validateEventPassword.ts b/client/src/utils/validate/validateEventPassword.ts index 70499e393..7075e2f3e 100644 --- a/client/src/utils/validate/validateEventPassword.ts +++ b/client/src/utils/validate/validateEventPassword.ts @@ -1,4 +1,4 @@ -import ERROR_MESSAGE from '@constants/errorMessage'; +import {ERROR_MESSAGE} from '@constants/errorMessage'; import REGEXP from '@constants/regExp'; import {ValidateResult} from './type'; @@ -7,7 +7,7 @@ const validateEventPassword = (password: string): ValidateResult => { if (!REGEXP.eventPassword.test(password)) { return {isValid: false, errorMessage: ERROR_MESSAGE.eventPasswordType}; } - return {isValid: true}; + return {isValid: true, errorMessage: null}; }; export default validateEventPassword; diff --git a/client/src/utils/validate/validateMemberName.ts b/client/src/utils/validate/validateMemberName.ts index 06c7416dd..053028761 100644 --- a/client/src/utils/validate/validateMemberName.ts +++ b/client/src/utils/validate/validateMemberName.ts @@ -16,7 +16,7 @@ const validateMemberName = (name: string): ValidateResult => { }; if (validateOnlyString() && validateLength()) { - return {isValid: true}; + return {isValid: true, errorMessage: null}; } return {isValid: false, errorMessage: ERROR_MESSAGE.memberName}; diff --git a/client/src/utils/validate/validatePurchase.ts b/client/src/utils/validate/validatePurchase.ts index 7c7a4b3d6..9915ce8b7 100644 --- a/client/src/utils/validate/validatePurchase.ts +++ b/client/src/utils/validate/validatePurchase.ts @@ -1,6 +1,6 @@ import type {Bill} from 'types/serviceType'; -import ERROR_MESSAGE from '@constants/errorMessage'; +import {ERROR_MESSAGE} from '@constants/errorMessage'; import RULE from '@constants/rule'; import REGEXP from '@constants/regExp'; @@ -8,7 +8,7 @@ import {ValidateResult} from './type'; const validatePurchase = (inputPair: Bill): ValidateResult => { const {title, price} = inputPair; - let errorMessage; + let errorMessage: string | null = null; const errorInfo = { price: false, @@ -38,7 +38,7 @@ const validatePurchase = (inputPair: Bill): ValidateResult => { }; if (validatePrice() && validateTitle()) { - return {isValid: true, errorMessage: ''}; + return {isValid: true, errorMessage: null}; } return {isValid: false, errorMessage, errorInfo}; From 18e1a65c2e8d4ad894d34073012357f8f3c23db4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EC=A7=84=ED=98=B8?= Date: Fri, 16 Aug 2024 15:53:56 +0900 Subject: [PATCH 3/6] =?UTF-8?q?fix:=20=EC=97=90=EB=9F=AC=20import=20?= =?UTF-8?q?=EB=90=98=EC=A7=80=20=EC=95=8A=EB=8D=98=20=ED=98=84=EC=83=81=20?= =?UTF-8?q?=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/ErrorProvider.tsx | 2 +- client/src/components/Toast/ToastProvider.tsx | 2 +- client/src/constants/errorMessage.ts | 4 +--- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/client/src/ErrorProvider.tsx b/client/src/ErrorProvider.tsx index ef0714c7f..92b93fb60 100644 --- a/client/src/ErrorProvider.tsx +++ b/client/src/ErrorProvider.tsx @@ -1,6 +1,6 @@ import {createContext, useState, useContext, useEffect, ReactNode} from 'react'; -import SERVER_ERROR_MESSAGES from '@constants/errorMessage'; +import {SERVER_ERROR_MESSAGES} from '@constants/errorMessage'; // 에러 컨텍스트 생성 interface ErrorContextType { diff --git a/client/src/components/Toast/ToastProvider.tsx b/client/src/components/Toast/ToastProvider.tsx index 3107e37ac..d842a3a08 100644 --- a/client/src/components/Toast/ToastProvider.tsx +++ b/client/src/components/Toast/ToastProvider.tsx @@ -1,7 +1,7 @@ /** @jsxImportSource @emotion/react */ import {createContext, useContext, useEffect, useState} from 'react'; -import SERVER_ERROR_MESSAGES from '@constants/errorMessage'; +import {SERVER_ERROR_MESSAGES} from '@constants/errorMessage'; import {useError} from '../../ErrorProvider'; diff --git a/client/src/constants/errorMessage.ts b/client/src/constants/errorMessage.ts index e238cf90e..f874f6ff4 100644 --- a/client/src/constants/errorMessage.ts +++ b/client/src/constants/errorMessage.ts @@ -1,6 +1,6 @@ type ErrorMessage = Record; -const SERVER_ERROR_MESSAGES: ErrorMessage = { +export const SERVER_ERROR_MESSAGES: ErrorMessage = { EVENT_NOT_FOUND: '존재하지 않는 행사입니다.', EVENT_NAME_LENGTH_INVALID: '행사 이름은 2자 이상 30자 이하만 입력 가능합니다.', EVENT_NAME_CONSECUTIVE_SPACES: '행사 이름에는 공백 문자가 연속될 수 없습니다.', @@ -45,5 +45,3 @@ export const ERROR_MESSAGE = { }; export const UNKNOWN_ERROR = 'UNKNOWN_ERROR'; - -export default SERVER_ERROR_MESSAGES; From fea31e0fbbb65f6d08567ca22813e27e246f06b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EC=A7=84=ED=98=B8?= Date: Fri, 16 Aug 2024 15:55:40 +0900 Subject: [PATCH 4/6] =?UTF-8?q?refactor:=20=EC=97=90=EB=9F=AC=20=EB=A9=94?= =?UTF-8?q?=EC=8B=9C=EC=A7=80=20validate=20=ED=95=A8=EC=88=98=20=EB=A6=AC?= =?UTF-8?q?=ED=84=B4=ED=95=98=EB=8A=94=20=EB=8C=80=EB=A1=9C=20=EA=B7=B8?= =?UTF-8?q?=EB=8C=80=EB=A1=9C=20set?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/hooks/useDynamicBillActionInput.tsx | 9 ++-- client/src/hooks/useDynamicInput.tsx | 11 ++--- client/src/hooks/usePutAndDeleteBillAction.ts | 8 ++-- client/src/hooks/useSetPassword.ts | 48 +++++++++++++++++++ 4 files changed, 60 insertions(+), 16 deletions(-) create mode 100644 client/src/hooks/useSetPassword.ts diff --git a/client/src/hooks/useDynamicBillActionInput.tsx b/client/src/hooks/useDynamicBillActionInput.tsx index 252b40862..f21311de8 100644 --- a/client/src/hooks/useDynamicBillActionInput.tsx +++ b/client/src/hooks/useDynamicBillActionInput.tsx @@ -14,7 +14,7 @@ export type BillInputType = 'title' | 'price'; const useDynamicBillActionInput = (validateFunc: (inputPair: Bill) => ValidateResult) => { const [inputPairList, setInputPairList] = useState([{title: '', price: '', index: 0}]); const inputRefList = useRef<(HTMLInputElement | null)[]>([]); - const [errorMessage, setErrorMessage] = useState(''); + const [errorMessage, setErrorMessage] = useState(null); const [errorIndexList, setErrorIndexList] = useState([]); const [canSubmit, setCanSubmit] = useState(false); @@ -34,13 +34,14 @@ const useDynamicBillActionInput = (validateFunc: (inputPair: Bill) => ValidateRe [field]: value, }); + setErrorMessage(validationResultMessage); + // TODO: (@weadie) 가독성이 안좋다는 리뷰. 함수로 분리 if ( isLastInputPairFilled({index, field, value}) && targetInputPair.title.trim().length !== 0 && targetInputPair.price.trim().length !== 0 ) { - setErrorMessage(''); setInputPairList(prevInputPairList => { const updatedInputPairList = [...prevInputPairList]; @@ -52,19 +53,17 @@ const useDynamicBillActionInput = (validateFunc: (inputPair: Bill) => ValidateRe }); } else if (isValidInput) { // 입력된 값이 유효하면 데이터(inputLis)를 변경합니다. - setErrorMessage(''); if (errorIndexList.includes(index)) { setErrorIndexList(prev => prev.filter(i => i !== index)); } changeInputListValue(index, value, field); } else if (value.length === 0) { - setErrorMessage(''); + setErrorMessage(null); changeErrorIndex(index); changeInputListValue(index, value, field); } else { - setErrorMessage(validationResultMessage ?? ''); changeErrorIndex(targetInputPair.index); } diff --git a/client/src/hooks/useDynamicInput.tsx b/client/src/hooks/useDynamicInput.tsx index 3584d3a05..77e25098c 100644 --- a/client/src/hooks/useDynamicInput.tsx +++ b/client/src/hooks/useDynamicInput.tsx @@ -12,7 +12,7 @@ export type ReturnUseDynamicInput = { inputRefList: React.MutableRefObject<(HTMLInputElement | null)[]>; handleInputChange: (index: number, event: React.ChangeEvent) => void; deleteEmptyInputElementOnBlur: () => void; - errorMessage: string; + errorMessage: string | null; getFilledInputList: (list?: InputValue[]) => InputValue[]; focusNextInputOnEnter: (e: React.KeyboardEvent, index: number) => void; canSubmit: boolean; @@ -23,7 +23,7 @@ export type ReturnUseDynamicInput = { const useDynamicInput = (validateFunc: (name: string) => ValidateResult): ReturnUseDynamicInput => { const [inputList, setInputList] = useState([{index: 0, value: ''}]); const inputRefList = useRef<(HTMLInputElement | null)[]>([]); - const [errorMessage, setErrorMessage] = useState(''); + const [errorMessage, setErrorMessage] = useState(null); const [errorIndexList, setErrorIndexList] = useState([]); const [canSubmit, setCanSubmit] = useState(false); @@ -62,11 +62,10 @@ const useDynamicInput = (validateFunc: (name: string) => ValidateResult): Return // onChange와 setValue 둘 다 지원하기 위해서 validate를 분리 const validateAndSetTargetInput = (index: number, value: string) => { const {isValid: isValidInput, errorMessage: validationResultMessage} = validateFunc(value); + setErrorMessage(validationResultMessage); if (isValidInput) { // 입력된 값이 유효하면 데이터(inputList)를 변경합니다. - setErrorMessage(''); - if (errorIndexList.includes(index)) { setErrorIndexList(prev => prev.filter(i => i !== index)); } @@ -75,7 +74,7 @@ const useDynamicInput = (validateFunc: (name: string) => ValidateResult): Return } else if (value.length === 0) { // value의 값이 0이라면 errorMessage는 띄워지지 않지만 값은 변경됩니다. 또한 invalid한 값이기에 errorIndex에 추가합니다. - setErrorMessage(''); + setErrorMessage(null); changeErrorIndex(index); changeInputListValue(index, value); @@ -83,8 +82,6 @@ const useDynamicInput = (validateFunc: (name: string) => ValidateResult): Return // 유효성 검사에 실패한 입력입니다. 에러 메세지를 세팅합니다. const targetInput = findInputByIndex(index); - - setErrorMessage(validationResultMessage ?? ''); changeErrorIndex(targetInput.index); } }; diff --git a/client/src/hooks/usePutAndDeleteBillAction.ts b/client/src/hooks/usePutAndDeleteBillAction.ts index 9cb399ef8..925f591e8 100644 --- a/client/src/hooks/usePutAndDeleteBillAction.ts +++ b/client/src/hooks/usePutAndDeleteBillAction.ts @@ -12,7 +12,7 @@ import {useFetch} from '@apis/useFetch'; import getEventIdByUrl from '@utils/getEventIdByUrl'; -import ERROR_MESSAGE from '@constants/errorMessage'; +import {ERROR_MESSAGE} from '@constants/errorMessage'; const usePutAndDeleteBillAction = ( initialValue: InputPair, @@ -26,7 +26,7 @@ const usePutAndDeleteBillAction = ( const [inputPair, setInputPair] = useState(initialValue); const [canSubmit, setCanSubmit] = useState(false); const [errorInfo, setErrorInfo] = useState>({title: false, price: false}); - const [errorMessage, setErrorMessage] = useState(); + const [errorMessage, setErrorMessage] = useState(null); const handleInputChange = (field: BillInputType, event: React.ChangeEvent) => { const {value} = event.target; @@ -42,9 +42,10 @@ const usePutAndDeleteBillAction = ( const {isValid, errorMessage, errorInfo} = validateFunc(getFieldValue()); + setErrorMessage(errorMessage); + if (isValid) { // valid일 경우 에러메시지 nope, setValue, submit은 value가 비지 않았을 때 true를 설정 - setErrorMessage(undefined); setInputPair(prevInputPair => { return { ...prevInputPair, @@ -55,7 +56,6 @@ const usePutAndDeleteBillAction = ( } else { // valid하지 않으면 event.target.value 덮어쓰기 event.target.value = inputPair[field]; - setErrorMessage(errorMessage); setCanSubmit(false); } diff --git a/client/src/hooks/useSetPassword.ts b/client/src/hooks/useSetPassword.ts new file mode 100644 index 000000000..8e8cf9c8c --- /dev/null +++ b/client/src/hooks/useSetPassword.ts @@ -0,0 +1,48 @@ +import {useState} from 'react'; + +import validateEventPassword from '@utils/validate/validateEventPassword'; + +import {useFetch} from '@apis/useFetch'; + +import RULE from '@constants/rule'; + +import useEvent from './useEvent'; + +const useSetPassword = (eventName: string) => { + const {fetch} = useFetch(); + const [password, setPassword] = useState(''); + const [errorMessage, setErrorMessage] = useState(null); + const [canSubmit, setCanSubmit] = useState(false); + const {createNewEvent} = useEvent(); + + const submitPassword = async (event: React.FormEvent) => { + event.preventDefault(); + + const {eventId} = await fetch({queryFunction: () => createNewEvent({eventName, password: parseInt(password)})}); + return eventId; + }; + + const handlePasswordChange = (event: React.ChangeEvent) => { + const newValue = event.target.value; + const {isValid, errorMessage} = validateEventPassword(newValue); + + setCanSubmit(newValue.length === RULE.maxEventPasswordLength); + setErrorMessage(errorMessage); + + if (isValid) { + setPassword(newValue); + } else { + event.target.value = password; + } + }; + + return { + password, + errorMessage, + canSubmit, + submitPassword, + handlePasswordChange, + }; +}; + +export default useSetPassword; From 01e0a15e9c4bb1afa2b9b792fbc2160893d9982d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EC=A7=84=ED=98=B8?= Date: Fri, 16 Aug 2024 15:57:45 +0900 Subject: [PATCH 5/6] =?UTF-8?q?feat:=20=EC=97=90=EB=9F=AC=EB=A9=94?= =?UTF-8?q?=EC=8B=9C=EC=A7=80=20=EB=B3=B4=EC=97=AC=EC=A7=80=EB=8F=84?= =?UTF-8?q?=EB=A1=9D=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../AddBillActionListModalContent.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/client/src/components/Modal/SetActionModal/AddBillActionListModalContent/AddBillActionListModalContent.tsx b/client/src/components/Modal/SetActionModal/AddBillActionListModalContent/AddBillActionListModalContent.tsx index 239bc0d2d..cc49d5953 100644 --- a/client/src/components/Modal/SetActionModal/AddBillActionListModalContent/AddBillActionListModalContent.tsx +++ b/client/src/components/Modal/SetActionModal/AddBillActionListModalContent/AddBillActionListModalContent.tsx @@ -1,4 +1,5 @@ import {FixedButton, LabelGroupInput} from 'haengdong-design'; +import {useEffect} from 'react'; import validatePurchase from '@utils/validate/validatePurchase'; @@ -15,6 +16,7 @@ const AddBillActionListModalContent = ({setIsOpenBottomSheet}: AddBillActionList const { inputPairList, inputRefList, + errorMessage, errorIndexList, handleInputChange, getFilledInputPairList, @@ -34,7 +36,7 @@ const AddBillActionListModalContent = ({setIsOpenBottomSheet}: AddBillActionList return (
- + {inputPairList.map(({index, title, price}) => (
Date: Fri, 16 Aug 2024 15:58:15 +0900 Subject: [PATCH 6/6] =?UTF-8?q?refactor:=20=EC=97=90=EB=9F=AC=EB=A9=94?= =?UTF-8?q?=EC=8B=9C=EC=A7=80=20=ED=83=80=EC=9E=85=20string=20|=20null?= =?UTF-8?q?=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/LabelGroupInput/LabelGroupInput.type.ts | 2 +- HDesign/src/components/LabelInput/LabelInput.tsx | 8 +++++--- HDesign/src/components/LabelInput/LabelInput.type.ts | 2 +- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/HDesign/src/components/LabelGroupInput/LabelGroupInput.type.ts b/HDesign/src/components/LabelGroupInput/LabelGroupInput.type.ts index cfa938457..8507311b5 100644 --- a/HDesign/src/components/LabelGroupInput/LabelGroupInput.type.ts +++ b/HDesign/src/components/LabelGroupInput/LabelGroupInput.type.ts @@ -2,7 +2,7 @@ export interface LabelGroupInputStyleProps {} export interface LabelGroupInputCustomProps { labelText: string; - errorText?: string; + errorText: string | null; } export type LabelGroupInputOptionProps = LabelGroupInputStyleProps & LabelGroupInputCustomProps; diff --git a/HDesign/src/components/LabelInput/LabelInput.tsx b/HDesign/src/components/LabelInput/LabelInput.tsx index f9dd3b71a..43f60c220 100644 --- a/HDesign/src/components/LabelInput/LabelInput.tsx +++ b/HDesign/src/components/LabelInput/LabelInput.tsx @@ -29,9 +29,11 @@ const LabelInput: React.FC = forwardRef {labelText} - - {errorText} - + {errorText && ( + + {errorText} + + )} diff --git a/HDesign/src/components/LabelInput/LabelInput.type.ts b/HDesign/src/components/LabelInput/LabelInput.type.ts index ec24b3a30..83e7e9751 100644 --- a/HDesign/src/components/LabelInput/LabelInput.type.ts +++ b/HDesign/src/components/LabelInput/LabelInput.type.ts @@ -2,7 +2,7 @@ export interface LabelInputStyleProps {} export interface LabelInputCustomProps { labelText: string; - errorText?: string; + errorText: string | null; isError?: boolean; autoFocus: boolean; }