카테고리 없음

23/12/15 심화주차 팀과제 리뷰(3)

한지지우우 2023. 12. 18. 08:53

오늘은 미희님이 짜신 코드중에서 로그인과 회원가입을 봅세다.

 

<Login.jsx>

import React, {useState} from 'react';
import Button from '../components/UI/Button';
import {signInWithEmailAndPassword, signInWithPopup} from 'firebase/auth';  //이거는 단순한 로그인
import {auth} from '../shared/firebase';                                                       //  두번째 인자는 뭐지?
import styled from 'styled-components';
import {useNavigate} from 'react-router-dom';
import {toast} from 'react-toastify';                        
import {GoogleAuthProvider} from 'firebase/auth';   //이게 파이어베이스에서 제공하는 구글로 로그인
import {useDispatch} from 'react-redux';               //하는건가봄
import {login} from '../redux/modules/Auth';   //이건 만드신 리듀서 이따가 확인해 보자

const Login = () => {
  const navigate = useNavigate();
  const dispatch = useDispatch();

  const [inputs, setInputs] = useState({     //초기 스테이트를 객체로 하셨군 흠흠 좋아
    email: '',
    password: '',
  });

  // input 변경
  const changeInputs = e => {
    setInputs({
      ...inputs,
      [e.target.name]: e.target.value,    //e.target.name이 있는것으로 봐선 온체인지들에
    });                                              //공통으로 쓰실 용도 인가봄
  };

  // input 비우기
  const clearInputs = () => {     //인풋 비우기 함수가 따로 있다고???
    setInputs({
      email: '',
      password: '',
    });
  };

  // 유효성 검사
  const checkInputs = () => {
    // 빈칸 
    if (inputs.email.trim().length === 0 || inputs.email.trim().length === 0) {
      toast.error('이메일과 비밀번호를 모두 입력해주세요', {
        position: 'top-center',                                       //trim() 이 메서드는 처음보넹 다듬는건가?
        autoClose: 3000,                                         //그런데 || 양 옆이 같은 로직잉네?? 뭐지?
        hideProgressBar: false,                            //두개의 인풋에 내용이 없으면 alert 뜨는 로직같은데 말이지
        closeOnClick: true,
        pauseOnHover: true,                          //이건 토스트 에러고 객체들은 걍 옵션이고..
        draggable: false,
        progress: undefined,
        theme: 'colored',
      });
      clearInputs();            //아하 이러실려고 클리어 인풋이 있었구나 깔끔하네
      return;                         //에러뜨면 바로 함수 종료
    }
    // 이메일형식이 아닐 때
    if (!inputs.email.includes('@')) {       //이메일 형식이 아니면 alert 주는구먼
      toast.error('올바른 이메일 형식을 입력해주세요', {      //토스트가 옵션이 참 많네
        position: 'top-center',         //위치, 꺼지는 시간 , 눌렀을때 꺼저라, 드레그 안되고
        autoClose: 3000,
        hideProgressBar: false,       
        closeOnClick: true,                 // 호버됐을때 멈춰라 주제는 색깔칠?
        pauseOnHover: true,
        draggable: false,
        progress: undefined,
        theme: 'colored',
      });
      clearInputs();
      return;
    }
  };

  // email 로그인
  const loginEmail = async e => {
    e.preventDefault();                       // 폼태그 인가보넹 preventDefault 있는거 보니깐
    checkInputs();                     //인풋 체크해주고
    try {
      const userCredential = await signInWithEmailAndPassword(auth, inputs.email, inputs.password);

      toast.success('로그인 성공!', {                   //파이어베이스 로그인 로직 이고
        position: 'top-center',
        autoClose: 3000,
        hideProgressBar: false,           //성공시 토스트 뜨고
        closeOnClick: true,
        pauseOnHover: true,
        draggable: false,
        progress: undefined,
        theme: 'colored',
      });
      localStorage.setItem('accessToken', userCredential.user.accessToken);      //엑세스토큰 로컬에 저장해주고
      dispatch(login(userCredential.user));            //리덕스에 스테이트도 변경해주고
      navigate('/');                                             // userCredential.user 이런 요소를 내장하고 있구먼
    } catch (error) {
      toast.error('로그인 정보를 다시 확인해주세요', {
        position: 'top-center',
        autoClose: 3000,
        hideProgressBar: false,
        closeOnClick: true,
        pauseOnHover: true,
        draggable: false,
        progress: undefined,
        theme: 'colored',
      });
    }
  };

  // google 로그인
  const loginGoogle = async e => {
    e.preventDefault();
    const provider = new GoogleAuthProvider();     //이게 구글 로그인 이구먼 //제공받는 함수 같고..
    try {
      const userCredential = await signInWithPopup(auth, provider);
      toast.success('로그인 성공!', {                      // 아하 사인윗팝업을 구글로그인때 쓰는 구먼
        position: 'top-center',                                    //인자 두개 제공해주고
        autoClose: 3000,
        hideProgressBar: false,
        closeOnClick: true,
        pauseOnHover: true,
        draggable: false,
        progress: undefined,
        theme: 'colored',
      });
      localStorage.setItem('accessToken', userCredential.user.accessToken);
      navigate('/');                                                       // 역시 토큰 저장과  // 홈화면 이동 그리고 스테이트 변경
      dispatch(login(userCredential.user));               // 근데 어차피 액션리듀서에 유저정보 넘기니까
    } catch (error) {                                                             //로컬스토리지는 리듀서에 설정해서 엑세스토큰 받고
      toast.error('로그인 정보를 다시 확인해주세요', {           //로직 작성하는게 깔끔 할듯?
        position: 'top-center',
        autoClose: 3000,
        hideProgressBar: false,
        closeOnClick: true,
        pauseOnHover: true,
        draggable: false,
        progress: undefined,
        theme: 'colored',
      });
    }
  };

  const moveToRegisterPage = e => {     //흠흠 회원가입 페이지로 이동이라 좋군
    e.preventDefault();
    navigate('/register');
  };

  return (
    <ScWrapper>
      <ScForm>
        <h1>로그인</h1>
        <input type="email" placeholder="이메일" name="email" value={inputs.email} onChange={changeInputs} />
        <input
          type="password"
          placeholder="비밀번호"           //여기다가 네임 속성을 줘서 이걸로 
          name="password"
          required
          value={inputs.password}                //e.target 의 벨류와 네임을 쓸 예정이겠고
          onChange={changeInputs}             //요기 함수에서 사용하는구먼
        />
        <Button onClick={loginEmail}>로그인</Button>
        <Button onClick={loginGoogle}>구글로 로그인</Button>
        <span onClick={moveToRegisterPage}>회원가입 하러가기</span>
      </ScForm>
    </ScWrapper>
  );
};

const ScWrapper = styled.div`
  display: flex;
  justify-content: center;
  align-items: center;
  width: 100%;
  height: 100vh;
  background-color: var(--light-blue);
`;

const ScForm = styled.form`
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  width: 40%;
  height: 50%;
  padding: 30px;
  border-radius: 10px;
  background-color: var(--white);

  h1 {
    font-size: 2rem;
    font-weight: bold;
    margin-bottom: 30px;
  }

  input {
    width: 50%;
    border: none;
    padding: 10px;
    border-radius: 10px;
    margin-bottom: 10px;
    background-color: #eee;
  }

  input:nth-child(3) {
    margin-bottom: 20px;
  }

  button {
    width: 50%;
    margin-bottom: 10px;
  }

  span {
    margin-top: 10px;
    cursor: pointer;
    color: var(--deep-blue);
    font-weight: bold;
  }
`;

export default Login;

//흠흠 

 

로그인때 사용하는 RTK 만 보자구

<Auth.js>

import {createSlice} from '@reduxjs/toolkit';

const initialState = {                        //로컬 스토리지 겟네임으로 첫 랜더링시 밸류값이 생기가 하셨고
  isLogin: !!localStorage.getItem('accessToken'),
  displayName: localStorage.getItem('displayName'),   //그러고 보니 나 심화플러스 개인과제때 
  uid: localStorage.getItem('uid'),                              //로컬 스토리지를 안썻네?? 인증단계가 없어서 안썻네 ㅋㅋ
  photoURL: localStorage.getItem('photoURL'),      
  email: localStorage.getItem('email'),
};

const AuthSlice = createSlice({
  name: 'auth',
  initialState,
  reducers: {
    login: (state, action) => {
      const {displayName, uid, photoURL, email} = action.payload;
      localStorage.setItem('displayName', displayName);
      localStorage.setItem('uid', uid);
      localStorage.setItem('photoURL', photoURL);   //여기서 로컬스토리지로 저장해 주고
      localStorage.setItem('email', email);                    //아니 여기 다 있으신다 왜  accessToken 만
      state.isLogin = true;                                            //왕따 시키셨지? 귀찮으셨나?
      state.displayName = displayName;
      state.uid = uid;                                     //로컬에 저장하는 것만으로는 스테이트가 안변하니까
      state.photoURL = photoURL;              //스테이트 변하는 로직도 쓰셨고
      state.email = email;                   // 이머가 있으니까 편하군
    },
    logout: (state, action) => {
      localStorage.clear();               //로컬스토리지 날려주시고 // 파이어베이스 로그아웃은 따로
                                                  //안 만드셨길래 그건 내가 조용히 로그아웃 버튼에 직접 달았음 ㅋㅋ
      return (state = {});
    },
    updateNickname: (state, action) => {                                 // 밑에 두개 리듀서는 실제 페이지에서 
      localStorage.setItem('displayName', action.payload);      //보고 리뷰 해야겠네
      state.displayName = action.payload;
    },
    updatePhoto: (state, action) => {
      localStorage.setItem('photoURL', action.payload);
      state.photoURL = action.payload;
    },
  },
});

export const {login, logout, updateNickname, updatePhoto} = AuthSlice.actions;
export default AuthSlice.reducer;                  //액션들 과 리듀서 익스포트 

// 굳굳굳 좋은 로직이었당.