diff options
| author | Wes Bos <wesbos@gmail.com> | 2017-08-08 22:09:05 -0400 |
|---|---|---|
| committer | Wes Bos <wesbos@gmail.com> | 2017-08-08 22:09:05 -0400 |
| commit | 222ab374d53a206332b1ab51c7c43f6d5dc7a31e (patch) | |
| tree | 2b446d96bfc6c7efab07f3d0fbb84d96ecb1253b /components | |
yep
Diffstat (limited to 'components')
| -rw-r--r-- | components/Count.js | 37 | ||||
| -rw-r--r-- | components/CreateItem.js | 100 | ||||
| -rw-r--r-- | components/Items.js | 83 | ||||
| -rw-r--r-- | components/UpdateItem.js | 82 |
4 files changed, 302 insertions, 0 deletions
diff --git a/components/Count.js b/components/Count.js new file mode 100644 index 0000000..800a902 --- /dev/null +++ b/components/Count.js @@ -0,0 +1,37 @@ +import React, { Component } from 'react' +import { graphql, gql } from 'react-apollo' + +import { ALL_ITEMS_QUERY } from '../queries'; + +class Count extends Component { + + render() { + + // 1 + if (this.props.allLinksQuery && this.props.allLinksQuery.loading) { + return <div>Loading</div> + } + + // 2 + if (this.props.allLinksQuery && this.props.allLinksQuery.error) { + return <div>Error</div> + } + + // 3 + const itemsToRender = this.props.allLinksQuery.allItems + + return ( + <div> + <h1>There are {itemsToRender.length} items for sale</h1> + </div> + ) + } + +} + +// 1 + +// We export the graphQL HOC - this will fetch the data and inject it into the Count compeont via props + +export { ALL_ITEMS_QUERY } +export default graphql(ALL_ITEMS_QUERY, { name: 'allLinksQuery' }) (Count) diff --git a/components/CreateItem.js b/components/CreateItem.js new file mode 100644 index 0000000..843263c --- /dev/null +++ b/components/CreateItem.js @@ -0,0 +1,100 @@ +import React, { Component } from 'react' +import { graphql, gql } from 'react-apollo' +import { ALL_ITEMS_QUERY, CREATE_LINK_MUTATION } from '../queries'; + +class CreateLink extends Component { + + state = { + description: '', + title: '', + image: '', + loading: false + } + + componentWillReceiveProps(nextProps) { + console.log(nextProps); + } + + uploadFile = async (e) => { + const files = e.currentTarget.files; + + let data = new FormData(); + data.append('data', files[0]); + + // use the file endpoint + const res = await fetch('https://api.graph.cool/file/v1/cj5xz8szs28930145gct82bdj', { + method: 'POST', + body: data + }); + const file = await res.json(); + console.log(file); + this.setState({ image: file.id }); + } + + render() { + return ( + <div> + { this.state.loading ? 'LOADING...' : 'Ready!' } + <form onSubmit={this._createLink}> + <p>Image: {this.state.image}</p> + <input + value={this.state.title} + onChange={(e) => this.setState({ title: e.target.value })} + type='text' + placeholder='A description for the link' + /> + <input + onChange={this.uploadFile} + type='file' + /> + <textarea + value={this.state.description} + onChange={(e) => this.setState({ description: e.target.value })} + type='text' + placeholder='The desc for this item' + ></textarea> + <button type="submit">Submit</button> + </form> + </div> + ) + } + + _createLink = async (e) => { + e.preventDefault(); + // pull the values from state + const { description, title, image } = this.state + // create a mutation + // TODO: handle any errors + // turn loading on + this.setState({ loading: true }); + const res = await this.props.createLinkMutation({ + // pass in those variables from state + variables: { + description, + title, + imageId: image + } + }); + 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_LINK_MUTATION, { name: 'createLinkMutation', 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! + update: (proxy, { data: { createItem } }) => { + console.log({createItem, ALL_ITEMS_QUERY}); + const data = proxy.readQuery({ query: ALL_ITEMS_QUERY }); + // data is our store, allItems is our sub-"state", it's just an array. We can just add it to + data.allItems.unshift(createItem); + // and then "set state", so it will update on the page. This will update the cache for us! + proxy.writeQuery({ query: ALL_ITEMS_QUERY, data }); + }, + } })(CreateLink) diff --git a/components/Items.js b/components/Items.js new file mode 100644 index 0000000..1e6b3bf --- /dev/null +++ b/components/Items.js @@ -0,0 +1,83 @@ +import React, { Component } from 'react' +import { graphql, compose } from 'react-apollo' +import UpdateItem from './UpdateItem'; +import Link from 'next/link'; +import styled from 'styled-components'; + +import { ALL_ITEMS_QUERY, DELETE_ITEM_MUTATION } from '../queries'; + +const Title = styled.h1` + font-size: 50px; +`; + +class ItemList extends Component { + + render() { + + // 1 + if (this.props.allLinksQuery && this.props.allLinksQuery.loading) { + return <div>Loading</div> + } + + // 2 + if (this.props.allLinksQuery && this.props.allLinksQuery.error) { + console.log(this.props.allLinksQuery.error) + return <div>Error</div> + } + + // 3 + const itemsToRender = this.props.allLinksQuery.allItems + + return ( + <div> + <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 } + <h3>{item.title}</h3> + <p>{item.description}</p> + <Link href={{ + pathname: '/admin/update', + query: { id: item.id } + }}> + <a>Edit {item.id}</a> + </Link> + + <UpdateItem id={item.id} /> + + <button onClick={() => this.props.removeItemMutation({ variables: { id: item.id }})}>× Delete item</button> + + </div> + ))} + </div> + ) + } + +} + +// 1 + +// We export the graphQL HOC - this will fetch the data and inject it into the ItemList compeont via props + +// Create some Enhancers +const itemsEnahncer = graphql(ALL_ITEMS_QUERY, { name: 'allLinksQuery' }); +const deleteItemEnhancer = graphql(DELETE_ITEM_MUTATION, { + name: 'removeItemMutation', + options: { + update: (proxy, { data: { deleteItem } }) => { + + // grab the data from our cache + const data = proxy.readQuery({ query: ALL_ITEMS_QUERY }); + + // filter out the delted item + data.allItems = data.allItems.filter(item => item.id !== deleteItem.id); + + // and then "set state" (update cache), so it will update whereever we have used this data on the page + proxy.writeQuery({ query: ALL_ITEMS_QUERY, data }); + + }, + } +}); + +export default compose(itemsEnahncer, deleteItemEnhancer)(ItemList) diff --git a/components/UpdateItem.js b/components/UpdateItem.js new file mode 100644 index 0000000..8ca8b73 --- /dev/null +++ b/components/UpdateItem.js @@ -0,0 +1,82 @@ +import React, { Component } from 'react' +import { graphql, gql, compose } from 'react-apollo' +import { SINGLE_LINK_QUERY, UPDATE_LINK_MUTATION } from '../queries'; + +class UpdateLink extends Component { + + state = { + ...this.props.findItem.Item, + price: 0, + fullPrice: 0 + } + + saveToState = (e) => { + let { name, value, type } = e.target; + if (type === 'number') { + value = parseInt(value); + } + + this.setState({ [name]: value }); + } + + render() { + return ( + <div> + + <h2>Edit {this.props.id}</h2> + { this.state.loading ? 'LOADING...' : 'Ready!' } + <form onSubmit={this._createLink}> + + <label htmlFor="title">Title</label> + <input value={this.state.title} name="title" onChange={this.saveToState} type='text'/> + + <label htmlFor="description">Description</label> + <textarea value={this.state.description} name="description" onChange={this.saveToState}></textarea> + + <label htmlFor="price">Price</label> + <input type="number" name="price" onChange={this.saveToState} value={this.state.price} /> + + <label htmlFor="fullPrice">Full Price</label> + <input type="number" name="fullPrice" onChange={this.saveToState} value={this.state.fullPrice} /> + + <button type="submit">Save...</button> + </form> + </div> + ) + } + + _createLink = async (e) => { + e.preventDefault(); + // pull the values from state + const { description, title } = this.state + const { id } = this.props; + // create a mutation + // TODO: handle any errors + // turn loading on + this.setState({ loading: true }); + console.log(this.state); + const res = await this.props.updateItem({ + // pass in those variables from state + variables: { + ...this.state + } + }); + this.setState({ loading: false }); + } + +} + +const ComponentWithMutations = compose( + // First, query for getting the link + graphql(SINGLE_LINK_QUERY, { + name: 'findItem', + options: ({ id }) => ({ + variables: { id } + }) + }), + // Second, the mutation for updating the link + graphql(UPDATE_LINK_MUTATION, { name: 'updateItem' }) +)(UpdateLink); + + +export default ComponentWithMutations; |
