mirror of
https://github.com/tooot-app/app
synced 2025-04-22 22:27:37 +02:00
parent
0cc1cdd4b6
commit
f619d1bb6a
@ -4,39 +4,47 @@ import { StackNavigationProp } from '@react-navigation/stack'
|
|||||||
import { TabLocalStackParamList } from '@utils/navigation/navigators'
|
import { TabLocalStackParamList } from '@utils/navigation/navigators'
|
||||||
import { StyleConstants } from '@utils/styles/constants'
|
import { StyleConstants } from '@utils/styles/constants'
|
||||||
import { useTheme } from '@utils/styles/ThemeManager'
|
import { useTheme } from '@utils/styles/ThemeManager'
|
||||||
import React, { useCallback } from 'react'
|
import React, { PropsWithChildren } from 'react'
|
||||||
import { Pressable, View } from 'react-native'
|
import { Pressable, View } from 'react-native'
|
||||||
import GracefullyImage from './GracefullyImage'
|
import GracefullyImage from './GracefullyImage'
|
||||||
import CustomText from './Text'
|
import CustomText from './Text'
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
account: Mastodon.Account
|
account: Mastodon.Account
|
||||||
onPress?: () => void
|
Component?: typeof View | typeof Pressable
|
||||||
|
props?: {}
|
||||||
}
|
}
|
||||||
|
|
||||||
const ComponentAccount: React.FC<Props> = ({ account, onPress: customOnPress }) => {
|
const ComponentAccount: React.FC<PropsWithChildren & Props> = ({
|
||||||
|
account,
|
||||||
|
Component,
|
||||||
|
props,
|
||||||
|
children
|
||||||
|
}) => {
|
||||||
const { colors } = useTheme()
|
const { colors } = useTheme()
|
||||||
const navigation = useNavigation<StackNavigationProp<TabLocalStackParamList>>()
|
const navigation = useNavigation<StackNavigationProp<TabLocalStackParamList>>()
|
||||||
|
|
||||||
const onPress = useCallback(() => navigation.push('Tab-Shared-Account', { account }), [])
|
if (!props) {
|
||||||
|
props = { onPress: () => navigation.push('Tab-Shared-Account', { account }) }
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return React.createElement(
|
||||||
<Pressable
|
Component || Pressable,
|
||||||
accessibilityRole='button'
|
{
|
||||||
style={{
|
...props,
|
||||||
|
style: {
|
||||||
flex: 1,
|
flex: 1,
|
||||||
paddingHorizontal: StyleConstants.Spacing.Global.PagePadding,
|
paddingHorizontal: StyleConstants.Spacing.Global.PagePadding,
|
||||||
paddingVertical: StyleConstants.Spacing.M,
|
paddingVertical: StyleConstants.Spacing.M,
|
||||||
flexDirection: 'row',
|
flexDirection: 'row',
|
||||||
alignSelf: 'flex-start',
|
justifyContent: 'space-between',
|
||||||
alignItems: 'center'
|
alignItems: 'center'
|
||||||
}}
|
}
|
||||||
onPress={customOnPress || onPress}
|
},
|
||||||
>
|
<View style={{ flex: 1, flexDirection: 'row', alignItems: 'center' }}>
|
||||||
<GracefullyImage
|
<GracefullyImage
|
||||||
uri={{ original: account.avatar, static: account.avatar_static }}
|
uri={{ original: account.avatar, static: account.avatar_static }}
|
||||||
style={{
|
style={{
|
||||||
alignSelf: 'flex-start',
|
|
||||||
width: StyleConstants.Avatar.S,
|
width: StyleConstants.Avatar.S,
|
||||||
height: StyleConstants.Avatar.S,
|
height: StyleConstants.Avatar.S,
|
||||||
borderRadius: 6,
|
borderRadius: 6,
|
||||||
@ -62,7 +70,8 @@ const ComponentAccount: React.FC<Props> = ({ account, onPress: customOnPress })
|
|||||||
@{account.acct}
|
@{account.acct}
|
||||||
</CustomText>
|
</CustomText>
|
||||||
</View>
|
</View>
|
||||||
</Pressable>
|
</View>,
|
||||||
|
children
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,7 +57,7 @@ const TimelineEmpty = React.memo(
|
|||||||
style={{
|
style={{
|
||||||
marginTop: StyleConstants.Spacing.S,
|
marginTop: StyleConstants.Spacing.S,
|
||||||
marginBottom: StyleConstants.Spacing.L,
|
marginBottom: StyleConstants.Spacing.L,
|
||||||
color: colors.primaryDefault
|
color: colors.secondary
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{t('empty.success.message')}
|
{t('empty.success.message')}
|
||||||
|
@ -46,17 +46,20 @@
|
|||||||
"language": {
|
"language": {
|
||||||
"name": "Language"
|
"name": "Language"
|
||||||
},
|
},
|
||||||
"lists": {
|
"list": {
|
||||||
"name": "Lists"
|
"name": "List: {{list}}"
|
||||||
|
},
|
||||||
|
"listAccounts": {
|
||||||
|
"name": "Users in list: {{list}}"
|
||||||
},
|
},
|
||||||
"listAdd": {
|
"listAdd": {
|
||||||
"name": "Add a List"
|
"name": "Add a List"
|
||||||
},
|
},
|
||||||
"listEdit": {
|
"listEdit": {
|
||||||
"name": "Edit List"
|
"name": "Edit List Details"
|
||||||
},
|
},
|
||||||
"list": {
|
"lists": {
|
||||||
"name": "List: {{list}}"
|
"name": "Lists"
|
||||||
},
|
},
|
||||||
"push": {
|
"push": {
|
||||||
"name": "Push Notification"
|
"name": "Push Notification"
|
||||||
@ -93,7 +96,13 @@
|
|||||||
"XXL": "XXL"
|
"XXL": "XXL"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"listAccounts": {
|
||||||
|
"heading": "Manage users",
|
||||||
|
"error": "Delete user from list",
|
||||||
|
"empty": "No user added in this list"
|
||||||
|
},
|
||||||
"listEdit": {
|
"listEdit": {
|
||||||
|
"heading": "Edit list details",
|
||||||
"title": "Title",
|
"title": "Title",
|
||||||
"repliesPolicy": {
|
"repliesPolicy": {
|
||||||
"heading": "Show replies to:",
|
"heading": "Show replies to:",
|
||||||
|
@ -44,7 +44,7 @@ const ComposeRootSuggestion: React.FC<Props> = ({ item }) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return item.acct ? (
|
return item.acct ? (
|
||||||
<ComponentAccount account={item} onPress={onPress} />
|
<ComponentAccount account={item} props={{ onPress }} />
|
||||||
) : (
|
) : (
|
||||||
<ComponentHashtag hashtag={item} onPress={onPress} origin='suggestion' />
|
<ComponentHashtag hashtag={item} onPress={onPress} origin='suggestion' />
|
||||||
)
|
)
|
||||||
|
@ -8,8 +8,9 @@ import TabMeBookmarks from './Me/Bookmarks'
|
|||||||
import TabMeConversations from './Me/Cconversations'
|
import TabMeConversations from './Me/Cconversations'
|
||||||
import TabMeFavourites from './Me/Favourites'
|
import TabMeFavourites from './Me/Favourites'
|
||||||
import TabMeList from './Me/List'
|
import TabMeList from './Me/List'
|
||||||
import TabMeListEdit from './Me/ListEdit'
|
import TabMeListAccounts from './Me/List/Accounts'
|
||||||
import TabMeLists from './Me/Lists'
|
import TabMeListEdit from './Me/List/Edit'
|
||||||
|
import TabMeListList from './Me/List/List'
|
||||||
import TabMeProfile from './Me/Profile'
|
import TabMeProfile from './Me/Profile'
|
||||||
import TabMePush from './Me/Push'
|
import TabMePush from './Me/Push'
|
||||||
import TabMeRoot from './Me/Root'
|
import TabMeRoot from './Me/Root'
|
||||||
@ -86,21 +87,28 @@ const TabMe = React.memo(
|
|||||||
headerLeft: () => <HeaderLeft onPress={() => navigation.pop(1)} />
|
headerLeft: () => <HeaderLeft onPress={() => navigation.pop(1)} />
|
||||||
})}
|
})}
|
||||||
/>
|
/>
|
||||||
|
<Stack.Screen
|
||||||
|
name='Tab-Me-List-Accounts'
|
||||||
|
component={TabMeListAccounts}
|
||||||
|
options={({ navigation, route: { params } }) => ({
|
||||||
|
title: t('me.stacks.listAccounts.name', { list: params.title }),
|
||||||
|
...(Platform.OS === 'android' && {
|
||||||
|
headerCenter: () => <HeaderCenter content={t('me.stacks.listsAdd.name')} />
|
||||||
|
}),
|
||||||
|
headerLeft: () => <HeaderLeft onPress={() => navigation.pop(1)} />
|
||||||
|
})}
|
||||||
|
/>
|
||||||
<Stack.Screen
|
<Stack.Screen
|
||||||
name='Tab-Me-List-Edit'
|
name='Tab-Me-List-Edit'
|
||||||
component={TabMeListEdit}
|
component={TabMeListEdit}
|
||||||
options={{
|
options={{
|
||||||
gestureEnabled: false,
|
gestureEnabled: false,
|
||||||
presentation: 'modal',
|
presentation: 'modal'
|
||||||
title: t('me.stacks.listsAdd.name'),
|
|
||||||
...(Platform.OS === 'android' && {
|
|
||||||
headerCenter: () => <HeaderCenter content={t('me.stacks.listsAdd.name')} />
|
|
||||||
})
|
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<Stack.Screen
|
<Stack.Screen
|
||||||
name='Tab-Me-Lists'
|
name='Tab-Me-List-List'
|
||||||
component={TabMeLists}
|
component={TabMeListList}
|
||||||
options={({ navigation }: any) => ({
|
options={({ navigation }: any) => ({
|
||||||
title: t('me.stacks.lists.name'),
|
title: t('me.stacks.lists.name'),
|
||||||
...(Platform.OS === 'android' && {
|
...(Platform.OS === 'android' && {
|
||||||
|
99
src/screens/Tabs/Me/List/Accounts.tsx
Normal file
99
src/screens/Tabs/Me/List/Accounts.tsx
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
import ComponentAccount from '@components/Account'
|
||||||
|
import Button from '@components/Button'
|
||||||
|
import haptics from '@components/haptics'
|
||||||
|
import { displayMessage } from '@components/Message'
|
||||||
|
import CustomText from '@components/Text'
|
||||||
|
import { TabMeStackScreenProps } from '@utils/navigation/navigators'
|
||||||
|
import {
|
||||||
|
QueryKeyListAccounts,
|
||||||
|
useListAccountsMutation,
|
||||||
|
useListAccountsQuery
|
||||||
|
} from '@utils/queryHooks/lists'
|
||||||
|
import { StyleConstants } from '@utils/styles/constants'
|
||||||
|
import { useTheme } from '@utils/styles/ThemeManager'
|
||||||
|
import React from 'react'
|
||||||
|
import { useTranslation } from 'react-i18next'
|
||||||
|
import { FlatList, View } from 'react-native'
|
||||||
|
|
||||||
|
const TabMeListAccounts: React.FC<TabMeStackScreenProps<'Tab-Me-List-Accounts'>> = ({
|
||||||
|
route: { params }
|
||||||
|
}) => {
|
||||||
|
const { colors, theme } = useTheme()
|
||||||
|
const { t } = useTranslation('screenTabs')
|
||||||
|
|
||||||
|
const queryKey: QueryKeyListAccounts = ['ListAccounts', { id: params.id }]
|
||||||
|
const { data, refetch, fetchNextPage, hasNextPage } = useListAccountsQuery({
|
||||||
|
...queryKey[1],
|
||||||
|
options: {
|
||||||
|
getNextPageParam: lastPage =>
|
||||||
|
lastPage?.links?.next && {
|
||||||
|
max_id: lastPage.links.next
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const flattenData = data?.pages ? data.pages?.flatMap(page => [...page.body]) : []
|
||||||
|
|
||||||
|
const mutation = useListAccountsMutation({
|
||||||
|
onSuccess: () => {
|
||||||
|
haptics('Light')
|
||||||
|
refetch()
|
||||||
|
},
|
||||||
|
onError: () => {
|
||||||
|
displayMessage({
|
||||||
|
theme,
|
||||||
|
type: 'error',
|
||||||
|
message: t('common:message.error.message', {
|
||||||
|
function: t('me.listAccounts.error')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return (
|
||||||
|
<FlatList
|
||||||
|
data={flattenData}
|
||||||
|
renderItem={({ item, index }) => (
|
||||||
|
<ComponentAccount
|
||||||
|
key={index}
|
||||||
|
account={item}
|
||||||
|
Component={View}
|
||||||
|
children={
|
||||||
|
<Button
|
||||||
|
type='icon'
|
||||||
|
content='X'
|
||||||
|
round
|
||||||
|
onPress={() =>
|
||||||
|
mutation.mutate({ type: 'delete', payload: { id: params.id, accounts: [item.id] } })
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
ListEmptyComponent={
|
||||||
|
<View
|
||||||
|
style={{
|
||||||
|
flex: 1,
|
||||||
|
minHeight: '100%',
|
||||||
|
justifyContent: 'center',
|
||||||
|
alignItems: 'center'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<CustomText
|
||||||
|
fontStyle='M'
|
||||||
|
style={{
|
||||||
|
marginTop: StyleConstants.Spacing.S,
|
||||||
|
marginBottom: StyleConstants.Spacing.L,
|
||||||
|
color: colors.secondary
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{t('me.listAccounts.empty')}
|
||||||
|
</CustomText>
|
||||||
|
</View>
|
||||||
|
}
|
||||||
|
onEndReached={() => hasNextPage && fetchNextPage()}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default TabMeListAccounts
|
@ -1,6 +1,6 @@
|
|||||||
import { EmojisState } from '@components/Emojis/helpers/EmojisContext'
|
import { EmojisState } from '@components/Emojis/helpers/EmojisContext'
|
||||||
import haptics from '@components/haptics'
|
import haptics from '@components/haptics'
|
||||||
import { HeaderLeft, HeaderRight } from '@components/Header'
|
import { HeaderCenter, HeaderLeft, HeaderRight } from '@components/Header'
|
||||||
import ComponentInput from '@components/Input'
|
import ComponentInput from '@components/Input'
|
||||||
import { displayMessage, Message } from '@components/Message'
|
import { displayMessage, Message } from '@components/Message'
|
||||||
import Selections from '@components/Selections'
|
import Selections from '@components/Selections'
|
||||||
@ -12,7 +12,7 @@ import { StyleConstants } from '@utils/styles/constants'
|
|||||||
import { useTheme } from '@utils/styles/ThemeManager'
|
import { useTheme } from '@utils/styles/ThemeManager'
|
||||||
import React, { useEffect, useRef, useState } from 'react'
|
import React, { useEffect, useRef, useState } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { Alert, ScrollView, TextInput } from 'react-native'
|
import { Alert, Platform, ScrollView, TextInput } from 'react-native'
|
||||||
import { useQueryClient } from 'react-query'
|
import { useQueryClient } from 'react-query'
|
||||||
|
|
||||||
const TabMeListEdit: React.FC<TabMeStackScreenProps<'Tab-Me-List-Edit'>> = ({
|
const TabMeListEdit: React.FC<TabMeStackScreenProps<'Tab-Me-List-Edit'>> = ({
|
||||||
@ -83,6 +83,16 @@ const TabMeListEdit: React.FC<TabMeStackScreenProps<'Tab-Me-List-Edit'>> = ({
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
navigation.setOptions({
|
navigation.setOptions({
|
||||||
|
title: params.type === 'add' ? t('me.stacks.listAdd.name') : t('me.stacks.listEdit.name'),
|
||||||
|
...(Platform.OS === 'android' && {
|
||||||
|
headerCenter: () => (
|
||||||
|
<HeaderCenter
|
||||||
|
content={
|
||||||
|
params.type === 'add' ? t('me.stacks.listAdd.name') : t('me.stacks.listEdit.name')
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}),
|
||||||
headerLeft: () => (
|
headerLeft: () => (
|
||||||
<HeaderLeft
|
<HeaderLeft
|
||||||
content='X'
|
content='X'
|
@ -5,7 +5,7 @@ import { useListsQuery } from '@utils/queryHooks/lists'
|
|||||||
import React, { useEffect } from 'react'
|
import React, { useEffect } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
|
|
||||||
const TabMeLists: React.FC<TabMeStackScreenProps<'Tab-Me-Lists'>> = ({ navigation }) => {
|
const TabMeListList: React.FC<TabMeStackScreenProps<'Tab-Me-List-List'>> = ({ navigation }) => {
|
||||||
const { data } = useListsQuery({})
|
const { data } = useListsQuery({})
|
||||||
const { t } = useTranslation('screenTabs')
|
const { t } = useTranslation('screenTabs')
|
||||||
|
|
||||||
@ -23,17 +23,17 @@ const TabMeLists: React.FC<TabMeStackScreenProps<'Tab-Me-Lists'>> = ({ navigatio
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<MenuContainer>
|
<MenuContainer>
|
||||||
{data?.map((d: Mastodon.List, i: number) => (
|
{data?.map((params, index) => (
|
||||||
<MenuRow
|
<MenuRow
|
||||||
key={i}
|
key={index}
|
||||||
iconFront='List'
|
iconFront='List'
|
||||||
iconBack='ChevronRight'
|
iconBack='ChevronRight'
|
||||||
title={d.title}
|
title={params.title}
|
||||||
onPress={() => navigation.navigate('Tab-Me-List', d)}
|
onPress={() => navigation.navigate('Tab-Me-List', params)}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</MenuContainer>
|
</MenuContainer>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export default TabMeLists
|
export default TabMeListList
|
@ -9,9 +9,9 @@ import { StyleConstants } from '@utils/styles/constants'
|
|||||||
import { useTheme } from '@utils/styles/ThemeManager'
|
import { useTheme } from '@utils/styles/ThemeManager'
|
||||||
import React, { useEffect } from 'react'
|
import React, { useEffect } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { Alert } from 'react-native'
|
|
||||||
import { useQueryClient } from 'react-query'
|
import { useQueryClient } from 'react-query'
|
||||||
import * as DropdownMenu from 'zeego/dropdown-menu'
|
import * as DropdownMenu from 'zeego/dropdown-menu'
|
||||||
|
import { menuListAccounts, menuListDelete, menuListEdit } from './menus'
|
||||||
|
|
||||||
const TabMeList: React.FC<TabMeStackScreenProps<'Tab-Me-List'>> = ({
|
const TabMeList: React.FC<TabMeStackScreenProps<'Tab-Me-List'>> = ({
|
||||||
navigation,
|
navigation,
|
||||||
@ -40,6 +40,10 @@ const TabMeList: React.FC<TabMeStackScreenProps<'Tab-Me-List'>> = ({
|
|||||||
})
|
})
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
const listAccounts = menuListAccounts({ params })
|
||||||
|
const listEdit = menuListEdit({ params, key })
|
||||||
|
const listDelete = menuListDelete({ params, mutation })
|
||||||
|
|
||||||
navigation.setOptions({
|
navigation.setOptions({
|
||||||
headerRight: () => (
|
headerRight: () => (
|
||||||
<DropdownMenu.Root>
|
<DropdownMenu.Root>
|
||||||
@ -52,41 +56,24 @@ const TabMeList: React.FC<TabMeStackScreenProps<'Tab-Me-List'>> = ({
|
|||||||
</DropdownMenu.Trigger>
|
</DropdownMenu.Trigger>
|
||||||
|
|
||||||
<DropdownMenu.Content>
|
<DropdownMenu.Content>
|
||||||
<DropdownMenu.Item
|
<DropdownMenu.Group>
|
||||||
key='list-edit'
|
<DropdownMenu.Item key={listAccounts.key} onSelect={listAccounts.onSelect}>
|
||||||
onSelect={() =>
|
<DropdownMenu.ItemTitle children={listAccounts.title} />
|
||||||
navigation.navigate('Tab-Me-List-Edit', {
|
<DropdownMenu.ItemIcon iosIconName={listAccounts.icon} />
|
||||||
type: 'edit',
|
</DropdownMenu.Item>
|
||||||
payload: params,
|
</DropdownMenu.Group>
|
||||||
key
|
|
||||||
})
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<DropdownMenu.ItemTitle children={t('me.stacks.listEdit.name')} />
|
|
||||||
<DropdownMenu.ItemIcon iosIconName='square.and.pencil' />
|
|
||||||
</DropdownMenu.Item>
|
|
||||||
|
|
||||||
<DropdownMenu.Item
|
<DropdownMenu.Group>
|
||||||
key='list-delete'
|
<DropdownMenu.Item key={listEdit.key} onSelect={listEdit.onSelect}>
|
||||||
destructive
|
<DropdownMenu.ItemTitle children={listEdit.title} />
|
||||||
onSelect={() =>
|
<DropdownMenu.ItemIcon iosIconName={listEdit.icon} />
|
||||||
Alert.alert(
|
</DropdownMenu.Item>
|
||||||
t('me.listDelete.confirm.title', { list: params.title.slice(0, 6) }),
|
|
||||||
t('me.listDelete.confirm.message'),
|
<DropdownMenu.Item key={listDelete.key} destructive onSelect={listDelete.onSelect}>
|
||||||
[
|
<DropdownMenu.ItemTitle children={listDelete.title} />
|
||||||
{
|
<DropdownMenu.ItemIcon iosIconName={listDelete.icon} />
|
||||||
text: t('common:buttons.delete'),
|
</DropdownMenu.Item>
|
||||||
style: 'destructive',
|
</DropdownMenu.Group>
|
||||||
onPress: () => mutation.mutate({ type: 'delete', payload: params })
|
|
||||||
},
|
|
||||||
{ text: t('common:buttons.cancel') }
|
|
||||||
]
|
|
||||||
)
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<DropdownMenu.ItemTitle children={t('me.listDelete.heading')} />
|
|
||||||
<DropdownMenu.ItemIcon iosIconName='trash' />
|
|
||||||
</DropdownMenu.Item>
|
|
||||||
</DropdownMenu.Content>
|
</DropdownMenu.Content>
|
||||||
</DropdownMenu.Root>
|
</DropdownMenu.Root>
|
||||||
)
|
)
|
48
src/screens/Tabs/Me/List/menus.tsx
Normal file
48
src/screens/Tabs/Me/List/menus.tsx
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
import navigationRef from '@helpers/navigationRef'
|
||||||
|
import i18next from 'i18next'
|
||||||
|
import { Alert } from 'react-native'
|
||||||
|
import { UseMutationResult } from 'react-query'
|
||||||
|
|
||||||
|
export const menuListAccounts = ({ params }: { params: Mastodon.List }) => ({
|
||||||
|
key: 'list-accounts',
|
||||||
|
onSelect: () => navigationRef.navigate<any>('Tab-Me-List-Accounts', params),
|
||||||
|
title: i18next.t('screenTabs:me.listAccounts.heading'),
|
||||||
|
icon: 'person.crop.circle.fill.badge.checkmark'
|
||||||
|
})
|
||||||
|
|
||||||
|
export const menuListEdit = ({ params, key }: { params: Mastodon.List; key: string }) => ({
|
||||||
|
key: 'list-edit',
|
||||||
|
onSelect: () =>
|
||||||
|
navigationRef.navigate<any>('Tab-Me-List-Edit', {
|
||||||
|
type: 'edit',
|
||||||
|
payload: params,
|
||||||
|
key
|
||||||
|
}),
|
||||||
|
title: i18next.t('screenTabs:me.listEdit.heading'),
|
||||||
|
icon: 'square.and.pencil'
|
||||||
|
})
|
||||||
|
|
||||||
|
export const menuListDelete = ({
|
||||||
|
params,
|
||||||
|
mutation
|
||||||
|
}: {
|
||||||
|
params: Mastodon.List
|
||||||
|
mutation: UseMutationResult<any, any, unknown, unknown>
|
||||||
|
}) => ({
|
||||||
|
key: 'list-delete',
|
||||||
|
onSelect: () =>
|
||||||
|
Alert.alert(
|
||||||
|
i18next.t('screenTabs:me.listDelete.confirm.title', { list: params.title.slice(0, 6) }),
|
||||||
|
i18next.t('screenTabs:me.listDelete.confirm.message'),
|
||||||
|
[
|
||||||
|
{
|
||||||
|
text: i18next.t('common:buttons.delete'),
|
||||||
|
style: 'destructive',
|
||||||
|
onPress: () => mutation.mutate({ type: 'delete', payload: params })
|
||||||
|
},
|
||||||
|
{ text: i18next.t('common:buttons.cancel') }
|
||||||
|
]
|
||||||
|
),
|
||||||
|
title: i18next.t('screenTabs:me.listDelete.heading'),
|
||||||
|
icon: 'trash'
|
||||||
|
})
|
@ -85,7 +85,7 @@ const Collections: React.FC = () => {
|
|||||||
iconFront='List'
|
iconFront='List'
|
||||||
iconBack='ChevronRight'
|
iconBack='ChevronRight'
|
||||||
title={t('me.stacks.lists.name')}
|
title={t('me.stacks.lists.name')}
|
||||||
onPress={() => navigation.navigate('Tab-Me-Lists')}
|
onPress={() => navigation.navigate('Tab-Me-List-List')}
|
||||||
/>
|
/>
|
||||||
) : null}
|
) : null}
|
||||||
{mePage.announcements.shown ? (
|
{mePage.announcements.shown ? (
|
||||||
|
@ -139,6 +139,7 @@ export type TabMeStackParamList = {
|
|||||||
'Tab-Me-Conversations': undefined
|
'Tab-Me-Conversations': undefined
|
||||||
'Tab-Me-Favourites': undefined
|
'Tab-Me-Favourites': undefined
|
||||||
'Tab-Me-List': Mastodon.List
|
'Tab-Me-List': Mastodon.List
|
||||||
|
'Tab-Me-List-Accounts': Omit<Mastodon.List, 'replies_policy'>
|
||||||
'Tab-Me-List-Edit':
|
'Tab-Me-List-Edit':
|
||||||
| {
|
| {
|
||||||
type: 'add'
|
type: 'add'
|
||||||
@ -148,7 +149,7 @@ export type TabMeStackParamList = {
|
|||||||
payload: Mastodon.List
|
payload: Mastodon.List
|
||||||
key: string // To update title after successful mutation
|
key: string // To update title after successful mutation
|
||||||
}
|
}
|
||||||
'Tab-Me-Lists': undefined
|
'Tab-Me-List-List': undefined
|
||||||
'Tab-Me-Profile': undefined
|
'Tab-Me-Profile': undefined
|
||||||
'Tab-Me-Push': undefined
|
'Tab-Me-Push': undefined
|
||||||
'Tab-Me-Settings': undefined
|
'Tab-Me-Settings': undefined
|
||||||
|
@ -1,6 +1,14 @@
|
|||||||
import apiInstance from '@api/instance'
|
import apiInstance, { InstanceResponse } from '@api/instance'
|
||||||
import { AxiosError } from 'axios'
|
import { AxiosError } from 'axios'
|
||||||
import { useMutation, UseMutationOptions, useQuery, UseQueryOptions } from 'react-query'
|
import {
|
||||||
|
QueryFunctionContext,
|
||||||
|
useInfiniteQuery,
|
||||||
|
UseInfiniteQueryOptions,
|
||||||
|
useMutation,
|
||||||
|
UseMutationOptions,
|
||||||
|
useQuery,
|
||||||
|
UseQueryOptions
|
||||||
|
} from 'react-query'
|
||||||
|
|
||||||
export type QueryKeyLists = ['Lists']
|
export type QueryKeyLists = ['Lists']
|
||||||
|
|
||||||
@ -53,10 +61,10 @@ const mutationFunction = async (params: MutationVarsLists) => {
|
|||||||
body
|
body
|
||||||
}).then(res => res.body)
|
}).then(res => res.body)
|
||||||
case 'delete':
|
case 'delete':
|
||||||
return apiInstance({
|
return apiInstance<{}>({
|
||||||
method: 'delete',
|
method: 'delete',
|
||||||
url: `lists/${params.payload.id}`
|
url: `lists/${params.payload.id}`
|
||||||
})
|
}).then(res => res.body)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -66,4 +74,54 @@ const useListsMutation = (
|
|||||||
return useMutation(mutationFunction, options)
|
return useMutation(mutationFunction, options)
|
||||||
}
|
}
|
||||||
|
|
||||||
export { useListsQuery, useListsMutation }
|
/* ----- */
|
||||||
|
|
||||||
|
export type QueryKeyListAccounts = ['ListAccounts', { id: Mastodon.List['id'] }]
|
||||||
|
|
||||||
|
const accountsQueryFunction = async ({
|
||||||
|
queryKey,
|
||||||
|
pageParam
|
||||||
|
}: QueryFunctionContext<QueryKeyListAccounts>) => {
|
||||||
|
const { id } = queryKey[1]
|
||||||
|
|
||||||
|
return await apiInstance<Mastodon.Account[]>({
|
||||||
|
method: 'get',
|
||||||
|
url: `lists/${id}/accounts`,
|
||||||
|
params: { ...pageParam, limit: 40 }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const useListAccountsQuery = ({
|
||||||
|
options,
|
||||||
|
...queryKeyParams
|
||||||
|
}: QueryKeyListAccounts[1] & {
|
||||||
|
options?: UseInfiniteQueryOptions<InstanceResponse<Mastodon.Account[]>, AxiosError>
|
||||||
|
}) => {
|
||||||
|
const queryKey: QueryKeyListAccounts = ['ListAccounts', queryKeyParams]
|
||||||
|
return useInfiniteQuery(queryKey, accountsQueryFunction, options)
|
||||||
|
}
|
||||||
|
|
||||||
|
type AccountsMutationVarsLists = {
|
||||||
|
type: 'add' | 'delete'
|
||||||
|
payload: Pick<Mastodon.List, 'id'> & { accounts: Mastodon.Account['id'][] }
|
||||||
|
}
|
||||||
|
|
||||||
|
const accountsMutationFunction = async (params: AccountsMutationVarsLists) => {
|
||||||
|
const body = new FormData()
|
||||||
|
for (const account of params.payload.accounts) {
|
||||||
|
body.append('account_ids[]', account)
|
||||||
|
}
|
||||||
|
return apiInstance<{}>({
|
||||||
|
method: params.type === 'add' ? 'post' : 'delete',
|
||||||
|
url: `lists/${params.payload.id}/accounts`,
|
||||||
|
body
|
||||||
|
}).then(res => res.body)
|
||||||
|
}
|
||||||
|
|
||||||
|
const useListAccountsMutation = (
|
||||||
|
options: UseMutationOptions<Mastodon.List, AxiosError, AccountsMutationVarsLists>
|
||||||
|
) => {
|
||||||
|
return useMutation(accountsMutationFunction, options)
|
||||||
|
}
|
||||||
|
|
||||||
|
export { useListsQuery, useListsMutation, useListAccountsQuery, useListAccountsMutation }
|
||||||
|
Loading…
x
Reference in New Issue
Block a user