카테고리 없음
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; //액션들 과 리듀서 익스포트
// 굳굳굳 좋은 로직이었당.