Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: 회원가입 api 연결 및 동작 처리 구현 #181

Merged
merged 10 commits into from
Sep 23, 2024

Conversation

hsgh085
Copy link
Collaborator

@hsgh085 hsgh085 commented Sep 13, 2024

💡 작업 내용

  • 기본 프로필 설정하기
  • 수정된 회원가입 관련 api에 맞춰 코드 수정
  • 회원가입 관련 UI 동작 처리 구현

💡 자세한 설명

✅기본 프로필 설정하기

아름님이 만들어주신 모달창 UI를 회원가입 페이지에 연결했습니다.

chrome-capture-2024-9-14

기본 프로필 이미지의 경우에는 사용자 커스텀 이미지와 다르게 매번 file upload api를 활용해서 amazone에 저장할 필요가 없다고 판단했습니다. 그래서 서버에 6개의 기본 이미지를 미리 저장해두고, 기본 이미지로 프로필 설정 시, 서버 이미지 경로를 가져오도록 했습니다.

// hooks\common\inputsUserInfo\useCheckProfileImage.ts
const handleDefaultImage = (src: string) => {
    let profileImgUrl = '';
    switch (src) {
      case DEFAULT_PROFILE_URL.OCTOPUS.CLIENT:
        profileImgUrl = DEFAULT_PROFILE_URL.OCTOPUS.SERVER;
        break;
      ...
    }
    setImageSrc(src);
    setProfilePhoto('profileImgUrl', profileImgUrl);
  };

하지만 현재 회원가입 api에서 프로필 관련된 에러가 있습니다.
스웨거로 테스트해보았을 때도 프로필 이미지가 회원 정보에 저장되지 않는 문제가 있어 담당 백엔드 개발자분께 이슈 요청드릴 예정입니다.

-> 이슈 해결! 회원가입 시 세팅한 이미지 잘 보입니당

image

✅회원가입 페이지 동작

회원가입 페이지 동작 처리는 아래와 같습니다.

  1. 프로필 이미지 선택 시, 파일 크기에 대해 유효성 검사를 진행합니다.

  2. 이메일, 인증번호, 닉네임 입력창은 버튼 클릭시에 유효성 검사를 진행합니다.

  3. 비밀번호, 비밀번호 확인 입력창은 입력을 할 때마다 유효성 검사를 진행합니다.

  4. 위 값 중 유효성 검사에 위배가 되는 항목이 있다면, 유효하지 않은 항목의 입력창을 focus시킵니다.

  5. 유효성 검사에 모두 성공했다면 회원 가입 토스트창이 2초 띄워진 후, 로그인 페이지로 이동합니다.

chrome-capture-2024-9-14-1

유효성 검사 성공 시, 문구나 디자인은 기획자님과 디자이너님께 한 번 문의드려 봐야 하는 사항으로 현재는 이전에 구현된 사항 그대로 둔 상태입니다!

📗 참고 자료 (선택)

📢 리뷰 요구 사항 (선택)

🚩 후속 작업 (선택)

✅ 셀프 체크리스트

  • PR 제목을 형식에 맞게 작성했나요?
  • 브랜치 전략에 맞는 브랜치에 PR을 올리고 있나요? (master/main이 아닙니다.)
  • 이슈는 close 했나요?
  • Reviewers, Labels, Projects를 등록했나요?
  • 작업 도중 문서 수정이 필요한 경우 잘 수정했나요?
  • 테스트는 잘 통과했나요?
  • 불필요한 코드는 제거했나요?

closes #161

@hsgh085 hsgh085 added ✔︎pull requests pull requests 코드 체크 요청 👩🏻‍💻 frontend 프론트엔드 작업 ✅feature 🙆‍♀️회원가입 labels Sep 13, 2024
@hsgh085 hsgh085 self-assigned this Sep 13, 2024
Copy link
Contributor

@areumH areumH left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

바쁘신데 회원가입 기능 구현해주셔서 너무 감사합니다🙇‍♀️🙇‍♀️ 고생 많으셨어요!!!!!
기본 이미지를 저장해두고 경로로 가져오는 부분 너무 좋은 것 같습니다 👍
프로필 이미지 문제 해결되고 확인 후 머지하시면 될 것 같아요!!! 수고 많으셨습니닷 🙌

Comment on lines +33 to +34
onSuccess: (res) => {
setProfilePhoto('profileImgUrl', res.imgUrls[0]);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

코드를 보니 위의 setProfilePhoto 함수는 useInput 훅의 setEach 함수와 연결되어있는 것 같은데 initialState의 profileImageUrl 값에 선택된 이미지 string 값을 지정하는 역할인 정도로 이해하면 될까요!?? 함수의 연결이 어떻게 되는지 궁금합니다 😯

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

네네 맞아요 정확히 이해하셨어요! useInputs 훅이 범용적인 hook으로 여러 프로퍼티를 갖는 객체를 관리하는 데 사용하고 있어요~!

function useInputs<T>(initialState: T) {
  const [form, setForm] = useState<T>(initialState);
  ...
const setEach = useCallback(<U>(name: string, value: U) => {
    setForm((prevForm) => ({ ...prevForm, [name]: value }));
  }, []);

여기서 setEach함수는 내가 지정한 프로퍼티에 값을 set하는 함수입니당!

저는 회원가입 시 필요한 Member 정보를 form으로 저장하고,

export interface MemberForm {
  email: string;
  verificationCode: string;
  nickname: string;
  password: string;
  passwordCheck: string;
  profileImgUrl: string;
  role: 'USER';
}

setProfilePhoto함수 = setEach('profileImgUrl', res.imgUrls[0]); 를 통해서 profileImgUrl 값을 저장해줬습니다!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

지금 다시 봤는데, useInputs 훅 이용해서 전반적인 폼 데이터 처리를 하는데에 이용하는 군요...! 해당 훅은 전반적인 폼 관련 요소들을 관리하는 것 같은데 다른 모달 창들에서도 사용가능할지 여부를 여쭙고 싶어요 :)
@hsgh085

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

네네! 전반적인 폼 관련 요소를 관리하는 곳이라면 어디서든 사용가능해요😊

밸런스 게임 태그 선택 모달을 예시로 들면, 메인 태그와 서브 태그를 관리하는 form을 useInputs 훅을 통해 관리할 수 있을 듯 해요!

function useInputs<T>(initialState: T) {
  const [form, setForm] = useState<T>(initialState);

useInputs의 initialState로 메인 태그와 서브 태그를 관리하는 form을 넘겨주고,

 const onChange = useCallback(
    (
      e: ChangeEvent<
        HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement
      >,
    ) => {
      const { name, value } = e.target;
      setForm((prevForm) => ({ ...prevForm, [name]: value }));
    },
    [],
  );

onChange함수를 통해 값이 변경될 때마다 form의 값을 업데이트하고,

const setEach = useCallback(<U>(name: string, value: U) => {
    setForm((prevForm) => ({ ...prevForm, [name]: value }));
  }, []);

setEach 함수를 통해 내가 지정한 프로퍼티에 값을 직접 셋팅해주면서 form 데이터를 관리할 수 있을 것 같아요!

Copy link
Contributor

@alwubin alwubin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

시간 없음에도 불구하고 회원가입 관련 기능 구현해주시다니..🥹정말 정말 수고많으셨습니다!!👏 간단한 질문 남겨두었으니 확인부탁드립니당☺️

@@ -31,9 +18,9 @@ export const getMemberProfile = async (memberId: number) => {
};

export const postMember = async (
form: Pick<MemberForm, 'nickname' | 'email' | 'password'>,
form: Pick<MemberForm, 'nickname' | 'email' | 'password' | 'role'>,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

role 매개변수의 역할이 혹시 유저와 어드민 이렇게 이후에 나누어질 구분에 대한 것인지 궁금합니당🧐

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

회원 가입 api에서 body값으로 role이라는 값을 넣어주어야 해서 추가해주었습니다! 아마 말씀하신 것처럼 차후에 유저와 어드민을 구분하기 위해서 기능을 미리 만들어 두신 게 아닐까 싶네요🤔

navigate(`/${PATH.LOGIN}`);
alert('회원가입에 성공했습니다😀');
},
onSuccess: () => {},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

회원가입 후 로그인페이지로 이동하도록 로직이 설정되어있다고 하셨는데 제거하신 이유가 따로 있을까용?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

회원가입 성공 시 로직은 아래 파일로 이동해두었습니다!

// hooks\signup\useSignupForm.ts
const { mutate: signup } = useSignUpMutation();

const handleSubmit = (e: ChangeEvent<HTMLFormElement>) => {
    e.preventDefault();
    if (isAllTrue(successForm)) {
      const newForm = createNewForm(form);
      signup(newForm, {
        onSuccess: () => {
          setSignupSuccess(true);
          setTimeout(() => {
            navigate(`/${PATH.LOGIN}`);
          }, 2000);
        },
      });
    } else {
      focus(e);
    }
  };

위와 같이 옮겨둔 이유는 회원 가입 성공 토스트 메시지 창이 2초간 띄워진 이후로 로그인 페이지로 이동해야 했기 때문입니당

const [signupSuccess, setSignupSuccess] = useState<boolean>(false);

signupSuccess 변수를 통해서 토스트 메시지 창을 띄울지 말지 여부를 제어하는 데 이 로직을 useSignUpMutation 훅에 넣기에는 해당 훅의 관심사에 맞지 않다고 판단했습니다🤔 이 훅은 다른 컴포넌트를 직접 제어하지 않는 것이 원칙이라고 생각해서 회원가입 로직을 전체적으로 관리하는 useSignupForm 훅으로 옮겨두었습니다!

Copy link
Contributor

@WonJuneKim WonJuneKim left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

바쁘실텐데 시간 쪼개서 해당 부분 구현 마무리 해주신 점 정말 감사드려요 👍
희선님이 만들어 주신 모달에 닫기 버튼 추가는 제 브랜치에서 처리하도록 하겠습니다!!
고생 많으셨어요 🚀🚀🚀

src/components/molecules/InputPw/InputPw.tsx Show resolved Hide resolved
src/constants/image.ts Show resolved Hide resolved
@@ -18,10 +20,20 @@ const InputProfileImage = ({
}: InputProfileImageProps) => {
const { imageSrc, isError, getRootProps, handleDefaultImage } =
useCheckProfileImage({ setProfilePhoto, imgSrc });

const [defaultProfileModalOpen, setDefaultProfileModalOpen] =
useState<boolean>(false);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

useState의 경우 기본 타입 추정 값이 false로 알고 있는데, lint 관련 설정 때문에 까지 추가 하신 것인지 궁금합니다!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

해당 모달 동작 부분을 하나의 함수로 처리해도 좋을 것 같다는 의견도 제시봅시다!

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lint 관련 설정보다는 명시적으로 초기화해주는 것이 좋아 위와 같이 코드를 작성했습니다 :)
useState<boolean>() 이렇게 해도 되나 싶어서 방금 해보았더니, false로 초기값을 주지 않는다면 undefined값으로 초기화되어 에러가 발생하네요🥲

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

해당 모달 동작 부분을 하나의 함수로 처리해도 좋을 것 같다 를 제가 잘 이해하지 못해서 혹시 예시를 들어주실 수 있을까요??

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

처음 의도는 이미지가 선택된 후 자동으로 모달 창이 닫도록 동시에 처리 하는게 어떨까 하는 코멘트였는데, 이러한 의도로 모달 open 상태 관리 + 이미지 선택 부분을 하나의 함수로 처리해도 좋다는 의견을 제시하였습니다.
다만, 현재 모달에 닫기 버튼이 따로 출력시키기로 하였고, 해당 동작 둘을 동시에 처리하는 것은 기획 의도에도 맞지 않아 제 코멘트 스스로 반려 하도록 하겠습니닷 😢

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+) useState 관련해서는 희선님의 의도가 더 적절하신 거 같네요! 오히려 제가 하나 더 배워갑니다! 확인해주셔서 정말 감사드려요 👍

src/hooks/common/inputsUserInfo/useCheckProfileImage.ts Outdated Show resolved Hide resolved
Copy link
Contributor

@WonJuneKim WonJuneKim left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

다시 한번 고생 많으셨습니다! 코멘트에 주신 답변들로 제가 더 배워가네요! 감사합니다 :)

Comment on lines +33 to +34
onSuccess: (res) => {
setProfilePhoto('profileImgUrl', res.imgUrls[0]);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

지금 다시 봤는데, useInputs 훅 이용해서 전반적인 폼 데이터 처리를 하는데에 이용하는 군요...! 해당 훅은 전반적인 폼 관련 요소들을 관리하는 것 같은데 다른 모달 창들에서도 사용가능할지 여부를 여쭙고 싶어요 :)
@hsgh085

@@ -18,10 +20,20 @@ const InputProfileImage = ({
}: InputProfileImageProps) => {
const { imageSrc, isError, getRootProps, handleDefaultImage } =
useCheckProfileImage({ setProfilePhoto, imgSrc });

const [defaultProfileModalOpen, setDefaultProfileModalOpen] =
useState<boolean>(false);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

처음 의도는 이미지가 선택된 후 자동으로 모달 창이 닫도록 동시에 처리 하는게 어떨까 하는 코멘트였는데, 이러한 의도로 모달 open 상태 관리 + 이미지 선택 부분을 하나의 함수로 처리해도 좋다는 의견을 제시하였습니다.
다만, 현재 모달에 닫기 버튼이 따로 출력시키기로 하였고, 해당 동작 둘을 동시에 처리하는 것은 기획 의도에도 맞지 않아 제 코멘트 스스로 반려 하도록 하겠습니닷 😢

@@ -18,10 +20,20 @@ const InputProfileImage = ({
}: InputProfileImageProps) => {
const { imageSrc, isError, getRootProps, handleDefaultImage } =
useCheckProfileImage({ setProfilePhoto, imgSrc });

const [defaultProfileModalOpen, setDefaultProfileModalOpen] =
useState<boolean>(false);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+) useState 관련해서는 희선님의 의도가 더 적절하신 거 같네요! 오히려 제가 하나 더 배워갑니다! 확인해주셔서 정말 감사드려요 👍

@hsgh085 hsgh085 merged commit 341cb91 into dev Sep 23, 2024
3 checks passed
@hsgh085 hsgh085 deleted the feat/161-signup-api branch September 27, 2024 17:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
Status: Done
Development

Successfully merging this pull request may close these issues.

회원가입 페이지 api 연결 및 동작 처리 구현
4 participants