미니 프로젝트 [MbtiColor] (6)

박기범·2024년 9월 22일
0

다음은 등록 기능을 만들 차례이다.

api 구현 + 적용

등록 함수는 다음과 같다.
body에 mbti, 색상코드, 비밀번호 모두 문자열로 필수로 넣어야한다.

import api from './base';

const postColorSurvey = async (mbti?: string, colorCode?: string, password?: string) => {
  try {
    const response = await api.post('/api/color-surveys', {
      mbti,
      colorCode,
      password,
    });
    return response.data;
  } catch (error) {
    console.error('Error posting color surveys:', error);
    throw error;
  }
};

export default postColorSurvey;

아마 로그인 기능이 없어서 자신이 정한 4자리 비밀번호로 수정, 삭제 기능을 구현해주는 것 같아보였다.

그래서 비밀번호를 치기 위한 로직을 먼저 구현하였다.

mbti와 색상이 모두 선택된 상태에서 등록 버튼을 누를 때 비밀번호 입력 모달이 나오도록 해야겠다고 생각했다.

또한 비밀번호에 대한 전역 상태 관리도 필요한 것 같아서 아래와 같이 저장소를 만들어주었다.

import { create } from 'zustand';

interface PasswordState {
  userPassword: string;
  setUserPassword: (userPassword: string) => void;
}

const usePassword = create<PasswordState>((set) => ({
  userPassword: '',
  setUserPassword: (userPassword) => set({ userPassword }), // 축약형 사용
}));

export default usePassword;

그러고 난 뒤 비밀번호 모달을 다음과 같이 만들어주었다.
유효성 검사를 통해 숫자로 입력하거나 4자리 이하인 경우 로컬 상태와 전역 상태 모두 갱신되도록 해주었고 추가적으로 4글자인 경우에만 유효성 상태가 true가 되도록 하였으며

유효성 상태가 false인 경우에는 오류 메세지와 입력완료 버튼 비활성화를 해주었다.

import React, { useState } from 'react';
import usePassword from '../../store/passwordStore';

interface TypePasswordModalProps {
  closeModal: () => void;
}

const TypePasswordModal = ({ closeModal }: TypePasswordModalProps) => {
  const [password, setPassword] = useState<string>('');
  const [isValid, setIsValid] = useState<boolean>(false);
  const { setUserPassword } = usePassword();

  const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    const inputValue = e.target.value;

    // 숫자만 허용하고 4자리까지만 입력
    if (/^\d*$/.test(inputValue) && inputValue.length <= 4) {
      setPassword(inputValue);
      setUserPassword(inputValue);
      // 4자리 숫자일 때만 유효성 검사 통과
      setIsValid(inputValue.length === 4);
    }
  };

  return (
  ...
  );
};

export default TypePasswordModal;


이렇게 비밀번호 입력이 완료되었고

만들었던 등록 함수를 useMutation을 이용한 커스텀 훅을 사용하여 등록 기능을 만드려고 하였다.

import { useMutation } from '@tanstack/react-query';
import { toast } from 'react-toastify';
import { useNavigate } from 'react-router-dom'; // useNavigate 임포트
import postColorSurvey from '../api/postColorSurvey';

const useAssignMbtiColorMutation = () => {
  const navigate = useNavigate();

  return useMutation({
    mutationFn: ({ mbti, colorCode, password }: { mbti?: string; colorCode?: string; password?: string }) => {
      // postColorSurvey 호출 시에 매개변수를 전달
      return postColorSurvey(mbti, colorCode, password);
    },
    onSuccess: () => {
      // 성공 시 처리
      toast.success('등록에 성공하였습니다.');
      navigate('/');
    },
    onError: (error: any) => {
      // 에러 처리
      toast.error('등록에 실패했습니다:', error);
    },
  });
};

export default useAssignMbtiColorMutation;

다음과 같이 만들었던 api를 사용해서 커스텀 훅을 만들었고 성공 시에는 성공 메시지를 보여주면서 메인페이지로 돌아가도록 하였다.

최종적으로 등록 버튼 컴포넌트에서

handleCloseModal 즉 비밀번호 모달에서 선택완료 버튼을 눌렀을 때 최종적으로 등록이 진행되어야 하므로

전역 상태들을 가져와 뮤테이션 함수 파라미터로 넣은 다음 완성시켰다.

import { useState } from 'react';
import { toast } from 'react-toastify';
import useSelectedColorStore from '../store/selectedColorStore';
import useSelectedMbtiStore from '../store/selectedMbtiStore';
import checkMbti from '../util/checkMbti';
import TypePasswordModal from './modal/TypePasswordModal';
import usePassword from '../store/passwordStore';
import useAssignMbtiColorMutation from '../hooks/useAssignMbtiColorMutation';

const AssignColorButton = () => {
  const [isOpen, setIsOpen] = useState(false);

  const { selectedMbti } = useSelectedMbtiStore();
  const { selectedColor } = useSelectedColorStore();
  const { userPassword } = usePassword();

  const assignMbtiColorMutation = useAssignMbtiColorMutation();

  const handleAssignColor = () => {
    if (checkMbti(selectedMbti)) {
      setIsOpen(true);
    } else {
      toast.error('mbti 항목을 모두 선택해주세요');
    }
  };

  const handleCloseModal = () => {
    setIsOpen(false);
    const mergedMbtiValue = `${selectedMbti.EI || ''}${selectedMbti.SN || ''}${selectedMbti.TF || ''}${selectedMbti.JP || ''}`;
    assignMbtiColorMutation.mutate({
      mbti: mergedMbtiValue,
      colorCode: selectedColor,
      password: userPassword,
    });
  };

  return (
  ...
  );
};
export default AssignColorButton;

profile
프론트엔드 개발공부를 하고있습니다.

0개의 댓글

관련 채용 정보