Merge branch 'users-statuses-pinia' into weight-removal

This commit is contained in:
Henry Jameson 2026-09-01 17:05:53 +03:00
commit 0b8ca8aeb0
22 changed files with 126 additions and 83 deletions

View file

@ -51,7 +51,7 @@ const chatNew = {
this.$emit('cancel') this.$emit('cancel')
}, },
goToChat(user) { goToChat(user) {
this.$router.push({ name: 'chat', params: { recipient_id: user.id } }) this.$router.push({ name: 'chat', params: { chatUserId: user.id } })
}, },
onInput() { onInput() {
this.search(this.query) this.search(this.query)

View file

@ -622,6 +622,7 @@ const conversation = {
}, },
updateVirtualHeight() { updateVirtualHeight() {
if (this.hide) return // no updates when not rendering if (this.hide) return // no updates when not rendering
if (!this.status) return // not loaded yet
this.$nextTick(() => { this.$nextTick(() => {
this.virtualHeight = this.$refs.body.getBoundingClientRect().height this.virtualHeight = this.$refs.body.getBoundingClientRect().height
this.$emit('update:virtualHeight', { this.$emit('update:virtualHeight', {

View file

@ -15,7 +15,7 @@ const FollowCard = {
}, },
computed: { computed: {
isMe() { isMe() {
return useUsersStore().currentUser.id === this.user.id return useUsersStore().currentUser?.id === this.user.id
}, },
loggedIn() { loggedIn() {
return useUsersStore().currentUser return useUsersStore().currentUser

View file

@ -5,8 +5,8 @@ import Popover from 'src/components/popover/popover.vue'
import { useInterfaceStore } from 'src/stores/interface.js' import { useInterfaceStore } from 'src/stores/interface.js'
import { useLocalConfigStore } from 'src/stores/local_config.js' import { useLocalConfigStore } from 'src/stores/local_config.js'
import { useMergedConfigStore } from 'src/stores/merged_config.js' import { useMergedConfigStore } from 'src/stores/merged_config.js'
import { useStatusesStore } from 'src/stores/statuses.js'
import { useSyncConfigStore } from 'src/stores/sync_config.js' import { useSyncConfigStore } from 'src/stores/sync_config.js'
import { useTimelinesStore } from 'src/stores/timelines.js'
import { useUsersStore } from 'src/stores/users.js' import { useUsersStore } from 'src/stores/users.js'
import { library } from '@fortawesome/fontawesome-svg-core' import { library } from '@fortawesome/fontawesome-svg-core'
@ -28,7 +28,7 @@ const QuickFilterSettings = {
path: 'replyVisibility', path: 'replyVisibility',
value: visibility, value: visibility,
}) })
useStatusesStore().requireReloadAll() useTimelinesStore().requireReloadAll()
}, },
openTab(tab) { openTab(tab) {
useInterfaceStore().openSettingsModalTab(tab) useInterfaceStore().openSettingsModalTab(tab)

View file

@ -221,7 +221,7 @@ const AppearanceTab = {
}, },
computed: { computed: {
isDefaultBackground() { isDefaultBackground() {
return !useUsersStore().currentUser.background_image return !useUsersStore().currentUser?.background_image
}, },
switchInProgress() { switchInProgress() {
return useInterfaceStore().themeChangeInProgress return useInterfaceStore().themeChangeInProgress
@ -283,7 +283,7 @@ const AppearanceTab = {
instanceWallpaperUsed() { instanceWallpaperUsed() {
return ( return (
useInstanceStore().instanceIdentity.background && useInstanceStore().instanceIdentity.background &&
!useUsersStore().currentUser.background_image !useUsersStore().currentUser?.background_image
) )
}, },
customThemeVersion() { customThemeVersion() {

View file

@ -162,9 +162,9 @@
<div class="fun-monitor-display-bezel button-default"> <div class="fun-monitor-display-bezel button-default">
<div class="fun-monitor-display-screen input"> <div class="fun-monitor-display-screen input">
<img <img
v-if="backgroundPreview || user.background_image || instanceWallpaper" v-if="backgroundPreview || user?.background_image || instanceWallpaper"
class="fun-monitor-display-screen-image" class="fun-monitor-display-screen-image"
:src="backgroundPreview || user.background_image || instanceWallpaper" :src="backgroundPreview || user?.background_image || instanceWallpaper"
> >
<div <div
v-else v-else

View file

@ -11,7 +11,7 @@ import UnitSetting from '../helpers/unit_setting.vue'
import { useInstanceStore } from 'src/stores/instance.js' import { useInstanceStore } from 'src/stores/instance.js'
import { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.js' import { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.js'
import { useStatusesStore } from 'src/stores/statuses.js' import { useTimelinesStore } from 'src/stores/timelines.js'
const ClutterTab = { const ClutterTab = {
components: { components: {
@ -36,7 +36,7 @@ const ClutterTab = {
// Updating nested properties // Updating nested properties
watch: { watch: {
replyVisibility() { replyVisibility() {
useStatusesStore().requireReloadAll() useTimelinesStore().requireReloadAll()
}, },
}, },
} }

View file

@ -14,8 +14,8 @@ import UnitSetting from '../helpers/unit_setting.vue'
import { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.js' import { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.js'
import { useInterfaceStore } from 'src/stores/interface' import { useInterfaceStore } from 'src/stores/interface'
import { useMergedConfigStore } from 'src/stores/merged_config.js' import { useMergedConfigStore } from 'src/stores/merged_config.js'
import { useStatusesStore } from 'src/stores/statuses.js'
import { useSyncConfigStore } from 'src/stores/sync_config.js' import { useSyncConfigStore } from 'src/stores/sync_config.js'
import { useTimelinesStore } from 'src/stores/timelines.js'
import { import {
newExporter, newExporter,
@ -266,7 +266,7 @@ const FilteringTab = {
// Updating nested properties // Updating nested properties
watch: { watch: {
replyVisibility() { replyVisibility() {
useStatusesStore().requireReloadAll() useTimelinesStore().requireReloadAll()
}, },
muteFiltersObject() { muteFiltersObject() {
this.muteFiltersDraftObject = cloneDeep( this.muteFiltersDraftObject = cloneDeep(

View file

@ -27,7 +27,7 @@ const GeneralTab = {
value: mode, value: mode,
label: this.$t(`settings.absolute_time_format_12h_${mode}`), label: this.$t(`settings.absolute_time_format_12h_${mode}`),
})), })),
emailLanguage: useUsersStore().currentUser.language || [''], emailLanguage: useUsersStore().currentUser?.language || [''],
} }
}, },
components: { components: {
@ -72,6 +72,9 @@ const GeneralTab = {
useLocalConfigStore().set({ path, value }) useLocalConfigStore().set({ path, value })
}, },
toggleStreaming(value) { toggleStreaming(value) {
// Streaming is not available for the unauthenticated
if (!useOAuthStore().token) return
if (value) { if (value) {
useStreamingStore().initSocket() useStreamingStore().initSocket()
} else { } else {

View file

@ -136,13 +136,30 @@ const Status = {
useScrobblesStore().getLatestScrobble(this.status.user.id) useScrobblesStore().getLatestScrobble(this.status.user.id)
}, },
computed: { computed: {
// Whatever we're given to work with
status() { status() {
return this.statusoid ?? useStatusesStore().allStatuses.get(this.statusId) return this.statusoid ?? useStatusesStore().allStatuses.get(this.statusId)
}, },
// Status repeated
repeatedStatus() { repeatedStatus() {
if (this.status.retweeted_status === undefined) return undefined if (this.status.retweeted_status === undefined) return undefined
return useStatusesStore().allStatuses.get(this.status.retweeted_status.id) return useStatusesStore().allStatuses.get(this.status.retweeted_status.id)
}, },
// THE repeat
repeatStatus() {
if (this.isRepeat) {
return this.status
} else {
return null
}
},
mainStatus() {
if (this.isRepeat) {
return this.repeatedStatus
} else {
return this.status
}
},
repeater() { repeater() {
return useUsersStore().findUser(this.status.user.id) return useUsersStore().findUser(this.status.user.id)
}, },
@ -151,7 +168,7 @@ const Status = {
}, },
showReasonMutedThread() { showReasonMutedThread() {
return ( return (
(this.mainStatus.thread_muted || this.mainSatus.reblog?.thread_muted) && (this.mainStatus.thread_muted || this.repeatStatus?.thread_muted) &&
!this.inConversation !this.inConversation
) )
}, },
@ -217,13 +234,6 @@ const Status = {
this.repeater.screen_name, this.repeater.screen_name,
) )
}, },
mainStatus() {
if (this.isRepeat) {
return this.repeatedStatus
} else {
return this.status
}
},
loggedIn() { loggedIn() {
return !!this.currentUser return !!this.currentUser
}, },

View file

@ -102,7 +102,10 @@ const Timeline = {
} }
}, },
statusesToDisplay() { statusesToDisplay() {
if (!this.virtualScrollingEnabled) return this.visibleStatusIds if (!this.virtualScrollingEnabled) {
return new Set(this.filteredVisibleStatuses.map(({ id }) => id))
}
const amount = this.timeline.visibleStatusIds.size const amount = this.timeline.visibleStatusIds.size
const statusesPerSide = Math.ceil(Math.max(3, window.innerHeight / 80)) const statusesPerSide = Math.ceil(Math.max(3, window.innerHeight / 80))
const min = Math.max(0, this.virtualScrollIndex - statusesPerSide) const min = Math.max(0, this.virtualScrollIndex - statusesPerSide)

View file

@ -68,7 +68,6 @@ const TimelineMenu = {
return '#' + this.$route.params.tag return '#' + this.$route.params.tag
} }
if (route === 'lists-timeline') { if (route === 'lists-timeline') {
console.log(useListsStore, this.$route.params.id)
return useListsStore().findListTitle(this.$route.params.id) return useListsStore().findListTitle(this.$route.params.id)
} }
if (route === 'bookmark-folder') { if (route === 'bookmark-folder') {

View file

@ -238,7 +238,7 @@ export default {
return useUsersStore().relationship(this.userId) return useUsersStore().relationship(this.userId)
}, },
isOtherUser() { isOtherUser() {
return this.user.id !== useUsersStore().currentUser.id return this.user.id !== useUsersStore().currentUser?.id
}, },
subscribeUrl() { subscribeUrl() {
const serverUrl = new URL(this.user.statusnet_profile_url) const serverUrl = new URL(this.user.statusnet_profile_url)

View file

@ -24,10 +24,13 @@ const UserListPopover = {
UserAvatar, UserAvatar,
}, },
computed: { computed: {
usersCapped() { users() {
return [...this.userIds] return [...this.userIds]
.slice(0, 16)
.map((id) => useUsersStore().findUser(id)) .map((id) => useUsersStore().findUser(id))
.filter(Boolean)
},
usersCapped() {
return [...this.users].slice(0, 16)
}, },
allowNonSquareEmoji() { allowNonSquareEmoji() {
return useMergedConfigStore().mergedConfig.nonSquareEmoji return useMergedConfigStore().mergedConfig.nonSquareEmoji

View file

@ -1634,7 +1634,6 @@
"no_statuses": "No statuses", "no_statuses": "No statuses",
"socket_reconnected": "Realtime connection established", "socket_reconnected": "Realtime connection established",
"socket_disconnected": "Realtime connection unavaialable", "socket_disconnected": "Realtime connection unavaialable",
"socket_closed": "Realtime connection closed",
"socket_broke": "Realtime connection lost: CloseEvent code {0}", "socket_broke": "Realtime connection lost: CloseEvent code {0}",
"quick_view_settings": "Quick view settings", "quick_view_settings": "Quick view settings",
"quick_filter_settings": "Quick filter settings", "quick_filter_settings": "Quick filter settings",

View file

@ -385,10 +385,13 @@ export const parseLinkHeaderPagination = (linkHeader, opts = {}) => {
const maxId = parsedLinkHeader.next?.max_id const maxId = parsedLinkHeader.next?.max_id
const minId = parsedLinkHeader.prev?.min_id const minId = parsedLinkHeader.prev?.min_id
return { const result = {}
maxId: flakeId ? maxId : Number.parseInt(maxId, 10), if (maxId !== undefined)
minId: flakeId ? minId : Number.parseInt(minId, 10), result.maxId = flakeId ? maxId : Number.parseInt(maxId, 10)
} if (minId !== undefined)
result.minId = flakeId ? minId : Number.parseInt(minId, 10)
return result
} }
export const parseChat = (chat) => { export const parseChat = (chat) => {

View file

@ -36,7 +36,7 @@ const notificationsFetcher = (credentials) => {
const notifications = response.data const notifications = response.data
if (older && notifications.length === 0) bottomedOut.value = true if (older && notifications.length === 0) bottomedOut.value = true
useNotificationsStore().addNewNotifications(response) useNotificationsStore().addNewNotifications(response, older)
} catch (error) { } catch (error) {
if ( if (
error.statusCode === 400 && error.statusCode === 400 &&
@ -78,16 +78,13 @@ const notificationsFetcher = (credentials) => {
args.timeline = 'notifications' args.timeline = 'notifications'
if (older) { if (older) {
if (timelineData.minId !== Number.POSITIVE_INFINITY) { if (timelineData.minId !== '') {
args.maxId = timelineData.minId args.maxId = timelineData.minId
} }
return await fetchNotifications({ args, older }) return await fetchNotifications({ args, older })
} else { } else {
// fetch new notifications // fetch new notifications
if ( if (sinceId === undefined && timelineData.maxId !== '') {
sinceId === undefined &&
timelineData.maxId !== Number.POSITIVE_INFINITY
) {
args.sinceId = timelineData.maxId args.sinceId = timelineData.maxId
} else if (sinceId !== null) { } else if (sinceId !== null) {
args.sinceId = sinceId args.sinceId = sinceId

View file

@ -52,7 +52,11 @@ const timelineFetcher = (timeline, argument, credentials) => {
const numStatusesBeforeFetch = timeline.statusIds.size const numStatusesBeforeFetch = timeline.statusIds.size
if (older && bottomedOut.value) return if (older && bottomedOut.value) {
loadingOlder.value = false
return
}
return fetchTimeline(args) return fetchTimeline(args)
.then(({ data, pagination, timestamp }) => { .then(({ data, pagination, timestamp }) => {
// No statuses for timeline, ever. // No statuses for timeline, ever.
@ -135,6 +139,9 @@ const timelineFetcher = (timeline, argument, credentials) => {
loadingOlder, loadingOlder,
loadingNewer, loadingNewer,
bottomedOut, bottomedOut,
resetBottomedOut: () => {
bottomedOut.value = false
},
} }
} }

View file

@ -134,14 +134,7 @@ export const useInterfaceStore = defineStore('interface', {
1001, // Going away 1001, // Going away
]) ])
const { code } = closeEvent.original const { code } = closeEvent.original
if (intendedCodes.has(code)) { if (!intendedCodes.has(code)) {
this.pushGlobalNotice({
level: 'success',
messageKey: 'timeline.socket_closed',
messageArgs: [code],
timeout: 5000,
})
} else {
this.pushGlobalNotice({ this.pushGlobalNotice({
level: 'error', level: 'error',
messageKey: 'timeline.socket_broke', messageKey: 'timeline.socket_broke',

View file

@ -108,6 +108,8 @@ export const useStreamingStore = defineStore('streaming', {
} }
}, },
initSocket(initial) { initSocket(initial) {
if (this.socket) throw new Error('Socket already exists!')
this.state = initial this.state = initial
? WSConnectionStatus.STARTING_INITIAL ? WSConnectionStatus.STARTING_INITIAL
: WSConnectionStatus.STARTING : WSConnectionStatus.STARTING
@ -129,7 +131,11 @@ export const useStreamingStore = defineStore('streaming', {
}, },
stopSocket() { stopSocket() {
this.socket.close() this.socket.close()
this.socket = null
this.state = WSConnectionStatus.CLOSED this.state = WSConnectionStatus.CLOSED
this.retrying = false
this.retryMultiplier = 1
this.error = null
}, },
getSubArgs(stream) { getSubArgs(stream) {
@ -229,6 +235,8 @@ export const useStreamingStore = defineStore('streaming', {
) )
setTimeout(() => { setTimeout(() => {
if (this.retrying) return // retry aborted (i.e. due to logout)
this.initSocket() this.initSocket()
}, retryTimeout(this.retryMultiplier)) }, retryTimeout(this.retryMultiplier))

View file

@ -81,6 +81,7 @@ export const ARGUMENT_MAP = {
user: 'userId', user: 'userId',
userPinned: 'userId', userPinned: 'userId',
media: 'userId', media: 'userId',
favorites: 'userId',
} }
const TIMELINES = new Set([ const TIMELINES = new Set([
@ -180,7 +181,7 @@ export const useTimelinesStore = defineStore('timelines', {
timeline.socket.handlers timeline.socket.handlers
timeline.socket.et.removeEventListener('open', openHandler) timeline.socket.et.removeEventListener('open', openHandler)
timeline.socket.et.removeEventListener('close', closeHandler) timeline.socket.et.removeEventListener('close', closeHandler)
timeline.socket.et.removeEventListener('message', messageHandler) timeline.socket.et.removeEventListener('update', messageHandler)
} }
this[timelineName] = emptyTl(timelineName) this[timelineName] = emptyTl(timelineName)
@ -196,6 +197,7 @@ export const useTimelinesStore = defineStore('timelines', {
timeline.maxId = '' timeline.maxId = ''
timeline.minId = '' timeline.minId = ''
timeline.reloadNeeded = false timeline.reloadNeeded = false
timeline.fetcher.resetBottomedOut()
}, },
activatePersistents() { activatePersistents() {
TIMELINES.forEach((name) => { TIMELINES.forEach((name) => {
@ -266,8 +268,6 @@ export const useTimelinesStore = defineStore('timelines', {
if (statuses.length === 0) return if (statuses.length === 0) return
const timeline = this[timelineName] const timeline = this[timelineName]
this.populateRepeats(timeline, repeats)
// This makes sure that user timeline won't get data meant for other // This makes sure that user timeline won't get data meant for other
// user. I.e. opening different user profiles makes request which could // user. I.e. opening different user profiles makes request which could
// return data late after user already viewing different user profile // return data late after user already viewing different user profile
@ -278,9 +278,7 @@ export const useTimelinesStore = defineStore('timelines', {
return return
} }
if (!noIdUpdate) { this.populateRepeats(timeline, repeats)
this.updateTimelineExtremes(timeline, pagination)
}
const filtered = statuses.filter((id) => !timeline.statusIds.has(id)) const filtered = statuses.filter((id) => !timeline.statusIds.has(id))
if (older) { if (older) {
@ -289,26 +287,36 @@ export const useTimelinesStore = defineStore('timelines', {
timeline.order.unshift(...filtered) timeline.order.unshift(...filtered)
} }
const newStatuses = new Set()
statuses.forEach((statusId) => { statuses.forEach((statusId) => {
const isNew = !timeline.statusIds.has(statusId) const isNew = !timeline.statusIds.has(statusId)
timeline.statusIds.add(statusId) timeline.statusIds.add(statusId)
if (isNew) { if (isNew) {
const seenBefore = this.checkSeenBefore(timeline, statusId) newStatuses.add(statusId)
if (!seenBefore) {
if (showImmediately) {
// Add it directly to the visibleStatuses, don't change
// newStatusCount
timeline.visibleStatusIds.add(statusId)
} else {
// Just change newStatuscount
timeline.newStatusCount += 1
}
} else {
timeline.ignoredIds.add(statusId)
}
} }
}) })
newStatuses.forEach((statusId) => {
const seenBefore = this.checkSeenBefore(timeline, statusId)
if (!seenBefore) {
if (showImmediately) {
// Add it directly to the visibleStatuses, don't change
// newStatusCount
timeline.visibleStatusIds.add(statusId)
} else {
// Just change newStatuscount
timeline.newStatusCount += 1
}
} else {
timeline.ignoredIds.add(statusId)
}
})
if (!noIdUpdate) {
this.updateTimelineExtremes(timeline, pagination)
}
}, },
onStreamMessage(timelineName, argument, event) { onStreamMessage(timelineName, argument, event) {
this.addStatusesToTimeline(timelineName, argument, { this.addStatusesToTimeline(timelineName, argument, {
@ -347,7 +355,7 @@ export const useTimelinesStore = defineStore('timelines', {
// If it's the only reprööt then we've never seen post before // If it's the only reprööt then we've never seen post before
if (knownRepeats.size === 1) return false if (knownRepeats.size === 1) return false
// If we're working on oldest known reprööt then we've never seen it before // If we're working on oldest known reprööt then we've never seen it before
return first(knownRepeats) !== statusId return knownRepeats.values().next().value !== statusId
}, },
// Poll & Push // Poll & Push
@ -414,7 +422,7 @@ export const useTimelinesStore = defineStore('timelines', {
}, },
// Queues & Timeline manip // Queues & Timeline manip
updateTimelineExtremes(timeline, pagination = {}) { updateTimelineExtremes(timeline, pagination = {}, force = false) {
// Can't use Math.min/max because it doesn't work with string (duh) // Can't use Math.min/max because it doesn't work with string (duh)
const minNew = pagination.maxId ?? last(timeline.order) ?? '' const minNew = pagination.maxId ?? last(timeline.order) ?? ''
const maxNew = pagination.minId ?? first(timeline.order) ?? '' const maxNew = pagination.minId ?? first(timeline.order) ?? ''
@ -422,10 +430,10 @@ export const useTimelinesStore = defineStore('timelines', {
const newer = maxNew > timeline.maxId const newer = maxNew > timeline.maxId
const older = minNew < timeline.minId const older = minNew < timeline.minId
if (newer || timeline.maxId === '') { if (force || newer || timeline.maxId === '') {
timeline.maxId = maxNew timeline.maxId = maxNew
} }
if (older || timeline.minId === '') { if (force || older || timeline.minId === '') {
timeline.minId = minNew timeline.minId = minNew
} }
@ -442,7 +450,8 @@ export const useTimelinesStore = defineStore('timelines', {
timeline.visibleStatusIds = new Set([ timeline.visibleStatusIds = new Set([
...timeline.order.filter((id) => !timeline.ignoredIds.has(id)), ...timeline.order.filter((id) => !timeline.ignoredIds.has(id)),
]) ])
this.updateTimelineExtremes(timeline) this.updateTimelineExtremes(timeline, {}, true)
timeline.fetcher.resetBottomedOut()
}, },
syncOrder(timeline) { syncOrder(timeline) {
timeline.order = timeline.order.filter((id) => timeline.statusIds.has(id)) timeline.order = timeline.order.filter((id) => timeline.statusIds.has(id))
@ -451,8 +460,10 @@ export const useTimelinesStore = defineStore('timelines', {
this[timeline].reloadNeeded = true this[timeline].reloadNeeded = true
}, },
requireReloadAll() { requireReloadAll() {
Object.keys(this).forEach((timeline) => { TIMELINES.forEach((timelineName) => {
this[timeline].reloadNeeded = true const timeline = this[timelineName]
timeline.reloadNeeded = true
}) })
}, },

View file

@ -278,15 +278,21 @@ export const useUsersStore = defineStore('users', {
const result = await promise const result = await promise
if (result) { try {
const { id, screen_name } = result if (result) {
const { id, screen_name } = result
// Save promise for future use // Save promise for future use
this.fetchesIds.set(id, promise) this.fetchesIds.set(id, promise)
this.fetchesNames.set(screen_name, promise) this.fetchesNames.set(screen_name, promise)
return this.users.get(id) return this.users.get(id)
} else { } else {
return null return null
}
} catch (e) {
console.error(`Failed fetching user ${identifier}`, e)
map.delete(identifier)
throw e
} }
}, },
async fetchUser(id) { async fetchUser(id) {
@ -520,7 +526,7 @@ export const useUsersStore = defineStore('users', {
/// Mute /// Mute
muteUser(id, expiresIn = 0) { muteUser(id, expiresIn = 0) {
const predictedRelationship = this.relationships[id] || { id } const predictedRelationship = this.relationships.get(id) || { id }
predictedRelationship.muting = true predictedRelationship.muting = true
this.updateUserRelationships({ this.updateUserRelationships({
optimism: true, optimism: true,
@ -539,7 +545,7 @@ export const useUsersStore = defineStore('users', {
return Promise.all(data.map((d) => this.muteUser(d))) return Promise.all(data.map((d) => this.muteUser(d)))
}, },
unmuteUser(id) { unmuteUser(id) {
const predictedRelationship = this.relationships[id] || { id } const predictedRelationship = this.relationships.get(id) || { id }
predictedRelationship.muting = false predictedRelationship.muting = false
this.updateUserRelationships({ this.updateUserRelationships({
optimism: true, optimism: true,
@ -556,7 +562,7 @@ export const useUsersStore = defineStore('users', {
/// Block /// Block
blockUser(id, expiresIn = 0) { blockUser(id, expiresIn = 0) {
const predictedRelationship = this.relationships[id] || { id } const predictedRelationship = this.relationships.get(id) || { id }
this.updateUserRelationships({ this.updateUserRelationships({
optimism: true, optimism: true,
data: [predictedRelationship], data: [predictedRelationship],