diff --git a/components/Author.vue b/components/Author.vue
index f1f57113b..54770d33d 100644
--- a/components/Author.vue
+++ b/components/Author.vue
@@ -107,7 +107,9 @@
author.followedByCurrentUser = follow"
+ @update="follow => author.followedByCurrentUser = follow"
/>
@@ -139,21 +141,12 @@ export default {
trunc: { type: Number, default: null },
showAuthorPopover: { type: Boolean, default: true }
},
- data() {
- return {
- voted: false
- }
- },
computed: {
itsMe() {
return this.author.slug === this.$store.getters['auth/user'].slug
},
fanCount() {
let count = Number(this.author.followedByCount) || 0
- if (this.voted) {
- // NOTE: this is used for presentation
- count += 1
- }
return count
},
author() {
diff --git a/components/FollowButton.vue b/components/FollowButton.vue
index 3540726d2..f5c705a8d 100644
--- a/components/FollowButton.vue
+++ b/components/FollowButton.vue
@@ -2,12 +2,15 @@
- Folgen
+ {{ label }}
@@ -18,37 +21,69 @@ export default {
name: 'HcFollowButton',
props: {
- followId: { type: String, default: null }
+ followId: { type: String, default: null },
+ isFollowed: { type: Boolean, default: false }
},
data() {
return {
disabled: false,
- loading: false
+ loading: false,
+ hovered: false
+ }
+ },
+ computed: {
+ icon() {
+ if (this.isFollowed && this.hovered) {
+ return 'close'
+ } else {
+ return this.isFollowed ? 'check' : 'plus'
+ }
+ },
+ label() {
+ if (this.isFollowed) {
+ return this.$t('followButton.following')
+ } else {
+ return this.$t('followButton.follow')
+ }
+ }
+ },
+ watch: {
+ isFollowed() {
+ this.loading = false
+ this.hovered = false
}
},
methods: {
- follow() {
- this.loading = true
+ onHover() {
+ if (!this.disabled && !this.loading) {
+ this.hovered = true
+ }
+ },
+ toggle() {
+ const follow = !this.isFollowed
+ const mutation = follow ? 'follow' : 'unfollow'
+
+ this.hovered = false
+
+ this.$emit('optimistic', follow)
+
this.$apollo
.mutate({
mutation: gql`
- mutation($myId: ID!, $followId: ID!) {
- AddUserFollowing(from: { id: $myId }, to: { id: $followId }) {
- from {
- id
- }
- }
+ mutation($id: ID!) {
+ ${mutation}(id: $id, type: User)
}
`,
variables: {
- myId: this.$store.getters['auth/user'].id,
- followId: this.followId
+ id: this.followId
}
})
- .then(() => {
- this.loading = false
- this.disabled = true
- this.$emit('update')
+ .then(res => {
+ // this.$emit('optimistic', follow ? res.data.follow : follow)
+ this.$emit('update', follow)
+ })
+ .catch(() => {
+ this.$emit('optimistic', !follow)
})
}
}
diff --git a/components/ShoutButton.vue b/components/ShoutButton.vue
index 075006b2e..02d7cb639 100644
--- a/components/ShoutButton.vue
+++ b/components/ShoutButton.vue
@@ -4,20 +4,25 @@
style="text-align: center"
>
-
+
{{ shoutedCount }}x
- Empfohlen
+ {{ $t('shoutButton.shouted') }}
@@ -28,41 +33,69 @@ import gql from 'graphql-tag'
export default {
props: {
count: { type: Number, default: 0 },
- postId: { type: String, default: null }
+ postId: { type: String, default: null },
+ isShouted: { type: Boolean, default: false },
+ disabled: { type: Boolean, default: false }
},
data() {
return {
loading: false,
- disabled: false,
- shoutedCount: this.count
+ shoutedCount: this.count,
+ shouted: false
+ }
+ },
+ watch: {
+ isShouted: {
+ immediate: true,
+ handler: function(shouted) {
+ this.shouted = shouted
+ }
}
},
methods: {
- shout() {
- this.loading = true
+ toggle() {
+ const shout = !this.shouted
+ const mutation = shout ? 'shout' : 'unshout'
+ const count = shout ? this.shoutedCount + 1 : this.shoutedCount - 1
+
+ const backup = {
+ shoutedCount: this.shoutedCount,
+ shouted: this.shouted
+ }
+
+ this.shoutedCount = count
+ this.shouted = shout
+
this.$apollo
.mutate({
mutation: gql`
- mutation($myId: ID!, $postId: ID!) {
- AddUserShouted(from: { id: $myId }, to: { id: $postId }) {
- from {
- id
- }
- }
+ mutation($id: ID!) {
+ ${mutation}(id: $id, type: Post)
}
`,
variables: {
- myId: this.$store.getters['auth/user'].id,
- postId: this.postId
+ id: this.postId
}
})
- .then(() => {
+ .then(res => {
+ if (res && res.data) {
+ this.$emit('update', shout)
+ }
+ })
+ .catch(() => {
+ this.shoutedCount = backup.shoutedCount
+ this.shouted = backup.shouted
+ })
+ .finally(() => {
this.loading = false
- this.disabled = true
- this.shoutedCount++
- this.$emit('update')
})
}
}
}
+
+
diff --git a/graphql/UserProfileQuery.js b/graphql/UserProfileQuery.js
index 4e0245b52..30431602b 100644
--- a/graphql/UserProfileQuery.js
+++ b/graphql/UserProfileQuery.js
@@ -29,6 +29,7 @@ export default app => {
slug
avatar
followedByCount
+ followedByCurrentUser
contributionsCount
commentsCount
badges {
@@ -41,12 +42,14 @@ export default app => {
}
}
followedByCount
+ followedByCurrentUser
followedBy(first: 7) {
id
name
slug
avatar
followedByCount
+ followedByCurrentUser
contributionsCount
commentsCount
badges {
diff --git a/locales/de.json b/locales/de.json
index c0275a928..0c3d8cfd3 100644
--- a/locales/de.json
+++ b/locales/de.json
@@ -28,6 +28,13 @@
"moreInfo": "Was ist Human Connection?",
"hello": "Hallo"
},
+ "followButton": {
+ "follow": "Folgen",
+ "following": "Folge Ich"
+ },
+ "shoutButton": {
+ "shouted": "empfohlen"
+ },
"profile": {
"name": "Mein Profil",
"memberSince": "Mitglied seit",
diff --git a/locales/en.json b/locales/en.json
index cfe889d1e..35d3122f2 100644
--- a/locales/en.json
+++ b/locales/en.json
@@ -28,6 +28,13 @@
"moreInfo": "What is Human Connection?",
"hello": "Hello"
},
+ "followButton": {
+ "follow": "Follow",
+ "following": "Following"
+ },
+ "shoutButton": {
+ "shouted": "shouted"
+ },
"profile": {
"name": "My Profile",
"memberSince": "Member since",
diff --git a/package.json b/package.json
index 8cc7620fa..e0cafe56f 100644
--- a/package.json
+++ b/package.json
@@ -55,7 +55,7 @@
"v-tooltip": "~2.0.0-rc.33",
"vue-count-to": "~1.0.13",
"string-hash": "^1.1.3",
- "tiptap": "^1.13.0",
+ "tiptap": "^1.14.0",
"tiptap-extensions": "^1.13.0",
"vue-izitoast": "1.1.2",
"vue-sweetalert-icons": "~3.2.0",
diff --git a/pages/index.vue b/pages/index.vue
index 7bc85b3a4..f4785b3ac 100644
--- a/pages/index.vue
+++ b/pages/index.vue
@@ -108,6 +108,7 @@ export default {
shoutedCount
commentsCount
followedByCount
+ followedByCurrentUser
location {
name: name${this.$i18n.locale().toUpperCase()}
}
diff --git a/pages/post/_slug/index.vue b/pages/post/_slug/index.vue
index f3726d6db..e6abcd1e2 100644
--- a/pages/post/_slug/index.vue
+++ b/pages/post/_slug/index.vue
@@ -32,7 +32,9 @@
@@ -168,69 +170,72 @@ export default {
} = context
const client = apolloProvider.defaultClient
const query = gql(`
- query Post($slug: String!) {
- Post(slug: $slug) {
+ query Post($slug: String!) {
+ Post(slug: $slug) {
+ id
+ title
+ content
+ createdAt
+ slug
+ image
+ author {
+ id
+ slug
+ name
+ avatar
+ shoutedCount
+ contributionsCount
+ commentsCount
+ followedByCount
+ followedByCurrentUser
+ location {
+ name: name${$i18n.locale().toUpperCase()}
+ }
+ badges {
id
- title
- content
- createdAt
- slug
- image
- author {
- id
- slug
- name
- avatar
- shoutedCount
- contributionsCount
- commentsCount
- followedByCount
- location {
- name: name${$i18n.locale().toUpperCase()}
- }
- badges {
- id
- key
- icon
- }
- }
- tags {
- name
- }
- commentsCount
- comments(orderBy: createdAt_desc) {
- id
- contentExcerpt
- createdAt
- deleted
- author {
- id
- slug
- name
- avatar
- shoutedCount
- contributionsCount
- commentsCount
- followedByCount
- location {
- name: name${$i18n.locale().toUpperCase()}
- }
- badges {
- id
- key
- icon
- }
- }
- }
- categories {
- id
- name
- icon
- }
- shoutedCount
+ key
+ icon
}
}
- `)
+ tags {
+ name
+ }
+ commentsCount
+ comments(orderBy: createdAt_desc) {
+ id
+ contentExcerpt
+ createdAt
+ deleted
+ author {
+ id
+ slug
+ name
+ avatar
+ shoutedCount
+ contributionsCount
+ commentsCount
+ followedByCount
+ followedByCurrentUser
+ location {
+ name: name${$i18n.locale().toUpperCase()}
+ }
+ badges {
+ id
+ key
+ icon
+ }
+ }
+ }
+ categories {
+ id
+ name
+ icon
+ }
+ shoutedCount
+ shoutedByCurrentUser
+ }
+ }
+ `)
const variables = { slug: params.slug }
const {
data: { Post }
diff --git a/pages/post/_slug/more-info.vue b/pages/post/_slug/more-info.vue
index 847975757..d4de5f6f3 100644
--- a/pages/post/_slug/more-info.vue
+++ b/pages/post/_slug/more-info.vue
@@ -109,6 +109,7 @@ export default {
avatar
contributionsCount
followedByCount
+ followedByCurrentUser
commentsCount
location {
name: name${this.$i18n.locale().toUpperCase()}
diff --git a/pages/profile/_slug.vue b/pages/profile/_slug.vue
index 98d3b9f48..614187004 100644
--- a/pages/profile/_slug.vue
+++ b/pages/profile/_slug.vue
@@ -61,7 +61,7 @@
-
+
-
+
user.followedByCurrentUser = follow"
+ @update="follow => fetchUser()"
/>
@@ -335,10 +337,6 @@ export default {
},
followedByCount() {
let count = Number(this.user.followedByCount) || 0
- if (this.voted) {
- // NOTE: this is used for presentation
- count += 1
- }
return count
},
user() {
diff --git a/yarn.lock b/yarn.lock
index 81e60045b..72992506f 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -9451,15 +9451,15 @@ prosemirror-transform@^1.0.0, prosemirror-transform@^1.1.0:
dependencies:
prosemirror-model "^1.0.0"
-prosemirror-utils@^0.7.5:
+prosemirror-utils@^0.7.5, prosemirror-utils@^0.7.6:
version "0.7.6"
resolved "https://registry.yarnpkg.com/prosemirror-utils/-/prosemirror-utils-0.7.6.tgz#c462ddfbf2452e56e4b25d1f02b34caccddb0f33"
integrity sha512-vzsCBTiJ56R3nRDpIJnKOJzsZP7KFO8BkXk7zvQgQiXpml2o/djPCRhuyaFc7VTqSHlLPQHVI1feTLAwHp+prQ==
-prosemirror-view@^1.0.0, prosemirror-view@^1.1.0, prosemirror-view@^1.7.1:
- version "1.7.1"
- resolved "https://registry.yarnpkg.com/prosemirror-view/-/prosemirror-view-1.7.1.tgz#f0ea75faa6d7bd25ea22897dd5bae35708c59a28"
- integrity sha512-UFY/h4i5H1Yen8u2ZTve0WL+nh/y1qU3geC3SrWl5yIKSgGbvllD5vr5LxmeRgVsY8hb+oDXRHk5KvLwqmu7Lg==
+prosemirror-view@^1.0.0, prosemirror-view@^1.1.0, prosemirror-view@^1.7.1, prosemirror-view@^1.8.3:
+ version "1.8.3"
+ resolved "https://registry.yarnpkg.com/prosemirror-view/-/prosemirror-view-1.8.3.tgz#f8deff22c7d371f63db2686ac6f3661ded1b3ae3"
+ integrity sha512-CAW3SycaJgfPlWwYcDGiwNaCwcikBLSFAgLF+H+bTn0aCAUzcl2DXQdU9dMvK3HeWG+6Xn/QPQbhyyqCcV3ZBw==
dependencies:
prosemirror-model "^1.1.0"
prosemirror-state "^1.0.0"
@@ -11041,16 +11041,16 @@ timsort@^0.3.0:
resolved "https://registry.yarnpkg.com/timsort/-/timsort-0.3.0.tgz#405411a8e7e6339fe64db9a234de11dc31e02bd4"
integrity sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q=
-tiptap-commands@^1.6.0:
- version "1.6.0"
- resolved "https://registry.yarnpkg.com/tiptap-commands/-/tiptap-commands-1.6.0.tgz#567b7b218bd7d1c1214534a2007acbb7b8d06688"
- integrity sha512-9HO8UYJz1qGyqsHn0+PifmndlRTInqfcb7vjNDvqWQA2P7r8koJqrP8CYMR0DXQHlys1druJnaBaOzLa1d5PQQ==
+tiptap-commands@^1.6.0, tiptap-commands@^1.7.0:
+ version "1.7.0"
+ resolved "https://registry.yarnpkg.com/tiptap-commands/-/tiptap-commands-1.7.0.tgz#d15cec2cb09264b5c1f6f712dab8819bb9ab7e13"
+ integrity sha512-JhgvBPIhGnisEdxD6gmM3U76BUlKF9n1LW1X/dO1AUOsm3Xc9tQB5BIOV/DpZTvrjntLP3AUTfd+yJeRIz5CPA==
dependencies:
prosemirror-commands "^1.0.7"
prosemirror-inputrules "^1.0.1"
prosemirror-schema-list "^1.0.2"
prosemirror-state "^1.2.2"
- tiptap-utils "^1.2.0"
+ tiptap-utils "^1.3.0"
tiptap-extensions@^1.13.0:
version "1.13.0"
@@ -11066,20 +11066,20 @@ tiptap-extensions@^1.13.0:
tiptap "^1.13.0"
tiptap-commands "^1.6.0"
-tiptap-utils@^1.2.0:
- version "1.2.0"
- resolved "https://registry.yarnpkg.com/tiptap-utils/-/tiptap-utils-1.2.0.tgz#e1e566af1212acff6b2e3c4ca6edc21ebf306440"
- integrity sha512-p8Q0UfNhYHXqMDSwvCc6x0Vm95AYgM/f1V+8oNu9FI0aRWwXpTwIJj+1CAGO1mb6NFUSxn9HcZaUvEcBKR5WzQ==
+tiptap-utils@^1.3.0:
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/tiptap-utils/-/tiptap-utils-1.3.0.tgz#bfc77cf57c07cd5c1f1d33f65ef94c4190506b77"
+ integrity sha512-b9GRQB3Kilu9Yq6hwjjzQgZtQDXDOrB/vZPV5OzwcKRN5a9PfLGrTLJ5LbU414Vcy9HTXiqX2pq0o5FslJhHpg==
dependencies:
prosemirror-model "^1.7.0"
prosemirror-state "^1.2.2"
prosemirror-tables "^0.7.9"
- prosemirror-utils "^0.7.5"
+ prosemirror-utils "^0.7.6"
-tiptap@^1.13.0:
- version "1.13.0"
- resolved "https://registry.yarnpkg.com/tiptap/-/tiptap-1.13.0.tgz#52b086fc8d4df7534123d31571366dd90ee62a23"
- integrity sha512-kwzgtOY5PnbSfzMyNPFchI/Cyi1O3kFNiRP7K4p6t0zcNCXy9EaWgaM/U2bKArI0/HxG/GSPM6RTTCCOF3I6EA==
+tiptap@^1.13.0, tiptap@^1.14.0:
+ version "1.14.0"
+ resolved "https://registry.yarnpkg.com/tiptap/-/tiptap-1.14.0.tgz#8dd84b199533e08f0dcc34b39d517ea73e20fb95"
+ integrity sha512-38gCYeJx5O83oTnpfgMGGrjem1ZNDK2waaUMq+bkYPaQwvvtyMDGffvEIT9/jcLvA+WYfaNp8BWnn1rqNpYKxA==
dependencies:
prosemirror-commands "^1.0.7"
prosemirror-dropcursor "^1.1.1"
@@ -11088,9 +11088,9 @@ tiptap@^1.13.0:
prosemirror-keymap "^1.0.1"
prosemirror-model "^1.7.0"
prosemirror-state "^1.2.1"
- prosemirror-view "^1.7.1"
- tiptap-commands "^1.6.0"
- tiptap-utils "^1.2.0"
+ prosemirror-view "^1.8.3"
+ tiptap-commands "^1.7.0"
+ tiptap-utils "^1.3.0"
title-case@^2.1.1:
version "2.1.1"