Skip to content

Commit

Permalink
fix: 참여한 사람 입력 시 자음이 분리되는 버그와 리펙터링 (#889)
Browse files Browse the repository at this point in the history
* feat: 닉네임 길이 8자로 늘림

* feat: 반복되는 닉네임 상태와 유효성 검증을 수행하는 useMemberName 훅 구현

* feat: 이름 입력 관리를 훅 사용으로 대체하여 같은 로직 반복 제거

* feat: 상수를 사용하도록 수정

* chore: 임시로 props 매칭하여 넘기도록 함

* chore: 불필요해진 파일 제거

* chore: 철자 수정

* chore: 사용하지 않는 import 제거

* feat: 중복 이름이면 에러 메세지 띄우도록 함

* feat: 이름 중복 시 출력할 에러 메세지 선언

* feat: 중복 요소 확인 유틸 분리

* fix: props로 받는 타입 정의

* rename: nickname -> memberName으로 변경

* rename: isDuplicate -> isDuplicated로 변경
  • Loading branch information
pakxe authored Jan 3, 2025
1 parent 1ddcd23 commit f19a331
Show file tree
Hide file tree
Showing 10 changed files with 74 additions and 60 deletions.
1 change: 1 addition & 0 deletions client/src/constants/errorMessage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ export const ERROR_MESSAGE = {
eventPasswordType: SERVER_ERROR_MESSAGES.EVENT_PASSWORD_FORMAT_INVALID,
memberNameLength: `이름은 ${RULE.maxMemberNameLength}자까지 입력 가능해요.`,
memberNameFormat: `이름은 한글, 영어만 가능해요.`,
memberNameDuplicate: '이미 이름이 같은 사람이 존재해요.',
purchasePrice: `${RULE.maxPrice.toLocaleString('ko-kr')}원 이하의 숫자만 입력이 가능해요`,
purchaseTitle: `지출 이름은 ${RULE.maxBillNameLength}자 이하의 한글, 영어, 숫자만 가능해요`,
preventEmpty: '값은 비어있을 수 없어요',
Expand Down
2 changes: 1 addition & 1 deletion client/src/constants/rule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ const EVENT_PASSWORD_LENGTH = 4;
const RULE = {
maxEventNameLength: 30,
maxEventPasswordLength: EVENT_PASSWORD_LENGTH,
maxMemberNameLength: 4,
maxMemberNameLength: 8,
maxPrice: 10000000,
maxBillNameLength: 30,
minAccountNumberLength: 8,
Expand Down
11 changes: 8 additions & 3 deletions client/src/hooks/createEvent/useCreateGuestEventData.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,24 @@
import {useState} from 'react';

import useMemberName from '@hooks/useMemberName';

import useSetEventNameStep from './useSetEventNameStep';
import {useSetNicknameStep} from './useSetNicknameStep';

// 행사 생성 페이지에서 여러 스텝에 걸쳐 사용되는 상태를 선언해 내려주는 용도의 훅입니다.
const useCreateGuestEventData = () => {
const eventNameProps = useSetEventNameStep();
const nickNameProps = useSetNicknameStep();
const {name: nickname, handleNameChange: handleNicknameChange, ...rest} = useMemberName();
const [eventToken, setEventToken] = useState('');

return {
eventNameProps,
nickNameProps,
eventToken,
setEventToken,
nicknameProps: {
nickname,
handleNicknameChange,
...rest,
},
};
};

Expand Down
26 changes: 0 additions & 26 deletions client/src/hooks/createEvent/useSetNicknameStep.ts

This file was deleted.

31 changes: 31 additions & 0 deletions client/src/hooks/useMemberName.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import {useState} from 'react';

import validateMemberName from '@utils/validate/validateMemberName';
import {Nickname} from 'types/serviceType';

const useMemberName = (defaultMemberName?: string) => {
const [name, setName] = useState<Nickname>(defaultMemberName ?? '');
const [errorMessage, setErrorMessage] = useState<string | null>(null);
const [canSubmit, setCanSubmit] = useState(false);

const handleNameChange = (event: React.ChangeEvent<HTMLInputElement>) => {
const name = event.target.value;
const {memberName: memberNameResult, isValid, errorMessage: errorMessageResult} = validateMemberName(name);
setErrorMessage(errorMessageResult);

if (isValid || name.length === 0) {
setName(memberNameResult);
setCanSubmit(isValid);
}
};

const clearMemberName = () => {
setName('');
setErrorMessage(null);
setCanSubmit(false);
};

return {errorMessage, canSubmit, name, handleNameChange, clearMemberName};
};

export default useMemberName;
44 changes: 22 additions & 22 deletions client/src/hooks/useMembersStep.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,23 @@
import {useEffect, useRef, useState} from 'react';
import {useEffect, useRef} from 'react';
import {useNavigate} from 'react-router-dom';

import {BillInfo} from '@pages/event/[eventId]/admin/add-bill/AddBillFunnel';
import {Member} from 'types/serviceType';
import validateMemberName from '@utils/validate/validateMemberName';

import getEventIdByUrl from '@utils/getEventIdByUrl';
import {isIOS} from '@utils/detectDevice';
import isDuplicated from '@utils/isDuplicate';

import RULE from '@constants/rule';
import {ERROR_MESSAGE} from '@constants/errorMessage';

import useRequestPostMembers from './queries/member/useRequestPostMembers';
import useRequestPostBill from './queries/bill/useRequestPostBill';
import {BillStep} from './useAddBillFunnel';
import useRequestGetAllMembers from './queries/member/useRequestGetAllMembers';
import useAmplitude from './useAmplitude';
import useRequestGetEvent from './queries/event/useRequestGetEvent';
import useMemberName from './useMemberName';

interface Props {
billInfo: BillInfo;
Expand All @@ -22,9 +26,7 @@ interface Props {
currentMembers: Member[];
}

const useMembersStep = ({billInfo, setBillInfo, currentMembers, setStep}: Props) => {
const [errorMessage, setErrorMessage] = useState<null | string>('');
const [nameInput, setNameInput] = useState('');
const useMembersStep = ({billInfo, setBillInfo, setStep}: Props) => {
const inputRef = useRef<HTMLInputElement>(null);
const hiddenRef = useRef<HTMLInputElement>(null);

Expand All @@ -38,22 +40,14 @@ const useMembersStep = ({billInfo, setBillInfo, currentMembers, setStep}: Props)
const eventId = getEventIdByUrl();
const {eventName} = useRequestGetEvent();

const handleNameInputChange = (event: React.ChangeEvent<HTMLInputElement>) => {
const name = event.target.value;
const {isValid, errorMessage: errorMessageResult} = validateMemberName(name);

setErrorMessage(errorMessageResult);
if (isValid) {
setNameInput(name);
}
};

const canAddMembers = nameInput && nameInput.length <= 4;
const {name, handleNameChange, clearMemberName, errorMessage} = useMemberName();

const canAddMembers = name && name.length <= RULE.maxMemberNameLength;
const canSubmitMembers = billInfo.members.length !== 0;

const setBillInfoMemberWithId = (name: string) => {
const existingMember = allMembers.find(currentMember => currentMember.name === name);

if (existingMember) {
setBillInfo(prev => ({...prev, members: [...prev.members, {id: existingMember.id, name: name}]}));
} else {
Expand All @@ -62,9 +56,10 @@ const useMembersStep = ({billInfo, setBillInfo, currentMembers, setStep}: Props)
};

const addMembersFromInput = () => {
if (!billInfo.members.map(({name}) => name).includes(nameInput)) {
setBillInfoMemberWithId(nameInput);
setNameInput('');
if (!billInfo.members.map(({name}) => name).includes(name)) {
setBillInfoMemberWithId(name);
clearMemberName();

if (isIOS()) {
hiddenRef.current?.focus();
inputRef.current?.focus();
Expand Down Expand Up @@ -124,11 +119,16 @@ const useMembersStep = ({billInfo, setBillInfo, currentMembers, setStep}: Props)
};

return {
errorMessage,
nameInput,
errorMessage: isDuplicated(
allMembers.map(({name}) => name),
name,
)
? ERROR_MESSAGE.memberNameDuplicate
: errorMessage,
nameInput: name,
inputRef,
hiddenRef,
handleNameInputChange,
handleNameInputChange: handleNameChange,
handleNameInputEnter,
handleNameInputComplete,
isPendingPostBill,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ const CreateGuestEventFunnel = () => {
stepList: STEP_SEQUENCE,
});

const {eventNameProps, nickNameProps, eventToken, setEventToken} = useCreateGuestEventData();
const {eventNameProps, nicknameProps, eventToken, setEventToken} = useCreateGuestEventData();

const handleBack = () => {
if (step === STEP_SEQUENCE[0]) {
Expand All @@ -45,13 +45,13 @@ const CreateGuestEventFunnel = () => {
</Funnel.Step>

<Funnel.Step name="adminName">
<SetNicknameStep moveToNextStep={moveToNextStep} {...nickNameProps} />
<SetNicknameStep moveToNextStep={moveToNextStep} {...nicknameProps} />
</Funnel.Step>

<Funnel.Step name="eventPassword">
<SetEventPasswordStep
moveToNextStep={moveToNextStep}
nickname={nickNameProps.nickname}
nickname={nicknameProps.nickname}
eventName={eventNameProps.eventName}
setEventToken={setEventToken}
/>
Expand Down
6 changes: 3 additions & 3 deletions client/src/pages/event/create/guest/SetNickNameStep.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import {css} from '@emotion/react';

import Top from '@components/Design/components/Top/Top';
import {UseSetNicknameStepProps} from '@hooks/createEvent/useSetNicknameStep';
import useCreateGuestEventData from '@hooks/createEvent/useCreateGuestEventData';

import {FixedButton, Input} from '@HDesign/index';

type SetEventNamePageProps = UseSetNicknameStepProps & {
type SetNicknameStepProps = Pick<ReturnType<typeof useCreateGuestEventData>, 'nicknameProps'>['nicknameProps'] & {
moveToNextStep: () => void;
};

Expand All @@ -15,7 +15,7 @@ const SetNicknameStep = ({
errorMessage,
handleNicknameChange,
canSubmit,
}: SetEventNamePageProps) => {
}: SetNicknameStepProps) => {
const onSubmit = (event: React.FormEvent<HTMLFormElement>) => {
event.preventDefault();

Expand Down
5 changes: 5 additions & 0 deletions client/src/utils/isDuplicate.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
const isDuplicated = (arr: string[], target: string) => {
return arr.includes(target);
};

export default isDuplicated;
2 changes: 0 additions & 2 deletions client/src/utils/validate/validateMemberName.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@ import REGEXP from '@constants/regExp';
import {ERROR_MESSAGE} from '@constants/errorMessage';
import RULE from '@constants/rule';

import {ValidateResult} from './type';

const validateMemberName = (name: string) => {
const slicedName = name.trim().slice(0, RULE.maxMemberNameLength);

Expand Down

0 comments on commit f19a331

Please sign in to comment.