Commit fa8802ee authored by kusang96's avatar kusang96
Browse files

Merge branch 'ourMaster' into kimpen

parents 0ce738d0 90a916f8
...@@ -13,31 +13,28 @@ const INIT_ACCOUNT = { ...@@ -13,31 +13,28 @@ const INIT_ACCOUNT = {
function Account() { function Account() {
const [account, setAccount] = useState(INIT_ACCOUNT) const [account, setAccount] = useState(INIT_ACCOUNT)
const [show, setShow] = useState(false); const [show, setShow] = useState(false);
const [proshow, setProshow] = useState(false)
const [error, setError] = useState("") const [error, setError] = useState("")
const userId = isAuthenticated() const userId = isAuthenticated()
const [ordered, setOrdered] = useState('')
async function getUsername(user) { async function getUsername(user) {
// console.log("tlg")
try { try {
const response = await axios.get(`/api/users/account/${user}`) const response = await axios.get(`/api/users/account/${user}`)
setAccount(response.data) setAccount(response.data)
// console.log('555555555', response.data);
} catch (error) { } catch (error) {
catchError(error, setError) catchError(error, setError)
// console.log('error2222', error)
} }
} }
useEffect(() => { useEffect(() => {
getUsername(userId) getUsername(userId)
getOrdered(userId)
}, [userId]) }, [userId])
const handleChange = (event) => { const handleChange = (event) => {
const { name, value, files } = event.target const { name, value, files } = event.target
if (files) { if (files) {
for (const file of files) {
// console.log("name=", name, "value=", value, 'file=', file);
}
setAccount({ ...account, [name]: files }) setAccount({ ...account, [name]: files })
} else { } else {
console.log("name=", name, "value=", value); console.log("name=", name, "value=", value);
...@@ -80,6 +77,16 @@ function Account() { ...@@ -80,6 +77,16 @@ function Account() {
} }
} }
async function getOrdered({}) {
console.log("object")
try {
const response = await axios.get(`/api/users/addorder`)
setOrdered(response.data)
} catch (error) {
catchError(error, setError)
}
}
return ( return (
<Container className="px-3"> <Container className="px-3">
<style type="text/css"> <style type="text/css">
...@@ -104,8 +111,8 @@ function Account() { ...@@ -104,8 +111,8 @@ function Account() {
)} )}
</Button> </Button>
<Modal show={show} onHide={() => setShow(false)}> <Modal show={show} onHide={() => setShow(false)}>
<Modal.Header closeButton> <Modal.Header closeButton style={{ background: "#F7F3F3" }}>
<Modal.Title>이미지를 변경하시겠습니까?</Modal.Title> <Modal.Title >이미지를 변경하시겠습니까?</Modal.Title>
</Modal.Header> </Modal.Header>
<Form onSubmit={handleSubmit}> <Form onSubmit={handleSubmit}>
<Modal.Body> <Modal.Body>
...@@ -127,7 +134,28 @@ function Account() { ...@@ -127,7 +134,28 @@ function Account() {
<Row className="mt-4 text-center"> <Row className="mt-4 text-center">
<Col> <Col>
<h2> <h2>
<strong>{account.name}</strong> <small>({account.id}){" "}님</small> <strong title='회원정보' style={{ cursor: "pointer", textDecoration: 'underline' }} onClick={() => setProshow(true)}>
{account.name}
</strong>
<Modal
size="sm"
show={proshow}
onHide={() => setProshow(false)}>
<Modal.Header closeButton style={{ background: "#F7F3F3" }}>
<Modal.Title>회원정보</Modal.Title>
</Modal.Header>
<Modal.Body>
<Col className="p-1">
<li><strong>Role :</strong> {account.role}</li>
<li><strong>ID :</strong> {account.id}</li>
<li><strong>Username :</strong> {account.name}</li>
<li><strong>Email :</strong> {account.email}</li>
<li><strong>Tel :</strong> {account.tel}</li>
</Col>
</Modal.Body>
</Modal>
<small>{' '}({account.id}){" "}</small>
</h2> </h2>
</Col> </Col>
</Row> </Row>
......
...@@ -89,8 +89,8 @@ function Login() { ...@@ -89,8 +89,8 @@ function Login() {
</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 m-1">
<Link to="/signup" style={{ color: '#91877F' }}>회원이 아니십니까?</Link> <Link to="/signup" style={{ color: '#91877F' }}>회원이 아니십니까?</Link>
</div> </div>
</Form> </Form>
......
...@@ -2,14 +2,14 @@ import axios from 'axios'; ...@@ -2,14 +2,14 @@ import axios from 'axios';
import React, { useState, useEffect, useRef } from 'react'; import React, { useState, useEffect, useRef } from 'react';
import DaumPostcode from "react-daum-postcode"; import DaumPostcode from "react-daum-postcode";
import { Container, Card, Row, Col, Button, Form, FormGroup } from 'react-bootstrap'; import { Container, Card, Row, Col, Button, Form, FormGroup } from 'react-bootstrap';
import { Redirect } from 'react-router-dom'; import { Redirect, Link } from 'react-router-dom';
import PaymentCard from '../Components/PaymentCard'; import PaymentCard from '../Components/PaymentCard';
import { isAuthenticated } from '../utils/auth'; import { isAuthenticated } from '../utils/auth';
import catchErrors from '../utils/catchErrors'; import catchErrors from '../utils/catchErrors';
function Payment({ match, location }) { function Payment({ match, location }) {
const [cart, setCart] = useState(location.state) const [cart, setCart] = useState([])
const [order, setOrder] = useState({products: location.state}) const [order, setOrder] = useState({products: []})
const [userData, setUserData] = useState({}) const [userData, setUserData] = useState({})
const [error, setError] = useState() const [error, setError] = useState()
const [paymentWay, setPaymentWay] = useState([]) const [paymentWay, setPaymentWay] = useState([])
...@@ -25,18 +25,31 @@ function Payment({ match, location }) { ...@@ -25,18 +25,31 @@ function Payment({ match, location }) {
useEffect(() => { useEffect(() => {
getUser() getUser()
getCart()
}, [user])
useEffect(() => {
let price = 0 let price = 0
cart.map((el) => { cart.map((el) => {
price = Number(el.count) * Number(el.productId.price) + price price = Number(el.count) * Number(el.productId.price) + price
}) })
setFinalPrice(price) setFinalPrice(price)
}, [user]) }, [cart])
async function getUser() { async function getUser() {
const name = localStorage.getItem('name')
const tel = localStorage.getItem('tel')
// const email = localStorage.getItem('email')
setUserData({ name: name, tel: tel })
}
async function getCart() {
try { try {
const response = await axios.get(`/api/users/getuser/${user}`) const response = await axios.get(`/api/cart/showcart/${user}`)
console.log(response.data) console.log(response.data)
setUserData(response.data) const preCart = response.data.filter((el) => el.checked === true)
setCart(preCart)
setOrder({ products: preCart })
} catch (error) { } catch (error) {
catchErrors(error, setError) catchErrors(error, setError)
} }
...@@ -44,8 +57,8 @@ function Payment({ match, location }) { ...@@ -44,8 +57,8 @@ function Payment({ match, location }) {
function handleReceiverInfo(e) { function handleReceiverInfo(e) {
const { name, value } = e.target const { name, value } = e.target
console.log(name,value) console.log(name, value)
setOrder({ ...order, receiverInfo: {...order.receiverInfo, [name]: value } }) setOrder({ ...order, receiverInfo: { ...order.receiverInfo, [name]: value } })
} }
function postClick() { function postClick() {
...@@ -77,7 +90,7 @@ function Payment({ match, location }) { ...@@ -77,7 +90,7 @@ function Payment({ match, location }) {
fullAddress += extraAddress !== "" ? ` (${extraAddress})` : ""; fullAddress += extraAddress !== "" ? ` (${extraAddress})` : "";
} }
setAddress({ full: fullAddress, code: data.zonecode }); setAddress({ full: fullAddress, code: data.zonecode });
setOrder({ ...order, receiverInfo: {...order.receiverInfo, address: fullAddress, postalCode: data.zonecode } }) setOrder({ ...order, receiverInfo: { ...order.receiverInfo, address: fullAddress, postalCode: data.zonecode } })
console.log(fullAddress); console.log(fullAddress);
} }
...@@ -124,6 +137,12 @@ function Payment({ match, location }) { ...@@ -124,6 +137,12 @@ function Payment({ match, location }) {
} }
async function kakaopay() { async function kakaopay() {
let itemNames = ""
if (cart.length > 1) {
itemNames = cart[0].productId.pro_name + '' + String(cart.length - 1) + ''
} else {
itemNames = cart[0].productId.pro_name
}
const response = await fetch('/api/kakaopay/test/single', { const response = await fetch('/api/kakaopay/test/single', {
method: "POST", method: "POST",
headers: { headers: {
...@@ -132,15 +151,15 @@ function Payment({ match, location }) { ...@@ -132,15 +151,15 @@ function Payment({ match, location }) {
body: JSON.stringify({ body: JSON.stringify({
cid: 'TC0ONETIME', cid: 'TC0ONETIME',
partner_order_id: 'partner_order_id', partner_order_id: 'partner_order_id',
partner_user_id: 'partner_user_id', partner_user_id: user,
item_name: '앙고라 반목 폴라 베이직 모헤어 니트 (T)', item_name: itemNames,
quantity: 1, quantity: cart.length,
total_amount: 22000, total_amount: finalPrice + 2500,
vat_amount: 200, vat_amount: 200,
tax_free_amount: 0, tax_free_amount: 0,
approval_url: 'http://localhost:3000/account', approval_url: 'http://localhost:3000/payment',
fail_url: 'http://localhost:3000/shoppingcart', fail_url: 'http://localhost:3000/payment',
cancel_url: 'http://localhost:3000/kakaopay/payment', cancel_url: 'http://localhost:3000/payment',
}) })
}) })
const data = await response.json() const data = await response.json()
...@@ -149,19 +168,31 @@ function Payment({ match, location }) { ...@@ -149,19 +168,31 @@ function Payment({ match, location }) {
// setRedirect(data.redirect_url) // setRedirect(data.redirect_url)
} }
async function paymentCompleted(){ async function paymentCompleted() {
console.log(user)
console.log(order) console.log(order)
console.log(finalPrice) const cartIds = []
order.products.map((el) => {
cartIds.push(el._id)
})
try { try {
const response = await axios.post(`/api/order/addorder`, { const response = await axios.post(`/api/order/addorder`, {
userId : user, userId: user,
...order, ...order,
total : finalPrice+2500 total: finalPrice + 2500
})
const response2 = await axios.post(`/api/cart/deletecart2`, {
userId: user,
cartId: cartIds
})
const response3 = await axios.post(`/api/product/pluspurchase`, {
products: order.products
}) })
console.log(response.data) console.log(response.data)
alert("주문이 완료되었습니다.")
return <Redirect to={'/account'} />
} catch (error) { } catch (error) {
catchErrors(error, setError) catchErrors(error, setError)
alert("주문에 실패하셨습니다. 다시 확인해주세요.")
} }
} }
...@@ -259,7 +290,7 @@ function Payment({ match, location }) { ...@@ -259,7 +290,7 @@ function Payment({ match, location }) {
<div> <div>
<h5 className="font-weight-bold py-3 border-top border-bottom text-center" style={{ background: '#F7F3F3' }}>결제수단</h5> <h5 className="font-weight-bold py-3 border-top border-bottom text-center" style={{ background: '#F7F3F3' }}>결제수단</h5>
<div className="text-center mt-5"> <div className="text-center m-3">
<Button variant="success" className="align-top" onClick={handleClick} >무통장입금</Button> <Button variant="success" className="align-top" onClick={handleClick} >무통장입금</Button>
<input type="image" alt="카카오페이결제" src="icon/payment_icon_yellow_small.png" onClick={kakaopay} /> <input type="image" alt="카카오페이결제" src="icon/payment_icon_yellow_small.png" onClick={kakaopay} />
</div> </div>
......
import axios from 'axios'; import axios from 'axios';
import React, { useState, useEffect, useRef } from 'react'; import React, { useState, useEffect, useRef } from 'react';
import { Row, Col, Form, Card, Button } from 'react-bootstrap'; import { Row, Col, Form, Card, Button, Image } from 'react-bootstrap';
import { Redirect } from 'react-router-dom'; import { Redirect } from 'react-router-dom';
import catchErrors from '../utils/catchErrors'; import catchErrors from '../utils/catchErrors';
...@@ -14,6 +14,7 @@ function Product({ match, location }) { ...@@ -14,6 +14,7 @@ function Product({ match, location }) {
const [selected, setSelected] = useState({ sizes: false, colors: false }) const [selected, setSelected] = useState({ sizes: false, colors: false })
const [count, setCount] = useState(1) const [count, setCount] = useState(1)
const [price, setPrice] = useState(0) const [price, setPrice] = useState(0)
// let price = 0
useEffect(() => { useEffect(() => {
if (size && color) { if (size && color) {
...@@ -22,16 +23,16 @@ function Product({ match, location }) { ...@@ -22,16 +23,16 @@ function Product({ match, location }) {
} }
}, [size, color]) }, [size, color])
function handleClick(e) { function handleClick(e) {
const box = e.target.parentNode.parentNode const box = e.target.parentNode.parentNode
box.style.display = "none" box.style.display = "none"
} }
function pushOptions() { function pushOptions() {
setCart([...cart, { color, size, productId: product.id }]) setCart([...cart, { color, size, productId: product.id, count: 1 }])
selected.sizes = false selected.sizes = false
selected.colors = false selected.colors = false
console.log(product)
setColor("") setColor("")
setSize("") setSize("")
setPrice(product.price + price) setPrice(product.price + price)
...@@ -50,19 +51,28 @@ function Product({ match, location }) { ...@@ -50,19 +51,28 @@ function Product({ match, location }) {
function deleteOption(e) { function deleteOption(e) {
e.preventDefault() e.preventDefault()
let preprice = 0
const asd = cart.filter((el) => el.color !== e.target.id || el.size !== e.target.name) const asd = cart.filter((el) => el.color !== e.target.id || el.size !== e.target.name)
asd.map((el) => {
preprice = preprice + el.count * product.price
})
setCart(asd) setCart(asd)
setPrice(Number(preprice))
} }
function handleCount(e) { function handleCount(e) {
e.preventDefault() const addCount = cart.map((el) => {
const addCount = cart.map((el)=>{ if (el.color !== e.target.id || el.size !== e.target.name) {
if(el.color !== e.target.id || el.size !== e.target.name){ return { ...el }
return {el}
} else { } else {
return {...el, count : e.target.value} return { ...el, count: e.target.value }
} }
}) })
let preprice = 0
addCount.map((el) => {
preprice = preprice + el.count * product.price
})
setPrice(Number(preprice))
setCart(addCount) setCart(addCount)
setCount(e.value) setCount(e.value)
} }
...@@ -90,7 +100,7 @@ function Product({ match, location }) { ...@@ -90,7 +100,7 @@ function Product({ match, location }) {
return ( return (
<div> <div>
{/* {console.log("match=", match.params, "location=", location.state, "product=", product)} */} {console.log(cart)}
<style type="text/css"> <style type="text/css">
{` {`
.btn { .btn {
...@@ -129,14 +139,15 @@ function Product({ match, location }) { ...@@ -129,14 +139,15 @@ function Product({ match, location }) {
</Form.Control> </Form.Control>
</Form.Group> </Form.Group>
{cart.map((e) => ( {cart.map((e) => (
<div> <Row className="mx-1">
<span>{e.color}/{e.size}</span> <Col xs={6}>{e.color}/{e.size}</Col>
<input onClick={deleteOption} id={e.color} name={e.size} type="image" alt="삭제버튼" src="https://img.icons8.com/fluent-systems-regular/24/000000/close-window.png" className="float-right align-middle" /> <Col xs={4} className="text-right" >
<span>{e.price}</span>
<span className="float-right mx-2">
<input type='number' id={e.color} name={e.size} onChange={handleCount} value={count} style={{ width: '3rem' }} className="text-center" /> <input type='number' id={e.color} name={e.size} onChange={handleCount} value={count} style={{ width: '3rem' }} className="text-center" />
</span> </Col>
</div> <Col xs={2} className="text-right">
<input onClick={deleteOption} id={e.color} name={e.size} type="image" alt="삭제버튼" src="https://img.icons8.com/fluent-systems-regular/24/000000/close-window.png" className="align-middle" />
</Col>
</Row>
))} ))}
<Row className="justify-content-between mx-0 my-3" style={{ width: "100%" }}> <Row className="justify-content-between mx-0 my-3" style={{ width: "100%" }}>
...@@ -152,14 +163,30 @@ function Product({ match, location }) { ...@@ -152,14 +163,30 @@ function Product({ match, location }) {
</Row> </Row>
<Row className="justify-content-center mt-5 mx-0"> <Row className="justify-content-center mt-5 mx-0">
<Col sm={11} md={8}> <Col sm={11} md={8}>
<h3 style={{ borderBottom: "1px solid #91877F", paddingBottom: "5px", marginBottom: "1em" }}>설명</h3> <h3 style={{ borderBottom: "1px solid #91877F", paddingBottom: "5px", marginBottom: "1em" }} className="p-3">
<div></div> 설명
</h3>
<Col className='m-3 text-center d-flex justify-content-center'>
<div style={{ wordBreak: 'break-all', wordWrap: 'break-word', fontFamily: "맑은 고딕" }} className="p-3">
<h1 className='m-3'>{product.name} </h1>
<>
<Image src={`/images/${product.main_img}`} style={{ objectFit: "contain", width: '100%'}} />
</>
<Card className='m-3 d-flex justify-content-center'>
<Card.Body>
{product.description}
</Card.Body>
</Card>
<h3 className='mt-5'>[ Detail Images ]</h3>
<Image src={`/images/${product.detail_imgs}`} style={{ objectFit: "contain"}} className='m-3' />
</div>
</Col>
</Col> </Col>
</Row> </Row>
<Row className="justify-content-center mx-0 pt-3 px-2" style={{ position: "fixed", bottom: "0", width: "100%", backgroundColor: "#fff" }}> <Row className="justify-content-center mx-0 pt-3 px-2" style={{ position: "fixed", bottom: "0", width: "100%", backgroundColor: "#fff" }}>
<Col sm={12} md={9}> <Col sm={12} md={9}>
<h6 style={{ borderBottom: "1px solid", paddingBottom: "5px", marginBottom: "1em" }}>회원님이 선호할만한 상품 추천 <h6 style={{ borderBottom: "1px solid", paddingBottom: "5px", marginBottom: "1em" }}>회원님이 선호할만한 상품 추천
<a className="close float-right" onClick={(e) => handleClick(e)} style={{ fontSize: "1rem" }}>X</a> <a className="close float-right" onClick={(e) => handleClick(e)} style={{ fontSize: "1rem", cursor: "pointer" }}>X</a>
</h6> </h6>
<Row className="justify-content-space mx-0" style={{ flexWrap: "nowrap", width: "100%", overflowX: "auto" }}> <Row className="justify-content-space mx-0" style={{ flexWrap: "nowrap", width: "100%", overflowX: "auto" }}>
<Col as={Card} style={{ minWidth: "10rem", marginRight: "1rem" }}> <Col as={Card} style={{ minWidth: "10rem", marginRight: "1rem" }}>
......
...@@ -102,11 +102,8 @@ function ProductsRegist() { ...@@ -102,11 +102,8 @@ function ProductsRegist() {
} }
function deleteColor(e) { function deleteColor(e) {
// console.log("e.name=",e.target.name)
e.target.parentNode.remove() e.target.parentNode.remove()
product["colors"].splice(e.name, 1) product["colors"].splice(e.name, 1)
// setColor({})
// console.log(product)
} }
function handleColor(e) { function handleColor(e) {
...@@ -136,7 +133,7 @@ function ProductsRegist() { ...@@ -136,7 +133,7 @@ function ProductsRegist() {
for (let key in product) { for (let key in product) {
if (key === "main_image" || key === "detail_image") { if (key === "main_image" || key === "detail_image") {
formData.append(key, product[key][0]) formData.append(key, product[key][0])
} else if(key === "sizes" || key === "colors"){ } else if(key === "sizes" || key === "colors" || key === 'sub_category'){
for (let i = 0; i < product[key].length ; i++){ for (let i = 0; i < product[key].length ; i++){
formData.append([key], product[key][i]) formData.append([key], product[key][i])
} }
......
...@@ -75,6 +75,7 @@ function ProductsList({ match }) { ...@@ -75,6 +75,7 @@ function ProductsList({ match }) {
} }
async function getProductlist() { async function getProductlist() {
console.log("tlfgpd")
try { try {
const response = await axios.get(`/api/product/getproduct/${mainCategory}`) const response = await axios.get(`/api/product/getproduct/${mainCategory}`)
setProductlist(response.data) setProductlist(response.data)
...@@ -92,6 +93,19 @@ function ProductsList({ match }) { ...@@ -92,6 +93,19 @@ function ProductsList({ match }) {
} }
} }
async function handleSubname(e) {
const subname = e.target.name
console.log("subname=", subname)
try {
console.log("first test!!!!!!!!")
const response = await axios.get(`/api/product/getproduct/sub/${subname}`)
console.log("subname response data=", response.data)
setProductlist([response.data])
} catch (error) {
console.log("error22")
}
}
return ( return (
<Container> <Container>
<style type="text/css"> <style type="text/css">
...@@ -114,8 +128,8 @@ function ProductsList({ match }) { ...@@ -114,8 +128,8 @@ function ProductsList({ match }) {
<Col sm={10} xs={12} > <Col sm={10} xs={12} >
<h1 style={{ fontSize: "3rem" }} className="text-center">{mainCategory}</h1> <h1 style={{ fontSize: "3rem" }} className="text-center">{mainCategory}</h1>
<div className="text-center"> <div className="text-center">
<ButtonGroup className="d-flex flex-wrap"> <ButtonGroup className="m-3" variant="outline-light secondary" style={{ display: "inline-block" }}>
{subCategory.map(el => (<Button className="m-1" onClick={() => handleClick(el)}>{el}</Button>))} {subCategory.map(el => (<Button className="m-1" variant="secondary" name={el} onClick={handleSubname}>{el}</Button>))}
</ButtonGroup> </ButtonGroup>
</div> </div>
</Col> </Col>
...@@ -139,7 +153,7 @@ function ProductsList({ match }) { ...@@ -139,7 +153,7 @@ function ProductsList({ match }) {
</Row> </Row>
<Row md={8} sm={12} className="justify-content-center m-2"> <Row md={8} sm={12} className="justify-content-center m-2">
{productlist.map(pro => ( {productlist.map(pro => (
<ListCard as={Link} id={pro._id} name={pro.pro_name} price={pro.price} main_img={pro.main_imgUrl} to={{ <Link to={{
pathname: `/product/${pro._id}`, pathname: `/product/${pro._id}`,
state: { state: {
id: pro._id, id: pro._id,
...@@ -151,10 +165,12 @@ function ProductsList({ match }) { ...@@ -151,10 +165,12 @@ function ProductsList({ match }) {
main_img: pro.main_imgUrl, main_img: pro.main_imgUrl,
detail_imgs: pro.detail_imgUrls detail_imgs: pro.detail_imgUrls
} }
}} /> }}>
<ListCard id={pro._id} name={pro.pro_name} price={pro.price} main_img={pro.main_imgUrl} />
</Link>
))} ))}
{/* <Pagination className="justify-content-center" index={} endPage={} handlePage={}/> */}
</Row> </Row>
{/* <Pagination className="justify-content-center" index={} endPage={} handlePage={}/> */}
</Container> </Container>
) )
} }
......
...@@ -75,6 +75,7 @@ function ShoppingCart() { ...@@ -75,6 +75,7 @@ function ShoppingCart() {
async function getCart() { async function getCart() {
try { try {
setError('')
const response = await axios.get(`/api/cart/showcart/${user}`) const response = await axios.get(`/api/cart/showcart/${user}`)
const addChecked = response.data.map((el) => { const addChecked = response.data.map((el) => {
return { ...el, checked: false } return { ...el, checked: false }
...@@ -86,8 +87,22 @@ function ShoppingCart() { ...@@ -86,8 +87,22 @@ function ShoppingCart() {
} }
} }
function putCheckedCart(){
try {
setError('')
const response = axios.post(`/api/cart/changecart`, {
userId:user,
products: cart
})
console.log(response.data)
} catch (error) {
catchErrors(error, setError)
}
}
return ( return (
<div> <div>
{console.log(cart)}
<Container className="justify-content-center"> <Container className="justify-content-center">
<h1 className="my-5 font-weight-bold text-center">장바구니</h1> <h1 className="my-5 font-weight-bold text-center">장바구니</h1>
<div> <div>
...@@ -116,7 +131,7 @@ function ShoppingCart() { ...@@ -116,7 +131,7 @@ function ShoppingCart() {
<Button as={Link} to={{ <Button as={Link} to={{
pathname: `/payment`, pathname: `/payment`,
state: finalCart state: finalCart
}} className="px-5" style={{ background: "#91877F", borderColor: '#91877F' }} block>결제하기</Button> }} className="px-5" style={{ background: "#91877F", borderColor: '#91877F' }} onClick={putCheckedCart} block>결제하기</Button>
</div> </div>
</Container> </Container>
</div> </div>
......
...@@ -10,7 +10,8 @@ const INIT_USER = { ...@@ -10,7 +10,8 @@ const INIT_USER = {
id: '', id: '',
password: '', password: '',
password2: '', password2: '',
tel: '' tel: '',
email: ''
} }
function Signup() { function Signup() {
...@@ -61,134 +62,160 @@ function Signup() { ...@@ -61,134 +62,160 @@ function Signup() {
if (success) { if (success) {
alert('회원가입 되었습니다.') alert('회원가입 되었습니다.')
return <Redirect to='/login'/> return <Redirect to='/login' />
} }
return ( return (
<div> <div>
<Container className="my-5"> <Container className="my-5">
<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 m-5">Sign Up</h2>
{error && <Alert variant='danger'> {error && <Alert variant='danger'>
{error} {error}
</Alert>} </Alert>}
<Form <Form
noValidate validated={validated} noValidate validated={validated}
onSubmit={handleSubmit} onSubmit={handleSubmit}
className="p-5"> className="p-4">
<Form.Group controlId="formBasicName"> <Form.Group as={Col} controlId="formBasicName" className="justify-content-end">
<Form.Row> <Form.Row>
<Col sm={4} xs={6} as={Form.Label} for="id"> </Col> <Col sm={4} xs={6} as={Form.Label} for="id"> </Col>
<Col sm={8} xs={12} as={Form.Control} <Col sm={8} xs={6} as={Form.Control}
required type="text"
name="name"
placeholder="Name"
style={{ width: '160px' }}
value={user.name}
onChange={handleChange} />
<Form.Control.Feedback type="invalid">이름을 입력하세요. </Form.Control.Feedback>
</Form.Row>
</Form.Group>
<Form.Group controlId="formBasicNumber">
<Form.Row>
<Col sm={4} xs={6} as={Form.Label} for="number">주민등록번호</Col>
<Col as={Row} sm={8} xs={10} >
<Form.Control
required type="text" required type="text"
name="number1" name="name"
maxlength="6" placeholder="Name"
className="mx-2" style={{ width: '17 0px' }} style={{ width: '160px' }}
value={user.number1} value={user.name}
onChange={handleChange}> onChange={handleChange} />
</Form.Control> <Form.Control.Feedback type="invalid" >이름을 입력하세요. </Form.Control.Feedback>
- </Form.Row>
<Form.Control </Form.Group>
required type="text" <Form.Group as={Col} controlId="formBasicNumber">
name="number2" <Form.Row>
maxlength="1" className="mx-3" <Col sm={4} xs={6} as={Form.Label} for="number">주민등록번호</Col>
style={{ width: '50px' }} <Col xs={3}>
value={user.number2} <Form.Control
onChange={handleChange}> required type="text"
</Form.Control> name="number1"
****** maxlength="6"
className="ml-1 mr-3 p-1" style={{ width: '80px' }}
value={user.number1}
onChange={handleChange}>
</Form.Control>
</Col>
<Col xs={1}>
<div className='font-weight-bold d-flex align-items-center' style={{ text: 'center' }}>-</div>
</Col>
<Col xs={2}>
<Form.Control
required type="text"
name="number2"
maxlength="1" className="mx-3 p-1"
style={{ width: '30px' }}
value={user.number2}
onChange={handleChange}>
</Form.Control>
</Col>
<div className='font-weight-bold d-flex align-items-center'>* * * * * * </div>
<Form.Control.Feedback type="invalid">주민등록번호를 입력하세요.</Form.Control.Feedback> <Form.Control.Feedback type="invalid">주민등록번호를 입력하세요.</Form.Control.Feedback>
</Col> </Form.Row>
</Form.Row> </Form.Group>
</Form.Group> <Form.Group as={Col} controlId="formBasicId">
<Form.Group controlId="formBasicId"> <Form.Row>
<Form.Row> <Col sm={4} xs={6} as={Form.Label} for="id">아이디</Col>
<Col sm={4} xs={6} as={Form.Label} for="id">아이디</Col> <Col sm={8} xs={12} as={Form.Control}
<Col sm={8} xs={12} as={Form.Control} required
required type="text"
type="text" name="id"
name="id" placeholder="ID"
placeholder="ID" style={{ width: '160px' }}
style={{ width: '160px' }} value={user.id}
value={user.id} onChange={handleChange} />
onChange={handleChange} /> <Form.Control.Feedback type="invalid"> 아이디를 입력하세요.</Form.Control.Feedback>
<Form.Control.Feedback type="invalid"> 아이디를 입력하세요.</Form.Control.Feedback> </Form.Row>
</Form.Row> </Form.Group>
</Form.Group> <Form.Group as={Col} controlId="formBasicPassword">
<Form.Group controlId="formBasicPassword"> <Form.Row>
<Form.Row> <Col sm={4} xs={6} as={Form.Label} for="password">비밀번호</Col>
<Col sm={4} xs={6} as={Form.Label} for="password">비밀번호</Col> <Col sm={8} xs={12} as={Form.Control}
<Col sm={8} xs={12} as={Form.Control} type="password"
type="password" name="password"
name="password" placeholder="Password"
placeholder="Password" style={{ width: '160px' }}
style={{ width: '160px' }} value={user.password}
value={user.password} required
required onChange={handleChange}
onChange={handleChange} />
/> <Form.Control.Feedback className="text-end" type="invalid">
<Form.Control.Feedback className="text-center" type="invalid"> 비밀번호를 입력하세요.
비밀번호를 입력하세요. </Form.Control.Feedback>
</Form.Row>
</Form.Group>
<Form.Group as={Col} controlId="formBasicPassword2">
<Form.Row>
<Col sm={4} xs={6} as={Form.Label} for="password">비밀번호 확인</Col>
<Col sm={8} xs={12} as={Form.Control}
type="password"
name="password2"
placeholder="Password"
style={{ width: '160px' }}
value={user.password2}
required
onChange={handleChange}
/>
<Form.Control.Feedback type="invalid"> 비밀번호를 한번 입력하세요.
</Form.Control.Feedback> </Form.Control.Feedback>
</Form.Row> </Form.Row>
</Form.Group> </Form.Group>
<Form.Group controlId="formBasicPassword2"> <Form.Group as={Col} controlId="formBasicEmail">
<Form.Row> <Form.Row>
<Col sm={4} xs={6} as={Form.Label} for="password">비밀번호 확인</Col> <Col sm={4} xs={6} as={Form.Label} for="email">이메일</Col>
<Col sm={8} xs={12} as={Form.Control} <Col sm={8} xs={12} as={Form.Control}
type="password" required type="email"
name="password2" name="email"
placeholder="Password" placeholder="E-mail"
style={{ width: '160px' }} style={{ width: '160px' }}
value={user.password2} value={user.email}
required onChange={handleChange} />
onChange={handleChange} <Form.Control.Feedback type="invalid"> 이메일 입력하세요. </Form.Control.Feedback>
/> </Form.Row>
<Form.Control.Feedback type="invalid"> 비밀번호를 한번 입력하세요. </Form.Group>
<Form.Group as={Col} controlId="formBasicTel">
<Form.Row>
<Col sm={4} xs={6} as={Form.Label} for="tel">휴대전화</Col>
<Col sm={8} xs={12} style={{ width: '160px' }} className='p-0'>
<Col
as={Form.Control}
required type="text"
name="tel"
placeholder="Telephone"
className='p-1'
value={user.tel}
onChange={handleChange}>
</Col>
<div className='d-flex justify-content-end mt-1'><small >' - ' 함께 입력해주세요^^</small></div>
</Col>
<Form.Control.Feedback type="invalid"> 휴대전화를 입력하세요. </Form.Control.Feedback>
</Form.Row>
<Form.Control.Feedback className="text-end" type="invalid">
비밀번호를 입력하세요.
</Form.Control.Feedback> </Form.Control.Feedback>
</Form.Row> </Form.Group >
</Form.Group> <Button
<Form.Group controlId="formBasicTel"> style={{ background: '#91877F', borderColor: '#91877F' }} type="submit" block
<Form.Row> onClick={checkPassword}
<Col sm={4} xs={6} as={Form.Label} for="tel">휴대전화</Col> >
<Col sm={8} xs={12} as={Form.Control} Sign Up
required
type="text"
name="tel"
size="sm" style={{ width: '160px' }}
value={user.tel}
onChange={handleChange} />
<Form.Control.Feedback type="invalid"> 휴대전화를 입력하세요. </Form.Control.Feedback>
</Form.Row>
</Form.Group>
<Button
style={{ background: '#91877F', borderColor: '#91877F' }} type="submit" block
onClick={checkPassword}
>
Sign Up
</Button> </Button>
</Form> </Form>
</Col> </Col>
</Row> </Row>
</Container> </Container>
</div> </div >
) )
} }
export default Signup export default Signup
\ No newline at end of file
import Cart from "../schemas/Cart.js"; import Cart from "../schemas/Cart.js";
const addcart = async (req, res) => { const addCart = async (req, res) => {
const { userId, products} = req.body const { userId, products } = req.body
try { try {
const cart = await Cart.findOne({ userId: userId }) const cart = await Cart.findOne({ userId: userId })
await Cart.updateOne( await Cart.updateOne(
{ _id: cart._id }, { _id: cart._id },
{$push: {products: products}} { $push: { products: products } }
) )
res.status(200).send('카트에 저장되었습니다.') res.status(200).send('카트에 저장되었습니다.')
} catch (error) { } catch (error) {
...@@ -15,31 +15,49 @@ const addcart = async (req, res) => { ...@@ -15,31 +15,49 @@ const addcart = async (req, res) => {
} }
} }
const showcart = async (req, res) => { const changeCart = async (req, res) => {
const { userId, products } = req.body
console.log(products)
try { try {
const cart = await Cart.findOne({ userId: userId })
await Cart.updateOne(
{ _id: cart._id },
{ $set: { products: products } }
)
res.send("카트에 체크가 활성화되었습니다")
} catch (error) {
res.send("카트 체인지 실패")
}
}
const showCart = async (req, res) => {
try {
console.log("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@")
const cart = await Cart.findOne({ userId: req.id }).populate({ const cart = await Cart.findOne({ userId: req.id }).populate({
path: 'products.productId', path: 'products.productId',
model: 'Product' model: 'Product'
}) })
res.status(200).json(cart.products) res.status(200).json(cart.products)
console.log("cart-products : ", cart.products);
} catch (error) { } catch (error) {
console.log("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx")
console.log(error) console.log(error)
res.status(500).send('쇼핑카트를 불러오지 못했습니다.') res.status(500).send('쇼핑카트를 불러오지 못했습니다.')
} }
} }
const deletecart = async (req, res) => { const deleteCart = async (req, res) => {
console.log(req.body) console.log(req.body)
const { userId,cartId } = req.body const { userId, cartId } = req.body
try { try {
const cart = await Cart.findOneAndUpdate( const cart = await Cart.findOneAndUpdate(
{ userId: userId }, { userId: userId },
{ $pull: { products: {_id:cartId} } }, { $pull: { products: { _id: cartId } } },
{ new: true } { new: true }
).populate({ ).populate({
path: 'products.productId', path: 'products.productId',
model: 'Product' model: 'Product'
}) })
// res.send("삭제완료") // res.send("삭제완료")
res.json(cart) res.json(cart)
} catch (error) { } catch (error) {
...@@ -48,6 +66,29 @@ const deletecart = async (req, res) => { ...@@ -48,6 +66,29 @@ const deletecart = async (req, res) => {
} }
} }
const deleteCart2 = async (req, res) => {
console.log(req.body)
const { userId, cartId } = req.body
try {
for( let i = 0; i < cartId.length; i++ ){
await Cart.findOneAndUpdate(
{ userId: userId },
{ $pull: { products: { _id: cartId[i] } } },
{ new: true }
).populate({
path: 'products.productId',
model: 'Product'
})
}
res.send("주문완료 쇼핑카트 삭제")
// res.json(cart)
} catch (error) {
console.log(error)
res.status(500).send('해당 카트를 삭제하지 못했습니다.')
}
}
const userById = async (req, res, next, id) => { const userById = async (req, res, next, id) => {
try { try {
const cart = await Cart.findOne({ userId: id }) const cart = await Cart.findOne({ userId: id })
...@@ -63,4 +104,4 @@ const userById = async (req, res, next, id) => { ...@@ -63,4 +104,4 @@ const userById = async (req, res, next, id) => {
} }
export default { addcart, showcart, deletecart, userById } export default { addCart, changeCart, showCart, deleteCart,deleteCart2, userById }
\ No newline at end of file \ No newline at end of file
...@@ -11,10 +11,12 @@ const getCategory = async (req, res) => { ...@@ -11,10 +11,12 @@ const getCategory = async (req, res) => {
} }
const getSubCategory = async (req, res) => { const getSubCategory = async (req, res) => {
const name = req.params.name console.log("req.params=?(getsubcategory)", req.params);
const { sub } = req.params
try { try {
const subcategory = await Category.findOne({}, { _id: 0}).select(`${name}`) const subcategory = await Category.findOne({}, { _id: 0}).select(`${sub}`)
res.json(subcategory); res.json(subcategory);
console.log("sub= ",subcategory);
} catch (error) { } catch (error) {
res.status(500).send('카테고리를 불러오지 못했습니다.') res.status(500).send('카테고리를 불러오지 못했습니다.')
} }
...@@ -24,8 +26,8 @@ const getToHome = async (res, req) => { ...@@ -24,8 +26,8 @@ const getToHome = async (res, req) => {
try { try {
const bestProduct = await Product.find({}).sort({ purchase: 1 }).limit(6) const bestProduct = await Product.find({}).sort({ purchase: 1 }).limit(6)
const newProduct = await Product.find({}).sort({ createdAt: -1 }).limit(6) const newProduct = await Product.find({}).sort({ createdAt: -1 }).limit(6)
console.log("best=", bestProduct) // console.log("best=", bestProduct)
console.log("new=", newProduct) // console.log("new=", newProduct)
res.json(bestProduct, newProduct) res.json(bestProduct, newProduct)
} catch { } catch {
res.status(500).send('상품을 불러오지 못했습니다.') res.status(500).send('상품을 불러오지 못했습니다.')
...@@ -48,20 +50,4 @@ const getsubId = async (req, res, next, ele) => { ...@@ -48,20 +50,4 @@ const getsubId = async (req, res, next, ele) => {
next() next()
} }
// const userById = async (req, res, next, id) => {
// try {
// const user = await User.findById(id)
// if (!user) {
// res.status(404).send('사용자를 찾을 수 없습니다')
// }
// req.account = user
// next()
// } catch (error) {
// console.log(error);
// res.status(500).send('사용자 아이디 검색 실패')
// }
// }
export default { getCategory, getsubId, getSubCategory, getToHome } export default { getCategory, getsubId, getSubCategory, getToHome }
\ No newline at end of file
...@@ -13,6 +13,17 @@ const addorder = async (req, res) => { ...@@ -13,6 +13,17 @@ const addorder = async (req, res) => {
} }
} }
const Ordered = async (req, res) => {
const { db } = req.body
try {
const ordered = await req.body.findOne({}, { _id: 0}).select(`${db}`)
console.log("sub= ",ordered);
res.json(ordered);
} catch (error) {
res.status(500).send('카테고리를 불러오지 못했습니다.')
}
}
const showorder = async (req, res) => { const showorder = async (req, res) => {
try { try {
const order = await Order.findOne({ userId: req.id }).populate({ const order = await Order.findOne({ userId: req.id }).populate({
...@@ -30,4 +41,4 @@ const showorder = async (req, res) => { ...@@ -30,4 +41,4 @@ const showorder = async (req, res) => {
export default { addorder, showorder } export default { addorder, showorder, Ordered }
\ No newline at end of file \ No newline at end of file
...@@ -33,8 +33,8 @@ const getToHome = async (req, res) => { ...@@ -33,8 +33,8 @@ const getToHome = async (req, res) => {
try { try {
const bestProduct = await Product.find({}).sort({ purchase: -1 }).limit(6) const bestProduct = await Product.find({}).sort({ purchase: -1 }).limit(6)
const newProduct = await Product.find({}).sort({ createdAt: -1 }).limit(6) const newProduct = await Product.find({}).sort({ createdAt: -1 }).limit(6)
console.log("best=", bestProduct) // console.log("best=", bestProduct)
console.log("new=", newProduct) // console.log("new=", newProduct)
res.json({ bestProduct, newProduct }) res.json({ bestProduct, newProduct })
} catch { } catch {
res.status(500).send('상품을 불러오지 못했습니다.') res.status(500).send('상품을 불러오지 못했습니다.')
...@@ -59,6 +59,15 @@ const getlist = (req, res) => { ...@@ -59,6 +59,15 @@ const getlist = (req, res) => {
} }
} }
const subname = async (req, res) => {
try {
console.log("last subname::: LET ME SEE")
res.json(req.findsubname)
} catch (error) {
res.status(500).send('상품을 불러오지 못했습니다.')
}
}
const categoryId = async (req, res, next, category) => { const categoryId = async (req, res, next, category) => {
const { search } = req.body const { search } = req.body
console.log("server=",search) console.log("server=",search)
...@@ -68,31 +77,53 @@ const categoryId = async (req, res, next, category) => { ...@@ -68,31 +77,53 @@ const categoryId = async (req, res, next, category) => {
res.status(404).send('상품을 찾을 수 없습니다.') res.status(404).send('상품을 찾을 수 없습니다.')
} }
req.productslist = productslist req.productslist = productslist
console.log("nononono", req.productslist)
next() next()
} catch (error) { } catch (error) {
res.status(500).send('상품을 불러오지 못했습니다.') res.status(500).send('상품을 불러오지 못했습니다.')
} }
} }
// const subgetlist = (req, res) => { const subcategoryId = async (req, res, next, subname) => {
// try { try {
// res.json(req.subproductslist) console.log("Please===>>>", subname)
// } catch (error) { const findSubname = await Product.findOne({ sub_category: subname })
// res.status(500).send('상품을 불러오지 못했습니다.') console.log("findSubname111=", findSubname)
// }
// }
// const subcategoryId = async (req, res, next, subcategory) => { if (!findSubname) {
// try { const findSubname = {
// const subproductslist = await Product.find({ sub_category: subcategory }) _id: 'nothing',
// if (!subproductslist) { pro_name: '상품준비중',
// res.status(404).send('상품을 찾을 수 없습니다.') price: 0,
// } main_imgUrl:''
// req.subproductslist = subproductslist }
// next() console.log("findSubname2222=", findSubname)
// } catch (error) { res.send(findSubname)
// res.status(500).send('상품을 불러오지 못했습니다.') }
// } res.send(findSubname)
// } } catch (error) {
res.send('상품을 불러오지 못했습니다.')
}
}
const plusPurchase = async (req, res) => {
const { products } = req.body
try {
for (let i = 0; i < products.length; i++) {
const count = products[i].count
const product = await Product.findOne(
{ _id: products[i].productId._id }
)
const purchase = product.purchase
await Product.updateOne(
{ _id: products[i].productId._id },
{ $set: { purchase: count + purchase } }
)
}
res.send("구매수 늘리기 성공")
} catch (error) {
res.status(500).send('구매숫자를 늘리지 못함')
}
}
export default { imageUpload, regist, getToHome, getAll, categoryId, getlist } export default { imageUpload, regist, getToHome, getAll, categoryId, getlist, subcategoryId, subname, plusPurchase }
\ No newline at end of file
...@@ -31,8 +31,8 @@ const userById = async (req, res, next, id) => { ...@@ -31,8 +31,8 @@ const userById = async (req, res, next, id) => {
const signup = async (req, res) => { const signup = async (req, res) => {
const { name, number1, number2, id, password, tel } = req.body const { name, number1, number2, id, password, tel, email } = req.body
console.log(req.body) console.log("whatup", req.body)
try { try {
if (!isLength(password, { min: 8, max: 15 })) { if (!isLength(password, { min: 8, max: 15 })) {
return res.status(422).send('비밀번호는 8-15자리로 입력해주세요.') return res.status(422).send('비밀번호는 8-15자리로 입력해주세요.')
...@@ -51,8 +51,9 @@ const signup = async (req, res) => { ...@@ -51,8 +51,9 @@ const signup = async (req, res) => {
id, id,
password: hash, password: hash,
tel, tel,
email
}).save() }).save()
await new Cart({ userId: newUser._id, role }).save() await new Cart({ userId: newUser._id }).save()
console.log(newUser) console.log(newUser)
res.json(newUser) res.json(newUser)
......
...@@ -5,15 +5,20 @@ import cartCtrl from '../controllers/cart.controller.js'; ...@@ -5,15 +5,20 @@ import cartCtrl from '../controllers/cart.controller.js';
const router = express.Router() const router = express.Router()
router.route('/addcart') router.route('/addcart')
.put(cartCtrl.addcart) .put(cartCtrl.addCart)
// .get() // .get()
router.route('/showcart/:userId') router.route('/showcart/:userId')
.get(cartCtrl.showcart) .get(cartCtrl.showCart)
router.param('userId', cartCtrl.userById)
router.route('/changecart')
.post(cartCtrl.changeCart)
router.route('/deletecart') router.route('/deletecart')
.post(cartCtrl.deletecart) .post(cartCtrl.deleteCart)
router.route('/deletecart2')
.post(cartCtrl.deleteCart2)
router.param('userId', cartCtrl.userById)
export default router export default router
\ No newline at end of file
...@@ -13,14 +13,16 @@ router.route('/getproduct') ...@@ -13,14 +13,16 @@ router.route('/getproduct')
router.route('/getproduct/all') router.route('/getproduct/all')
.get(productCtrl.getAll) .get(productCtrl.getAll)
router.route('/getproduct/:category') router.route('/getproduct/main/:category')
.get(productCtrl.getlist) .get(productCtrl.getlist)
// router.route('/getproduct/:subcategory') router.route('/getproduct/sub/:subname')
// .get(productCtrl.subgetlist) .get(productCtrl.subname)
router.param('category', productCtrl.categoryId) router.route('/pluspurchase')
.post(productCtrl.plusPurchase)
// router.param('subcategory',productCtrl.subcategoryId) router.param('category', productCtrl.categoryId)
router.param('subname',productCtrl.subcategoryId)
export default router export default router
\ No newline at end of file
...@@ -22,6 +22,9 @@ const CartSchema = new mongoose.Schema({ ...@@ -22,6 +22,9 @@ const CartSchema = new mongoose.Schema({
}, },
color: { color: {
type: String type: String
},
checked: {
type: Boolean
} }
} }
] ]
......
...@@ -24,32 +24,35 @@ const OrderSchema = new mongoose.Schema({ ...@@ -24,32 +24,35 @@ const OrderSchema = new mongoose.Schema({
color: { color: {
type: String, type: String,
required: true required: true
},
checked: {
type: Boolean
} }
} }
], ],
receiverInfo: receiverInfo:
{ {
name: { name: {
type:String, type: String,
required:true required: true
}, },
tel: { tel: {
type: String, type: String,
required:true required: true
}, },
postalCode:{ postalCode: {
type:String, type: String,
required:true required: true
}, },
address: { address: {
type: String, type: String,
required: true required: true
}, },
address2: { address2: {
type: String, type: String,
required: true required: true
}
} }
}
, ,
total: { total: {
type: Number, type: Number,
......
...@@ -34,6 +34,10 @@ const UserSchema = new mongoose.Schema({ ...@@ -34,6 +34,10 @@ const UserSchema = new mongoose.Schema({
default: 'user', default: 'user',
enum: ['user', 'admin', 'root'] enum: ['user', 'admin', 'root']
}, },
email : {
type : String,
required: true,
},
avatarUrl: { avatarUrl: {
type: String type: String
} }
......
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