Commit 55693856 authored by 한규민's avatar 한규민
Browse files

마이페이지

parent 87029678
import axios from "axios";
import { baseUrl } from "../utils/baseUrl.js";
import config from "../utils/clientConfig.js";
const getUser = async () => {
const url = `${baseUrl}/api/auth/user`
......@@ -38,8 +37,13 @@ const confirmMbnum = async (id, token) => {
return data
}
const getNickName = async (id) => {
const url = `${baseUrl}/api/auth/nickname/${id}`
const profile = async (formData) => {
const url = `${baseUrl}/api/auth/profile`
const { data } = await axios.post(url, formData)
return data
}
const getMember = async (id) => {
const url = `${baseUrl}/api/auth/member`
const { data } = await axios.get(url)
return data
}
......@@ -62,7 +66,8 @@ const authApi = {
signup,
compareId,
confirmMbnum,
getNickName,
profile,
getMember,
comparePw,
modifyUser,
};
......
import styles from "./my-info.module.scss";
import { useAuth } from "../../context/auth_context";
import { useState, useEffect } from "react";
import authApi from "../../apis/auth.api";
import catchErrors from "../../utils/catchErrors.js";
const MyInfo = () => {
const { user } = useAuth();
const [userNickName, setUserNickName] = useState("사용자");
const [img, setImg] = useState("");
const [profile, setProfile] = useState("");
// 사용자 이름 가져오는 함수
const getNickName = async (id) => {
const nickname = await authApi.getNickName(id);
setUserNickName(nickname);
const getMember = async () => {
const member = await authApi.getMember();
setUserNickName(member.nickname);
setProfile(member.img);
}
const [page, setPage] = useState(true);
//현재 비밀번호 state
const [presentPw, setPresentPw] = useState("");
const [loading, setLoading] = useState(false);
const [style, setStyle] = useState("visually-hidden-focusable");
//변경할 데이터 입력받는 state
const [userRe, setUserRe] = useState({
......@@ -39,7 +40,7 @@ const MyInfo = () => {
})
useEffect(() => {
getNickName(user.id);
getMember();
}, [])
const handlePwOnChange = (e) => {
......@@ -65,6 +66,24 @@ const MyInfo = () => {
handleOnSummitVerify(e);
}
}
const handleOnChange = (e) => {
setImg(e.target.files[0]);
}
const handleOnSummitForm = async (e) => {
e.preventDefault();
try {
setError("")
const formData = new FormData();
formData.append("image", img);
const image = await authApi.profile(formData);
console.log(image.img);
setProfile(image.img);
} catch (error) {
catchErrors(error, setError);
}
}
//기존 비밀번호 확인
const handleOnSummitVerify = async (e) => {
e.preventDefault();
......@@ -74,9 +93,8 @@ const MyInfo = () => {
const pw = presentPw;
const confirmPw = await authApi.comparePw(pw);
if (confirmPw) {
setStyle("");
setPage(false);
} else {
setStyle("visually-hidden-focusable");
alert("비밀번호가 일치하지 않습니다.");
}
} catch (error) {
......@@ -103,8 +121,8 @@ const MyInfo = () => {
}
}
//유효성 검사
const validation = async () => {
try {//별명 유효성 검사
const validation = () => {
//별명 유효성 검사
vaildationData((userRe.userNickName.length === 0), false, "errorNickName");
// 휴대폰 유효성 검사
vaildationData(userRe.userMbnum.length, 11, "errorMbnum");
......@@ -117,32 +135,31 @@ const MyInfo = () => {
if ((Object.values(errorMsg).some((element) => (element)) === false)) {
return true
} else {
throw new Error("유효하지 않은 데이터입니다.");
}
} catch (error) {
catchErrors(error, setError);
return false
}
}
const handleOnSummit = async (e) => {
e.preventDefault();
try {
setError(() => (""));
//처리가 될때까지 버튼(가입하기)이 안눌리게 지정
setLoading(() => (true));
console.log("userRe : " + userRe.userEmail);
//유효성 검사
const vaild = validation();
if (vaild) {
let valid = validation();
console.log("valid :" + valid);
if (valid) {
const userData = userRe;
console.log(userData);
//서버로 전송
const process = await authApi.modifyUser(userData);
console.log("process : " + process);
alert("회원정보 수정 완료");
}
valid = false;
} else { throw new Error("유효하지 않은 데이터입니다.") }
} catch (error) {
//에러전송
catchErrors(error, setError);
......@@ -151,17 +168,21 @@ const MyInfo = () => {
}
}
const handleOnClick = (e) => {
e.preventDefault();
setPage(true);
}
return (
<>
{/* 마이페이지 창 */}
<div className="d-flex flex-column">
<span className={styles.title}>마이페이지</span>
<div className="d-flex flex justify-content-center">
<img src="https://search.pstatic.net/sunny/?src=https%3A%2F%2Fi.pinimg.com%2Foriginals%2F1e%2F1c%2F2e%2F1e1c2e4e07f5c440c3adad38bcd6f854.jpg&type=a340"
className="img-fluid px-5 rounded-circle" />
{/* <button type="submit"></button> */}
<div className="d-flex justify-content-around">
<div className={`${styles.box} me-5`}>
<p className={`${styles.hoverTxt}`}>프로필 변경</p>
<img src={`/upload/${profile}`} className={`figure-img img-fluid rounded-circle ${styles.profile}`} role="button" data-bs-toggle="modal" data-bs-target="#staticBackdrop" />
</div>
<div className="d-flex flex-column py-4 justify-content-around">
<span className={`${styles.userName}`}>{`${userNickName}`} 반갑습니다!</span>
<button className={`rounded my-3 fs-5 ${styles.butterYellowAndBtn} ${styles.btnHover}`} data-bs-toggle="modal" href="#verifyPassword" >회원정보 수정</button>
......@@ -169,39 +190,49 @@ const MyInfo = () => {
</div>
</div>
<div className="modal fade" id="staticBackdrop" data-bs-backdrop="static" data-bs-keyboard="false" tabindex="-1" aria-labelledby="staticBackdropLabel" aria-hidden="true">
<div className="modal-dialog modal-dialog-centered">
<form className="modal-content" onSubmit={handleOnSummitForm}>
<div className="modal-header">
<h5 className="modal-title" id="staticBackdropLabel">프로필변경</h5>
<button type="button" className="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div className="modal-body">
<input type="file" onChange={handleOnChange} />
</div>
<div className="modal-footer">
<button type="button" className="btn btn-secondary" data-bs-dismiss="modal">닫기</button>
<button type="submit" className={`rounded fs-5 ${styles.butterYellowAndBtn} ${styles.btnHover}`}>변경</button>
</div>
</form>
</div>
</div>
{/* 기존 비밀번호 확인 모달창 */}
<div className="modal fade" id="verifyPassword" data-bs-backdrop="static" data-bs-keyboard="false" aria-hidden="true" aria-labelledby="verifyPasswordLabel" tabindex="-1">
<div className="modal-dialog modal-dialog-centered">
<form className="modal-content" onSubmit={handleOnSummitVerify}>
<div className="modal-dialog modal-dialog-centered modal-dialog-centered">
{page ?
<><form className="modal-content" onSubmit={handleOnSummitVerify}>
<div className="modal-header">
<h5 className="modal-title" id="verifyPasswordLabel">기존 비밀번호 확인</h5>
<button type="button" className="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
<button type="button" className="btn-close" data-bs-dismiss="modal" aria-label="Close" onclick={handleOnClick}></button>
</div>
<div clasNames="modal-body">
<div className="d-flex flex-column ">
<div className="d-flex flex-column">
<div className="d-flex justify-content-around align-items-center my-4">
<label className={styles.signupLabel}>현재 비밀번호</label>
<input className={`${styles.input} ${styles.inputSize}`} type="password" name="userPassword" placeholder="8~11자리 사이" onChange={handlePwOnChange} onKeyPress={enterKey} maxLength="11" required />
</div>
{(style !== "visually-hidden-focusable") && <p className={styles.passwordConfirmError}>다음을 클릭해주세요.</p>}
</div>
</div>
<div className="modal-footer">
<button className={`${style} rounded my-3 fs-5 ${styles.butterYellowAndBtn} ${styles.btnHover}`} data-bs-target="#modify" data-bs-toggle="modal" data-bs-dismiss="modal" disable={style === "visually-hidden-focusable"}>다음</button>
<button type="submit" className={`rounded my-3 fs-5 ${styles.butterYellowAndBtn} ${styles.btnHover}`} disabled={loading}>확인</button>
</div>
</form>
</div>
</div>
{/* 회원정보 수정 모달창 */}
<div className="modal fade" id="modify" data-bs-backdrop="static" data-bs-keyboard="false" aria-hidden="true" aria-labelledby="modifyLabel" tabindex="-1">
<div className="modal-dialog modal-dialog-centered">
<form className={`modal-content d-flex col-md-6 col-12 justify-content-center d-flex flex-column`} onSubmit={handleOnSummit}>
</form></>
: <><form className={`modal-content d-flex col-md-6 col-12 justify-content-center d-flex flex-column`} onSubmit={handleOnSummit}>
<div className="modal-header">
<h5 className="modal-title" id="modifyLabel">회원정보 수정</h5>
<button type="button" className="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
<button type="button" className="btn-close" data-bs-dismiss="modal" aria-label="Close" onclick={handleOnClick}></button>
</div>
<div className={`modal-body`}>
<div className="d-flex flex-column">
......@@ -249,10 +280,10 @@ const MyInfo = () => {
</div>
<div className="modal-footer">
<button type="button" className="btn btn-secondary rounded my-3 py-2 fs-5" data-bs-dismiss="modal" disabled={loading}>닫기</button>
<button type="button" className="btn btn-secondary rounded my-3 py-2 fs-5" data-bs-dismiss="modal" onClick={handleOnClick} disabled={loading}>닫기</button>
<button type="submit" className={`rounded my-3 py-2 fs-5 ${styles.butterYellowAndBtn} ${styles.btnHover}`} disabled={loading}>수정하기</button>
</div>
</form>
</form></>}
</div>
</div>
</>
......
......@@ -28,13 +28,45 @@ width: 40%;
padding-right: 8px;
text-align: left;
}
.input_file_button{
padding: 6px 25px;
background-color:#FF6600;
border-radius: 4px;
color: white;
cursor: pointer;
}
.inputContent{
display: flex;
justify-content: space-around;
align-items: center;
margin: 1rem 0;
}
.box{
width:12rem;
margin: 0px auto;
position: relative;
}
.box:hover{
display: block;
}
.hoverTxt{
display: none;
position:absolute;
top:5rem;
left:2.5rem;
color : #FEDC00;
font-size: 1.5rem;
}
.box:hover .hoverTxt{
display: block;
}
.profile{
width: 12rem;
height: 12rem;
}
.profile:hover{
opacity: 0.5;
}
.input {
margin: 0.5rem 0 0 0;
padding: 0.5rem 0 0.5rem 0;
......
import styles from "./reservation-details.module.scss";
const ReservationDetails = () => {
return(
<div className={`${styles.width}`}>
<header className={`${styles.header}`}>나의 예매 내역</header>
<main>
</main>
</div>
)
}
export default ReservationDetails
\ No newline at end of file
export { default } from "./ReservationDetails"
\ No newline at end of file
.width{
width : 100%;
display: flex;
margin-top: 5rem;
justify-content: center;
}
.header{
display: flex;
justify-content: center;
background-color: #FEDC00;
width: 80%;
text-align: center;
font-size: 2.5rem;
}
\ No newline at end of file
import MyInfo from "../components/MyInfo/MyInfo"
import ReservationDetails from "../components/ReservationDetails";
const MyPage = () => {
return (
<div className="d-flex justify-content-center py-4">
<div className="d-flex flex-column justify-content-center align-items-center py-4">
<MyInfo/>
<ReservationDetails/>
</div>
)
}
......
......@@ -666,6 +666,11 @@
"resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
"integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac="
},
"fs": {
"version": "0.0.1-security",
"resolved": "https://registry.npmjs.org/fs/-/fs-0.0.1-security.tgz",
"integrity": "sha1-invTcYa23d84E/I4WLV+yq9eQdQ="
},
"fsevents": {
"version": "2.3.2",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
......
......@@ -7,7 +7,7 @@ const app = express()
app.use(express.json())
app.use(express.urlencoded({ extended: true }))
app.use(cookieParser())
app.use('/upload', express.static('upload'))
app.use('/api', mainRouter)
......
import jwt from "jsonwebtoken";
import config from "../config/app.config.js";
import { User, Role } from '../db/index.js';
import fs from "fs";
const getUser = async (req, res) => {
try {
if (req.cookies) {
if (req.cookies.butterStudio) {
const token = req.cookies.butterStudio;
const decoded = jwt.verify(token, config.jwtSecret);
res.json(decoded);
......@@ -109,14 +110,19 @@ const confirmMbnum = async (req, res) => {
}
const signup = async (req, res) => {
const { userId, userEmail, userNickName, userBirthday, userPassword } = req.body;
const { userId, userEmail, userNickName, userBirthday, userMbnum, userPassword } = req.body;
// 휴대폰 중복 확인
const userMbnum = String(req.body.userMbnum);
try {
const mbnum = await User.findOne({ where: { phoneNumber: userMbnum } });
if (mbnum) {
const email = await User.findOne({ where: { email: userEmail } });
if (mbnum && email) {
return res.status(422).send(`이미 있는 이메일, 휴대폰번호입니다.`);
} else if (!mbnum && email) {
return res.status(422).send(`이미 있는 이메일입니다.`);
} else if (mbnum && !email) {
return res.status(422).send(`이미 있는 휴대폰번호입니다.`);
}
} else {
const role = await Role.findOne({ where: { name: "member" } })
const newUser = await User.create({
userId: userId,
......@@ -128,19 +134,20 @@ const signup = async (req, res) => {
roleId: role.id
});
res.json(newUser);
}
} catch (error) {
console.error(error.message);
res.status(500).send("회원가입 에러. 나중에 다시 시도 해주세요");
}
};
const getNickName = async (req, res) => {
const getMember = async (req, res) => {
try {
const token = req.cookies.butterStudio;
const decoded = jwt.verify(token, config.jwtSecret);
if (decoded.role === "member") {
const user = await User.findOne({ where: { id: decoded.id }, attributes: ["nickname"] });
res.json(user.nickname);
const user = await User.findOne({ where: { id: decoded.id } });
res.json({nickname : user.nickname, img : user.img});
} else {
res.status(401).send("잘못된 접근입니다.");
}
......@@ -150,6 +157,34 @@ const getNickName = async (req, res) => {
}
}
const uploadProfile = async (req, res) => {
try {
const image = req.file.filename;
console.log(req.file);
const token = req.cookies.butterStudio;
const decoded = jwt.verify(token, config.jwtSecret);
if (decoded) {
const img = await User.findOne({ where: { id:decoded.id }, attributes : ["img"]});
console.log("여기여기");
fs.unlink( "upload"+`\\${img.img}`, function(data){ console.log(data);});
const user = await User.update({
img: image
}, { where: { id: decoded.id } });
if(user){
const success = await User.findOne({ where: { id: decoded.id }, attributes: ["img"]});
res.json(success)
}else{
throw new Error("프로필 등록 실패")
}
}
} catch (error) {
console.error(error.message);
res.status(500).send("프로필 에러");
}
}
const comparePw = async (req, res) => {
try {
//쿠키 안 토큰에서 id추출
......@@ -171,26 +206,50 @@ const comparePw = async (req, res) => {
}
}
const overlap = async (decoded, dataType, data) => {
try {
let overlap = await User.findOne({ where: { id: decoded.id } });
console.log("overlap : ", overlap, "overlap[dataType] : ", overlap[dataType]);
if (overlap[dataType] === data) {
console.log("여기여기")
return true
} else {
overlap = await User.findOne({ where: { id: decoded.id }, attributes: [dataType] });
if (overlap) {
return false
} else {
return true
}
}
}catch(error){
console.error(error.message);
}
}
const modifyUser = async (req, res) => {
try {
const token = req.cookies.butterStudio;
const decoded = jwt.verify(token, config.jwtSecret);
const { userEmail, userNickName, userMbnum, userPassword } = req.body;
const emailOverlap = await User.findOne({ where: { email: userEmail } });
const overlapEmail = await overlap(decoded, "email", userEmail);
const overlapMbnum = await overlap(decoded, "phoneNumber", userMbnum);
console.log("overlapEmail", overlapEmail, " overlapMbnum : ", overlapMbnum);
if (emailOverlap) {
return res.status(422).send(`이미 있는 이메일입니다.`);
} else {
if (decoded) {
let user = await User.findOne({ where: { id: decoded.id } });
await user.update({
email : userEmail,
nickname : userNickName,
phoneNumber : userMbnum,
password : userPassword,
});
if (overlapEmail && overlapMbnum) {
const user = await User.update({
email: userEmail,
nickname: userNickName,
phoneNumber: userMbnum,
password: userPassword,
}, { where: { id: decoded.id } });
console.log("user22 :", user);
res.json(user);
}
} else if (!overlapEmail && overlapMbnum) {
res.status(500).send("이미 있는 이메일입니다.");
} else if (overlapEmail && !overlapMbnum) {
res.status(500).send("이미 있는 이메일입니다.");
} else {
res.status(500).send("이미 있는 이메일, 핸드폰번호입니다.");
}
} catch (error) {
console.error(error.message);
......@@ -205,7 +264,8 @@ export default {
compareId,
confirmMbnum,
signup,
getNickName,
getMember,
uploadProfile,
comparePw,
modifyUser
}
......@@ -19,7 +19,6 @@ sequelize
);
const adminRole = await Role.findOne({ where: { name: "admin" } });
console.log("adminRole : ", adminRole);
if (!adminRole) {
await User.create({
userId: "admin",
......
......@@ -14,23 +14,26 @@ const UserModel = (sequelize) => {
autoIncrement: true,
},
userId: {
type: DataTypes.STRING,
type: DataTypes.STRING
},
email: {
type: DataTypes.STRING,
type: DataTypes.STRING
},
nickname: {
type: DataTypes.STRING,
type: DataTypes.STRING
},
birth: {
type: DataTypes.STRING,
type: DataTypes.STRING
},
phoneNumber: {
type: DataTypes.STRING
},
password: {
type: DataTypes.STRING,
type: DataTypes.STRING
},
img: {
type: DataTypes.STRING
}
},
{
timestamps: true,
......
import express from "express";
import userCtrl from "../controllers/user.controller.js";
import multer from "multer"
const router = express.Router();
const upload = multer({
dest: "upload/"
})
router
.route("/user")
......@@ -19,14 +23,16 @@ router
.route("/signup")
.post(userCtrl.signup)
router
.post("/profile", upload.single("image"), userCtrl.uploadProfile)
router
.route("/modify")
.post(userCtrl.modifyUser)
router
.route("/nickname/:id")
.get(userCtrl.getNickName)
.route("/member")
.get(userCtrl.getMember)
router
.route("/pw/:pw")
......
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