본문 바로가기

TIL

뉴스피드 팀 프로젝트 ④ - 기능구현(비밀번호 변경)

■ 비밀번호 변경

(1) 기본 UI 작성 후 변경할 값을 받을 Input 의 value를 password, newPassword state 와 연결해주기

const ChangePassword = () => {
  const [password, SetPassword] = useState("");
  const [newPassword, setNewPassword] = useState("");
  const { userInfo } = useContext(EntireContext);
  
  // 변경 비밀번호
  const onChangePassword = (e) => {
    setNewPassword(e.target.value);
  };

  // 비밀번호 확인
  const onChangeCheckPassword = (e) => {
    setCheckPassword(e.target.value);
  };

  return (
    <>
      <button onClick={handleToggle}>회원정보 수정</button>
          <div>
            <p>회원정보 수정</p>
            <IdBox>
              <p>▸ 아이디</p>
              <p>{userInfo.email}</p>
            </IdBox>
            <div>
              <label htmlFor="new-password">▸ 변경 비밀번호</label>
              <input
                type="password"
                id="new-password"
                value={newPassword}
                onChange={onChangePassword}
                placeholder="비밀번호"
              />
            </div>
            <p>비밀번호는 숫자, 영어, 특수문자를 포함한 8자 이상 15자 이하입니다.</p>
            <div>
              <label htmlFor="check-password">▸ 비밀번호 확인</label>
              <input
                type="password"
                id="check-password"
                value={checkPassword}
                onChange={onChangeCheckPassword}
                placeholder="비밀번호 확인"
              />
            </div>
            <button>취소</button>
            <button>수정</button>
          </div>
    </>
  );
};

 

(2) 비밀번호 변경 함수 생성 후 수정버튼에 onClick 이벤트로 연결

  const handleChangePassword = async () => {
    // 정규표현식 파일에 생성한 PASSWORD_REGEX import 후 사용
    // (PASSWORD_REGEX = /^(?=.*[a-zA-Z])(?=.*[!@#$%^*+=-])(?=.*[0-9]).{8,15}$/)
    if (newPassword === checkPassword && PASSWORD_REGEX.test(newPassword)) {
      await supabase.auth.updateUser({
        password: newPassword // 입력받을 값인 newPassword로 패스워드 업데이트
      });
      toast.success("비밀번호가 변경되었습니다.");
      setModal(!modal);
      handleSetInit();
    } else {
      toast.error("올바른 비밀번호 형식이 아닙니다. 다시 입력해주세요.");
      handleSetInit();
    }
  };
  
    // input 초기화 함수
  const handleSetInit = () => {
    setNewPassword("");
    setCheckPassword("");
  };

 

(3) 유효성 검사 메세지 추가

// 변경 비밀번호 입력 시 조회될 메세지
<ConfirmMessage>
 {newPassword.length > 0 &&
 (PASSWORD_REGEX.test(newPassword) ||
 "비밀번호는 숫자, 영어, 특수문자를 포함한 8자 이상 15자 이하입니다.")}
</ConfirmMessage>

// 확인 비밀번호 입력 시 조회될 메세지
<ConfirmMessage>
 {checkPassword.length > 0 && (newPassword === checkPassword || "비밀번호가 일치하지 않습니다.")}
</ConfirmMessage>

 

(4) 회원가입한 사용자에게만 비밀번호 변경 화면이 보이도록 해주기

  *  소셜로그인 사용자의 경우 비밀번호 재설정 메일이 해당 소셜계정으로 전송된다.

// userInfo 내 provider 속성으로 소셜로그인 사용자와 일반회원가입 사용자를 구분
const userProvider = userInfo.app_metadata.provider;

return (
{ userProvider === "email" && (회원정보 수정 ~~~) }
)

 

(5) 모달창 구현하기

// 초기값이 false 인 modal 상태 생성
const [modal, setModal] = useState(false);

  // 모달 열고 닫는 함수
const handleClickModal = () => {
  setModal(!modal);
  handleSetInit();
};

// 모달 적용
<ModalOpenBtn type="button" onClick={handleClickModal}>
 회원정보 수정
</ModalOpenBtn>
{modal && (
  <Modal onClick={handleClickModal}>
   <ModalContainer onClick={(e) => e.stopPropagation()}>
    <CloseBtn onClick={handleClickModal}>✖</CloseBtn>
    <p>회원정보 수정</p>
    <ModalContents>
     <p>▸ 아이디</p>
     <EmailText>{userInfo.email}</EmailText>
     <label htmlFor="new-password">▸ 변경 비밀번호</label>
     <PasswordInput
      type="password"
      id="new-password"
      value={newPassword}
      onChange={onChangePassword}
      placeholder="비밀번호"
     />
     <ConfirmMessage>
      {newPassword.length > 0 &&
      (PASSWORD_REGEX.test(newPassword) ||
      "비밀번호는 숫자, 영어, 특수문자를 포함한 8자 이상 15자 이하입니다.")}
     </ConfirmMessage>
     <label htmlFor="check-password">▸ 비밀번호 확인</label>
     <PasswordInput
      type="password"
      id="check-password"
      value={checkPassword}
      onChange={onChangeCheckPassword}
      placeholder="비밀번호 확인"
     />
     <ConfirmMessage>
      {checkPassword.length > 0 && (newPassword === checkPassword || "비밀번호가 일치하지 않습니다.")}
      </ConfirmMessage>
     </ModalContents>
     <ConfirmBtn onClick={handleClickModal}>취소</ConfirmBtn>
     <ConfirmBtn name="confirm" onClick={handleChangePassword}>
      확인
     </ConfirmBtn>
    </ModalContainer>
   </Modal>
)}

 

(6) styled-components 로 css 적용

     - 취소, x 버튼, 모달바깥화면 클릭 시 수정화면 수정모드 꺼짐

 

 

■ 발생했던 문제

비밀번호 유효성 검사를 위해 메세지 상태들을 만들어서 각 메세지 상태를 화면에 띄우게 했었는데 리렌더링 문제로 비밀번호 1자리씩 덜 읽으면서 메세지를 보여주는 오류가 발생했다.

const [passwordMessage, setPasswordMessage] = useState("");
const [confirmMessage, setConfirmMessage] = useState("");

 

 

■ 해결 방법

비밀번호를 구현했던 팀원분과 같이 코드를 보고 메세지를 상태로 만들기보다는 &&, || 와 같은 논리연산자로 구현해보라는 조언을 듣고 return 문 안에서 논리연산자로 구현하니 입력하는 값에 따라 바로바로 반응하는 것을 확인할 수 있었다.

{newPassword.length > 0 &&
 (PASSWORD_REGEX.test(newPassword) ||
 "비밀번호는 숫자, 영어, 특수문자를 포함한 8자 이상 15자 이하입니다.")}
 
  {checkPassword.length > 0 && (newPassword === checkPassword || "비밀번호가 일치하지 않습니다.")}

 

 

■ 느낀점

팀 프로젝트를 하면서 팀원들이 작성한 코드를 보고 활용도 해보면서 좀더 간결하고 쉬운 방법을 익힐 수 있었고 막히는 부분이 있을 때마다 팀원들과 질문하면서 하나씩 해결해가는 과정을 통해 프로젝트 전보다 로직 구현방법에 대해 좀 더 다양하게 생각 할 수 있게 된 것 같다.