diff options
| author | Wes Bos <wesbos@gmail.com> | 2018-02-15 16:59:58 -0500 |
|---|---|---|
| committer | Wes Bos <wesbos@gmail.com> | 2018-02-15 16:59:58 -0500 |
| commit | 8f2c595eca30e2d7138c8e8d6685774a8f44e55d (patch) | |
| tree | 3408b9c8eb3b0ea43cb72e13e0bd6393ab5bac61 /frontend/components | |
| parent | a09b01abf7c03e6b7e43f2175e5a34501808821b (diff) | |
omg
Diffstat (limited to 'frontend/components')
| -rw-r--r-- | frontend/components/AddToCart.js | 1 | ||||
| -rw-r--r-- | frontend/components/Cart.js | 136 | ||||
| -rw-r--r-- | frontend/components/CartItem.js | 39 | ||||
| -rw-r--r-- | frontend/components/CartList.js | 32 | ||||
| -rw-r--r-- | frontend/components/CreateItem.js | 3 | ||||
| -rw-r--r-- | frontend/components/Header.js | 70 | ||||
| -rw-r--r-- | frontend/components/Item.js | 79 | ||||
| -rw-r--r-- | frontend/components/Items.js | 6 | ||||
| -rw-r--r-- | frontend/components/LoginAuth0.js | 76 | ||||
| -rw-r--r-- | frontend/components/Meta.js | 3 | ||||
| -rw-r--r-- | frontend/components/Nav.js | 98 | ||||
| -rw-r--r-- | frontend/components/OrderList.js | 3 | ||||
| -rw-r--r-- | frontend/components/Page.js | 62 | ||||
| -rw-r--r-- | frontend/components/Pagination.js | 11 | ||||
| -rw-r--r-- | frontend/components/RemoveFromCart.js | 16 | ||||
| -rw-r--r-- | frontend/components/Search.js | 81 | ||||
| -rw-r--r-- | frontend/components/SingleItem.js | 4 | ||||
| -rw-r--r-- | frontend/components/TakeMyMoney.js | 37 | ||||
| -rw-r--r-- | frontend/components/ToggleCart.js | 22 | ||||
| -rw-r--r-- | frontend/components/styles/Title.js | 20 |
20 files changed, 482 insertions, 317 deletions
diff --git a/frontend/components/AddToCart.js b/frontend/components/AddToCart.js index 5a11513..6cab321 100644 --- a/frontend/components/AddToCart.js +++ b/frontend/components/AddToCart.js @@ -7,7 +7,6 @@ import { CURRENT_USER_QUERY, SINGLE_ITEM_QUERY } from '../queries'; import { removeFromCartEnhancer, userEnhancer, addtoCartEnhancer } from '../enhancers/enhancers'; console.log(addtoCartEnhancer); -import makeImage from '../lib/image'; const JumpImg = styled.img` border: 0 solid black; diff --git a/frontend/components/Cart.js b/frontend/components/Cart.js index 72c34ae..78e0d88 100644 --- a/frontend/components/Cart.js +++ b/frontend/components/Cart.js @@ -1,9 +1,14 @@ import { Component } from 'react'; import { graphql, compose } from 'react-apollo'; import styled from 'styled-components'; -import { networkEnhancer, userEnhancer, uiEnhancer } from '../enhancers/enhancers'; +import Title from './styles/Title'; +import { updateUIEnhancer, userEnhancer, uiEnhancer } from '../enhancers/enhancers'; import RemoveFromCart from './RemoveFromCart'; import TakeMyMoney from './TakeMyMoney'; +import ToggleCart from './ToggleCart'; +import formatMoney from '../lib/formatMoney'; + +import CartItem from './CartItem'; const CartStyles = styled.div` padding: 20px; @@ -13,75 +18,104 @@ const CartStyles = styled.div` height: 100%; top: 0; right: 0; + width: 40%; + min-width: 500px; bottom: 0; transform: translateX(100%); transition: all 0.3s; box-shadow: 0 0 10px 3px rgba(0, 0, 0, 0.2); z-index: 5; + display: grid; + grid-template-rows: auto 1fr auto; ${props => props.open && `transform: translateX(0);`}; - .toggleOpen { - position: absolute; - top: 0; - left: 0; - transform: translateX(-100%); + header { + border-bottom: 5px solid ${props => props.theme.black}; + margin-bottom: 2rem; + padding-bottom: 2rem; + } + footer { + border-top: 10px double ${props => props.theme.black}; + margin-top: 2rem; + padding-top: 2rem; + display: grid; + grid-template-columns: auto auto; + align-items: center; + font-size: 3rem; + font-weight: 900; + p { + margin: 0; + } } `; +const CartUl = styled.ul` + margin: 0; + padding: 0; + list-style: none; + overflow: scroll; +`; + +const Supreme = styled.h3` + background: ${props => props.theme.red}; + color: white; + display: inline-block; + padding: 4px 5px; + transform: skew(-3deg); + margin: 0; + font-size: 4rem; +`; + +const CloseButton = styled.button` + background: black; + color: white; + font-size: 3rem; + border: 0; + position: absolute; + z-index: 2; + right: 0; +`; + class Cart extends Component { - state = { - open: true, - }; componentDidMount() { - console.log('refetching..'); - setTimeout(this.props.currentUser.refetch, 10); + // TODO listen for escape + } + + componentWillUnmount() { + // TODO unlisten for escape } - toggleOpen = () => { - this.setState({ open: !this.state.open }); - }; - handleClick = () => { - console.log('CLICK'); - this.props.updateNetworkStatus(!this.props.ui.networkStatus.isConnected); - }; render() { - if (!this.props.currentUser.me) { - return null; - } const { me } = this.props.currentUser; + if (!me) return null; + const itemCount = me.cart.length; + const quantityCount = me.cart.reduce((tally, cartItem) => tally + cartItem.quantity, 0); + const totalPrice = me.cart.reduce((tally, cartItem) => tally + cartItem.quantity * cartItem.item.price, 0); return ( - <CartStyles className="cart" open={this.state.open}> - <button onClick={this.handleClick}> - Toggle Network Status:: {this.props.ui.networkStatus.isConnected.toString()} - </button> - <button className="toggleOpen" onClick={this.toggleOpen}> - Open Cart - </button> - - <p>🛒: {me.cart.length} Items</p> - <ul> - {me.cart.map(cartItem => ( - <li key={cartItem.id}> - <strong> - {cartItem.quantity} of {cartItem.item.title} - </strong> - <RemoveFromCart id={cartItem.id} /> - </li> - ))} - </ul> + <CartStyles open={this.props.ui.uiData.isCartOpen}> + <header> + <ToggleCart + render={toggle => ( + <CloseButton title="close" onClick={toggle}> + × + </CloseButton> + )} + /> + <Supreme>Your Cart.</Supreme> + <p> + You have {itemCount} item{itemCount === 1 ? '' : 's'} in your cart. S{'I'.repeat(quantityCount)}CK + </p> + </header> - <TakeMyMoney> - <hr /> - <button>Checkout!!!</button> - </TakeMyMoney> - {/* Theren - {user.cart.length === 1 ? ' is ' : 'are '} - <ChaChing amount={user.cart.length} /> - {user.cart.length === 1 ? ' item ' : ' items '} - in your cart totaling */} - {/* <ChaChing amount={formatMoney(total)} /> */} + <CartUl>{me.cart.map(cartItem => <CartItem key={cartItem.id} cartItem={cartItem} />)}</CartUl> + <footer> + <p>{formatMoney(totalPrice)}</p> + <TakeMyMoney> + <button>Checkout</button> + </TakeMyMoney> + </footer> </CartStyles> ); } } -export default compose(userEnhancer, networkEnhancer, uiEnhancer)(Cart); +export default compose(userEnhancer, uiEnhancer)(Cart); diff --git a/frontend/components/CartItem.js b/frontend/components/CartItem.js new file mode 100644 index 0000000..83c948e --- /dev/null +++ b/frontend/components/CartItem.js @@ -0,0 +1,39 @@ +import formatMoney from '../lib/formatMoney'; +import RemoveFromCart from './RemoveFromCart'; +import styled from 'styled-components'; + +const CartItemStyles = styled.li` + padding: 1rem 0; + border-bottom: 1px solid ${props => props.theme.lightgrey}; + display: grid; + align-items: center; + grid-template-columns: auto 1fr auto; + img { + margin-right: 10px; + } + h3 { + margin: 0; + } + p { + margin: 0; + } +`; + +const CartItem = ({ cartItem }) => ( + <CartItemStyles key={cartItem.id}> + <img width="100" src={cartItem.item.image} alt={cartItem.item.title} /> + <div className="cart-item-details"> + <h3>{cartItem.item.title}</h3> + <p> + {formatMoney(cartItem.quantity * cartItem.item.price)} + {' — '} + <em> + {cartItem.quantity} × {formatMoney(cartItem.item.price)} each + </em> + </p> + </div> + <RemoveFromCart id={cartItem.id} /> + </CartItemStyles> +); + +export default CartItem; diff --git a/frontend/components/CartList.js b/frontend/components/CartList.js index bf08f87..1a44012 100644 --- a/frontend/components/CartList.js +++ b/frontend/components/CartList.js @@ -1,21 +1,11 @@ // I THINK THIS CAN BE DELETED import { Component } from 'react'; -import withData from '../lib/withData'; -import Items from '../components/Items'; -import Signup from '../components/Signup'; -import LoginAuth0 from '../components/LoginAuth0'; -import Page from '../components/Page'; -import { USER_ORDERS_QUERY, GET_CART_STATE } from '../queries'; -import { graphql, compose } from 'react-apollo'; -import has from 'lodash.has'; -import get from 'lodash.get'; +import { compose } from 'react-apollo'; import styled from 'styled-components'; +import PropTypes from 'prop-types'; import formatMoney from '../lib/formatMoney'; -import makeImage from '../lib/image'; import TakeMyMoney from './TakeMyMoney'; -import { removeFromCartEnhancer } from '../enhancers/enhancers'; -import { CURRENT_USER_QUERY } from '../queries'; -import PropTypes from 'prop-types'; +import { removeFromCartEnhancer, userEnhancer, uiEnhancer } from '../enhancers/enhancers'; const CartStyles = styled.div` padding: 20px; @@ -44,15 +34,6 @@ class CartList extends Component { client: PropTypes.object, }; - componentDidMount() { - setTimeout(this.props.currentUserQuery.refetch, 1); - // Set the cart state to be closed - this.context.client.writeQuery({ - query: GET_CART_STATE, - data: { ui: { isCartOpen: true, __typename: 'Network' } }, - }); - } - toggleOpen = () => { this.props.uiQuery.updateQuery(() => ({ ui: { isCartOpen: false, __typename: 'Network' } })); }; @@ -66,15 +47,13 @@ class CartList extends Component { return <p>Error....</p>; } - // if (!has(this.props, 'currentUserQuery.user.cart')) { // return <p>Don't have it yet!</p>; // } // OMG Clean this up - let { user = {} } = this.props.currentUserQuery || {}; + if (!user) user = {}; const cart = user.cart || []; const userId = user.id; - // const userId = this.props.currentUserQuery.user.id; const total = cart.reduce((a, b) => a + b.price, 0); return ( @@ -83,7 +62,6 @@ class CartList extends Component { Open Cart </button> <h1>{cart.length} Items</h1> - <ul> {cart.map(item => ( <li key={item.id}> @@ -110,6 +88,4 @@ class CartList extends Component { } } -const userEnhancer = graphql(CURRENT_USER_QUERY, { name: 'currentUserQuery' }); -const uiEnhancer = graphql(GET_CART_STATE, { name: 'uiQuery' }); export default compose(userEnhancer, removeFromCartEnhancer, uiEnhancer)(CartList); diff --git a/frontend/components/CreateItem.js b/frontend/components/CreateItem.js index 47e98ec..0d43c68 100644 --- a/frontend/components/CreateItem.js +++ b/frontend/components/CreateItem.js @@ -2,7 +2,6 @@ import React, { Component } from 'react'; import { graphql, gql } from 'react-apollo'; import { ALL_ITEMS_QUERY, CREATE_ITEM_MUTATION } from '../queries'; import ErrorMessage from './ErrorMessage'; -import makeImage from '../lib/image'; import { fileEndpoint } from '../config'; class CreateLink extends Component { @@ -102,7 +101,7 @@ class CreateLink extends Component { type="text" placeholder="The desc for this item" /> - <button disabledx={!this.state.loading} type="submit"> + <button disabled={!this.state.loading} type="submit"> Submit </button> </form> diff --git a/frontend/components/Header.js b/frontend/components/Header.js index aa3c3d8..0183e4a 100644 --- a/frontend/components/Header.js +++ b/frontend/components/Header.js @@ -1,40 +1,66 @@ import { Component } from 'react'; -import { graphql, compose } from 'react-apollo'; +import { compose } from 'react-apollo'; import { userEnhancer } from '../enhancers/enhancers'; -import Cart from './Cart'; -import Login from './LoginAuth0'; -import Search from './Search'; import NProgress from 'nprogress'; import Router from 'next/router'; +import styled from 'styled-components'; +import Link from 'next/link'; import Signout from './Signout'; +import Cart from './Cart'; +import Search from './Search'; +import Nav from './Nav'; Router.onRouteChangeStart = url => { - console.log(`Loading: ${url}`); NProgress.start(); }; Router.onRouteChangeComplete = () => NProgress.done(); Router.onRouteChangeError = () => NProgress.done(); -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); - console.log(this.props.currentUser); +const StyledHeader = styled.header` + .bar { + border-bottom: 10px solid ${props => props.theme.black}; + display: grid; + grid-template-columns: auto 1fr; + justify-content: space-between; + align-items: stretch; + } + .sub-bar { + display: grid; + grid-template-columns: 1fr auto; + border-bottom: 1px solid ${props => props.theme.lightgrey}; } +`; - render() { - return ( - <div> - {this.props.currentUser.me ? this.props.currentUser.me.email : 'Not Signed in'} - <Signout /> - <Cart /> - {/* <Search /> */} - </div> - ); +const Logo = styled.h1` + font-size: 4rem; + margin-left: 2rem; + transform: skew(-5deg); + a { + padding: 1rem 1.5rem; + background: ${props => props.theme.red}; + color: white; + letter-spacing: -2px; + text-transform: uppercase; } -} +`; + +const Header = props => ( + <StyledHeader> + <div className="bar"> + <Logo> + <Link href="/"> + <a>Sick Fits!</a> + </Link> + </Logo> + <Nav /> + </div> + <div className="sub-bar"> + <Search /> + <Signout /> + </div> + <Cart /> + </StyledHeader> +); export default compose(userEnhancer)(Header); // export default Header; diff --git a/frontend/components/Item.js b/frontend/components/Item.js index 42a6c87..87fb0b9 100644 --- a/frontend/components/Item.js +++ b/frontend/components/Item.js @@ -1,31 +1,74 @@ import React from 'react'; +import Title from './styles/Title'; import styled from 'styled-components'; import slugify from 'slugify'; import { compose } from 'react-apollo'; import { Link } from '../routes'; import AddToCart from './AddToCart'; -import makeImage from '../lib/image'; import formatMoney from '../lib/formatMoney'; import { removeItemMutation } from '../enhancers/enhancers'; const Item = styled.div` - background: #f3f3f3; - padding: 5px; + background: white; + border: 1px solid ${props => props.theme.offWhite}; + box-shadow: 0 12px 24px 0 rgba(0, 0, 0, 0.09); + position: relative; + display: grid; + align-content: start; + /* grid-template-rows: repeat(auto-fit, minmax(100px,)); */ + grid-auto-rows: fit-content; img { width: 100%; } + p { + font-size: 14px; + line-height: 2; + font-weight: 600; + padding: 0 3rem; + font-size: 1.5rem; + } + .buttonList { + display: grid; + border-top: 1px solid ${props => props.theme.lightgrey}; + grid-template-columns: repeat(auto-fit, minmax(100px, 1fr)); + grid-gap: 1px; + background: ${props => props.theme.lightgrey}; + align-self: end; + & > * { + background: white; + border: 0; + text-align: center; + font-size: 1rem; + padding: 1rem; + } + } +`; + +const PriceTag = styled.span` + background: ${props => props.theme.red}; + transform: rotate(2deg); + color: white; + font-weight: 600; + padding: 5px; + font-size: 3rem; + display: inline-block; + position: absolute; + top: -3px; + right: -3px; `; class ItemComponent extends React.Component { removeItem = () => { - this.props.removeItem({ variables: { id: this.props.item.id } }); + if (confirm('Are you sure you want to delete this item?')) { + this.props.removeItem({ variables: { id: this.props.item.id } }); + } }; render() { const item = this.props.item; return ( <Item key={item.id}> {item.image ? <img src={item.image} alt={item.title} /> : null} - <h3> + <Title> <Link route="item" params={{ @@ -35,20 +78,24 @@ class ItemComponent extends React.Component { > <a>{item.title}</a> </Link> - </h3> + </Title> + + <PriceTag>{formatMoney(item.price)}</PriceTag> <p>{item.description}</p> - <Link - href={{ - pathname: '/admin/update', - query: { id: item.id }, - }} - > - <a>Edit ✏️</a> - </Link> - <AddToCart id={item.id} /> - <button onClick={this.removeItem}>× Delete item</button> + <div className="buttonList"> + <Link + href={{ + pathname: '/admin/update', + query: { id: item.id }, + }} + > + <a>Edit ✏️</a> + </Link> + <AddToCart id={item.id} /> + <button onClick={this.removeItem}>× Delete item</button> + </div> </Item> ); } diff --git a/frontend/components/Items.js b/frontend/components/Items.js index a3f98c9..6206592 100644 --- a/frontend/components/Items.js +++ b/frontend/components/Items.js @@ -13,8 +13,10 @@ const Title = styled.h1` const Items = styled.div` display: grid; - grid-template-columns: repeat(4, 1fr); - grid-gap: 20px; + grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); + grid-gap: 60px; + max-width: ${props => props.theme.maxWidth}; + margin: 0 auto; `; class ItemList extends Component { diff --git a/frontend/components/LoginAuth0.js b/frontend/components/LoginAuth0.js deleted file mode 100644 index b55ae4a..0000000 --- a/frontend/components/LoginAuth0.js +++ /dev/null @@ -1,76 +0,0 @@ -import { Component, PropTypes } from 'react'; -import Auth0Lock from 'auth0-lock'; -import { graphql, compose } from 'react-apollo'; -import { CURRENT_USER_QUERY } from '../queries/index'; - -class LoginAuth0 extends Component { - constructor(props) { - super(props); - if (typeof window === 'undefined') return; - const redirectUrl = `http://localhost:3000/signup`; - this._lock = new Auth0Lock('r6D64Waoq7roAnv8GT04dnn1tpq9PAqu', 'wesbos.auth0.com', { - auth: { - redirect: false, - }, - }); - } - - componentDidMount() { - this._lock.on('authenticated', authResult => { - console.log(authResult); - window.localStorage.setItem('auth0IdToken', authResult.idToken); - console.log('Im baaaack!'); - this.props.currentUserQuery.refetch(); - }); - - this._lock.on('authorization_error', err => { - console.error(err); - }); - - // refech on page load because of the server render - this.props.currentUserQuery.refetch(); - } - - logout = () => { - window.localStorage.removeItem('auth0IdToken'); - this.props.currentUserQuery.refetch(); - }; - - createUser = async () => { - 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.currentUserQuery.refetch(); - this.props.history.replace('/'); - }) - .catch(e => { - console.error(e); - this.props.history.replace('/'); - }); - }; - - _showLogin = () => { - this._lock.show(); - }; - - render() { - const { user } = this.props.currentUserQuery; - if (user) { - return <button onClick={this.logout}>Log out 👋</button>; - } - return ( - <div> - <button onClick={this._showLogin}>Log in with Auth0 </button> - </div> - ); - } -} - -const userEnhancer = graphql(CURRENT_USER_QUERY, { name: 'currentUserQuery' }); -export default compose(userEnhancer)(LoginAuth0); diff --git a/frontend/components/Meta.js b/frontend/components/Meta.js index d7a2e17..bee5a69 100644 --- a/frontend/components/Meta.js +++ b/frontend/components/Meta.js @@ -12,8 +12,7 @@ const Meta = () => ( } `} <meta charSet="utf-8" /> - <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" /> + <link rel="shortcut icon" href="/static/favicon.png" /> <link rel="stylesheet" type="text/css" href="/static/nprogress.css" /> <title>Sick Fits</title> diff --git a/frontend/components/Nav.js b/frontend/components/Nav.js index 25965c2..9793087 100644 --- a/frontend/components/Nav.js +++ b/frontend/components/Nav.js @@ -1,49 +1,95 @@ -import Link from "next/link"; -import styled from "styled-components"; +import Link from 'next/link'; +import styled from 'styled-components'; +import { userEnhancer } from '../enhancers/enhancers'; +import { compose } from 'react-apollo'; +import ToggleCart from './ToggleCart'; const StyledUl = styled.ul` margin: 0; padding: 0; display: flex; - li { + justify-self: end; + a, + button { + padding: 0 30px; display: flex; - flex: 1; + align-items: center; + position: relative; + text-transform: uppercase; + font-weight: 900; + font-size: 2rem; + background: none; + border: 0; + &:before { + content: ''; + width: 1px; + background: ${props => props.theme.lightgrey}; + height: 100%; + left: 0; + position: absolute; + transform: rotate(20deg); + top: 0; + bottom: 0; + } + &:after { + height: 2px; + background: red; + content: ''; + width: 0; + position: absolute; + transform: translateX(-50%); + transition: width 0.6s; + transition-timing-function: cubic-bezier(1, -0.65, 0, 2.31); + left: 50%; + margin-top: 2rem; + } + &:hover, + &:focus { + outline: none; + &:after { + width: calc(100% - 60px); + } + } } - a { - padding: 10px; - flex: 1; - text-decoration: none; - text-align: center; - background: rgba(0, 0, 0, 0.2); + .cart-count { + background: ${props => props.theme.red}; color: white; - margin-right: 20px; - &:hover { - background: rgba(0, 0, 0, 0.3); - } + border-radius: 50%; + padding: 5px; + margin-left: 1rem; + font-weight: 100; + font-feature-settings: 'tnum'; + font-variant-numeric: tabular-nums; } `; -const Nav = () => ( +const Nav = ({ currentUser }) => ( <StyledUl> - <Link prefetch href="/"> - <a>Home</a> - </Link> <Link prefetch href="/items"> - <a>Just Items</a> + <a>Shop</a> + </Link> + <Link prefetch href="/add"> + <a>Sell</a> </Link> <Link prefetch href="/signup"> <a>Sign Up</a> </Link> - <Link prefetch href="/add"> - <a>Add an Item</a> - </Link> <Link prefetch href="/orders"> <a>Orders</a> </Link> - <Link prefetch href="/cart"> - <a>My Cart</a> - </Link> + {currentUser.me ? ( + <ToggleCart + render={toggle => ( + <button onClick={toggle}> + My Cart + <span className="cart-count"> + {currentUser.me.cart.reduce((tally, cartItem) => tally + cartItem.quantity, 0)} + </span> + </button> + )} + /> + ) : null} </StyledUl> ); -export default Nav; +export default compose(userEnhancer)(Nav); diff --git a/frontend/components/OrderList.js b/frontend/components/OrderList.js index e478984..5e32ba2 100644 --- a/frontend/components/OrderList.js +++ b/frontend/components/OrderList.js @@ -3,14 +3,12 @@ import { USER_ORDERS_QUERY } from '../queries'; import { graphql, compose } from 'react-apollo'; import { format, formatDistance } from 'date-fns'; import formatMoney from '../lib/formatMoney'; -import makeImage from '../lib/image'; class OrderList extends Component { componentDidMount() { this.props.userOrdersQuery.refetch(); } render() { - console.log(this.props.userOrdersQuery); if (this.props.loading) { return <p>Loading...</p>; } @@ -23,7 +21,6 @@ class OrderList extends Component { if (!orders || !orders.length) return <p>No Orders Yet!</p>; - console.log(orders); return ( <div> <h2>You have {orders.length} Orders</h2> diff --git a/frontend/components/Page.js b/frontend/components/Page.js index 93cd7c9..66c65e6 100644 --- a/frontend/components/Page.js +++ b/frontend/components/Page.js @@ -1,44 +1,56 @@ -import styled from 'styled-components'; +import styled, { ThemeProvider, injectGlobal } from 'styled-components'; import Header from './Header'; import Meta from './Meta'; import Nav from './Nav'; import CartList from './CartList'; import { Component } from 'react'; -class ErrorBoundary extends Component { - state = { - error: null, - errorInfo: null, - }; - componentDidCatch(error, errorInfo) { - console.log('Caught an erorrror!'); - this.setState({ error, errorInfo }); +// Global Style + +const theme = { + red: '#FF0000', + black: '#393939', + grey: '#3A3A3A', + lightgrey: '#E1E1E1', + offWhite: '#EDEDED', + maxWidth: '1300px', +}; + +const globals = injectGlobal` + html { + box-sizing: border-box; + font-size: 10px; + } + body { + font-family: 'radnika next', sans-serif; + padding: 0; + background-color: #ffffff; + background: blue; + margin: 0; + font-size: 1.5rem; } - render() { - if (this.state.error) { - return <p>Shit! AN error! {this.state.error.message}</p>; - } - return this.props.children; + *, *:before, *:after { + box-sizing: inherit; } -} + a { + color: ${theme.black}; + text-decoration: none; + } +`; const StyledPage = styled.div` - font-family: sans-serif; - color: #303030; - background: #efc600; - padding: 100px; + color: ${props => props.theme.black}; + background: white; `; const Page = ({ children }) => ( - <StyledPage className="main"> - <ErrorBoundary> + <ThemeProvider theme={theme}> + <StyledPage className="main"> <Meta /> - <Nav /> <Header /> - {/* <CartList /> */} {children} - </ErrorBoundary> - </StyledPage> + </StyledPage> + </ThemeProvider> ); export default Page; diff --git a/frontend/components/Pagination.js b/frontend/components/Pagination.js index 2cb5080..d00778b 100644 --- a/frontend/components/Pagination.js +++ b/frontend/components/Pagination.js @@ -1,15 +1,10 @@ -import React, { Component } from 'react'; -import { graphql, gql, compose } from 'react-apollo'; -import { ALL_ITEMS_QUERY } from '../queries'; -import withData from '../lib/withData'; +import React from 'react'; +import { compose } from 'react-apollo'; import { Link } from '../routes'; import { itemEnhancer } from '../enhancers/enhancers'; const Pagination = props => { - const { loading, error } = props.itemsQuery; - - if (loading) return <p>Loading Item...</p>; - + if (props.loading) return <p>Loading Item...</p>; const { aggregate, pageInfo } = props.itemsQuery.itemsConnection; const { page } = props; diff --git a/frontend/components/RemoveFromCart.js b/frontend/components/RemoveFromCart.js index e3eb919..8d0d214 100644 --- a/frontend/components/RemoveFromCart.js +++ b/frontend/components/RemoveFromCart.js @@ -5,6 +5,16 @@ import styled from 'styled-components'; import PropTypes from 'prop-types'; import { removeFromCartEnhancer } from '../enhancers/enhancers'; +const BigButton = styled.button` + font-size: 3rem; + background: none; + border: 0; + &:hover { + color: ${props => props.theme.red}; + cursor: pointer; + } +`; + class RemoveFromCart extends Component { handleRemoveFromCart = async () => { console.log(`gonna remove item from cart`); @@ -18,7 +28,11 @@ class RemoveFromCart extends Component { }; render() { - return <button onClick={this.handleRemoveFromCart}>× Remove</button>; + return ( + <BigButton title="Remove From Cart" onClick={this.handleRemoveFromCart}> + × + </BigButton> + ); } } diff --git a/frontend/components/Search.js b/frontend/components/Search.js index 0ce136e..33017dd 100644 --- a/frontend/components/Search.js +++ b/frontend/components/Search.js @@ -1,9 +1,9 @@ import Downshift from 'downshift'; -import { SEARCH_ITEMS_QUERY } from '../queries'; import { graphql, compose } from 'react-apollo'; -import makeImage from '../lib/image'; -import { Router } from '../routes'; import slugify from 'slugify'; +import styled from 'styled-components'; +import { SEARCH_ITEMS_QUERY } from '../queries'; +import { Router } from '../routes'; function routeToItem(item) { Router.pushRoute('item', { @@ -12,38 +12,62 @@ function routeToItem(item) { }); } -function BasicAutocomplete(props) { +const DropDown = styled.div` + position: absolute; + width: 100%; + z-index: 2; + border: 1px solid ${props => props.theme.lightgrey}; + input { + border: 0; + } +`; + +const DropDownItem = styled.div` + border-bottom: 1px solid ${props => props.theme.lightgrey}; + background: ${props => (props.highlighted ? '#f7f7f7' : 'white')}; + padding: 1rem; + transition: all 0.2s; + ${props => (props.highlighted ? 'padding-left: 2rem;' : null)}; + display: flex; + align-items: center; + border-left: 10px solid ${props => (props.highlighted ? props.theme.lightgrey : 'white')}; + img { + margin-right: 10px; + } +`; + +const SearchStyles = styled.div` + position: relative; +`; + +function AutoComplete(props) { const { items, onChange } = props; return ( - <Downshift onChange={routeToItem} itemToString={item => item.title}> + <Downshift onChange={routeToItem} itemToString={i => (i === null ? '' : i.title)}> {({ getInputProps, getItemProps, isOpen, inputValue, selectedItem, highlightedIndex }) => ( <div> + {/* This is the searchInput */} <input {...getInputProps({ placeholder: 'Search For Item', - onChange: e => props.refetch({ searchTerm: e.target.value }), - style: { fontSize: '20px', padding: '20px', display: 'block', width: '100%' }, + id: 'search', + onChange: e => { + console.log('Change happened'); + props.refetch({ searchTerm: e.target.value }); + }, + style: { fontSize: '20px', padding: '10px', display: 'block', width: '100%' }, })} /> {isOpen ? ( - <div> + <DropDown> + {/* This is the Dropdown */} {items.map((item, index) => ( - <div - {...getItemProps({ item })} - key={item.id} - style={{ - backgroundColor: highlightedIndex === index ? '#e8e8e8' : 'white', - borderLeft: highlightedIndex === index ? '10px solid #ffc600' : '10px solid white', - padding: '10px', - display: 'flex', - alignItems: 'center', - }} - > - <img width="50" style={{ 'margin-right': '10px' }} src={makeImage(item.image)} alt={item.title} /> + <DropDownItem {...getItemProps({ item })} key={item.id} highlighted={highlightedIndex === index}> + <img width="50" src={item.image} alt={item.title} /> {item.title} - </div> + </DropDownItem> ))} - </div> + </DropDown> ) : null} </div> )} @@ -52,16 +76,19 @@ function BasicAutocomplete(props) { } const Search = props => ( - <BasicAutocomplete - items={props.searchItems.allItems} - onChange={selectedItem => console.log(selectedItem)} - refetch={props.searchItems.refetch} - /> + <SearchStyles> + <AutoComplete + items={props.searchItems.items} + onChange={selectedItem => console.log(selectedItem)} + refetch={props.searchItems.refetch} + /> + </SearchStyles> ); const searchEnhancer = graphql(SEARCH_ITEMS_QUERY, { name: 'searchItems', options: { + // TODO: Why is this camo variables: { searchTerm: 'camo' }, }, }); diff --git a/frontend/components/SingleItem.js b/frontend/components/SingleItem.js index 47dbd0e..58da71c 100644 --- a/frontend/components/SingleItem.js +++ b/frontend/components/SingleItem.js @@ -3,9 +3,9 @@ import { SINGLE_ITEM_QUERY } from '../queries'; import { singleItemEnhancer } from '../enhancers/enhancers'; const SingleItem = props => { - if (props.loading || !props.item) return <p>Loading...</p>; - if (props.error) return <p>Error...</p>; console.log(props); + if (props.loading) return <p>Loading...</p>; + if (props.error) return <p>Error...</p>; const item = props.findItem.items[0]; return ( <div> diff --git a/frontend/components/TakeMyMoney.js b/frontend/components/TakeMyMoney.js index 30a19dc..5bdc409 100644 --- a/frontend/components/TakeMyMoney.js +++ b/frontend/components/TakeMyMoney.js @@ -7,22 +7,12 @@ import formatMoney from '../lib/formatMoney'; class TakeMyMoney extends Component { onToken = async res => { console.log('We got a toooken!'); - console.log(res); const order = await this.props.createOrder({ variables: { token: res.id, }, }); console.log(order); - // 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}`); - // 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() { @@ -31,21 +21,18 @@ class TakeMyMoney extends Component { const total = me.cart.reduce((tally, cartItem) => tally + cartItem.item.price * cartItem.quantity, 0); const totalItems = me.cart.reduce((tally, cartItem) => tally + cartItem.quantity, 0); return ( - <div> - <StripeCheckout - amount={total} - name="Sick Fits Haul" - description={`Order of ${totalItems} Items From Sick Fits`} - image={me.cart[0].item.image} - token={this.onToken} - stripeKey="pk_lclTtThFp8CnO3QtEZSd8HA9mFUps" - currency="USD" - email={me.email} - > - {formatMoney(total)} - {this.props.children} - </StripeCheckout> - </div> + <StripeCheckout + amount={total} + name="Sick Fits Haul" + description={`Order of ${totalItems} Items From Sick Fits`} + image={me.cart[0].item.image} + token={this.onToken} + stripeKey="pk_lclTtThFp8CnO3QtEZSd8HA9mFUps" + currency="USD" + email={me.email} + > + {this.props.children} + </StripeCheckout> ); } } diff --git a/frontend/components/ToggleCart.js b/frontend/components/ToggleCart.js new file mode 100644 index 0000000..c80baa6 --- /dev/null +++ b/frontend/components/ToggleCart.js @@ -0,0 +1,22 @@ +import { Component } from 'react'; +import { compose } from 'react-apollo'; +import { uiEnhancer, updateUIEnhancer } from '../enhancers/enhancers'; +import PropTypes from 'prop-types'; + +class ToggleCart extends Component { + static propTypes = { + render: PropTypes.func.isRequired, + toggleCart: PropTypes.func.isRequired, + ui: PropTypes.object.isRequired, + }; + toggle = e => { + // if this is a keyPress event, make sure it's the enter key + if (e.keyCode && e.keyCode !== 16) return; + this.props.toggleCart(!this.props.ui.uiData.isCartOpen); + }; + render() { + return this.props.render(this.toggle); + } +} + +export default compose(uiEnhancer, updateUIEnhancer)(ToggleCart); diff --git a/frontend/components/styles/Title.js b/frontend/components/styles/Title.js new file mode 100644 index 0000000..e1901ec --- /dev/null +++ b/frontend/components/styles/Title.js @@ -0,0 +1,20 @@ +import styled from 'styled-components'; + +const Title = styled.h3` + margin: 0 1rem; + text-align: center; + transform: skew(-5deg) rotate(-1deg); + margin-top: -3rem; + text-shadow: 2px 2px 0 rgba(0, 0, 0, 0.1); + a { + background: ${props => props.theme.red}; + display: inline; + line-height: 1.3; + font-size: 4rem; + text-align: center; + color: white; + padding: 0 1rem; + } +`; + +export default Title; |
