From 17498ef906b79dd68276faa2a5624b90f3f0bc2b Mon Sep 17 00:00:00 2001 From: taehoon Date: Mon, 24 Jun 2019 04:21:09 -0400 Subject: update favs and repeats stats using favoritedByUsers and rebloggedByUsers data --- src/modules/statuses.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'src/modules') diff --git a/src/modules/statuses.js b/src/modules/statuses.js index cf65c9f4..514f3081 100644 --- a/src/modules/statuses.js +++ b/src/modules/statuses.js @@ -492,10 +492,15 @@ export const mutations = { queueFlush (state, { timeline, id }) { state.timelines[timeline].flushMarker = id }, - addFavsAndRepeats (state, { id, favoritedByUsers, rebloggedByUsers }) { + addFavsAndRepeats (state, { id, favoritedByUsers, rebloggedByUsers, currentUser }) { const newStatus = state.allStatusesObject[id] newStatus.favoritedBy = favoritedByUsers.filter(_ => _) newStatus.rebloggedBy = rebloggedByUsers.filter(_ => _) + // favorites and repeats stats can be incorrect based on polling condition, let's update them using the most recent data + newStatus.fave_num = newStatus.favoritedBy.length + newStatus.repeat_num = newStatus.rebloggedBy.length + newStatus.favorited = !!newStatus.favoritedBy.find(({ id }) => currentUser.id === id) + newStatus.repeated = !!newStatus.rebloggedBy.find(({ id }) => currentUser.id === id) }, updateStatusWithPoll (state, { id, poll }) { const status = state.allStatusesObject[id] @@ -582,7 +587,7 @@ const statuses = { rootState.api.backendInteractor.fetchFavoritedByUsers(id), rootState.api.backendInteractor.fetchRebloggedByUsers(id) ]).then(([favoritedByUsers, rebloggedByUsers]) => - commit('addFavsAndRepeats', { id, favoritedByUsers, rebloggedByUsers }) + commit('addFavsAndRepeats', { id, favoritedByUsers, rebloggedByUsers, currentUser: rootState.users.currentUser }) ) } }, -- cgit v1.2.3-70-g09d2 From ab4d7d9616319778b7ed5d79ca1f389c9e439113 Mon Sep 17 00:00:00 2001 From: taehoon Date: Thu, 27 Jun 2019 08:14:54 -0400 Subject: refetch favs and repeats separately --- src/components/status/status.js | 7 ++----- src/modules/statuses.js | 29 +++++++++++++++++++++-------- 2 files changed, 23 insertions(+), 13 deletions(-) (limited to 'src/modules') diff --git a/src/components/status/status.js b/src/components/status/status.js index 6f83dbe0..284c657c 100644 --- a/src/components/status/status.js +++ b/src/components/status/status.js @@ -402,9 +402,6 @@ const Status = { setMedia () { const attachments = this.attachmentSize === 'hide' ? this.status.attachments : this.galleryAttachments return () => this.$store.dispatch('setMedia', attachments) - }, - refetchFavsAndRepeats () { - this.$store.dispatch('fetchFavsAndRepeats', this.status.id) } }, watch: { @@ -425,12 +422,12 @@ const Status = { }, 'status.repeat_num': function (num) { if (this.isFocused && this.statusFromGlobalRepository.rebloggedBy && this.statusFromGlobalRepository.rebloggedBy.length !== num) { - this.refetchFavsAndRepeats() + this.$store.dispatch('fetchRepeats', this.status.id) } }, 'status.fave_num': function (num) { if (this.isFocused && this.statusFromGlobalRepository.favoritedBy && this.statusFromGlobalRepository.favoritedBy.length !== num) { - this.refetchFavsAndRepeats() + this.$store.dispatch('fetchFavs', this.status.id) } } }, diff --git a/src/modules/statuses.js b/src/modules/statuses.js index 514f3081..9d8d768c 100644 --- a/src/modules/statuses.js +++ b/src/modules/statuses.js @@ -492,16 +492,20 @@ export const mutations = { queueFlush (state, { timeline, id }) { state.timelines[timeline].flushMarker = id }, - addFavsAndRepeats (state, { id, favoritedByUsers, rebloggedByUsers, currentUser }) { + addRepeats (state, { id, rebloggedByUsers, currentUser }) { const newStatus = state.allStatusesObject[id] - newStatus.favoritedBy = favoritedByUsers.filter(_ => _) newStatus.rebloggedBy = rebloggedByUsers.filter(_ => _) - // favorites and repeats stats can be incorrect based on polling condition, let's update them using the most recent data - newStatus.fave_num = newStatus.favoritedBy.length + // repeats stats can be incorrect based on polling condition, let's update them using the most recent data newStatus.repeat_num = newStatus.rebloggedBy.length - newStatus.favorited = !!newStatus.favoritedBy.find(({ id }) => currentUser.id === id) newStatus.repeated = !!newStatus.rebloggedBy.find(({ id }) => currentUser.id === id) }, + addFavs (state, { id, favoritedByUsers, currentUser }) { + const newStatus = state.allStatusesObject[id] + newStatus.favoritedBy = favoritedByUsers.filter(_ => _) + // favorites stats can be incorrect based on polling condition, let's update them using the most recent data + newStatus.fave_num = newStatus.favoritedBy.length + newStatus.favorited = !!newStatus.favoritedBy.find(({ id }) => currentUser.id === id) + }, updateStatusWithPoll (state, { id, poll }) { const status = state.allStatusesObject[id] status.poll = poll @@ -586,9 +590,18 @@ const statuses = { Promise.all([ rootState.api.backendInteractor.fetchFavoritedByUsers(id), rootState.api.backendInteractor.fetchRebloggedByUsers(id) - ]).then(([favoritedByUsers, rebloggedByUsers]) => - commit('addFavsAndRepeats', { id, favoritedByUsers, rebloggedByUsers, currentUser: rootState.users.currentUser }) - ) + ]).then(([favoritedByUsers, rebloggedByUsers]) => { + commit('addFavs', { id, favoritedByUsers, currentUser: rootState.users.currentUser }) + commit('addRepeats', { id, rebloggedByUsers, currentUser: rootState.users.currentUser }) + }) + }, + fetchFavs ({ rootState, commit }, id) { + rootState.api.backendInteractor.fetchFavoritedByUsers(id) + .then(favoritedByUsers => commit('addFavs', { id, favoritedByUsers, currentUser: rootState.users.currentUser })) + }, + fetchRepeats ({ rootState, commit }, id) { + rootState.api.backendInteractor.fetchRebloggedByUsers(id) + .then(rebloggedByUsers => commit('addRepeats', { id, rebloggedByUsers, currentUser: rootState.users.currentUser })) } }, mutations -- cgit v1.2.3-70-g09d2 From 532b76eb64119848d424d6d0d644a72d817fba59 Mon Sep 17 00:00:00 2001 From: Tae Hoon Date: Wed, 10 Jul 2019 16:58:49 +0000 Subject: Refactor user search api, better api error response handling --- src/components/user_search/user_search.js | 8 ++--- src/components/user_settings/user_settings.js | 8 ++--- src/modules/users.js | 10 +----- src/services/api/api.service.js | 23 ++++++++++++-- .../backend_interactor_service.js | 5 ++- src/services/new_api/user_search.js | 20 ------------ src/services/new_api/utils.js | 36 ---------------------- 7 files changed, 31 insertions(+), 79 deletions(-) delete mode 100644 src/services/new_api/user_search.js delete mode 100644 src/services/new_api/utils.js (limited to 'src/modules') diff --git a/src/components/user_search/user_search.js b/src/components/user_search/user_search.js index 62dafdf1..5c29d8f2 100644 --- a/src/components/user_search/user_search.js +++ b/src/components/user_search/user_search.js @@ -35,15 +35,13 @@ const userSearch = { }, search (query) { if (!query) { - this.users = [] return } this.loading = true + this.userIds = [] this.$store.dispatch('searchUsers', query) - .then((res) => { - this.loading = false - this.userIds = map(res, 'id') - }) + .then((res) => { this.userIds = map(res, 'id') }) + .finally(() => { this.loading = false }) } } } diff --git a/src/components/user_settings/user_settings.js b/src/components/user_settings/user_settings.js index 19f4604f..0c3b2aef 100644 --- a/src/components/user_settings/user_settings.js +++ b/src/components/user_settings/user_settings.js @@ -17,7 +17,6 @@ import Autosuggest from '../autosuggest/autosuggest.vue' import Importer from '../importer/importer.vue' import Exporter from '../exporter/exporter.vue' import withSubscription from '../../hocs/with_subscription/with_subscription' -import userSearchApi from '../../services/new_api/user_search.js' import Mfa from './mfa.vue' const BlockList = withSubscription({ @@ -322,11 +321,8 @@ const UserSettings = { }) }, queryUserIds (query) { - return userSearchApi.search({ query, store: this.$store }) - .then((users) => { - this.$store.dispatch('addNewUsers', users) - return map(users, 'id') - }) + return this.$store.dispatch('searchUsers', query) + .then((users) => map(users, 'id')) }, blockUsers (ids) { return this.$store.dispatch('blockUsers', ids) diff --git a/src/modules/users.js b/src/modules/users.js index 6c7a96f6..453a6899 100644 --- a/src/modules/users.js +++ b/src/modules/users.js @@ -1,5 +1,4 @@ import backendInteractorService from '../services/backend_interactor_service/backend_interactor_service.js' -import userSearchApi from '../services/new_api/user_search.js' import oauthApi from '../services/new_api/oauth.js' import { compact, map, each, merge, last, concat, uniq } from 'lodash' import { set } from 'vue' @@ -356,14 +355,7 @@ const users = { }) }, searchUsers (store, query) { - // TODO: Move userSearch api into api.service - return userSearchApi.search({ - query, - store: { - state: store.rootState, - getters: store.rootGetters - } - }) + return store.rootState.api.backendInteractor.searchUsers(query) .then((users) => { store.commit('addNewUsers', users) return users diff --git a/src/services/api/api.service.js b/src/services/api/api.service.js index 22db671e..304fc869 100644 --- a/src/services/api/api.service.js +++ b/src/services/api/api.service.js @@ -65,6 +65,7 @@ const MASTODON_PROFILE_UPDATE_URL = '/api/v1/accounts/update_credentials' const MASTODON_REPORT_USER_URL = '/api/v1/reports' const MASTODON_PIN_OWN_STATUS = id => `/api/v1/statuses/${id}/pin` const MASTODON_UNPIN_OWN_STATUS = id => `/api/v1/statuses/${id}/unpin` +const MASTODON_USER_SEARCH_URL = '/api/v1/accounts/search' const oldfetch = window.fetch @@ -76,7 +77,7 @@ let fetch = (url, options) => { return oldfetch(fullUrl, options) } -const promisedRequest = ({ method, url, payload, credentials, headers = {} }) => { +const promisedRequest = ({ method, url, params, payload, credentials, headers = {} }) => { const options = { method, headers: { @@ -85,6 +86,11 @@ const promisedRequest = ({ method, url, payload, credentials, headers = {} }) => ...headers } } + if (params) { + url += '?' + Object.entries(params) + .map(([key, value]) => encodeURIComponent(key) + '=' + encodeURIComponent(value)) + .join('&') + } if (payload) { options.body = JSON.stringify(payload) } @@ -837,6 +843,18 @@ const reportUser = ({ credentials, userId, statusIds, comment, forward }) => { }) } +const searchUsers = ({ credentials, query }) => { + return promisedRequest({ + url: MASTODON_USER_SEARCH_URL, + params: { + q: query, + resolve: true + }, + credentials + }) + .then((data) => data.map(parseUser)) +} + const apiService = { verifyCredentials, fetchTimeline, @@ -899,7 +917,8 @@ const apiService = { fetchFavoritedByUsers, fetchRebloggedByUsers, reportUser, - updateNotificationSettings + updateNotificationSettings, + searchUsers } export default apiService diff --git a/src/services/backend_interactor_service/backend_interactor_service.js b/src/services/backend_interactor_service/backend_interactor_service.js index 3550aafd..5162d38f 100644 --- a/src/services/backend_interactor_service/backend_interactor_service.js +++ b/src/services/backend_interactor_service/backend_interactor_service.js @@ -147,6 +147,8 @@ const backendInteractorService = credentials => { const retweet = (id) => apiService.retweet({ id, credentials }) const unretweet = (id) => apiService.unretweet({ id, credentials }) + const searchUsers = (query) => apiService.searchUsers({ query, credentials }) + const backendInteractorServiceInstance = { fetchStatus, fetchConversation, @@ -205,7 +207,8 @@ const backendInteractorService = credentials => { unfavorite, retweet, unretweet, - updateNotificationSettings + updateNotificationSettings, + searchUsers } return backendInteractorServiceInstance diff --git a/src/services/new_api/user_search.js b/src/services/new_api/user_search.js deleted file mode 100644 index 5936fef9..00000000 --- a/src/services/new_api/user_search.js +++ /dev/null @@ -1,20 +0,0 @@ -import utils from './utils.js' -import { parseUser } from '../entity_normalizer/entity_normalizer.service.js' - -const search = ({ query, store }) => { - return utils.request({ - store, - url: '/api/v1/accounts/search', - params: { - q: query, - resolve: true - } - }) - .then((data) => data.json()) - .then((data) => data.map(parseUser)) -} -const UserSearch = { - search -} - -export default UserSearch diff --git a/src/services/new_api/utils.js b/src/services/new_api/utils.js deleted file mode 100644 index 57111026..00000000 --- a/src/services/new_api/utils.js +++ /dev/null @@ -1,36 +0,0 @@ -const queryParams = (params) => { - return Object.keys(params) - .map(k => encodeURIComponent(k) + '=' + encodeURIComponent(params[k])) - .join('&') -} - -const headers = (store) => { - const accessToken = store.getters.getToken() - if (accessToken) { - return { 'Authorization': `Bearer ${accessToken}` } - } else { - return {} - } -} - -const request = ({ method = 'GET', url, params, store }) => { - const instance = store.state.instance.server - let fullUrl = `${instance}${url}` - - if (method === 'GET' && params) { - fullUrl = fullUrl + `?${queryParams(params)}` - } - - return window.fetch(fullUrl, { - method, - headers: headers(store), - credentials: 'same-origin' - }) -} - -const utils = { - queryParams, - request -} - -export default utils -- cgit v1.2.3-70-g09d2 From d5e8315e83327c7b8dda71eca5dd1c9d7d0a23dc Mon Sep 17 00:00:00 2001 From: jared Date: Tue, 16 Apr 2019 10:13:26 -0400 Subject: #482 - add subscribe button --- .../subscribe_button/subscribe_button.js | 26 ++ .../subscribe_button/subscribe_button.vue | 22 ++ src/components/user_card/user_card.js | 4 +- src/components/user_card/user_card.vue | 365 +++++++-------------- src/modules/users.js | 1 + 5 files changed, 172 insertions(+), 246 deletions(-) create mode 100644 src/components/subscribe_button/subscribe_button.js create mode 100644 src/components/subscribe_button/subscribe_button.vue (limited to 'src/modules') diff --git a/src/components/subscribe_button/subscribe_button.js b/src/components/subscribe_button/subscribe_button.js new file mode 100644 index 00000000..e3a2842c --- /dev/null +++ b/src/components/subscribe_button/subscribe_button.js @@ -0,0 +1,26 @@ +export default { + props: [ 'user' ], + data () { + return { + inProgress: false + } + }, + methods: { + subscribe () { + this.inProgress = true + this.$store.state.api.backendInteractor.subscribeUser(this.user.id) + .then((updated) => { + console.log(updated) + this.inProgress = false + }) + }, + unsubscribe () { + this.inProgress = true + this.$store.state.api.backendInteractor.unsubscribeUser(this.user.id) + .then((updated) => { + console.log(updated) + this.inProgress = false + }) + } + } +} diff --git a/src/components/subscribe_button/subscribe_button.vue b/src/components/subscribe_button/subscribe_button.vue new file mode 100644 index 00000000..f7dd8c61 --- /dev/null +++ b/src/components/subscribe_button/subscribe_button.vue @@ -0,0 +1,22 @@ + + + diff --git a/src/components/user_card/user_card.js b/src/components/user_card/user_card.js index 92cd0e54..bab1a654 100644 --- a/src/components/user_card/user_card.js +++ b/src/components/user_card/user_card.js @@ -1,5 +1,6 @@ import UserAvatar from '../user_avatar/user_avatar.vue' import RemoteFollow from '../remote_follow/remote_follow.vue' +import SubscribeButton from '../subscribe_button/subscribe_button.vue' import ModerationTools from '../moderation_tools/moderation_tools.vue' import { hex2rgb } from '../../services/color_convert/color_convert.js' import { requestFollow, requestUnfollow } from '../../services/follow_manipulate/follow_manipulate' @@ -104,7 +105,8 @@ export default { components: { UserAvatar, RemoteFollow, - ModerationTools + ModerationTools, + SubscribeButton }, methods: { followUser () { diff --git a/src/components/user_card/user_card.vue b/src/components/user_card/user_card.vue index 5a5a4881..18ec6e94 100644 --- a/src/components/user_card/user_card.vue +++ b/src/components/user_card/user_card.vue @@ -1,260 +1,135 @@ diff --git a/src/modules/users.js b/src/modules/users.js index 453a6899..f9b609b4 100644 --- a/src/modules/users.js +++ b/src/modules/users.js @@ -135,6 +135,7 @@ export const mutations = { user.following = relationship.following user.muted = relationship.muting user.statusnet_blocking = relationship.blocking + user.subscribing = relationship.subscribing } }) }, -- cgit v1.2.3-70-g09d2 From 646d197bf181eff7d0df268d5eda2debcda3f4fe Mon Sep 17 00:00:00 2001 From: taehoon Date: Thu, 25 Apr 2019 04:30:08 -0400 Subject: mutate updated relationship to the store --- src/components/user_card/user_card.js | 4 ++-- src/modules/users.js | 8 ++++++++ 2 files changed, 10 insertions(+), 2 deletions(-) (limited to 'src/modules') diff --git a/src/components/user_card/user_card.js b/src/components/user_card/user_card.js index d7fe71d0..e019ebbd 100644 --- a/src/components/user_card/user_card.js +++ b/src/components/user_card/user_card.js @@ -138,10 +138,10 @@ export default { this.$store.dispatch('unmuteUser', this.user.id) }, subscribeUser () { - return this.$store.state.api.backendInteractor.subscribeUser(this.user.id) + return this.$store.dispatch('subscribeUser', this.user.id) }, unsubscribeUser () { - return this.$store.state.api.backendInteractor.unsubscribeUser(this.user.id) + return this.$store.dispatch('unsubscribeUser', this.user.id) }, setProfileView (v) { if (this.switcher) { diff --git a/src/modules/users.js b/src/modules/users.js index f9b609b4..c7ebbc85 100644 --- a/src/modules/users.js +++ b/src/modules/users.js @@ -305,6 +305,14 @@ const users = { clearFollowers ({ commit }, userId) { commit('clearFollowers', userId) }, + subscribeUser ({ rootState, commit }, id) { + return rootState.api.backendInteractor.subscribeUser(id) + .then((relationship) => commit('updateUserRelationship', [relationship])) + }, + unsubscribeUser ({ rootState, commit }, id) { + return rootState.api.backendInteractor.unsubscribeUser(id) + .then((relationship) => commit('updateUserRelationship', [relationship])) + }, registerPushNotifications (store) { const token = store.state.currentUser.credentials const vapidPublicKey = store.rootState.instance.vapidPublicKey -- cgit v1.2.3-70-g09d2 From 670cbfdd1c262ddd34717b88f879d5fb80280b60 Mon Sep 17 00:00:00 2001 From: taehoon Date: Thu, 25 Apr 2019 12:33:50 -0400 Subject: change subscribing to subscribed --- src/components/user_card/user_card.vue | 2 +- src/modules/users.js | 2 +- src/services/entity_normalizer/entity_normalizer.service.js | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'src/modules') diff --git a/src/components/user_card/user_card.vue b/src/components/user_card/user_card.vue index 720415f0..5d23bf1e 100644 --- a/src/components/user_card/user_card.vue +++ b/src/components/user_card/user_card.vue @@ -73,7 +73,7 @@
- + {{ $t('user_card.subscribe') }} diff --git a/src/modules/users.js b/src/modules/users.js index c7ebbc85..57d3a3e3 100644 --- a/src/modules/users.js +++ b/src/modules/users.js @@ -135,7 +135,7 @@ export const mutations = { user.following = relationship.following user.muted = relationship.muting user.statusnet_blocking = relationship.blocking - user.subscribing = relationship.subscribing + user.subscribed = relationship.subscribing } }) }, diff --git a/src/services/entity_normalizer/entity_normalizer.service.js b/src/services/entity_normalizer/entity_normalizer.service.js index 60c6285a..de6664d1 100644 --- a/src/services/entity_normalizer/entity_normalizer.service.js +++ b/src/services/entity_normalizer/entity_normalizer.service.js @@ -68,7 +68,7 @@ export const parseUser = (data) => { output.following = relationship.following output.statusnet_blocking = relationship.blocking output.muted = relationship.muting - output.subscribing = relationship.subscribing + output.subscribed = relationship.subscribing } output.hide_follows = data.pleroma.hide_follows -- cgit v1.2.3-70-g09d2 From 69a4bcb238b347a139bfb1192413b45c8b9d7e36 Mon Sep 17 00:00:00 2001 From: Eugenij Date: Mon, 15 Jul 2019 16:42:27 +0000 Subject: New search --- src/App.js | 12 +- src/App.vue | 6 +- src/boot/routes.js | 4 +- src/components/search/search.js | 98 ++++++++++ src/components/search/search.vue | 211 +++++++++++++++++++++ src/components/search_bar/search_bar.js | 27 +++ src/components/search_bar/search_bar.vue | 73 +++++++ src/components/side_drawer/side_drawer.vue | 4 +- src/components/tab_switcher/tab_switcher.js | 12 +- src/components/user_finder/user_finder.js | 20 -- src/components/user_finder/user_finder.vue | 67 ------- src/components/user_search/user_search.js | 49 ----- src/components/user_search/user_search.vue | 57 ------ src/i18n/en.json | 8 + src/i18n/ru.json | 10 +- src/modules/statuses.js | 8 + src/services/api/api.service.js | 54 ++++-- .../backend_interactor_service.js | 6 +- 18 files changed, 502 insertions(+), 224 deletions(-) create mode 100644 src/components/search/search.js create mode 100644 src/components/search/search.vue create mode 100644 src/components/search_bar/search_bar.js create mode 100644 src/components/search_bar/search_bar.vue delete mode 100644 src/components/user_finder/user_finder.js delete mode 100644 src/components/user_finder/user_finder.vue delete mode 100644 src/components/user_search/user_search.js delete mode 100644 src/components/user_search/user_search.vue (limited to 'src/modules') diff --git a/src/App.js b/src/App.js index e72c73e3..3624171e 100644 --- a/src/App.js +++ b/src/App.js @@ -1,7 +1,7 @@ import UserPanel from './components/user_panel/user_panel.vue' import NavPanel from './components/nav_panel/nav_panel.vue' import Notifications from './components/notifications/notifications.vue' -import UserFinder from './components/user_finder/user_finder.vue' +import SearchBar from './components/search_bar/search_bar.vue' import InstanceSpecificPanel from './components/instance_specific_panel/instance_specific_panel.vue' import FeaturesPanel from './components/features_panel/features_panel.vue' import WhoToFollowPanel from './components/who_to_follow_panel/who_to_follow_panel.vue' @@ -19,7 +19,7 @@ export default { UserPanel, NavPanel, Notifications, - UserFinder, + SearchBar, InstanceSpecificPanel, FeaturesPanel, WhoToFollowPanel, @@ -32,7 +32,7 @@ export default { }, data: () => ({ mobileActivePanel: 'timeline', - finderHidden: true, + searchBarHidden: true, supportsMask: window.CSS && window.CSS.supports && ( window.CSS.supports('mask-size', 'contain') || window.CSS.supports('-webkit-mask-size', 'contain') || @@ -70,7 +70,7 @@ export default { logoBgStyle () { return Object.assign({ 'margin': `${this.$store.state.instance.logoMargin} 0`, - opacity: this.finderHidden ? 1 : 0 + opacity: this.searchBarHidden ? 1 : 0 }, this.enableMask ? {} : { 'background-color': this.enableMask ? '' : 'transparent' }) @@ -101,8 +101,8 @@ export default { this.$router.replace('/main/public') this.$store.dispatch('logout') }, - onFinderToggled (hidden) { - this.finderHidden = hidden + onSearchBarToggled (hidden) { + this.searchBarHidden = hidden }, updateMobileState () { const mobileLayout = windowWidth() <= 800 diff --git a/src/App.vue b/src/App.vue index 758c9fce..be4d1f75 100644 --- a/src/App.vue +++ b/src/App.vue @@ -38,9 +38,9 @@
- { { name: 'login', path: '/login', component: AuthForm }, { name: 'chat', path: '/chat', component: ChatPanel, props: () => ({ floating: false }) }, { name: 'oauth-callback', path: '/oauth-callback', component: OAuthCallback, props: (route) => ({ code: route.query.code }) }, - { name: 'user-search', path: '/user-search', component: UserSearch, props: (route) => ({ query: route.query.query }) }, + { name: 'search', path: '/search', component: Search, props: (route) => ({ query: route.query.query }) }, { name: 'who-to-follow', path: '/who-to-follow', component: WhoToFollow }, { name: 'about', path: '/about', component: About }, { name: 'user-profile', path: '/(users/)?:name', component: UserProfile } diff --git a/src/components/search/search.js b/src/components/search/search.js new file mode 100644 index 00000000..b434e127 --- /dev/null +++ b/src/components/search/search.js @@ -0,0 +1,98 @@ +import FollowCard from '../follow_card/follow_card.vue' +import Conversation from '../conversation/conversation.vue' +import Status from '../status/status.vue' +import map from 'lodash/map' + +const Search = { + components: { + FollowCard, + Conversation, + Status + }, + props: [ + 'query' + ], + data () { + return { + loaded: false, + loading: false, + searchTerm: this.query || '', + userIds: [], + statuses: [], + hashtags: [], + currenResultTab: 'statuses' + } + }, + computed: { + users () { + return this.userIds.map(userId => this.$store.getters.findUser(userId)) + }, + visibleStatuses () { + const allStatusesObject = this.$store.state.statuses.allStatusesObject + + return this.statuses.filter(status => + allStatusesObject[status.id] && !allStatusesObject[status.id].deleted + ) + } + }, + mounted () { + this.search(this.query) + }, + watch: { + query (newValue) { + this.searchTerm = newValue + this.search(newValue) + } + }, + methods: { + newQuery (query) { + this.$router.push({ name: 'search', query: { query } }) + this.$refs.searchInput.focus() + }, + search (query) { + if (!query) { + this.loading = false + return + } + + this.loading = true + this.userIds = [] + this.statuses = [] + this.hashtags = [] + this.$refs.searchInput.blur() + + this.$store.dispatch('search', { q: query, resolve: true }) + .then(data => { + this.loading = false + this.userIds = map(data.accounts, 'id') + this.statuses = data.statuses + this.hashtags = data.hashtags + this.currenResultTab = this.getActiveTab() + this.loaded = true + }) + }, + resultCount (tabName) { + const length = this[tabName].length + return length === 0 ? '' : ` (${length})` + }, + onResultTabSwitch (_index, dataset) { + this.currenResultTab = dataset.filter + }, + getActiveTab () { + if (this.visibleStatuses.length > 0) { + return 'statuses' + } else if (this.users.length > 0) { + return 'people' + } else if (this.hashtags.length > 0) { + return 'hashtags' + } + + return 'statuses' + }, + lastHistoryRecord (hashtag) { + return hashtag.history && hashtag.history[0] + } + } +} + +export default Search diff --git a/src/components/search/search.vue b/src/components/search/search.vue new file mode 100644 index 00000000..4350e672 --- /dev/null +++ b/src/components/search/search.vue @@ -0,0 +1,211 @@ + + + + + diff --git a/src/components/search_bar/search_bar.js b/src/components/search_bar/search_bar.js new file mode 100644 index 00000000..b8a792ee --- /dev/null +++ b/src/components/search_bar/search_bar.js @@ -0,0 +1,27 @@ +const SearchBar = { + data: () => ({ + searchTerm: undefined, + hidden: true, + error: false, + loading: false + }), + watch: { + '$route': function (route) { + if (route.name === 'search') { + this.searchTerm = route.query.query + } + } + }, + methods: { + find (searchTerm) { + this.$router.push({ name: 'search', query: { query: searchTerm } }) + this.$refs.searchInput.focus() + }, + toggleHidden () { + this.hidden = !this.hidden + this.$emit('toggled', this.hidden) + } + } +} + +export default SearchBar diff --git a/src/components/search_bar/search_bar.vue b/src/components/search_bar/search_bar.vue new file mode 100644 index 00000000..4d5a1aec --- /dev/null +++ b/src/components/search_bar/search_bar.vue @@ -0,0 +1,73 @@ + + + + + diff --git a/src/components/side_drawer/side_drawer.vue b/src/components/side_drawer/side_drawer.vue index 80b75ce5..5b2d4473 100644 --- a/src/components/side_drawer/side_drawer.vue +++ b/src/components/side_drawer/side_drawer.vue @@ -100,8 +100,8 @@
  • - - {{ $t("nav.user_search") }} + + {{ $t("nav.search") }}
  • _.tag) @@ -24,6 +24,14 @@ export default Vue.component('tab-switcher', { } this.active = index } + }, + isActiveTab (index) { + const customActiveIndex = this.$slots.default.findIndex(slot => { + const dataFilter = slot.data && slot.data.attrs && slot.data.attrs['data-filter'] + return this.customActive && this.customActive === dataFilter + }) + + return customActiveIndex > -1 ? customActiveIndex === index : index === this.active } }, render (h) { @@ -33,7 +41,7 @@ export default Vue.component('tab-switcher', { const classesTab = ['tab'] const classesWrapper = ['tab-wrapper'] - if (index === this.active) { + if (this.isActiveTab(index)) { classesTab.push('active') classesWrapper.push('active') } diff --git a/src/components/user_finder/user_finder.js b/src/components/user_finder/user_finder.js deleted file mode 100644 index 27153f45..00000000 --- a/src/components/user_finder/user_finder.js +++ /dev/null @@ -1,20 +0,0 @@ -const UserFinder = { - data: () => ({ - username: undefined, - hidden: true, - error: false, - loading: false - }), - methods: { - findUser (username) { - this.$router.push({ name: 'user-search', query: { query: username } }) - this.$refs.userSearchInput.focus() - }, - toggleHidden () { - this.hidden = !this.hidden - this.$emit('toggled', this.hidden) - } - } -} - -export default UserFinder diff --git a/src/components/user_finder/user_finder.vue b/src/components/user_finder/user_finder.vue deleted file mode 100644 index 39d49237..00000000 --- a/src/components/user_finder/user_finder.vue +++ /dev/null @@ -1,67 +0,0 @@ - - - - - diff --git a/src/components/user_search/user_search.js b/src/components/user_search/user_search.js deleted file mode 100644 index 5c29d8f2..00000000 --- a/src/components/user_search/user_search.js +++ /dev/null @@ -1,49 +0,0 @@ -import FollowCard from '../follow_card/follow_card.vue' -import map from 'lodash/map' - -const userSearch = { - components: { - FollowCard - }, - props: [ - 'query' - ], - data () { - return { - username: '', - userIds: [], - loading: false - } - }, - computed: { - users () { - return this.userIds.map(userId => this.$store.getters.findUser(userId)) - } - }, - mounted () { - this.search(this.query) - }, - watch: { - query (newV) { - this.search(newV) - } - }, - methods: { - newQuery (query) { - this.$router.push({ name: 'user-search', query: { query } }) - this.$refs.userSearchInput.focus() - }, - search (query) { - if (!query) { - return - } - this.loading = true - this.userIds = [] - this.$store.dispatch('searchUsers', query) - .then((res) => { this.userIds = map(res, 'id') }) - .finally(() => { this.loading = false }) - } - } -} - -export default userSearch diff --git a/src/components/user_search/user_search.vue b/src/components/user_search/user_search.vue deleted file mode 100644 index e1c6074c..00000000 --- a/src/components/user_search/user_search.vue +++ /dev/null @@ -1,57 +0,0 @@ - - - - - diff --git a/src/i18n/en.json b/src/i18n/en.json index 49989f78..b5c6b1d8 100644 --- a/src/i18n/en.json +++ b/src/i18n/en.json @@ -78,6 +78,7 @@ "timeline": "Timeline", "twkn": "The Whole Known Network", "user_search": "User Search", + "search": "Search", "who_to_follow": "Who to follow", "preferences": "Preferences" }, @@ -595,5 +596,12 @@ "GiB": "GiB", "TiB": "TiB" } + }, + "search": { + "people": "People", + "hashtags": "Hashtags", + "person_talking": "{count} person talking", + "people_talking": "{count} people talking", + "no_results": "No results" } } diff --git a/src/i18n/ru.json b/src/i18n/ru.json index d24ef0cb..90ed6664 100644 --- a/src/i18n/ru.json +++ b/src/i18n/ru.json @@ -38,7 +38,8 @@ "interactions": "Взаимодействия", "public_tl": "Публичная лента", "timeline": "Лента", - "twkn": "Федеративная лента" + "twkn": "Федеративная лента", + "search": "Поиск" }, "notifications": { "broken_favorite": "Неизвестный статус, ищем...", @@ -381,5 +382,12 @@ }, "user_profile": { "timeline_title": "Лента пользователя" + }, + "search": { + "people": "Люди", + "hashtags": "Хэштэги", + "person_talking": "Популярно у {count} человека", + "people_talking": "Популярно у {count} человек", + "no_results": "Ничего не найдено" } } diff --git a/src/modules/statuses.js b/src/modules/statuses.js index 9d8d768c..7d5d5a67 100644 --- a/src/modules/statuses.js +++ b/src/modules/statuses.js @@ -602,6 +602,14 @@ const statuses = { fetchRepeats ({ rootState, commit }, id) { rootState.api.backendInteractor.fetchRebloggedByUsers(id) .then(rebloggedByUsers => commit('addRepeats', { id, rebloggedByUsers, currentUser: rootState.users.currentUser })) + }, + search (store, { q, resolve, limit, offset, following }) { + return store.rootState.api.backendInteractor.search2({ q, resolve, limit, offset, following }) + .then((data) => { + store.commit('addNewUsers', data.accounts) + store.commit('addNewStatuses', { statuses: data.statuses }) + return data + }) } }, mutations diff --git a/src/services/api/api.service.js b/src/services/api/api.service.js index e417cf29..2de1c3b7 100644 --- a/src/services/api/api.service.js +++ b/src/services/api/api.service.js @@ -67,7 +67,7 @@ const MASTODON_PROFILE_UPDATE_URL = '/api/v1/accounts/update_credentials' const MASTODON_REPORT_USER_URL = '/api/v1/reports' const MASTODON_PIN_OWN_STATUS = id => `/api/v1/statuses/${id}/pin` const MASTODON_UNPIN_OWN_STATUS = id => `/api/v1/statuses/${id}/unpin` -const MASTODON_USER_SEARCH_URL = '/api/v1/accounts/search' +const MASTODON_SEARCH_2 = `/api/v2/search` const oldfetch = window.fetch @@ -853,16 +853,46 @@ const reportUser = ({ credentials, userId, statusIds, comment, forward }) => { }) } -const searchUsers = ({ credentials, query }) => { - return promisedRequest({ - url: MASTODON_USER_SEARCH_URL, - params: { - q: query, - resolve: true - }, - credentials - }) - .then((data) => data.map(parseUser)) +const search2 = ({ credentials, q, resolve, limit, offset, following }) => { + let url = MASTODON_SEARCH_2 + let params = [] + + if (q) { + params.push(['q', encodeURIComponent(q)]) + } + + if (resolve) { + params.push(['resolve', resolve]) + } + + if (limit) { + params.push(['limit', limit]) + } + + if (offset) { + params.push(['offset', offset]) + } + + if (following) { + params.push(['following', true]) + } + + let queryString = map(params, (param) => `${param[0]}=${param[1]}`).join('&') + url += `?${queryString}` + + return fetch(url, { headers: authHeaders(credentials) }) + .then((data) => { + if (data.ok) { + return data + } + throw new Error('Error fetching search result', data) + }) + .then((data) => { return data.json() }) + .then((data) => { + data.accounts = data.accounts.slice(0, limit).map(u => parseUser(u)) + data.statuses = data.statuses.slice(0, limit).map(s => parseStatus(s)) + return data + }) } const apiService = { @@ -930,7 +960,7 @@ const apiService = { fetchRebloggedByUsers, reportUser, updateNotificationSettings, - searchUsers + search2 } export default apiService diff --git a/src/services/backend_interactor_service/backend_interactor_service.js b/src/services/backend_interactor_service/backend_interactor_service.js index 4e1675c2..4f067df9 100644 --- a/src/services/backend_interactor_service/backend_interactor_service.js +++ b/src/services/backend_interactor_service/backend_interactor_service.js @@ -148,8 +148,8 @@ const backendInteractorService = credentials => { const unfavorite = (id) => apiService.unfavorite({ id, credentials }) const retweet = (id) => apiService.retweet({ id, credentials }) const unretweet = (id) => apiService.unretweet({ id, credentials }) - - const searchUsers = (query) => apiService.searchUsers({ query, credentials }) + const search2 = ({ q, resolve, limit, offset, following }) => + apiService.search2({ credentials, q, resolve, limit, offset, following }) const backendInteractorServiceInstance = { fetchStatus, @@ -212,7 +212,7 @@ const backendInteractorService = credentials => { retweet, unretweet, updateNotificationSettings, - searchUsers + search2 } return backendInteractorServiceInstance -- cgit v1.2.3-70-g09d2