박민정

[update] Fix countless error.. and admin page is deleted

Showing 103 changed files with 2906 additions and 875 deletions
This diff could not be displayed because it is too large.
......@@ -4,21 +4,25 @@
"private": true,
"dependencies": {
"antd": "^3.24.1",
"axios": "^0.19.2",
"core-js": "^3.6.4",
"axios": "^0.18.0",
"bootstrap": "^4.6.0",
"formik": "^1.5.8",
"moment": "^2.24.0",
"react": "^16.8.6",
"react-app-polyfill": "^1.0.6",
"react-bootstrap": "^1.6.1",
"react-dom": "^16.8.6",
"react-dropzone": "^11.3.2",
"react-dropzone": "^10.2.1",
"react-icons": "^3.7.0",
"react-image-gallery": "^1.0.3",
"react-paypal-express-checkout": "^1.0.5",
"react-redux": "^7.1.0-rc.1",
"react-router-dom": "^5.0.1",
"react-scripts": "3.4.1",
"react-scripts": "3.0.1",
"redux": "^4.0.0",
"redux-form": "^8.2.6",
"redux-promise": "^0.6.0",
"redux-thunk": "^2.3.0",
"socket.io-client": "^2.2.0",
"yup": "^0.27.0"
},
"scripts": {
......
......@@ -19,7 +19,13 @@
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<title>React App</title>
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.1/dist/css/bootstrap.min.css"
integrity="sha384-+0n0xVW2eSR5OomGNYDnhzAbDsOXxcvSN1TPprVMTNDbiYZCxYbOOl7+AMvyTG2x"
crossorigin="anonymous"
/>
<title>약 배달 서비스 : 약사</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
......
// type들만 관리하는 곳
export const LOGIN_USER = 'login_user';
export const REGISTER_USER = 'register_user';
export const AUTH_USER = 'auth_user';
export const LOGOUT_USER = 'logout_user';
export const ADD_TO_CART_USER = 'add_to_cart_user';
export const GET_CART_ITEMS_USER = 'get_cart_items_user';
export const REMOVE_CART_ITEM_USER = 'remove_cart_item_user';
export const ON_SUCCESS_BUY_USER = 'on_success_buy_user';
\ No newline at end of file
......
......@@ -4,38 +4,36 @@ import {
REGISTER_USER,
AUTH_USER,
LOGOUT_USER,
ADD_TO_CART_USER,
GET_CART_ITEMS_USER,
REMOVE_CART_ITEM_USER,
ON_SUCCESS_BUY_USER
} from './types';
import { USER_SERVER } from '../components/Config.js';
export function loginUser(logInfo){
const request = axios.post(`${USER_SERVER}/login`,logInfo)// logInfo를 post로 전달
.then(response => response.data); // 서버에서 받은 데이터를 request에 저장
return { // return을 통해 Reducer로 보냄
// Reducer에서 previousState, action을 이용해 nextState로 만들기 때문 :: (previousState, action) => nextState
// request를 reducer로 보내는 작업
// action은 type과 response을 넣어줘야 함
type: LOGIN_USER,
payload: request // payroad == response
}
}
export function registerUser(dataToSubmit){
const request = axios.post(`${USER_SERVER}/register`,dataToSubmit)
export function registerUser(dataToSubmit) {
const request = axios.post(`${USER_SERVER}/register`, dataToSubmit)
.then(response => response.data);
return {
type: REGISTER_USER,
payload: request
}
}
export function loginUser(dataToSubmit) {
const request = axios.post(`${USER_SERVER}/login`, dataToSubmit)
.then(response => response.data);
return {
type: LOGIN_USER,
payload: request
}
}
export function auth(){
export function auth() {
const request = axios.get(`${USER_SERVER}/auth`)
.then(response => response.data);
.then(response => response.data);
return {
type: AUTH_USER,
......@@ -43,9 +41,9 @@ export function auth(){
}
}
export function logoutUser(){
export function logoutUser() {
const request = axios.get(`${USER_SERVER}/logout`)
.then(response => response.data);
.then(response => response.data);
return {
type: LOGOUT_USER,
......@@ -53,3 +51,80 @@ export function logoutUser(){
}
}
export function addToCart(_id) {
const request = axios.get(`${USER_SERVER}/addToCart?productId=${_id}`)
.then(response => response.data);
return {
type: ADD_TO_CART_USER,
payload: request
}
}
export function getCartItems(cartItems, userCart) {
const request = axios.get(`/api/product/products_by_id?id=${cartItems}&type=array`)
.then(response => {
//Make CartDetail inside Redux Store
// We need to add quantity data to Product Information that come from Product Collection.
userCart.forEach(cartItem => {
response.data.forEach((productDetail, i) => {
if (cartItem.id === productDetail._id) {
response.data[i].quantity = cartItem.quantity;
}
})
})
return response.data;
});
return {
type: GET_CART_ITEMS_USER,
payload: request
}
}
export function removeCartItem(id) {
const request = axios.get(`/api/users/removeFromCart?_id=${id}`)
.then(response => {
response.data.cart.forEach(item => {
response.data.cartDetail.forEach((k, i) => {
if (item.id === k._id) {
response.data.cartDetail[i].quantity = item.quantity
}
})
})
return response.data;
});
return {
type: REMOVE_CART_ITEM_USER,
payload: request
}
}
export function onSuccessBuy(data) {
const request = axios.post(`${USER_SERVER}/successBuy`, data)
.then(response => response.data);
return {
type: ON_SUCCESS_BUY_USER,
payload: request
}
}
......
import { combineReducers } from 'redux';
import user from './user_reducer';
import { combineReducers } from "redux";
import user from "./user_reducer";
const rootReducer = combineReducers({
user,
user,
});
export default rootReducer;
\ No newline at end of file
export default rootReducer;
......
......@@ -3,19 +3,54 @@ import {
REGISTER_USER,
AUTH_USER,
LOGOUT_USER,
ADD_TO_CART_USER,
GET_CART_ITEMS_USER,
REMOVE_CART_ITEM_USER,
ON_SUCCESS_BUY_USER
} from '../_actions/types';
export default function(state={},action){
switch(action.type){
export default function (state = {}, action) {
switch (action.type) {
case REGISTER_USER:
return {...state, register: action.payload }
return { ...state, register: action.payload }
case LOGIN_USER:
return { ...state, loginSucces: action.payload }
case AUTH_USER:
return {...state, userData: action.payload }
return { ...state, userData: action.payload }
case LOGOUT_USER:
return {...state }
return { ...state }
case ADD_TO_CART_USER:
return {
...state, userData: {
...state.userData,
cart: action.payload
}
}
case GET_CART_ITEMS_USER:
return {
...state, cartDetail: action.payload
}
case REMOVE_CART_ITEM_USER:
return {
...state,
cartDetail: action.payload.cartDetail,
userData: {
...state.userData,
cart: action.payload.cart
}
}
case ON_SUCCESS_BUY_USER:
return {
...state,
userData: {
...state.userData,
cart: action.payload.cart
},
cartDetail: action.payload.cartDetail
}
default:
return state;
}
......
import React, { Suspense } from 'react';
import React, { Suspense } from "react";
import { Route, Switch } from "react-router-dom";
import Auth from "../hoc/auth";
// pages for this product
import LandingPage from "./views/LandingPage/LandingPage.js";
import LoginPage from "./views/LoginPage/LoginPage.js";
import RegisterPage from "./views/RegisterPage/RegisterPage.js";
import UploadPage from './views/UploadPage/UploadPage';
import NavBar from "./views/NavBar/NavBar";
import Footer from "./views/Footer/Footer"
//null Anyone Can go inside
//true only logged in user can go inside
//false logged in user can't go inside
import Footer from "./views/Footer/Footer";
import UploadProductPage from "./views/UploadProductPage/UploadProductPage";
import DetailProductPage from "./views/DetailProductPage/DetailProductPage";
import CartPage from "./views/CartPage/CartPage";
import HistoryPage from "./views/HistoryPage/HistoryPage";
import adminPage from "./views/adminPage/adminPage";
function App() {
return (
<Suspense fallback={(<div>Loading...</div>)}>
<Suspense fallback={<div>Loading...</div>}>
<NavBar />
<div style={{ paddingTop: '69px', minHeight: 'calc(100vh - 80px)' }}>
<div style={{ paddingTop: "75px", minHeight: "calc(100vh - 80px)" }}>
<Switch>
<Route exact path="/" component={Auth(LandingPage, null)} />
<Route exact path="/login" component={Auth(LoginPage, false)} />
<Route exact path="/register" component={Auth(RegisterPage, false)} />
<Route exact path="/upload" component={Auth(UploadPage, true)} />
<Route exact path="/product/upload" component={Auth(UploadProductPage, true)} />
<Route exact path="/product/:productId" component={Auth(DetailProductPage, null)} />
<Route exact path="/user/cart" component={Auth(CartPage, true)} />
<Route exact path="/history" component={Auth(HistoryPage, true)} />
<Route exact path="/admin" component={Auth(adminPage, true)} />
</Switch>
</div>
<Footer />
......
#test {
width: 300px;
height: 200px;
border: 1px solid lightgray;
border-radius: 1em;
display: flex;
position: relative;
}
#alert {
width: 300px;
height: 200px;
border: 1px solid lightgray;
border-radius: 1em;
display: flex;
justify-content: center;
align-items: center;
}
#test:hover {
animation: del 0.2s forwards;
}
@keyframes del {
to {
filter: brightness(50%);
}
}
#alert {
position: relative;
bottom: 200px;
opacity: 0;
}
#alert:hover {
background-color: black;
color: white;
animation: fadeInUP 1s forwards;
}
@keyframes fadeInUP {
to {
opacity: 0.5;
}
}
import React, { useState } from "react";
import Dropzone from "react-dropzone";
import { Icon } from "antd";
import Axios from "axios";
import "./FileUpload.css";
function FileUpload(props) {
const [Images, setImages] = useState([]);
const onDrop = files => {
let formData = new FormData();
const config = {
header: { "content-type": "multipart/form-data" },
};
formData.append("file", files[0]);
Axios.post("/api/product/uploadImage", formData, config).then(response => {
if (response.data.success) {
setImages([...Images, response.data.image]);
props.refreshFunction([...Images, response.data.image]);
} else {
alert("Failed to save the Image in Server");
}
});
};
const onDelete = image => {
const currentIndex = Images.indexOf(image);
let newImages = [...Images];
newImages.splice(currentIndex, 1);
setImages(newImages);
props.refreshFunction(newImages);
};
return (
<div style={{ display: "flex", justifyContent: "space-between" }}>
<Dropzone onDrop={onDrop} multiple={false} maxSize={800000000}>
{({ getRootProps, getInputProps }) => (
<div
style={{
width: "300px",
height: "240px",
border: "1px solid lightgray",
borderRadius: '15px',
display: "flex",
alignItems: "center",
justifyContent: "center",
}}
{...getRootProps()}
>
{console.log("getRootProps", { ...getRootProps() })}
{console.log("getInputProps", { ...getInputProps() })}
<input {...getInputProps()} />
<Icon type="plus" style={{ fontSize: "3rem" }} />
</div>
)}
</Dropzone>
<div style={{ display: "flex", width: "350px", height: "240px", overflowX: "scroll" }}>
{Images.map((image, index) => (
<div onClick={() => onDelete(image)}>
<img id="test" src={`http://localhost:5000/${image}`} />
<div id="alert">클릭하면 삭제돼요!</div>
</div>
))}
</div>
</div>
);
}
export default FileUpload;
import React from "react";
import { Carousel } from "antd";
function ImageSlider(props) {
return (
<div>
<Carousel autoplay>
{props.images.map((image, index) => (
<div key={index}>
<img style={{ width: "100%", maxWidth: "300px", height: "300px" }} src={`http://localhost:5000/${image}`} alt="productImage" />
</div>
))}
</Carousel>
</div>
);
}
export default ImageSlider;
#test {
width: 300px;
height: 200px;
border: 1px solid rgb(155, 155, 155);
border-radius: 1em;
display: flex;
position: relative;
}
#alert {
width: 300px;
height: 200px;
border: 1px solid rgb(155, 155, 155);
border-radius: 1em;
display: flex;
justify-content: center;
align-items: center;
}
#test:hover {
animation: del 0.7s forwards;
}
@keyframes del {
to {
filter: brightness(50%);
}
}
#alert {
position: relative;
bottom: 200px;
opacity: 0;
}
#alert:hover {
background-color: black;
color: white;
animation: fadeInUP 0.2s forwards;
}
@keyframes fadeInUP {
to {
opacity: 0.5;
}
}
......@@ -2,6 +2,7 @@ import React from 'react'
import Dropzone from 'react-dropzone'
import axios from 'axios';
import { useState } from 'react';
import './ImageUpload.css'
function ImageUpload(props) {
......@@ -51,13 +52,14 @@ function ImageUpload(props) {
<Dropzone onDrop={imageDropEvent}>
{({getRootProps, getInputProps}) => (
<section>
{/* Dropzone */}
<div style={{
width: 300, height: 200, border: '1px solid lightgray', borderRadius: '1em', display: 'flex',
alignItems: 'center', textAlign: 'center', justifyContent: 'center'
}}
{...getRootProps()}>
<input {...getInputProps()} />
<p>이곳을 클릭하여 <br/> 상품 사진을 업로드 해주세요.</p>
<p>이곳을 클릭하여<br/>상품 사진을 업로드 해주세요.</p>
</div>
</section>
)}
......@@ -72,11 +74,10 @@ function ImageUpload(props) {
{Images.map((image, index) => (
<div onClick={ () => deleteEvent(image) }
key={index}>
<img style={{
width: '300px', height: '200px', border: '1px solid lightgray',
borderRadius: '1em', display: 'flex'}}
src={`http://localhost:5000/${image}`} />
key={index}>
<img id="test" src={`http://localhost:5000/${image}`} />
<div id="alert">클릭하면 삭제돼요!</div>
</div>
))}
</div>
......
import React from 'react';
import PaypalExpressBtn from 'react-paypal-express-checkout';
export default class Paypal extends React.Component {
render() {
const onSuccess = (payment) => {
// Congratulation, it came here means everything's fine!
console.log("The payment was succeeded!", payment);
// You can bind the "payment" object's value to your state or props or whatever here, please see below for sample returned data
this.props.onSuccess(payment);
}
const onCancel = (data) => {
// User pressed "cancel" or close Paypal's popup!
console.log('The payment was cancelled!', data);
// You can bind the "data" object's value to your state or props or whatever here, please see below for sample returned data
}
const onError = (err) => {
// The main Paypal's script cannot be loaded or somethings block the loading of that script!
console.log("Error!", err);
// Because the Paypal's main script is loaded asynchronously from "https://www.paypalobjects.com/api/checkout.js"
// => sometimes it may take about 0.5 second for everything to get set, or for the button to appear
}
let env = 'sandbox'; // you can set here to 'production' for production
let currency = 'USD'; // or you can set this value from your props or state
let total = this.props.toPay; // same as above, this is the total amount (based on currency) to be paid by using Paypal express checkout
// Document on Paypal's currency code: https://developer.paypal.com/docs/classic/api/currency_codes/
const client = {
sandbox: 'ASbCsyjZeUzpNCkVbbqseQzcXivFRRoyPfpJK24688vFvIchTR-CCK79Ao5FB6zgqIO2r5Xw-a4Xh-44',
production: 'YOUR-PRODUCTION-APP-ID',
}
// In order to get production's app-ID, you will have to send your app to Paypal for approval first
// For sandbox app-ID (after logging into your developer account, please locate the "REST API apps" section, click "Create App"):
// => https://developer.paypal.com/docs/classic/lifecycle/sb_credentials/
// For production app-ID:
// => https://developer.paypal.com/docs/classic/lifecycle/goingLive/
// NB. You can also have many Paypal express checkout buttons on page, just pass in the correct amount and they will work!
return (
<PaypalExpressBtn
env={env}
client={client}
currency={currency}
total={total}
onError={onError}
onSuccess={onSuccess}
onCancel={onCancel}
style={{
size:'large',
color:'blue',
shape: 'rect',
label: 'checkout'
}}
/>
);
}
}
\ No newline at end of file
import React, { useEffect, useState } from "react";
import { useDispatch } from "react-redux";
import { getCartItems, removeCartItem, onSuccessBuy } from "../../../_actions/user_actions";
import UserCardBlock from "./Sections/UserCardBlock";
import { Result, Empty } from "antd";
import Axios from "axios";
import Paypal from "../../utils/Paypal";
import { Container } from "react-bootstrap";
function CartPage(props) {
const dispatch = useDispatch();
const [Total, setTotal] = useState(0);
const [ShowTotal, setShowTotal] = useState(false);
const [ShowSuccess, setShowSuccess] = useState(false);
useEffect(() => {
let cartItems = [];
if (props.user.userData && props.user.userData.cart) {
if (props.user.userData.cart.length > 0) {
props.user.userData.cart.forEach(item => {
cartItems.push(item.id);
});
dispatch(getCartItems(cartItems, props.user.userData.cart)).then(response => {
if (response.payload.length > 0) {
calculateTotal(response.payload);
}
});
}
}
}, [props.user.userData]);
const calculateTotal = cartDetail => {
let total = 0;
cartDetail.map(item => {
total += parseInt(item.price, 10) * item.quantity;
});
setTotal(total);
setShowTotal(true);
};
const removeFromCart = productId => {
dispatch(removeCartItem(productId)).then(response => {
if (response.payload.cartDetail.length <= 0) {
setShowTotal(false);
} else {
calculateTotal(response.payload.cartDetail);
}
});
};
const transactionSuccess = data => {
dispatch(
onSuccessBuy({
cartDetail: props.user.cartDetail,
paymentData: data,
})
).then(response => {
if (response.payload.success) {
setShowSuccess(true);
setShowTotal(false);
}
});
};
const transactionError = () => {
console.log("Paypal error");
};
const transactionCanceled = () => {
console.log("Transaction canceled");
};
return (
<div style={{ width: "85%", margin: "3rem auto" }}>
<h1>장바구니</h1>
<div style={{ marginTop: "30px" }}>
<UserCardBlock products={props.user.cartDetail} removeItem={removeFromCart} />
{ShowTotal ? (
<div style={{ marginTop: "3rem", textAlign: "right" }}>
<h2> 금액: ${Total} </h2>
</div>
) : ShowSuccess ? (
<Result status="success" title="Successfully Purchased Items" />
) : (
<div
style={{
width: "100%",
display: "flex",
flexDirection: "column",
justifyContent: "center",
}}
>
<br />
<Empty description={false} />
<p>장바구니가 비었습니다.</p>
</div>
)}
</div>
{ShowTotal && (
<Container style={{ width: "max-content", marginTop: "100px" }}>
<Paypal sty toPay={Total} onSuccess={transactionSuccess} transactionError={transactionError} transactionCanceled={transactionCanceled} />
</Container>
)}
</div>
);
}
export default CartPage;
import React from "react";
function UserCardBlock(props) {
const renderCartImage = images => {
if (images.length > 0) {
let image = images[0];
return `http://localhost:5000/${image}`;
}
};
const renderItems = () =>
props.products &&
props.products.map(product => (
<tr key={product._id} style={{ margin: "auto", backgroundColor: "white" }}>
<td style={{ margin: "auto", textAlign: "center" }}>
<img style={{ width: "70px" }} alt="product" src={renderCartImage(product.images)} />
</td>
<td style={{ margin: "auto", textAlign: "center" }}>{product.title}</td>
<td style={{ margin: "auto", textAlign: "center" }}>{product.quantity} EA</td>
<td style={{ margin: "auto", textAlign: "center" }}>$ {product.price} </td>
<td style={{ margin: "auto", textAlign: "center" }}>
<button onClick={() => props.removeItem(product._id)}></button>
</td>
</tr>
));
return (
<div>
<table>
<thead>
<tr style={{ textAlign: "center" }}>
<th>상품 이미지</th>
<th>상품명</th>
<th>개수</th>
<th>가격</th>
<th>장바구니에서 삭제하기</th>
</tr>
</thead>
<tbody>{renderItems()}</tbody>
</table>
</div>
);
}
export default UserCardBlock;
import React, { useEffect, useState } from 'react'
import Axios from 'axios'
import { Row, Col } from 'antd';
import ProductImage from './Sections/ProductImage';
import ProductInfo from './Sections/ProductInfo';
import { addToCart } from '../../../_actions/user_actions';
import { useDispatch } from 'react-redux';
function DetailProductPage(props) {
const dispatch = useDispatch();
const productId = props.match.params.productId
const [Product, setProduct] = useState([])
useEffect(() => {
Axios.get(`/api/product/products_by_id?id=${productId}&type=single`)
.then(response => {
setProduct(response.data[0])
})
}, [])
const addToCartHandler = (productId) => {
dispatch(addToCart(productId))
}
return (
<div className="postPage" style={{ width: '100%', padding: '3rem 4rem' }}>
<div style={{ display: 'flex', justifyContent: 'center' }}>
<h1>{Product.title}</h1>
</div>
<br />
<Row gutter={[16, 16]} >
<Col lg={12} xs={24}>
<ProductImage detail={Product} style={{width :"300px"}} />
</Col>
<Col lg={12} xs={24}>
<ProductInfo
addToCart={addToCartHandler}
detail={Product} />
</Col>
</Row>
</div>
)
}
export default DetailProductPage
import React, { useEffect, useState } from 'react'
import ImageGallery from 'react-image-gallery';
function ProductImage(props) {
const [Images, setImages] = useState([])
useEffect(() => {
if (props.detail.images && props.detail.images.length > 0) {
let images = [];
props.detail.images && props.detail.images.map(item => {
images.push({
original: `http://localhost:5000/${item}`,
thumbnail: `http://localhost:5000/${item}`
})
})
setImages(images)
}
}, [props.detail])
return (
<div>
<ImageGallery showFullscreenButton={false} showPlayButton={false} items={Images} />
</div>
)
}
export default ProductImage
import React, { useEffect, useState } from "react";
import { Button, Descriptions } from "antd";
import { Container } from "react-bootstrap";
function ProductInfo(props) {
const [Product, setProduct] = useState({});
useEffect(() => {
setProduct(props.detail);
}, [props.detail]);
const addToCarthandler = () => {
props.addToCart(props.detail._id);
};
return (
<Container style={{ paddingTop: "100px" }}>
<Container style={{ textAlign: "center" }}>
{/* <h7>{Product.description}</h7><br/> */}
<h3>가격 : {Product.price}000 </h3>
</Container>
<br />
<br />
<div style={{ display: "flex", justifyContent: "center" }}>
<Button size="large" shape="round" type="danger" onClick={addToCarthandler}>
<a href="/user/cart">
장바구니에 담기
</a>
</Button>
</div>
</Container>
);
}
export default ProductInfo;
import React from 'react'
import axios from 'axios'
import {useEffect, useState} from 'react'
import ProductImage from './Sections/ProductImage'
import ProductInfo from './Sections/ProductInfo'
import { Row, Col } from 'antd';
function DetailProductPages(props) {
const [Product, setProduct] = useState({})
const productId = props.match.params.prouductID
//console.log(props.match.params.prouductID) //->정상적으로 출력
useEffect(() => {
axios.get(`/api/product/products_by_id?id=${productId}&type=single`)
.then(response => {
if (response.data.success) {
console.log(response.data)
setProduct(response.data.goods[0]);
}
else {
alert('Fail.');
}
})
},[])
return (
<div style={{width:'100%', padding:'3rem 4rem'}}>
<div style={{ display: 'flex', justifyContent: 'center' }}>
<h1>{Product.title}</h1>
</div>
<br />
<Row gutter={[16, 16]}>
<Col lg={12} sm={24}>
<ProductImage detail={Product} />
</Col>
<Col lg={12} sm={24}>
<ProductImage />
</Col>
</Row>
{/* image */}
{/* info */}
<ProductInfo />
</div>
)
}
export default DetailProductPages
import React from 'react'
import ImageGallery from 'react-image-gallery'
import { useEffect, useState } from 'react'
function ProductImage(props) {
const [Images, setImages] = useState([])
useEffect(() => {
console.log('now ::::::: ', props.goods)
let images = []
if (props.goods.images && props.goods.images.length > 0) {
props.goods.images.map(item => {
images.push({
original: `http://localhost:5000/${item}`,
thumbnail: `http://localhost:5000/${item}`
})
})
setImages(images)
}
}, [props.goods])
return (
<div>
<ImageGallery items={Images} />
</div>
)
// return (
// <div>
// ..
// </div>
// )
}
export default ProductImage
import React from 'react'
function ProductInfo() {
return (
<div>
info
</div>
)
}
export default ProductInfo
import React from 'react'
import {Icon} from 'antd';
import React from "react";
import { Icon } from "antd";
function Footer() {
return (
<div style={{
height: '80px', display: 'flex',
flexDirection: 'column', alignItems: 'center',
justifyContent: 'center', fontSize:'1rem'
}}>
<p> 2018110650 박민정</p>
</div>
)
return (
<div
style={{
height: "80px",
display: "flex",
flexDirection: "column",
alignItems: "center",
justifyContent: "center",
fontSize: "1rem",
}}
>
<p> Copyright © 2021 Minjeong Park All rights reserved</p>
</div>
);
}
export default Footer
export default Footer;
......
import React from "react";
function HistoryPage(props) {
return (
<div style={{ width: "80%", margin: "3rem auto" }}>
<div style={{ textAlign: "center" }}>
<h1>구매내역</h1>
</div>
<br />
<table>
<thead>
<tr>
<th style={{ textAlign: "center" }}>구매 ID</th>
<th style={{ textAlign: "center" }}>가격</th>
<th style={{ textAlign: "center" }}>수량</th>
<th style={{ textAlign: "center" }}>구매 날짜</th>
</tr>
</thead>
<tbody>
{props.user.userData &&
props.user.userData.history &&
props.user.userData.history.map(item => (
<tr key={item.id}>
<td style={{ textAlign: "center", margin: "auto" }}>{item.id}</td>
<td style={{ textAlign: "center", margin: "auto" }}>{item.price}</td>
<td style={{ textAlign: "center", margin: "auto" }}>{item.quantity}</td>
<td style={{ textAlign: "center", margin: "auto" }}>{item.dateOfPurchase}</td>
</tr>
))}
</tbody>
</table>
</div>
);
}
export default HistoryPage;
import React from 'react'
import { FaCode } from "react-icons/fa";
import React, { useEffect, useState } from "react";
import Axios from "axios";
import { Icon, Col, Card, Row } from "antd";
import ImageSlider from "../../utils/ImageSlider";
import CheckBox from "./Sections/CheckBox";
import { medicines, price } from "./Sections/Datas";
import SearchFeature from "./Sections/SearchFeature";
import { Container } from "react-bootstrap";
const { Meta } = Card;
function LandingPage() {
const [Products, setProducts] = useState([]);
const [Skip, setSkip] = useState(0);
const [Limit, setLimit] = useState(8);
const [PostSize, setPostSize] = useState();
const [SearchTerms, setSearchTerms] = useState("");
const [Filters, setFilters] = useState({
medicines: [],
price: [],
});
useEffect(() => {
const variables = {
skip: Skip,
limit: Limit,
};
getProducts(variables);
}, []);
const getProducts = variables => {
Axios.post("/api/product/getProducts", variables).then(response => {
if (response.data.success) {
if (variables.loadMore) {
setProducts([...Products, ...response.data.products]);
} else {
setProducts(response.data.products);
}
setPostSize(response.data.postSize);
} else {
alert("실패하였습니다.");
}
});
};
const onLoadMore = () => {
let skip = Skip + Limit;
const variables = {
skip: skip,
limit: Limit,
loadMore: true,
filters: Filters,
searchTerm: SearchTerms,
};
getProducts(variables);
setSkip(skip);
};
const renderCards = Products.map((product, index) => {
return (
<>
<div className="app">
..
</div>
</>
)
<Col style={{ marginTop: "30px" }} lg={6} md={8} xs={24}>
<Card
style={{ margin: "5px" }}
hoverable={true}
cover={
<a href={`/product/${product._id}`}>
<ImageSlider images={product.images} />
</a>
}
>
<Meta title={product.title} description={`${product.price}000원`} />
</Card>
</Col>
);
});
const showFilteredResults = filters => {
const variables = {
skip: 0,
limit: Limit,
filters: filters,
};
getProducts(variables);
setSkip(0);
};
const handlePrice = value => {
const data = price;
let array = [];
for (let key in data) {
if (data[key]._id === parseInt(value, 10)) {
array = data[key].array;
}
}
console.log("array", array);
return array;
};
const handleFilters = (filters, category) => {
const newFilters = { ...Filters };
newFilters[category] = filters;
if (category === "price") {
let priceValues = handlePrice(filters);
newFilters[category] = priceValues;
}
console.log(newFilters);
showFilteredResults(newFilters);
setFilters(newFilters);
};
const updateSearchTerms = newSearchTerm => {
const variables = {
skip: 0,
limit: Limit,
filters: Filters,
searchTerm: newSearchTerm,
};
setSkip(0);
setSearchTerms(newSearchTerm);
getProducts(variables);
};
return (
<div style={{ width: "75%", margin: "3rem auto" }}>
<div style={{ textAlign: "center" }}>
<img src={"/whatmedicine.png"} style={{ width: "500px" }} />
{/* <h2>
{" "}
<Icon type="alert" />
&nbsp; 어떤 약이 필요하신가요?&nbsp;<Icon type="alert" />{" "}
</h2> */}
</div>
<Container style={{ width: "50%" }}>
<CheckBox list={medicines} handleFilters={filters => handleFilters(filters, "medicines")} />
</Container>
{/* Search */}
{Products.length === 0 ? (
<div style={{ display: "flex", height: "300px", justifyContent: "center", alignItems: "center" }}>
</div>
) : (
<div>
<Row gutter={[16, 16]}>{renderCards}</Row>
</div>
)}
<br />
<br />
{PostSize >= Limit && (
<div style={{ display: "flex", justifyContent: "center" }}>
<button onClick={onLoadMore}>Load More</button>
</div>
)}
</div>
);
}
export default LandingPage
export default LandingPage;
......
import React, { useState } from 'react'
import { Checkbox, Collapse } from 'antd';
const { Panel } = Collapse
function CheckBox(props) {
const [Checked, setChecked] = useState([])
const handleToggle = (value) => {
const currentIndex = Checked.indexOf(value);
const newChecked = [...Checked];
if (currentIndex === -1) {
newChecked.push(value)
} else {
newChecked.splice(currentIndex, 1)
}
setChecked(newChecked)
props.handleFilters(newChecked)
}
const renderCheckboxLists = () => props.list && props.list.map((value, index) => (
<React.Fragment key={index}>
<Checkbox
onChange={() => handleToggle(value._id)}
type="checkbox"
checked={Checked.indexOf(value._id) === -1 ? false : true}
/>&nbsp;&nbsp;
<span>{value.name}</span>
</React.Fragment>
))
return (
<div>
<Collapse defaultActiveKey={['0']} >
<Panel header="약 종류" key="1">
{renderCheckboxLists()}
</Panel>
</Collapse>
</div>
)
}
export default CheckBox
\ No newline at end of file
const symtoms = [
{
"_id": 0,
"name": "전체"
},
{
"_id": 1,
"name": "진통제"
},
{
"_id": 2,
"name": "소화제"
},
{
"_id": 3,
"name": "감기약"
},
{
"_id": 4,
"name": "해열제"
},
{
"_id": 5,
"name": "파스류"
},
{
"_id": 6,
"name": "상처치료"
},
{
"_id": 7,
"name": "기타"
}
]
export {
symtoms
}
\ No newline at end of file
const medicines = [
{ _id: 0, name: "전체" },
{
_id: 1,
name: "진통제",
},
{
_id: 2,
name: "소화제",
},
{
_id: 3,
name: "감기약",
},
{
_id: 4,
name: "해열제",
},
{
_id: 5,
name: "파스류",
},
{
_id: 6,
name: "상처치료",
},
{
_id: 7,
name: "기타",
},
];
const price = [
{
_id: 0,
name: "Any",
array: [],
},
{
_id: 1,
name: "배달비 무료",
array: [0],
},
{
_id: 2,
name: "배달비 500원 ~ 1000원",
array: [500, 1000],
},
{
_id: 3,
name: "배달비 1000원 ~ 2000원",
array: [1001, 2000],
},
{
_id: 4,
name: "배달비 200원 ~ 3000원",
array: [2001, 3000],
},
{
_id: 5,
name: "3000원 이상",
array: [3000, 1500000],
},
];
export { price, medicines };
import React from 'react'
function RadioBox() {
return (
<div>
</div>
)
}
export default RadioBox
import React, { useState } from "react";
import { Input } from "antd";
const { Search } = Input;
function SearchFeature(props) {
const [SearchTerms, setSearchTerms] = useState("");
const onChangeSearch = event => {
setSearchTerms(event.currentTarget.value);
props.refreshFunction(event.currentTarget.value);
};
return (
<div style={{ margin: "auto" }}>
<Search value={SearchTerms} onChange={onChangeSearch} placeholder="상품명" />
</div>
);
}
export default SearchFeature;
import React, { useState } from "react";
import { withRouter } from "react-router-dom";
import { loginUser } from "../../../_actions/user_actions";
import { Formik } from 'formik';
import * as Yup from 'yup';
import { Form, Icon, Input, Button, Checkbox, Typography } from 'antd';
import { Formik } from "formik";
import * as Yup from "yup";
import { Form, Icon, Input, Button, Checkbox, Typography } from "antd";
import { useDispatch } from "react-redux";
const { Title } = Typography;
function LoginPage(props) {
const dispatch = useDispatch();
//const rememberMeChecked = localStorage.getItem("rememberMe") ? true : false;
const rememberMeChecked = localStorage.getItem("rememberMe") ? true : false;
const [Error, setError] = useState('')
//const [rememberMe, setRememberMe] = useState(rememberMeChecked)
const [formErrorMessage, setFormErrorMessage] = useState("");
const [rememberMe, setRememberMe] = useState(rememberMeChecked);
// const handleRememberMe = () => {
// setRememberMe(!rememberMe)
// };
const handleRememberMe = () => {
setRememberMe(!rememberMe);
};
//const initialEmail = localStorage.getItem("rememberMe") ? localStorage.getItem("rememberMe") : '';
return (
<Formik
initialValues={{
email: '',
password: '',
email: "",
password: "",
}}
// validationSchema={Yup.object().shape({
// email: Yup.string()
// .email('Email is invalid')
// .required('Email is required'),
// password: Yup.string()
// .min(6, 'Password must be at least 6 characters')
// .required('Password is required'),
// })}
validationSchema={Yup.object().shape({
email: Yup.string().email("이메일이 유효하지 않습니다.").required("이메일을 입력해주세요."),
password: Yup.string().min(5, "비밀번호가 너무 짧습니다.").required("비밀번호를 입력해주세요."),
})}
onSubmit={(values, { setSubmitting }) => {
setTimeout(() => {
let dataToSubmit = {
email: values.email,
password: values.password
password: values.password,
};
dispatch(loginUser(dataToSubmit))
.then(response => {
if (response.payload.loginSuccess) {
window.localStorage.setItem('userId', response.payload.userId);
// if (rememberMe === true) {
// window.localStorage.setItem('rememberMe', values.id);
// } else {
// localStorage.removeItem('rememberMe');
// }
window.localStorage.setItem("userId", response.payload.userId);
if (rememberMe === true) {
window.localStorage.setItem("rememberMe", values.id);
} else {
localStorage.removeItem("rememberMe");
}
props.history.push("/");
} else {
setError('이메일 또는 비밀번호가 올바르지 않습니다.')
setFormErrorMessage("Check out your Account or Password again");
}
})
.catch(err => {
setError('이메일 또는 비밀번호가 올바르지 않습니다.')
setFormErrorMessage("Check out your Account or Password again");
setTimeout(() => {
setError("")
setFormErrorMessage("");
}, 3000);
});
setSubmitting(false);
......@@ -67,74 +62,51 @@ function LoginPage(props) {
}}
>
{props => {
const {
values,
touched,
errors,
dirty,
isSubmitting,
handleChange,
handleBlur,
handleSubmit,
handleReset,
} = props;
const { values, touched, errors, dirty, isSubmitting, handleChange, handleBlur, handleSubmit, handleReset } = props;
return (
<div className="app">
<Title level={2}>로그인</Title>
<form onSubmit={handleSubmit} style={{ width: '350px' }}>
<form onSubmit={handleSubmit} style={{ width: "350px" }}>
<Form.Item required>
<Input
id="email"
prefix={<Icon type="user" style={{ color: 'rgba(0,0,0,.25)' }} />}
prefix={<Icon type="user" style={{ color: "rgba(0,0,0,.25)" }} />}
placeholder="Enter your email"
type="email"
value={values.email}
onChange={handleChange}
onBlur={handleBlur}
className={
errors.email && touched.email ? 'text-input error' : 'text-input'
}
className={errors.email && touched.email ? "text-input error" : "text-input"}
/>
{errors.email && touched.email && (
<div className="input-feedback">{errors.email}</div>
)}
{errors.email && touched.email && <div className="input-feedback">{errors.email}</div>}
</Form.Item>
<Form.Item required>
<Input
id="password"
prefix={<Icon type="lock" style={{ color: 'rgba(0,0,0,.25)' }} />}
prefix={<Icon type="lock" style={{ color: "rgba(0,0,0,.25)" }} />}
placeholder="Enter your password"
type="password"
value={values.password}
onChange={handleChange}
onBlur={handleBlur}
className={
errors.password && touched.password ? 'text-input error' : 'text-input'
}
className={errors.password && touched.password ? "text-input error" : "text-input"}
/>
{errors.password && touched.password && (
<div className="input-feedback">{errors.password}</div>
)}
{errors.password && touched.password && <div className="input-feedback">{errors.password}</div>}
</Form.Item>
{Error && (
<label ><p style={{ color: '#508DFF', fontSize: '0.8rem' }}>{Error}</p></label>
{formErrorMessage && (
<label>
<p style={{ color: "#ff0000bf", fontSize: "0.7rem", border: "1px solid", padding: "1rem", borderRadius: "10px" }}>{formErrorMessage}</p>
</label>
)}
<Form.Item>
{/* <Checkbox id="rememberMe" onChange={handleRememberMe} checked={rememberMe} >Remember me</Checkbox>
<a className="login-form-forgot" href="/reset_user" style={{ float: 'right' }}>
forgot password
</a> */}
<div>
<Button type="primary" htmlType="submit" className="login-form-button" style={{ minWidth: '100%' }} disabled={isSubmitting} onSubmit={handleSubmit}>
<Button type="primary" htmlType="submit" className="login-form-button" style={{ minWidth: "100%" }} disabled={isSubmitting} onSubmit={handleSubmit}>
로그인
</Button>
</Button>
</div>
<a href="/register" style={{ minWidth: '100%' }}>회원가입</a>
</Form.Item>
</form>
</div>
......@@ -142,8 +114,6 @@ function LoginPage(props) {
}}
</Formik>
);
};
}
export default withRouter(LoginPage);
......
import React, { useState } from 'react';
import LeftMenu from './Sections/LeftMenu';
import RightMenu from './Sections/RightMenu';
import { Drawer, Button, Icon } from 'antd';
import './Sections/Navbar.css';
import React, { useState } from "react";
import RightMenu from "./Sections/RightMenu";
import { Drawer, Button, Icon } from "antd";
import "./Sections/Navbar.css";
import { Container, Navbar, Nav } from "react-bootstrap";
function NavBar() {
const [visible, setVisible] = useState(false)
const [visible, setVisible] = useState(false);
const showDrawer = () => {
setVisible(true)
setVisible(true);
};
const onClose = () => {
setVisible(false)
setVisible(false);
};
return (
<nav className="menu" style={{ position: 'fixed', zIndex: 5, width: '100%' }}>
<div className="menu__logo">
<a href="/">Logo</a>
</div>
<div className="menu__container">
<div className="menu_left">
<LeftMenu mode="horizontal" />
</div>
<div className="menu_rigth">
<RightMenu mode="horizontal" />
</div>
<Button
className="menu__mobile-button"
type="primary"
onClick={showDrawer}
>
<Icon type="align-right" />
</Button>
<Drawer
title="Basic Drawer"
placement="right"
className="menu_drawer"
closable={false}
onClose={onClose}
visible={visible}
>
<LeftMenu mode="inline" />
<RightMenu mode="inline" />
</Drawer>
</div>
</nav>
)
<Navbar bg="white" variant="light" style={{ position: "fixed", zIndex: 5, width: "100%", border: "1px solid lightgray" }}>
<Container>
<Navbar.Brand href="/">
<img src={"/logo.png"} style={{ width: "120px", marginLeft:"50px"}} />
</Navbar.Brand>
<Nav className="mx-3" style={{ position: "relative", right: "0" }}>
<div className="menu__container">
<div className="menu_left"></div>
<div className="menu_rigth">
<RightMenu mode="horizontal" />
</div>
<Button className="menu__mobile-button" type="primary" onClick={showDrawer}>
<Icon type="align-right" />
</Button>
<Drawer title="Basic Drawer" placement="right" className="menu_drawer" closable={false} onClose={onClose} visible={visible}>
<RightMenu mode="inline" />
</Drawer>
</div>
</Nav>
</Container>
</Navbar>
);
}
export default NavBar
\ No newline at end of file
export default NavBar;
......
......@@ -50,7 +50,7 @@
padding: 6px;
margin-top: 8px;
display: none !important; /* use of important to overwrite ant-btn */
background: #3e91f7;
background: lightgray;
}
.menu_drawer .ant-drawer-body {
......
import React from 'react';
import { Menu } from 'antd';
import axios from 'axios';
import { USER_SERVER } from '../../../Config';
import { withRouter } from 'react-router-dom';
/* eslint-disable jsx-a11y/anchor-is-valid */
import React from "react";
import { Menu, Icon, Badge } from "antd";
import axios from "axios";
import { USER_SERVER } from "../../../Config";
import { withRouter } from "react-router-dom";
import { useSelector } from "react-redux";
function RightMenu(props) {
const user = useSelector(state => state.user)
const user = useSelector(state => state.user);
const logoutHandler = () => {
axios.get(`${USER_SERVER}/logout`).then(response => {
if (response.status === 200) {
props.history.push("/login");
} else {
alert('Log Out Failed')
alert("로그아웃에 실패했습니다.");
}
});
};
//console.log(user.userData);
//console.log(!user.userData.isAuth);
if (user.userData && !user.userData.isAuth) {
return (
<Menu mode={props.mode}>
<Menu style={{ paddingTop: "10px" }} mode={props.mode}>
<Menu.Item key="mail">
<a href="/login">로그인</a>
<a href="/login"><h6>로그인</h6></a>
</Menu.Item>
<Menu.Item key="app">
<a href="/register">회원가입</a>
<a href="/register"><h6>회원가입</h6></a>
</Menu.Item>
</Menu>
)
);
} else {
return (
<Menu mode={props.mode}>
<Menu mode={props.mode} style={{ paddingTop: "5px" }}>
<Menu.Item key="history">
<a href="/history">
<h6>구매내역</h6>
</a>
</Menu.Item>
<Menu.Item key="upload">
<a href="/upload">업로드</a>
<a href="/product/upload">
<h6>등록하기</h6>
</a>
</Menu.Item>
<Menu.Item key="cart" style={{ paddingBottom: -4 }}>
<a href="/user/cart" style={{ marginRight: -22, paddingbottom: "30px", color: "#667777" }}>
<Icon type="shopping-cart" style={{ fontSize: 30, marginBottom: 3 }} />
</a>
</Menu.Item>
<Menu.Item key="logout">
<a onClick={logoutHandler}>로그아웃</a>
<a onClick={logoutHandler}><h6>로그아웃</h6></a>
</Menu.Item>
</Menu>
)
);
}
}
export default withRouter(RightMenu);
......
import React from "react";
import moment from "moment";
import { Formik } from 'formik';
import * as Yup from 'yup';
import { Formik } from "formik";
import * as Yup from "yup";
import { registerUser } from "../../../_actions/user_actions";
import { useDispatch } from "react-redux";
import {
Form,
Input,
Button,
} from 'antd';
import { Form, Input, Button } from "antd";
const { TextArea } = Input;
const formItemLayout = {
labelCol: {
xs: { span: 24 },
......@@ -37,139 +33,121 @@ const tailFormItemLayout = {
function RegisterPage(props) {
const dispatch = useDispatch();
return (
<Formik
initialValues={{
email: '',
name: '',
password: '',
confirmPassword: ''
email: "",
name: "",
address: "",
password: "",
confirmPassword: "",
}}
validationSchema={Yup.object().shape({
name: Yup.string()
.required('이름이 올바르게 입력되지 않았습니다.'),
email: Yup.string()
.required('이메일이 올바르게 입력되지 않았습니다.'),
password: Yup.string()
.min(3, '비밀번호는 3자리 이상이어야 합니다.')
.required('비밀번호를 입력해주세요.'),
name: Yup.string().required("이름을 입력해주세요."),
email: Yup.string().email("이메일 형식이 올바르지 않습니다.").required("이메일을 입력해주세요."),
password: Yup.string().min(5, "비밀번호는 5자리 이상이어야 합니다.").required("비밀번호를 입력해주세요."),
confirmPassword: Yup.string()
.oneOf([Yup.ref('password'), null], '비밀번호를 다시 확인해주세요.')
.required('비밀번호 확인이 올바르게 입력되지 않았습니다.')
.oneOf([Yup.ref("password"), null], "비밀번호가 일치하지 않습니다.")
.required("비밀번호를 한번 더 입력해주세요."),
adress: Yup.string().required("주소를 입력해주세요."),
})}
onSubmit={(values, { setSubmitting }) => {
setTimeout(() => {
let dataToSubmit = {
email: values.email,
password: values.password,
name: values.name,
//image: `http://gravatar.com/avatar/${moment().unix()}?d=identicon`
adress: values.adress,
image: `http://gravatar.com/avatar/${moment().unix()}?d=identicon`,
};
dispatch(registerUser(dataToSubmit)).then(response => {
if (response.payload.success) {
props.history.push("/login");
} else {
alert(response.payload.err.errmsg)
alert(response.payload.err.errmsg);
}
})
});
setSubmitting(false);
}, 500);
}}
>
{props => {
const {
values,
touched,
errors,
dirty,
isSubmitting,
handleChange,
handleBlur,
handleSubmit,
handleReset,
} = props;
const { values, touched, errors, dirty, isSubmitting, handleChange, handleBlur, handleSubmit, handleReset } = props;
return (
<div className="app">
<h2>회원가입</h2>
<Form style={{ minWidth: '375px' }} {...formItemLayout} onSubmit={handleSubmit} >
<Form.Item required label="Name">
<h3>회원가입</h3>
<Form style={{ minWidth: "375px" }} {...formItemLayout} onSubmit={handleSubmit}>
<Form.Item required label="이름">
<Input
id="name"
placeholder="이름을 입력하세요."
placeholder="이름을 입력하세요"
type="text"
value={values.name}
onChange={handleChange}
onBlur={handleBlur}
className={
errors.name && touched.name ? 'text-input error' : 'text-input'
}
className={errors.name && touched.name ? "text-input error" : "text-input"}
/>
{errors.name && touched.name && (
<div className="input-feedback">{errors.name}</div>
)}
</Form.Item>
{errors.name && touched.name && <div className="input-feedback">{errors.name}</div>}
</Form.Item>
<Form.Item required label="Email" hasFeedback>
<Form.Item required label="이메일">
<Input
id="email"
placeholder="이메일을 입력세요."
placeholder="이메일을 입력해주세요."
type="email"
value={values.email}
onChange={handleChange}
onBlur={handleBlur}
className={
errors.email && touched.email ? 'text-input error' : 'text-input'
}
className={errors.email && touched.email ? "text-input error" : "text-input"}
/>
{errors.email && touched.email && (
<div className="input-feedback">{errors.email}</div>
)}
{errors.email && touched.email && <div className="input-feedback">{errors.email}</div>}
</Form.Item>
<Form.Item required label="Password" hasFeedback>
<Form.Item required label="비밀번호">
<Input
id="password"
placeholder="비밀번호를 입력세요."
placeholder="비밀번호를 입력해주세요."
type="password"
value={values.password}
onChange={handleChange}
onBlur={handleBlur}
className={
errors.password && touched.password ? 'text-input error' : 'text-input'
}
className={errors.password && touched.password ? "text-input error" : "text-input"}
/>
{errors.password && touched.password && (
<div className="input-feedback">{errors.password}</div>
)}
{errors.password && touched.password && <div className="input-feedback">{errors.password}</div>}
</Form.Item>
<Form.Item required label="Confirm" hasFeedback>
<Form.Item required label="비밀번호 확인">
<Input
id="confirmPassword"
placeholder="비밀번호를 다시 한 번 입력해주세요."
placeholder="비밀번호를 한번 더 입력해주세요."
type="password"
value={values.confirmPassword}
onChange={handleChange}
onBlur={handleBlur}
className={
errors.confirmPassword && touched.confirmPassword ? 'text-input error' : 'text-input'
}
className={errors.confirmPassword && touched.confirmPassword ? "text-input error" : "text-input"}
/>
{errors.confirmPassword && touched.confirmPassword && <div className="input-feedback">{errors.confirmPassword}</div>}
</Form.Item>
<Form.Item required label="주소">
<TextArea
id="adress"
placeholder="주소를 입력하세요"
type="text"
value={values.adress}
onChange={handleChange}
onBlur={handleBlur}
className={errors.adress && touched.adress ? "text-input error" : "text-input"}
/>
{errors.confirmPassword && touched.confirmPassword && (
<div className="input-feedback">{errors.confirmPassword}</div>
)}
{errors.adress && touched.adress && <div className="input-feedback">{errors.adress}</div>}
</Form.Item>
<Form.Item {...tailFormItemLayout}>
<Button onClick={handleSubmit} type="primary" disabled={isSubmitting}>
Submit
가입
</Button>
</Form.Item>
</Form>
......@@ -178,7 +156,6 @@ function RegisterPage(props) {
}}
</Formik>
);
};
}
export default RegisterPage
export default RegisterPage;
......
......@@ -2,16 +2,21 @@ import React from 'react';
import { useState } from 'react';
import { Typography, Button, Form, Input } from 'antd'; // css
import ImageUpload from '../../utils/ImageUpload'
import Axios from 'axios';
const { TextArea } = Input; // 박스크기 조절을 사용자가 임의로 가능하게 함.
// Select Options
const options = [{ key: 1, value: "a" },
{ key: 2, value: "b" },
{key: 3, value : "c"}
// Select symtoms
const symtoms = [{ key: 1, value: "진통제" },
{ key: 2, value: "소화제" },
{ key: 3, value: "감기약" },
{ key: 4, value: "해열제" },
{ key: 5, value: "파스류" },
{ key: 6, value: "상처치료" },
{ key: 7, value: "기타" }
]
function UploadPage() {
function UploadPage(props) {
// OnChange Function
......@@ -47,6 +52,35 @@ function UploadPage() {
setImage(newImages);
}
const submitEvent = (event) => {
event.preventDefault(); // 확인버튼을 누를 때 리프레시 되지 않도록
if (!Title || !Info || !Cost || !Option || !Image) {
return alert("모두 입력해주세요.")
}
// 서버에 보낼 값들
const body = {
seller: props.user.userData._id,
title: Title,
info: Info,
price: Cost,
images: Image,
symtoms: Option
}
Axios.post("/api/product", body)
.then(response => {
if (response.data.success) {
alert("업로드가 완료되었습니다.");
props.history.push('/'); // 상품 업로드가 성공하면 메인페이지로 돌아감.
}
else {
alert("업로드에 실패했습니다.")
}
})
}
return (
<div style={{ maxWidth: '700px', margin: '2rem auto' }}>
......@@ -56,7 +90,7 @@ function UploadPage() {
</div>
<Form>
<Form onSubmit={submitEvent}>
{/* 파일업로드 부분은 코드가 길어서 따로 컴포넌트로 만들어버리기~! */}
<ImageUpload refreshFunction={updateImages}/>
<br />
......@@ -75,14 +109,14 @@ function UploadPage() {
<br />
<br />
<select onChange={optionEvent} value={ Option}>
{options.map(item => (
{symtoms.map(item => (
<option key={item.key} value={item.key}>{ item.value}</option>
))}
<option></option>
</select>
<br />
<br />
<Button>확인</Button>
<Button onClick={submitEvent}>확인</Button>
</Form>
......@@ -90,4 +124,4 @@ function UploadPage() {
)
}
export default UploadPage
export default UploadPage;
......
import React, { useState } from "react";
import {Button, Form, message, Input, Icon } from "antd";
import FileUpload from "../../utils/FileUpload";
import Axios from "axios";
const { TextArea } = Input;
const Medicines = [
{ key: 1, value: "진통제" },
{ key: 2, value: "소화제" },
{ key: 3, value: "감기약" },
{ key: 4, value: "해열제" },
{ key: 5, value: "파스류" },
{ key: 6, value: "상처치료" },
{ key: 7, value: "기타" }
];
function UploadProductPage(props) {
const [TitleValue, setTitleValue] = useState("");
const [DescriptionValue, setDescriptionValue] = useState("");
const [PriceValue, setPriceValue] = useState(0);
const [MedicinesValue, setMedicinesValue] = useState(1);
const [Images, setImages] = useState([]);
const onTitleChange = event => {
setTitleValue(event.currentTarget.value);
};
const onDescriptionChange = event => {
setDescriptionValue(event.currentTarget.value);
};
const onPriceChange = event => {
setPriceValue(event.currentTarget.value);
};
const onMedicinesSelectChange = event => {
setMedicinesValue(event.currentTarget.value);
};
const updateImages = newImages => {
setImages(newImages);
};
const onSubmit = event => {
event.preventDefault();
if (!TitleValue || !DescriptionValue || !PriceValue || !MedicinesValue || !Images) {
return alert("fill all the fields first!");
}
const variables = {
writer: props.user.userData._id,
title: TitleValue,
description: DescriptionValue,
price: PriceValue,
images: Images,
medicines: MedicinesValue,
};
Axios.post("/api/product/uploadProduct", variables).then(response => {
if (response.data.success) {
alert("Product Successfully Uploaded");
props.history.push("/");
} else {
alert("Failed to upload Product");
}
});
};
return (
<div style={{ maxWidth: "700px", margin: "2rem auto" }}>
<div style={{ textAlign: "center", marginBottom: "2rem" }}>
<h3> 등록하기</h3>
</div>
<Form onSubmit={onSubmit}>
{/* DropZone */}
<FileUpload refreshFunction={updateImages} />
<br />
<br />
<label> 이름</label>
<Input onChange={onTitleChange} value={TitleValue} />
<br />
<br />
<label>설명</label>
<TextArea onChange={onDescriptionChange} value={DescriptionValue} />
<br />
<br />
<label>가격($)</label>
<Input onChange={onPriceChange} value={PriceValue} type="number" />
<br />
<br />
<select onChange={onMedicinesSelectChange} value={MedicinesValue}>
{Medicines.map(item => (
<option key={item.key} value={item.key}>{item.value} </option>
))}
</select>
<br />
<br />
<Button onClick={onSubmit}>등록</Button>
</Form>
</div>
);
}
export default UploadProductPage;
import React, { Component } from 'react'
import { Typography, Button, Form, Input } from 'antd';
import axios from 'axios';
import FileUpload from '../../utils/FileUpload';
const { Title } = Typography;
const { TextArea } = Input;
const Medicines = [
{ key: 1, value: "진통제" },
{ key: 2, value: "소화제" },
{ key: 3, value: "감기약" },
{ key: 4, value: "해열제" },
{ key: 5, value: "파스류" },
{ key: 6, value: "상처치료" },
{ key: 7, value: "기타" }
]
export class UploadProductPage extends Component {
state = {
title: '',
description: '',
medicines: 1,
images: [],
price: 0
}
handleChangeTitle = (event) => {
this.setState({ title: event.currentTarget.value })
}
handleChangePrice = (event) => {
this.setState({ price: parseInt(event.currentTarget.value, 10) })
}
handleChangeDecsription = (event) => {
// console.log(event.currentTarget.value)
this.setState({ description: event.currentTarget.value })
}
handleChangeMedicines = (event) => {
this.setState({ medicines: event.currentTarget.value })
}
onSubmit = (event) => {
event.preventDefault();
if (this.props.user.userData && !this.props.user.userData.isAuth) {
return alert('!! 접근할 수 없습니다 !!')
}
if (!this.state.title || !this.state.description ||
!this.state.medicines || !this.state.images
|| !this.state.price) {
return alert('모든 항목을 채워주세요.')
}
const variables = {
writer: this.props.user.userData._id,
title: this.state.title,
description: this.state.description,
images: this.state.images,
medicines: this.state.medicines,
price: this.state.price
}
axios.post('/api/product/uploadProduct', variables)
.then(response => {
if (response.data.success) {
alert('성공적으로 업로드 했습니다.')
setTimeout(() => {
this.props.history.push('/')
}, 1000);
} else {
alert('업로드에 실패했습니다.')
}
})
}
updateFiles = (newImages) => {
this.setState({ images: newImages })
}
render() {
return (
<div style={{ maxWidth: '700px', margin: '2rem auto' }}>
<div style={{ textAlign: 'center', marginBottom: '2rem' }}>
<Title level={2} > 배달 서비스 : 약사</Title>
</div>
<Form onSubmit={this.onSubmit}>
<FileUpload refreshFunction={this.updateFiles} />
<br /><br />
<label>제품명</label>
<Input
onChange={this.handleChangeTitle}
value={this.state.title}
/>
<br /><br />
<label>설명</label>
<TextArea
onChange={this.handleChangeDecsription}
value={this.state.description}
/>
<br /><br />
<label>가격</label>
<Input
type="number"
onChange={this.handleChangePrice}
value={this.state.price}
/>
<br /><br />
<select onChange={this.handleChangeMedicines}>
{Medicines.map(item => (
<option key={item.key} value={item.key}>{item.value}</option>
))}
</select>
<br /><br />
<Button type="primary" size="large" onClick={this.onSubmit}>
Submit
</Button>
</Form>
</div>
)
}
}
export default UploadProductPage
import React from "react";
import axios from 'axios';
function adminPage(props) {
}
export default adminPage;
/* eslint-disable react-hooks/exhaustive-deps */
import React, { useEffect } from 'react';
import { auth } from '../_actions/user_actions';
import { useSelector, useDispatch } from "react-redux";
export default function (SpecificComponent, option, adminRoute = null) {
export default function (ComposedClass, reload, adminRoute = null) {
function AuthenticationCheck(props) {
let user = useSelector(state => state.user);
const dispatch = useDispatch();
useEffect(() => {
//To know my current status, send Auth request
dispatch(auth()).then(response => {
//Not Loggined in Status
if (!response.payload.isAuth) {
if (option) {
dispatch(auth()).then(async response => {
if (await !response.payload.isAuth) {
if (reload) {
props.history.push('/login')
}
//Loggined in Status
} else {
//supposed to be Admin page, but not admin person wants to go inside
if (adminRoute && !response.payload.isAdmin) {
props.history.push('/')
}
//Logged in Status, but Try to go into log in page
else {
if (option === false) {
if (reload === false) {
props.history.push('/')
}
}
}
})
}, [])
}, [dispatch, props.history, user.googleAuth])
return (
<SpecificComponent {...props} user={user} />
<ComposedClass {...props} user={user} />
)
}
return AuthenticationCheck
......
@import "~react-image-gallery/styles/css/image-gallery.css";
@font-face {
font-family: "BRBA_B";
src: url("https://cdn.jsdelivr.net/gh/projectnoonnu/noonfonts_seven@1.2/BRBA_B.woff")
format("woff");
font-weight: normal;
font-style: normal;
}
@font-face {
font-family: "InfinitySans-RegularA1";
src: url("https://cdn.jsdelivr.net/gh/projectnoonnu/noonfonts_20-04@2.1/InfinitySans-RegularA1.woff")
format("woff");
font-weight: normal;
font-style: normal;
}
@font-face {
font-family: "GongGothicMedium";
src: url("https://cdn.jsdelivr.net/gh/projectnoonnu/noonfonts_20-10@1.0/GongGothicMedium.woff")
format("woff");
font-weight: normal;
font-style: normal;
}
body {
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen",
......@@ -38,3 +63,28 @@ input.error {
height: 5px;
margin-top: -12px;
}
table {
font-family: arial, sans-serif;
border-collapse: collapse;
width: 100%;
}
td,
th {
border: 1px solid #dddddd;
text-align: left;
padding: 8px;
}
tr:nth-child(even) {
background-color: #dddddd;
}
h1 {
font-family: "GongGothicMedium";
}
h3 {
font-family: "InfinitySans-RegularA1";
}
......
import 'react-app-polyfill/ie9';
import 'react-app-polyfill/ie11';
import 'core-js';
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './components/App';
import * as serviceWorker from './serviceWorker';
import React from "react";
import ReactDOM from "react-dom";
import "./index.css";
import App from "./components/App";
import * as serviceWorker from "./serviceWorker";
import { BrowserRouter } from "react-router-dom";
import Reducer from './_reducers';
import { Provider } from 'react-redux';
import { createStore, applyMiddleware } from 'redux';
import promiseMiddleware from 'redux-promise';
import ReduxThunk from 'redux-thunk';
import Reducer from "./_reducers";
import { Provider } from "react-redux";
import { createStore, applyMiddleware } from "redux";
import promiseMiddleware from "redux-promise";
import ReduxThunk from "redux-thunk";
const createStoreWithMiddleware = applyMiddleware(promiseMiddleware, ReduxThunk)(createStore);
ReactDOM.render(
<Provider
store={createStoreWithMiddleware(
Reducer,
window.__REDUX_DEVTOOLS_EXTENSION__ &&
window.__REDUX_DEVTOOLS_EXTENSION__()
)}
>
<BrowserRouter>
<App />
</BrowserRouter>
</Provider>
, document.getElementById('root'));
<Provider store={createStoreWithMiddleware(Reducer, window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__())}>
<BrowserRouter>
<App />
</BrowserRouter>
</Provider>,
document.getElementById("root")
);
// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: https://bit.ly/CRA-PWA
......
This diff could not be displayed because it is too large.
......@@ -5,11 +5,11 @@
"requires": true,
"dependencies": {
"@babel/runtime": {
"version": "7.9.2",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.9.2.tgz",
"integrity": "sha512-NE2DtOdufG7R5vnfQUTehdTfNycfUANEtCa9PssN9O/xmTzP4E08UI797ixaei6hBEVL9BI/PsdJS5x7mWoB9Q==",
"version": "7.6.0",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.6.0.tgz",
"integrity": "sha512-89eSBLJsxNxOERC0Op4vd+0Bqm6wRMqMbFtV3i0/fbaWw/mJ8Q3eBvgX0G4SyrOOLCtbu98HspF8o09MRT+KzQ==",
"requires": {
"regenerator-runtime": "^0.13.4"
"regenerator-runtime": "^0.13.2"
}
},
"abbrev": {
......@@ -26,6 +26,11 @@
"negotiator": "0.6.2"
}
},
"after": {
"version": "0.8.2",
"resolved": "https://registry.npmjs.org/after/-/after-0.8.2.tgz",
"integrity": "sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8="
},
"ansi-align": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-2.0.0.tgz",
......@@ -151,24 +156,44 @@
"integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=",
"dev": true
},
"arraybuffer.slice": {
"version": "0.0.7",
"resolved": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz",
"integrity": "sha512-wGUIVQXuehL5TCqQun8OW81jGzAWycqzFF8lFp+GOM5BXLYj3bKNsYC4daB7n6XjCqxQA/qgTJ+8ANR3acjrog=="
},
"assign-symbols": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz",
"integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=",
"dev": true
},
"async": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/async/-/async-3.1.0.tgz",
"integrity": "sha512-4vx/aaY6j/j3Lw3fbCHNWP0pPaTCew3F6F3hYyl/tHs/ndmV1q7NW9T5yuJ2XAGwdQrP+6Wu20x06U4APo/iQQ=="
},
"async-each": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz",
"integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==",
"dev": true
},
"async-limiter": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz",
"integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ=="
},
"atob": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz",
"integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==",
"dev": true
},
"backo2": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz",
"integrity": "sha1-MasayLEpNjRj41s+u2n038+6eUc="
},
"balanced-match": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
......@@ -229,13 +254,31 @@
}
}
},
"base64-arraybuffer": {
"version": "0.1.5",
"resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz",
"integrity": "sha1-c5JncZI7Whl0etZmqlzUv5xunOg="
},
"base64id": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/base64id/-/base64id-1.0.0.tgz",
"integrity": "sha1-R2iMuZu2gE8OBtPnY7HDLlfY5rY="
},
"bcrypt": {
"version": "3.0.8",
"resolved": "https://registry.npmjs.org/bcrypt/-/bcrypt-3.0.8.tgz",
"integrity": "sha512-jKV6RvLhI36TQnPDvUFqBEnGX9c8dRRygKxCZu7E+MgLfKZbmmXL8a7/SFFOyHoPNX9nV81cKRC5tbQfvEQtpw==",
"version": "3.0.6",
"resolved": "https://registry.npmjs.org/bcrypt/-/bcrypt-3.0.6.tgz",
"integrity": "sha512-taA5bCTfXe7FUjKroKky9EXpdhkVvhE5owfxfLYodbrAR1Ul3juLmIQmIQBK4L9a5BuUcE6cqmwT+Da20lF9tg==",
"requires": {
"nan": "2.14.0",
"node-pre-gyp": "0.14.0"
"nan": "2.13.2",
"node-pre-gyp": "0.12.0"
}
},
"better-assert": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/better-assert/-/better-assert-1.0.2.tgz",
"integrity": "sha1-QIZrnhueC1W0gYlDEeaPr/rrxSI=",
"requires": {
"callsite": "1.0.0"
}
},
"binary-extensions": {
......@@ -244,24 +287,10 @@
"integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==",
"dev": true
},
"bindings": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz",
"integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==",
"dev": true,
"optional": true,
"requires": {
"file-uri-to-path": "1.0.0"
}
},
"bl": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/bl/-/bl-2.2.0.tgz",
"integrity": "sha512-wbgvOpqopSr7uq6fJrLH8EsvYMJf9gzfo2jCsL2eTy75qXPukA4pCgHamOQkZtY5vmfVtjB+P3LNlMHW5CEZXA==",
"requires": {
"readable-stream": "^2.3.5",
"safe-buffer": "^5.1.1"
}
"blob": {
"version": "0.0.5",
"resolved": "https://registry.npmjs.org/blob/-/blob-0.0.5.tgz",
"integrity": "sha512-gaqbzQPqOoamawKg0LGVd7SzLgXS+JH61oWprSLH+P+abTczqJbhTR8CmJ2u9/bUYNmHTGJx/UEmn6doAvvuig=="
},
"bluebird": {
"version": "3.5.1",
......@@ -393,9 +422,9 @@
}
},
"bson": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/bson/-/bson-1.1.4.tgz",
"integrity": "sha512-S/yKGU1syOMzO86+dGpg2qGoDL0zvzcb262G+gqEy6TgP6rt6z6qxSFX/8X6vLC91P7G7C3nLs0+bvDzmvBA3Q=="
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/bson/-/bson-1.1.1.tgz",
"integrity": "sha512-jCGVYLoYMHDkOsbwJZBCqwMHyH4c+wzgI9hG7Z6SZJRXWr+x58pdIbm2i9a/jFGCkRJqRUr8eoI7lDWa0hTkxg=="
},
"buffer-equal-constant-time": {
"version": "1.0.1",
......@@ -461,6 +490,11 @@
"unset-value": "^1.0.0"
}
},
"callsite": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz",
"integrity": "sha1-KAOY5dZkvXQDi28JBRU+borxvCA="
},
"camelcase": {
"version": "5.3.1",
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
......@@ -484,12 +518,6 @@
"supports-color": "^5.3.0"
},
"dependencies": {
"has-flag": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
"integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
"dev": true
},
"supports-color": {
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
......@@ -522,9 +550,9 @@
}
},
"chownr": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz",
"integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg=="
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.2.tgz",
"integrity": "sha512-GkfeAQh+QNy3wquu9oIZr6SS5x7wGdSgNQvD10X3r+AZr1Oys22HW8kAmDMvNg2+Dm0TeGaEuO8gFwdBXxwO8A=="
},
"ci-info": {
"version": "1.6.0",
......@@ -635,11 +663,20 @@
"integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
"dev": true
},
"component-bind": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/component-bind/-/component-bind-1.0.0.tgz",
"integrity": "sha1-AMYIq33Nk4l8AAllGx06jh5zu9E="
},
"component-emitter": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz",
"integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==",
"dev": true
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz",
"integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY="
},
"component-inherit": {
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/component-inherit/-/component-inherit-0.0.3.tgz",
"integrity": "sha1-ZF/ErfWLcrZJ1crmUTVhnbJv8UM="
},
"concat-map": {
"version": "0.0.1",
......@@ -672,23 +709,6 @@
"supports-color": "^4.5.0",
"tree-kill": "^1.2.1",
"yargs": "^12.0.5"
},
"dependencies": {
"has-flag": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz",
"integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=",
"dev": true
},
"supports-color": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.5.0.tgz",
"integrity": "sha1-vnoN5ITexcXN34s9WRJQRJEvY1s=",
"dev": true,
"requires": {
"has-flag": "^2.0.0"
}
}
}
},
"configstore": {
......@@ -724,16 +744,16 @@
"integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA=="
},
"cookie": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz",
"integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg=="
"version": "0.3.1",
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz",
"integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s="
},
"cookie-parser": {
"version": "1.4.5",
"resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.5.tgz",
"integrity": "sha512-f13bPUj/gG/5mDr+xLmSxxDsB9DQiTIfhJS/sqjrmfAWiAN+x2O4i/XguTL9yDZ+/IFDanJ+5x7hC4CXT9Tdzw==",
"version": "1.4.4",
"resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.4.tgz",
"integrity": "sha512-lo13tqF3JEtFO7FyA49CqbhaFkskRJ0u/UAiINgrIXeRCY41c88/zxtrECl8AKH3B0hj9q10+h3Kt8I7KlW4tw==",
"requires": {
"cookie": "0.4.0",
"cookie": "0.3.1",
"cookie-signature": "1.0.6"
}
},
......@@ -797,9 +817,9 @@
"dev": true
},
"debug": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
"integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
"version": "3.2.6",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz",
"integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==",
"requires": {
"ms": "^2.1.1"
}
......@@ -867,11 +887,6 @@
"resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz",
"integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o="
},
"denque": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/denque/-/denque-1.4.1.tgz",
"integrity": "sha512-OfzPuSZKGcgr96rf1oODnfjqBFmr1DVoc/TrItj3Ohe0Ah1C5WX5Baquw/9U9KovnQ88EqmJbD66rKYUQYN1tQ=="
},
"depd": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
......@@ -953,14 +968,87 @@
"integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k="
},
"end-of-stream": {
"version": "1.4.4",
"resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz",
"integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==",
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz",
"integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==",
"dev": true,
"requires": {
"once": "^1.4.0"
}
},
"engine.io": {
"version": "3.3.2",
"resolved": "https://registry.npmjs.org/engine.io/-/engine.io-3.3.2.tgz",
"integrity": "sha512-AsaA9KG7cWPXWHp5FvHdDWY3AMWeZ8x+2pUVLcn71qE5AtAzgGbxuclOytygskw8XGmiQafTmnI9Bix3uihu2w==",
"requires": {
"accepts": "~1.3.4",
"base64id": "1.0.0",
"cookie": "0.3.1",
"debug": "~3.1.0",
"engine.io-parser": "~2.1.0",
"ws": "~6.1.0"
},
"dependencies": {
"debug": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
"integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
"requires": {
"ms": "2.0.0"
}
},
"ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
}
}
},
"engine.io-client": {
"version": "3.3.2",
"resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-3.3.2.tgz",
"integrity": "sha512-y0CPINnhMvPuwtqXfsGuWE8BB66+B6wTtCofQDRecMQPYX3MYUZXFNKDhdrSe3EVjgOu4V3rxdeqN/Tr91IgbQ==",
"requires": {
"component-emitter": "1.2.1",
"component-inherit": "0.0.3",
"debug": "~3.1.0",
"engine.io-parser": "~2.1.1",
"has-cors": "1.1.0",
"indexof": "0.0.1",
"parseqs": "0.0.5",
"parseuri": "0.0.5",
"ws": "~6.1.0",
"xmlhttprequest-ssl": "~1.5.4",
"yeast": "0.1.2"
},
"dependencies": {
"debug": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
"integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
"requires": {
"ms": "2.0.0"
}
},
"ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
}
}
},
"engine.io-parser": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-2.1.3.tgz",
"integrity": "sha512-6HXPre2O4Houl7c4g7Ic/XzPnHBvaEmN90vtRO9uLmwtRqQmTOw0QMevL1TOfL2Cpu1VzsaTmMotQgMdkzGkVA==",
"requires": {
"after": "0.8.2",
"arraybuffer.slice": "~0.0.7",
"base64-arraybuffer": "0.1.5",
"blob": "0.0.5",
"has-binary2": "~1.0.2"
}
},
"error-ex": {
"version": "1.3.2",
"resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
......@@ -1088,6 +1176,11 @@
"vary": "~1.1.2"
},
"dependencies": {
"cookie": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz",
"integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg=="
},
"debug": {
"version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
......@@ -1189,13 +1282,6 @@
}
}
},
"file-uri-to-path": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz",
"integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==",
"dev": true,
"optional": true
},
"fill-range": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz",
......@@ -1283,11 +1369,11 @@
"integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac="
},
"fs-minipass": {
"version": "1.2.7",
"resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.7.tgz",
"integrity": "sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA==",
"version": "1.2.6",
"resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.6.tgz",
"integrity": "sha512-crhvyXcMejjv3Z5d2Fa9sf5xLYVCF5O1c71QxbVnbLsmYMBEvDAftewesN/HhY03YRoA7zOMxjNGrF5svGaaeQ==",
"requires": {
"minipass": "^2.6.0"
"minipass": "^2.2.1"
}
},
"fs.realpath": {
......@@ -1296,38 +1382,41 @@
"integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8="
},
"fsevents": {
"version": "1.2.12",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.12.tgz",
"integrity": "sha512-Ggd/Ktt7E7I8pxZRbGIs7vwqAPscSESMrCSkx2FtWeqmheJgCo2R74fTsZFCifr0VTPwqRpPv17+6b8Zp7th0Q==",
"version": "1.2.9",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.9.tgz",
"integrity": "sha512-oeyj2H3EjjonWcFjD5NvZNE9Rqe4UW+nQBU2HNeKw0koVLEFIhtyETyAakeAM3de7Z/SW5kcA+fZUait9EApnw==",
"dev": true,
"optional": true,
"requires": {
"bindings": "^1.5.0",
"nan": "^2.12.1",
"node-pre-gyp": "*"
"node-pre-gyp": "^0.12.0"
},
"dependencies": {
"abbrev": {
"version": "1.1.1",
"bundled": true,
"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
"integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==",
"dev": true,
"optional": true
},
"ansi-regex": {
"version": "2.1.1",
"bundled": true,
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
"integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
"dev": true,
"optional": true
},
"aproba": {
"version": "1.2.0",
"bundled": true,
"resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz",
"integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==",
"dev": true,
"optional": true
},
"are-we-there-yet": {
"version": "1.1.5",
"bundled": true,
"resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz",
"integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==",
"dev": true,
"optional": true,
"requires": {
......@@ -1337,13 +1426,15 @@
},
"balanced-match": {
"version": "1.0.0",
"bundled": true,
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
"dev": true,
"optional": true
},
"brace-expansion": {
"version": "1.1.11",
"bundled": true,
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
"dev": true,
"optional": true,
"requires": {
......@@ -1352,38 +1443,44 @@
}
},
"chownr": {
"version": "1.1.4",
"bundled": true,
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.1.tgz",
"integrity": "sha512-j38EvO5+LHX84jlo6h4UzmOwi0UgW61WRyPtJz4qaadK5eY3BTS5TY/S1Stc3Uk2lIM6TPevAlULiEJwie860g==",
"dev": true,
"optional": true
},
"code-point-at": {
"version": "1.1.0",
"bundled": true,
"resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz",
"integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=",
"dev": true,
"optional": true
},
"concat-map": {
"version": "0.0.1",
"bundled": true,
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
"dev": true,
"optional": true
},
"console-control-strings": {
"version": "1.1.0",
"bundled": true,
"resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz",
"integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=",
"dev": true,
"optional": true
},
"core-util-is": {
"version": "1.0.2",
"bundled": true,
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=",
"dev": true,
"optional": true
},
"debug": {
"version": "3.2.6",
"bundled": true,
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
"integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
"dev": true,
"optional": true,
"requires": {
......@@ -1392,40 +1489,46 @@
},
"deep-extend": {
"version": "0.6.0",
"bundled": true,
"resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz",
"integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==",
"dev": true,
"optional": true
},
"delegates": {
"version": "1.0.0",
"bundled": true,
"resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz",
"integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=",
"dev": true,
"optional": true
},
"detect-libc": {
"version": "1.0.3",
"bundled": true,
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz",
"integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=",
"dev": true,
"optional": true
},
"fs-minipass": {
"version": "1.2.7",
"bundled": true,
"version": "1.2.5",
"resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.5.tgz",
"integrity": "sha512-JhBl0skXjUPCFH7x6x61gQxrKyXsxB5gcgePLZCwfyCGGsTISMoIeObbrvVeP6Xmyaudw4TT43qV2Gz+iyd2oQ==",
"dev": true,
"optional": true,
"requires": {
"minipass": "^2.6.0"
"minipass": "^2.2.1"
}
},
"fs.realpath": {
"version": "1.0.0",
"bundled": true,
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
"integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
"dev": true,
"optional": true
},
"gauge": {
"version": "2.7.4",
"bundled": true,
"resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz",
"integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=",
"dev": true,
"optional": true,
"requires": {
......@@ -1440,8 +1543,9 @@
}
},
"glob": {
"version": "7.1.6",
"bundled": true,
"version": "7.1.3",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz",
"integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==",
"dev": true,
"optional": true,
"requires": {
......@@ -1455,13 +1559,15 @@
},
"has-unicode": {
"version": "2.0.1",
"bundled": true,
"resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz",
"integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=",
"dev": true,
"optional": true
},
"iconv-lite": {
"version": "0.4.24",
"bundled": true,
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
"integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
"dev": true,
"optional": true,
"requires": {
......@@ -1469,8 +1575,9 @@
}
},
"ignore-walk": {
"version": "3.0.3",
"bundled": true,
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.1.tgz",
"integrity": "sha512-DTVlMx3IYPe0/JJcYP7Gxg7ttZZu3IInhuEhbchuqneY9wWe5Ojy2mXLBaQFUQmo0AW2r3qG7m1mg86js+gnlQ==",
"dev": true,
"optional": true,
"requires": {
......@@ -1479,7 +1586,8 @@
},
"inflight": {
"version": "1.0.6",
"bundled": true,
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
"integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
"dev": true,
"optional": true,
"requires": {
......@@ -1488,20 +1596,23 @@
}
},
"inherits": {
"version": "2.0.4",
"bundled": true,
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
"integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=",
"dev": true,
"optional": true
},
"ini": {
"version": "1.3.5",
"bundled": true,
"resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz",
"integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==",
"dev": true,
"optional": true
},
"is-fullwidth-code-point": {
"version": "1.0.0",
"bundled": true,
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
"integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
"dev": true,
"optional": true,
"requires": {
......@@ -1510,13 +1621,15 @@
},
"isarray": {
"version": "1.0.0",
"bundled": true,
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
"dev": true,
"optional": true
},
"minimatch": {
"version": "3.0.4",
"bundled": true,
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
"dev": true,
"optional": true,
"requires": {
......@@ -1524,14 +1637,16 @@
}
},
"minimist": {
"version": "1.2.5",
"bundled": true,
"version": "0.0.8",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
"integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=",
"dev": true,
"optional": true
},
"minipass": {
"version": "2.9.0",
"bundled": true,
"version": "2.3.5",
"resolved": "https://registry.npmjs.org/minipass/-/minipass-2.3.5.tgz",
"integrity": "sha512-Gi1W4k059gyRbyVUZQ4mEqLm0YIUiGYfvxhF6SIlk3ui1WVxMTGfGdQ2SInh3PDrRTVvPKgULkpJtT4RH10+VA==",
"dev": true,
"optional": true,
"requires": {
......@@ -1540,43 +1655,48 @@
}
},
"minizlib": {
"version": "1.3.3",
"bundled": true,
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.2.1.tgz",
"integrity": "sha512-7+4oTUOWKg7AuL3vloEWekXY2/D20cevzsrNT2kGWm+39J9hGTCBv8VI5Pm5lXZ/o3/mdR4f8rflAPhnQb8mPA==",
"dev": true,
"optional": true,
"requires": {
"minipass": "^2.9.0"
"minipass": "^2.2.1"
}
},
"mkdirp": {
"version": "0.5.3",
"bundled": true,
"version": "0.5.1",
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
"integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
"dev": true,
"optional": true,
"requires": {
"minimist": "^1.2.5"
"minimist": "0.0.8"
}
},
"ms": {
"version": "2.1.2",
"bundled": true,
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
"integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==",
"dev": true,
"optional": true
},
"needle": {
"version": "2.3.3",
"bundled": true,
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/needle/-/needle-2.3.0.tgz",
"integrity": "sha512-QBZu7aAFR0522EyaXZM0FZ9GLpq6lvQ3uq8gteiDUp7wKdy0lSd2hPlgFwVuW1CBkfEs9PfDQsQzZghLs/psdg==",
"dev": true,
"optional": true,
"requires": {
"debug": "^3.2.6",
"debug": "^4.1.0",
"iconv-lite": "^0.4.4",
"sax": "^1.2.4"
}
},
"node-pre-gyp": {
"version": "0.14.0",
"bundled": true,
"version": "0.12.0",
"resolved": "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.12.0.tgz",
"integrity": "sha512-4KghwV8vH5k+g2ylT+sLTjy5wmUOb9vPhnM8NHvRf9dHmnW/CndrFXy2aRPaPST6dugXSdHXfeaHQm77PIz/1A==",
"dev": true,
"optional": true,
"requires": {
......@@ -1589,12 +1709,13 @@
"rc": "^1.2.7",
"rimraf": "^2.6.1",
"semver": "^5.3.0",
"tar": "^4.4.2"
"tar": "^4"
}
},
"nopt": {
"version": "4.0.3",
"bundled": true,
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.1.tgz",
"integrity": "sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=",
"dev": true,
"optional": true,
"requires": {
......@@ -1603,34 +1724,27 @@
}
},
"npm-bundled": {
"version": "1.1.1",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"npm-normalize-package-bin": "^1.0.1"
}
},
"npm-normalize-package-bin": {
"version": "1.0.1",
"bundled": true,
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.0.6.tgz",
"integrity": "sha512-8/JCaftHwbd//k6y2rEWp6k1wxVfpFzB6t1p825+cUb7Ym2XQfhwIC5KwhrvzZRJu+LtDE585zVaS32+CGtf0g==",
"dev": true,
"optional": true
},
"npm-packlist": {
"version": "1.4.8",
"bundled": true,
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-1.4.1.tgz",
"integrity": "sha512-+TcdO7HJJ8peiiYhvPxsEDhF3PJFGUGRcFsGve3vxvxdcpO2Z4Z7rkosRM0kWj6LfbK/P0gu3dzk5RU1ffvFcw==",
"dev": true,
"optional": true,
"requires": {
"ignore-walk": "^3.0.1",
"npm-bundled": "^1.0.1",
"npm-normalize-package-bin": "^1.0.1"
"npm-bundled": "^1.0.1"
}
},
"npmlog": {
"version": "4.1.2",
"bundled": true,
"resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz",
"integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==",
"dev": true,
"optional": true,
"requires": {
......@@ -1642,19 +1756,22 @@
},
"number-is-nan": {
"version": "1.0.1",
"bundled": true,
"resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz",
"integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=",
"dev": true,
"optional": true
},
"object-assign": {
"version": "4.1.1",
"bundled": true,
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
"integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
"dev": true,
"optional": true
},
"once": {
"version": "1.4.0",
"bundled": true,
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
"dev": true,
"optional": true,
"requires": {
......@@ -1663,19 +1780,22 @@
},
"os-homedir": {
"version": "1.0.2",
"bundled": true,
"resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz",
"integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=",
"dev": true,
"optional": true
},
"os-tmpdir": {
"version": "1.0.2",
"bundled": true,
"resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
"integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=",
"dev": true,
"optional": true
},
"osenv": {
"version": "0.1.5",
"bundled": true,
"resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz",
"integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==",
"dev": true,
"optional": true,
"requires": {
......@@ -1685,19 +1805,22 @@
},
"path-is-absolute": {
"version": "1.0.1",
"bundled": true,
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
"integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
"dev": true,
"optional": true
},
"process-nextick-args": {
"version": "2.0.1",
"bundled": true,
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz",
"integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==",
"dev": true,
"optional": true
},
"rc": {
"version": "1.2.8",
"bundled": true,
"resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz",
"integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==",
"dev": true,
"optional": true,
"requires": {
......@@ -1705,11 +1828,21 @@
"ini": "~1.3.0",
"minimist": "^1.2.0",
"strip-json-comments": "~2.0.1"
},
"dependencies": {
"minimist": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
"integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
"dev": true,
"optional": true
}
}
},
"readable-stream": {
"version": "2.3.7",
"bundled": true,
"version": "2.3.6",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
"dev": true,
"optional": true,
"requires": {
......@@ -1723,8 +1856,9 @@
}
},
"rimraf": {
"version": "2.7.1",
"bundled": true,
"version": "2.6.3",
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz",
"integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==",
"dev": true,
"optional": true,
"requires": {
......@@ -1733,43 +1867,50 @@
},
"safe-buffer": {
"version": "5.1.2",
"bundled": true,
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
"dev": true,
"optional": true
},
"safer-buffer": {
"version": "2.1.2",
"bundled": true,
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
"dev": true,
"optional": true
},
"sax": {
"version": "1.2.4",
"bundled": true,
"resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
"integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==",
"dev": true,
"optional": true
},
"semver": {
"version": "5.7.1",
"bundled": true,
"version": "5.7.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz",
"integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==",
"dev": true,
"optional": true
},
"set-blocking": {
"version": "2.0.0",
"bundled": true,
"resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
"integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=",
"dev": true,
"optional": true
},
"signal-exit": {
"version": "3.0.2",
"bundled": true,
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz",
"integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=",
"dev": true,
"optional": true
},
"string-width": {
"version": "1.0.2",
"bundled": true,
"resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
"integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
"dev": true,
"optional": true,
"requires": {
......@@ -1780,7 +1921,8 @@
},
"string_decoder": {
"version": "1.1.1",
"bundled": true,
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
"dev": true,
"optional": true,
"requires": {
......@@ -1789,7 +1931,8 @@
},
"strip-ansi": {
"version": "3.0.1",
"bundled": true,
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
"integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
"dev": true,
"optional": true,
"requires": {
......@@ -1798,34 +1941,38 @@
},
"strip-json-comments": {
"version": "2.0.1",
"bundled": true,
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
"integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=",
"dev": true,
"optional": true
},
"tar": {
"version": "4.4.13",
"bundled": true,
"version": "4.4.8",
"resolved": "https://registry.npmjs.org/tar/-/tar-4.4.8.tgz",
"integrity": "sha512-LzHF64s5chPQQS0IYBn9IN5h3i98c12bo4NCO7e0sGM2llXQ3p2FGC5sdENN4cTW48O915Sh+x+EXx7XW96xYQ==",
"dev": true,
"optional": true,
"requires": {
"chownr": "^1.1.1",
"fs-minipass": "^1.2.5",
"minipass": "^2.8.6",
"minizlib": "^1.2.1",
"minipass": "^2.3.4",
"minizlib": "^1.1.1",
"mkdirp": "^0.5.0",
"safe-buffer": "^5.1.2",
"yallist": "^3.0.3"
"yallist": "^3.0.2"
}
},
"util-deprecate": {
"version": "1.0.2",
"bundled": true,
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=",
"dev": true,
"optional": true
},
"wide-align": {
"version": "1.1.3",
"bundled": true,
"resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz",
"integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==",
"dev": true,
"optional": true,
"requires": {
......@@ -1834,13 +1981,15 @@
},
"wrappy": {
"version": "1.0.2",
"bundled": true,
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
"dev": true,
"optional": true
},
"yallist": {
"version": "3.1.1",
"bundled": true,
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.3.tgz",
"integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==",
"dev": true,
"optional": true
}
......@@ -1883,9 +2032,9 @@
"dev": true
},
"glob": {
"version": "7.1.6",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
"integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
"version": "7.1.4",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz",
"integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==",
"requires": {
"fs.realpath": "^1.0.0",
"inflight": "^1.0.4",
......@@ -1953,15 +2102,36 @@
}
},
"graceful-fs": {
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz",
"integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==",
"version": "4.2.2",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.2.tgz",
"integrity": "sha512-IItsdsea19BoLC7ELy13q1iJFNmd7ofZH5+X/pJr90/nRoPEX0DJo1dHDbgtYWOhJhcCgMDTOw84RZ72q6lB+Q==",
"dev": true
},
"has-binary2": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/has-binary2/-/has-binary2-1.0.3.tgz",
"integrity": "sha512-G1LWKhDSvhGeAQ8mPVQlqNcOB2sJdwATtZKl2pDKKHfpf/rYj24lkinxf69blJbnsvtqqNU+L3SL50vzZhXOnw==",
"requires": {
"isarray": "2.0.1"
},
"dependencies": {
"isarray": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz",
"integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4="
}
}
},
"has-cors": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/has-cors/-/has-cors-1.1.0.tgz",
"integrity": "sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk="
},
"has-flag": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
"integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
"dev": true
},
"has-unicode": {
"version": "2.0.1",
......@@ -2001,17 +2171,17 @@
}
},
"hoist-non-react-statics": {
"version": "3.3.2",
"resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz",
"integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==",
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.0.tgz",
"integrity": "sha512-0XsbTXxgiaCDYDIWFcwkmerZPSwywfUqYmwT4jzewKTQSWoE6FCMoUVOeBJWK3E/CrWbxRG3m5GzY4lnIwGRBA==",
"requires": {
"react-is": "^16.7.0"
}
},
"hosted-git-info": {
"version": "2.8.8",
"resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.8.tgz",
"integrity": "sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==",
"version": "2.8.4",
"resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.4.tgz",
"integrity": "sha512-pzXIvANXEFrc5oFFXRMkbLPQ2rXRoDERwDLyrcUxGhaZhgP54BBSl9Oheh7Vv0T090cszWBxPjkQQ5Sq1PbBRQ==",
"dev": true
},
"http-errors": {
......@@ -2048,9 +2218,9 @@
"dev": true
},
"ignore-walk": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.3.tgz",
"integrity": "sha512-m7o6xuOaT1aqheYHKf8W6J5pYH85ZI9w077erOzLje3JsB1gkafkAhHHY19dqjulgIZHFm32Cp5uNZgcQqdJKw==",
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.2.tgz",
"integrity": "sha512-EXyErtpHbn75ZTsOADsfx6J/FPo6/5cjev46PXrcTpd8z3BoRkXgYu9/JVqrI7tusjmwCZutGeRJeU0Wo1e4Cw==",
"requires": {
"minimatch": "^3.0.4"
}
......@@ -2067,6 +2237,11 @@
"integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=",
"dev": true
},
"indexof": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz",
"integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10="
},
"inflight": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
......@@ -2101,9 +2276,9 @@
"dev": true
},
"ipaddr.js": {
"version": "1.9.1",
"resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
"integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g=="
"version": "1.9.0",
"resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.0.tgz",
"integrity": "sha512-M4Sjn6N/+O6/IXSJseKqHoFc+5FdGJ22sXqnjTpdZweHK64MzEPAyQZyEU3R/KRv2GLoa7nNtg/C2Ev6m7z+eA=="
},
"is-accessor-descriptor": {
"version": "0.1.6",
......@@ -2377,9 +2552,9 @@
"integrity": "sha512-l3hLhffs9zqoDe8zjmb/mAN4B8VT3L56EUvKNqLFVs9YlFA+zx7ke1DO8STAdDyYNkeSo1nKmjuvQeI12So8Xw=="
},
"kind-of": {
"version": "6.0.3",
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
"integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==",
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz",
"integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==",
"dev": true
},
"latest-version": {
......@@ -2413,8 +2588,7 @@
"lodash": {
"version": "4.17.15",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
"integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==",
"dev": true
"integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A=="
},
"lodash.includes": {
"version": "4.3.0",
......@@ -2532,11 +2706,6 @@
"p-is-promise": "^2.0.0"
}
},
"memory-pager": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz",
"integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg=="
},
"merge-descriptors": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
......@@ -2574,16 +2743,16 @@
"integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg=="
},
"mime-db": {
"version": "1.43.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.43.0.tgz",
"integrity": "sha512-+5dsGEEovYbT8UY9yD7eE4XTc4UwJ1jBYlgaQQF38ENsKR3wj/8q8RFZrF9WIZpB2V1ArTVFUva8sAul1NzRzQ=="
"version": "1.40.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.40.0.tgz",
"integrity": "sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA=="
},
"mime-types": {
"version": "2.1.26",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.26.tgz",
"integrity": "sha512-01paPWYgLrkqAyrlDorC1uDwl2p3qZT7yl806vW7DvDoxwXi46jsjFbg+WdwotBIk6/MbEhO/dh5aZ5sNj/dWQ==",
"version": "2.1.24",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.24.tgz",
"integrity": "sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ==",
"requires": {
"mime-db": "1.43.0"
"mime-db": "1.40.0"
}
},
"mimic-fn": {
......@@ -2601,25 +2770,25 @@
}
},
"minimist": {
"version": "1.2.5",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw=="
"version": "0.0.8",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
"integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0="
},
"minipass": {
"version": "2.9.0",
"resolved": "https://registry.npmjs.org/minipass/-/minipass-2.9.0.tgz",
"integrity": "sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==",
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/minipass/-/minipass-2.5.1.tgz",
"integrity": "sha512-dmpSnLJtNQioZFI5HfQ55Ad0DzzsMAb+HfokwRTNXwEQjepbTkl5mtIlSVxGIkOkxlpX7wIn5ET/oAd9fZ/Y/Q==",
"requires": {
"safe-buffer": "^5.1.2",
"yallist": "^3.0.0"
}
},
"minizlib": {
"version": "1.3.3",
"resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.3.3.tgz",
"integrity": "sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q==",
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.2.1.tgz",
"integrity": "sha512-7+4oTUOWKg7AuL3vloEWekXY2/D20cevzsrNT2kGWm+39J9hGTCBv8VI5Pm5lXZ/o3/mdR4f8rflAPhnQb8mPA==",
"requires": {
"minipass": "^2.9.0"
"minipass": "^2.2.1"
}
},
"mixin-deep": {
......@@ -2644,11 +2813,11 @@
}
},
"mkdirp": {
"version": "0.5.4",
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.4.tgz",
"integrity": "sha512-iG9AK/dJLtJ0XNgTuDbSyNS3zECqDlAhnQW4CsNxBG3LQJBbHmRX1egw39DmtOdCAqY+dKXV+sgPgilNWUKMVw==",
"version": "0.5.1",
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
"integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
"requires": {
"minimist": "^1.2.5"
"minimist": "0.0.8"
}
},
"moment": {
......@@ -2657,34 +2826,42 @@
"integrity": "sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg=="
},
"mongodb": {
"version": "3.5.5",
"resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.5.5.tgz",
"integrity": "sha512-GCjDxR3UOltDq00Zcpzql6dQo1sVry60OXJY3TDmFc2SWFY6c8Gn1Ardidc5jDirvJrx2GC3knGOImKphbSL3A==",
"version": "3.3.2",
"resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.3.2.tgz",
"integrity": "sha512-fqJt3iywelk4yKu/lfwQg163Bjpo5zDKhXiohycvon4iQHbrfflSAz9AIlRE6496Pm/dQKQK5bMigdVo2s6gBg==",
"requires": {
"bl": "^2.2.0",
"bson": "^1.1.1",
"denque": "^1.4.1",
"require_optional": "^1.0.1",
"safe-buffer": "^5.1.2",
"saslprep": "^1.0.0"
"safe-buffer": "^5.1.2"
}
},
"mongoose": {
"version": "5.9.7",
"resolved": "https://registry.npmjs.org/mongoose/-/mongoose-5.9.7.tgz",
"integrity": "sha512-WJOBh9WMvivqBK8my9HFtSzSySKdUxJPNGAwswEakAasWUcPXJl3yHMtZ4ngGnKbwTT9KnAr75xamlt/PouR9w==",
"version": "5.7.0",
"resolved": "https://registry.npmjs.org/mongoose/-/mongoose-5.7.0.tgz",
"integrity": "sha512-nE43r4kEUpUBfr32rf+zJKEtzd6I3F5YdbrSHp/DDdVQyej34Cv7gfBdcoRNehrPQDV3khOh0JpiS1aLN9/OCw==",
"requires": {
"async": "2.6.2",
"bson": "~1.1.1",
"kareem": "2.3.1",
"mongodb": "3.5.5",
"mongodb": "3.3.2",
"mongoose-legacy-pluralize": "1.0.2",
"mpath": "0.6.0",
"mquery": "3.2.2",
"mquery": "3.2.1",
"ms": "2.1.2",
"regexp-clone": "1.0.0",
"safe-buffer": "5.1.2",
"sift": "7.0.1",
"sliced": "1.0.1"
},
"dependencies": {
"async": {
"version": "2.6.2",
"resolved": "https://registry.npmjs.org/async/-/async-2.6.2.tgz",
"integrity": "sha512-H1qVYh1MYhEEFLsP97cVKqCGo7KfCyTt6uEWqsTBr9SO84oK9Uwbyd/yCW+6rKJLHksBNUVWZDAjfS+Ccx0Bbg==",
"requires": {
"lodash": "^4.17.11"
}
}
}
},
"mongoose-legacy-pluralize": {
......@@ -2698,9 +2875,9 @@
"integrity": "sha512-i75qh79MJ5Xo/sbhxrDrPSEG0H/mr1kcZXJ8dH6URU5jD/knFxCVqVC/gVSW7GIXL/9hHWlT9haLbCXWOll3qw=="
},
"mquery": {
"version": "3.2.2",
"resolved": "https://registry.npmjs.org/mquery/-/mquery-3.2.2.tgz",
"integrity": "sha512-XB52992COp0KP230I3qloVUbkLUxJIu328HBP2t2EsxSFtf4W1HPSOBWOXf1bqxK4Xbb66lfMJ+Bpfd9/yZE1Q==",
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/mquery/-/mquery-3.2.1.tgz",
"integrity": "sha512-kY/K8QToZWTTocm0U+r8rqcJCp5PRl6e8tPmoDs5OeSO3DInZE2rAL6AYH+V406JTo8305LdASOQcxRDqHojyw==",
"requires": {
"bluebird": "3.5.1",
"debug": "3.1.0",
......@@ -2745,9 +2922,9 @@
}
},
"nan": {
"version": "2.14.0",
"resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz",
"integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg=="
"version": "2.13.2",
"resolved": "https://registry.npmjs.org/nan/-/nan-2.13.2.tgz",
"integrity": "sha512-TghvYc72wlMGMVMluVo9WRJc0mB8KxxF/gZ4YYFy7V2ZQX9l7rgbPg7vjS9mt6U5HXODVFVI2bOduCzwOMv/lw=="
},
"nanomatch": {
"version": "1.2.13",
......@@ -2769,23 +2946,13 @@
}
},
"needle": {
"version": "2.4.1",
"resolved": "https://registry.npmjs.org/needle/-/needle-2.4.1.tgz",
"integrity": "sha512-x/gi6ijr4B7fwl6WYL9FwlCvRQKGlUNvnceho8wxkwXqN8jvVmmmATTmZPRRG7b/yC1eode26C2HO9jl78Du9g==",
"version": "2.4.0",
"resolved": "https://registry.npmjs.org/needle/-/needle-2.4.0.tgz",
"integrity": "sha512-4Hnwzr3mi5L97hMYeNl8wRW/Onhy4nUKR/lVemJ8gJedxxUyBLm9kkrDColJvoSfwi0jCNhD+xCdOtiGDQiRZg==",
"requires": {
"debug": "^3.2.6",
"iconv-lite": "^0.4.4",
"sax": "^1.2.4"
},
"dependencies": {
"debug": {
"version": "3.2.6",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz",
"integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==",
"requires": {
"ms": "^2.1.1"
}
}
}
},
"negotiator": {
......@@ -2800,9 +2967,9 @@
"dev": true
},
"node-pre-gyp": {
"version": "0.14.0",
"resolved": "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.14.0.tgz",
"integrity": "sha512-+CvDC7ZttU/sSt9rFjix/P05iS43qHCOOGzcr3Ry99bXG7VX953+vFyEuph/tfqoYu8dttBkE86JSKBO2OzcxA==",
"version": "0.12.0",
"resolved": "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.12.0.tgz",
"integrity": "sha512-4KghwV8vH5k+g2ylT+sLTjy5wmUOb9vPhnM8NHvRf9dHmnW/CndrFXy2aRPaPST6dugXSdHXfeaHQm77PIz/1A==",
"requires": {
"detect-libc": "^1.0.2",
"mkdirp": "^0.5.1",
......@@ -2813,42 +2980,27 @@
"rc": "^1.2.7",
"rimraf": "^2.6.1",
"semver": "^5.3.0",
"tar": "^4.4.2"
"tar": "^4"
}
},
"nodemon": {
"version": "1.19.4",
"resolved": "https://registry.npmjs.org/nodemon/-/nodemon-1.19.4.tgz",
"integrity": "sha512-VGPaqQBNk193lrJFotBU8nvWZPqEZY2eIzymy2jjY0fJ9qIsxA0sxQ8ATPl0gZC645gijYEc1jtZvpS8QWzJGQ==",
"version": "1.19.2",
"resolved": "https://registry.npmjs.org/nodemon/-/nodemon-1.19.2.tgz",
"integrity": "sha512-hRLYaw5Ihyw9zK7NF+9EUzVyS6Cvgc14yh8CAYr38tPxJa6UrOxwAQ351GwrgoanHCF0FalQFn6w5eoX/LGdJw==",
"dev": true,
"requires": {
"chokidar": "^2.1.8",
"debug": "^3.2.6",
"chokidar": "^2.1.5",
"debug": "^3.1.0",
"ignore-by-default": "^1.0.1",
"minimatch": "^3.0.4",
"pstree.remy": "^1.1.7",
"semver": "^5.7.1",
"supports-color": "^5.5.0",
"pstree.remy": "^1.1.6",
"semver": "^5.5.0",
"supports-color": "^5.2.0",
"touch": "^3.1.0",
"undefsafe": "^2.0.2",
"update-notifier": "^2.5.0"
},
"dependencies": {
"debug": {
"version": "3.2.6",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz",
"integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==",
"dev": true,
"requires": {
"ms": "^2.1.1"
}
},
"has-flag": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
"integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
"dev": true
},
"supports-color": {
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
......@@ -2861,9 +3013,9 @@
}
},
"nopt": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.3.tgz",
"integrity": "sha512-CvaGwVMztSMJLOeXPrez7fyfObdZqNUK1cPAEzLHrTybIua9pMdmmPR5YwtfNftIOMv3DPUhFaxsZMNTQO20Kg==",
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.1.tgz",
"integrity": "sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=",
"requires": {
"abbrev": "1",
"osenv": "^0.1.4"
......@@ -2888,26 +3040,17 @@
"dev": true
},
"npm-bundled": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.1.1.tgz",
"integrity": "sha512-gqkfgGePhTpAEgUsGEgcq1rqPXA+tv/aVBlgEzfXwA1yiUJF7xtEt3CtVwOjNYQOVknDk0F20w58Fnm3EtG0fA==",
"requires": {
"npm-normalize-package-bin": "^1.0.1"
}
},
"npm-normalize-package-bin": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz",
"integrity": "sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA=="
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.0.6.tgz",
"integrity": "sha512-8/JCaftHwbd//k6y2rEWp6k1wxVfpFzB6t1p825+cUb7Ym2XQfhwIC5KwhrvzZRJu+LtDE585zVaS32+CGtf0g=="
},
"npm-packlist": {
"version": "1.4.8",
"resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-1.4.8.tgz",
"integrity": "sha512-5+AZgwru5IevF5ZdnFglB5wNlHG1AOOuw28WhUq8/8emhBmLv6jX5by4WJCh7lW0uSYZYS6DXqIsyZVIXRZU9A==",
"version": "1.4.4",
"resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-1.4.4.tgz",
"integrity": "sha512-zTLo8UcVYtDU3gdeaFu2Xu0n0EvelfHDGuqtNIn5RO7yQj4H1TqNdBc/yZjxnWA0PVB8D3Woyp0i5B43JwQ6Vw==",
"requires": {
"ignore-walk": "^3.0.1",
"npm-bundled": "^1.0.1",
"npm-normalize-package-bin": "^1.0.1"
"npm-bundled": "^1.0.1"
}
},
"npm-run-path": {
......@@ -2940,6 +3083,11 @@
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
"integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM="
},
"object-component": {
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/object-component/-/object-component-0.0.3.tgz",
"integrity": "sha1-8MaapQ78lbhmwYb0AKM3acsvEpE="
},
"object-copy": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz",
......@@ -3054,9 +3202,9 @@
"dev": true
},
"p-limit": {
"version": "2.2.2",
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.2.tgz",
"integrity": "sha512-WGR+xHecKTr7EbUEhyLSh5Dube9JtdiG78ufaeLxTgpudf/20KqyMioIUZJAezlTIi6evxuoUs9YXc11cU+yzQ==",
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.1.tgz",
"integrity": "sha512-85Tk+90UCVWvbDavCLKPOLC9vvY8OwEX/RtKF+/1OADJMVlFfEHOiMTPVyxg7mk/dKa+ipdHm0OUkTvCpMTuwg==",
"dev": true,
"requires": {
"p-try": "^2.0.0"
......@@ -3099,6 +3247,22 @@
"json-parse-better-errors": "^1.0.1"
}
},
"parseqs": {
"version": "0.0.5",
"resolved": "https://registry.npmjs.org/parseqs/-/parseqs-0.0.5.tgz",
"integrity": "sha1-1SCKNzjkZ2bikbouoXNoSSGouJ0=",
"requires": {
"better-assert": "~1.0.0"
}
},
"parseuri": {
"version": "0.0.5",
"resolved": "https://registry.npmjs.org/parseuri/-/parseuri-0.0.5.tgz",
"integrity": "sha1-gCBKUNTbt3m/3G6+J3jZDkvOMgo=",
"requires": {
"better-assert": "~1.0.0"
}
},
"parseurl": {
"version": "1.3.3",
"resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
......@@ -3184,12 +3348,12 @@
}
},
"proxy-addr": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.6.tgz",
"integrity": "sha512-dh/frvCBVmSsDYzw6n926jv974gddhkFPfiN8hPOi30Wax25QZyZEGveluCgliBnqmuM+UJmBErbAUFIoDbjOw==",
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.5.tgz",
"integrity": "sha512-t/7RxHXPH6cJtP0pRG6smSr9QJidhB+3kXu0KgXnbGYMgzEnUxRQ4/LDdfOwZEMyIh3/xHb8PX3t+lfL9z+YVQ==",
"requires": {
"forwarded": "~0.1.2",
"ipaddr.js": "1.9.1"
"ipaddr.js": "1.9.0"
}
},
"pseudomap": {
......@@ -3244,12 +3408,19 @@
"ini": "~1.3.0",
"minimist": "^1.2.0",
"strip-json-comments": "~2.0.1"
},
"dependencies": {
"minimist": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
"integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ="
}
}
},
"react-is": {
"version": "16.13.1",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
"version": "16.9.0",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.9.0.tgz",
"integrity": "sha512-tJBzzzIgnnRfEm046qRcURvwQnZVXmuCbscxUO5RWrGTXpon2d4c8mI0D8WE6ydVIm29JiLB6+RslkIvym9Rjw=="
},
"react-lifecycles-compat": {
"version": "3.0.4",
......@@ -3257,12 +3428,12 @@
"integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA=="
},
"react-redux": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/react-redux/-/react-redux-5.1.2.tgz",
"integrity": "sha512-Ns1G0XXc8hDyH/OcBHOxNgQx9ayH3SPxBnFCOidGKSle8pKihysQw2rG/PmciUQRoclhVBO8HMhiRmGXnDja9Q==",
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/react-redux/-/react-redux-5.1.1.tgz",
"integrity": "sha512-LE7Ned+cv5qe7tMV5BPYkGQ5Lpg8gzgItK07c67yHvJ8t0iaD9kPFPAli/mYkiyJYrs2pJgExR2ZgsGqlrOApg==",
"requires": {
"@babel/runtime": "^7.1.2",
"hoist-non-react-statics": "^3.3.0",
"hoist-non-react-statics": "^3.1.0",
"invariant": "^2.2.4",
"loose-envify": "^1.1.0",
"prop-types": "^15.6.1",
......@@ -3282,9 +3453,9 @@
}
},
"readable-stream": {
"version": "2.3.7",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
"integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
"version": "2.3.6",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
"requires": {
"core-util-is": "~1.0.0",
"inherits": "~2.0.3",
......@@ -3307,9 +3478,9 @@
}
},
"regenerator-runtime": {
"version": "0.13.5",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.5.tgz",
"integrity": "sha512-ZS5w8CpKFinUzOwW3c83oPeVXoNsrLsaCoLtJvAClH135j/R77RuymhiSErhm2lKcwSCIpmvIWSbDkIfAqKQlA=="
"version": "0.13.3",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.3.tgz",
"integrity": "sha512-naKIZz2GQ8JWh///G7L3X6LaQUAMp2lvb1rvwwsURe/VXwD6VMfr+/1NuNw3ag8v2kY1aQ/go5SNn79O9JU7yw=="
},
"regex-not": {
"version": "1.0.2",
......@@ -3385,9 +3556,9 @@
}
},
"resolve": {
"version": "1.15.1",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.15.1.tgz",
"integrity": "sha512-84oo6ZTtoTUpjgNEr5SJyzQhzL72gaRodsSfyxC/AXRvwu0Yse9H8eF9IpGo7b8YetZhlI6v7ZQ6bKBFV/6S7w==",
"version": "1.12.0",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.12.0.tgz",
"integrity": "sha512-B/dOmuoAik5bKcD6s6nXDCjzUKnaDvdkRyAk6rsmsKLipWj4797iothd7jmmUhWTfinVMU+wc56rYKsit2Qy4w==",
"dev": true,
"requires": {
"path-parse": "^1.0.6"
......@@ -3419,9 +3590,9 @@
}
},
"rxjs": {
"version": "6.5.5",
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.5.tgz",
"integrity": "sha512-WfQI+1gohdf0Dai/Bbmk5L5ItH5tYqm3ki2c5GdWhKjalzjg93N3avFjVStyZZz+A2Em+ZxKH5bNghw9UeylGQ==",
"version": "6.5.3",
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.3.tgz",
"integrity": "sha512-wuYsAYYFdWTAnAaPoKGNhfpWwKZbJW+HgAJ+mImp+Epl7BG8oNWBCTyRM8gba9k4lk8BgWdoYm21Mo/RYhhbgA==",
"dev": true,
"requires": {
"tslib": "^1.9.0"
......@@ -3446,14 +3617,6 @@
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
},
"saslprep": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/saslprep/-/saslprep-1.0.3.tgz",
"integrity": "sha512-/MY/PEMbk2SuY5sScONwhUDsV2p77Znkb/q3nSVstq/yQzYJOH/Azh29p9oJLsl3LnQwSvZDKagDGBsBwSooag==",
"requires": {
"sparse-bitfield": "^3.0.3"
}
},
"sax": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
......@@ -3580,9 +3743,9 @@
"integrity": "sha512-oqD7PMJ+uO6jV9EQCl0LrRw1OwsiPsiFQR5AR30heR+4Dl7jBBbDLnNvWiak20tzZlSE1H7RB30SX/1j/YYT7g=="
},
"signal-exit": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz",
"integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA=="
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz",
"integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0="
},
"sliced": {
"version": "1.0.1",
......@@ -3711,6 +3874,100 @@
}
}
},
"socket.io": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/socket.io/-/socket.io-2.2.0.tgz",
"integrity": "sha512-wxXrIuZ8AILcn+f1B4ez4hJTPG24iNgxBBDaJfT6MsyOhVYiTXWexGoPkd87ktJG8kQEcL/NBvRi64+9k4Kc0w==",
"requires": {
"debug": "~4.1.0",
"engine.io": "~3.3.1",
"has-binary2": "~1.0.2",
"socket.io-adapter": "~1.1.0",
"socket.io-client": "2.2.0",
"socket.io-parser": "~3.3.0"
},
"dependencies": {
"debug": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
"integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
"requires": {
"ms": "^2.1.1"
}
}
}
},
"socket.io-adapter": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-1.1.1.tgz",
"integrity": "sha1-KoBeihTWNyEk3ZFZrUUC+MsH8Gs="
},
"socket.io-client": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-2.2.0.tgz",
"integrity": "sha512-56ZrkTDbdTLmBIyfFYesgOxsjcLnwAKoN4CiPyTVkMQj3zTUh0QAx3GbvIvLpFEOvQWu92yyWICxB0u7wkVbYA==",
"requires": {
"backo2": "1.0.2",
"base64-arraybuffer": "0.1.5",
"component-bind": "1.0.0",
"component-emitter": "1.2.1",
"debug": "~3.1.0",
"engine.io-client": "~3.3.1",
"has-binary2": "~1.0.2",
"has-cors": "1.1.0",
"indexof": "0.0.1",
"object-component": "0.0.3",
"parseqs": "0.0.5",
"parseuri": "0.0.5",
"socket.io-parser": "~3.3.0",
"to-array": "0.1.4"
},
"dependencies": {
"debug": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
"integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
"requires": {
"ms": "2.0.0"
}
},
"ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
}
}
},
"socket.io-parser": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.3.0.tgz",
"integrity": "sha512-hczmV6bDgdaEbVqhAeVMM/jfUfzuEZHsQg6eOmLgJht6G3mPKMxYm75w2+qhAQZ+4X+1+ATZ+QFKeOZD5riHng==",
"requires": {
"component-emitter": "1.2.1",
"debug": "~3.1.0",
"isarray": "2.0.1"
},
"dependencies": {
"debug": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
"integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
"requires": {
"ms": "2.0.0"
}
},
"isarray": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz",
"integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4="
},
"ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
}
}
},
"source-map": {
"version": "0.5.7",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
......@@ -3718,12 +3975,12 @@
"dev": true
},
"source-map-resolve": {
"version": "0.5.3",
"resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz",
"integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==",
"version": "0.5.2",
"resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.2.tgz",
"integrity": "sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA==",
"dev": true,
"requires": {
"atob": "^2.1.2",
"atob": "^2.1.1",
"decode-uri-component": "^0.2.0",
"resolve-url": "^0.2.1",
"source-map-url": "^0.4.0",
......@@ -3736,14 +3993,6 @@
"integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=",
"dev": true
},
"sparse-bitfield": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz",
"integrity": "sha1-/0rm5oZWBWuks+eSqzM004JzyhE=",
"requires": {
"memory-pager": "^1.0.2"
}
},
"spawn-command": {
"version": "0.0.2-1",
"resolved": "https://registry.npmjs.org/spawn-command/-/spawn-command-0.0.2-1.tgz",
......@@ -3860,21 +4109,30 @@
"integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo="
},
"supports-color": {
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz",
"integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==",
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.5.0.tgz",
"integrity": "sha1-vnoN5ITexcXN34s9WRJQRJEvY1s=",
"dev": true,
"requires": {
"has-flag": "^4.0.0"
"has-flag": "^2.0.0"
},
"dependencies": {
"has-flag": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz",
"integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=",
"dev": true
}
}
},
"tar": {
"version": "4.4.13",
"resolved": "https://registry.npmjs.org/tar/-/tar-4.4.13.tgz",
"integrity": "sha512-w2VwSrBoHa5BsSyH+KxEqeQBAllHhccyMFVHtGtdMpF4W7IRWfZjFiQceJPChOeTsSDVUpER2T8FA93pr0L+QA==",
"version": "4.4.10",
"resolved": "https://registry.npmjs.org/tar/-/tar-4.4.10.tgz",
"integrity": "sha512-g2SVs5QIxvo6OLp0GudTqEf05maawKUxXru104iaayWA09551tFCTI8f1Asb4lPfkBr91k07iL4c11XO3/b0tA==",
"requires": {
"chownr": "^1.1.1",
"fs-minipass": "^1.2.5",
"minipass": "^2.8.6",
"minipass": "^2.3.5",
"minizlib": "^1.2.1",
"mkdirp": "^0.5.0",
"safe-buffer": "^5.1.2",
......@@ -3930,6 +4188,11 @@
"integrity": "sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8=",
"dev": true
},
"to-array": {
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/to-array/-/to-array-0.1.4.tgz",
"integrity": "sha1-F+bBH3PdTz10zaek/zI46a2b+JA="
},
"to-object-path": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz",
......@@ -3998,15 +4261,15 @@
}
},
"tree-kill": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz",
"integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==",
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.1.tgz",
"integrity": "sha512-4hjqbObwlh2dLyW4tcz0Ymw0ggoaVDMveUB9w8kFSQScdRLo0gxO9J7WFcUBo+W3C1TLdFIEwNOWebgZZ0RH9Q==",
"dev": true
},
"tslib": {
"version": "1.11.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.11.1.tgz",
"integrity": "sha512-aZW88SY8kQbU7gpV19lN24LtXh/yD4ZZg6qieAJDDg+YBsJcSmLGK9QpnUjAKVG/xefmvJGd1WUmfpT/g6AJGA==",
"version": "1.10.0",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz",
"integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==",
"dev": true
},
"type-is": {
......@@ -4024,9 +4287,9 @@
"integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c="
},
"undefsafe": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.3.tgz",
"integrity": "sha512-nrXZwwXrD/T/JXeygJqdCO6NZZ1L66HrxM/Z7mIq2oPanoN0F1nLx3lwJMu6AwJY69hdixaFQOuoYsMjE5/C2A==",
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.2.tgz",
"integrity": "sha1-Il9rngM3Zj4Njnz9aG/Cg2zKznY=",
"dev": true,
"requires": {
"debug": "^2.2.0"
......@@ -4282,12 +4545,25 @@
"signal-exit": "^3.0.2"
}
},
"ws": {
"version": "6.1.4",
"resolved": "https://registry.npmjs.org/ws/-/ws-6.1.4.tgz",
"integrity": "sha512-eqZfL+NE/YQc1/ZynhojeV8q+H050oR8AZ2uIev7RU10svA9ZnJUddHcOUZTJLinZ9yEfdA2kSATS2qZK5fhJA==",
"requires": {
"async-limiter": "~1.0.0"
}
},
"xdg-basedir": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-3.0.0.tgz",
"integrity": "sha1-SWsswQnsqNus/i3HK2A8F8WHCtQ=",
"dev": true
},
"xmlhttprequest-ssl": {
"version": "1.5.5",
"resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz",
"integrity": "sha1-wodrBhaKrcQOV9l+gRkayPQ5iz4="
},
"xtend": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
......@@ -4300,9 +4576,9 @@
"dev": true
},
"yallist": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
"integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.3.tgz",
"integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A=="
},
"yargs": {
"version": "12.0.5",
......@@ -4366,6 +4642,11 @@
"camelcase": "^5.0.0",
"decamelize": "^1.2.0"
}
},
"yeast": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz",
"integrity": "sha1-AI4G2AlDIMNy28L47XagymyKxBk="
}
}
}
......
......@@ -10,25 +10,24 @@
"scripts": {
"start": "node server/index.js",
"backend": "nodemon server/index.js",
"frontend": "npm run start --prefix client",
"frontend": "npm run front --prefix client",
"dev": "concurrently \"npm run backend\" \"npm run start --prefix client\""
},
"author": "John ahn",
"license": "ISC",
"dependencies": {
"async": "^3.1.0",
"bcrypt": "^3.0.6",
"body-parser": "^1.18.3",
"cookie-parser": "^1.4.3",
"cors": "^2.8.5",
"debug": "^4.1.1",
"express": "^4.17.1",
"jsonwebtoken": "^8.5.1",
"moment": "^2.24.0",
"mongoose": "^5.4.20",
"multer": "^1.4.2",
"react-redux": "^5.0.7",
"saslprep": "^1.0.3",
"supports-color": "^7.1.0"
"socket.io": "^2.2.0"
},
"devDependencies": {
"concurrently": "^4.1.0",
......
dev.js
\ No newline at end of file
// development모드이면 process.env.NODE_ENV는 development라고 나오고
// production모드이면 production이라고 나옴
if(process.env.NODE_ENV === 'production') // === 는 형변환을 하지 않음.
// ex) true == 1 -> return true
// true === 1 -> return false
{
module.exports = require('./prod')
}
else
{
module.exports = require('./dev')
if (process.env.NODE_ENV === 'production') {
module.exports = require('./prod');
} else {
module.exports = require('./dev');
}
\ No newline at end of file
......
module.exports ={
mongoURI: process.env.mongo_URI
module.exports = {
mongoURI:process.env.MONGO_URI
}
\ No newline at end of file
......
const express = require("express")
const app = express()
const port = process.env.PORT || 5000
const express = require("express");
const app = express();
const path = require("path");
const cors = require('cors')
// body-parser 가져옴
const bodyParser = require('body-parser')
// bodyParser option
app.use(bodyParser.urlencoded({ extended: true })) //application/x-www-form-urlencoded로 된 데이터를 분석해서 가져옴
app.use(bodyParser.json()) // application/json 타입으로 된 데이터를 분석해서 가져옴
const bodyParser = require("body-parser");
const cookieParser = require("cookie-parser");
app.use(cookieParser());
const config = require("./config/key");
// const mongoose = require("mongoose");
// mongoose
// .connect(config.mongoURI, { useNewUrlParser: true })
// .then(() => console.log("DB connected"))
// .catch(err => console.error(err));
const mongoose = require("mongoose");
const connect = mongoose.connect(config.mongoURI,
{
useNewUrlParser: true, useUnifiedTopology: true,
useCreateIndex: true, useFindAndModify: false
})
.then(() => console.log('MongoDB ---> Connected'))
const connect = mongoose.connect(config.mongoURI, { useNewUrlParser: true, useUnifiedTopology: true })
.then(() => console.log('MongoDB Connected...'))
.catch(err => console.log(err));
app.use(cors())
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
app.use(cookieParser());
app.use('/api/users', require('./routes/users'));
app.use('/api/product', require('./routes/product'));
// 업로드 하려고
//use this to show the image you have in node js server to client (react js)
//https://stackoverflow.com/questions/48914987/send-image-path-from-node-js-express-server-to-react-client
app.use('/uploads', express.static('uploads'));
// Serve static assets if in production
if (process.env.NODE_ENV === "production") {
// Set static folder
app.use(express.static("client/build"));
// index.html for all page routes
app.get("*", (req, res) => {
res.sendFile(path.resolve(__dirname, "../client", "build", "index.html"));
});
}
const port = process.env.PORT || 5000
app.listen(port, () => {
console.log(`Server ---> http://localhost:${port}`)
});
console.log(`Server Running at ${port}`)
});
\ No newline at end of file
......
const { User } = require('../models/User');
let auth = (req, res, next) => {
// 인증 처리
// 1. client 쿠키에서 토큰을 가져옴.
let token = req.cookies.w_auth;
// 2. 토큰을 복호화한 후 유저를 찾는다. (User.js에 findByToken(); 있음)
User.findByToken(token, (err, user)=>{
// 에러가 있으면
if(err) throw err;
// 유저가 없으면
if(!user) return res.json({ isAuth:false, error: true})
// 에러도 없고 유저도 있으면
req.token = token; // token과 user를 request에 넣어줌으로써 index.js에서 request 사용할 수 있음
User.findByToken(token, (err, user) => {
if (err) throw err;
if (!user)
return res.json({
isAuth: false,
error: true
});
req.token = token;
req.user = user;
next();
});
// 3. 유저가 있으면 인증OK, 유저가 없으면 인증No!
}
});
};
// 이 auth를 다른 파일에서도 쓸 수 있도록
module.exports = { auth };
\ No newline at end of file
module.exports = { auth };
......
const mongoose = require('mongoose');
const paymentSchema = mongoose.Schema({
user: { // 구매자 정보
type: Array,
default: []
},
data: { // 구매일자 정보
type: Array,
default: []
},
product: { // 상품 정보
type: Array,
default: []
}
}, { timestamps: true })
const Payment = mongoose.model('Payment', paymentSchema);
module.exports = { Payment }
\ No newline at end of file
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const productSchema = mongoose.Schema({
writer: {
type: Schema.Types.ObjectId,
ref: 'User'
},
title: {
type: String,
maxlength: 50
},
description: {
type: String
},
price: {
type: Number,
default: 0
},
images: {
type: Array,
default: []
},
continents: {
type: Number,
default: 1
},
sold: {
type: Number,
maxlength: 100,
default: 0
},
views: {
type: Number,
default: 0
}
}, { timestamps: true })
productSchema.index({
title:'text',
description: 'text',
}, {
weights: {
name: 5,
description: 1,
}
})
const Product = mongoose.model('Product', productSchema);
module.exports = { Product }
\ No newline at end of file
// monggoDB Model and Schema
const mongoose = require('mongoose');
// bcrypt 가져옴
const bcrypt = require('bcrypt')
// bcrypt 사용하기 위해 salt를 생성하고 그걸 이용해 암호화 시킴
const saltRounds = 10 // salt를 몇글자 할 건지
const bcrypt = require('bcrypt');
const saltRounds = 10;
const jwt = require('jsonwebtoken');
const moment = require("moment");
const moment = require('moment');
const userSchema = mongoose.Schema({
name: {
type:String,
maxlength:50
type: String,
maxlength: 50
},
email: {
type:String,
trim:true,
unique: 1
type: String,
trim: true,
unique: 1
},
password: {
type: String,
minglength: 3
minlength: 5
},
lastname: {
type:String,
maxlength: 50
adress: {
type: String,
maxlength: 100
},
role: {
type: Number,
default: 0
},
role : {
type:Number, // Number==1 이면 관리자, number==0 이면 일반 유저
default: 0 // default는 0
cart: {
type: Array,
default: []
},
history: {
type: Array,
default: []
},
image: String,
token : {
token: {
type: String,
},
tokenExp :{
tokenExp: {
type: Number
}
})
// index.js의 app.post('/register', (req, res)에 있는
// user model에 user 정보를 저장하기 전에 무엇을 한다는 것
// function( next )를 해서 얘네가 끝난 다음에 다음걸 실행해라~
userSchema.pre('save', function( next ) {
userSchema.pre('save', function (next) {
var user = this;
if(user.isModified('password')){ // password를 변경할 때만 적용되도록..
// 비밀번호 암호화 (https://www.npmjs.com/package/bcrypt 에서 가져옴)
bcrypt.genSalt(saltRounds, (err, salt) => // salt를 만드는 함수
{
if(err) return next(err) // 에러 나면 return err
bcrypt.hash(user.password, salt, (err, hash) => { // bcrypt.hash(암호화되지 않은 pw, salt, function(err, 암호화된 비밀번호))
if(err) return next(err) // 에러 나면 return err
user.password = hash // 성공하면 user.password를 hash로 교체
next()
if (user.isModified('password')) {
console.log('password changed')
bcrypt.genSalt(saltRounds, function (err, salt) {
if (err) return next(err);
bcrypt.hash(user.password, salt, function (err, hash) {
if (err) return next(err);
user.password = hash
next()
})
})
} else {
......@@ -62,44 +62,35 @@ userSchema.pre('save', function( next ) {
}
});
userSchema.methods.comparePassword = function(plainPassword,cb){
// 1. plainPassword가 1234567 암호화된 비밀번호 가 같은지 체크해야함
// 그러면 plainPassword도 암호화해서 비교해야함. (복호화 할 수 없기 때문에)
bcrypt.compare(plainPassword, this.password, function(err, isMatch)
{ // 에러가 나면 err callback, 아니면 isMatch
if(err) return cb(err);
cb(null, isMatch);
userSchema.methods.comparePassword = function (plainPassword, cb) {
bcrypt.compare(plainPassword, this.password, function (err, isMatch) {
if (err) return cb(err);
cb(null, isMatch)
})
}
userSchema.methods.generateToken = function(cb) {
userSchema.methods.generateToken = function (cb) {
var user = this;
// jsonwebtoken을 이용해서 token 생성
var token = jwt.sign(user._id.toHexString(), 'secretToken') //database에 있는 id라서 _id
var token = jwt.sign(user._id.toHexString(), 'secret')
var oneHour = moment().add(1, 'hour').valueOf();
user.tokenExp = oneHour;
user.token = token;
user.save(function (err, user){
if(err) return cb(err)// 에러가 있다면 callback으로 에러 전달
cb(null, user) // 에러가 없다면 err는 없고 user정보만 전달
user.save(function (err, user) {
if (err) return cb(err)
cb(null, user);
})
}
userSchema.statics.findByToken = function (token, cb) {
var user = this;
// 1. 토큰을 decoding
jwt.verify(token, 'secretToken', function(err, decoded) {
// 2. 유저 아이디를 이용해서 유저를 찾은 다음에 클라이언트에서 가져온 토큰과 DB에 보관된 토큰이 일치하는지 확인.
user.findOne({"_id": decoded, "token": token}, function(err, user){ // findOne :: mongoDB에 이미 있는 method
// 에러가 나면
if(err) return cb(err);
// 에러가 안나면
cb(null, user)
})
})
jwt.verify(token, 'secret', function (err, decode) {
user.findOne({ "_id": decode, "token": token }, function (err, user) {
if (err) return cb(err);
cb(null, user);
})
})
}
const User = mongoose.model('User', userSchema);
......
const express = require('express');
const { User } = require("../models/User");
const { auth } = require("../middleware/auth");
const router = express.Router();
const { Product } = require("../models/Product");
const multer = require('multer');
const { auth } = require("../middleware/auth");
var storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, 'uploads/') // 어느 폴더에 저장할건지
destination: (req, file, cb) => {
cb(null, 'uploads/')
},
filename: (req, file, cb) => {
cb(null, `${Date.now()}_${file.originalname}`)
},
filename: function (req, file, cb) {
cb(null, Date.now() + '_' + file.originalname) // 이미지 이름
}
})
var upload = multer({ storage: storage }).single("file");
router.post('/image', (req, res) => {
// 클라이언트로부터 받은 이미지 저장
upload(req, res, (err) => {
if (err) {
return req.json({ success: false, err })
}
return res.json({ success: true, filePath: res.req.file.path, fileName: res.req.file.filename })
fileFilter: (req, file, cb) => {
const ext = path.extname(file.originalname)
if (ext !== '.jpg' || ext !== '.png') {
return cb(res.status(400).end('JPG, PNG 확장자만 가능합니다.'), false);
}
cb(null, true)
}
)
})
var upload = multer({ storage: storage }).single("file")
router.post("/uploadImage", auth, (req, res) => {
upload(req, res, err => {
if (err) {
return res.json({ success: false, err })
}
return res.json({ success: true, image: res.req.file.path, fileName: res.req.file.filename })
})
});
router.post("/uploadProduct", auth, (req, res) => {
//save all the data we got from the client into the DB
const product = new Product(req.body)
product.save((err) => {
if (err) return res.status(400).json({ success: false, err })
return res.status(200).json({ success: true })
})
});
router.post("/getProducts", (req, res) => {
let order = req.body.order ? req.body.order : "desc";
let sortBy = req.body.sortBy ? req.body.sortBy : "_id";
let limit = req.body.limit ? parseInt(req.body.limit) : 100;
let skip = parseInt(req.body.skip);
let findArgs = {};
let term = req.body.searchTerm;
for (let key in req.body.filters) {
if (req.body.filters[key].length > 0) {
if (key === "price") {
findArgs[key] = {
$gte: req.body.filters[key][0],
$lte: req.body.filters[key][1]
}
} else {
findArgs[key] = req.body.filters[key];
}
}
}
console.log(findArgs)
if (term) {
Product.find(findArgs)
.find({ $text: { $search: term } })
.populate("writer")
.sort([[sortBy, order]])
.skip(skip)
.limit(limit)
.exec((err, products) => {
if (err) return res.status(400).json({ success: false, err })
res.status(200).json({ success: true, products, postSize: products.length })
})
} else {
Product.find(findArgs)
.populate("writer")
.sort([[sortBy, order]])
.skip(skip)
.limit(limit)
.exec((err, products) => {
if (err) return res.status(400).json({ success: false, err })
res.status(200).json({ success: true, products, postSize: products.length })
})
}
});
//?id=${productId}&type=single
//id=12121212,121212,1212121 type=array
router.get("/products_by_id", (req, res) => {
let type = req.query.type
let productIds = req.query.id
console.log("req.query.id", req.query.id)
if (type === "array") {
let ids = req.query.id.split(',');
productIds = [];
productIds = ids.map(item => {
return item
})
}
console.log("productIds", productIds)
//we need to find the product information that belong to product Id
Product.find({ '_id': { $in: productIds } })
.populate('writer')
.exec((err, product) => {
if (err) return res.status(400).send(err)
return res.status(200).send(product)
})
});
module.exports = router;
......
const express = require('express');
const router = express.Router();
const { User } = require("../models/User");
const { Product } = require('../models/Product');
const { auth } = require("../middleware/auth");
const router = express.Router();
const { Payment } = require('../models/Payment');
const async = require('async');
router.get("/auth", auth, (req, res) => {
res.status(200).json({
......@@ -10,9 +16,11 @@ router.get("/auth", auth, (req, res) => {
isAuth: true,
email: req.user.email,
name: req.user.name,
lastname: req.user.lastname,
address: req.user.address,
role: req.user.role,
image: req.user.image,
cart: req.user.cart,
history: req.user.history
});
});
......@@ -33,12 +41,12 @@ router.post("/login", (req, res) => {
if (!user)
return res.json({
loginSuccess: false,
message: "Auth failed, email not found"
message: "존재하지 않는 계정입니다."
});
user.comparePassword(req.body.password, (err, isMatch) => {
if (!isMatch)
return res.json({ loginSuccess: false, message: "Wrong password" });
return res.json({ loginSuccess: false, message: "비밀번호가 다릅니다." });
user.generateToken((err, user) => {
if (err) return res.status(400).send(err);
......@@ -63,4 +71,185 @@ router.get("/logout", auth, (req, res) => {
});
});
router.get('/addToCart', auth, (req, res) => {
User.findOne({ _id: req.user._id }, (err, userInfo) => {
let duplicate = false;
console.log(userInfo)
userInfo.cart.forEach((item) => {
if (item.id == req.query.productId) {
duplicate = true;
}
})
if (duplicate) {
User.findOneAndUpdate(
{ _id: req.user._id, "cart.id": req.query.productId },
{ $inc: { "cart.$.quantity": 1 } },
{ new: true },
(err, userInfo) => {
if (err) return res.json({ success: false, err });
res.status(200).json(userInfo.cart)
}
)
} else {
User.findOneAndUpdate(
{ _id: req.user._id },
{
$push: {
cart: {
id: req.query.productId,
quantity: 1,
date: Date.now()
}
}
},
{ new: true },
(err, userInfo) => {
if (err) return res.json({ success: false, err });
res.status(200).json(userInfo.cart)
}
)
}
})
});
router.get('/removeFromCart', auth, (req, res) => {
User.findOneAndUpdate(
{ _id: req.user._id },
{
"$pull":
{ "cart": { "id": req.query._id } }
},
{ new: true },
(err, userInfo) => {
let cart = userInfo.cart;
let array = cart.map(item => {
return item.id
})
Product.find({ '_id': { $in: array } })
.populate('writer')
.exec((err, cartDetail) => {
return res.status(200).json({
cartDetail,
cart
})
})
}
)
})
router.get('/userCartInfo', auth, (req, res) => {
User.findOne(
{ _id: req.user._id },
(err, userInfo) => {
let cart = userInfo.cart;
let array = cart.map(item => {
return item.id
})
Product.find({ '_id': { $in: array } })
.populate('writer')
.exec((err, cartDetail) => {
if (err) return res.status(400).send(err);
return res.status(200).json({ success: true, cartDetail, cart })
})
}
)
})
router.post('/successBuy', auth, (req, res) => {
let history = [];
let transactionData = {};
req.body.cartDetail.forEach((item) => {
history.push({
dateOfPurchase: Date.now(),
name: item.title,
id: item._id,
price: item.price,
quantity: item.quantity,
paymentId: req.body.paymentData.paymentID
})
})
// 페이팔에서 받아온 데이터 넣음
transactionData.user = {
id: req.user._id,
name: req.user.name,
address: req.user.address,
email: req.user.email
}
transactionData.data = req.body.paymentData;
transactionData.product = history
User.findOneAndUpdate(
{ _id: req.user._id },
{ $push: { history: history }, $set: { cart: [] } },
{ new: true },
(err, user) => {
if (err) return res.json({ success: false, err });
const payment = new Payment(transactionData)
payment.save((err, doc) => {
if (err) return res.json({ success: false, err });
let products = [];
doc.product.forEach(item => {
products.push({ id: item.id, quantity: item.quantity })
})
async.eachSeries(products, (item, callback) => {
Product.update(
{ _id: item.id },
{
$inc: {
"sold": item.quantity
}
},
{ new: false },
callback
)
}, (err) => {
if (err) return res.json({ success: false, err })
res.status(200).json({
success: true,
cart: user.cart,
cartDetail: []
})
})
})
}
)
})
router.get('/getHistory', auth, (req, res) => {
User.findOne(
{ _id: req.user._id },
(err, doc) => {
let history = doc.history;
if (err) return res.status(400).send(err)
return res.status(200).json({ success: true, history })
}
)
})
module.exports = router;
......