본문 바로가기

TIL

개인과제 - MBTI 성격 유형 테스트 ①

(1) 기본 페이지, 컴포넌트 구성

페이지

Home, Signin, Signup, Profile, TestPage, TestResultPage

컴포넌트

Layout, AuthForm, TestForm, TestResultList, TestResultItem

 

(2) 레이아웃 컴포넌트 만들기

레이아웃을 PublicLayout과  PrivateLayout으로 분리하여 만들었다.

// PublicLayout
const PublicLayout = () => {
  return (
    <>
      <Link to="/signin">로그인</Link>
    </>
  );
};

// PrivateLayout
const PrivateLayout = () => {
  const { logout } = useContext(AuthContext);
  const navigate = useNavigate();

  const handleLogout = () => {
    const confirmLogout = window.confirm("정말로 로그아웃 하시겠습니까?");
    if (confirmLogout) {
      logout();
      navigate("/");
    }
  };

  return (
    <>
      <Link to="/profile">프로필</Link>
      <Link to="/testpage">테스트</Link>
      <Link to="/testresult">결과보기</Link>
      <button onClick={handleLogout}>로그아웃</button>
    </>
  );
};
// Layout
const Layout = () => {
  const { isAuthenticated } = useContext(AuthContext);
  return (
    <div>
      <header>
        <Link to="/">홈</Link>
        {isAuthenticated ? <PrivateLayout /> : <PublicLayout />}
      </header>
      <main>
        <Outlet />
      </main>
    </div>
  );
};

 

(3) 로그인 및 회원가입 구현

// 회원가입
const SignUp = () => {
  return (
    <>
      <AuthForm />
    </>
  );
};

const AuthForm = () => {
  const navigate = useNavigate();
  const [formData, setFormData] = useState({
    id: "",
    password: "",
    nickname: "",
  });

  const handleChange = (e) => {
    setFormData({ ...formData, [e.target.name]: e.target.value });
  };

  const handleSubmit = async (e) => {
    e.preventDefault();
    try {
      const response = await axios.post(
        `${API_URL}/register`,
        {
          id: formData.id,
          password: formData.password,
          nickname: formData.nickname,
        }
      );
      const data = response.data;

      if (data.success) {
        navigate("/signin");
      } else {
        alert("회원가입 실패");
      }
    } catch (error) {
      console.error("회원가입 에러 :", error);
      alert("회원가입 실패");
    }
  };

  return (
    <div>
      <h1>회원가입</h1>
      <form onSubmit={handleSubmit}>
        <input
          name="id"
          type="text"
          placeholder="아이디 입력"
          value={formData.id}
          onChange={handleChange}
        />
        <input
          name="password"
          type="password"
          placeholder="비밀번호 입력"
          value={formData.password}
          onChange={handleChange}
        />
        <input
          name="nickname"
          type="text"
          placeholder="닉네임 입력"
          value={formData.nickname}
          onChange={handleChange}
        />
        <button type="submit">회원가입</button>
      </form>
      <p>
        이미 계정이 있으신가요?{" "}
        <button onClick={() => navigate("/signin")}>로그인</button>
      </p>
    </div>
  );
};
// 로그인
const SignIn = () => {
  const [id, setId] = useState("");
  const [password, setPassword] = useState("");
  const { login } = useContext(AuthContext);
  const navigate = useNavigate();

  const handleSubmit = async (e) => {
    e.preventDefault();
    try {
      const response = await axios.post(
        `${API_URL}/login`,
        {
          id,
          password,
        }
      );

      const data = response.data;
      if (data.success) {
        login(data.accessToken);
        navigate("/profile");
      } else {
        alert("로그인에 실패했습니다.");
      }
    } catch (error) {
      console.error("Login error :", error);
      alert("로그인에 실패했습니다.");
    }
  };

  return (
    <div>
      <h3>SignIn</h3>
      <form onSubmit={handleSubmit}>
        <input type="text" value={id} onChange={(e) => setId(e.target.value)} />
        <input
          type="password"
          value={password}
          onChange={(e) => setPassword(e.target.value)}
        />
        <button type="submit">로그인</button>
      </form>
      <p>
        계정이 없으신가요?
        <button onClick={() => navigate("/signup")}>회원가입</button>
      </p>
    </div>
  );
};

 

(4) 라우터 설정(Private, Public 페이지 분리)

PublicRoute, PrivateRoute 생성 후 로그인된 사용자만 특정 페이지에 접근 할 수 있도록 하기

// PublicRoute
const PublicRoute = () => {
  const { isAuthenticated } = useContext(AuthContext);
  return isAuthenticated ? <Navigate to="/" /> : <Outlet />;
};

// PrivateRoute
const PrivateRoute = () => {
  const { isAuthenticated } = useContext(AuthContext);
  return !isAuthenticated ? <Navigate to="/signin" /> : <Outlet />;
};

// Router
const AppRouter = () => {
  return (
    <Router>
      <Routes>
        <Route element={<Layout />}>
          <Route path="/" element={<Home />} />

          <Route element={<PublicRoute />}>
            <Route path="/signin" element={<SignIn />} />
            <Route path="/signup" element={<SignUp />} />
          </Route>

          <Route element={<PrivateRoute />}>
            <Route path="/profile" element={<Profile />} />
            <Route path="/testpage" element={<TestPage />} />
            <Route path="/testresult" element={<TestResultPage />} />
          </Route>
        </Route>
      </Routes>
    </Router>
  );
};

 

 

■ 느낀점

하루종일 인증/인가 부분을 코드로 구현하는 게 어려워서 강의와 강의자료를 엄청 많이 봤다. 어떻게든 따라서 구현은했는데,, 아직 익숙하진 않은 것 같다. 좀 더 연습해야 할 것 같고, 내일은 테스트페이지와 테스트 결과 페이지를 구현하고 Tailwind CSS 도 해보기!