From 88d5149db5948e19dbe66406d00e0e5167237a4f Mon Sep 17 00:00:00 2001 From: floatingghost Date: Sat, 4 Feb 2023 21:09:09 +0000 Subject: [PATCH] paginate-follow-requests (#277) Co-authored-by: FloatingGhost Reviewed-on: https://akkoma.dev/AkkomaGang/akkoma-fe/pulls/277 --- .../follow_request_card.js | 7 ++++ .../follow_request_card.vue | 2 +- .../follow_requests/follow_requests.js | 18 +++++++- .../follow_requests/follow_requests.vue | 11 +++-- src/components/nav_panel/nav_panel.js | 11 ++--- src/components/user_profile/user_profile.js | 2 +- src/modules/api.js | 41 +++++++++++-------- src/modules/users.js | 13 +++++- src/services/api/api.service.js | 30 ++++++++++---- .../backend_interactor_service.js | 5 --- .../entity_normalizer.service.js | 1 + .../follow_request_fetcher.service.js | 23 ----------- 12 files changed, 92 insertions(+), 72 deletions(-) delete mode 100644 src/services/follow_request_fetcher/follow_request_fetcher.service.js diff --git a/src/components/follow_request_card/follow_request_card.js b/src/components/follow_request_card/follow_request_card.js index b0873bb1..47c86e15 100644 --- a/src/components/follow_request_card/follow_request_card.js +++ b/src/components/follow_request_card/follow_request_card.js @@ -43,6 +43,7 @@ const FollowRequestCard = { doApprove () { this.$store.state.api.backendInteractor.approveUser({ id: this.user.id }) this.$store.dispatch('removeFollowRequest', this.user) + this.$store.dispatch('decrementFollowRequestsCount') const notifId = this.findFollowRequestNotificationId() this.$store.dispatch('markSingleNotificationAsSeen', { id: notifId }) @@ -66,6 +67,7 @@ const FollowRequestCard = { this.$store.state.api.backendInteractor.denyUser({ id: this.user.id }) .then(() => { this.$store.dispatch('dismissNotificationLocal', { id: notifId }) + this.$store.dispatch('decrementFollowRequestsCount') this.$store.dispatch('removeFollowRequest', this.user) }) this.hideDenyConfirmDialog() @@ -80,6 +82,11 @@ const FollowRequestCard = { }, shouldConfirmDeny () { return this.mergedConfig.modalOnDenyFollow + }, + show () { + const notifId = this.$store.state.api.followRequests.find(req => req.id === this.user.id) + + return notifId !== undefined } } } diff --git a/src/components/follow_request_card/follow_request_card.vue b/src/components/follow_request_card/follow_request_card.vue index 835471e7..80445021 100644 --- a/src/components/follow_request_card/follow_request_card.vue +++ b/src/components/follow_request_card/follow_request_card.vue @@ -1,5 +1,5 @@ diff --git a/src/components/nav_panel/nav_panel.js b/src/components/nav_panel/nav_panel.js index af165d47..2eda912e 100644 --- a/src/components/nav_panel/nav_panel.js +++ b/src/components/nav_panel/nav_panel.js @@ -33,11 +33,6 @@ library.add( ) const NavPanel = { - created () { - if (this.currentUser && this.currentUser.locked) { - this.$store.dispatch('startFetchingFollowRequests') - } - }, components: { TimelineMenuContent }, @@ -54,11 +49,13 @@ const NavPanel = { computed: { ...mapState({ currentUser: state => state.users.currentUser, - followRequestCount: state => state.api.followRequests.length, privateMode: state => state.instance.private, federating: state => state.instance.federating }), - ...mapGetters(['unreadAnnouncementCount']) + ...mapGetters(['unreadAnnouncementCount']), + followRequestCount () { + return this.$store.state.users.currentUser.follow_requests_count + } } } diff --git a/src/components/user_profile/user_profile.js b/src/components/user_profile/user_profile.js index 1cadddda..9ea8c2a7 100644 --- a/src/components/user_profile/user_profile.js +++ b/src/components/user_profile/user_profile.js @@ -224,7 +224,7 @@ const UserProfile = { TabSwitcher, Conversation, RichContent, - FollowedTagList, + FollowedTagList } } diff --git a/src/modules/api.js b/src/modules/api.js index c54aa4fb..8de1449b 100644 --- a/src/modules/api.js +++ b/src/modules/api.js @@ -1,5 +1,6 @@ import backendInteractorService from '../services/backend_interactor_service/backend_interactor_service.js' import { WSConnectionStatus } from '../services/api/api.service.js' +import { map } from 'lodash' const retryTimeout = (multiplier) => 1000 * multiplier @@ -40,9 +41,6 @@ const api = { setSocket (state, socket) { state.socket = socket }, - setFollowRequests (state, value) { - state.followRequests = value - }, setMastoUserSocketStatus (state, value) { state.mastoUserSocketStatus = value }, @@ -51,6 +49,15 @@ const api = { }, resetRetryMultiplier (state) { state.retryMultiplier = 1 + }, + setFollowRequests (state, value) { + state.followRequests = [...value] + }, + saveFollowRequests (state, requests) { + state.followRequests = [...state.followRequests, ...requests] + }, + saveFollowRequestPagination (state, pagination) { + state.followRequestsPagination = pagination } }, actions: { @@ -240,24 +247,22 @@ const api = { ...rest }) }, - - // Follow requests - startFetchingFollowRequests (store) { - if (store.state.fetchers['followRequests']) return - const fetcher = store.state.backendInteractor.startFetchingFollowRequests({ store }) - - store.commit('addFetcher', { fetcherName: 'followRequests', fetcher }) - }, - stopFetchingFollowRequests (store) { - const fetcher = store.state.fetchers.followRequests - if (!fetcher) return - store.commit('removeFetcher', { fetcherName: 'followRequests', fetcher }) - }, removeFollowRequest (store, request) { - let requests = store.state.followRequests.filter((it) => it !== request) + let requests = [...store.state.followRequests].filter((it) => it.id !== request.id) store.commit('setFollowRequests', requests) }, - + fetchFollowRequests ({ rootState, commit }) { + const pagination = rootState.api.followRequestsPagination + return rootState.api.backendInteractor.getFollowRequests({ pagination }) + .then((requests) => { + if (requests.data.length > 0) { + commit('addNewUsers', requests.data) + commit('saveFollowRequests', requests.data) + commit('saveFollowRequestPagination', requests.pagination) + } + return requests + }) + }, // Lists startFetchingLists (store) { if (store.state.fetchers['lists']) return diff --git a/src/modules/users.js b/src/modules/users.js index c63b93de..bc1943c8 100644 --- a/src/modules/users.js +++ b/src/modules/users.js @@ -265,6 +265,12 @@ export const mutations = { signUpFailure (state, errors) { state.signUpPending = false state.signUpErrors = errors + }, + decrementFollowRequestsCount (store) { + store.currentUser.follow_requests_count-- + }, + incrementFollowRequestsCount (store) { + store.currentUser.follow_requests_count++ } } @@ -504,6 +510,12 @@ const users = { store.commit('setUserForNotification', notification) }) }, + decrementFollowRequestsCount (store) { + store.commit('decrementFollowRequestsCount') + }, + incrementFollowRequestsCount (store) { + store.commit('incrementFollowRequestsCount') + }, searchUsers ({ rootState, commit }, { query }) { return rootState.api.backendInteractor.searchUsers({ query }) .then((users) => { @@ -567,7 +579,6 @@ const users = { store.dispatch('stopFetchingTimeline', 'friends') store.commit('setBackendInteractor', backendInteractorService(store.getters.getToken())) store.dispatch('stopFetchingNotifications') - store.dispatch('stopFetchingFollowRequests') store.dispatch('stopFetchingConfig') store.commit('clearNotifications') store.commit('resetStatuses') diff --git a/src/services/api/api.service.js b/src/services/api/api.service.js index 0f8b75a4..947e9da9 100644 --- a/src/services/api/api.service.js +++ b/src/services/api/api.service.js @@ -406,14 +406,6 @@ const fetchFollowers = ({ id, maxId, sinceId, limit = 20, credentials }) => { .then((data) => data.json()) .then((data) => data.map(parseUser)) } - -const fetchFollowRequests = ({ credentials }) => { - const url = MASTODON_FOLLOW_REQUESTS_URL - return fetch(url, { headers: authHeaders(credentials) }) - .then((data) => data.json()) - .then((data) => data.map(parseUser)) -} - const fetchLists = ({ credentials }) => { const url = MASTODON_LISTS_URL return fetch(url, { headers: authHeaders(credentials) }) @@ -1601,6 +1593,26 @@ const getFollowedHashtags = ({ credentials, pagination: savedPagination }) => { }); } +const getFollowRequests = ({ credentials, pagination: savedPagination }) => { + const queryParams = new URLSearchParams() + if (savedPagination?.maxId) { + queryParams.append('max_id', savedPagination.maxId) + } + const url = `${MASTODON_FOLLOW_REQUESTS_URL}?${queryParams.toString()}` + let pagination = {}; + return fetch(url, { + credentials + }).then((data) => { + pagination = parseLinkHeaderPagination(data.headers.get('Link'), { flakeId: true }); + return data.json() + }).then((data) => { + return { + pagination, + data: data.map(parseUser) + } + }); +} + export const getMastodonSocketURI = ({ credentials, stream, args = {} }) => { return Object.entries({ ...(credentials @@ -1790,7 +1802,6 @@ const apiService = { mfaConfirmOTP, addBackup, listBackups, - fetchFollowRequests, fetchLists, createList, getList, @@ -1841,6 +1852,7 @@ const apiService = { followHashtag, unfollowHashtag, getFollowedHashtags, + getFollowRequests } 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 4d6f80c2..58515387 100644 --- a/src/services/backend_interactor_service/backend_interactor_service.js +++ b/src/services/backend_interactor_service/backend_interactor_service.js @@ -1,7 +1,6 @@ import apiService, { getMastodonSocketURI, ProcessedWS } from '../api/api.service.js' import timelineFetcher from '../timeline_fetcher/timeline_fetcher.service.js' import notificationsFetcher from '../notifications_fetcher/notifications_fetcher.service.js' -import followRequestFetcher from '../../services/follow_request_fetcher/follow_request_fetcher.service' import listsFetcher from '../../services/lists_fetcher/lists_fetcher.service.js' import announcementsFetcher from '../../services/announcements_fetcher/announcements_fetcher.service.js' import configFetcher from '../config_fetcher/config_fetcher.service.js' @@ -28,10 +27,6 @@ const backendInteractorService = credentials => ({ return notificationsFetcher.fetchAndUpdate({ ...args, credentials }) }, - startFetchingFollowRequests ({ store }) { - return followRequestFetcher.startFetching({ store, credentials }) - }, - startFetchingLists ({ store }) { return listsFetcher.startFetching({ store, credentials }) }, diff --git a/src/services/entity_normalizer/entity_normalizer.service.js b/src/services/entity_normalizer/entity_normalizer.service.js index c54ce3e2..e330ca8c 100644 --- a/src/services/entity_normalizer/entity_normalizer.service.js +++ b/src/services/entity_normalizer/entity_normalizer.service.js @@ -90,6 +90,7 @@ export const parseUser = (data) => { output.friends_count = data.following_count output.bot = data.bot + output.follow_requests_count = data.follow_requests_count if (data.akkoma) { output.instance = data.akkoma.instance output.status_ttl_days = data.akkoma.status_ttl_days diff --git a/src/services/follow_request_fetcher/follow_request_fetcher.service.js b/src/services/follow_request_fetcher/follow_request_fetcher.service.js deleted file mode 100644 index 5c0ab85e..00000000 --- a/src/services/follow_request_fetcher/follow_request_fetcher.service.js +++ /dev/null @@ -1,23 +0,0 @@ -import apiService from '../api/api.service.js' -import { promiseInterval } from '../promise_interval/promise_interval.js' - -const fetchAndUpdate = ({ store, credentials }) => { - return apiService.fetchFollowRequests({ credentials }) - .then((requests) => { - store.commit('setFollowRequests', requests) - store.commit('addNewUsers', requests) - }, () => {}) - .catch(() => {}) -} - -const startFetching = ({ credentials, store }) => { - const boundFetchAndUpdate = () => fetchAndUpdate({ credentials, store }) - boundFetchAndUpdate() - return promiseInterval(boundFetchAndUpdate, 240000) -} - -const followRequestFetcher = { - startFetching -} - -export default followRequestFetcher