summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWes Bos <wesbos@gmail.com>2018-05-25 14:06:53 -0400
committerWes Bos <wesbos@gmail.com>2018-05-25 14:06:53 -0400
commit22635ea05dab85a71fa93dbb98f93da7670ef899 (patch)
treeb9e974dee484634d0401a9149c9a68f5537553db
parent549cfa77c9fec0936c3a8d87a49b69401cbfbd7a (diff)
Delete and Add refetch refinements
-rw-r--r--backend/prisma/datamodel.graphql4
-rw-r--r--backend/src/generated/prisma.graphql15
-rw-r--r--backend/src/resolvers/Mutation.js11
-rw-r--r--frontend/README.md42
-rw-r--r--frontend/__tests__/__snapshots__/Nav.test.js.snap2
-rw-r--r--frontend/__tests__/__snapshots__/Pagination.test.js.snap3
-rw-r--r--frontend/components/CreateItem.js10
-rw-r--r--frontend/components/DeleteItem.js21
-rw-r--r--frontend/components/Items.js2
-rw-r--r--frontend/components/Order.js3
-rw-r--r--frontend/components/Pagination.js6
-rw-r--r--frontend/components/RemoveFromCart.js2
-rw-r--r--frontend/components/SingleItem.js6
-rw-r--r--frontend/components/styles/ItemStyles.js12
-rw-r--r--frontend/package.json6
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": {