React/Daily

[moneybook]_day6

오늘도 코딩하나 2024. 9. 2. 23:52

로그인 화면 만들기

 

일단 간단하게 아이디를 입력 후 로그인 버튼을 누르면 회원아이디 여부를 확인하는 로직만 만들었다.

 

 

- server.js

app.post('/loginCheck', function(req, res) {
    const userId = req.body.userId;
    const password = req.body.userPw;
    const sendData = { isLogin: "" };

    if(userId && password) {
        db.query('SELECT * FROM USER WHERE USER_ID = ?', [userId], function(err, results, fields) {
            if(err) {
                console.log('Database error: ', err);
                sendData.isLogin = "서버 에러가 발생했습니다.";
                return res.status(500).send(sendData);
            }
            
            if(results.length) {
                sendData.isLogin = "True"
            } else {
                sendData.isLogin = "로그인 정보가 일치하지 않습니다."
            }
            res.send(sendData);
        })
    }
    
})

 

 

- paySlice.js

export const loginData = createAsyncThunk('loginCheck/loginData', async (data) => {
    const response = await axios.post('http://localhost:8009/loginCheck', data);
    console.log(response.data)
    return response.data;
})

let payList = createSlice({
    name : 'payList',
    initialState : {
        items: [],
        status: 'idle',
        error: null,
    },
    extraReducers: (builder) => {
        builder
            .addCase(fetchData.pending, (state) => {
                state.status = 'loading';
            })
            .addCase(fetchData.fulfilled, (state, action) => {
                state.status = 'succeeded';
                state.items = action.payload;
            })
            .addCase(fetchData.rejected, (state, action) => {
                state.status = 'failed';
                state.error = action.error.message;
            })
            .addCase(saveData.fulfilled, (state, action) => {
                state.items = action.payload;
            })
            .addCase(loginData.pending, (state) => {
                state.loginStatus = 'loading';
            })
            .addCase(loginData.fulfilled, (state, action) => {
                state.loginStatus = 'succeeded';
                state.loginMessage = action.payload.isLogin;
            })
            .addCase(loginData.rejected, (state, action) => {
                state.loginStatus = 'failed';
                state.loginMessage = action.payload.isLogin;
            })
    }
})

(1) loginData : 회원정보 확인 thunk 추가

(2) loginData에 대한 extaReducers 추가(pending, fulfilled, rejected)

 

 

- Login.js

import './../App.css';
import { Form, Button } from 'react-bootstrap'
import { useEffect, useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { loginData } from '../store/paySlice';
import { useNavigate } from 'react-router-dom';

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

    const [userId, setUserId] = useState('');
    const [userPw, setUserPw] = useState('');
    
    const loginStatus = useSelector((state) => state.payList.loginStatus);
    const loginMessage = useSelector((state) => state.payList.loginMessage);

    // 로그인
    const handleLogin = () => {
        if(userId === '') {
            alert('아이디 안썼는디?');
            return false;
        }

        dispatch(loginData({userId, userPw}));
    }

    // loginData result에 따른 처리
    // 회원정보 O -> /dashboard(main화면)으로 이동
    // 회원정보 X -> loginMessage 출력
    useEffect(() => {
        if(loginStatus === 'succeeded' && loginMessage === 'True') {
            navigate('/dashboard');
        } else if(loginStatus === 'succeeded' && loginMessage !== 'True') {
            alert(loginMessage);
        }
    }, [loginStatus, loginMessage, navigate])

    return (
        <div className="contents login_contents">
            <div className="login_box">
                <h2 className="loginTit">로그인</h2>
                <div className="input_item id">
                    <input type="text" id="user_id" className="input_id" value={userId} onChange={e => setUserId(e.target.value)} />
                    <label htmlFor="user_id" className="text_label">아이디 또는 전화번호</label>
                    <button type="button" className="btn_delete" id="id_clear">
                        <span className="icon_delete"><span className="blind">삭제</span></span>
                    </button>
                </div>
                <div className="input_item pw">
                    <input type="password" id="user_pw" className="input_pw" value={userPw} onChange={e => setUserPw(e.target.value)} />
                    <label htmlFor="user_pw" className="text_label">비밀번호</label>
                    <button type="button" className="btn_view hide" id="pw_hide">
                        <span className="icon_view">
                            <span className="blind" id="icon_view">선택 안 됨,비밀번호 표시</span>
                        </span>
                    </button>
                    <button type="button" className="btn_delete" id="pw_clear">
                        <span className="icon_delete">
                            <span className="blind">삭제</span>
                        </span>
                    </button>
                </div>
                <div className="save">
                    <Form.Check label="아이디 저장" />
                </div>
                <div className="link">
                    <p>아이디 찾기</p>
                    <p>비밀번호 찾기</p>
                </div>
                <Button className="loginBtn" onClick={handleLogin}>로그인</Button>
            </div>
        </div>
    )
}

 

이제 기본적인 것들을 해봤으니

비밀번호 암호화, 로그인 상태 관리, 아이디 저장, 아이디/비밀번호 찾기 등등

로그인 관련 모든 기능에 대한 구현을 해볼 생각이다.