From 7d54702f4fd11a455323b47dd6b93b18a8fb0338 Mon Sep 17 00:00:00 2001 From: JinHo Kim <81083461+jinhokim98@users.noreply.github.com> Date: Fri, 16 Aug 2024 17:56:51 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20Input=20=EA=B2=80=EC=A6=9D=20=EC=97=90?= =?UTF-8?q?=EB=9F=AC=20=EB=A9=94=EC=8B=9C=EC=A7=80=20=ED=83=80=EC=9E=85=20?= =?UTF-8?q?=EA=B5=AC=EC=A1=B0=20=EB=B3=80=EA=B2=BD=20(#376)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * refactor: errorMessage 타입을 string | undefined에서 string | null로 변경 * refactor: 에러가 아닐 때 errorMessage를 null로 리턴 * fix: 에러 import 되지 않던 현상 해결 * refactor: 에러 메시지 validate 함수 리턴하는 대로 그대로 set * feat: 에러메시지 보여지도록 추가 * refactor: 에러메시지 타입 string | null로 변경 --- .../LabelGroupInput/LabelGroupInput.type.ts | 2 +- HDesign/src/components/LabelInput/LabelInput.tsx | 8 +++++--- HDesign/src/components/LabelInput/LabelInput.type.ts | 2 +- client/src/ErrorProvider.tsx | 2 +- .../AddBillActionListModalContent.tsx | 4 +++- client/src/components/Toast/ToastProvider.tsx | 2 +- client/src/constants/errorMessage.ts | 4 +--- client/src/hooks/useDynamicBillActionInput.tsx | 9 ++++----- client/src/hooks/useDynamicInput.tsx | 11 ++++------- client/src/hooks/usePutAndDeleteBillAction.ts | 8 ++++---- client/src/hooks/useSetPassword.ts | 5 ++--- client/src/utils/validate/type.ts | 2 +- 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 +++--- 16 files changed, 36 insertions(+), 39 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; } 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/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}) => (
; -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; 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 index 0ba5e7272..8e8cf9c8c 100644 --- a/client/src/hooks/useSetPassword.ts +++ b/client/src/hooks/useSetPassword.ts @@ -11,7 +11,7 @@ import useEvent from './useEvent'; const useSetPassword = (eventName: string) => { const {fetch} = useFetch(); const [password, setPassword] = useState(''); - const [errorMessage, setErrorMessage] = useState(''); + const [errorMessage, setErrorMessage] = useState(null); const [canSubmit, setCanSubmit] = useState(false); const {createNewEvent} = useEvent(); @@ -27,13 +27,12 @@ const useSetPassword = (eventName: string) => { const {isValid, errorMessage} = validateEventPassword(newValue); setCanSubmit(newValue.length === RULE.maxEventPasswordLength); + setErrorMessage(errorMessage); if (isValid) { setPassword(newValue); - setErrorMessage(''); } else { event.target.value = password; - setErrorMessage(errorMessage ?? ''); } }; 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; } 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};