logo

pleroma-fe

My custom branche(s) on git.pleroma.social/pleroma/pleroma-fe git clone https://hacktivis.me/git/pleroma-fe.git

statuses.js (22659B)


  1. import {
  2. remove,
  3. slice,
  4. each,
  5. findIndex,
  6. find,
  7. maxBy,
  8. minBy,
  9. merge,
  10. first,
  11. last,
  12. isArray,
  13. omitBy
  14. } from 'lodash'
  15. import apiService from '../services/api/api.service.js'
  16. const emptyTl = (userId = 0) => ({
  17. statuses: [],
  18. statusesObject: {},
  19. faves: [],
  20. visibleStatuses: [],
  21. visibleStatusesObject: {},
  22. newStatusCount: 0,
  23. maxId: 0,
  24. minId: 0,
  25. minVisibleId: 0,
  26. loading: false,
  27. followers: [],
  28. friends: [],
  29. userId,
  30. flushMarker: 0
  31. })
  32. export const defaultState = () => ({
  33. allStatuses: [],
  34. allStatusesObject: {},
  35. conversationsObject: {},
  36. maxId: 0,
  37. favorites: new Set(),
  38. timelines: {
  39. mentions: emptyTl(),
  40. public: emptyTl(),
  41. user: emptyTl(),
  42. favorites: emptyTl(),
  43. media: emptyTl(),
  44. publicAndExternal: emptyTl(),
  45. friends: emptyTl(),
  46. tag: emptyTl(),
  47. dms: emptyTl(),
  48. bookmarks: emptyTl(),
  49. list: emptyTl()
  50. }
  51. })
  52. export const prepareStatus = (status) => {
  53. // Set deleted flag
  54. status.deleted = false
  55. // To make the array reactive
  56. status.attachments = status.attachments || []
  57. return status
  58. }
  59. const mergeOrAdd = (arr, obj, item) => {
  60. const oldItem = obj[item.id]
  61. if (oldItem) {
  62. // We already have this, so only merge the new info.
  63. // We ignore null values to avoid overwriting existing properties with missing data
  64. // we also skip 'user' because that is handled by users module
  65. merge(oldItem, omitBy(item, (v, k) => v === null || k === 'user'))
  66. // Reactivity fix.
  67. oldItem.attachments.splice(oldItem.attachments.length)
  68. return { item: oldItem, new: false }
  69. } else {
  70. // This is a new item, prepare it
  71. prepareStatus(item)
  72. arr.push(item)
  73. obj[item.id] = item
  74. return { item, new: true }
  75. }
  76. }
  77. const sortById = (a, b) => {
  78. const seqA = Number(a.id)
  79. const seqB = Number(b.id)
  80. const isSeqA = !Number.isNaN(seqA)
  81. const isSeqB = !Number.isNaN(seqB)
  82. if (isSeqA && isSeqB) {
  83. return seqA > seqB ? -1 : 1
  84. } else if (isSeqA && !isSeqB) {
  85. return 1
  86. } else if (!isSeqA && isSeqB) {
  87. return -1
  88. } else {
  89. return a.id > b.id ? -1 : 1
  90. }
  91. }
  92. const sortTimeline = (timeline) => {
  93. timeline.visibleStatuses = timeline.visibleStatuses.sort(sortById)
  94. timeline.statuses = timeline.statuses.sort(sortById)
  95. timeline.minVisibleId = (last(timeline.visibleStatuses) || {}).id
  96. return timeline
  97. }
  98. // Add status to the global storages (arrays and objects maintaining statuses) except timelines
  99. const addStatusToGlobalStorage = (state, data) => {
  100. const result = mergeOrAdd(state.allStatuses, state.allStatusesObject, data)
  101. if (result.new) {
  102. // Add to conversation
  103. const status = result.item
  104. const conversationsObject = state.conversationsObject
  105. const conversationId = status.statusnet_conversation_id
  106. if (conversationsObject[conversationId]) {
  107. conversationsObject[conversationId].push(status)
  108. } else {
  109. conversationsObject[conversationId] = [status]
  110. }
  111. }
  112. return result
  113. }
  114. const addNewStatuses = (state, { statuses, showImmediately = false, timeline, user = {}, noIdUpdate = false, userId, pagination = {} }) => {
  115. // Sanity check
  116. if (!isArray(statuses)) {
  117. return false
  118. }
  119. const allStatuses = state.allStatuses
  120. const timelineObject = state.timelines[timeline]
  121. // Mismatch between API pagination and our internal minId/maxId tracking systems:
  122. // pagination.maxId is the oldest of the returned statuses when fetching older,
  123. // and pagination.minId is the newest when fetching newer. The names come directly
  124. // from the arguments they're supposed to be passed as for the next fetch.
  125. const minNew = pagination.maxId || (statuses.length > 0 ? minBy(statuses, 'id').id : 0)
  126. const maxNew = pagination.minId || (statuses.length > 0 ? maxBy(statuses, 'id').id : 0)
  127. const newer = timeline && (maxNew > timelineObject.maxId || timelineObject.maxId === 0) && statuses.length > 0
  128. const older = timeline && (minNew < timelineObject.minId || timelineObject.minId === 0) && statuses.length > 0
  129. if (!noIdUpdate && newer) {
  130. timelineObject.maxId = maxNew
  131. }
  132. if (!noIdUpdate && older) {
  133. timelineObject.minId = minNew
  134. }
  135. // This makes sure that user timeline won't get data meant for other
  136. // user. I.e. opening different user profiles makes request which could
  137. // return data late after user already viewing different user profile
  138. if ((timeline === 'user' || timeline === 'media') && timelineObject.userId !== userId) {
  139. return
  140. }
  141. const addStatus = (data, showImmediately, addToTimeline = true) => {
  142. const result = addStatusToGlobalStorage(state, data)
  143. const status = result.item
  144. if (result.new) {
  145. // We are mentioned in a post
  146. if (status.type === 'status' && find(status.attentions, { id: user.id })) {
  147. const mentions = state.timelines.mentions
  148. // Add the mention to the mentions timeline
  149. if (timelineObject !== mentions) {
  150. mergeOrAdd(mentions.statuses, mentions.statusesObject, status)
  151. mentions.newStatusCount += 1
  152. sortTimeline(mentions)
  153. }
  154. }
  155. if (status.visibility === 'direct') {
  156. const dms = state.timelines.dms
  157. mergeOrAdd(dms.statuses, dms.statusesObject, status)
  158. dms.newStatusCount += 1
  159. sortTimeline(dms)
  160. }
  161. }
  162. // Decide if we should treat the status as new for this timeline.
  163. let resultForCurrentTimeline
  164. // Some statuses should only be added to the global status repository.
  165. if (timeline && addToTimeline) {
  166. resultForCurrentTimeline = mergeOrAdd(timelineObject.statuses, timelineObject.statusesObject, status)
  167. }
  168. if (timeline && showImmediately) {
  169. // Add it directly to the visibleStatuses, don't change
  170. // newStatusCount
  171. mergeOrAdd(timelineObject.visibleStatuses, timelineObject.visibleStatusesObject, status)
  172. } else if (timeline && addToTimeline && resultForCurrentTimeline.new) {
  173. // Just change newStatuscount
  174. timelineObject.newStatusCount += 1
  175. }
  176. if (status.quote) {
  177. addStatus(status.quote, /* showImmediately = */ false, /* addToTimeline = */ false)
  178. }
  179. return status
  180. }
  181. const favoriteStatus = (favorite, counter) => {
  182. const status = find(allStatuses, { id: favorite.in_reply_to_status_id })
  183. if (status) {
  184. // This is our favorite, so the relevant bit.
  185. if (favorite.user.id === user.id) {
  186. status.favorited = true
  187. } else {
  188. status.fave_num += 1
  189. }
  190. }
  191. return status
  192. }
  193. const processors = {
  194. status: (status) => {
  195. addStatus(status, showImmediately)
  196. },
  197. edit: (status) => {
  198. addStatus(status, showImmediately)
  199. },
  200. retweet: (status) => {
  201. // RetweetedStatuses are never shown immediately
  202. const retweetedStatus = addStatus(status.retweeted_status, false, false)
  203. let retweet
  204. // If the retweeted status is already there, don't add the retweet
  205. // to the timeline.
  206. if (timeline && find(timelineObject.statuses, (s) => {
  207. if (s.retweeted_status) {
  208. return s.id === retweetedStatus.id || s.retweeted_status.id === retweetedStatus.id
  209. } else {
  210. return s.id === retweetedStatus.id
  211. }
  212. })) {
  213. // Already have it visible (either as the original or another RT), don't add to timeline, don't show.
  214. retweet = addStatus(status, false, false)
  215. } else {
  216. retweet = addStatus(status, showImmediately)
  217. }
  218. retweet.retweeted_status = retweetedStatus
  219. },
  220. favorite: (favorite) => {
  221. // Only update if this is a new favorite.
  222. // Ignore our own favorites because we get info about likes as response to like request
  223. if (!state.favorites.has(favorite.id)) {
  224. state.favorites.add(favorite.id)
  225. favoriteStatus(favorite)
  226. }
  227. },
  228. follow: (follow) => {
  229. // NOOP, it is known status but we don't do anything about it for now
  230. },
  231. default: (unknown) => {
  232. console.log('unknown status type')
  233. console.log(unknown)
  234. }
  235. }
  236. each(statuses, (status) => {
  237. const type = status.type
  238. const processor = processors[type] || processors.default
  239. processor(status)
  240. })
  241. // Keep the visible statuses sorted
  242. if (timeline && !(timeline === 'bookmarks')) {
  243. sortTimeline(timelineObject)
  244. }
  245. }
  246. const removeStatus = (state, { timeline, userId }) => {
  247. const timelineObject = state.timelines[timeline]
  248. if (userId) {
  249. remove(timelineObject.statuses, { user: { id: userId } })
  250. remove(timelineObject.visibleStatuses, { user: { id: userId } })
  251. timelineObject.minVisibleId = timelineObject.visibleStatuses.length > 0 ? last(timelineObject.visibleStatuses).id : 0
  252. timelineObject.maxId = timelineObject.statuses.length > 0 ? first(timelineObject.statuses).id : 0
  253. }
  254. }
  255. export const mutations = {
  256. addNewStatuses,
  257. removeStatus,
  258. showNewStatuses (state, { timeline }) {
  259. const oldTimeline = (state.timelines[timeline])
  260. oldTimeline.newStatusCount = 0
  261. oldTimeline.visibleStatuses = slice(oldTimeline.statuses, 0, 50)
  262. oldTimeline.minVisibleId = last(oldTimeline.visibleStatuses).id
  263. oldTimeline.minId = oldTimeline.minVisibleId
  264. oldTimeline.visibleStatusesObject = {}
  265. each(oldTimeline.visibleStatuses, (status) => { oldTimeline.visibleStatusesObject[status.id] = status })
  266. },
  267. resetStatuses (state) {
  268. const emptyState = defaultState()
  269. Object.entries(emptyState).forEach(([key, value]) => {
  270. state[key] = value
  271. })
  272. },
  273. clearTimeline (state, { timeline, excludeUserId = false }) {
  274. const userId = excludeUserId ? state.timelines[timeline].userId : undefined
  275. state.timelines[timeline] = emptyTl(userId)
  276. },
  277. setFavorited (state, { status, value }) {
  278. const newStatus = state.allStatusesObject[status.id]
  279. if (newStatus.favorited !== value) {
  280. if (value) {
  281. newStatus.fave_num++
  282. } else {
  283. newStatus.fave_num--
  284. }
  285. }
  286. newStatus.favorited = value
  287. },
  288. setFavoritedConfirm (state, { status, user }) {
  289. const newStatus = state.allStatusesObject[status.id]
  290. newStatus.favorited = status.favorited
  291. newStatus.fave_num = status.fave_num
  292. const index = findIndex(newStatus.favoritedBy, { id: user.id })
  293. if (index !== -1 && !newStatus.favorited) {
  294. newStatus.favoritedBy.splice(index, 1)
  295. } else if (index === -1 && newStatus.favorited) {
  296. newStatus.favoritedBy.push(user)
  297. }
  298. },
  299. setMutedStatus (state, status) {
  300. const newStatus = state.allStatusesObject[status.id]
  301. newStatus.thread_muted = status.thread_muted
  302. if (newStatus.thread_muted !== undefined) {
  303. state.conversationsObject[newStatus.statusnet_conversation_id].forEach(status => { status.thread_muted = newStatus.thread_muted })
  304. }
  305. },
  306. setRetweeted (state, { status, value }) {
  307. const newStatus = state.allStatusesObject[status.id]
  308. if (newStatus.repeated !== value) {
  309. if (value) {
  310. newStatus.repeat_num++
  311. } else {
  312. newStatus.repeat_num--
  313. }
  314. }
  315. newStatus.repeated = value
  316. },
  317. setRetweetedConfirm (state, { status, user }) {
  318. const newStatus = state.allStatusesObject[status.id]
  319. newStatus.repeated = status.repeated
  320. newStatus.repeat_num = status.repeat_num
  321. const index = findIndex(newStatus.rebloggedBy, { id: user.id })
  322. if (index !== -1 && !newStatus.repeated) {
  323. newStatus.rebloggedBy.splice(index, 1)
  324. } else if (index === -1 && newStatus.repeated) {
  325. newStatus.rebloggedBy.push(user)
  326. }
  327. },
  328. setBookmarked (state, { status, value }) {
  329. const newStatus = state.allStatusesObject[status.id]
  330. newStatus.bookmarked = value
  331. },
  332. setBookmarkedConfirm (state, { status }) {
  333. const newStatus = state.allStatusesObject[status.id]
  334. newStatus.bookmarked = status.bookmarked
  335. },
  336. setDeleted (state, { status }) {
  337. const newStatus = state.allStatusesObject[status.id]
  338. if (newStatus) newStatus.deleted = true
  339. },
  340. setManyDeleted (state, condition) {
  341. Object.values(state.allStatusesObject).forEach(status => {
  342. if (condition(status)) {
  343. status.deleted = true
  344. }
  345. })
  346. },
  347. setLoading (state, { timeline, value }) {
  348. state.timelines[timeline].loading = value
  349. },
  350. setNsfw (state, { id, nsfw }) {
  351. const newStatus = state.allStatusesObject[id]
  352. newStatus.nsfw = nsfw
  353. },
  354. queueFlush (state, { timeline, id }) {
  355. state.timelines[timeline].flushMarker = id
  356. },
  357. queueFlushAll (state) {
  358. Object.keys(state.timelines).forEach((timeline) => {
  359. state.timelines[timeline].flushMarker = state.timelines[timeline].maxId
  360. })
  361. },
  362. addRepeats (state, { id, rebloggedByUsers, currentUser }) {
  363. const newStatus = state.allStatusesObject[id]
  364. newStatus.rebloggedBy = rebloggedByUsers.filter(_ => _)
  365. // repeats stats can be incorrect based on polling condition, let's update them using the most recent data
  366. newStatus.repeat_num = newStatus.rebloggedBy.length
  367. newStatus.repeated = !!newStatus.rebloggedBy.find(({ id }) => currentUser.id === id)
  368. },
  369. addFavs (state, { id, favoritedByUsers, currentUser }) {
  370. const newStatus = state.allStatusesObject[id]
  371. newStatus.favoritedBy = favoritedByUsers.filter(_ => _)
  372. // favorites stats can be incorrect based on polling condition, let's update them using the most recent data
  373. newStatus.fave_num = newStatus.favoritedBy.length
  374. newStatus.favorited = !!newStatus.favoritedBy.find(({ id }) => currentUser.id === id)
  375. },
  376. addEmojiReactionsBy (state, { id, emojiReactions, currentUser }) {
  377. const status = state.allStatusesObject[id]
  378. status.emoji_reactions = emojiReactions
  379. },
  380. addOwnReaction (state, { id, emoji, currentUser }) {
  381. const status = state.allStatusesObject[id]
  382. const reactionIndex = findIndex(status.emoji_reactions, { name: emoji })
  383. const reaction = status.emoji_reactions[reactionIndex] || { name: emoji, count: 0, accounts: [] }
  384. const newReaction = {
  385. ...reaction,
  386. count: reaction.count + 1,
  387. me: true,
  388. accounts: [
  389. ...reaction.accounts,
  390. currentUser
  391. ]
  392. }
  393. // Update count of existing reaction if it exists, otherwise append at the end
  394. if (reactionIndex >= 0) {
  395. status.emoji_reactions[reactionIndex] = newReaction
  396. } else {
  397. status.emoji_reactions = [...status.emoji_reactions, newReaction]
  398. }
  399. },
  400. removeOwnReaction (state, { id, emoji, currentUser }) {
  401. const status = state.allStatusesObject[id]
  402. const reactionIndex = findIndex(status.emoji_reactions, { name: emoji })
  403. if (reactionIndex < 0) return
  404. const reaction = status.emoji_reactions[reactionIndex]
  405. const accounts = reaction.accounts || []
  406. const newReaction = {
  407. ...reaction,
  408. count: reaction.count - 1,
  409. me: false,
  410. accounts: accounts.filter(acc => acc.id !== currentUser.id)
  411. }
  412. if (newReaction.count > 0) {
  413. status.emoji_reactions[reactionIndex] = newReaction
  414. } else {
  415. status.emoji_reactions = status.emoji_reactions.filter(r => r.name !== emoji)
  416. }
  417. },
  418. updateStatusWithPoll (state, { id, poll }) {
  419. const status = state.allStatusesObject[id]
  420. status.poll = poll
  421. },
  422. setVirtualHeight (state, { statusId, height }) {
  423. state.allStatusesObject[statusId].virtualHeight = height
  424. }
  425. }
  426. const statuses = {
  427. state: defaultState(),
  428. actions: {
  429. addNewStatuses ({ rootState, commit, dispatch, state }, { statuses, showImmediately = false, timeline = false, noIdUpdate = false, userId, pagination }) {
  430. commit('addNewStatuses', { statuses, showImmediately, timeline, noIdUpdate, user: rootState.users.currentUser, userId, pagination })
  431. },
  432. fetchStatus ({ rootState, dispatch }, id) {
  433. return rootState.api.backendInteractor.fetchStatus({ id })
  434. .then((status) => dispatch('addNewStatuses', { statuses: [status] }))
  435. },
  436. fetchStatusSource ({ rootState, dispatch }, status) {
  437. return apiService.fetchStatusSource({ id: status.id, credentials: rootState.users.currentUser.credentials })
  438. },
  439. fetchStatusHistory ({ rootState, dispatch }, status) {
  440. return apiService.fetchStatusHistory({ status })
  441. },
  442. deleteStatus ({ rootState, commit, dispatch }, status) {
  443. apiService.deleteStatus({ id: status.id, credentials: rootState.users.currentUser.credentials })
  444. .then((_) => {
  445. commit('setDeleted', { status })
  446. })
  447. .catch((e) => {
  448. dispatch('pushGlobalNotice', {
  449. level: 'error',
  450. messageKey: 'status.delete_error',
  451. messageArgs: [e.message],
  452. timeout: 5000
  453. })
  454. })
  455. },
  456. deleteStatusById ({ rootState, commit }, id) {
  457. const status = rootState.statuses.allStatusesObject[id]
  458. commit('setDeleted', { status })
  459. },
  460. markStatusesAsDeleted ({ commit }, condition) {
  461. commit('setManyDeleted', condition)
  462. },
  463. favorite ({ rootState, commit }, status) {
  464. // Optimistic favoriting...
  465. commit('setFavorited', { status, value: true })
  466. rootState.api.backendInteractor.favorite({ id: status.id })
  467. .then(status => commit('setFavoritedConfirm', { status, user: rootState.users.currentUser }))
  468. },
  469. unfavorite ({ rootState, commit }, status) {
  470. // Optimistic unfavoriting...
  471. commit('setFavorited', { status, value: false })
  472. rootState.api.backendInteractor.unfavorite({ id: status.id })
  473. .then(status => commit('setFavoritedConfirm', { status, user: rootState.users.currentUser }))
  474. },
  475. fetchPinnedStatuses ({ rootState, dispatch }, userId) {
  476. rootState.api.backendInteractor.fetchPinnedStatuses({ id: userId })
  477. .then(statuses => dispatch('addNewStatuses', { statuses, timeline: 'user', userId, showImmediately: true, noIdUpdate: true }))
  478. },
  479. pinStatus ({ rootState, dispatch }, statusId) {
  480. return rootState.api.backendInteractor.pinOwnStatus({ id: statusId })
  481. .then((status) => dispatch('addNewStatuses', { statuses: [status] }))
  482. },
  483. unpinStatus ({ rootState, dispatch }, statusId) {
  484. rootState.api.backendInteractor.unpinOwnStatus({ id: statusId })
  485. .then((status) => dispatch('addNewStatuses', { statuses: [status] }))
  486. },
  487. muteConversation ({ rootState, commit }, statusId) {
  488. return rootState.api.backendInteractor.muteConversation({ id: statusId })
  489. .then((status) => commit('setMutedStatus', status))
  490. },
  491. unmuteConversation ({ rootState, commit }, statusId) {
  492. return rootState.api.backendInteractor.unmuteConversation({ id: statusId })
  493. .then((status) => commit('setMutedStatus', status))
  494. },
  495. retweet ({ rootState, commit }, status) {
  496. // Optimistic retweeting...
  497. commit('setRetweeted', { status, value: true })
  498. rootState.api.backendInteractor.retweet({ id: status.id })
  499. .then(status => commit('setRetweetedConfirm', { status: status.retweeted_status, user: rootState.users.currentUser }))
  500. },
  501. unretweet ({ rootState, commit }, status) {
  502. // Optimistic unretweeting...
  503. commit('setRetweeted', { status, value: false })
  504. rootState.api.backendInteractor.unretweet({ id: status.id })
  505. .then(status => commit('setRetweetedConfirm', { status, user: rootState.users.currentUser }))
  506. },
  507. bookmark ({ rootState, commit }, status) {
  508. commit('setBookmarked', { status, value: true })
  509. rootState.api.backendInteractor.bookmarkStatus({ id: status.id })
  510. .then(status => {
  511. commit('setBookmarkedConfirm', { status })
  512. })
  513. },
  514. unbookmark ({ rootState, commit }, status) {
  515. commit('setBookmarked', { status, value: false })
  516. rootState.api.backendInteractor.unbookmarkStatus({ id: status.id })
  517. .then(status => {
  518. commit('setBookmarkedConfirm', { status })
  519. })
  520. },
  521. queueFlush ({ rootState, commit }, { timeline, id }) {
  522. commit('queueFlush', { timeline, id })
  523. },
  524. queueFlushAll ({ rootState, commit }) {
  525. commit('queueFlushAll')
  526. },
  527. fetchFavsAndRepeats ({ rootState, commit }, id) {
  528. Promise.all([
  529. rootState.api.backendInteractor.fetchFavoritedByUsers({ id }),
  530. rootState.api.backendInteractor.fetchRebloggedByUsers({ id })
  531. ]).then(([favoritedByUsers, rebloggedByUsers]) => {
  532. commit('addFavs', { id, favoritedByUsers, currentUser: rootState.users.currentUser })
  533. commit('addRepeats', { id, rebloggedByUsers, currentUser: rootState.users.currentUser })
  534. })
  535. },
  536. reactWithEmoji ({ rootState, dispatch, commit }, { id, emoji }) {
  537. const currentUser = rootState.users.currentUser
  538. if (!currentUser) return
  539. commit('addOwnReaction', { id, emoji, currentUser })
  540. rootState.api.backendInteractor.reactWithEmoji({ id, emoji }).then(
  541. ok => {
  542. dispatch('fetchEmojiReactionsBy', id)
  543. }
  544. )
  545. },
  546. unreactWithEmoji ({ rootState, dispatch, commit }, { id, emoji }) {
  547. const currentUser = rootState.users.currentUser
  548. if (!currentUser) return
  549. commit('removeOwnReaction', { id, emoji, currentUser })
  550. rootState.api.backendInteractor.unreactWithEmoji({ id, emoji }).then(
  551. ok => {
  552. dispatch('fetchEmojiReactionsBy', id)
  553. }
  554. )
  555. },
  556. fetchEmojiReactionsBy ({ rootState, commit }, id) {
  557. return rootState.api.backendInteractor.fetchEmojiReactions({ id }).then(
  558. emojiReactions => {
  559. commit('addEmojiReactionsBy', { id, emojiReactions, currentUser: rootState.users.currentUser })
  560. }
  561. )
  562. },
  563. fetchFavs ({ rootState, commit }, id) {
  564. rootState.api.backendInteractor.fetchFavoritedByUsers({ id })
  565. .then(favoritedByUsers => commit('addFavs', { id, favoritedByUsers, currentUser: rootState.users.currentUser }))
  566. },
  567. fetchRepeats ({ rootState, commit }, id) {
  568. rootState.api.backendInteractor.fetchRebloggedByUsers({ id })
  569. .then(rebloggedByUsers => commit('addRepeats', { id, rebloggedByUsers, currentUser: rootState.users.currentUser }))
  570. },
  571. search (store, { q, resolve, limit, offset, following, type }) {
  572. return store.rootState.api.backendInteractor.search2({ q, resolve, limit, offset, following, type })
  573. .then((data) => {
  574. store.commit('addNewUsers', data.accounts)
  575. store.commit('addNewUsers', data.statuses.map(s => s.user).filter(u => u))
  576. store.commit('addNewStatuses', { statuses: data.statuses })
  577. return data
  578. })
  579. },
  580. setVirtualHeight ({ commit }, { statusId, height }) {
  581. commit('setVirtualHeight', { statusId, height })
  582. }
  583. },
  584. mutations
  585. }
  586. export default statuses