Skip to content

Commit

Permalink
폼 관련 페이지 리팩토링 (#501)
Browse files Browse the repository at this point in the history
* feat: CreateCrewPage 스타일 추가

* feat: createCrewPage 에러 메시지 상수화

* refactor: CreateCrewPage 리팩토링

* refactor: 게임 시작시간 유효성 검사 함수 분리

* refactor: ConditionalFormInput 컴포넌트 리팩토링

* refactor: TextArea 컴포넌트 리팩토링

* refactor: 크루 생성 페이지 리팩토링

* refactor: 크루 생성 페이지 리팩토링
  • Loading branch information
imb96 authored Jan 9, 2024
1 parent c60bff4 commit af2254a
Show file tree
Hide file tree
Showing 9 changed files with 221 additions and 192 deletions.
85 changes: 49 additions & 36 deletions src/components/ConditionalFormInput/ConditionalFormInput.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useFormContext } from 'react-hook-form';
import { FieldValues, UseFormRegister } from 'react-hook-form';

import { Modal } from '@components/Modal';
import { Text } from '@components/shared/Text';
Expand All @@ -10,55 +10,68 @@ import {
} from './ConditionalFormInput.styles';

export type ConditionalFormInputProps = {
title: string;
inputLabel: string;
inputValue?: string;
label: string;
name: string;
register: UseFormRegister<FieldValues>;
required?: boolean;
isContainModal?: boolean;
isModalOpen?: boolean;
isContainModal: boolean;
isRequired?: boolean;
children?: React.ReactNode;
inputOnChange?: (item: string) => void;
closeModal?: () => void;
children?: React.ReactNode;
};

export const ConditionalFormInput = ({
title,
label,
name,
register,
required = false,
isContainModal = false,
inputLabel,
inputOnChange,
isModalOpen,
closeModal,
isRequired,
children,
...inputProps
}: React.ComponentProps<'input'> & ConditionalFormInputProps) => {
const { register } = useFormContext();
return (
<>
<StyledSubTitle>
<Text size={16} weight={300}>
{title}
</Text>
</StyledSubTitle>
<StyledInput
{...register(inputLabel, { required: isRequired })}
{...inputProps}
onChange={(event) => inputOnChange && inputOnChange(event.target.value)}
onWheel={(event) => event.currentTarget.blur()}
/>
{isContainModal && (
<Modal
isOpen={isModalOpen as boolean}
close={closeModal as VoidFunction}
header={true}
>
<StyledModalHeader>
<Text size={20} weight={700}>
{title}
{isContainModal ? (
<>
<StyledSubTitle>
<Text size={16} weight={300}>
{label}
</Text>
</StyledSubTitle>
<StyledInput
{...register(name, { required: required })}
{...inputProps}
onWheel={(event) => event.currentTarget.blur()}
readOnly={true}
/>
<Modal
isOpen={isModalOpen as boolean}
close={closeModal as VoidFunction}
header={true}
>
<StyledModalHeader>
<Text size={20} weight={700}>
{label}
</Text>
</StyledModalHeader>
<Modal.Content>{children}</Modal.Content>
</Modal>
</>
) : (
<>
<StyledSubTitle>
<Text size={16} weight={300}>
{label}
</Text>
</StyledModalHeader>
<Modal.Content>{children}</Modal.Content>
</Modal>
</StyledSubTitle>
<StyledInput
{...register(name, { required: required })}
{...inputProps}
onWheel={(event) => event.currentTarget.blur()}
/>
</>
)}
</>
);
Expand Down
21 changes: 9 additions & 12 deletions src/components/TextArea/TextArea.tsx
Original file line number Diff line number Diff line change
@@ -1,36 +1,33 @@
import { useForm } from 'react-hook-form';
import { FieldValues, UseFormRegister } from 'react-hook-form';

import { Text } from '@components/shared/Text';

import { StyledSubTitle, StyledTextArea } from './TextArea.styles';

type textAreaProps = {
title: string;
inputLabel: string;
label: string;
name: string;
defaultValue?: string;
inputOnChange?: (item: string) => void;
register: UseFormRegister<FieldValues>;
};

export const TextArea = ({
title,
inputLabel,
label,
register,
name,
defaultValue,
inputOnChange,
}: textAreaProps) => {
const { register } = useForm();

return (
<>
<StyledSubTitle>
<Text size={16} weight={300}>
{title}
{label}
</Text>
</StyledSubTitle>
<StyledTextArea
{...register(inputLabel)}
{...register(name)}
maxLength={1000}
defaultValue={defaultValue}
onChange={(event) => inputOnChange && inputOnChange(event.target.value)}
/>
</>
);
Expand Down
24 changes: 24 additions & 0 deletions src/pages/CreateCrewPage/CreateCrewPage.styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,21 @@ export const StyledCreateForm = styled.form`
gap: 4px;
`;

export const StyledSubTitle = styled.div`
margin-bottom: 8px;
`;

export const StyledInput = styled.input<{ height?: number | string }>`
padding-left: 10px;
width: 100%;
height: 30px;
height: ${({ height }) =>
typeof height === 'number' ? `${height}px` : height};
border: 1px solid ${({ theme }) => theme.PALETTE.GRAY_300};
border-radius: 8px;
margin-bottom: 8px;
`;

export const StyledEmptyContainer = styled.div`
height: 16px;
`;
Expand Down Expand Up @@ -70,3 +85,12 @@ export const StyledModalContent = styled(Modal.Content)`
${({ theme }) => theme.STYLES.FLEX_CENTER}
padding: 30px;
`;

export const StyledTextArea = styled.textarea`
border: 1px solid ${({ theme }) => theme.PALETTE.GRAY_300};
border-radius: 8px;
width: 100%;
height: 340px;
padding: 8px;
margin-bottom: 16px;
`;
31 changes: 13 additions & 18 deletions src/pages/CreateCrewPage/CreateCrewPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,16 +36,13 @@ export const CreateCrewPage = () => {
methods,
locations,
onSubmit,
setName,
setContent,
handleMaxMemberCount,
handleToggleLocation,
toggleMaxMemberCountModal,
toggleAddressDepth2Modal,
} = useCreateCrewPage();

const {
name,
maxMemberCount,
selectedLocation,
selectedLocations,
Expand All @@ -58,7 +55,7 @@ export const CreateCrewPage = () => {
<PageWrapper>
<Header title={showHeaderTitle ? CREATE_CREW_STRINGS.TITLE : ''} />
<FormProvider {...methods}>
<StyledCreateForm onSubmit={methods.handleSubmit(onSubmit)}>
<StyledCreateForm onSubmit={onSubmit}>
<StyledTitle>
<div ref={entryRef}>
<Text size={20} weight={700}>
Expand All @@ -67,24 +64,22 @@ export const CreateCrewPage = () => {
</div>
</StyledTitle>
<ConditionalFormInput
title={CREATE_CREW_STRINGS.CREW_NAME}
isRequired={true}
isContainModal={false}
inputLabel="crew-name"
inputOnChange={setName}
value={name}
label={CREATE_CREW_STRINGS.CREW_NAME}
name="name"
register={methods.register}
required={true}
minLength={1}
maxLength={20}
/>
<ConditionalFormInput
title={CREATE_CREW_STRINGS.CREW_MEMBER_COUNT}
readOnly={true}
label={CREATE_CREW_STRINGS.CREW_MEMBER_COUNT}
name="maxMemberCount"
register={methods.register}
isContainModal={true}
inputLabel="crew-count"
onClick={toggleMaxMemberCountModal}
value={maxMemberCount}
isModalOpen={isOpenMaxMemberCountModal}
closeModal={toggleMaxMemberCountModal}
value={maxMemberCount}
onClick={toggleMaxMemberCountModal}
>
<VirtualScroll
width="100%"
Expand Down Expand Up @@ -131,9 +126,9 @@ export const CreateCrewPage = () => {
</StyledModalContent>
</Modal>
<TextArea
title={CREATE_CREW_STRINGS.CREW_DESCRIPTION}
inputLabel="content"
inputOnChange={setContent}
label={CREATE_CREW_STRINGS.CREW_DESCRIPTION}
register={methods.register}
name="content"
/>
<Button
width="100%"
Expand Down
5 changes: 5 additions & 0 deletions src/pages/CreateCrewPage/constants/createCrewOptions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,8 @@ export const CREATE_CREW_STRINGS = {
CREW_DESCRIPTION: '상세설명을 입력해 주세요!',
CREATE: '만들기',
} as const;

export const CREATE_CREW_ERROR_MESSAGE = {
MAX_CREW_LIMIT_EXCEEDED: '최대 크루 생성 횟수 3회를 초과했습니다.',
DUPLICATE_CREW_NAME: '중복된 크루 이름 입니다.',
};
70 changes: 35 additions & 35 deletions src/pages/CreateCrewPage/hooks/useCreateCrewPage.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import { useState } from 'react';
import { useForm } from 'react-hook-form';
import { FieldValues, useForm } from 'react-hook-form';
import toast from 'react-hot-toast';
import { useNavigate } from 'react-router-dom';

import { AxiosError } from 'axios';

import { CREATE_CREW_ERROR_MESSAGE } from '@pages/CreateCrewPage/constants/createCrewOptions';

import { LoginRequireError } from '@routes/LoginRequireBoundary';

import { useToggleButtons } from '@components/shared/ToggleButton';
Expand All @@ -27,41 +29,13 @@ export const useCreateCrewPage = () => {

const navigate = useNavigate();
const { data: locations } = useLocationsQuery();

const { mutate } = useCrewMutation();

const methods = useForm();
const { handleSubmit } = methods;

const [name, setName] = useState<string>('');
const [content, setContent] = useState<string>('');
const [maxMemberCount, setMaxMemberCount] = useState<string>('');
const [selectedLocation, setSelectedLocation] = useState<string[]>();

const onSubmit = () => {
const crewData: PostCrewRequest = {
name,
content,
maxMemberCount: parseInt(maxMemberCount),
addressDepth1: '서울시',
addressDepth2: selectedLocation![0],
};

mutate(crewData, {
onSuccess: ({ crewId }) => {
navigate(PATH_NAME.GET_CREWS_PATH(String(crewId)));
},
onError: (error) => {
if (error instanceof AxiosError) {
if (error.response?.data.code === 'CRE-012') {
return toast.error('최대 크루 생성 횟수 3회를 초과했습니다.');
}
if (error.response?.data.code === 'CRE-002') {
return toast.error('중복된 크루 이름 입니다.');
}
}
},
});
};

const [isOpenMaxMemberCountModal, setIsOpenMaxMemberCountModal] =
useState(false);
const [isOpenAddressDepth2Modal, setIsOpenAddressDepth2Modal] =
Expand All @@ -87,20 +61,46 @@ export const useCreateCrewPage = () => {
isOpenMaxMemberCountModal || setMaxMemberCount(maxMemberCount);
};

const onSubmit = handleSubmit((data: FieldValues) => {
const addressDepth2 = selectedLocation![0];
const { name, content } = data;
const crewData: PostCrewRequest = {
name,
content,
maxMemberCount: parseInt(maxMemberCount),
addressDepth1: '서울시',
addressDepth2,
};
mutate(crewData, {
onSuccess: ({ crewId }) => {
navigate(PATH_NAME.GET_CREWS_PATH(String(crewId)));
},
onError: (error) => {
if (error instanceof AxiosError) {
if (error.response?.data.code === 'CRE-012') {
return toast.error(
CREATE_CREW_ERROR_MESSAGE.MAX_CREW_LIMIT_EXCEEDED
);
}
if (error.response?.data.code === 'CRE-002') {
return toast.error(CREATE_CREW_ERROR_MESSAGE.DUPLICATE_CREW_NAME);
}
}
},
});
});

return {
state: {
name,
maxMemberCount,
selectedLocation,
selectedLocations,
isOpenMaxMemberCountModal,
isOpenAddressDepth2Modal,
},
methods,
locations,
methods,
onSubmit,
setName,
setContent,
handleMaxMemberCount,
handleToggleLocation,
toggleMaxMemberCountModal,
Expand Down
Loading

0 comments on commit af2254a

Please sign in to comment.