|
@@ -43,7 +43,7 @@ const jwtDecode = token => {
|
|
|
return JSON.parse(base64Token)
|
|
|
}
|
|
|
catch (e) {
|
|
|
- console.log('Лажа, Бро ' + e);
|
|
|
+ console.log(e);
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -177,7 +177,7 @@ actionPromise('rootCats', gql(`query {
|
|
|
}
|
|
|
}`))
|
|
|
|
|
|
-const actionGoodById = (_id) => actionPromise("goodById1", gql(
|
|
|
+const actionGoodById = (_id) => actionPromise("goodById", gql(
|
|
|
`query goodById($q: String) {
|
|
|
GoodFindOne(query: $q) {
|
|
|
_id name description price categories {
|
|
@@ -193,6 +193,79 @@ const actionGoodById = (_id) => actionPromise("goodById1", gql(
|
|
|
)
|
|
|
);
|
|
|
|
|
|
+const actionGoodFind = (word) => (
|
|
|
+ actionPromise('goodFind', gql(`query goodById($q: String) {
|
|
|
+ GoodFind(query: $q) {
|
|
|
+ _id name price description images {
|
|
|
+ url
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }`, {q: JSON.stringify([
|
|
|
+ {
|
|
|
+ $or: [{title: `/${word}/`}, {description: `/${word}/`}, {name: `/${word}/`}]
|
|
|
+ },
|
|
|
+ {
|
|
|
+ sort: [{title: 1}]
|
|
|
+ }
|
|
|
+ ])
|
|
|
+ }
|
|
|
+ ))
|
|
|
+)
|
|
|
+
|
|
|
+const actionReg = (login, password) => {
|
|
|
+ return actionPromise(
|
|
|
+ "reg",
|
|
|
+ gql(
|
|
|
+ `mutation reg($l: String, $p: String){
|
|
|
+ UserUpsert(user: {login: $l,
|
|
|
+ password:$p
|
|
|
+ }){
|
|
|
+ _id login
|
|
|
+ }
|
|
|
+ }`,
|
|
|
+ { l: login, p: password }
|
|
|
+ )
|
|
|
+ );
|
|
|
+};
|
|
|
+
|
|
|
+const actionFullReg = (login, password) =>
|
|
|
+ async function a(dispatch) {
|
|
|
+ try {
|
|
|
+ await dispatch(actionReg(login, password));
|
|
|
+ } catch (e) {
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ await dispatch(actionFullLogin(login, password));
|
|
|
+ }
|
|
|
+
|
|
|
+const actionNewOrder = () => async (dispatch, getState) => {
|
|
|
+ let { cart } = getState();
|
|
|
+ const orderGoods = Object.entries(cart).map(([_id, { count }]) => ({
|
|
|
+ good: { _id },
|
|
|
+ count,
|
|
|
+ }));
|
|
|
+
|
|
|
+ let result = await dispatch(
|
|
|
+ actionPromise(
|
|
|
+ "order",gql(
|
|
|
+ `mutation newOrder($order:OrderInput){
|
|
|
+ OrderUpsert(order:$order)
|
|
|
+ { _id total}
|
|
|
+ }`,
|
|
|
+ { order: {orderGoods} }) )
|
|
|
+ );
|
|
|
+};
|
|
|
+
|
|
|
+const actionGetOrdersHistory = () => actionPromise("orderHistory", gql(`query o {
|
|
|
+ OrderFind(query: "[{},{\\"sort\\": [{\\"_id\\": -1}]}]") {
|
|
|
+ createdAt
|
|
|
+ orderGoods{
|
|
|
+ price, total, count
|
|
|
+ good{_id, name, images{_id, url}}
|
|
|
+ }, total
|
|
|
+ }
|
|
|
+ }`)
|
|
|
+)
|
|
|
|
|
|
const store = createStore(combineReducers({ promise: promiseReducer,
|
|
|
auth: authReducer,
|
|
@@ -203,7 +276,7 @@ store.dispatch(actionCatById());
|
|
|
|
|
|
const defaultRootCats = [
|
|
|
{_id: '5dc49f4d5df9d670df48cc64', name: 'Airconditions'},
|
|
|
- {_id: '5dc458985df9d670df48cc47', name: ' Smartphones'},
|
|
|
+ {_id: '5dc458985df9d670df48cc47', name: 'Smartphones'},
|
|
|
{_id: '5dc4b2553f23b553bf354101', name: 'Крупная бытовая техника'},
|
|
|
{_id: '5dcac1b56d09c45440d14cf8', name: 'Макароны'},
|
|
|
{_id: '5dcac6cf6d09c45440d14cfd', name: 'Drinks'},
|
|
@@ -219,7 +292,7 @@ const RootCategory = ({cat: {_id, name}={}}) =>
|
|
|
|
|
|
const RootCategories = ({cats=defaultRootCats}) => (
|
|
|
<ul className='RootCategories'>
|
|
|
- {cats.map(cat => <RootCategory cat ={cat} />)}
|
|
|
+ {cats.map(cat => <RootCategory cat = {cat} />)}
|
|
|
</ul>
|
|
|
)
|
|
|
|
|
@@ -227,18 +300,36 @@ const CRootCategories = connect(state => ({cats: state.promise.rootCats?.payload
|
|
|
|
|
|
const GoodCard = ({good: {_id, name, price, images}={}, onCartAdd}) =>
|
|
|
<div className='GoodCard'>
|
|
|
- <Link to={`/good/${_id}`} className="Good"><h2>{name}</h2></Link>
|
|
|
+ <Link to={`/good/${_id}`}><h2>{name}</h2></Link>
|
|
|
{images && images[0] && images[0].url && <img src={backURL + '/' + images[0].url} />}
|
|
|
- <strong>{price}</strong>
|
|
|
+ <strong>{price} ₴</strong>
|
|
|
<button onClick={() => onCartAdd({_id, name, price, images})}>+</button>
|
|
|
</div>
|
|
|
|
|
|
-const CGoodCard = connect(null, {onCartAdd: actionCartAdd})(GoodCard)
|
|
|
+const CGoodCard = connect(null, {onCartAdd: actionCartAdd})(GoodCard);
|
|
|
+
|
|
|
+const Search = ({ onSearch }) => {
|
|
|
+ const [value, setValue] = useState('');
|
|
|
+
|
|
|
+ return (
|
|
|
+ <div>
|
|
|
+ <input type="text" placeholder='Поиск...' value={value} onChange={e => setValue(e.target.value)}/>
|
|
|
+ <button onClick={() => onSearch(value)}>Найти</button>
|
|
|
+ </div>
|
|
|
+ )
|
|
|
+}
|
|
|
+
|
|
|
+const CSearch = connect(null, {onSearch: actionGoodFind})(Search);
|
|
|
+
|
|
|
+const SubCategories = ({cats}) =>
|
|
|
+ <>
|
|
|
+ {cats.map(cat => <RootCategory cat={cat}/>)}
|
|
|
+ </>
|
|
|
|
|
|
-const Category = ({cat: {_id, name, goods, subCategories}=actionCatById}) =>
|
|
|
+const Category = ({cat: {name, goods, subCategories}}) =>
|
|
|
<div className='Category'>
|
|
|
<h1>{name}</h1>
|
|
|
- {subCategories && <subCategories cats={subCategories} />}
|
|
|
+ {subCategories && <SubCategories cats={subCategories} />}
|
|
|
{(goods || []).map(good => <CGoodCard good={good} />)}
|
|
|
</div>
|
|
|
|
|
@@ -259,7 +350,7 @@ const CKoshik = connect(({cart}) => ({cart}))(Koshik)
|
|
|
const GoodInCart = ({item: {count, good: {_id, name, price, images}}, onCartChange, onCartRemove}) => (
|
|
|
<div className='GoodInCart'>
|
|
|
<h2>{name}</h2>
|
|
|
- <h2>{count}</h2>
|
|
|
+ <strong>{count}</strong> шт. на <strong>{price*count} ₴</strong>
|
|
|
{images && images[0] && images[0].url && <img src={backURL + '/' + images[0].url} />}
|
|
|
<strong>{price}</strong>
|
|
|
<br/>
|
|
@@ -269,22 +360,24 @@ const GoodInCart = ({item: {count, good: {_id, name, price, images}}, onCartCha
|
|
|
</div>
|
|
|
)
|
|
|
|
|
|
-const Cart = ({cart, onCartClear}) => (
|
|
|
+const CGoodInCart = connect(null, { onCartChange: actionCartChange,
|
|
|
+ onCartRemove: actionCartRemove,
|
|
|
+ onCartAdd: actionCartAdd
|
|
|
+ })(GoodInCart)
|
|
|
+
|
|
|
+const Cart = ({cart, onCartClear, onNewOrder}) => (
|
|
|
<div className='Cart'>
|
|
|
{cart.length === 0 ? <></> : <button onClick={() => onCartClear()}>Очистить корзину</button>}
|
|
|
{cart.map(item => <CGoodInCart item={item} />)}
|
|
|
- {cart.length === 0 ? <></> : <button>Оформить заказ</button>}
|
|
|
+ {cart.length === 0 ? <></> : <button onClick={() => {onNewOrder(); onCartClear()}}>Оформить заказ</button>}
|
|
|
</div>
|
|
|
)
|
|
|
|
|
|
const CCart = connect(state => ({cart: Object.values(state.cart) || []}),
|
|
|
- { onCartClear: actionCartClear})(Cart);
|
|
|
+ { onCartClear: actionCartClear, onNewOrder: actionNewOrder})(Cart);
|
|
|
|
|
|
-const CGoodInCart = connect(null, { onCartChange: actionCartChange,
|
|
|
- onCartRemove: actionCartRemove,
|
|
|
- onCartAdd: actionCartAdd
|
|
|
- })(GoodInCart)
|
|
|
|
|
|
+
|
|
|
// const LowerCase = ({children}) => (
|
|
|
// <>{children.toLowerCase()}</>
|
|
|
// )
|
|
@@ -372,6 +465,26 @@ const CGoodInCart = connect(null, { onCartChange: actionCartChange,
|
|
|
// </>
|
|
|
// )
|
|
|
// }
|
|
|
+const LoginButtons = ({onLogout, history, token}) => {
|
|
|
+
|
|
|
+ return (
|
|
|
+ <>
|
|
|
+ {!token ?
|
|
|
+ ( <div className='loginButtons'>
|
|
|
+ <Link to='/login'><button className='btn' onClick={() => history.push('/')}>Вход</button></Link>
|
|
|
+ <Link to='/registration'><button className='btn'>Регистрация</button></Link>
|
|
|
+ </div>) :
|
|
|
+ (<div className='LoginButtons'>
|
|
|
+ <strong>{`Привет, ${JSON.parse(atob(token.split(".")[1])).sub.login}!`}</strong>
|
|
|
+ <Link to='/orderhistory'><button className='exit'>История заказов</button></Link>
|
|
|
+ <button className='exit' onClick={() => {onLogout(); history.push('/')}}>Выйти</button>
|
|
|
+ </div>)
|
|
|
+ }
|
|
|
+ </>
|
|
|
+ )
|
|
|
+}
|
|
|
+
|
|
|
+const CLoginButtons = connect(state => ({token: state.auth.token}), {onLogout: actionAuthLogout})(LoginButtons)
|
|
|
|
|
|
const LoginForm = ({onLogin}) => {
|
|
|
|
|
@@ -382,13 +495,30 @@ const LoginForm = ({onLogin}) => {
|
|
|
<div className='LoginForm'>
|
|
|
<input type="text" value={login} onChange={e => setLogin(e.target.value)} style={{border: (login.length === 0) ? '1px solid red' : ''}}/>
|
|
|
<input type="password" value={password} onChange={e => setPassword(e.target.value)} style={{border: (password.length === 0) ? '1px solid red' : ''}}/>
|
|
|
- <button className='loginBtn' onClick={() => onLogin(login,password)} disabled={login.length == 0 || password.length == 0}>LOGIN</button>
|
|
|
+ <button className='link' onClick={() => onLogin(login,password)} disabled={login.length == 0 || password.length == 0}>LOGIN</button>
|
|
|
</div>
|
|
|
)
|
|
|
}
|
|
|
|
|
|
const CLoginForm = connect(null, {onLogin: actionFullLogin})(LoginForm)
|
|
|
|
|
|
+const RegForm = ({ onReg }) => {
|
|
|
+ const [login, setLogin] = useState("");
|
|
|
+ const [password, setPassword] = useState("");
|
|
|
+
|
|
|
+ return (
|
|
|
+ <div className='link'>
|
|
|
+ {login === "" ? (<input style={{ border: "1px solid red" }} onChange={(e) => setLogin(e.target.value)}></input>)
|
|
|
+ : (<input value={login} onChange={(e) => setLogin(e.target.value)} />)}
|
|
|
+ {password === "" ? (<input style={{ border: "1px solid red" }} onChange={(e) => setPassword(e.target.value)}></input>)
|
|
|
+ : (<input value={password} onChange={(e) => setPassword(e.target.value)} />)}
|
|
|
+ <button onClick={() => {onReg(login, password); history.push('/')}}>Register</button>
|
|
|
+ </div>
|
|
|
+ );
|
|
|
+};
|
|
|
+
|
|
|
+const CRegForm = connect(null,{onReg: actionFullReg})(RegForm)
|
|
|
+
|
|
|
const Logo = ({logo}) => (
|
|
|
<a href='#' className="Logo">
|
|
|
<img src={logo} />
|
|
@@ -400,6 +530,12 @@ const Header = ({logo=logoDefault}) => (
|
|
|
<h1 className='name'>S T O R E</h1>
|
|
|
<Logo logo={logo} />
|
|
|
<CKoshik />
|
|
|
+ <CSearch />
|
|
|
+ <Switch>
|
|
|
+ <Route path="/login" component={CLoginForm}/>
|
|
|
+ <Route path="/registration" component={CRegForm}/>
|
|
|
+ <Route path='*' component={CLoginButtons} />
|
|
|
+ </Switch>
|
|
|
</header>
|
|
|
)
|
|
|
|
|
@@ -447,7 +583,6 @@ const PageGood = ({match: {params: { _id }}, getData}) => {
|
|
|
getData(_id);
|
|
|
}, [_id]);
|
|
|
return <CGood />;
|
|
|
- // return <h1>{console.log(_id)}</h1>;
|
|
|
};
|
|
|
|
|
|
const CPageGood = connect(null, { getData: actionGoodById })(PageGood);
|
|
@@ -455,19 +590,19 @@ const CPageGood = connect(null, { getData: actionGoodById })(PageGood);
|
|
|
const Page404 = () => <h1>PAGE НЭМА</h1>
|
|
|
|
|
|
const Main = () =>
|
|
|
-<main>
|
|
|
- <Aside />
|
|
|
- <Content>
|
|
|
- <Redirect from='/main' to='/'/>
|
|
|
- <Switch>
|
|
|
- <Route path='/' component={PageMain} exact/>
|
|
|
- <Route path="/category/:_id" component={CPageCategory}/>
|
|
|
- <Route path="/good/:_id" component={CPageGood}/>
|
|
|
- <Route path="/korzina" component={CCart}/>
|
|
|
- <Route path='*' component={Page404} />
|
|
|
- </Switch>
|
|
|
- </Content>
|
|
|
-</main>
|
|
|
+ <main>
|
|
|
+ <Aside />
|
|
|
+ <Content>
|
|
|
+ <Redirect from='/main' to='/'/>
|
|
|
+ <Switch>
|
|
|
+ <Route path='/' component={PageMain} exact/>
|
|
|
+ <Route path="/category/:_id" component={CPageCategory}/>
|
|
|
+ <Route path="/good/:_id" component={CPageGood}/>
|
|
|
+ <Route path="/korzina" component={CCart}/>
|
|
|
+ <Route path='*' component={Page404} />
|
|
|
+ </Switch>
|
|
|
+ </Content>
|
|
|
+ </main>
|
|
|
|
|
|
|
|
|
const Footer = () => (
|
|
@@ -502,7 +637,6 @@ function App() {
|
|
|
<Router history={history}>
|
|
|
<Provider store={store}>
|
|
|
<div className="App">
|
|
|
- <CLoginForm onLogin={(l,p) => console.log(l,p)} />
|
|
|
{/* <RGBInput /> */}
|
|
|
{/* <Input /> */}
|
|
|
{/* {list} */}
|