Commit 598bf2fc authored by 한규민's avatar 한규민
Browse files

서버연결성공

parent ae3326aa
...@@ -2,8 +2,8 @@ import axios from "axios"; ...@@ -2,8 +2,8 @@ import axios from "axios";
import { baseUrl } from "../utils/baseUrl.js"; import { baseUrl } from "../utils/baseUrl.js";
import config from "../utils/clientConfig.js"; import config from "../utils/clientConfig.js";
const login = async (id, password) => { const login = async (login) => {
const payload = { id, password }; const payload = login;
const { data } = await axios.post(`${baseUrl}/api/auth/login`, payload); const { data } = await axios.post(`${baseUrl}/api/auth/login`, payload);
return data return data
}; };
......
import { useState } from "react";
import styles from "./login.module.scss"; import styles from "./login.module.scss";
import { useState } from "react";
import authApi from "../../apis/auth.api.js";
import { Redirect } from "react-router";
import catchErrors from "../../utils/catchErrors";
const Login = () => { const Login = () => {
//useState를 이용해서 각 state 생성 및 초기값 저장 //useState를 이용해서 각 state 생성 및 초기값 저장
...@@ -9,9 +12,11 @@ const Login = () => { ...@@ -9,9 +12,11 @@ const Login = () => {
id:'', id:'',
password:'' password:''
}); });
const [error, setError] = useState("");
const [loading, setLoading] = useState(false);
const [success, setSuccess] = useState(false); const [success, setSuccess] = useState(false);
const [guestText, setGusetText] = useState({ const [guest, setGuset] = useState({
guestName:'', guestName:'',
gusetBirthday:'', gusetBirthday:'',
gusetMbnum:'', gusetMbnum:'',
...@@ -28,15 +33,54 @@ const Login = () => { ...@@ -28,15 +33,54 @@ const Login = () => {
}; };
const handleGuestOnChange = (e) =>{ const handleGuestOnChange = (e) =>{
setGusetText({ ...guestText, setGuset({ ...guest,
[e.target.name]:e.target.value [e.target.name]:e.target.value
}) })
} }
const handleOnSummitUser = async(e) => {
e.preventDefault();
try{
console.log("하하")
setError("");
setLoading(true);
const userData = login;
await authApi.login(userData);
alert('로그인이 완료되었습니다.')
setSuccess(true);
}catch(error){
catchErrors(error, setError);
}finally{
setLoading(false);
}
}
const handleOnSummitGuest = async(e) => {
e.preventDefault();
try{
setError("");
setLoading(true);
const gusetData = guest;
await authApi.post(gusetData);
alert('로그인이 완료되었습니다.')
setSuccess(true);
}catch(error){
catchErrors(error, setError);
}finally{
setLoading(false);
}
}
if (success) {
return <Redirect to="/" />;
}
return ( return (
<div className={`d-flex flex-column col-md-5 col-10`}> <div className={`d-flex flex-column col-md-5 col-10`}>
{/* nav-tabs */} {/* nav-tabs */}
{/* {console.log(login)} */} {/* {console.log(login)} */}
{console.log(success)}
<ul className="nav nav-fill nav-tabs w-100" id="loginTab" role="tablist"> <ul className="nav nav-fill nav-tabs w-100" id="loginTab" role="tablist">
<li className="nav-item fs-6" role="presentation"> <li className="nav-item fs-6" role="presentation">
<button className={`nav-link active px-2 ${styles.fontSize}`} style={{ color: state ? "black" : "#FEDC00", backgroundColor: state ? "#FEDC00" : "black"}} <button className={`nav-link active px-2 ${styles.fontSize}`} style={{ color: state ? "black" : "#FEDC00", backgroundColor: state ? "#FEDC00" : "black"}}
...@@ -53,27 +97,27 @@ const Login = () => { ...@@ -53,27 +97,27 @@ const Login = () => {
<div className="tab-content w-100" id="myTabContent"> <div className="tab-content w-100" id="myTabContent">
{/* 로그인 */} {/* 로그인 */}
<div className="tab-pane fade show active" id="login" role="tabpanel" aria-labelledby="login-tab"> <div className="tab-pane fade show active" id="login" role="tabpanel" aria-labelledby="login-tab">
<div className="d-flex flex-column "> <form className="d-flex flex-column" onSubmit={handleOnSummitUser}>
<input className={styles.input} type="text" name="id" placeholder="ID" onChange={handleLoginOnChange}/> <input className={styles.input} type="text" name="id" placeholder="ID" onChange={handleLoginOnChange} maxLength="10" required/>
<input className={styles.input} type="text" name="password" placeholder="Password" onChange={handleLoginOnChange} minlength="8" required /> <input className={styles.input} type="password" name="password" placeholder="Password" onChange={handleLoginOnChange} maxLength="8" required />
<input className={`rounded-2 mt-2 ${styles.butterYellowAndBtn} ${styles.btnHover}`} type="submit" value="Login" /> <input className={`rounded-2 mt-2 ${styles.butterYellowAndBtn} ${styles.btnHover}`} type="submit" value="Login" disabled={loading} />
<span><a href="./signup" className={styles.intoSignupPage}>회원이 아니십니까?</a></span> <span><a href="./signup" className={styles.intoSignupPage}>회원이 아니십니까?</a></span>
</div> </form>
</div> </div>
{/* 비회원예매 학인 */} {/* 비회원예매 학인 */}
<div className="tab-pane fade" id="guest" role="tabpanel" aria-labelledby="guest-tab"> <div className="tab-pane fade" id="guest" role="tabpanel" aria-labelledby="guest-tab">
<div className="d-flex flex-column"> <form className="d-flex flex-column" onSubmit={handleOnSummitGuest}>
<input className={styles.input} type="text" name="guestName" id="guestName" placeholder="이름" onChange={handleGuestOnChange} minlength="8" required /> <input className={styles.input} type="text" name="guestName" id="guestName" placeholder="이름" onChange={handleGuestOnChange} maxLength="5" required />
<input className={styles.input} type="number" name="gusetBirthday" id="gusetBirthday" placeholder="생년월일" onChange={handleGuestOnChange} minlength="8" required /> <input className={styles.input} type="number" name="gusetBirthday" id="gusetBirthday" placeholder="생년월일" onChange={handleGuestOnChange} maxLength="6" required />
<input className={styles.input} type="number" name="gusetMbnum" id="gusetMbnum" placeholder="휴대폰 번호" onChange={handleGuestOnChange} minlength="8" required /> <input className={styles.input} type="number" name="gusetMbnum" id="gusetMbnum" placeholder="휴대폰 번호" onChange={handleGuestOnChange} maxLength="11" required />
<input className={styles.input} type="text" name="guestPassword" id="password" placeholder="비밀번호" onChange={handleGuestOnChange} minlength="8" required /> <input className={styles.input} type="password" name="guestPassword" id="password" placeholder="비밀번호" onChange={handleGuestOnChange} maxLength="8" required />
<p className={`text-white ${styles.fontSizeTwo}`}> <p className={`text-white ${styles.fontSizeTwo}`}>
비회원 정보 입력 예매 내역 확인/취소 티켓 발권이 어려울 있으니 다시 한번 확인해 주시기 바랍니다. 비회원 정보 입력 예매 내역 확인/취소 티켓 발권이 어려울 있으니 다시 한번 확인해 주시기 바랍니다.
</p> </p>
<input className={`rounded-2 mt-2 ${styles.butterYellowAndBtn} ${styles.btnHover}`} type="submit" value="비회원 예매 확인" /> <input className={`rounded-2 mt-2 ${styles.butterYellowAndBtn} ${styles.btnHover}`} type="submit" value="비회원 예매 확인" disabled={loading}/>
</div> </form>
</div> </div>
</div> </div>
</div> </div>
......
...@@ -14,6 +14,14 @@ ...@@ -14,6 +14,14 @@
border-radius: 3px; border-radius: 3px;
} }
input[type=password]{
font-family: 'Courier New', Courier, monospace;
}
input::placeholder{
font-family: 'HangeulNuriB'
}
.fontSize{ .fontSize{
font-size: 16px; font-size: 16px;
} }
......
import styles from "./signup.module.scss"; import styles from "./signup.module.scss";
import { useState, useEffect } from 'react'; import { useState } from 'react';
import authApi from "../../apis/auth.api.js"; import authApi from "../../apis/auth.api.js";
import { Redirect } from "react-router"; import { Redirect } from "react-router";
import catchErrors from "../../utils/catchErrors.js"; import catchErrors from "../../utils/catchErrors.js";
const Signup = () => { const Signup = () => {
const [user, setUser] = useState({ const [user, setUser] = useState({
userId: '', userId: "",
userName: '', userNickName: "",
userBirthday: '', userBirthday: "",
userMbnum: '', userMbnum: "",
userPassword: '', userPassword: "",
userRePassword: '' userRePassword: ""
}) })
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const [success, setSuccess] = useState(false); const [success, setSuccess] = useState(false);
//각 타입별 error 유무 state //각 타입별 error 유무 state
const [error,setError] = useState(""); const [error,setError] = useState("");
const [errorMsg, setErrorMsg] = useState({ const [errorMsg, setErrorMsg] = useState({
errorId: null, errorId: null,
errorName: false, errorNickName: false,
errorBirthday: false, errorBirthday: false,
errorMbnum: false, errorMbnum: false,
errorPassword: false, errorPassword: false,
...@@ -41,13 +41,13 @@ const Signup = () => { ...@@ -41,13 +41,13 @@ const Signup = () => {
//id(중복확인 체크, 형식 에러) //id(중복확인 체크, 형식 에러)
const handleOnClickId = async (e) => { const handleOnClickId = async (e) => {
e.preventDefault(); e.preventDefault();
const existId = await authApi.compareId(user.userId) // const existId = await authApi.compareId(user.userId)
if (user.userId.length < 5) { if (user.userId.length < 5) {
setErrorMsg(errorMsg => ({ setErrorMsg(errorMsg => ({
...errorMsg, ...errorMsg,
[e.target.name]: true [e.target.name]: true
})); }));
if (existId === true) { if (overlapId === true) {
setOverlapId(() => (false)); setOverlapId(() => (false));
}; };
} else { } else {
...@@ -106,7 +106,7 @@ const Signup = () => { ...@@ -106,7 +106,7 @@ const Signup = () => {
} }
//별명 유효성 검사 //별명 유효성 검사
vaildationData((user.userName.length === 0), false, "errorName"); vaildationData((user.userNickName.length === 0), false, "errorNickName");
// 생일 유효성 검사 // 생일 유효성 검사
vaildationData(user.userBirthday.length, 6, "errorBirthday"); vaildationData(user.userBirthday.length, 6, "errorBirthday");
// 휴대폰 유효성 검사 // 휴대폰 유효성 검사
...@@ -118,9 +118,7 @@ const Signup = () => { ...@@ -118,9 +118,7 @@ const Signup = () => {
// 최종 유효성 검사 // 최종 유효성 검사
if (overlapId && (Object.values(errorMsg).some((element) => (element)) === false)) { if (overlapId && (Object.values(errorMsg).some((element) => (element)) === false)) {
console.log(";sadasda")
}else{ }else{
console.log("에러발생")
throw new Error("유효하지 않은 데이터입니다."); throw new Error("유효하지 않은 데이터입니다.");
} }
} }
...@@ -152,9 +150,9 @@ const Signup = () => { ...@@ -152,9 +150,9 @@ const Signup = () => {
<div className="d-flex flex-column"> <div className="d-flex flex-column">
<div className={styles.inputContent}> <div className={styles.inputContent}>
<label className={styles.signupLabel}>별명</label> <label className={styles.signupLabel}>별명</label>
<input className={`${styles.input} ${styles.inputSize}`} type="text" name="userName" id="userName" placeholder="10자리 이내" onChange={handleUserOnChange} maxLength="10" required /> <input className={`${styles.input} ${styles.inputSize}`} type="text" name="userNickName" id="userNickName" placeholder="10자리 이내" onChange={handleUserOnChange} maxLength="10" required />
</div> </div>
{errorMsg.errorName && <p className={styles.passwordConfirmError}>10 이내로 입력해주세요.</p>} {errorMsg.errorNickName && <p className={styles.passwordConfirmError}>10 이내로 입력해주세요.</p>}
</div> </div>
<div className="d-flex flex-column"> <div className="d-flex flex-column">
......
const config = { const config = {
env: process.env.NODE_ENV === 'production' ? 'production' : 'development', env: process.env.NODE_ENV === 'production' ? 'production' : 'development',
port: process.env.PORT || 3001, port: process.env.PORT || 3001,
// jwtSecret: 'dfkasf23i$efksdfks!', jwtSecret: 'dfkasf23i$efksdfks!',
jwtExpires: '7d', jwtExpires: '7d',
cookieName: 'butterStudio', cookieName: 'butterStudio',
cookieMaxAge: 60 * 60 * 24 * 7 * 1000, cookieMaxAge: 60 * 60 * 24 * 7 * 1000,
......
import axios from 'axios' import jwt from "jsonwebtoken";
import sequelize from 'sequelize' import config from "../config/app.config.js";
import { User } from '../db/index.js' import { User } from '../db/index.js'
const login = async(req, res) => {
try {
console.log(req.body);
const { id, password } = req.body;
//사용자 존재 확인
const user = await User.scope("withPassword").findOne({ where: { userId: id } });
if (!user) {
return res.status(422).send(`사용자가 존재하지 않습니다`);
}
// 2) 비밀번호 확인은 데이터베이스 프로토타입 메소드에서 처리
const passwordMatch = await user.comparePassword(password);
if (passwordMatch) {
// 3) 비밀번호가 맞으면 토큰 생성
// const userRole = await user.getRole();
const signData = {
userId: user.id,
// role: userRole.name,
};
const token = jwt.sign(signData, config.jwtSecret, {
expiresIn: config.jwtExpires,
});
// 4) 토큰을 쿠키에 저장
res.cookie(config.cookieName, token, {
maxAge: config.cookieMaxAge,
path: "/",
httpOnly: config.env === "production",
secure: config.env === "production",
});
// 5) 사용자 반환
res.json({
userId: user.id,
isLoggedIn: true,
// role: userRole.name,
// isMember: user.isMember,
});
} else {
// 6) 비밀번호 불일치
res.status(401).send("비밀번호가 일치하지 않습니다");
}
} catch (error) {
console.error(error);
return res.status(500).send("로그인 에러");
}
}
const compareId = async (req, res) => { const compareId = async (req, res) => {
const id = req.params.userId; const id = req.params.userId;
const userid = await User.findAll({where:{userId: id}}); const userid = await User.findAll({where:{userId: id}});
...@@ -12,6 +61,35 @@ const compareId = async (req, res) => { ...@@ -12,6 +61,35 @@ const compareId = async (req, res) => {
} }
} }
const signup = async (req, res) => {
const { userId, userNickName, userBirthday, userPassword } = req.body;
// 휴대폰 중복 확인
const userMbnum = String(req.body.userMbnum);
console.log(userMbnum);
console.log(typeof userMbnum);
try {
const mbnum = await User.findOne({ where: { phoneNumber: userMbnum } });
if (mbnum) {
return res.status(422).send(`이미 있는 휴대폰번호입니다.`);
}
const newUser = await User.create({
userId: userId,
nickname: userNickName,
birth: userBirthday,
phoneNumber: userMbnum,
password: userPassword
});
console.log("signup new user=", newUser);
res.json(newUser);
} catch (error) {
console.error(error.message);
res.status(500).send("회원가입 에러. 나중에 다시 시도 해주세요");
}
};
export default { export default {
compareId login,
compareId,
signup
} }
...@@ -16,17 +16,17 @@ const UserModel = (sequelize) => { ...@@ -16,17 +16,17 @@ const UserModel = (sequelize) => {
userId: { userId: {
type: DataTypes.STRING, type: DataTypes.STRING,
}, },
password: {
type: DataTypes.STRING,
},
nickname: { nickname: {
type: DataTypes.STRING, type: DataTypes.STRING,
}, },
birth: { birth: {
type: DataTypes.INTEGER, type: DataTypes.STRING,
}, },
phoneNumber: { phoneNumber: {
type: DataTypes.INTEGER type: DataTypes.STRING
},
password: {
type: DataTypes.STRING,
}, },
// role: { // role: {
// type: DataTypes.ENUM({ // type: DataTypes.ENUM({
...@@ -37,17 +37,37 @@ const UserModel = (sequelize) => { ...@@ -37,17 +37,37 @@ const UserModel = (sequelize) => {
{ {
timestamps: true, timestamps: true,
freezeTableName: true, freezeTableName: true,
tableName: "users" tableName: "users",
// defaultScope: { defaultScope: {
// attributes: { exclude: ["password"] }, attributes: { exclude: ["password"] },
// }, },
// scopes: { scopes: {
// withPassword: { withPassword: {
// attributes: { include: ["password"] }, attributes: { include: ["password"] },
// }, },
// }, },
} }
); );
User.beforeSave(async (user) => {
if (!user.changed("password")) {
return;
}
if (user.password) {
const hashedPassword = await bcrypt.hash(user.password, 10);
user.password = hashedPassword;
}
});
User.prototype.comparePassword = async function (plainPassword) {
const passwordMatch = await bcrypt.compare(
plainPassword,
this.password
);
return passwordMatch;
};
return User return User
}; };
......
...@@ -4,9 +4,13 @@ import userCtrl from "../controllers/user.controller.js"; ...@@ -4,9 +4,13 @@ import userCtrl from "../controllers/user.controller.js";
const router = express.Router(); const router = express.Router();
router router
.route("/") .route("/login")
.post() .post(userCtrl.login)
.get()
router
.route("/signup")
.post(userCtrl.signup)
router router
.route("/:userId") .route("/:userId")
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment