카테고리 없음

20240531_모놀리틱) 타입스크립트로 전환

일일일코_장민기 2024. 5. 31. 23:56
728x90

타입스크립트

import React, { useEffect, useState } from 'react';
import axios from 'axios';
import { NavLink, useNavigate } from 'react-router-dom';

interface MemberData {
    id: number;
    username: string;
    email: string;
    country: string;
    area: string;
}

const MyPage: React.FC = () => {
    const [memberData, setMemberData] = useState<MemberData | null>(null);
    const navigate = useNavigate();

    useEffect(() => {
        axios.get('http://localhost:8888/MyPage', { withCredentials: true })
            .then(response => {
                if (response.status === 200) {
                    setMemberData(response.data);
                } else if (response.status === 401) {
                    navigate('/LoginPage');
                }
            })
            .catch(error => {
                console.error('There was an error!', error);
                navigate('/LoginPage');
            });
    }, [navigate]);

    if (!memberData) {
        return <div>Loading...</div>;
    }

    return (
        <div>
            <h1>My Page</h1>
            <p>ID: {memberData.id}</p>
            <p>Username: {memberData.username}</p>
            <p>Email: {memberData.email}</p>
            <p>Country: {memberData.country}</p>
            <p>Area: {memberData.area}</p>
            <h2>Cloth</h2>
            <h2>Weather</h2>
            <h2>Dust</h2>
            <h2>GPT</h2>
            <p>
                <NavLink to="/ClothEditPage">옷장</NavLink><br/>
                <NavLink to="/ChangePasswordPage">비밀번호 변경</NavLink><br/>
                <NavLink to="/ChangeEmailPage">이메일 변경</NavLink><br/>
                <h2>로그아웃</h2>
            </p>
        </div>
    );
}

export default MyPage;

 

자바스크립트

import React, { useEffect, useState } from 'react';
import axios from 'axios';
import {NavLink, useNavigate} from 'react-router-dom';

function MyPage() {
    const [memberData, setMemberData] = useState(null);
    const navigate = useNavigate();

    useEffect(() => {
        axios.get('http://localhost:8888/MyPage', { withCredentials: true })
            .then(response => {
                if (response.status === 200) {
                    setMemberData(response.data);
                } else if (response.status === 401) {
                    navigate('/LoginPage');
                }
            })
            .catch(error => {
                console.error('There was an error!', error);
                navigate('/LoginPage');
            });
    }, [navigate]);

    if (!memberData) {
        return <div>Loading...</div>;
    }

    return (
        <div>
            <h1>My Page</h1>
            <p>{memberData.id}</p>
            <p>Username: {memberData.username}</p>
            <p>Email: {memberData.email}</p>
            <p>Country: {memberData.country}</p>
            <p>Area: {memberData.area}</p>
            <p><h2>Cloth</h2></p>
            <p><h2>Weather</h2></p>
            <p><h2>Dust</h2></p>
            <p><h2>GPT</h2></p>
            <p>
                <NavLink to="/ClothEditPage">옷장</NavLink><br/>
                <NavLink to="/ChangePasswordPage">비밀번호 변경</NavLink><br/>
                <NavLink to="/ChangeEmailPage">이메일 변경</NavLink><br/>
                <h2>로그아웃</h2>
            </p>
        </div>
    );
}

export default MyPage;

 

interface MemberData {
    id: number;
    username: string;
    email: string;
    country: string;
    area: string;
}

인터페이스를 생성해서 커스텀 타입 생성

 

const MyPage: React.FC = () => {

리엑트에서 타입스크립트를 사용하기 위한 React.FC

- 다만 이 경우에는 children Props의 타입 체킹이 되지 않기 때문에 지양하라는 글이 많기도 했다.

- 다음 작업부터는 사용하지 않고 명시적으로 타입을 입력할 것

 

const [memberData, setMemberData] = useState<MemberData | null>(null);

인터페이스를 useState에 타입 지정

 

 

기타 변경된 코드

더보기

LoginPage

import {NavLink, useNavigate} from "react-router-dom";
import React, {useState, FormEvent, ChangeEvent} from "react";
import axios from "axios";

const LoginPage: React.FC = () => {

    const [username, setUsername] = useState<string>('');
    const [password, setPassword] = useState<string>('');
    const navigate = useNavigate();

    const handleSubmit = async (event: FormEvent<HTMLFormElement>) => {
        event.preventDefault();
        axios.defaults.withCredentials = true;
        try {
            const response = await axios.post('/login', {
                username: username,
                password: password
            }, {
                headers: {
                    'Content-Type': 'application/json'
                }
            });
            if (response.status === 200) {
                navigate('/MyPage');
            } else {
                console.log('로그인 실패');
                navigate('/LoginPage');
            }
        } catch (error) {
            console.error('Error:', error);
        }
    };

    const handleUsernameChange = (event: ChangeEvent<HTMLInputElement>) => {
        setUsername(event.target.value);
    };

    const handlePasswordChange = (event: ChangeEvent<HTMLInputElement>) => {
        setPassword(event.target.value);
    };

    return (
        <div>
            <h1>로그인 페이지</h1>
            <form id="loginForm" onSubmit={handleSubmit}>
                <label>username: <input type="text" value={username} onChange={handleUsernameChange}/></label>
                <label>password: <input type="password" value={password} onChange={handlePasswordChange}/></label>
                <span id="loginErrorField"></span><br/>
                <div>
                    <input type="submit" value="로그인"/>
                </div>
            </form>
            <p>
                <NavLink to="/RegisterPage">회원가입 페이지</NavLink><br/>
                <NavLink to="/FindUserInfo">회원 정보 찾기 페이지</NavLink><br/>
            </p>
        </div>
    );
}

export default LoginPage;

 RegisterPage

import React, { useEffect, useState } from "react";
import { NavLink, useNavigate } from "react-router-dom";
import axios from "axios";

const RegisterPage: React.FC = () => {
    const [username, setUsername] = useState<string>("");
    const [password, setPassword] = useState<string>("");
    const [email, setEmail] = useState<string>("");
    const [country, setCountry] = useState<string>("");
    const [area, setArea] = useState<string>("");
    const [countryList, setCountryList] = useState<string[]>([]);
    const [areaList, setAreaList] = useState<string[]>([]);
    const [existUsername, setExistUsername] = useState<string>("");
    const [existEmail, setExistEmail] = useState<string>("");
    const [checkAuthorizationCodeField, setCheckAuthorizationCodeField] = useState<string>("");
    const [code, setCode] = useState<string>("");
    const navigate = useNavigate();

    useEffect(() => {
        fetch("/findCountries")
            .then((response: Response) => response.json())
            .then(function(result: string[]){
                setCountryList(result);
                if(result.length > 0){
                    setCountry(result[0]);
                }
            })
    }, []);

    useEffect(() => {
        fetch(`/findAreasByCountry?country=${country}`)
            .then((response: Response) => response.json())
            .then(function(result: string[]){
                setAreaList(result);
                setArea(result[0]);
            })
    }, [country]);


    // 아이디 중복 체크
    const usernameAjax = async (event: React.ChangeEvent<HTMLInputElement>) => {
        const newUsername = event.target.value;
        setUsername(newUsername);
        try {
            const response = await axios.post<boolean>(`/usernameAjax?username=${newUsername}`, {}, {
                headers: {
                    "Content-Type": "application/json"
                }
            });
            if (response.status === 200) {
                setExistUsername(response.data ? "아이디 중복" : "");
            }
        } catch (error) {
            console.error('Error checking username:', error);
        }
    }

    // 이메일 중복 체크
    const emailAjax = async (event: React.ChangeEvent<HTMLInputElement>) => {
        const newEmail = event.target.value;
        setEmail(newEmail);
        axios.defaults.withCredentials = true;
        try {
            const response = await axios.post<boolean>(`/emailAjax?email=${newEmail}`, {}, {
                headers: {
                    "Content-Type": "application/json"
                }
            });
            if (response.status === 200) {
                setExistEmail(response.data ? "이메일 중복" : "");
            }
        } catch (error) {
            console.error(error);
        }
    }

    // 이메일 인증 코드 요청
    const emailAuthorizationCode = async () => {
        axios.defaults.withCredentials = true;
        try {
            const response = await axios.post(`/emailAuthorizationCode?email=${email}`, {}, {
                headers: {
                    "Content-Type": "application/json"
                }
            });
            if (response.status === 200) {
                alert("인증번호가 메일로 전송되었습니다.");
            }
        } catch (error) {
            console.error(error);
        }
    }

    // 인증 코드 확인
    const codeAjax = async (event: React.ChangeEvent<HTMLInputElement>) => {
        const newCode = event.target.value;
        setCode(newCode);
        const cookies = document.cookie.split(";").map(cookie => cookie.split("=")).find(([name]) => name.trim() === "authorizationCode");
        if (cookies && cookies[1] === newCode) {
            setCheckAuthorizationCodeField("확인되었습니다.");
        } else {
            setCheckAuthorizationCodeField("인증번호 오류");
        }
    }

    const handleSubmit = async (event: React.FormEvent<HTMLFormElement>) => {
        event.preventDefault();
        let errorMessage = '';
        switch (true) {
            case existUsername === "아이디 중복":
                errorMessage = '아이디 중복 상태입니다.';
                break;
            case existEmail === "이메일 중복":
                errorMessage = '이메일 중복 상태입니다.';
                break;
            case checkAuthorizationCodeField === "인증번호 오류":
                errorMessage = '코드 불일치 상태입니다.';
                break;
            default:
                axios.defaults.withCredentials = true;
                try {
                    const response = await axios.post("/saveUser", {
                        username: username,
                        password: password,
                        email: email,
                        country: country,
                        area: area
                    }, {
                        headers: {
                            "Content-Type": "application/json"
                        }
                    });
                    if (response.status === 200) {
                        navigate("/LoginPage");
                    } else {
                        navigate("/RegisterPage");
                    }
                } catch (error) {
                    console.error("Error: ", error);
                }
        }
        if (errorMessage !== "") {
            alert(errorMessage);
        }
    }

    return (
        <div>
            <form id="registerForm" onSubmit={handleSubmit}>
                username:
                <input type="text" id="username" name="username"
                       onChange={usernameAjax}
                       required minLength={3} /><br />
                <span id="existUsername">{existUsername}</span><br />

                password:
                <input type="password" id="password" name="password"
                       onChange={(event) => setPassword(event.target.value)}
                       required minLength={3} /><br />

                email:
                <input type="email" id="email" name="email"
                       onChange={emailAjax}
                       required minLength={3} /><br />
                <span id="existEmail">{existEmail}</span><br />

                인증번호:
                <input type="text" id="authorizationCode" onChange={codeAjax} />
                <input type="button" id="sendEmail" value="인증번호 보내기" onClick={emailAuthorizationCode} /><br />
                <span id="checkAuthorizationCodeField">{checkAuthorizationCodeField}</span><br />

                country:
                <select id="country" value={country} onChange={(event) => setCountry(event.target.value)}>
                    {countryList && countryList.map((country: string, index: number) => (
                        <option key={index} value={country}>{country}</option>
                    ))}
                </select><br />

                area:
                <select id="area" value={area} onChange={(event) => setArea(event.target.value)}>
                    {areaList && areaList.map((area: string, index: number) => (
                        <option key={index} value={area}>{area}</option>
                    ))}
                </select>
                <input type="submit" value="회원가입" />
            </form>
            <p>
                <NavLink to="/loginPage">로그인 페이지</NavLink>
            </p>
        </div>
    );
}

export default RegisterPage;

 

 App

import main from './images/main.jpg';
import LoginPage from './path/beforeLogin/LoginPage';
import ClothEditPage from './path/afterLogin/ClothEditPage'
import RegisterPage from "./path/beforeLogin/RegisterPage"
import './App.css';
import React, { useState, useEffect, FormEvent } from "react";
import {HashRouter, Routes, Route, NavLink, useNavigate, useLocation} from "react-router-dom";
import MyPage from "./path/afterLogin/MyPage";
import axios from "axios";

const App: React.FC = () => {

    return (
        <HashRouter>
            <div className="App">
                <header className="mainImage">
                    <NavLink to='/loginPage'><img src={main} className="App-logo" alt="logo" height={"100px"}/></NavLink>
                </header>
                <Routes>
                    <Route path='/' element={'MainPage'}/>
                    <Route path='/LoginPage' element={<LoginPage></LoginPage>}/>
                    <Route path='/RegisterPage' element={<RegisterPage></RegisterPage>}/>
                    <Route path='/FindUserInfo' element={<FindUserInfo></FindUserInfo>}/>
                    <Route path='/ViewUsername' element={<ViewUsername></ViewUsername>}/>
                    <Route path='/ViewChangedPassword' element={<ViewChangedPassword></ViewChangedPassword>}/>
                    <Route path='/MyPage' element={<MyPage></MyPage>}/>
                    <Route path='/ClothEditPage' element={<ClothEditPage></ClothEditPage>}/>
                    <Route path='/ChangePasswordPage' element={<ChangePasswordPage></ChangePasswordPage>}/>
                    <Route path='/ChangeEmailPage' element={<ChangeEmailPage></ChangeEmailPage>}/>
                    <Route path='/*' element={'Not Found'}/>
                </Routes>
            </div>
        </HashRouter>
    );
}

function FindUserInfo() {
    const [email, setEmail] = useState<string>("");
    const [username, setUsername] = useState<string>("");
    const [passwordEmail, setPasswordEmail] = useState<string>("");
    const navigate = useNavigate();

    const handleUsernameSubmit = async (event: FormEvent<HTMLFormElement>) => {
        event.preventDefault();
        axios.defaults.withCredentials = true;
        try{
            const response = await axios.post(`/ViewUsername?email=${email}`, {}, {
                headers: {
                    "Content-Type": "application/json"
                }
            });
            if (response.status === 200) {
                navigate("/ViewUsername", { state: { username: response.data } });
            } else {
                navigate("/FindUserInfo")
            }
        } catch (error: any){
            console.error("Error: ", error.response ? error.response.data : error.message);
            navigate("/FindUserInfo");
        }
    }

    const handlePasswordSubmit = async (event: FormEvent<HTMLFormElement>) => {
        event.preventDefault();
        axios.defaults.withCredentials = true;
        const response = await axios.post("/SendPassword", {
            username: username,
            email: passwordEmail
        }, {
            headers: {
                "Content-Type": "application/json"
            }
        });
        if(response.status === 200){
            console.log(response.data)
            navigate("/ViewChangedPassword")
        } else {
            navigate("/FindUserInfo")
        }
    }

    return (
        <div>
            <form method="post" action="/FindUsernameByEmail" onSubmit={handleUsernameSubmit}>
                email: <input type="email" name="email" onChange={(event) => setEmail(event.target.value)}/><br/>
                <input type="submit" value="아이디 찾기"/>
            </form>
            <form method="post" action="/UpdatePasswordByEmail" onSubmit={handlePasswordSubmit}>
                id: <input type="text" name="username" onChange={(event) => setUsername(event.target.value)}/>
                email: <input type="email" name="email" onChange={(event) => setPasswordEmail(event.target.value)}/><br/>
                <input type="submit" value="비밀번호 찾기"/>
            </form>
            <p>
                <NavLink to="/loginPage">로그인 페이지</NavLink>
            </p>
        </div>
    )
}

function ViewUsername(){
    const [username, setUsername] = useState<string>('');
    const navigate = useNavigate();
    const location = useLocation();

    useEffect(() => {
        const usernameFromState = location.state?.username;
        if (usernameFromState) {
            setUsername(usernameFromState);
        } else {
            navigate("/FindUserInfo");
        }
    }, [location.state, navigate]);

    return(
        <div>
            <h1>아이디 출력</h1>
            <p>username: {username}</p>
            <p>
                <NavLink to="/loginPage">로그인 페이지</NavLink><br/>
                <NavLink to="/RegisterPage">회원가입 페이지</NavLink><br/>
                <NavLink to="/FindUserInfo">회원 정보 찾기 페이지</NavLink><br/>
            </p>
        </div>
    )
}

function ViewChangedPassword(){
    return(
        <div>
            임시비밀번호로 변경되었습니다.
            <p>
                <NavLink to="/loginPage">로그인 페이지</NavLink>
            </p>
        </div>
    )
}

function ChangePasswordPage() {
    const [password, setPassword] = useState<string>("");
    const navigate = useNavigate();

    const handleSubmit = async (event: FormEvent<HTMLFormElement>) => {
        event.preventDefault();
        axios.defaults.withCredentials = true;
        try {
            const response = await axios.post("/UpdatePasswordByUsername",
                {password: password},
                {headers: {'Content-Type':'application/json'}
                });
            if(response.status === 200){
                navigate('/=========================');
            } else {
                console.error("비밀번호 변경 실패")
                navigate('/=========================');
            }
        } catch (error) {
            console.error("Error: ", error)
        }
    }

    return (
        <div>
            <form id="ChangePasswordForm" onSubmit={handleSubmit}>
                New Password: <input type="text" value={password}
                                     onChange={(event) => setPassword(event.target.value)}/>
                <input type="submit" value="변경"/>
            </form>
            <p>
                <NavLink to="/MyPage">돌아가기</NavLink><br/>
            </p>
        </div>
    )
}

function ChangeEmailPage() {
    const [email, setEmail] = useState<string>("");
    const navigate = useNavigate();

    const handleSubmit = async (event: FormEvent<HTMLFormElement>) => {
        event.preventDefault();
        axios.defaults.withCredentials = true;
        try{
            const response = await axios.post("/UpdateEmailByUsername",
                {email: email},
                {
                    headers: {
                        'Content-Type':'application/json'
                    }
                });
            if(response.status === 200){
                navigate('/=========================');
            } else {
                console.error("이메일 변경 실패")
                navigate('/=========================');
            }
        } catch (error) {
            console.error("Error: ", error)
        }
    }
    return(
        <div>
            <form id="ChangeEmailForm" onSubmit={handleSubmit}>
                email: <input type="text" value={email} onChange={(event) => setEmail(event.target.value)}/>
                <input type="submit" value="변경"/>
            </form>
            <p>
                <NavLink to="/MyPage">돌아가기</NavLink><br/>
            </p>
        </div>
    )
}

export default App;