diff options
| author | Wes Bos <wesbos@gmail.com> | 2018-05-25 14:06:53 -0400 |
|---|---|---|
| committer | Wes Bos <wesbos@gmail.com> | 2018-05-25 14:06:53 -0400 |
| commit | 22635ea05dab85a71fa93dbb98f93da7670ef899 (patch) | |
| tree | b9e974dee484634d0401a9149c9a68f5537553db | |
| parent | 549cfa77c9fec0936c3a8d87a49b69401cbfbd7a (diff) | |
Delete and Add refetch refinements
| -rw-r--r-- | backend/prisma/datamodel.graphql | 4 | ||||
| -rw-r--r-- | backend/src/generated/prisma.graphql | 15 | ||||
| -rw-r--r-- | backend/src/resolvers/Mutation.js | 11 | ||||
| -rw-r--r-- | frontend/README.md | 42 | ||||
| -rw-r--r-- | frontend/__tests__/__snapshots__/Nav.test.js.snap | 2 | ||||
| -rw-r--r-- | frontend/__tests__/__snapshots__/Pagination.test.js.snap | 3 | ||||
| -rw-r--r-- | frontend/components/CreateItem.js | 10 | ||||
| -rw-r--r-- | frontend/components/DeleteItem.js | 21 | ||||
| -rw-r--r-- | frontend/components/Items.js | 2 | ||||
| -rw-r--r-- | frontend/components/Order.js | 3 | ||||
| -rw-r--r-- | frontend/components/Pagination.js | 6 | ||||
| -rw-r--r-- | frontend/components/RemoveFromCart.js | 2 | ||||
| -rw-r--r-- | frontend/components/SingleItem.js | 6 | ||||
| -rw-r--r-- | frontend/components/styles/ItemStyles.js | 12 | ||||
| -rw-r--r-- | frontend/package.json | 6 |
15 files changed, 94 insertions, 51 deletions
diff --git a/backend/prisma/datamodel.graphql b/backend/prisma/datamodel.graphql index 9465524..cb8afcb 100644 --- a/backend/prisma/datamodel.graphql +++ b/backend/prisma/datamodel.graphql @@ -52,8 +52,6 @@ type OrderItem { createdAt: DateTime! updatedAt: DateTime! quantity: Int! @default(value: 1) - item: Item! # Relationship to an Item - user: User! # Relationship to a user } type Order { @@ -64,4 +62,4 @@ type Order { createdAt: DateTime! updatedAt: DateTime! charge: String! -}
\ No newline at end of file +} diff --git a/backend/src/generated/prisma.graphql b/backend/src/generated/prisma.graphql index aeacf68..953ddc2 100644 --- a/backend/src/generated/prisma.graphql +++ b/backend/src/generated/prisma.graphql @@ -1,5 +1,5 @@ -# source: https://us1.prisma.sh/johannes-schickling/wesbos/dev -# timestamp: Mon May 21 2018 18:02:25 GMT-0700 (PDT) +# source: https://us1.prisma.sh/wesbos/sick-fits/dev +# timestamp: Fri May 25 2018 10:46:45 GMT-0400 (EDT) type AggregateCartItem { count: Int! @@ -418,6 +418,7 @@ input ItemUpdateInput { input ItemUpdateOneInput { create: ItemCreateInput connect: ItemWhereUniqueInput + disconnect: Boolean delete: Boolean update: ItemUpdateDataInput upsert: ItemUpsertNestedInput @@ -818,8 +819,6 @@ type OrderItem implements Node { createdAt: DateTime! updatedAt: DateTime! quantity: Int! - item(where: ItemWhereInput): Item! - user(where: UserWhereInput): User! } """A connection to a list of items.""" @@ -839,8 +838,6 @@ input OrderItemCreateInput { largeImage: String price: Int! quantity: Int - item: ItemCreateOneInput! - user: UserCreateOneInput! } input OrderItemCreateManyInput { @@ -936,8 +933,6 @@ input OrderItemUpdateDataInput { largeImage: String price: Int quantity: Int - item: ItemUpdateOneInput - user: UserUpdateOneInput } input OrderItemUpdateInput { @@ -947,8 +942,6 @@ input OrderItemUpdateInput { largeImage: String price: Int quantity: Int - item: ItemUpdateOneInput - user: UserUpdateOneInput } input OrderItemUpdateManyInput { @@ -1268,8 +1261,6 @@ input OrderItemWhereInput { """All values greater than or equal the given value.""" quantity_gte: Int - item: ItemWhereInput - user: UserWhereInput } input OrderItemWhereUniqueInput { diff --git a/backend/src/resolvers/Mutation.js b/backend/src/resolvers/Mutation.js index 9510cd6..2a67da5 100644 --- a/backend/src/resolvers/Mutation.js +++ b/backend/src/resolvers/Mutation.js @@ -81,12 +81,17 @@ const mutations = { }; // 1. find the item const item = await ctx.db.query.item({ where }, `{ user {id}, title, id, description }`); - // 2. Make sure they own it, or are an admin - if (item.user.id !== ctx.request.user.id || !ctx.request.user.permissions.includes('ADMIN')) { + console.log(item.user); + console.log('-----------------'); + console.log(ctx.request.user); + // 2. if they 1. Don't own it AND 2. aren't an admin + if (item.user.id !== ctx.request.user.id && !ctx.request.user.permissions.includes('ADMIN')) { throw new Error("You aren't allowed to delete that item!"); } - // You Should Either Own this item, or have ITEMDELETE in roles + // 3. remove any orderItems this item is in + + return ctx.db.mutation.deleteItem({ where }, info); }, diff --git a/frontend/README.md b/frontend/README.md index 9d20e7c..9914799 100644 --- a/frontend/README.md +++ b/frontend/README.md @@ -14,36 +14,46 @@ Nudie Belt Our accessories are all about genuine leather and denim. Belts, leather wallets cases, denim bags, Knitted hats and scarves in wool or organic cotton. For our leather accessories, we only use vegetable tanned leather. Leather accessories will acquire a patina and become more beautiful the longer you use them. -Ultra Boost +Triple Black Ultra Boost Ultraboost is the ultimate running shoe that delivers constant energy returns. The more you run the more energy you bring to your life. +Patagonia Black Hole +The Black Hole Duffle is highly weather-resistant, and protects your gear from rough handling. The U-shaped lid allows quick access to the main compartment, while 2 zippered internal mesh pockets keep small items organized. A padded bottom panel adds structure and helps cushion the load when it gets tossed out of the vehicle or dropped from the pack mule. -Black Hole +Yeti cooler -The Black Hole Duffle is highly weather-resistant, and protects your gear from rough handling. The U-shaped lid allows quick access to the main compartment, while 2 zippered internal mesh pockets keep small items organized. A padded bottom panel adds structure and helps cushion the load when it gets tossed out of the vehicle or dropped from the pack mule. +Keep your brie and bevies chilly. Heavy-duty insulation ensures cold temperatures persist. A self-stopping hinge and Yeti-tough details are durable. Non-slip rubber feet keep your drinks and snacks orderly through whitewater or rough approaches to the picnic site. +Black Vapor Max -Yeti +With the radically reinvented VaporMax Air cushioning unit, the Nike Air VaporMax not only defies convention, it delivers a sensation that seems to defy gravity. -Keep your brie and bevies chilly. Heavy-duty insulation ensures cold temperatures persist. A self-stopping hinge and Yeti-tough details are durable. Non-slip rubber feet keep your drinks and snacks orderly through whitewater or rough approaches to the picnic site. +Naked and Famous Jeans + +Naked & Famous Denim uses only the most unique and rare selvedge denim fabrics from Japan, with the best style and fits around. Made in Canada. + + +Rimowa Suitcase + +RIMOWA is one of Europe's leading manufacturers of premium travel and carry-on luggage made of aluminum and polycarbonate. + + +Canada goose Macmillian + +The MacMillan Parka offers active urban style with a quilt-through design and curved hem cut. Canada Goose. + +## The North Face Fanorak +This versatile pullover offers wind and rain resistance, and packs into its own stylish fanny-pack-style kangaroo pocket. -Test Order: -FormatMoney -Cart Count -CartItem +Kith Hoodie -Things to Ask James: +Hat -* Testing Mutations - overwrite instance Mutation.client.mutate? -* Client via <ApolloConsumer> - best way? -* Update on Items Pagination -* Testing with context. Is this context okay? Deprecation -* Testing Error States -* wait and loading - normal? +270s --> diff --git a/frontend/__tests__/__snapshots__/Nav.test.js.snap b/frontend/__tests__/__snapshots__/Nav.test.js.snap index 8ac3ae4..354fbc1 100644 --- a/frontend/__tests__/__snapshots__/Nav.test.js.snap +++ b/frontend/__tests__/__snapshots__/Nav.test.js.snap @@ -2,7 +2,7 @@ exports[`<Nav></Nav> Renders minimal nav when logged out 1`] = ` <ul - className="sc-htpNat jQXYY" + className="sc-dnqmqq kxZizK" data-test="nav" > <Link diff --git a/frontend/__tests__/__snapshots__/Pagination.test.js.snap b/frontend/__tests__/__snapshots__/Pagination.test.js.snap index ed10448..c757968 100644 --- a/frontend/__tests__/__snapshots__/Pagination.test.js.snap +++ b/frontend/__tests__/__snapshots__/Pagination.test.js.snap @@ -5,6 +5,9 @@ exports[`<Pagination/> displays loading message 1`] = ` className="sc-bdVaJa ijYKGd" data-test="pagination" > + <SideEffect(Head)> + <Head /> + </SideEffect(Head)> <Link href={ Object { diff --git a/frontend/components/CreateItem.js b/frontend/components/CreateItem.js index fc3dcb2..fbe9083 100644 --- a/frontend/components/CreateItem.js +++ b/frontend/components/CreateItem.js @@ -1,10 +1,12 @@ import React, { Component } from 'react'; import { Mutation } from 'react-apollo'; import Router from 'next/router'; +import wait from 'waait'; import gql from 'graphql-tag'; import Error from './ErrorMessage'; import Form from './styles/Form'; import formatMoney from '../lib/formatMoney'; +import { ALL_ITEMS_QUERY } from './Items'; const CREATE_ITEM_MUTATION = gql` mutation CREATE_ITEM_MUTATION( @@ -63,13 +65,19 @@ class CreateItem extends Component { render() { return ( - <Mutation mutation={CREATE_ITEM_MUTATION} variables={this.state}> + <Mutation + mutation={CREATE_ITEM_MUTATION} + variables={this.state} + refetchQueries={[{ query: ALL_ITEMS_QUERY }]} + > {(createItem, { loading, error }) => ( <Form data-test onSubmit={async e => { e.preventDefault(); const { data: { createItem: item } } = await createItem(); + // we wait 0 ms so it puts the router push at the end of the call stack. This ensures that refetchQueries runs before we unmount the component :) + await wait(); Router.push({ pathname: `/item`, query: { id: item.id }, diff --git a/frontend/components/DeleteItem.js b/frontend/components/DeleteItem.js index 9b09378..21f559c 100644 --- a/frontend/components/DeleteItem.js +++ b/frontend/components/DeleteItem.js @@ -2,7 +2,9 @@ import React from 'react'; import { Mutation } from 'react-apollo'; import PropTypes from 'prop-types'; import gql from 'graphql-tag'; +import { withRouter } from 'next/router'; import { ALL_ITEMS_QUERY } from './Items'; +import { perPage } from '../config'; const DELETE_ITEM_MUTATION = gql` mutation deleteItem($id: ID!) { @@ -21,18 +23,31 @@ class DeleteItem extends React.Component { update = (cache, payload) => { const deletedItem = payload.data.deleteItem; - const data = cache.readQuery({ query: ALL_ITEMS_QUERY }); + const { page = 1 } = this.props.router.query; + const skip = page * perPage - perPage; + const variables = { skip }; + // TODO Expose Page Number here + const data = cache.readQuery({ query: ALL_ITEMS_QUERY, variables }); + console.log(data.items); // filter this one out data.items = data.items.filter(item => item.id !== deletedItem.id); // write the data back to the cache - cache.writeQuery({ query: ALL_ITEMS_QUERY, data }); + console.log(data.items); + cache.writeQuery({ query: ALL_ITEMS_QUERY, data, variables }); }; render() { + console.log(this.props.router.query); return ( <Mutation mutation={DELETE_ITEM_MUTATION} variables={{ id: this.props.id }} + refetchQueries={[ + { + query: ALL_ITEMS_QUERY, + variables: { skip: this.props.router.query.page * perPage - perPage }, + }, + ]} update={this.update} > {(removeItem, { error }) => ( @@ -51,5 +66,5 @@ class DeleteItem extends React.Component { } } -export default DeleteItem; +export default withRouter(DeleteItem); export { DELETE_ITEM_MUTATION }; diff --git a/frontend/components/Items.js b/frontend/components/Items.js index 394f16d..5694d0b 100644 --- a/frontend/components/Items.js +++ b/frontend/components/Items.js @@ -9,7 +9,7 @@ import LoadingItem from './LoadingItem'; import { perPage } from '../config'; const ALL_ITEMS_QUERY = gql` - query ALL_ITEMS_QUERY($skip: Int = 0, $first: Int = 4) { + query ALL_ITEMS_QUERY($skip: Int = 0, $first: Int = ${perPage}) { items(orderBy: createdAt_DESC, first: $first, skip: $skip) { __typename id diff --git a/frontend/components/Order.js b/frontend/components/Order.js index 6411abe..b4a0a0e 100644 --- a/frontend/components/Order.js +++ b/frontend/components/Order.js @@ -15,6 +15,9 @@ const SINGLE_ORDER_QUERY = gql` charge total createdAt + user { + id + } items { id title diff --git a/frontend/components/Pagination.js b/frontend/components/Pagination.js index 8b25e06..b77f8f6 100644 --- a/frontend/components/Pagination.js +++ b/frontend/components/Pagination.js @@ -4,6 +4,7 @@ import styled from 'styled-components'; import Link from 'next/link'; import PropTypes from 'prop-types'; import gql from 'graphql-tag'; +import Head from 'next/head'; import { perPage } from '../config'; const PAGINATION_QUERY = gql` @@ -49,6 +50,11 @@ const Pagination = props => ( const pages = Math.ceil(aggregate.count / perPage); return ( <PaginationStyles data-test="pagination"> + <Head> + <title> + Sick Fits! — Page {page} of {pages} + </title> + </Head> <Link prefetch href={{ diff --git a/frontend/components/RemoveFromCart.js b/frontend/components/RemoveFromCart.js index cf5b6fd..d29cbf1 100644 --- a/frontend/components/RemoveFromCart.js +++ b/frontend/components/RemoveFromCart.js @@ -44,7 +44,7 @@ class RemoveFromCart extends Component { update={this.update} > {(removeFromCart, { loading }) => ( - <BigButton disabled={loading} title="Remove From Cart" onClick={removeFromCart}> + <BigButton disabled={loading} title="Remove From Cart" onClick={() => removeFromCart}> × </BigButton> )} diff --git a/frontend/components/SingleItem.js b/frontend/components/SingleItem.js index d543ad1..83ef8a0 100644 --- a/frontend/components/SingleItem.js +++ b/frontend/components/SingleItem.js @@ -1,6 +1,7 @@ import { Query } from 'react-apollo'; import PropTypes from 'prop-types'; import styled from 'styled-components'; +import Head from 'next/head'; import Link from 'next/link'; import gql from 'graphql-tag'; import Error from './ErrorMessage'; @@ -29,7 +30,7 @@ const SingleItemStyles = styled.div` img { width: 100%; height: 100%; - object-fit: cover; + object-fit: contain; } .details { margin: 3rem; @@ -45,6 +46,9 @@ const SingleItem = props => ( const [item] = data.items; return ( <SingleItemStyles data-test="SingleItem"> + <Head> + <title>{item.title}</title> + </Head> <img src={item.largeImage || item.image} alt={item.title} /> <div className="details"> <h2>Viewing {item.title}</h2> diff --git a/frontend/components/styles/ItemStyles.js b/frontend/components/styles/ItemStyles.js index 8ae0836..b117d5f 100644 --- a/frontend/components/styles/ItemStyles.js +++ b/frontend/components/styles/ItemStyles.js @@ -5,28 +5,28 @@ const Item = styled.div` border: 1px solid ${props => props.theme.offWhite}; box-shadow: ${props => props.theme.bs}; position: relative; - display: grid; - align-content: start; - grid-auto-rows: fit-content; + display: flex; + flex-direction: column; img { width: 100%; height: 400px; object-fit: cover; } p { - font-size: 14px; + font-size: 12px; line-height: 2; - font-weight: 600; + font-weight: 300; + flex-grow: 1; padding: 0 3rem; font-size: 1.5rem; } .buttonList { display: grid; + width: 100%; 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; diff --git a/frontend/package.json b/frontend/package.json index bd01c42..e826aac 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -33,7 +33,8 @@ "react-dom": "^16.3.2", "react-stripe-checkout": "^2.6.3", "react-transition-group": "^2.3.1", - "styled-components": "^3.2.6" + "styled-components": "^3.2.6", + "waait": "^1.0.2" }, "devDependencies": { "babel-jest": "^23.0.0", @@ -45,8 +46,7 @@ "graphql-tools": "^3.0.2", "jest": "^22.4.4", "jest-transform-graphql": "^2.1.0", - "next-plugin-graphql": "0.0.1", - "waait": "^1.0.2" + "next-plugin-graphql": "0.0.1" }, "//": "This is out babel config, I prefer this over a .babelrc file", "jest": { |
