diff options
| -rw-r--r-- | backend/database/datamodel.graphql | 8 | ||||
| -rw-r--r-- | backend/package.json | 2 | ||||
| -rw-r--r-- | backend/src/generated/prisma.graphql | 100 | ||||
| -rw-r--r-- | backend/src/index.js | 3 | ||||
| -rw-r--r-- | backend/src/resolvers/Mutation.js | 8 | ||||
| -rw-r--r-- | backend/src/resolvers/Query.js | 13 | ||||
| -rw-r--r-- | frontend/components/Cart.js | 58 | ||||
| -rw-r--r-- | frontend/components/CartList.js | 1 | ||||
| -rw-r--r-- | frontend/components/OrderList.js | 58 | ||||
| -rw-r--r-- | frontend/config.js | 2 | ||||
| -rw-r--r-- | frontend/enhancers/enhancers.js | 10 | ||||
| -rw-r--r-- | frontend/lib/initApollo.js | 39 | ||||
| -rw-r--r-- | frontend/package-lock.json | 10 | ||||
| -rw-r--r-- | frontend/package.json | 3 | ||||
| -rw-r--r-- | frontend/queries/index.js | 65 |
15 files changed, 282 insertions, 98 deletions
diff --git a/backend/database/datamodel.graphql b/backend/database/datamodel.graphql index ed70892..940fb6f 100644 --- a/backend/database/datamodel.graphql +++ b/backend/database/datamodel.graphql @@ -20,6 +20,8 @@ type User { resetToken: String resetTokenExpiry: String cart: [CartItem!]! + createdAt: DateTime! + updatedAt: DateTime! } type CartItem { @@ -27,6 +29,8 @@ type CartItem { quantity: Int! @default(value: 1) item: Item! # Relationship to an Item user: User! # Relationship to a user + createdAt: DateTime! + updatedAt: DateTime! } type Item { @@ -35,6 +39,8 @@ type Item { description: String! image: String price: Int! + createdAt: DateTime! + updatedAt: DateTime! } type Order { @@ -42,5 +48,7 @@ type Order { items: [Item!]! total: Int! user: User! + createdAt: DateTime! + updatedAt: DateTime! charge: String! }
\ No newline at end of file diff --git a/backend/package.json b/backend/package.json index 10b57aa..31f0618 100644 --- a/backend/package.json +++ b/backend/package.json @@ -30,4 +30,4 @@ "repository": { "url": "wesbos.com" } -} +}
\ No newline at end of file diff --git a/backend/src/generated/prisma.graphql b/backend/src/generated/prisma.graphql index 402e097..a0c3a3f 100644 --- a/backend/src/generated/prisma.graphql +++ b/backend/src/generated/prisma.graphql @@ -10,6 +10,8 @@ type CartItem implements Node { quantity: Int! item(where: ItemWhereInput): Item! user(where: UserWhereInput): User! + createdAt: DateTime! + updatedAt: DateTime! } type Item implements Node { @@ -18,6 +20,8 @@ type Item implements Node { description: String! image: String price: Int! + createdAt: DateTime! + updatedAt: DateTime! } type Order implements Node { @@ -25,6 +29,8 @@ type Order implements Node { items(where: ItemWhereInput, orderBy: ItemOrderByInput, skip: Int, after: String, before: String, first: Int, last: Int): [Item!] total: Int! user(where: UserWhereInput): User! + createdAt: DateTime! + updatedAt: DateTime! charge: String! } @@ -50,6 +56,8 @@ type User implements Node { resetToken: String resetTokenExpiry: String cart(where: CartItemWhereInput, orderBy: CartItemOrderByInput, skip: Int, after: String, before: String, first: Int, last: Int): [CartItem!] + createdAt: DateTime! + updatedAt: DateTime! } @@ -113,15 +121,17 @@ enum CartItemOrderByInput { id_DESC quantity_ASC quantity_DESC - updatedAt_ASC - updatedAt_DESC createdAt_ASC createdAt_DESC + updatedAt_ASC + updatedAt_DESC } type CartItemPreviousValues { id: ID! quantity: Int! + createdAt: DateTime! + updatedAt: DateTime! } type CartItemSubscriptionPayload { @@ -197,6 +207,22 @@ input CartItemWhereInput { quantity_lte: Int quantity_gt: Int quantity_gte: Int + createdAt: DateTime + createdAt_not: DateTime + createdAt_in: [DateTime!] + createdAt_not_in: [DateTime!] + createdAt_lt: DateTime + createdAt_lte: DateTime + createdAt_gt: DateTime + createdAt_gte: DateTime + updatedAt: DateTime + updatedAt_not: DateTime + updatedAt_in: [DateTime!] + updatedAt_not_in: [DateTime!] + updatedAt_lt: DateTime + updatedAt_lte: DateTime + updatedAt_gt: DateTime + updatedAt_gte: DateTime item: ItemWhereInput user: UserWhereInput } @@ -246,10 +272,10 @@ enum ItemOrderByInput { image_DESC price_ASC price_DESC - updatedAt_ASC - updatedAt_DESC createdAt_ASC createdAt_DESC + updatedAt_ASC + updatedAt_DESC } type ItemPreviousValues { @@ -258,6 +284,8 @@ type ItemPreviousValues { description: String! image: String price: Int! + createdAt: DateTime! + updatedAt: DateTime! } type ItemSubscriptionPayload { @@ -365,6 +393,22 @@ input ItemWhereInput { price_lte: Int price_gt: Int price_gte: Int + createdAt: DateTime + createdAt_not: DateTime + createdAt_in: [DateTime!] + createdAt_not_in: [DateTime!] + createdAt_lt: DateTime + createdAt_lte: DateTime + createdAt_gt: DateTime + createdAt_gte: DateTime + updatedAt: DateTime + updatedAt_not: DateTime + updatedAt_in: [DateTime!] + updatedAt_not_in: [DateTime!] + updatedAt_lt: DateTime + updatedAt_lte: DateTime + updatedAt_gt: DateTime + updatedAt_gte: DateTime } input ItemWhereUniqueInput { @@ -450,17 +494,19 @@ enum OrderOrderByInput { id_DESC total_ASC total_DESC - charge_ASC - charge_DESC - updatedAt_ASC - updatedAt_DESC createdAt_ASC createdAt_DESC + updatedAt_ASC + updatedAt_DESC + charge_ASC + charge_DESC } type OrderPreviousValues { id: ID! total: Int! + createdAt: DateTime! + updatedAt: DateTime! charge: String! } @@ -539,6 +585,22 @@ input OrderWhereInput { total_lte: Int total_gt: Int total_gte: Int + createdAt: DateTime + createdAt_not: DateTime + createdAt_in: [DateTime!] + createdAt_not_in: [DateTime!] + createdAt_lt: DateTime + createdAt_lte: DateTime + createdAt_gt: DateTime + createdAt_gte: DateTime + updatedAt: DateTime + updatedAt_not: DateTime + updatedAt_in: [DateTime!] + updatedAt_not_in: [DateTime!] + updatedAt_lt: DateTime + updatedAt_lte: DateTime + updatedAt_gt: DateTime + updatedAt_gte: DateTime charge: String charge_not: String charge_in: [String!] @@ -862,10 +924,10 @@ enum UserOrderByInput { resetToken_DESC resetTokenExpiry_ASC resetTokenExpiry_DESC - updatedAt_ASC - updatedAt_DESC createdAt_ASC createdAt_DESC + updatedAt_ASC + updatedAt_DESC } type UserPreviousValues { @@ -877,6 +939,8 @@ type UserPreviousValues { age: Int resetToken: String resetTokenExpiry: String + createdAt: DateTime! + updatedAt: DateTime! } type UserSubscriptionPayload { @@ -1114,6 +1178,22 @@ input UserWhereInput { resetTokenExpiry_not_starts_with: String resetTokenExpiry_ends_with: String resetTokenExpiry_not_ends_with: String + createdAt: DateTime + createdAt_not: DateTime + createdAt_in: [DateTime!] + createdAt_not_in: [DateTime!] + createdAt_lt: DateTime + createdAt_lte: DateTime + createdAt_gt: DateTime + createdAt_gte: DateTime + updatedAt: DateTime + updatedAt_not: DateTime + updatedAt_in: [DateTime!] + updatedAt_not_in: [DateTime!] + updatedAt_lt: DateTime + updatedAt_lte: DateTime + updatedAt_gt: DateTime + updatedAt_gte: DateTime posts_every: PostWhereInput posts_some: PostWhereInput posts_none: PostWhereInput diff --git a/backend/src/index.js b/backend/src/index.js index 22cc9ef..3630b74 100644 --- a/backend/src/index.js +++ b/backend/src/index.js @@ -35,4 +35,5 @@ server.start(() => console.log('Server is running on http://localhost:4000')); // overwrite console.log const chalk = require('chalk'); -global.console.l = (...butta) => console.log(chalk.bold.yellow(...butta)); +// global.console.l = (...butta) => console.log(chalk.bold.yellow(...butta)); +global.console.l = console.log; diff --git a/backend/src/resolvers/Mutation.js b/backend/src/resolvers/Mutation.js index 1c071fe..6349109 100644 --- a/backend/src/resolvers/Mutation.js +++ b/backend/src/resolvers/Mutation.js @@ -251,14 +251,6 @@ const mutations = { return ctx.db.mutation.deleteCartItem({ where: { id: args.id }, }); - // const userId = getUserId(ctx); - // return ctx.db.query.user({ where: { id: userId } }, '{ id, cart { id, quantity }}'); - // const cartItem = await ctx.db.query.cartItem({ - // where: { id: args.id }, - // }); - - // console.log(cartItem); - // return cartItem; }, async createOrder(parent, args, ctx, info) { const userId = getUserId(ctx); diff --git a/backend/src/resolvers/Query.js b/backend/src/resolvers/Query.js index 8649e43..2aabdb7 100644 --- a/backend/src/resolvers/Query.js +++ b/backend/src/resolvers/Query.js @@ -41,10 +41,15 @@ const Query = { return ctx.db.query.user({ where: { id } }, info); }, async orders(parent, args, ctx, info) { - console.l('--------------------FETCHING ORDERS---------------------'); - console.log(args); - return ctx.db.query.orders({}, info); - console.l('--------------------FETCHING ORDERS---------------------'); + const userId = getUserId(ctx); + return ctx.db.query.orders( + { + where: { + user: { id: userId }, + }, + }, + info + ); }, }; diff --git a/frontend/components/Cart.js b/frontend/components/Cart.js index 46a8941..72c34ae 100644 --- a/frontend/components/Cart.js +++ b/frontend/components/Cart.js @@ -1,39 +1,62 @@ import { Component } from 'react'; import { graphql, compose } from 'react-apollo'; import styled from 'styled-components'; -import { CURRENT_USER_QUERY } from '../queries'; +import { networkEnhancer, userEnhancer, uiEnhancer } from '../enhancers/enhancers'; import RemoveFromCart from './RemoveFromCart'; import TakeMyMoney from './TakeMyMoney'; -import { formatMoney } from '../lib/formatMoney'; const CartStyles = styled.div` - background: white; - border-radius: 10px; padding: 20px; - overflow: hidden; - display: flex; - align-items: center; + position: relative; + background: white; + position: fixed; + height: 100%; + top: 0; + right: 0; + bottom: 0; + transform: translateX(100%); + transition: all 0.3s; + box-shadow: 0 0 10px 3px rgba(0, 0, 0, 0.2); + z-index: 5; + ${props => props.open && `transform: translateX(0);`}; + .toggleOpen { + position: absolute; + top: 0; + left: 0; + transform: translateX(-100%); + } `; class Cart extends Component { + state = { + open: true, + }; componentDidMount() { console.log('refetching..'); setTimeout(this.props.currentUser.refetch, 10); } + 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; } - // Check for loading state.. - // const { loading, error } = this.props.currentUserQuery; - // const { user } = this.props.currentUserQuery; - // if (loading || error || !user) return <p>Cart Loading...</p>; - // const total = user.cart.reduce((a, b) => a + b.price, 0); - const { me } = this.props.currentUser; - console.log(me); + return ( - <CartStyles className="cart"> + <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 => ( @@ -50,7 +73,7 @@ class Cart extends Component { <hr /> <button>Checkout!!!</button> </TakeMyMoney> - {/* There + {/* Theren {user.cart.length === 1 ? ' is ' : 'are '} <ChaChing amount={user.cart.length} /> {user.cart.length === 1 ? ' item ' : ' items '} @@ -61,5 +84,4 @@ class Cart extends Component { } } -const userEnhancer = graphql(CURRENT_USER_QUERY, { name: 'currentUser' }); -export default compose(userEnhancer)(Cart); +export default compose(userEnhancer, networkEnhancer, uiEnhancer)(Cart); diff --git a/frontend/components/CartList.js b/frontend/components/CartList.js index 661d5ad..bf08f87 100644 --- a/frontend/components/CartList.js +++ b/frontend/components/CartList.js @@ -1,3 +1,4 @@ +// I THINK THIS CAN BE DELETED import { Component } from 'react'; import withData from '../lib/withData'; import Items from '../components/Items'; diff --git a/frontend/components/OrderList.js b/frontend/components/OrderList.js index c33f0b9..e478984 100644 --- a/frontend/components/OrderList.js +++ b/frontend/components/OrderList.js @@ -1,52 +1,58 @@ 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 { 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() { - console.log('Mounting!'); + this.props.userOrdersQuery.refetch(); } render() { - - if(this.props.loading) { - return <p>Loading...</p> + console.log(this.props.userOrdersQuery); + if (this.props.loading) { + return <p>Loading...</p>; } - if(this.props.error) { - return <p>Error...</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; - const orders = this.props.userOrdersQuery.user.orders; + if (!orders || !orders.length) return <p>No Orders Yet!</p>; 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>)} + {orders.map(order => ( + <li key={order.id}> + <ul className="order-items"> + <hr /> + <h2> + {order.id} + <time dateTime={order.createdAt} title={format(order.createdAt, 'MMMM D, YYYY h:mm A')}> + {formatDistance(order.createdAt, new Date())} + </time> + </h2> + + {order.items.map(item => ( + <li> + <img src={item.image} alt={item.title} /> + <p>{item.title}</p> + </li> + ))} + </ul> + </li> + ))} </ul> </div> - ) + ); } } const ordersEnhancer = graphql(USER_ORDERS_QUERY, { name: 'userOrdersQuery' }); -export default compose(ordersEnhancer)(OrderList) +export default compose(ordersEnhancer)(OrderList); diff --git a/frontend/config.js b/frontend/config.js index 7d5ebad..fa59a6d 100644 --- a/frontend/config.js +++ b/frontend/config.js @@ -1,5 +1,3 @@ // This is client side config only - don't put anything in here that shouldn't be public! export const projectId = `cj99zm6ye06sb01325ic751ww`; export const endpoint = `http://localhost:4000`; -export const imageEndpoint = `https://images.graph.cool/v1/${projectId}`; -export const fileEndpoint = `https://api.graph.cool/file/v1/${projectId}`; diff --git a/frontend/enhancers/enhancers.js b/frontend/enhancers/enhancers.js index 1abdd78..88bebe4 100644 --- a/frontend/enhancers/enhancers.js +++ b/frontend/enhancers/enhancers.js @@ -6,6 +6,8 @@ import { SINGLE_ITEM_QUERY, CURRENT_USER_QUERY, ADD_TO_CART_MUTATION, + UPDATE_NETWORK_STATUS, + GET_UI_STATE, } from '../queries/index'; export const itemEnhancer = graphql(ALL_ITEMS_QUERY, { @@ -74,3 +76,11 @@ export const addtoCartEnhancer = graphql(ADD_TO_CART_MUTATION, { }); export const userEnhancer = graphql(CURRENT_USER_QUERY, { name: 'currentUser' }); + +export const uiEnhancer = graphql(GET_UI_STATE, { name: 'ui' }); + +export const networkEnhancer = graphql(UPDATE_NETWORK_STATUS, { + props: ({ mutate }) => ({ + updateNetworkStatus: isConnected => mutate({ variables: { isConnected } }), + }), +}); diff --git a/frontend/lib/initApollo.js b/frontend/lib/initApollo.js index d0f1351..45f0fec 100644 --- a/frontend/lib/initApollo.js +++ b/frontend/lib/initApollo.js @@ -1,8 +1,9 @@ import { ApolloClient } from 'apollo-client'; -import { ApolloLink, concat } from 'apollo-link'; +import { ApolloLink, from } from 'apollo-link'; import { HttpLink } from 'apollo-link-http'; import { InMemoryCache } from 'apollo-cache-inmemory'; import fetch from 'isomorphic-fetch'; +import { withClientState } from 'apollo-link-state'; import { endpoint } from '../config'; let apolloClient = null; @@ -13,11 +14,38 @@ if (!process.browser) { } function create(initialState) { + // Create a new Cache + const cache = new InMemoryCache().restore(initialState || {}); // First we create three peices of middleware + const stateLink = withClientState({ + cache, + defaults: { + networkStatus: { + __typename: 'NetworkStatus', + isConnected: true, + isCartOpen: true, + }, + }, + resolvers: { + Mutation: { + updateNetworkStatus: (_, { isConnected }, { cache }) => { + console.log(isConnected); + const data = { + networkStatus: { + __typename: 'NetworkStatus', + isConnected, + }, + }; + cache.writeData({ data }); + return null; + }, + }, + }, + }); // 1. Create a link for local state to be managed in Apollo - // 1. connect to our GraphQL API + // 2. connect to our GraphQL API const httpLink = new HttpLink({ uri: endpoint, // Server URL (must be absolute) opts: { @@ -25,9 +53,8 @@ function create(initialState) { }, }); - // 2. One to tack on our auth token on each request + // 3. One to tack on our auth token on each request const authMiddleware = new ApolloLink((operation, forward) => { - console.log('Adding Auth'); const headers = {}; if (typeof localStorage !== 'undefined' && localStorage.getItem('token')) { @@ -41,8 +68,8 @@ function create(initialState) { return new ApolloClient({ connectToDevTools: process.browser, ssrMode: !process.browser, // Disables forceFetch on the server (so queries are only run once) - link: concat(authMiddleware, httpLink), - cache: new InMemoryCache().restore(initialState || {}), + link: from([stateLink, authMiddleware, httpLink]), + cache, defaultOptions: { query: { errorPolicy: 'all' }, mutate: { errorPolicy: 'all' }, diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 1cbed1a..b18b778 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -2687,6 +2687,11 @@ "assert-plus": "1.0.0" } }, + "date-fns": { + "version": "2.0.0-alpha.7", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.0.0-alpha.7.tgz", + "integrity": "sha1-JFrRb5V2Tqur+ywKQf1dAzwg5Xo=" + }, "date-now": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/date-now/-/date-now-0.1.4.tgz", @@ -7697,11 +7702,6 @@ "which": "1.3.0" } }, - "nodemailer": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-4.4.2.tgz", - "integrity": "sha512-sstDxbCSPHDXrWRQhH++khr3yVU0CGvH2dCtAHOPQQ0lRR7xwq2txItEXckMpX481B/cN+0akER2bfExh7Gu/Q==" - }, "nopt": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.1.tgz", diff --git a/frontend/package.json b/frontend/package.json index 547a576..264480f 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -21,6 +21,7 @@ "apollo-link-state": "^0.4.0", "auth0-lock": "^11.1.0", "babel-plugin-styled-components": "^1.5.0", + "date-fns": "^2.0.0-alpha.7", "downshift": "^1.25.0", "express": "^4.16.2", "graphql": "^0.12.3", @@ -47,4 +48,4 @@ "devDependencies": { "jest": "^22.1.4" } -}
\ No newline at end of file +} diff --git a/frontend/queries/index.js b/frontend/queries/index.js index 365c6f4..2464246 100644 --- a/frontend/queries/index.js +++ b/frontend/queries/index.js @@ -170,26 +170,39 @@ export const CURRENT_USER_QUERY = gql` `; export const USER_ORDERS_QUERY = gql` - query { - user { - # grab the current user + query orders { + orders(orderBy: createdAt_DESC) { id - orders { - # and a all their orders + total + createdAt + updatedAt + items { id - amount - charge - item { - # populate the details about the item they bought with the image, description and title - image { - id - secret - } - description - title - } + title + price + description + image } } + # user { + # # grab the current user + # id + # orders { + # # and a all their orders + # id + # amount + # charge + # item { + # # populate the details about the item they bought with the image, description and title + # image { + # id + # secret + # } + # description + # title + # } + # } + # } } `; @@ -234,3 +247,23 @@ export const UPDATE_CART_STATE = gql` } } `; + +export const UI_STATE = gql` + query { + isCartOpen @client + } +`; + +export const UPDATE_NETWORK_STATUS = gql` + mutation updateNetworkStatus($isConnected: Boolean) { + updateNetworkStatus(isConnected: $isConnected) @client + } +`; + +export const GET_UI_STATE = gql` + query cartState { + networkStatus @client { + isConnected + } + } +`; |
