124 lines
3.2 KiB
JavaScript
124 lines
3.2 KiB
JavaScript
|
|
import { get } from 'lodash-es'
|
||
|
|
import { computed, provide, ref } from 'vue'
|
||
|
|
|
||
|
|
import { useOAuthStore } from 'src/stores/oauth.js'
|
||
|
|
import { useStatusesStore } from 'src/stores/statuses.js'
|
||
|
|
|
||
|
|
import {
|
||
|
|
fetchConversation as apiFetchConversation,
|
||
|
|
fetchStatus as apiFetchStatus,
|
||
|
|
} from 'src/api/public.js'
|
||
|
|
|
||
|
|
export function useConversation(statusId, expanded) {
|
||
|
|
const getStatusObject = (id) => useStatusesStore().allStatuses.get(id)
|
||
|
|
const getConversationId = (statusId) => {
|
||
|
|
const status = getStatusObject(statusId)
|
||
|
|
return get(
|
||
|
|
status,
|
||
|
|
'retweeted_status.statusnet_conversation_id',
|
||
|
|
get(status, 'statusnet_conversation_id'),
|
||
|
|
)
|
||
|
|
}
|
||
|
|
|
||
|
|
const loadError = ref(null)
|
||
|
|
const currentStatus = computed(() => getStatusObject(statusId.value))
|
||
|
|
|
||
|
|
const sortById = (a, b) => {
|
||
|
|
const idA = a.type === 'retweet' ? a.retweeted_status.id : a.id
|
||
|
|
const idB = b.type === 'retweet' ? b.retweeted_status.id : b.id
|
||
|
|
const seqA = Number(idA)
|
||
|
|
const seqB = Number(idB)
|
||
|
|
const isSeqA = !Number.isNaN(seqA)
|
||
|
|
const isSeqB = !Number.isNaN(seqB)
|
||
|
|
if (isSeqA && isSeqB) {
|
||
|
|
return seqA < seqB ? -1 : 1
|
||
|
|
} else if (isSeqA && !isSeqB) {
|
||
|
|
return -1
|
||
|
|
} else if (!isSeqA && isSeqB) {
|
||
|
|
return 1
|
||
|
|
} else {
|
||
|
|
return idA < idB ? -1 : 1
|
||
|
|
}
|
||
|
|
}
|
||
|
|
const conversationId = computed(() => getConversationId(statusId.value))
|
||
|
|
const conversation = computed(() => {
|
||
|
|
if (!currentStatus.value) {
|
||
|
|
return []
|
||
|
|
}
|
||
|
|
|
||
|
|
if (!expanded.value) {
|
||
|
|
return [currentStatus.value]
|
||
|
|
}
|
||
|
|
|
||
|
|
const conversation = useStatusesStore().conversations.get(
|
||
|
|
conversationId.value,
|
||
|
|
)
|
||
|
|
|
||
|
|
return [...conversation.keys()]
|
||
|
|
.map((k) => useStatusesStore().allStatuses.get(k))
|
||
|
|
.filter((status) => status.type != 'repeat') // Old backend behavior?
|
||
|
|
.toSorted(sortById)
|
||
|
|
})
|
||
|
|
const replies = computed(() =>
|
||
|
|
conversation.value.reduce(
|
||
|
|
(result, { id, in_reply_to_status_id: irid }, index) => {
|
||
|
|
if (irid) {
|
||
|
|
if (!result.has(irid)) {
|
||
|
|
result.set(irid, new Set())
|
||
|
|
}
|
||
|
|
result.get(irid).add({
|
||
|
|
name: `#${index}`,
|
||
|
|
id,
|
||
|
|
})
|
||
|
|
}
|
||
|
|
return result
|
||
|
|
},
|
||
|
|
new Map(),
|
||
|
|
),
|
||
|
|
)
|
||
|
|
const getReplies = (id) => replies.value.get(id) ?? new Set()
|
||
|
|
provide('conversation', conversation)
|
||
|
|
provide('replies', replies)
|
||
|
|
|
||
|
|
const fetchConversation = async () => {
|
||
|
|
if (currentStatus.value) {
|
||
|
|
const {
|
||
|
|
data: { ancestors, descendants },
|
||
|
|
timestamp,
|
||
|
|
} = await apiFetchConversation({
|
||
|
|
id: statusId.value,
|
||
|
|
credentials: useOAuthStore().token,
|
||
|
|
})
|
||
|
|
|
||
|
|
useStatusesStore().addNewStatuses({ statuses: ancestors, timestamp })
|
||
|
|
useStatusesStore().addNewStatuses({
|
||
|
|
statuses: descendants,
|
||
|
|
timestamp,
|
||
|
|
})
|
||
|
|
} else {
|
||
|
|
try {
|
||
|
|
loadError.value = null
|
||
|
|
|
||
|
|
const { data: status } = await apiFetchStatus({
|
||
|
|
id: statusId.value,
|
||
|
|
credentials: useOAuthStore().token,
|
||
|
|
})
|
||
|
|
|
||
|
|
useStatusesStore().addNewStatuses({ statuses: [status] })
|
||
|
|
fetchConversation()
|
||
|
|
} catch (error) {
|
||
|
|
console.error(error)
|
||
|
|
loadError.value = error
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return {
|
||
|
|
currentStatus,
|
||
|
|
conversation,
|
||
|
|
replies,
|
||
|
|
getReplies,
|
||
|
|
fetchConversation,
|
||
|
|
loadError,
|
||
|
|
}
|
||
|
|
}
|