fixes for reprööts/favorites display

This commit is contained in:
Henry Jameson 2026-08-28 15:38:05 +03:00
commit 5854b222bd
6 changed files with 61 additions and 57 deletions

View file

@ -1,14 +1,19 @@
import UserAvatar from 'src/components/user_avatar/user_avatar.vue'
import { useInstanceStore } from 'src/stores/instance.js'
import { useUsersStore } from 'src/stores/users.js'
import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator'
const AvatarList = {
props: ['users'],
props: {
userIds: Set,
},
computed: {
slicedUsers() {
return this.users ? this.users.slice(0, 15) : []
return [...(this.userIds ?? [])]
.slice(0, 15)
.map((id) => useUsersStore().findUser(id))
},
},
components: {

View file

@ -1,4 +1,3 @@
import { uniqBy } from 'lodash'
import { defineAsyncComponent } from 'vue'
import AvatarList from 'src/components/avatar_list/avatar_list.vue'
@ -179,6 +178,12 @@ const Status = {
useUserHighlightStore().get(this.repeater.screen_name),
)
},
favoritedBy() {
return useStatusesStore().favs.get(this.mainStatus.id) ?? new Set()
},
repeatedBy() {
return useStatusesStore().repeats.get(this.mainStatus.id) ?? new Set()
},
userStyle() {
if (this.noHeading) return
return highlightStyle(useUserHighlightStore().get(this.user.screen_name))
@ -383,12 +388,10 @@ const Status = {
}
},
combinedFavsAndRepeatsUsers() {
// Use the status from the global status repository since favs and repeats are saved in it
const combinedUsers = [].concat(
this.mainStatus.favoritedBy,
this.mainStatus.rebloggedBy,
)
return uniqBy(combinedUsers, 'id')
return new Set([
...this.favoritedBy,
...this.repeatedBy,
])
},
tags() {
return [...this.status.tags]
@ -403,7 +406,7 @@ const Status = {
return (
!this.hidePostStats &&
this.focused &&
(this.combinedFavsAndRepeatsUsers.length > 0 ||
(this.combinedFavsAndRepeatsUsers.size > 0 ||
this.mainStatus.quotes_count)
)
},
@ -588,20 +591,18 @@ const Status = {
// refetch repeats when repeat_num is changed in any way
if (
this.focused &&
this.mainStatus.rebloggedBy &&
this.mainStatus.rebloggedBy.length !== num
this.repeatedBy.size !== num
) {
useStatusesStore().fetchRepeats(this.status.id)
useStatusesStore().fetchRepeats(this.mainStatus.id)
}
},
'mainStatus.fave_num': function (num) {
// refetch favs when fave_num is changed in any way
if (
this.focused &&
this.mainStatus.favoritedBy &&
this.mainStatus.favoritedBy.length !== num
this.favoritedBy.size !== num
) {
useStatusesStore().fetchFavs(this.status.id)
useStatusesStore().fetchFavs(this.mainStatus.id)
}
},
isSuspendable: function (suspend) {

View file

@ -464,26 +464,26 @@
>
<div class="stats">
<UserListPopover
v-if="mainStatus.rebloggedBy && mainStatus.rebloggedBy.length > 0"
:users="mainStatus.rebloggedBy"
v-if="repeatedBy.size > 0"
:user-ids="repeatedBy"
>
<div class="stat-count">
<a class="stat-title">{{ $t('status.repeats') }}</a>
<div class="stat-number">
{{ mainStatus.rebloggedBy.length }}
{{ repeatedBy.size }}
</div>
</div>
</UserListPopover>
<UserListPopover
v-if="mainStatus.favoritedBy && mainStatus.favoritedBy.length > 0"
:users="mainStatus.favoritedBy"
v-if="favoritedBy.size > 0"
:user-ids="favoritedBy"
>
<div
class="stat-count"
>
<a class="stat-title">{{ $t('status.favorites') }}</a>
<div class="stat-number">
{{ mainStatus.favoritedBy.length }}
{{ favoritedBy.size }}
</div>
</div>
</UserListPopover>
@ -501,7 +501,7 @@
</div>
</router-link>
<div class="avatar-row">
<AvatarList :users="combinedFavsAndRepeatsUsers" />
<AvatarList :user-ids="combinedFavsAndRepeatsUsers" />
</div>
</div>
</div>

View file

@ -4,6 +4,7 @@ import UserAvatar from 'src/components/user_avatar/user_avatar.vue'
import { useInstanceStore } from 'src/stores/instance.js'
import { useMergedConfigStore } from 'src/stores/merged_config.js'
import { useUsersStore } from 'src/stores/users.js'
import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator'
@ -14,7 +15,9 @@ library.add(faCircleNotch)
const UserListPopover = {
name: 'UserListPopover',
props: ['users'],
props: {
userIds: Set
},
components: {
UnicodeDomainIndicator,
Popover,
@ -22,7 +25,7 @@ const UserListPopover = {
},
computed: {
usersCapped() {
return this.users.slice(0, 16)
return [...this.userIds].slice(0, 16).map((id) => useUsersStore().findUser(id))
},
allowNonSquareEmoji() {
return useMergedConfigStore().mergedConfig.nonSquareEmoji

View file

@ -9,7 +9,7 @@
</template>
<template #content>
<div class="user-list-popover">
<template v-if="users.length">
<template v-if="userIds.size > 0">
<router-link
v-for="(user) in usersCapped"
:key="user.id"

View file

@ -36,6 +36,8 @@ export const defaultState = () => ({
conversations: new Map(),
favorites: new Set(),
socket: null,
favs: new Map(),
repeats: new Map(),
})
export const useStatusesStore = defineStore('statuses', {
@ -189,60 +191,53 @@ export const useStatusesStore = defineStore('statuses', {
id,
credentials: useOAuthStore().token,
}).then(({ data: emojiReactions }) => {
this.addEmojiReactionsBy({
id,
emojiReactions,
})
this.addEmojiReactionsBy(id, emojiReactions)
})
},
fetchFavs(id) {
return fetchFavoritedByUsers({
id,
credentials: useOAuthStore().token,
}).then(({ data: favoritedByUsers }) =>
this.addFavs({
id,
favoritedByUsers,
}),
)
}).then((result) => {
const users = useUsersStore().addNewUsers(result)
return this.addFavs(id, new Set(users.map(({ id }) => id)))
})
},
fetchRepeats(id) {
return fetchRebloggedByUsers({
id,
credentials: useOAuthStore().token,
}).then(({ data: rebloggedByUsers }) =>
this.addRepeats({
id,
rebloggedByUsers,
}),
)
}).then((result) => {
const users = useUsersStore().addNewUsers(result)
return this.addRepeats(id, new Set(users.map(({ id }) => id)))
})
},
fetchFavsAndRepeats(id) {
return Promise.all([this.fetchFavs(id), this.fetchRepeats(id)])
},
// Updates
addRepeats({ id, rebloggedByUsers }) {
addRepeats(id, users) {
const currentUser = useUsersStore().currentUser
const newStatus = this.allStatuses.get(id)
newStatus.rebloggedBy = rebloggedByUsers.filter(Boolean)
// 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.repeated = !!newStatus.rebloggedBy.find(
({ id }) => currentUser?.id === id,
)
this.repeats.set(id, users)
// repeats stats can be incorrect based on polling
// condition, let's update them using the most recent data
newStatus.repeat_num = users.size
newStatus.repeated = users.has(currentUser?.id)
},
addFavs({ id, favoritedByUsers }) {
addFavs(id, users) {
const currentUser = useUsersStore().currentUser
const newStatus = this.allStatuses.get(id)
newStatus.favoritedBy = favoritedByUsers.filter(Boolean)
// 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,
)
this.favs.set(id, users)
// favorites stats can be incorrect based on polling
// condition, let's update them using the most recent data
newStatus.fave_num = users.size
newStatus.favorited = users.has(currentUser?.id)
},
addEmojiReactionsBy({ id, emojiReactions }) {
addEmojiReactionsBy(id, emojiReactions) {
const status = this.allStatuses.get(id)
status.emoji_reactions = emojiReactions
},