Commit c4db43eb authored by Jiwon Yoon's avatar Jiwon Yoon
Browse files

Merge branch 'jaeyeon' into jj-merge

parents 19b84e36 a645a94a
const users=[
{ id:'wodus', password:'123'},
{id:'kim', password:'456'},
]
export function signIn({id,password}){
const user=users.find(user=>user.id===id && user.password===password);
if (user===undefined) throw new Error();
return user;
}
\ No newline at end of file
import React from 'react'
import {Route, Redirect} from "react-router-dom"
function AuthRoute({})
\ No newline at end of file
import React, { useState, useEffect, useRef } from 'react'; import React from 'react';
import { Navbar, Nav } from 'react-bootstrap'; import { Navbar, Nav } from 'react-bootstrap';
import logo from '../footprint.svg'; import logo from '../footprint.svg';
import cart from '../cart.svg'; import cart from '../cart.svg';
import option from '../option.svg'; import option from '../option.svg';
import { handleLogout, isAuthenticated } from '../utils/auth'
function MainNav() { function MainNav() {
function handleClick() { const user = isAuthenticated()
alert('로그아웃이 완료되었습니다.')
window.location.href="/home"
}
return ( return (
<Navbar sticky="top" style={{ background: "#CDC5C2" }}> <Navbar sticky="top" style={{ background: "#CDC5C2" }}>
...@@ -16,13 +14,17 @@ function MainNav() { ...@@ -16,13 +14,17 @@ function MainNav() {
<img alt="로고" src={logo} width="24" height="24" /> <img alt="로고" src={logo} width="24" height="24" />
{' '}KU# {' '}KU#
</Navbar.Brand> </Navbar.Brand>
<Nav className="float-right"> <Nav>
<Nav.Link className="text-light" href="/login">Login</Nav.Link> {user ? <Nav.Link className="text-light" onClick={() => handleLogout()}>Logout</Nav.Link>
<Nav.Link className="text-light" href="/signup">Signup</Nav.Link> : (
<>
<Nav.Link className="text-light" href='/login'>Login</Nav.Link>
<Nav.Link className="text-light" href='/signup'>Sign Up</Nav.Link>
</>
)}
<Nav.Link href="/shoppingcart"> <Nav.Link href="/shoppingcart">
<img alt="카트" src={cart} width="30" height="30" /> <img alt="카트" src={cart} width="30" height="30" />
</Nav.Link> </Nav.Link>
<Nav.Link className="text-light" onClick={() => handleClick()}>Logout</Nav.Link>
<Nav.Link href="/admin"> <Nav.Link href="/admin">
<img alt="관리자" src={option} width="30" height="30" /> <img alt="관리자" src={option} width="30" height="30" />
</Nav.Link> </Nav.Link>
......
import React, { useState, useEffect, useRef } from 'react'; import React, { useState } from 'react';
import { Link, Redirect } from 'react-router-dom'; import { Link, Redirect } from 'react-router-dom';
import { Form, Col, Container, Button, Row } from 'react-bootstrap'; import { Form, Col, Container, Button, Row, Alert } from 'react-bootstrap';
import axios from 'axios'
import catchErrors from '../utils/catchErrors'
import { handleLogin } from '../utils/auth'
function Login(){
const [validated,setValidated]=useState(false); const INIT_USER = {
id: '',
password: ''
}
function Login() {
const [validated, setValidated] = useState(false);
const [user, setUser] = useState(INIT_USER)
const [error, setError] = useState('')
const [success, setSuccess] = useState(false)
function handleChange(event) {
const { name, value } = event.target
setUser({ ...user, [name]: value })
const handleSubmit=(e)=>{ }
const form =e.currentTarget;
if(form.checkValidity() === false){ //checkValidity 는 입력 요소에 유효한 데이터가 포함되어 있는지 확인 async function handleSubmit(event) {
e.preventDefault(); event.preventDefault()
e.stopPropagation(); const form = event.currentTarget;
if (form.checkValidity() === false) {
event.preventDefault();
event.stopPropagation();
} }
setValidated(true); setValidated(true);
try {
setError('')
const response=await axios.post('/api/auth/login', user)
handleLogin(response.data.userId)
setSuccess(true)
} catch (error) {
catchErrors(error, setError)
}
} }
return (
<div>
<Container className="my-5"> if (success) {
<Row className="justify-content-center"> alert('로그인 되었습니다.')
<Col md={5} xs={10} className="border" style={{ background: '#F7F3F3' }}> window.location.href='/'
<h3 className="text-center mt-5">Login</h3> }
<Form noValidate validated={validated} onSubmit={handleSubmit} className="p-5">
<Form.Group controlId="formBasicId">
<Form.Row>
<Col sm={4} xs={6} as={Form.Label} for="id"> 아이디</Col>
<Col sm={8} xs={12} as={Form.Control}
required
type="text"
id="id"
placeholder="ID"
style={{ width: '160px' }}>
</Col>
<Form.Control.Feedback className="text-center" type="invalid"> 아이디를 입력하세요.</Form.Control.Feedback>
</Form.Row>
</Form.Group>
<Form.Group controlId="formBasicPassword"> return (
<Form.Row> <Container className="my-5">
<Col sm={4} xs={6} as={Form.Label} for="password">비밀번호</Col> <Row className="justify-content-center">
<Col sm={8} xs={12} as={Form.Control} <Col md={5} xs={10} className="border" style={{ background: '#F7F3F3' }}>
type="password" <h3 className="text-center mt-5">Login</h3>
id="password" {error && <Alert variant='danger'>
placeholder="Password" {error}
style={{ width: '160px' }} </Alert>}
required /> <Form noValidate validated={validated}
<Form.Control.Feedback className="text-center" type="invalid"> onSubmit={handleSubmit}
비밀번호를 입력하세요. className="p-5">
<Form.Group controlId="formBasicId">
<Form.Row>
<Col sm={4} xs={6} as={Form.Label} for="id"> 아이디</Col>
<Col sm={8} xs={12} as={Form.Control}
required
type="text"
name="id"
placeholder="ID"
value={user.id}
onChange={handleChange}
style={{ width: '160px' }}>
</Col>
<Form.Control.Feedback className="text-center" type="invalid"> 아이디를 입력하세요.</Form.Control.Feedback>
</Form.Row>
</Form.Group>
<Form.Group controlId="formBasicPassword">
<Form.Row>
<Col sm={4} xs={6} as={Form.Label} for="password">비밀번호</Col>
<Col sm={8} xs={12} as={Form.Control}
type="password"
name="password"
value={user.password}
placeholder="Password"
onChange={handleChange}
style={{ width: '160px' }}
required />
<Form.Control.Feedback className="text-center" type="invalid">
비밀번호를 입력하세요.
</Form.Control.Feedback> </Form.Control.Feedback>
</Form.Row> </Form.Row>
</Form.Group> </Form.Group>
<Button style={{ background: '#91877F', borderColor: '#91877F' }} type="submit" block>Login</Button> <Button style={{ background: '#91877F', borderColor: '#91877F' }} type="submit" block>Login</Button>
<div className="loginLine"> <div className="loginLine">
<Link to="/signup" style={{ color: '#91877F' }}>회원이 아니십니까?</Link> <Link to="/signup" style={{ color: '#91877F' }}>회원이 아니십니까?</Link>
</div> </div>
</Form> </Form>
</Col> </Col>
</Row> </Row>
</Container> </Container>
</div>
) )
} }
export default Login export default Login
\ No newline at end of file
import React from 'react'
import {withRouter} from 'react-router-dom'
function LogoutButton({logout,history}){
const handleClick = () =>{
logout()
history.push("/")
}
return <button onClick={handleClick}>Logout</button>
}
export default withRouter(LogoutButton)
\ No newline at end of file
...@@ -40,17 +40,18 @@ function ProductsList() { ...@@ -40,17 +40,18 @@ function ProductsList() {
`} `}
</style> </style>
<Container> <Container>
<Row className="justify-content-center mx-0 my-4"> <Row >
<Col sm={10}> <Col sm={10} xs={12}>
<h1 style={{ fontSize: "3rem" }}>OUTER</h1> <h1 style={{ fontSize: "3rem" }} className="text-center">OUTER</h1>
<div>{sub.map((ele) => ( <div>{sub.map((ele) => (
<Button className="m-1">{ele}</Button> <Button className="justify-content-center m-1">{ele}</Button>
))}</div> ))}</div>
</Col> </Col>
</Row> </Row>
<Row className="justify-content-between mx-0 my-5"> <Row className="justify-content-between mx-0 my-5">
<Dropdown> <Form as={Row} onSubmit={handleSubmit} className="justify-content-end mx-0">
<Dropdown.Toggle>정렬</Dropdown.Toggle> <Dropdown>
<Dropdown.Toggle className="mx-2">정렬</Dropdown.Toggle>
<Dropdown.Menu> <Dropdown.Menu>
<Dropdown.Item>인기상품</Dropdown.Item> <Dropdown.Item>인기상품</Dropdown.Item>
<Dropdown.Item>신상품</Dropdown.Item> <Dropdown.Item>신상품</Dropdown.Item>
...@@ -58,15 +59,13 @@ function ProductsList() { ...@@ -58,15 +59,13 @@ function ProductsList() {
<Dropdown.Item>높은가격</Dropdown.Item> <Dropdown.Item>높은가격</Dropdown.Item>
</Dropdown.Menu> </Dropdown.Menu>
</Dropdown> </Dropdown>
<Form as={Row} onSubmit={handleSubmit} className="justify-content-end mx-0"> <FormControl type="text" placeholder="Search" style={{ width: "13rem" }} />
<FormControl type="text" placeholder="Search" style={{ width: "13rem" }} /> <Button type="submit" className="search px-2 mb-1 ">
<Button type="submit" className="search px-2">
<img src={search} width="20" height="20" /> <img src={search} width="20" height="20" />
</Button> </Button>
<Button sm={2} xs={6} type="button" href="/regist" className="ml-1">상품 등록</Button>
</Form> </Form>
</Row> </Row>
<Row className="justify-content-start m-5"> <Row md={8} sm={12} className="justify-content-start m-2">
<Card className="mt-5" style={{ width: "18rem", margin: "auto" }}> <Card className="mt-5" style={{ width: "18rem", margin: "auto" }}>
<Card.Img variant="top" src="https://img.sonyunara.com/files/goods/67460/1607053816_0.jpg" style={{ objectFit: "contain", height: "22rem" }} /> <Card.Img variant="top" src="https://img.sonyunara.com/files/goods/67460/1607053816_0.jpg" style={{ objectFit: "contain", height: "22rem" }} />
<Card.Body> <Card.Body>
......
import React, { useState, useEffect, useRef } from 'react'; import React, { useState } from 'react';
import { Redirect } from 'react-router-dom'; import axios from 'axios'
import { Form, Col, Container, Button, Row, Alert } from 'react-bootstrap' import { Form, Col, Container, Button, Row, Alert } from 'react-bootstrap'
import axios from 'axios'; import catchErrors from '../utils/catchErrors'
const INIT_USER = { const INIT_USER = {
name: '', name: '',
...@@ -14,20 +14,15 @@ const INIT_USER = { ...@@ -14,20 +14,15 @@ const INIT_USER = {
function Signup() { function Signup() {
const [user, setUser] = useState(true) const [user, setUser] = useState(true)
//const [disabled, setDisabled] = useState(true)
const [error, setError] = useState('') const [error, setError] = useState('')
//useEffect(() => { const [validated, setValidated] = useState(false);
// const isUser = Object.values(user).every(el => Boolean(el))
// isUser ? setDisabled(false) : setDisabled(true)
//}, user)
function handleChange(event) { function handleChange(event) {
const { name, value } = event.target const { name, value } = event.target
setUser({ ...user, [name]: value }) setUser({ ...user, [name]: value })
} }
const [validated, setValidated] = useState(false);
async function handleSubmit(event) { async function handleSubmit(event) {
event.preventDefault() event.preventDefault()
...@@ -39,34 +34,44 @@ function Signup() { ...@@ -39,34 +34,44 @@ function Signup() {
} }
setValidated(true); setValidated(true);
console.log(user) console.log(user)
try { try {
setError('') setError('')
// const response = await axios.post('/api/user/signup', user) const response = await axios.post('/api/users/signup', user)
const response = await fetch('/api/users/signup', { console.log(response.data)
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(user)
})
const data = await response.json()
console.log(data)
} catch (error) { } catch (error) {
console.log(error) catchErrors(error, setError)
setError('다시 시도하세요.') }
}
function checkPassword(event){
const p1=user.password
const p2=user.password2
if(p1 !== p2){
event.preventDefault();
event.stopPropagation();
alert('비밀번호가 일치하지 않습니다.')
return false
}else{
return true
} }
} }
return ( return (
<div> <div>
<Container className="my-5"> <Container className="my-5">
{error && <Alert variant='danger'>
{error}
</Alert>}
<Row className="justify-content-center"> <Row className="justify-content-center">
<Col md={6} xs={10} className="border" style={{ background: '#F7F3F3' }}> <Col md={6} xs={10} className="border" style={{ background: '#F7F3F3' }}>
<h2 className="text-center mt-5">Sign Up</h2> <h2 className="text-center mt-5">Sign Up</h2>
{error && <Alert variant='danger'>
{error}
</Alert>}
<Form <Form
noValidate validated={validated} noValidate validated={validated}
onSubmit={handleSubmit} onSubmit={handleSubmit}
...@@ -134,7 +139,8 @@ function Signup() { ...@@ -134,7 +139,8 @@ function Signup() {
style={{ width: '160px' }} style={{ width: '160px' }}
value={user.password} value={user.password}
required required
onChange={handleChange} /> onChange={handleChange}
/>
<Form.Control.Feedback className="text-center" type="invalid"> <Form.Control.Feedback className="text-center" type="invalid">
비밀번호를 입력하세요. 비밀번호를 입력하세요.
</Form.Control.Feedback> </Form.Control.Feedback>
...@@ -150,7 +156,8 @@ function Signup() { ...@@ -150,7 +156,8 @@ function Signup() {
style={{ width: '160px' }} style={{ width: '160px' }}
value={user.password2} value={user.password2}
required required
onChange={handleChange} /> onChange={handleChange}
/>
<Form.Control.Feedback type="invalid"> 비밀번호를 한번 입력하세요. <Form.Control.Feedback type="invalid"> 비밀번호를 한번 입력하세요.
</Form.Control.Feedback> </Form.Control.Feedback>
</Form.Row> </Form.Row>
...@@ -169,7 +176,9 @@ function Signup() { ...@@ -169,7 +176,9 @@ function Signup() {
</Form.Row> </Form.Row>
</Form.Group> </Form.Group>
<Button <Button
style={{ background: '#91877F', borderColor: '#91877F' }} type="submit" block> style={{ background: '#91877F', borderColor: '#91877F' }} type="submit" block
onClick={checkPassword}
>
Sign Up Sign Up
</Button> </Button>
</Form> </Form>
......
import axios from "axios"
export function handleLogin(userId){
localStorage.setItem('loginStatus',userId)
}
export async function handleLogout(){
localStorage.removeItem('loginStatus')
await axios.get('/api/auth/logout')
window.location.href='/'
}
export function isAuthenticated(){
const userId= localStorage.getItem('loginStatus')
if(userId){
return userId
} else{
return false
}
}
\ No newline at end of file
// import React from 'react' function catchErrors(error,displayError){
function catchErrors(error, displayError) {
let errorMsg let errorMsg
if (error.response){
errorMsg = error.response.data if(error.response){
errorMsg=error.response.data
console.log(errorMsg) console.log(errorMsg)
} }else if(error.request){
else if (error.request){ errorMsg=error.request
errorMsg = error.request
console.log(errorMsg) console.log(errorMsg)
} }else{
else { errorMsg=error.message
errorMsg = error.message
console.log(errorMsg) console.log(errorMsg)
} }
displayError(errorMsg) displayError(errorMsg)
} }
export default catchErrors export default catchErrors
...@@ -7,6 +7,7 @@ import cartRouter from './routes/cart.routes.js'; ...@@ -7,6 +7,7 @@ import cartRouter from './routes/cart.routes.js';
import path from 'path' import path from 'path'
import kakaopayRoutes from './routes/kakaopay.routes.js' import kakaopayRoutes from './routes/kakaopay.routes.js'
import config from './config.js' import config from './config.js'
import authRouter from './routes/auth.routes.js'
import cors from 'cors' import cors from 'cors'
connectDb() connectDb()
...@@ -23,6 +24,7 @@ app.use(express.static(path.join(process.cwd(), 'dist'))) ...@@ -23,6 +24,7 @@ app.use(express.static(path.join(process.cwd(), 'dist')))
// app.use('/', indexRouter); // app.use('/', indexRouter);
app.use('/', kakaopayRoutes) app.use('/', kakaopayRoutes)
app.use('/api/users',userRouter) app.use('/api/users',userRouter)
app.use('/api/auth',authRouter)
app.use('/api/product', productRouter) app.use('/api/product', productRouter)
app.use('/api/addcart', cartRouter) app.use('/api/addcart', cartRouter)
......
...@@ -3,7 +3,8 @@ const config = { ...@@ -3,7 +3,8 @@ const config = {
port: process.env.PORT || 3001, port: process.env.PORT || 3001,
jwtSecret: process.env.JWT_SECRET || 'My_Secret_Key', jwtSecret: process.env.JWT_SECRET || 'My_Secret_Key',
mongoDbUri: process.env.MONGEDB_URI || 'mongodb://localhost/shopping-mall', mongoDbUri: process.env.MONGEDB_URI || 'mongodb://localhost/shopping-mall',
kakaoAdminKey: 'b2dda7685c5b2990684d813e362cff07' kakaoAdminKey: 'b2dda7685c5b2990684d813e362cff07',
cookieMaxAge: 60 * 60 * 24 * 7 * 1000
} }
// const config = { // const config = {
......
import User from '../schemas/User.js'
import bcrypt from 'bcryptjs'
import jwt from 'jsonwebtoken'
import config from '../config.js'
const login = async(req,res)=>{
const {id, password} =req.body
console.log(id,password)
try{
const user=await User.findOne({id}).select('+password')
if(!user){
return res.status(404).send(`${id}가 존재하지 않습니다.`)
}
const passwordMatch= await bcrypt.compare(password, user.password)
if(passwordMatch){
const token=jwt.sign({userId:user._id},config.jwtSecret,{
expiresIn:'3d'
})
res.cookie('token',token,{
maxAge:config.cookieMaxAge,
httpOnly:true,
secure:config.env ==='production'
})
res.json({userId:user._id})
}else{
res.status(401).send('비밀번호가 일치하지 않습니다.')
}
}catch(error){
console.log(error)
res.status(500).send('로그인 실패. 다시 시도하세요.')
}
}
const logout =(req,res)=>{
res.clearCookie('token')
res.send('로그아웃 되었습니다.')
}
export default {login, logout}
\ No newline at end of file
import User from "../models/User.js"; import User from "../schemas/User.js";
import isLength from 'validator/lib/isLength.js'; import isLength from 'validator/lib/isLength.js'
import bcrypt from 'bcryptjs'; import bcrypt from 'bcryptjs'
const signup = async (req, res) => { const signup = async (req, res) => {
console.log(req.body) console.log(req.body)
console.log('req.body.name=', req.body.name) const { name, number1, number2, id, password, tel } = req.body
const { name, number1, number2, id, password, password2, tel } = req.body
try { try {
if (!isLength(password, { min: 8, max: 15 })) { if(!isLength(password,{min:8, max:15})){
return res.status(422).json({ message: '비밀번호는 8-15자리로 입력해주세요.' }) return res.status(422).send('비밀번호는 8-15자리로 입력해주세요.')
} }
// if (!isLength(name, { min: 3, max: 10 })) { const user=await User.findOne({id})
// return res.status(422).send('이름은 3-10자로 입력해주세요.') if(user){
// } else if (!isLength(password, { min: 8, max: 15 })){ return res.status(422).send(`${id}가 이미 사용중입니다.`)
// return res.status(422).json({message: '비밀번호는 8-15자리로 입력해주세요.'}) }
// }
// const user = await User.findOne({id})
// if (user) { const hash=await bcrypt.hash(password,10)
// return res.status(422).send(`${id}가 이미 사용중입니다.`)
// } const newUser = await new User ({
const hash = await bcrypt.hash(password, 10)
const newUser = await new User({
name, name,
number1, number1,
number2, number2,
id, id,
password: hash, password:hash,
password2, tel,
tel
}).save() }).save()
console.log(newUser) console.log(newUser)
res.json(newUser) res.json(newUser)
} catch (error) { } catch (error) {
console.log(error) console.log(error)
res.status(500).json({ message: '죄송합니다. 다시 입력해 주십시오.' }) res.status(500).send('죄송합니다. 다시 입력해 주십시오.')
} }
} }
const hello = (req, res) => {
res.send('Hello from users contriller')
}
export default { signup, hello } export default { signup }
\ No newline at end of file
import mongoose from "mongoose";
const { String } = mongoose.Schema.Types
const UserSchema = new mongoose.Schema({
name: {
type: String,
required: true, // 꼭 필요한 값
},
id: {
type: String,
required: true,
unique: true,
},
password: {
type: String,
required: true,
},
number1:{
type:String,
required:true,
unique:true
},
number2:{
type:String,
required:true,
unique:true
},
tel:{
type:String,
required:true,
unique:true
},
role: {
type: String,
required: true,
default: 'user',
enum: ['user', 'admin', 'root']
}
}, {
timestamps: true
})
export default mongoose.models.User || mongoose.model('User', UserSchema)
\ No newline at end of file
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
"bcryptjs": "^2.4.3", "bcryptjs": "^2.4.3",
"cors": "^2.8.5", "cors": "^2.8.5",
"express": "^4.17.1", "express": "^4.17.1",
"jsonwebtoken": "^8.5.1",
"mongoose": "^5.11.9", "mongoose": "^5.11.9",
"multer": "^1.4.2", "multer": "^1.4.2",
"node-fetch": "^2.6.1", "node-fetch": "^2.6.1",
......
import express from "express";
import authCtrl from '../controllers/auth.controller.js';
const router = express.Router()
router.route('/login')
.post(authCtrl.login)
router.route('/logout')
.get(authCtrl.logout)
export default router
\ No newline at end of file
...@@ -5,6 +5,5 @@ const router = express.Router() ...@@ -5,6 +5,5 @@ const router = express.Router()
router.route('/signup') router.route('/signup')
.post(userCtrl.signup) .post(userCtrl.signup)
.get(userCtrl.hello)
export default router export default router
\ No newline at end of file
import mongoose from 'mongoose' import mongoose from 'mongoose'
const { String, Number, Array } = mongoose.Schema.Types const { String} = mongoose.Schema.Types
const ProductSchema = new mongoose.Schema({ const ProductSchema = new mongoose.Schema({
pro_name: { pro_name: {
......
import mongoose from 'mongoose' import mongoose from "mongoose";
const { String } = mongoose.Schema.Types const { String } = mongoose.Schema.Types
const UserSchema = new mongoose.Schema({ const UserSchema = new mongoose.Schema({
name: { name: {
type: String, type: String,
required: true, required: true,
}, },
id: { id: {
type: String, type: String,
required: true, required: true,
unique: true unique: true,
}, },
password: { password: {
type: String, type: String,
required: true, required: true,
select: false
}, },
confirm_password:{
number1: {
type: String, type: String,
required: true, required: true,
select: false
}, },
phoneNumber: { number2: {
type: String, type: String,
required: true, required: true,
}, },
role: { tel: {
type: String, type: String,
required: true, required: true,
default: 'user',
enum: ['user', 'admin', 'root']
}, },
birth: { role: {
type: String,
required: true,
},
sex: {
type: String, type: String,
required: true, required: true,
default: 'user',
enum: ['user', 'admin', 'root']
} }
}, { }, {
timestamps: true timestamps: true
......
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