캡스톤 디자인 프로젝트 -맛집 정보 사이트 만들기- (5) 프론트 회원 기능

2024. 12. 9. 16:05프로젝트

728x90

프론트 회원기능은 components 폴더의 user폴더의 AuthModal파일에서 전부 작성되고 있습니다.

 

  • 로그인회원가입을 위한 상태 관리
  • 실시간 유효성 검사
  • 전화번호 인증 코드 발송 및 검증
  • 서버와의 API 통신으로 인증 처리
  • 로그인 성공 시 Recoil을 사용해 글로벌 상태 관리

리코일을 통해서 백엔드에서 했던 세션을 통해 받아왔던 내용을 상태관리를 통해 세션을 통한 isAuthenticated을 true값을 받아와서 인증처리를 적용할 수 있습니다.

 

userAtoms.jsx

export const authState = atom({
  key: "authState",
  default: {
    isAuthenticated: false,
    isLoading: false,
    showAuthModal: false,
    userId: null,
    username: "",
    email: "",
    full_name: "",
  },
});

또 회원가입을 통한 유효성 검사 함수를 통해 회원가입 예외사항을 설정할 수 있습니다.

 

유효성 검사 함수

const validate = (name, value) => {
  let error = "";

  if (name === "username") {
    if (!idLength(value)) {
      error = "아이디는 4글자 이상, 12글자 이하로 입력해주세요.";
    } else if (!onlyNumberAndEnglish(value)) {
      error = "아이디는 영어 또는 숫자만 입력 가능합니다.";
    }
  } else if (name === "password") {
    if (!strongPassword(value)) {
      error = "비밀번호는 8자 이상, 영문, 숫자, 특수문자를 포함해야 합니다.";
    }
  } else if (name === "confirmPassword") {
    if (!isMatch(value, registerData.password)) {
      error = "비밀번호가 일치하지 않습니다.";
    }
  } else if (name === "phone_number") {
    if (!value) {
      error = "전화번호를 입력해주세요.";
    } else if (value.length < 10) {
      error = "전화번호 형식이 올바르지 않습니다.";
    }
  }

  return error;
};

전화번호 인증 코드는 

https://solapi.com/

 

SOLAPI - 알림톡과 문자메시지 발송, CRM 자동화 솔루션

CRM을 통해 고객에게 더 나은 서비스를 제공하고 비즈니스의 성장을 이룰 수 있는 방법을 소개합니다. 대량문자, 카카오 알림톡 친구톡, 문자 API연동, 앱발송, 웹발송, CRM자동화, 보이스톡

solapi.com

 

 

저번 시간에 했던 Solapi를 통해서 백엔드에서 만들어놨던 api를 통해 인증번호를 부여받고 인증 처리를 합니다. 

 

1. 인증 코드 전송

const sendVerificationCode = async () => {
  const cleanedPhoneNumber = registerData.phone_number.replace(/-/g, "");

  if (cleanedPhoneNumber.length < 10) {
    setErrors((prev) => ({
      ...prev,
      phone_number: "올바른 전화번호를 입력해주세요.",
    }));
    return;
  }

  try {
    const response = await fetch(
      "https://maketerbackend.fly.dev/api/v1/send-verification-code",
      {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ phone_number: cleanedPhoneNumber }),
      }
    );

    const parseRes = await response.json();
    if (parseRes.resultCode === "S-1") {
      setGeneratedCode(parseRes.verificationCode);
      setIsCodeSent(true);
      toast.success("인증코드가 발송되었습니다.");
    } else {
      toast.error("인증코드 발송 실패.");
    }
  } catch (error) {
    toast.error("서버 오류 발생: " + error.message);
  }
};

 

2. 인증 코드 확인

const verifyCode = async () => {
  if (!verificationCode) {
    setErrors((prev) => ({
      ...prev,
      verificationCode: "인증코드를 입력해주세요.",
    }));
    return;
  }

  try {
    const response = await fetch(
      "https://maketerbackend.fly.dev/api/v1/verify-code",
      {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({
          verificationCode: generatedCode,
          inputCode: verificationCode,
        }),
      }
    );

    const parseRes = await response.json();
    if (parseRes.resultCode === "S-1") {
      setIsVerified(true);
      toast.success(parseRes.msg);
    } else {
      toast.error(parseRes.msg);
    }
  } catch (error) {
    toast.error("서버 오류 발생: " + error.message);
  }
};

 

로그인 및 회원가입 처리

const handleSubmit = async (e) => {
  e.preventDefault();

  if (!isLogin && !isVerified) {
    setErrors((prev) => ({
      ...prev,
      verificationCode: "전화번호 인증을 완료해주세요.",
    }));
    return;
  }

  const cleanedPhoneNumber = registerData.phone_number.replace(/-/g, "");

  const endpoint = isLogin
    ? "https://maketerbackend.fly.dev/api/v1/login"
    : "https://maketerbackend.fly.dev/api/v1/register";

  const data = isLogin
    ? loginData
    : { ...registerData, phone_number: cleanedPhoneNumber };

  try {
    const response = await fetch(endpoint, {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify(data),
      credentials: "include",
    });

    const parseRes = await response.json();

    if (parseRes.resultCode === "S-1") {
      if (isLogin) {
        setAuth({
          isAuthenticated: true,
          userId: parseRes.data.userId,
          username: parseRes.data.username,
          email: parseRes.data.email,
        });
        toast.success("로그인 성공!");
        onClose();
      } else {
        toast.success("회원가입 성공!");
        setIsLogin(true);
      }
    } else {
      toast.error(isLogin ? "로그인 실패!" : "회원가입 실패!");
    }
  } catch (err) {
    toast.error("서버 오류 발생: " + err.message);
  }
};

 

 

로그인: 세션 생성 후 전역 상태(authState) 업데이트해서 세션 인증 처리완료

회원가입: 성공 시 로그인 화면으로 전환합니다