From ca190251870c239d49c45d245a2a219fe4169625 Mon Sep 17 00:00:00 2001 From: Henry Jameson <me@hjkos.com> Date: Tue, 4 Dec 2018 12:50:29 +0300 Subject: [PATCH 1/2] Added support for async following including delayed confirmation if we followed user or not --- .../user_card_content/user_card_content.js | 46 +++++++++++++++++++ .../user_card_content/user_card_content.vue | 21 +++++++-- src/i18n/en.json | 4 ++ src/i18n/ru.json | 4 ++ 4 files changed, 71 insertions(+), 4 deletions(-) diff --git a/src/components/user_card_content/user_card_content.js b/src/components/user_card_content/user_card_content.js index b5dd9b91..235cfb49 100644 --- a/src/components/user_card_content/user_card_content.js +++ b/src/components/user_card_content/user_card_content.js @@ -5,6 +5,8 @@ export default { props: [ 'user', 'switcher', 'selected', 'hideBio' ], data () { return { + followRequestInProgress: false, + followRequestSent: false, hideUserStatsLocal: typeof this.$store.state.config.hideUserStats === 'undefined' ? this.$store.state.instance.hideUserStats : this.$store.state.config.hideUserStats @@ -70,13 +72,57 @@ export default { methods: { followUser () { const store = this.$store + this.followRequestInProgress = true store.state.api.backendInteractor.followUser(this.user.id) .then((followedUser) => store.commit('addNewUsers', [followedUser])) + .then(() => { + if (this.user.following) { + this.followRequestInProgress = false + return + } + if (!this.user.locked) { + let attemptsLeft = 3 + const fetchUser = () => new Promise((resolve, reject) => { + setTimeout(() => { + store.state.api.backendInteractor.fetchUser({ id: this.user.id }) + .then((user) => store.commit('addNewUsers', [user])) + .then(() => resolve(this.user.following)) + .catch((e) => reject(e)) + }, 500) + }).then((confirmed) => { + if (!confirmed && attemptsLeft > 0) { + attemptsLeft-- + return fetchUser() + } else if (confirmed) { + return true + } else { + return false + } + }) + + return fetchUser() + .then((successfulConfirmation) => { + if (successfulConfirmation) { + this.followRequestInProgress = false + } else { + this.followRequestInProgress = false + this.followRequestSent = true + } + }) + } else { + this.followRequestInProgress = false + this.followRequestSent = true + } + }) }, unfollowUser () { const store = this.$store + this.followRequestInProgress = true store.state.api.backendInteractor.unfollowUser(this.user.id) .then((unfollowedUser) => store.commit('addNewUsers', [unfollowedUser])) + .then(() => { + this.followRequestInProgress = false + }) }, blockUser () { const store = this.$store diff --git a/src/components/user_card_content/user_card_content.vue b/src/components/user_card_content/user_card_content.vue index 84669d7f..1dcf348f 100644 --- a/src/components/user_card_content/user_card_content.vue +++ b/src/components/user_card_content/user_card_content.vue @@ -44,13 +44,26 @@ <div class="follow" v-if="loggedIn"> <span v-if="user.following"> <!--Following them!--> - <button @click="unfollowUser" class="pressed"> - {{ $t('user_card.following') }} + <button @click="unfollowUser" class="pressed" :disabled="followRequestInProgress" :title="$t('user_card.follow_unfollow')"> + <template v-if="followRequestInProgress"> + {{ $t('user_card.follow_progress') }} + </template> + <template v-else> + {{ $t('user_card.following') }} + </template> </button> </span> <span v-if="!user.following"> - <button @click="followUser"> - {{ $t('user_card.follow') }} + <button @click="followUser" :disabled="followRequestInProgress" :title="followRequestSent ? $t('user_card.follow_again') : ''"> + <template v-if="followRequestInProgress"> + {{ $t('user_card.follow_progress') }} + </template> + <template v-else-if="followRequestSent"> + {{ $t('user_card.follow_sent') }} + </template> + <template v-else> + {{ $t('user_card.follow') }} + </template> </button> </span> </div> diff --git a/src/i18n/en.json b/src/i18n/en.json index 893db931..9d12f09e 100644 --- a/src/i18n/en.json +++ b/src/i18n/en.json @@ -193,6 +193,10 @@ "blocked": "Blocked!", "deny": "Deny", "follow": "Follow", + "follow_sent": "Request sent!", + "follow_progress": "Requesting…", + "follow_again": "Send request again?", + "follow_unfollow": "Stop following", "followees": "Following", "followers": "Followers", "following": "Following!", diff --git a/src/i18n/ru.json b/src/i18n/ru.json index 9c28ccf4..37d88e3c 100644 --- a/src/i18n/ru.json +++ b/src/i18n/ru.json @@ -156,6 +156,10 @@ "block": "Заблокировать", "blocked": "Заблокирован", "follow": "Читать", + "follow_sent": "Запрос отправлен!", + "follow_progress": "Запрашиваем…", + "follow_again": "Запросить еще заново?", + "follow_unfollow": "Перестать читать", "followees": "Читаемые", "followers": "Читатели", "following": "Читаю", From 13fbef4550e0e95024df9f1cc77764b8c734ca3f Mon Sep 17 00:00:00 2001 From: Henry Jameson <me@hjkos.com> Date: Fri, 14 Dec 2018 17:33:48 +0300 Subject: [PATCH 2/2] slightly changed the code to have less mutations, added comments --- .../user_card_content/user_card_content.js | 71 +++++++++++-------- 1 file changed, 41 insertions(+), 30 deletions(-) diff --git a/src/components/user_card_content/user_card_content.js b/src/components/user_card_content/user_card_content.js index 8c6de8ec..206dba88 100644 --- a/src/components/user_card_content/user_card_content.js +++ b/src/components/user_card_content/user_card_content.js @@ -90,43 +90,54 @@ export default { store.state.api.backendInteractor.followUser(this.user.id) .then((followedUser) => store.commit('addNewUsers', [followedUser])) .then(() => { + // For locked users we just mark it that we sent the follow request + if (this.user.locked) { + this.followRequestInProgress = false + this.followRequestSent = true + return + } + if (this.user.following) { + // If we get result immediately, just stop. this.followRequestInProgress = false return } - if (!this.user.locked) { - let attemptsLeft = 3 - const fetchUser = () => new Promise((resolve, reject) => { - setTimeout(() => { - store.state.api.backendInteractor.fetchUser({ id: this.user.id }) - .then((user) => store.commit('addNewUsers', [user])) - .then(() => resolve(this.user.following)) - .catch((e) => reject(e)) - }, 500) - }).then((confirmed) => { - if (!confirmed && attemptsLeft > 0) { - attemptsLeft-- - return fetchUser() - } else if (confirmed) { - return true + + // But usually we don't get result immediately, so we ask server + // for updated user profile to confirm if we are following them + // Sometimes it takes several tries. Sometimes we end up not following + // user anyway, probably because they locked themselves and we + // don't know that yet. + // Recursive Promise, it will call itself up to 3 times. + const fetchUser = (attempt) => new Promise((resolve, reject) => { + setTimeout(() => { + store.state.api.backendInteractor.fetchUser({ id: this.user.id }) + .then((user) => store.commit('addNewUsers', [user])) + .then(() => resolve([this.user.following, attempt])) + .catch((e) => reject(e)) + }, 500) + }).then(([following, attempt]) => { + if (!following && attempt <= 3) { + // If we BE reports that we still not following that user - retry, + // increment attempts by one + return fetchUser(++attempt) + } else { + // If we run out of attempts, just return whatever status is. + return following + } + }) + + return fetchUser(1) + .then((following) => { + if (following) { + // We confirmed and everything its good. + this.followRequestInProgress = false } else { - return false + // If after all the tries, just treat it as if user is locked + this.followRequestInProgress = false + this.followRequestSent = true } }) - - return fetchUser() - .then((successfulConfirmation) => { - if (successfulConfirmation) { - this.followRequestInProgress = false - } else { - this.followRequestInProgress = false - this.followRequestSent = true - } - }) - } else { - this.followRequestInProgress = false - this.followRequestSent = true - } }) }, unfollowUser () {