2021-12-18 19:59:38 +01:00
|
|
|
import apiInstance, { InstanceResponse } from '@api/instance'
|
2021-01-11 21:36:57 +01:00
|
|
|
import haptics from '@components/haptics'
|
2021-05-12 15:40:55 +02:00
|
|
|
import queryClient from '@helpers/queryClient'
|
2021-03-17 15:30:28 +01:00
|
|
|
import { store } from '@root/store'
|
2021-03-25 00:25:37 +01:00
|
|
|
import { getInstanceNotificationsFilter } from '@utils/slices/instancesSlice'
|
2021-01-07 19:13:09 +01:00
|
|
|
import { AxiosError } from 'axios'
|
|
|
|
import { uniqBy } from 'lodash'
|
2021-01-11 21:36:57 +01:00
|
|
|
import {
|
|
|
|
MutationOptions,
|
2021-12-18 19:59:38 +01:00
|
|
|
QueryFunctionContext,
|
2021-01-11 21:36:57 +01:00
|
|
|
useInfiniteQuery,
|
|
|
|
UseInfiniteQueryOptions,
|
|
|
|
useMutation
|
|
|
|
} from 'react-query'
|
|
|
|
import deleteItem from './timeline/deleteItem'
|
|
|
|
import updateStatusProperty from './timeline/updateStatusProperty'
|
2021-01-07 19:13:09 +01:00
|
|
|
|
|
|
|
export type QueryKeyTimeline = [
|
|
|
|
'Timeline',
|
|
|
|
{
|
|
|
|
page: App.Pages
|
|
|
|
hashtag?: Mastodon.Tag['name']
|
|
|
|
list?: Mastodon.List['id']
|
|
|
|
toot?: Mastodon.Status['id']
|
|
|
|
account?: Mastodon.Account['id']
|
|
|
|
}
|
|
|
|
]
|
|
|
|
|
2021-03-29 00:22:30 +02:00
|
|
|
const queryFunction = async ({
|
2021-01-07 19:13:09 +01:00
|
|
|
queryKey,
|
|
|
|
pageParam
|
2021-12-18 19:59:38 +01:00
|
|
|
}: QueryFunctionContext<QueryKeyTimeline>) => {
|
2021-01-07 19:13:09 +01:00
|
|
|
const { page, account, hashtag, list, toot } = queryKey[1]
|
2021-02-11 01:33:31 +01:00
|
|
|
let params: { [key: string]: string } = { ...pageParam }
|
2021-01-07 19:13:09 +01:00
|
|
|
|
|
|
|
switch (page) {
|
|
|
|
case 'Following':
|
2021-02-20 19:12:44 +01:00
|
|
|
return apiInstance<Mastodon.Status[]>({
|
2021-01-07 19:13:09 +01:00
|
|
|
method: 'get',
|
|
|
|
url: 'timelines/home',
|
|
|
|
params
|
|
|
|
})
|
|
|
|
|
|
|
|
case 'Local':
|
2021-02-20 19:12:44 +01:00
|
|
|
return apiInstance<Mastodon.Status[]>({
|
2021-01-07 19:13:09 +01:00
|
|
|
method: 'get',
|
|
|
|
url: 'timelines/public',
|
2021-01-11 21:36:57 +01:00
|
|
|
params: {
|
|
|
|
...params,
|
|
|
|
local: 'true'
|
|
|
|
}
|
2021-01-07 19:13:09 +01:00
|
|
|
})
|
|
|
|
|
|
|
|
case 'LocalPublic':
|
2021-02-20 19:12:44 +01:00
|
|
|
return apiInstance<Mastodon.Status[]>({
|
2021-01-07 19:13:09 +01:00
|
|
|
method: 'get',
|
|
|
|
url: 'timelines/public',
|
|
|
|
params
|
|
|
|
})
|
|
|
|
|
|
|
|
case 'Notifications':
|
2021-03-17 15:30:28 +01:00
|
|
|
const rootStore = store.getState()
|
|
|
|
const notificationsFilter = getInstanceNotificationsFilter(rootStore)
|
2021-02-20 19:12:44 +01:00
|
|
|
return apiInstance<Mastodon.Notification[]>({
|
2021-01-07 19:13:09 +01:00
|
|
|
method: 'get',
|
|
|
|
url: 'notifications',
|
2021-03-17 15:30:28 +01:00
|
|
|
params: {
|
|
|
|
...params,
|
|
|
|
...(notificationsFilter && {
|
|
|
|
exclude_types: Object.keys(notificationsFilter)
|
|
|
|
// @ts-ignore
|
|
|
|
.filter(filter => notificationsFilter[filter] === false)
|
|
|
|
})
|
|
|
|
}
|
2021-01-07 19:13:09 +01:00
|
|
|
})
|
|
|
|
|
|
|
|
case 'Account_Default':
|
2021-02-11 23:42:13 +01:00
|
|
|
if (pageParam && pageParam.hasOwnProperty('max_id')) {
|
2021-02-20 19:12:44 +01:00
|
|
|
return apiInstance<Mastodon.Status[]>({
|
2021-01-07 19:13:09 +01:00
|
|
|
method: 'get',
|
|
|
|
url: `accounts/${account}/statuses`,
|
|
|
|
params: {
|
|
|
|
exclude_replies: 'true',
|
|
|
|
...params
|
|
|
|
}
|
|
|
|
})
|
|
|
|
} else {
|
2021-08-29 15:25:38 +02:00
|
|
|
const res1 = await apiInstance<
|
|
|
|
(Mastodon.Status & { _pinned: boolean })[]
|
|
|
|
>({
|
2021-01-07 19:13:09 +01:00
|
|
|
method: 'get',
|
|
|
|
url: `accounts/${account}/statuses`,
|
|
|
|
params: {
|
|
|
|
pinned: 'true'
|
|
|
|
}
|
2021-03-29 00:22:30 +02:00
|
|
|
})
|
|
|
|
res1.body = res1.body.map(status => {
|
|
|
|
status._pinned = true
|
|
|
|
return status
|
|
|
|
})
|
|
|
|
const res2 = await apiInstance<Mastodon.Status[]>({
|
|
|
|
method: 'get',
|
|
|
|
url: `accounts/${account}/statuses`,
|
|
|
|
params: {
|
|
|
|
exclude_replies: 'true'
|
2021-02-11 01:33:31 +01:00
|
|
|
}
|
2021-01-07 19:13:09 +01:00
|
|
|
})
|
2021-08-29 15:25:38 +02:00
|
|
|
return {
|
2021-03-29 00:22:30 +02:00
|
|
|
body: uniqBy([...res1.body, ...res2.body], 'id'),
|
|
|
|
...(res2.links.next && { links: { next: res2.links.next } })
|
|
|
|
}
|
2021-01-07 19:13:09 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
case 'Account_All':
|
2021-02-20 19:12:44 +01:00
|
|
|
return apiInstance<Mastodon.Status[]>({
|
2021-01-07 19:13:09 +01:00
|
|
|
method: 'get',
|
|
|
|
url: `accounts/${account}/statuses`,
|
|
|
|
params
|
|
|
|
})
|
|
|
|
|
2021-01-16 00:00:31 +01:00
|
|
|
case 'Account_Attachments':
|
2021-02-20 19:12:44 +01:00
|
|
|
return apiInstance<Mastodon.Status[]>({
|
2021-01-07 19:13:09 +01:00
|
|
|
method: 'get',
|
|
|
|
url: `accounts/${account}/statuses`,
|
|
|
|
params: {
|
|
|
|
only_media: 'true',
|
|
|
|
...params
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
case 'Hashtag':
|
2021-02-20 19:12:44 +01:00
|
|
|
return apiInstance<Mastodon.Status[]>({
|
2021-01-07 19:13:09 +01:00
|
|
|
method: 'get',
|
|
|
|
url: `timelines/tag/${hashtag}`,
|
|
|
|
params
|
|
|
|
})
|
|
|
|
|
|
|
|
case 'Conversations':
|
2021-02-20 19:12:44 +01:00
|
|
|
return apiInstance<Mastodon.Conversation[]>({
|
2021-01-07 19:13:09 +01:00
|
|
|
method: 'get',
|
|
|
|
url: `conversations`,
|
|
|
|
params
|
|
|
|
})
|
|
|
|
|
|
|
|
case 'Bookmarks':
|
2021-02-20 19:12:44 +01:00
|
|
|
return apiInstance<Mastodon.Status[]>({
|
2021-01-07 19:13:09 +01:00
|
|
|
method: 'get',
|
|
|
|
url: `bookmarks`,
|
|
|
|
params
|
|
|
|
})
|
|
|
|
|
|
|
|
case 'Favourites':
|
2021-02-20 19:12:44 +01:00
|
|
|
return apiInstance<Mastodon.Status[]>({
|
2021-01-07 19:13:09 +01:00
|
|
|
method: 'get',
|
|
|
|
url: `favourites`,
|
|
|
|
params
|
|
|
|
})
|
|
|
|
|
|
|
|
case 'List':
|
2021-02-20 19:12:44 +01:00
|
|
|
return apiInstance<Mastodon.Status[]>({
|
2021-01-07 19:13:09 +01:00
|
|
|
method: 'get',
|
|
|
|
url: `timelines/list/${list}`,
|
|
|
|
params
|
|
|
|
})
|
|
|
|
|
|
|
|
case 'Toot':
|
2021-03-29 00:22:30 +02:00
|
|
|
const res1_1 = await apiInstance<Mastodon.Status>({
|
2021-01-07 19:13:09 +01:00
|
|
|
method: 'get',
|
|
|
|
url: `statuses/${toot}`
|
|
|
|
})
|
2021-03-29 00:22:30 +02:00
|
|
|
const res2_1 = await apiInstance<{
|
|
|
|
ancestors: Mastodon.Status[]
|
|
|
|
descendants: Mastodon.Status[]
|
|
|
|
}>({
|
|
|
|
method: 'get',
|
|
|
|
url: `statuses/${toot}/context`
|
|
|
|
})
|
2021-08-29 15:25:38 +02:00
|
|
|
return {
|
|
|
|
body: [
|
|
|
|
...res2_1.body.ancestors,
|
|
|
|
res1_1.body,
|
|
|
|
...res2_1.body.descendants
|
|
|
|
]
|
2021-03-29 00:22:30 +02:00
|
|
|
}
|
2021-01-07 19:13:09 +01:00
|
|
|
default:
|
|
|
|
return Promise.reject()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
type Unpromise<T extends Promise<any>> = T extends Promise<infer U> ? U : never
|
2021-01-11 21:36:57 +01:00
|
|
|
export type TimelineData = Unpromise<ReturnType<typeof queryFunction>>
|
2021-12-18 19:59:38 +01:00
|
|
|
const useTimelineQuery = ({
|
2021-01-07 19:13:09 +01:00
|
|
|
options,
|
|
|
|
...queryKeyParams
|
|
|
|
}: QueryKeyTimeline[1] & {
|
2021-02-11 01:33:31 +01:00
|
|
|
options?: UseInfiniteQueryOptions<
|
2021-12-18 19:59:38 +01:00
|
|
|
InstanceResponse<
|
|
|
|
Mastodon.Status[] | Mastodon.Notification[] | Mastodon.Conversation[]
|
|
|
|
>,
|
|
|
|
AxiosError
|
2021-02-11 01:33:31 +01:00
|
|
|
>
|
2021-01-07 19:13:09 +01:00
|
|
|
}) => {
|
|
|
|
const queryKey: QueryKeyTimeline = ['Timeline', { ...queryKeyParams }]
|
2021-03-14 00:47:55 +01:00
|
|
|
return useInfiniteQuery(queryKey, queryFunction, {
|
|
|
|
refetchOnMount: false,
|
|
|
|
refetchOnReconnect: false,
|
|
|
|
refetchOnWindowFocus: false,
|
|
|
|
...options
|
|
|
|
})
|
2021-01-07 19:13:09 +01:00
|
|
|
}
|
|
|
|
|
2021-01-11 21:36:57 +01:00
|
|
|
// --- Separator ---
|
|
|
|
|
|
|
|
enum MapPropertyToUrl {
|
|
|
|
bookmarked = 'bookmark',
|
|
|
|
favourited = 'favourite',
|
|
|
|
muted = 'mute',
|
|
|
|
pinned = 'pin',
|
|
|
|
reblogged = 'reblog'
|
|
|
|
}
|
|
|
|
|
|
|
|
export type MutationVarsTimelineUpdateStatusProperty = {
|
|
|
|
// This is status in general, including "status" inside conversation and notification
|
|
|
|
type: 'updateStatusProperty'
|
|
|
|
queryKey: QueryKeyTimeline
|
2021-02-13 01:26:02 +01:00
|
|
|
rootQueryKey?: QueryKeyTimeline
|
2021-01-11 21:36:57 +01:00
|
|
|
id: Mastodon.Status['id'] | Mastodon.Poll['id']
|
|
|
|
reblog?: boolean
|
|
|
|
payload:
|
|
|
|
| {
|
2021-01-23 02:41:50 +01:00
|
|
|
property: 'bookmarked' | 'muted' | 'pinned'
|
2021-01-11 21:36:57 +01:00
|
|
|
currentValue: boolean
|
2021-01-23 02:41:50 +01:00
|
|
|
propertyCount: undefined
|
|
|
|
countValue: undefined
|
|
|
|
}
|
|
|
|
| {
|
|
|
|
property: 'favourited' | 'reblogged'
|
|
|
|
currentValue: boolean
|
|
|
|
propertyCount: 'favourites_count' | 'reblogs_count'
|
|
|
|
countValue: number
|
2021-01-11 21:36:57 +01:00
|
|
|
}
|
|
|
|
| {
|
|
|
|
property: 'poll'
|
|
|
|
id: Mastodon.Poll['id']
|
|
|
|
type: 'vote' | 'refresh'
|
|
|
|
options?: boolean[]
|
|
|
|
data?: Mastodon.Poll
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
export type MutationVarsTimelineUpdateAccountProperty = {
|
|
|
|
// This is status in general, including "status" inside conversation and notification
|
|
|
|
type: 'updateAccountProperty'
|
|
|
|
queryKey?: QueryKeyTimeline
|
|
|
|
id: Mastodon.Account['id']
|
|
|
|
payload: {
|
|
|
|
property: 'mute' | 'block' | 'reports'
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
export type MutationVarsTimelineDeleteItem = {
|
|
|
|
// This is for deleting status and conversation
|
|
|
|
type: 'deleteItem'
|
|
|
|
source: 'statuses' | 'conversations'
|
2021-02-13 01:26:02 +01:00
|
|
|
queryKey?: QueryKeyTimeline
|
|
|
|
rootQueryKey?: QueryKeyTimeline
|
2021-01-11 21:36:57 +01:00
|
|
|
id: Mastodon.Conversation['id']
|
|
|
|
}
|
|
|
|
|
|
|
|
export type MutationVarsTimelineDomainBlock = {
|
|
|
|
// This is for deleting status and conversation
|
|
|
|
type: 'domainBlock'
|
|
|
|
queryKey: QueryKeyTimeline
|
|
|
|
domain: string
|
|
|
|
}
|
|
|
|
|
|
|
|
export type MutationVarsTimeline =
|
|
|
|
| MutationVarsTimelineUpdateStatusProperty
|
|
|
|
| MutationVarsTimelineUpdateAccountProperty
|
|
|
|
| MutationVarsTimelineDeleteItem
|
|
|
|
| MutationVarsTimelineDomainBlock
|
|
|
|
|
|
|
|
const mutationFunction = async (params: MutationVarsTimeline) => {
|
|
|
|
switch (params.type) {
|
|
|
|
case 'updateStatusProperty':
|
|
|
|
switch (params.payload.property) {
|
|
|
|
case 'poll':
|
|
|
|
const formData = new FormData()
|
|
|
|
params.payload.type === 'vote' &&
|
2021-01-22 01:34:20 +01:00
|
|
|
params.payload.options?.forEach((option, index) => {
|
2021-01-11 21:36:57 +01:00
|
|
|
if (option) {
|
|
|
|
formData.append('choices[]', index.toString())
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
2021-02-20 19:12:44 +01:00
|
|
|
return apiInstance<Mastodon.Poll>({
|
2021-01-11 21:36:57 +01:00
|
|
|
method: params.payload.type === 'vote' ? 'post' : 'get',
|
|
|
|
url:
|
|
|
|
params.payload.type === 'vote'
|
|
|
|
? `polls/${params.payload.id}/votes`
|
|
|
|
: `polls/${params.payload.id}`,
|
|
|
|
...(params.payload.type === 'vote' && { body: formData })
|
|
|
|
})
|
|
|
|
default:
|
2021-02-20 19:12:44 +01:00
|
|
|
return apiInstance<Mastodon.Status>({
|
2021-01-11 21:36:57 +01:00
|
|
|
method: 'post',
|
|
|
|
url: `statuses/${params.id}/${
|
|
|
|
params.payload.currentValue ? 'un' : ''
|
|
|
|
}${MapPropertyToUrl[params.payload.property]}`
|
|
|
|
})
|
|
|
|
}
|
|
|
|
case 'updateAccountProperty':
|
|
|
|
switch (params.payload.property) {
|
|
|
|
case 'block':
|
|
|
|
case 'mute':
|
2021-02-20 19:12:44 +01:00
|
|
|
return apiInstance<Mastodon.Account>({
|
2021-01-11 21:36:57 +01:00
|
|
|
method: 'post',
|
|
|
|
url: `accounts/${params.id}/${params.payload.property}`
|
|
|
|
})
|
|
|
|
case 'reports':
|
2021-02-20 19:12:44 +01:00
|
|
|
return apiInstance<Mastodon.Account>({
|
2021-01-11 21:36:57 +01:00
|
|
|
method: 'post',
|
|
|
|
url: `reports`,
|
|
|
|
params: {
|
|
|
|
account_id: params.id
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
case 'deleteItem':
|
2021-02-20 19:12:44 +01:00
|
|
|
return apiInstance<Mastodon.Conversation>({
|
2021-01-11 21:36:57 +01:00
|
|
|
method: 'delete',
|
|
|
|
url: `${params.source}/${params.id}`
|
|
|
|
})
|
|
|
|
case 'domainBlock':
|
2021-02-20 19:12:44 +01:00
|
|
|
return apiInstance<any>({
|
2021-01-11 21:36:57 +01:00
|
|
|
method: 'post',
|
|
|
|
url: `domain_blocks`,
|
|
|
|
params: {
|
|
|
|
domain: params.domain
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
type MutationOptionsTimeline = MutationOptions<
|
2021-02-11 01:33:31 +01:00
|
|
|
{ body: Mastodon.Conversation | Mastodon.Notification | Mastodon.Status },
|
2021-01-11 21:36:57 +01:00
|
|
|
AxiosError,
|
|
|
|
MutationVarsTimeline
|
|
|
|
>
|
|
|
|
|
|
|
|
const useTimelineMutation = ({
|
|
|
|
onError,
|
|
|
|
onMutate,
|
|
|
|
onSettled,
|
|
|
|
onSuccess
|
|
|
|
}: {
|
|
|
|
onError?: MutationOptionsTimeline['onError']
|
|
|
|
onMutate?: boolean
|
|
|
|
onSettled?: MutationOptionsTimeline['onSettled']
|
2021-02-13 01:26:02 +01:00
|
|
|
onSuccess?: MutationOptionsTimeline['onSuccess']
|
2021-01-11 21:36:57 +01:00
|
|
|
}) => {
|
|
|
|
return useMutation<
|
2021-02-11 01:33:31 +01:00
|
|
|
{ body: Mastodon.Conversation | Mastodon.Notification | Mastodon.Status },
|
2021-01-11 21:36:57 +01:00
|
|
|
AxiosError,
|
|
|
|
MutationVarsTimeline
|
|
|
|
>(mutationFunction, {
|
|
|
|
onError,
|
|
|
|
onSettled,
|
2021-02-13 01:26:02 +01:00
|
|
|
onSuccess,
|
2021-01-11 21:36:57 +01:00
|
|
|
...(onMutate && {
|
|
|
|
onMutate: params => {
|
|
|
|
queryClient.cancelQueries(params.queryKey)
|
|
|
|
let oldData
|
|
|
|
params.queryKey && (oldData = queryClient.getQueryData(params.queryKey))
|
|
|
|
|
2021-02-27 16:33:54 +01:00
|
|
|
haptics('Light')
|
2021-01-11 21:36:57 +01:00
|
|
|
switch (params.type) {
|
|
|
|
case 'updateStatusProperty':
|
2021-03-25 00:25:37 +01:00
|
|
|
updateStatusProperty(params)
|
2021-01-11 21:36:57 +01:00
|
|
|
break
|
|
|
|
case 'deleteItem':
|
2021-03-25 00:25:37 +01:00
|
|
|
deleteItem(params)
|
2021-01-11 21:36:57 +01:00
|
|
|
break
|
|
|
|
}
|
|
|
|
return oldData
|
|
|
|
}
|
|
|
|
})
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
export { useTimelineQuery, useTimelineMutation }
|