forked from AkkomaGang/akkoma-fe
Add list of followed hashtags to profile
This commit is contained in:
parent
0e71597e56
commit
79d506e331
7 changed files with 147 additions and 13 deletions
27
src/components/followed_tag_card/FollowedTagCard.vue
Normal file
27
src/components/followed_tag_card/FollowedTagCard.vue
Normal file
|
@ -0,0 +1,27 @@
|
|||
<template>
|
||||
<div class="followed-tag-card">
|
||||
<h3>
|
||||
<router-link :to="{ name: 'tag-timeline', params: {tag: tag.name}}">
|
||||
#{{ tag.name }}
|
||||
</router-link>
|
||||
</h3>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'FollowedTagCard',
|
||||
props: {
|
||||
tag: {
|
||||
type: Object,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.followed-tag-card {
|
||||
margin-left: 1rem;
|
||||
}
|
||||
</style>
|
|
@ -13,6 +13,7 @@ import {
|
|||
faCircleNotch,
|
||||
faCircleCheck
|
||||
} from '@fortawesome/free-solid-svg-icons'
|
||||
import FollowedTagCard from '../followed_tag_card/FollowedTagCard.vue'
|
||||
|
||||
library.add(
|
||||
faCircleNotch,
|
||||
|
@ -35,6 +36,14 @@ const FriendList = withLoadMore({
|
|||
additionalPropNames: ['userId']
|
||||
})(List)
|
||||
|
||||
const FollowedTagList = withLoadMore({
|
||||
fetch: (props, $store) => $store.dispatch('fetchFollowedTags', props.userId),
|
||||
select: (props, $store) => get($store.getters.findUser(props.userId), 'followedTagIds', []).map(id => $store.getters.findTag(id)),
|
||||
destroy: (props, $store) => $store.dispatch('clearFollowedTags', props.userId),
|
||||
childPropName: 'items',
|
||||
additionalPropNames: ['userId']
|
||||
})(List)
|
||||
|
||||
const isUserPage = ({ name }) => name === 'user-profile' || name === 'external-user-profile'
|
||||
|
||||
const UserProfile = {
|
||||
|
@ -202,6 +211,7 @@ const UserProfile = {
|
|||
}
|
||||
},
|
||||
components: {
|
||||
FollowedTagCard,
|
||||
UserCard,
|
||||
Timeline,
|
||||
FollowerList,
|
||||
|
@ -209,7 +219,8 @@ const UserProfile = {
|
|||
FollowCard,
|
||||
TabSwitcher,
|
||||
Conversation,
|
||||
RichContent
|
||||
RichContent,
|
||||
FollowedTagList,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -104,6 +104,14 @@
|
|||
v-if="followsTabVisible"
|
||||
key="followees"
|
||||
:label="$t('user_card.followees')"
|
||||
>
|
||||
<tab-switcher
|
||||
:active-tab="users"
|
||||
:render-only-focused="true"
|
||||
>
|
||||
<div
|
||||
key="users"
|
||||
:label="$t('user_card.followed_users')"
|
||||
>
|
||||
<FriendList :user-id="userId">
|
||||
<template #item="{item}">
|
||||
|
@ -111,6 +119,23 @@
|
|||
</template>
|
||||
</FriendList>
|
||||
</div>
|
||||
<div
|
||||
key="tags"
|
||||
v-if="isUs"
|
||||
:label="$t('user_card.followed_tags')"
|
||||
>
|
||||
<FollowedTagList
|
||||
:user-id="userId"
|
||||
:following="false"
|
||||
:get-key="(item) => item.name"
|
||||
>
|
||||
<template #item="{item}">
|
||||
<FollowedTagCard :tag="item" />
|
||||
</template>
|
||||
</FollowedTagList>
|
||||
</div>
|
||||
</tab-switcher>
|
||||
</div>
|
||||
<div
|
||||
v-if="followersTabVisible"
|
||||
key="followers"
|
||||
|
|
|
@ -59,7 +59,8 @@ const withLoadMore = ({
|
|||
this.loading = false
|
||||
this.bottomedOut = isEmpty(newEntries)
|
||||
})
|
||||
.catch(() => {
|
||||
.catch((e) => {
|
||||
console.error(e)
|
||||
this.loading = false
|
||||
this.error = true
|
||||
})
|
||||
|
|
|
@ -1139,6 +1139,8 @@
|
|||
"follow_unfollow": "Unfollow this jerk",
|
||||
"followees": "Following",
|
||||
"followers": "Followers",
|
||||
"followed_tags": "Followed hashtags",
|
||||
"followed_users": "Followed users",
|
||||
"following": "Following!",
|
||||
"follows_you": "Follows you!",
|
||||
"hidden": "Hidden",
|
||||
|
|
|
@ -5,9 +5,9 @@ import { compact, map, each, mergeWith, last, concat, uniq, isArray } from 'loda
|
|||
import { registerPushNotifications, unregisterPushNotifications } from '../services/push/push.js'
|
||||
|
||||
// TODO: Unify with mergeOrAdd in statuses.js
|
||||
export const mergeOrAdd = (arr, obj, item) => {
|
||||
export const mergeOrAdd = (arr, obj, item, key = 'id') => {
|
||||
if (!item) { return false }
|
||||
const oldItem = obj[item.id]
|
||||
const oldItem = obj[item[key]]
|
||||
if (oldItem) {
|
||||
// We already have this, so only merge the new info.
|
||||
mergeWith(oldItem, item, mergeArrayLength)
|
||||
|
@ -15,7 +15,7 @@ export const mergeOrAdd = (arr, obj, item) => {
|
|||
} else {
|
||||
// This is a new item, prepare it
|
||||
arr.push(item)
|
||||
obj[item.id] = item
|
||||
obj[item[key]] = item
|
||||
if (item.screen_name && !item.screen_name.includes('@')) {
|
||||
obj[item.screen_name.toLowerCase()] = item
|
||||
}
|
||||
|
@ -157,6 +157,14 @@ export const mutations = {
|
|||
const user = state.usersObject[id]
|
||||
user.followerIds = uniq(concat(user.followerIds || [], followerIds))
|
||||
},
|
||||
saveFollowedTagIds (state, { id, followedTagIds }) {
|
||||
const user = state.usersObject[id]
|
||||
user.followedTagIds = uniq(concat(user.followedTagIds || [], followedTagIds))
|
||||
},
|
||||
saveFollowedTagPagination (state, { id, pagination }) {
|
||||
const user = state.usersObject[id]
|
||||
user.followedTagPagination = pagination
|
||||
},
|
||||
// Because frontend doesn't have a reason to keep these stuff in memory
|
||||
// outside of viewing someones user profile.
|
||||
clearFriends (state, userId) {
|
||||
|
@ -171,6 +179,12 @@ export const mutations = {
|
|||
user['followerIds'] = []
|
||||
}
|
||||
},
|
||||
clearFollowedTags (state, userId) {
|
||||
const user = state.usersObject[userId]
|
||||
if (user) {
|
||||
user['followedTagIds'] = []
|
||||
}
|
||||
},
|
||||
addNewUsers (state, users) {
|
||||
each(users, (user) => {
|
||||
if (user.relationship) {
|
||||
|
@ -179,6 +193,11 @@ export const mutations = {
|
|||
mergeOrAdd(state.users, state.usersObject, user)
|
||||
})
|
||||
},
|
||||
addNewTags (state, tags) {
|
||||
each(tags, (tag) => {
|
||||
mergeOrAdd(state.tags, state.tagsObject, tag, 'name')
|
||||
})
|
||||
},
|
||||
updateUserRelationship (state, relationships) {
|
||||
relationships.forEach((relationship) => {
|
||||
state.relationships[relationship.id] = relationship
|
||||
|
@ -271,7 +290,11 @@ export const getters = {
|
|||
relationship: state => id => {
|
||||
const rel = id && state.relationships[id]
|
||||
return rel || { id, loading: true }
|
||||
}
|
||||
},
|
||||
findTag: state => query => {
|
||||
const result = state.tagsObject[query]
|
||||
return result
|
||||
},
|
||||
}
|
||||
|
||||
export const defaultState = {
|
||||
|
@ -282,7 +305,9 @@ export const defaultState = {
|
|||
usersObject: {},
|
||||
signUpPending: false,
|
||||
signUpErrors: [],
|
||||
relationships: {}
|
||||
relationships: {},
|
||||
tags: [],
|
||||
tagsObject: {}
|
||||
}
|
||||
|
||||
const users = {
|
||||
|
@ -402,12 +427,27 @@ const users = {
|
|||
return followers
|
||||
})
|
||||
},
|
||||
fetchFollowedTags ({ rootState, commit }, id) {
|
||||
const user = rootState.users.usersObject[id]
|
||||
const pagination = user.followedTagPagination
|
||||
|
||||
return rootState.api.backendInteractor.getFollowedHashtags({ pagination })
|
||||
.then(({ data: tags, pagination }) => {
|
||||
commit('addNewTags', tags)
|
||||
commit('saveFollowedTagIds', { id, followedTagIds: tags.map(tag => tag.name) })
|
||||
commit('saveFollowedTagPagination', { id, pagination })
|
||||
return tags
|
||||
})
|
||||
},
|
||||
clearFriends ({ commit }, userId) {
|
||||
commit('clearFriends', userId)
|
||||
},
|
||||
clearFollowers ({ commit }, userId) {
|
||||
commit('clearFollowers', userId)
|
||||
},
|
||||
clearFollowedTags ({ commit }, userId) {
|
||||
commit('clearFollowedTags', userId)
|
||||
},
|
||||
subscribeUser ({ rootState, commit }, id) {
|
||||
return rootState.api.backendInteractor.subscribeUser({ id })
|
||||
.then((relationship) => commit('updateUserRelationship', [relationship]))
|
||||
|
@ -437,6 +477,9 @@ const users = {
|
|||
addNewUsers ({ commit }, users) {
|
||||
commit('addNewUsers', users)
|
||||
},
|
||||
addNewTags ({ commit }, tags) {
|
||||
commit('addNewTags', tags)
|
||||
},
|
||||
addNewStatuses (store, { statuses }) {
|
||||
const users = map(statuses, 'user')
|
||||
const retweetedUsers = compact(map(statuses, 'retweeted_status.user'))
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import { each, map, concat, last, get } from 'lodash'
|
||||
import { parseStatus, parseSource, parseUser, parseNotification, parseReport, parseAttachment, parseLinkHeaderPagination } from '../entity_normalizer/entity_normalizer.service.js'
|
||||
import { RegistrationError, StatusCodeError } from '../errors/errors'
|
||||
import { Url } from 'url'
|
||||
|
||||
/* eslint-env browser */
|
||||
const MUTES_IMPORT_URL = '/api/pleroma/mutes_import'
|
||||
|
@ -111,6 +112,7 @@ const AKKOMA_SETTING_PROFILE_LIST = `/api/v1/akkoma/frontend_settings/pleroma-fe
|
|||
const MASTODON_TAG_URL = (name) => `/api/v1/tags/${name}`
|
||||
const MASTODON_FOLLOW_TAG_URL = (name) => `/api/v1/tags/${name}/follow`
|
||||
const MASTODON_UNFOLLOW_TAG_URL = (name) => `/api/v1/tags/${name}/unfollow`
|
||||
const MASTODON_FOLLOWED_TAGS_URL = '/api/v1/followed_tags'
|
||||
|
||||
const oldfetch = window.fetch
|
||||
|
||||
|
@ -1575,6 +1577,28 @@ const unfollowHashtag = ({ tag, credentials }) => {
|
|||
})
|
||||
}
|
||||
|
||||
const getFollowedHashtags = ({ credentials, pagination: savedPagination }) => {
|
||||
const queryParams = new URLSearchParams()
|
||||
if (savedPagination?.maxId) {
|
||||
queryParams.append('max_id', savedPagination.maxId)
|
||||
}
|
||||
const url = `${MASTODON_FOLLOWED_TAGS_URL}?${queryParams.toString()}`
|
||||
let pagination = {};
|
||||
return fetch(url, {
|
||||
credentials
|
||||
}).then((data) => {
|
||||
pagination = parseLinkHeaderPagination(data.headers.get('Link'), {
|
||||
flakeId: false
|
||||
});
|
||||
return data.json()
|
||||
}).then((data) => {
|
||||
return {
|
||||
pagination,
|
||||
data
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export const getMastodonSocketURI = ({ credentials, stream, args = {} }) => {
|
||||
return Object.entries({
|
||||
...(credentials
|
||||
|
@ -1813,7 +1837,8 @@ const apiService = {
|
|||
deleteNoteFromReport,
|
||||
getHashtag,
|
||||
followHashtag,
|
||||
unfollowHashtag
|
||||
unfollowHashtag,
|
||||
getFollowedHashtags,
|
||||
}
|
||||
|
||||
export default apiService
|
||||
|
|
Loading…
Reference in a new issue