From e687b58091bcedb6f3a56d94030fa312e51830d5 Mon Sep 17 00:00:00 2001
From: taehoon
Date: Thu, 21 Feb 2019 13:32:47 -0500
Subject: Show error message when visit profile page of invalid user
---
src/components/user_profile/user_profile.js | 8 ++++++++
1 file changed, 8 insertions(+)
(limited to 'src/components/user_profile/user_profile.js')
diff --git a/src/components/user_profile/user_profile.js b/src/components/user_profile/user_profile.js
index 37179ce1..44192e9a 100644
--- a/src/components/user_profile/user_profile.js
+++ b/src/components/user_profile/user_profile.js
@@ -4,6 +4,11 @@ import Timeline from '../timeline/timeline.vue'
import FollowList from '../follow_list/follow_list.vue'
const UserProfile = {
+ data () {
+ return {
+ error: false
+ }
+ },
created () {
this.$store.commit('clearTimeline', { timeline: 'user' })
this.$store.commit('clearTimeline', { timeline: 'favorites' })
@@ -13,6 +18,9 @@ const UserProfile = {
this.startFetchFavorites()
if (!this.user.id) {
this.$store.dispatch('fetchUser', this.fetchBy)
+ .catch(() => {
+ this.error = true
+ })
}
},
destroyed () {
--
cgit v1.2.3-70-g09d2
From b78227456ea6b1a80cd85988d3ef91cb654a881c Mon Sep 17 00:00:00 2001
From: taehoon
Date: Tue, 26 Feb 2019 12:26:04 -0500
Subject: Better error handling
---
src/components/user_profile/user_profile.js | 12 ++++++++++--
src/components/user_profile/user_profile.vue | 2 +-
src/i18n/en.json | 3 ++-
src/services/api/api.service.js | 15 +++++++++------
src/services/errors/errors.js | 14 ++++++++++++++
5 files changed, 36 insertions(+), 10 deletions(-)
create mode 100644 src/services/errors/errors.js
(limited to 'src/components/user_profile/user_profile.js')
diff --git a/src/components/user_profile/user_profile.js b/src/components/user_profile/user_profile.js
index 44192e9a..ebf6c61a 100644
--- a/src/components/user_profile/user_profile.js
+++ b/src/components/user_profile/user_profile.js
@@ -1,3 +1,4 @@
+import get from 'lodash/get'
import UserCardContent from '../user_card_content/user_card_content.vue'
import UserCard from '../user_card/user_card.vue'
import Timeline from '../timeline/timeline.vue'
@@ -18,8 +19,15 @@ const UserProfile = {
this.startFetchFavorites()
if (!this.user.id) {
this.$store.dispatch('fetchUser', this.fetchBy)
- .catch(() => {
- this.error = true
+ .catch((reason) => {
+ const errorMessage = get(reason, 'error.error')
+ if (errorMessage === 'No user with such user_id') { // Known error
+ this.error = this.$t('user_profile.profile_does_not_exist')
+ } else if (errorMessage) {
+ this.error = errorMessage
+ } else {
+ this.error = this.$t('user_profile.profile_loading_error')
+ }
})
}
},
diff --git a/src/components/user_profile/user_profile.vue b/src/components/user_profile/user_profile.vue
index ccebe20b..ba1a7760 100644
--- a/src/components/user_profile/user_profile.vue
+++ b/src/components/user_profile/user_profile.vue
@@ -55,7 +55,7 @@
- {{ $t('user_profile.profile_does_not_exist') }}
+ {{ error }}
diff --git a/src/i18n/en.json b/src/i18n/en.json
index c482ecb6..9fdd1692 100644
--- a/src/i18n/en.json
+++ b/src/i18n/en.json
@@ -384,7 +384,8 @@
},
"user_profile": {
"timeline_title": "User Timeline",
- "profile_does_not_exist": "Sorry, this profile does not exist."
+ "profile_does_not_exist": "Sorry, this profile does not exist.",
+ "profile_loading_error": "Sorry, there was an error loading this profile."
},
"who_to_follow": {
"more": "More",
diff --git a/src/services/api/api.service.js b/src/services/api/api.service.js
index d8716596..fbe5afa0 100644
--- a/src/services/api/api.service.js
+++ b/src/services/api/api.service.js
@@ -47,6 +47,7 @@ const MASTODON_USER_FAVORITES_TIMELINE_URL = '/api/v1/favourites'
import { each, map } from 'lodash'
import { parseStatus, parseUser, parseNotification } from '../entity_normalizer/entity_normalizer.service.js'
import 'whatwg-fetch'
+import { StatusCodeError } from '../errors/errors'
const oldfetch = window.fetch
@@ -244,13 +245,15 @@ const denyUser = ({id, credentials}) => {
const fetchUser = ({id, credentials}) => {
let url = `${USER_URL}?user_id=${id}`
return fetch(url, { headers: authHeaders(credentials) })
- .then((data) => {
- if (!data.ok) {
- throw Error(data.statusText)
- }
- return data
+ .then((response) => {
+ return new Promise((resolve, reject) => response.json()
+ .then((json) => {
+ if (!response.ok) {
+ return reject(new StatusCodeError(response.status, json, { url }, response))
+ }
+ return resolve(json)
+ }))
})
- .then((data) => data.json())
.then((data) => parseUser(data))
}
diff --git a/src/services/errors/errors.js b/src/services/errors/errors.js
new file mode 100644
index 00000000..548f3c68
--- /dev/null
+++ b/src/services/errors/errors.js
@@ -0,0 +1,14 @@
+export function StatusCodeError (statusCode, body, options, response) {
+ this.name = 'StatusCodeError'
+ this.statusCode = statusCode
+ this.message = statusCode + ' - ' + (JSON && JSON.stringify ? JSON.stringify(body) : body)
+ this.error = body // legacy attribute
+ this.options = options
+ this.response = response
+
+ if (Error.captureStackTrace) { // required for non-V8 environments
+ Error.captureStackTrace(this)
+ }
+}
+StatusCodeError.prototype = Object.create(Error.prototype)
+StatusCodeError.prototype.constructor = StatusCodeError
--
cgit v1.2.3-70-g09d2
From 080786c9458ba8b9db1ea63732824a3e297e10dc Mon Sep 17 00:00:00 2001
From: taehoon
Date: Mon, 25 Feb 2019 04:51:23 -0500
Subject: Rewrite FollowList using hocs
---
src/components/follow_list/follow_list.js | 68 ----------------------------
src/components/follow_list/follow_list.vue | 33 --------------
src/components/user_profile/user_profile.js | 29 +++++++++++-
src/components/user_profile/user_profile.vue | 10 +---
src/hocs/with_load_more/with_load_more.js | 2 +
src/modules/users.js | 19 ++++++--
6 files changed, 45 insertions(+), 116 deletions(-)
delete mode 100644 src/components/follow_list/follow_list.js
delete mode 100644 src/components/follow_list/follow_list.vue
(limited to 'src/components/user_profile/user_profile.js')
diff --git a/src/components/follow_list/follow_list.js b/src/components/follow_list/follow_list.js
deleted file mode 100644
index 9777c87e..00000000
--- a/src/components/follow_list/follow_list.js
+++ /dev/null
@@ -1,68 +0,0 @@
-import UserCard from '../user_card/user_card.vue'
-
-const FollowList = {
- data () {
- return {
- loading: false,
- bottomedOut: false,
- error: false
- }
- },
- props: ['userId', 'showFollowers'],
- created () {
- window.addEventListener('scroll', this.scrollLoad)
- if (this.entries.length === 0) {
- this.fetchEntries()
- }
- },
- destroyed () {
- window.removeEventListener('scroll', this.scrollLoad)
- this.$store.dispatch('clearFriendsAndFollowers', this.userId)
- },
- computed: {
- user () {
- return this.$store.getters.userById(this.userId)
- },
- entries () {
- return this.showFollowers ? this.user.followers : this.user.friends
- },
- showFollowsYou () {
- return !this.showFollowers || (this.showFollowers && this.userId !== this.$store.state.users.currentUser.id)
- }
- },
- methods: {
- fetchEntries () {
- if (!this.loading) {
- const command = this.showFollowers ? 'addFollowers' : 'addFriends'
- this.loading = true
- this.$store.dispatch(command, this.userId).then(entries => {
- this.error = false
- this.loading = false
- this.bottomedOut = entries.length === 0
- }).catch(() => {
- this.error = true
- this.loading = false
- })
- }
- },
- scrollLoad (e) {
- const bodyBRect = document.body.getBoundingClientRect()
- const height = Math.max(bodyBRect.height, -(bodyBRect.y))
- if (this.loading === false &&
- this.bottomedOut === false &&
- this.$el.offsetHeight > 0 &&
- (window.innerHeight + window.pageYOffset) >= (height - 750)
- ) {
- this.fetchEntries()
- }
- }
- },
- watch: {
- 'user': 'fetchEntries'
- },
- components: {
- UserCard
- }
-}
-
-export default FollowList
diff --git a/src/components/follow_list/follow_list.vue b/src/components/follow_list/follow_list.vue
deleted file mode 100644
index 27102edf..00000000
--- a/src/components/follow_list/follow_list.vue
+++ /dev/null
@@ -1,33 +0,0 @@
-
-
-
-
-
-
-
-
-
-
diff --git a/src/components/user_profile/user_profile.js b/src/components/user_profile/user_profile.js
index ebf6c61a..9f9d43e4 100644
--- a/src/components/user_profile/user_profile.js
+++ b/src/components/user_profile/user_profile.js
@@ -1,8 +1,32 @@
+import { compose } from 'vue-compose'
import get from 'lodash/get'
import UserCardContent from '../user_card_content/user_card_content.vue'
import UserCard from '../user_card/user_card.vue'
import Timeline from '../timeline/timeline.vue'
-import FollowList from '../follow_list/follow_list.vue'
+import withLoadMore from '../../hocs/with_load_more/with_load_more'
+import withList from '../../hocs/with_list/with_list'
+
+const FollowerList = compose(
+ withLoadMore({
+ fetch: (props, $store) => $store.dispatch('addFollowers', props.userId),
+ select: (props, $store) => get($store.getters.userById(props.userId), 'followers', []),
+ destory: (props, $store) => $store.dispatch('clearFollowers', props.userId),
+ childPropName: 'entries',
+ additionalPropNames: ['userId']
+ }),
+ withList({ getEntryProps: user => ({ user }) })
+)(UserCard)
+
+const FriendList = compose(
+ withLoadMore({
+ fetch: (props, $store) => $store.dispatch('addFriends', props.userId),
+ select: (props, $store) => get($store.getters.userById(props.userId), 'friends', []),
+ destory: (props, $store) => $store.dispatch('clearFriends', props.userId),
+ childPropName: 'entries',
+ additionalPropNames: ['userId']
+ }),
+ withList({ getEntryProps: user => ({ user }) })
+)(UserCard)
const UserProfile = {
data () {
@@ -123,7 +147,8 @@ const UserProfile = {
UserCardContent,
UserCard,
Timeline,
- FollowList
+ FollowerList,
+ FriendList
}
}
diff --git a/src/components/user_profile/user_profile.vue b/src/components/user_profile/user_profile.vue
index ba1a7760..a3d2825f 100644
--- a/src/components/user_profile/user_profile.vue
+++ b/src/components/user_profile/user_profile.vue
@@ -18,16 +18,10 @@
:user-id="fetchBy"
/>
(WrappedComponent) => {
@@ -58,6 +59,7 @@ const withLoadMore = ({
},
destroyed () {
window.removeEventListener('scroll', this.scrollLoad)
+ destroy && destroy(this.$props, this.$store)
},
methods: {
fetchEntries () {
diff --git a/src/modules/users.js b/src/modules/users.js
index b2821a92..093af497 100644
--- a/src/modules/users.js
+++ b/src/modules/users.js
@@ -72,14 +72,20 @@ export const mutations = {
},
// Because frontend doesn't have a reason to keep these stuff in memory
// outside of viewing someones user profile.
- clearFriendsAndFollowers (state, userKey) {
- const user = state.usersObject[userKey]
+ clearFriends (state, userId) {
+ const user = state.usersObject[userId]
if (!user) {
return
}
user.friends = []
- user.followers = []
user.friendsPage = 0
+ },
+ clearFollowers (state, userId) {
+ const user = state.usersObject[userId]
+ if (!user) {
+ return
+ }
+ user.followers = []
user.followersPage = 0
},
addNewUsers (state, users) {
@@ -197,8 +203,11 @@ const users = {
return followers
})
},
- clearFriendsAndFollowers ({ commit }, userKey) {
- commit('clearFriendsAndFollowers', userKey)
+ clearFriends ({ commit }, userId) {
+ commit('clearFriends', userId)
+ },
+ clearFollowers ({ commit }, userId) {
+ commit('clearFollowers', userId)
},
registerPushNotifications (store) {
const token = store.state.currentUser.credentials
--
cgit v1.2.3-70-g09d2
From bb1fac4bc202c58064ee94d124967db463b3178e Mon Sep 17 00:00:00 2001
From: taehoon
Date: Mon, 25 Feb 2019 07:36:38 -0500
Subject: Remove needless component local registration
---
src/components/user_profile/user_profile.js | 1 -
1 file changed, 1 deletion(-)
(limited to 'src/components/user_profile/user_profile.js')
diff --git a/src/components/user_profile/user_profile.js b/src/components/user_profile/user_profile.js
index 9f9d43e4..643727de 100644
--- a/src/components/user_profile/user_profile.js
+++ b/src/components/user_profile/user_profile.js
@@ -145,7 +145,6 @@ const UserProfile = {
},
components: {
UserCardContent,
- UserCard,
Timeline,
FollowerList,
FriendList
--
cgit v1.2.3-70-g09d2
From 9ca805a99110d5521933b2a4b2a60c8691de82c8 Mon Sep 17 00:00:00 2001
From: taehoon
Date: Mon, 25 Feb 2019 22:51:04 -0500
Subject: Add new FollowCard component
---
src/components/follow_card/follow_card.js | 45 +++++++++++++++++++++++++++++
src/components/follow_card/follow_card.vue | 40 +++++++++++++++++++++++++
src/components/user_profile/user_profile.js | 6 ++--
3 files changed, 88 insertions(+), 3 deletions(-)
create mode 100644 src/components/follow_card/follow_card.js
create mode 100644 src/components/follow_card/follow_card.vue
(limited to 'src/components/user_profile/user_profile.js')
diff --git a/src/components/follow_card/follow_card.js b/src/components/follow_card/follow_card.js
new file mode 100644
index 00000000..85e6a6d2
--- /dev/null
+++ b/src/components/follow_card/follow_card.js
@@ -0,0 +1,45 @@
+import BasicUserCard from '../basic_user_card/basic_user_card.vue'
+import { requestFollow, requestUnfollow } from '../../services/follow_manipulate/follow_manipulate'
+
+const FollowCard = {
+ props: [
+ 'user',
+ 'noFollowsYou'
+ ],
+ data () {
+ return {
+ progress: false,
+ requestSent: false,
+ updated: false
+ }
+ },
+ components: {
+ BasicUserCard
+ },
+ computed: {
+ isMe () { return this.$store.state.users.currentUser.id === this.user.id },
+ following () { return this.updated ? this.updated.following : this.user.following },
+ showFollow () {
+ return !this.following || this.updated && !this.updated.following
+ }
+ },
+ methods: {
+ followUser () {
+ this.progress = true
+ requestFollow(this.user, this.$store).then(({ sent, updated }) => {
+ this.progress = false
+ this.requestSent = sent
+ this.updated = updated
+ })
+ },
+ unfollowUser () {
+ this.progress = true
+ requestUnfollow(this.user, this.$store).then(({ updated }) => {
+ this.progress = false
+ this.updated = updated
+ })
+ }
+ }
+}
+
+export default FollowCard
diff --git a/src/components/follow_card/follow_card.vue b/src/components/follow_card/follow_card.vue
new file mode 100644
index 00000000..dcb85d62
--- /dev/null
+++ b/src/components/follow_card/follow_card.vue
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+
+
+
+ {{ isMe ? $t('user_card.its_you') : $t('user_card.follows_you') }}
+
+
+
+
+
+
diff --git a/src/components/user_profile/user_profile.js b/src/components/user_profile/user_profile.js
index 643727de..7708141c 100644
--- a/src/components/user_profile/user_profile.js
+++ b/src/components/user_profile/user_profile.js
@@ -1,7 +1,7 @@
import { compose } from 'vue-compose'
import get from 'lodash/get'
import UserCardContent from '../user_card_content/user_card_content.vue'
-import UserCard from '../user_card/user_card.vue'
+import FollowCard from '../follow_card/follow_card.vue'
import Timeline from '../timeline/timeline.vue'
import withLoadMore from '../../hocs/with_load_more/with_load_more'
import withList from '../../hocs/with_list/with_list'
@@ -15,7 +15,7 @@ const FollowerList = compose(
additionalPropNames: ['userId']
}),
withList({ getEntryProps: user => ({ user }) })
-)(UserCard)
+)(FollowCard)
const FriendList = compose(
withLoadMore({
@@ -26,7 +26,7 @@ const FriendList = compose(
additionalPropNames: ['userId']
}),
withList({ getEntryProps: user => ({ user }) })
-)(UserCard)
+)(FollowCard)
const UserProfile = {
data () {
--
cgit v1.2.3-70-g09d2
From 5a0bb29f02349aed4a7948b963ff0a78d3975237 Mon Sep 17 00:00:00 2001
From: dave
Date: Sun, 3 Mar 2019 13:38:48 -0500
Subject: #417: reset tab from the outside
---
src/components/tab_switcher/tab_switcher.js | 9 +--------
src/components/user_profile/user_profile.js | 3 +++
src/components/user_profile/user_profile.vue | 2 +-
3 files changed, 5 insertions(+), 9 deletions(-)
(limited to 'src/components/user_profile/user_profile.js')
diff --git a/src/components/tab_switcher/tab_switcher.js b/src/components/tab_switcher/tab_switcher.js
index 03da8249..423df258 100644
--- a/src/components/tab_switcher/tab_switcher.js
+++ b/src/components/tab_switcher/tab_switcher.js
@@ -4,19 +4,12 @@ import './tab_switcher.scss'
export default Vue.component('tab-switcher', {
name: 'TabSwitcher',
- props: ['refresh', 'renderOnlyFocused'],
+ props: ['renderOnlyFocused'],
data () {
return {
active: this.$slots.default.findIndex(_ => _.tag)
}
},
- watch: {
- $route () {
- if (this.refresh) {
- this.active = 0
- }
- }
- },
methods: {
activateTab (index) {
return () => {
diff --git a/src/components/user_profile/user_profile.js b/src/components/user_profile/user_profile.js
index 7708141c..cdf1cee9 100644
--- a/src/components/user_profile/user_profile.js
+++ b/src/components/user_profile/user_profile.js
@@ -141,6 +141,9 @@ const UserProfile = {
}
this.cleanUp()
this.startUp()
+ },
+ $route () {
+ this.$refs.tabSwitcher.activateTab(0)()
}
},
components: {
diff --git a/src/components/user_profile/user_profile.vue b/src/components/user_profile/user_profile.vue
index 54f1b97b..8090efa5 100644
--- a/src/components/user_profile/user_profile.vue
+++ b/src/components/user_profile/user_profile.vue
@@ -6,7 +6,7 @@
:switcher="true"
:selected="timeline.viewing"
/>
-
+