summaryrefslogtreecommitdiffstats
path: root/components
diff options
context:
space:
mode:
authorWes Bos <wesbos@gmail.com>2017-08-25 09:33:53 -0400
committerWes Bos <wesbos@gmail.com>2017-08-25 09:33:53 -0400
commit7af74ff8988961c988f03c95961b70c2918521ae (patch)
treed73cd0dd94751b76595b7febcae4162811c2040b /components
parent416c2cbae0e69b724876d232bf813eefd7550174 (diff)
yay
Diffstat (limited to 'components')
-rw-r--r--components/CreateItem.js7
-rw-r--r--components/Header.js28
-rw-r--r--components/Items.js36
-rw-r--r--components/LoginAuth0.js58
-rw-r--r--components/Meta.js16
-rw-r--r--components/Nav.js9
-rw-r--r--components/OrderList.js52
-rw-r--r--components/Page.js25
-rw-r--r--components/Signup.js76
-rw-r--r--components/TakeMyMoney.js38
10 files changed, 320 insertions, 25 deletions
diff --git a/components/CreateItem.js b/components/CreateItem.js
index b29b210..3b86f2c 100644
--- a/components/CreateItem.js
+++ b/components/CreateItem.js
@@ -8,6 +8,8 @@ class CreateLink extends Component {
description: '',
title: '',
image: '',
+ price: 0,
+ fullPrice: 0,
loading: false
}
@@ -43,6 +45,7 @@ class CreateLink extends Component {
<p>Title
<input value={this.state.title} onChange={(e) => this.setState({ title: e.target.value })} type='text' placeholder='A description for the link'/>
</p>
+ <label>Price<input type="number" min="0" value={this.state.price} onChange={(e) => this.setState({ price: e.target.value })} /></label>
<textarea
value={this.state.description}
onChange={(e) => this.setState({ description: e.target.value })}
@@ -58,7 +61,7 @@ class CreateLink extends Component {
_createLink = async (e) => {
e.preventDefault();
// pull the values from state
- const { description, title, image } = this.state
+ const { description, title, image, price, fullPrice } = this.state;
// create a mutation
// TODO: handle any errors
// turn loading on
@@ -68,6 +71,8 @@ class CreateLink extends Component {
variables: {
description,
title,
+ price: parseInt(price),
+ fullPrice,
imageId: image
}
});
diff --git a/components/Header.js b/components/Header.js
new file mode 100644
index 0000000..52aeef9
--- /dev/null
+++ b/components/Header.js
@@ -0,0 +1,28 @@
+import { Component } from 'react'
+import { graphql, compose } from 'react-apollo'
+import { CURRENT_USER_QUERY } from '../queries';
+
+class Header extends Component {
+
+ componentDidMount() {
+ // This fetches the new data, but doesn't populate the user via props
+ // this.props.currentUserQuery.refetch();
+ // This fetches the new data, and populates the user via props
+ setTimeout(this.props.currentUserQuery.refetch, 1);
+ }
+
+ render() {
+ console.log(this.props.currentUserQuery.user);
+ const user = this.props.currentUserQuery.user || {};
+ const { email = '' } = user;
+
+ return (
+ <div>
+ <p>{email} I'm the header!</p>
+ </div>
+ )
+ }
+}
+
+const userEnhancer = graphql(CURRENT_USER_QUERY, { name: 'currentUserQuery' });
+export default compose(userEnhancer)(Header)
diff --git a/components/Items.js b/components/Items.js
index 35db906..7d07643 100644
--- a/components/Items.js
+++ b/components/Items.js
@@ -1,10 +1,11 @@
-import React, { Component } from 'react'
+import { Component } from 'react'
import { graphql, compose } from 'react-apollo'
import UpdateItem from './UpdateItem';
import Link from 'next/link';
import styled from 'styled-components';
import TakeMyMoney from './TakeMyMoney';
import formatMoney from '../lib/formatMoney';
+import makeImage from '../lib/image';
import { ALL_ITEMS_QUERY, DELETE_ITEM_MUTATION } from '../queries';
@@ -12,6 +13,22 @@ const Title = styled.h1`
font-size: 50px;
`;
+
+
+const Items = styled.div`
+ display: grid;
+ grid-template-columns: repeat(4, calc(25% - 20px));
+ grid-gap: 20px;
+`;
+
+const Item = styled.div`
+ background: #f3f3f3;
+ padding: 20px;
+ img {
+ width: 100%;
+ }
+`;
+
class ItemList extends Component {
render() {
@@ -31,12 +48,11 @@ class ItemList extends Component {
const itemsToRender = this.props.allLinksQuery.allItems
return (
- <div>
+ <Items>
<Title>Items For Sale</Title>
{itemsToRender.map((item,i) => (
- <div className="item" key={i}>
- <hr/>
- { item.image ? <img src={`https://images.graph.cool/v1/cj5xz8szs28930145gct82bdj/${item.image.secret}/300x300`} /> : null }
+ <Item className="item" key={i}>
+ { item.image ? <img src={makeImage(item.image)} /> : null }
<h3>{item.title}</h3>
<p>{item.description}</p>
<Link href={{
@@ -47,21 +63,19 @@ class ItemList extends Component {
</Link>
<TakeMyMoney
+ id={item.id}
amount={item.price}
name={item.title} // the pop-in header title
description={item.description} // the pop-in header subtitle
- image={`https://images.graph.cool/v1/cj5xz8szs28930145gct82bdj/${item.image.secret}/300x300`}
+ image={makeImage(item.image)}
>
<button>Buy for {formatMoney(item.price)}</button>
</TakeMyMoney>
-
- <UpdateItem id={item.id} />
-
<button onClick={() => this.props.removeItemMutation({ variables: { id: item.id }})}>&times; Delete item</button>
- </div>
+ </Item>
))}
- </div>
+ </Items>
)
}
diff --git a/components/LoginAuth0.js b/components/LoginAuth0.js
new file mode 100644
index 0000000..d5293b5
--- /dev/null
+++ b/components/LoginAuth0.js
@@ -0,0 +1,58 @@
+import { Component, PropTypes } from 'react'
+import Auth0Lock from 'auth0-lock'
+
+class LoginAuth0 extends Component {
+
+ constructor (props) {
+ super(props)
+ if(typeof window === 'undefined') return;
+ const redirectUrl = `http://localhost:3000/signup`;
+ console.log(redirectUrl);
+ this._lock = new Auth0Lock('l851ev2q8X48wf56eGLjIWFbMwwbvWPE', 'wesbos.auth0.com', {
+ auth: {
+ redirect: false,
+ }
+ });
+ }
+
+ createUser = () => {
+ const variables = {
+ idToken: window.localStorage.getItem("auth0IdToken"),
+ emailAddress: 'wesbos@gmail.com',
+ name: 'Hardcoded Wes'
+ };
+ // TODO - make a createUser function
+ this.props
+ .createUser({ variables })
+ .then(response => {
+ this.props.history.replace("/");
+ })
+ .catch(e => {
+ console.error(e);
+ this.props.history.replace("/");
+ });
+ };
+
+ componentDidMount() {
+ console.log('MOUNT');
+ this._lock.on('authenticated', (authResult) => {
+ console.log('HIIIIIIII')
+ window.localStorage.setItem('auth0IdToken', authResult.idToken)
+ console.log('Done!', authResult);
+ })
+ }
+
+ _showLogin = () => {
+ this._lock.show()
+ }
+
+ render() {
+ return (
+ <div>
+ <button onClick={this._showLogin}>Log in with Auth0 </button>
+ </div>
+ )
+ }
+}
+
+export default LoginAuth0;
diff --git a/components/Meta.js b/components/Meta.js
new file mode 100644
index 0000000..d851946
--- /dev/null
+++ b/components/Meta.js
@@ -0,0 +1,16 @@
+import Head from 'next/head'
+import Router from 'next/router'
+import Nav from './Nav';
+
+export default () => (
+ <div>
+ <Head>
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
+ <meta charSet="utf-8" />
+ <Nav/>
+ <link rel="shortcut icon" href="https://wesbos.com/wp-content/themes/wb2014/i/crown-yellow-small.png" />
+ <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css"/>
+ <title>Sick Fits</title>
+ </Head>
+ </div>
+)
diff --git a/components/Nav.js b/components/Nav.js
new file mode 100644
index 0000000..2e32a1c
--- /dev/null
+++ b/components/Nav.js
@@ -0,0 +1,9 @@
+import Link from 'next/link'
+
+export default () => (
+ <ul>
+ <Link href="/"><a>Home</a></Link>
+ <Link href="/signup/"><a>Signup</a></Link>
+ <Link href="/orders/"><a>Orders</a></Link>
+ </ul>
+)
diff --git a/components/OrderList.js b/components/OrderList.js
new file mode 100644
index 0000000..c33f0b9
--- /dev/null
+++ b/components/OrderList.js
@@ -0,0 +1,52 @@
+import { Component } from 'react';
+import withData from '../lib/withData';
+import Items from '../components/Items';
+import CreateItem from '../components/CreateItem';
+import Signup from '../components/Signup';
+import LoginAuth0 from '../components/LoginAuth0';
+import Page from '../components/Page';
+import { USER_ORDERS_QUERY } from '../queries';
+import { graphql, compose } from 'react-apollo'
+import has from 'lodash.has';
+import get from 'lodash.get';
+import formatMoney from '../lib/formatMoney';
+import makeImage from '../lib/image';
+
+class OrderList extends Component {
+ componentDidMount() {
+ console.log('Mounting!');
+ }
+ render() {
+
+ if(this.props.loading) {
+ return <p>Loading...</p>
+ }
+
+ if(this.props.error) {
+ return <p>Error...</p>
+ }
+
+ if(!has(this.props, 'userOrdersQuery.user.orders')) {
+ return <p>Don't have it yet!</p>
+ }
+
+ const orders = this.props.userOrdersQuery.user.orders;
+
+ console.log(orders);
+ return (
+ <div>
+ <h2>You have {orders.length} Orders</h2>
+ <ul>
+ {orders.map(order => <li key={order.id}>
+ <img src={makeImage(order.item.image)} alt=""/>
+ <h3>{order.item.title} ({formatMoney(order.amount)}) </h3>
+ <p>{order.item.description}</p>
+ </li>)}
+ </ul>
+ </div>
+ )
+ }
+}
+
+const ordersEnhancer = graphql(USER_ORDERS_QUERY, { name: 'userOrdersQuery' });
+export default compose(ordersEnhancer)(OrderList)
diff --git a/components/Page.js b/components/Page.js
new file mode 100644
index 0000000..1b07fe6
--- /dev/null
+++ b/components/Page.js
@@ -0,0 +1,25 @@
+import Header from './Header'
+import Meta from './Meta'
+import withData from '../lib/withData';
+import Nav from './Nav';
+import styled from 'styled-components';
+
+const StyledPage = styled.div`
+ font-family: sans-serif;
+ color: #303030;
+ background: #efc600;
+ padding: 100px;
+`;
+
+const Page = ({ children }) => (
+ <StyledPage className="main">
+ <Meta />
+ <Header />
+ <Nav></Nav>
+ <div>
+ { children }
+ </div>
+ </StyledPage>
+)
+
+export default withData(Page);
diff --git a/components/Signup.js b/components/Signup.js
new file mode 100644
index 0000000..ab0a498
--- /dev/null
+++ b/components/Signup.js
@@ -0,0 +1,76 @@
+import React, { Component } from 'react'
+import { graphql, gql } from 'react-apollo'
+import { CREATE_USER_MUTATION } from '../queries';
+
+class Signup extends Component {
+
+ constructor() {
+ super();
+ const idToken = typeof window !== 'undefined' ? localStorage.getItem('auth0IdToken') || '' : '';
+ this.state = {
+ email: '',
+ name: '',
+ idToken,
+ error: undefined
+ }
+
+ }
+
+
+ render() {
+ return (
+ <div>
+ { this.state.loading ? 'LOADING...' : 'Ready!' }
+
+ { this.state.error ? <p>{this.state.error.message}</p> : '' }
+
+ <form onSubmit={this._createUser}>
+ <p>Email
+ <input value={this.state.email} onChange={(e) => this.setState({ email: e.target.value })} type='text' placeholder='email'/>
+ </p>
+
+ <p>Name
+ <input value={this.state.name} onChange={(e) => this.setState({ name: e.target.value })} type='text' placeholder='name'/>
+ </p>
+
+ <p>idToken
+ <input disabled value={this.state.idToken} onChange={(e) => this.setState({ idToken: e.target.value })} type='text' placeholder='name'/>
+ </p>
+
+ <button type="submit">Submit</button>
+ </form>
+ </div>
+ )
+ }
+
+ _createUser = async (e) => {
+ e.preventDefault();
+ // pull the values from state
+ const { email, name, idToken } = this.state
+ // create a mutation
+ // TODO: handle any errors
+ // turn loading on
+ this.setState({ loading: true });
+ console.log(name, email, idToken);
+ try {
+ const res = await this.props.createUserMutation({
+ // pass in those variables from state
+ variables: { name, email, idToken }
+ });
+ } catch(error) {
+ this.setState({ error });
+ console.dir(error);
+ }
+ this.setState({ loading: false });
+ }
+}
+// When we submit this mutation, we need to update our store - we have a few ways to do that:
+// One - we can go nucular and run refetchQueries() which will just go get everything - this is easy, but at the cost of efficiency.
+
+
+export default graphql(CREATE_USER_MUTATION, { name: 'createUserMutation', options: {
+ // Easy, but slow
+ // refetchQueries: ['AllLinksQuery']
+ // This is much Better / efficient
+ // Notice how the variable is called createItem - that is because createItem is the name of the query!
+ } })(Signup)
diff --git a/components/TakeMyMoney.js b/components/TakeMyMoney.js
index 143f990..d68cca1 100644
--- a/components/TakeMyMoney.js
+++ b/components/TakeMyMoney.js
@@ -1,31 +1,43 @@
import { Component } from 'react';
import StripeCheckout from 'react-stripe-checkout';
-import { CREATE_ORDER_MUTATION } from '../queries';
-import { graphql } from 'react-apollo';
+import { CREATE_ORDER_MUTATION, CURRENT_USER_QUERY } from '../queries';
+import { graphql, compose } from 'react-apollo';
class TakeMyMoney extends Component {
onToken = async (res) => {
const token = res.id;
+ const userId = this.props.currentUserQuery.user.id;
+ const itemId = this.props.id;
console.log(`Going to make a purchase with ${token}`);
- const charge = await this.props.createOrder({ variables: { token }});
+ console.log(`THe person that bought this was ${userId}`)
+ console.log(`The item id is ${itemId}`)
+ const charge = await this.props.createOrder({ variables: { token, userId, itemId }});
alert(`Back from the charge! ${charge.id}`);
console.log(charge);
}
render() {
+ const user = this.props.currentUserQuery.user || {};
+ const email = user.email || '';
return (
- // ...
- <StripeCheckout
- {...this.props}
- token={this.onToken}
- stripeKey="pk_lclTtThFp8CnO3QtEZSd8HA9mFUps"
- currency="USD"
- >
- {this.props.children}
- </StripeCheckout>
+ <div>
+ <StripeCheckout
+ amount={this.props.amount}
+ name={this.props.name}
+ description={this.props.description}
+ token={this.onToken}
+ stripeKey="pk_lclTtThFp8CnO3QtEZSd8HA9mFUps"
+ currency="USD"
+ email={email}
+ >
+ {this.props.children}
+ </StripeCheckout>
+ </div>
)
}
}
-export default graphql(CREATE_ORDER_MUTATION, { name: 'createOrder' })(TakeMyMoney);
+const userEnhancer = graphql(CURRENT_USER_QUERY, { name: 'currentUserQuery' });
+const createOrderEnhancer = graphql(CREATE_ORDER_MUTATION, { name: 'createOrder' });
+export default compose(userEnhancer, createOrderEnhancer)(TakeMyMoney);