지출 내역 APP (개인 프로젝트)

지출 내역 리스트 기능 추가하기 : 2

고래고래00 2024. 6. 13. 11:47

기존 지출 내역 리스트에 기능 추가하기

구현 순서

  1. 회원가입, 로그인 페이지 및 폼의 UI 생성
  2. jwt 인증서버를 사용한 회원가입, 로그인 기능 추가 및 인증 상태 관리
  3. 내비게이션 바 생성 및 라우터 설정
  4. 프로필 수정 페이지 생성 및 프로필 수정 기능 추가
  5. json-server와 Tanstack Query를 사용해 지출 CRUD 구현
  6. 이후 디테일한 부분 및 선택 구현 사항 다루기

 

2. jwt 인증서버를 사용한 회원가입, 로그인 기능 추가 및 인증 상태 관리

제공되는 jwt(토큰을 이용한 인증 방식) 인증서버를 사용해서 회원가입, 로그인 기능 추가

제공된 API 명세서를 보고 Method 및 URL PATH 등을 설정

 

현재 로그인 상태인지 로그아웃 상태인지를 확인하기 위해 로그인 상태 및 로그인한 유저의 정보를 Redux로 관리

src/redux/slices/auth.slice.js

더보기
import { createSlice } from "@reduxjs/toolkit";

const initialState = {
  isLogin: localStorage.getItem("accessToken") ? true : false,
  userInfo: null,
};

const authSlice = createSlice({
  name: "auth",
  initialState,
  reducers: {
    login: (state, action) => { // 로그인시 accessToken을 로컬스토리지에 저장
      state.isLogin = true; 
      localStorage.setItem("accessToken", action.payload); 
    },
    logout: (state) => { // 로그아웃시 accessToken을 로컬스토리지에서 삭제
      state.isLogin = false;
      localStorage.removeItem("accessToken");
      state.userInfo = null; // 로그아웃시 담아놨던 유저 정보를 제거
    },
    setUserInfo: (state, action) => {
      state.userInfo = action.payload; // 로그인시 현재 유저의 id, 닉네임과 같은 정보를 담음
    },
  },
});

export const { login, logout, setUserInfo } = authSlice.actions;
export default authSlice.reducer;

 

모든 요청은 axios를 이용해야하기 때문에 axios custom instance 생성

src/api/axios.js

더보기
export const authApi = axios.create({
  baseURL: 제공된 서버 URL
});

 

회원가입 기능

required 속성을 넣어도 공백을 넣으면 통과가 되기때문에 공백 또한 필터를 하기 위해 trim을 이용해 한번 더 검사

비밀번호와 비밀번호 확인의 내용이 다른 것 또한 필터링

더보기
const handleSubmitSignUpForm = async (event) => {
        event.preventDefault();
        setIsIdValid(true);
        setIsPasswordValid(true);
        setIsPasswordComfirmValid(true);
        setIsNicknameValid(true);
		
        // 유효성 검사
        if (!id.trim()) return setIsIdValid(false);
        if (!password.trim()) return setIsPasswordValid(false);
        if (password !== passwordConfirm) return setIsPasswordComfirmValid(false);
        if (!nickname.trim()) return setIsNicknameValid(false);

	// 회원가입 로직
        // 제공된 API 서버의 path로 새로운 유저 데이터 추가(POST) 요청
        try {
            const response = await authApi.post("/register", {
                id,
                password,
                nickname,
            })
            const { data } = response;
            if (data.success) {	// 요청(유저 추가)성공시 알림 및 로그인 페이지으로 이동
                alert("회원가입 성공!");
                navigate("/login");
            } else {			// 요청 실패시 알림
                alert("Signup failed");
            }
        } catch (error) {		
            console.error("Signup error:", error);
            alert("Signup failed");
        }

    };

 

로그인 기능

회원가입과 유사

더보기
const handleSubmiLoginForm = async (event) => {
        event.preventDefault();
        setIsIdValid(true);
        setIsPasswordValid(true);
        if (!id.trim()) return setIsIdValid(false);
        if (!password.trim()) return setIsPasswordValid(false);

        try {
            const response = await authApi.post("/login",
                {
                    id,
                    password,
                }
            );
            const data = response.data;
            if (data.success) {
                dispatch(login(data.accessToken));
                alert("로그인 성공!");
            } else {
                alert("Login failed");
            }
        } catch (error) {
            console.error("Login error:", error);
            alert("Login failed");
        }
    };

 

결과

회원가입

 

로그인