Skip to content

Commit

Permalink
refactor/#359: 반려동물 등록 인풋 핸들러 훅으로 분리
Browse files Browse the repository at this point in the history
- usePetProfileAddition 생성
  • Loading branch information
HyeryongChoi committed Aug 23, 2023
1 parent 311a5a9 commit 3d7b16c
Show file tree
Hide file tree
Showing 13 changed files with 230 additions and 208 deletions.
2 changes: 1 addition & 1 deletion frontend/src/context/petProfile/PetAdditionContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { createContext, ReactNode, useContext, useMemo, useState } from 'react';

import { PostPetProfileReq } from '@/types/petProfile/remote';

interface PetProfileValue extends PostPetProfileReq {}
export interface PetProfileValue extends PostPetProfileReq {}

interface PetAdditionContext {
petProfile: PetProfileValue;
Expand Down
144 changes: 137 additions & 7 deletions frontend/src/hooks/petProfile.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { ChangeEvent, useState } from 'react';
import { useNavigate } from 'react-router-dom';
import { useNavigate, useOutletContext } from 'react-router-dom';

import {
FEMALE,
Expand All @@ -8,41 +8,50 @@ import {
PET_AGE_MAX,
PET_AGE_MIN,
PET_PROFILE_ADDITION_STEP,
PET_SIZES,
STEP_PATH,
} from '@/constants/petProfile';
import { usePetAdditionContext } from '@/context/petProfile/PetAdditionContext';
import { usePetProfile } from '@/context/petProfile/PetProfileContext';
import { routerPath } from '@/router/routes';
import { Gender } from '@/types/petProfile/client';
import {
Gender,
PetAdditionOutletContextProps,
PetProfile,
PetSize,
} from '@/types/petProfile/client';

import { useAddPetProfileMutation, useBreedListQuery } from './query/petProfile';

export const usePetProfileStep = () => {
const navigate = useNavigate();
const { isMixedBreed } = usePetProfileValidation();
const { petProfile } = usePetAdditionContext();

const [step, setStep] = useState(0);
const [isValidStep, setIsValidStep] = useState(false);
const [isMixedBreed, setIsMixedBreed] = useState(false);

const totalStep = Object.values(PET_PROFILE_ADDITION_STEP).length;
const isLastStep = step === totalStep;

const goBack = (): void => navigate(routerPath.back);
const goNext = () => {
if (step === PET_PROFILE_ADDITION_STEP.BREED && !isMixedBreed) {
if (step === PET_PROFILE_ADDITION_STEP.BREED && !isMixedBreed(petProfile.breed)) {
navigate(STEP_PATH[step + 2]);
return;
}

if (!isLastStep) navigate(STEP_PATH[step + 1]);
};

const updateIsMixedBreed = (isMixed: boolean) => setIsMixedBreed(isMixed);
const updateCurrentStep = (step: number) => setStep(step);
const updateIsValidStep = (isValid: boolean) => setIsValidStep(isValid);

return {
step,
totalStep,
isLastStep,
isValidStep,
updateIsMixedBreed,
isLastStep,
updateCurrentStep,
updateIsValidStep,
goBack,
Expand Down Expand Up @@ -105,6 +114,8 @@ export const usePetProfileValidation = () => {
const isValidWeight = (weight: string) => {
const validWeightCharacters = /^(?:100(?:\.0)?|\d{1,2}(?:\.\d)?)$/; // 100.0 또는 1~2자리 숫자.소수 첫째짜리 숫자

if (Number(weight) <= 0) return false;

return validWeightCharacters.test(weight);
};

Expand All @@ -125,3 +136,122 @@ export const usePetProfileValidation = () => {
isMixedBreed,
};
};

export const usePetProfileAddition = () => {
const navigate = useNavigate();
const { breedList } = useBreedListQuery();
const { addPetProfileMutation } = useAddPetProfileMutation();
const { isValidAgeRange, isValidGender, isValidName, isValidWeight } = usePetProfileValidation();

const { updatePetProfile: updatePetProfileInHeader } = usePetProfile(); // 에디가 만든 context
const { petProfile, updatePetProfile } = usePetAdditionContext();
const { updateIsValidStep } = useOutletContext<PetAdditionOutletContextProps>();

const [isValidInput, setIsValidInput] = useState(true);

const onChangeAge = (e: ChangeEvent<HTMLSelectElement>) => {
const selectedAge = Number(e.target.value);

if (isValidAgeRange(selectedAge)) {
setIsValidInput(true);
updateIsValidStep(true);
updatePetProfile({ age: selectedAge });

return;
}

setIsValidInput(false);
updateIsValidStep(false);
};

const onChangeBreed = (e: ChangeEvent<HTMLSelectElement>) => {
const selectedBreed = e.target.value;

updateIsValidStep(true);
setIsValidInput(true);
updatePetProfile({ breed: selectedBreed });
};

const onChangeGender = (e: ChangeEvent<HTMLInputElement>) => {
const gender = e.target.value;

if (isValidGender(gender)) {
updateIsValidStep(true);
updatePetProfile({ gender });
}
};

const onChangeName = (e: ChangeEvent<HTMLInputElement>) => {
const petName = e.target.value;

if (isValidName(petName)) {
setIsValidInput(true);
updateIsValidStep(true);
updatePetProfile({ name: petName });

return;
}

setIsValidInput(false);
updateIsValidStep(false);
};

const onClickPetSize = (petSize: PetSize) => {
updateIsValidStep(true);
updatePetProfile({ petSize });
};

const onChangeWeight = (e: ChangeEvent<HTMLInputElement>) => {
const petWeight = e.target.value;

if (isValidWeight(petWeight)) {
setIsValidInput(true);
updateIsValidStep(true);
updatePetProfile({ weight: Number(petWeight) });

return;
}

setIsValidInput(false);
updateIsValidStep(false);
};

const onSubmitPetProfile = () => {
addPetProfileMutation
.addPetProfile(petProfile)
.then(async res => {
const userInfo = JSON.parse(localStorage.getItem('userInfo')!);

const userPetBreed = breedList?.find(breed => breed.name === petProfile.breed);
const petProfileWithId = {
...petProfile,
id: 1,
petSize: userPetBreed?.name === MIXED_BREED ? petProfile.petSize : PET_SIZES[0],
} as PetProfile;

updatePetProfileInHeader(petProfileWithId);

localStorage.setItem('userInfo', JSON.stringify({ ...userInfo, hasPet: true }));

alert('반려동물 정보 등록이 완료되었습니다.');
})
.catch(error => {
alert('반려동물 정보 등록에 실패했습니다.');
});

navigate(routerPath.home());
};

return {
isValidInput,
petProfile,
updateIsValidStep,
onChangeAge,
onChangeBreed,
onChangeGender,
onChangeName,
onClickPetSize,
onChangeWeight,
onSubmitPetProfile,
};
};
Original file line number Diff line number Diff line change
Expand Up @@ -4,49 +4,44 @@ import { styled } from 'styled-components';
import BackBtnIcon from '@/assets/svg/back_btn.svg';
import Button from '@/components/@common/Button/Button';
import Template from '@/components/@common/Template';
import { PetAdditionProvider } from '@/context/petProfile/PetAdditionContext';
import { usePetProfileStep } from '@/hooks/petProfile';

const PetProfileAddition = () => {
const {
step,
totalStep,
isLastStep,
isValidStep,
updateIsMixedBreed,
isLastStep,
updateCurrentStep,
updateIsValidStep,
goBack,
goNext,
} = usePetProfileStep();

return (
<PetAdditionProvider>
<Template
staticHeader={() =>
getPetProfileAdditionHeader({
title: '반려동물 정보 등록',
step,
totalStep,
onClickBackButton: goBack,
})
}
footer={false}
>
<ContentLayout>
<Outlet
context={{
updateIsMixedBreed,
updateCurrentStep,
updateIsValidStep,
}}
/>
</ContentLayout>
{!isLastStep && (
<Button type="button" text="다음" fixed onClick={goNext} disabled={!isValidStep} />
)}
</Template>
</PetAdditionProvider>
<Template
staticHeader={() =>
getPetProfileAdditionHeader({
title: '반려동물 정보 등록',
step,
totalStep,
onClickBackButton: goBack,
})
}
footer={false}
>
<ContentLayout>
<Outlet
context={{
updateCurrentStep,
updateIsValidStep,
}}
/>
</ContentLayout>
{!isLastStep && (
<Button type="button" text="다음" fixed onClick={goNext} disabled={!isValidStep} />
)}
</Template>
);
};

Expand Down
Original file line number Diff line number Diff line change
@@ -1,34 +1,22 @@
import { ChangeEvent, useEffect } from 'react';
import { useEffect } from 'react';
import { useOutletContext } from 'react-router-dom';
import { styled } from 'styled-components';

import PetAgeSelect from '@/components/PetProfile/PetAgeSelect';
import { PET_PROFILE_ADDITION_STEP } from '@/constants/petProfile';
import { usePetAdditionContext } from '@/context/petProfile/PetAdditionContext';
import { usePetProfileValidation } from '@/hooks/petProfile';
import { PetProfileOutletContextProps } from '@/types/petProfile/client';
import { usePetProfileAddition } from '@/hooks/petProfile';
import { PetAdditionOutletContextProps } from '@/types/petProfile/client';

const PetProfileAgeAddition = () => {
const { updateCurrentStep, updateIsValidStep } = useOutletContext<PetProfileOutletContextProps>();
const { petProfile, updatePetProfile } = usePetAdditionContext();
const { isValidAgeRange } = usePetProfileValidation();
const { petProfile, onChangeAge } = usePetProfileAddition();
const { updateIsValidStep, updateCurrentStep } =
useOutletContext<PetAdditionOutletContextProps>();

useEffect(() => {
updateCurrentStep(PET_PROFILE_ADDITION_STEP.AGE);
updateIsValidStep(false);
updateCurrentStep(PET_PROFILE_ADDITION_STEP.AGE);
}, []);

const onChangeAge = (e: ChangeEvent<HTMLSelectElement>) => {
const selectedAge = Number(e.target.value);

if (isValidAgeRange(selectedAge)) {
updateIsValidStep(true);
updatePetProfile({ age: selectedAge });
}

if (!isValidAgeRange(selectedAge)) updateIsValidStep(false);
};

return (
<Container>
<Title>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,35 +1,23 @@
import { ChangeEvent, useEffect } from 'react';
import { useEffect } from 'react';
import { useOutletContext } from 'react-router-dom';
import { styled } from 'styled-components';

import PetBreedSelect from '@/components/PetProfile/PetBreedSelect';
import { PET_PROFILE_ADDITION_STEP } from '@/constants/petProfile';
import { usePetAdditionContext } from '@/context/petProfile/PetAdditionContext';
import { usePetProfileValidation } from '@/hooks/petProfile';
import { PetProfileOutletContextProps } from '@/types/petProfile/client';
import { usePetProfileAddition } from '@/hooks/petProfile';
import { PetAdditionOutletContextProps } from '@/types/petProfile/client';
import { getTopicParticle } from '@/utils/getTopicParticle';

const PetProfileBreedAddition = () => {
const { petProfile, updatePetProfile } = usePetAdditionContext();
const { updateIsMixedBreed, updateCurrentStep, updateIsValidStep } =
useOutletContext<PetProfileOutletContextProps>();
const { isMixedBreed } = usePetProfileValidation();
const { petProfile, onChangeBreed } = usePetProfileAddition();
const { updateCurrentStep, updateIsValidStep } =
useOutletContext<PetAdditionOutletContextProps>();

useEffect(() => {
updateCurrentStep(PET_PROFILE_ADDITION_STEP.BREED);
updateIsValidStep(false);
updateCurrentStep(PET_PROFILE_ADDITION_STEP.BREED);
}, []);

const onChangeBreed = (e: ChangeEvent<HTMLSelectElement>) => {
const selectedBreed = e.target.value;

if (isMixedBreed(selectedBreed)) updateIsMixedBreed(true);
if (!isMixedBreed(selectedBreed)) updateIsMixedBreed(false);

updateIsValidStep(true);
updatePetProfile({ breed: selectedBreed });
};

return (
<Container>
<PetName>{petProfile.name}</PetName>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,28 +1,20 @@
import { ChangeEvent, useEffect } from 'react';
import { useEffect } from 'react';
import { useOutletContext } from 'react-router-dom';
import { styled } from 'styled-components';

import GenderRadioInput from '@/components/PetProfile/GenderRadioInput';
import { GENDERS, PET_PROFILE_ADDITION_STEP } from '@/constants/petProfile';
import { usePetAdditionContext } from '@/context/petProfile/PetAdditionContext';
import { usePetProfileValidation } from '@/hooks/petProfile';
import { PetProfileOutletContextProps } from '@/types/petProfile/client';
import { usePetProfileAddition } from '@/hooks/petProfile';
import { PetAdditionOutletContextProps } from '@/types/petProfile/client';

const PetProfileGenderAddition = () => {
const { updateCurrentStep } = useOutletContext<PetProfileOutletContextProps>();
const { petProfile, updatePetProfile } = usePetAdditionContext();
const { isValidGender } = usePetProfileValidation();
const { petProfile, onChangeGender } = usePetProfileAddition();
const { updateCurrentStep } = useOutletContext<PetAdditionOutletContextProps>();

useEffect(() => {
updateCurrentStep(PET_PROFILE_ADDITION_STEP.GENDER);
}, []);

const onChangeGender = (e: ChangeEvent<HTMLInputElement>) => {
const gender = e.target.value;

if (isValidGender(gender)) updatePetProfile({ gender });
};

return (
<Container>
<PetName>{petProfile.name}</PetName>
Expand Down
Loading

0 comments on commit 3d7b16c

Please sign in to comment.