Skip to content

Commit 7c59701

Browse files
committed
Reviews subscriptions
1 parent a32be98 commit 7c59701

File tree

5 files changed

+126
-4
lines changed

5 files changed

+126
-4
lines changed
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import React, { Component } from 'react'
2+
import { Subscription } from 'react-apollo'
3+
import Snackbar from '@material-ui/core/Snackbar'
4+
5+
import { ON_REVIEW_CREATED_SUBSCRIPTION } from '../graphql/Review'
6+
7+
class ReviewCreatedNotification extends Component {
8+
state = {
9+
isOpen: false
10+
}
11+
12+
close = () => {
13+
this.setState({ isOpen: false })
14+
}
15+
16+
open = () => {
17+
this.setState({ isOpen: true })
18+
setTimeout(this.close, 5000)
19+
}
20+
21+
render() {
22+
return (
23+
<Subscription
24+
subscription={ON_REVIEW_CREATED_SUBSCRIPTION}
25+
onSubscriptionData={this.open}
26+
>
27+
{({ data }) =>
28+
data && data.reviewCreated ? (
29+
<Snackbar
30+
anchorOrigin={{ vertical: 'bottom', horizontal: 'center' }}
31+
open={this.state.isOpen}
32+
onClose={this.close}
33+
message={`New review from ${data.reviewCreated.author.name}: ${
34+
data.reviewCreated.text
35+
}`}
36+
/>
37+
) : null
38+
}
39+
</Subscription>
40+
)
41+
}
42+
}
43+
44+
export default ReviewCreatedNotification

src/components/ReviewForm.js

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -163,8 +163,12 @@ const withAddReview = graphql(ADD_REVIEW_MUTATION, {
163163
}
164164

165165
let data = store.readQuery(query)
166-
data.reviews.unshift(newReview)
167-
store.writeQuery({ ...query, data })
166+
167+
const alreadyHaveNewReview = data.reviews[0].id === newReview.id
168+
if (!alreadyHaveNewReview) {
169+
data.reviews.unshift(newReview)
170+
store.writeQuery({ ...query, data })
171+
}
168172

169173
query.variables.orderBy = 'createdAt_ASC'
170174

src/components/ReviewList.js

Lines changed: 50 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,24 @@ import React, { Component } from 'react'
22
import PropTypes from 'prop-types'
33
import { graphql } from 'react-apollo'
44
import { propType } from 'graphql-anywhere'
5+
import reject from 'lodash/reject'
56

67
import Review from './Review'
78

8-
import { REVIEWS_QUERY, REVIEW_ENTRY } from '../graphql/Review'
9+
import {
10+
REVIEWS_QUERY,
11+
REVIEW_ENTRY,
12+
ON_REVIEW_CREATED_SUBSCRIPTION,
13+
ON_REVIEW_UPDATED_SUBSCRIPTION,
14+
ON_REVIEW_DELETED_SUBSCRIPTION
15+
} from '../graphql/Review'
916

1017
const FETCH_MORE = 3
1118

1219
class ReviewList extends Component {
1320
componentDidMount() {
1421
window.addEventListener('scroll', this.handleScroll)
22+
this.props.subscribeToReviewUpdates()
1523
}
1624

1725
componentWillUnmount() {
@@ -60,7 +68,10 @@ const withReviews = graphql(REVIEWS_QUERY, {
6068
variables: { limit: 10, orderBy },
6169
notifyOnNetworkStatusChange: true
6270
}),
63-
props: ({ data: { reviews, fetchMore, networkStatus } }) => ({
71+
props: ({
72+
data: { reviews, fetchMore, networkStatus, subscribeToMore },
73+
ownProps: { orderBy }
74+
}) => ({
6475
reviews,
6576
networkStatus,
6677
loadMoreReviews: () => {
@@ -82,6 +93,43 @@ const withReviews = graphql(REVIEWS_QUERY, {
8293
}
8394
}
8495
})
96+
},
97+
subscribeToReviewUpdates: () => {
98+
subscribeToMore({
99+
document: ON_REVIEW_CREATED_SUBSCRIPTION,
100+
updateQuery: (prev, { subscriptionData }) => {
101+
// Assuming infinite reviews, we don't need to add new reviews to
102+
// Oldest list
103+
if (orderBy === 'createdAt_ASC') {
104+
return prev
105+
}
106+
107+
const newReview = subscriptionData.data.reviewCreated
108+
return {
109+
reviews: [newReview, ...prev.reviews]
110+
}
111+
}
112+
})
113+
subscribeToMore({
114+
document: ON_REVIEW_UPDATED_SUBSCRIPTION,
115+
updateQuery: (prev, { subscriptionData }) => {
116+
const updatedReview = subscriptionData.data.reviewUpdated
117+
return {
118+
reviews: prev.reviews.map(review =>
119+
review.id === updatedReview.id ? updatedReview : review
120+
)
121+
}
122+
}
123+
})
124+
subscribeToMore({
125+
document: ON_REVIEW_DELETED_SUBSCRIPTION,
126+
updateQuery: (prev, { subscriptionData }) => {
127+
const deletedId = subscriptionData.data.reviewDeleted
128+
return {
129+
reviews: reject(prev.reviews, { id: deletedId })
130+
}
131+
}
132+
})
85133
}
86134
})
87135
})

src/components/Reviews.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import Select from 'material-ui/Select'
1212
import ReviewList from './ReviewList'
1313
import { withUser } from '../lib/withUser'
1414
import ReviewForm from './ReviewForm'
15+
import ReviewCreatedNotification from './ReviewCreatedNotification'
1516

1617
class Reviews extends Component {
1718
state = {
@@ -62,6 +63,7 @@ class Reviews extends Component {
6263
</div>
6364

6465
<ReviewList user={user} orderBy={this.state.orderBy} />
66+
<ReviewCreatedNotification />
6567

6668
{user && (
6769
<div>

src/graphql/Review.js

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,27 @@ export const REVIEWS_QUERY = gql`
2424
}
2525
${REVIEW_ENTRY}
2626
`
27+
28+
export const ON_REVIEW_CREATED_SUBSCRIPTION = gql`
29+
subscription onReviewCreated {
30+
reviewCreated {
31+
...ReviewEntry
32+
}
33+
}
34+
${REVIEW_ENTRY}
35+
`
36+
37+
export const ON_REVIEW_UPDATED_SUBSCRIPTION = gql`
38+
subscription onReviewUpdated {
39+
reviewUpdated {
40+
...ReviewEntry
41+
}
42+
}
43+
${REVIEW_ENTRY}
44+
`
45+
46+
export const ON_REVIEW_DELETED_SUBSCRIPTION = gql`
47+
subscription onReviewDeleted {
48+
reviewDeleted
49+
}
50+
`

0 commit comments

Comments
 (0)