elk/composables/masto/status.ts

105 lines
3 KiB
TypeScript
Raw Normal View History

2023-01-08 09:21:09 +03:00
import type { mastodon } from 'masto'
2022-12-01 09:46:26 +03:00
type Action = 'reblogged' | 'favourited' | 'bookmarked' | 'pinned' | 'muted'
2022-12-01 09:46:26 +03:00
type CountField = 'reblogsCount' | 'favouritesCount'
export interface StatusActionsProps {
2023-01-08 09:21:09 +03:00
status: mastodon.v1.Status
2022-12-01 09:46:26 +03:00
}
export function useStatusActions(props: StatusActionsProps) {
2023-01-08 09:21:09 +03:00
let status = $ref<mastodon.v1.Status>({ ...props.status })
2023-01-15 11:38:02 +03:00
const { client } = $(useMasto())
2022-12-01 09:46:26 +03:00
watch(
() => props.status,
val => status = { ...val },
{ deep: true, immediate: true },
)
// Use different states to let the user press different actions right after the other
const isLoading = $ref({
reblogged: false,
favourited: false,
bookmarked: false,
pinned: false,
translation: false,
muted: false,
2022-12-01 09:46:26 +03:00
})
2023-01-08 09:21:09 +03:00
async function toggleStatusAction(action: Action, fetchNewStatus: () => Promise<mastodon.v1.Status>, countField?: CountField) {
2022-12-02 05:18:57 +03:00
// check login
if (!checkLogin())
return
const prevCount = countField ? status[countField] : undefined
isLoading[action] = true
const isCancel = status[action]
fetchNewStatus().then((newStatus) => {
// when the action is cancelled, the count is not updated highly likely (if they're the same)
// issue of Mastodon API
if (isCancel && countField && prevCount === newStatus[countField])
newStatus[countField] -= 1
Object.assign(status, newStatus)
cacheStatus(newStatus, undefined, true)
}).finally(() => {
isLoading[action] = false
})
2022-12-02 05:18:57 +03:00
// Optimistic update
2022-12-01 09:46:26 +03:00
status[action] = !status[action]
cacheStatus(status, undefined, true)
2022-12-01 09:46:26 +03:00
if (countField)
status[countField] += status[action] ? 1 : -1
}
const canReblog = $computed(() =>
status.visibility !== 'direct'
&& (status.visibility !== 'private' || status.account.id === currentUser.value?.account.id),
)
2022-12-01 09:46:26 +03:00
const toggleReblog = () => toggleStatusAction(
'reblogged',
2024-01-09 11:56:15 +03:00
() => client.v1.statuses.$select(status.id)[status.reblogged ? 'unreblog' : 'reblog']().then((res) => {
2022-12-01 09:46:26 +03:00
if (status.reblogged)
// returns the original status
return res.reblog!
return res
}),
'reblogsCount',
)
const toggleFavourite = () => toggleStatusAction(
'favourited',
2024-01-09 11:56:15 +03:00
() => client.v1.statuses.$select(status.id)[status.favourited ? 'unfavourite' : 'favourite'](),
2022-12-01 09:46:26 +03:00
'favouritesCount',
)
const toggleBookmark = () => toggleStatusAction(
'bookmarked',
2024-01-09 11:56:15 +03:00
() => client.v1.statuses.$select(status.id)[status.bookmarked ? 'unbookmark' : 'bookmark'](),
2022-12-01 09:46:26 +03:00
)
const togglePin = async () => toggleStatusAction(
'pinned',
2024-01-09 11:56:15 +03:00
() => client.v1.statuses.$select(status.id)[status.pinned ? 'unpin' : 'pin'](),
2022-12-01 09:46:26 +03:00
)
const toggleMute = async () => toggleStatusAction(
'muted',
2024-01-09 11:56:15 +03:00
() => client.v1.statuses.$select(status.id)[status.muted ? 'unmute' : 'mute'](),
)
2022-12-01 09:46:26 +03:00
return {
status: $$(status),
isLoading: $$(isLoading),
canReblog: $$(canReblog),
toggleMute,
2022-12-01 09:46:26 +03:00
toggleReblog,
toggleFavourite,
toggleBookmark,
togglePin,
}
}