tooot/src/components/Timelines/Timeline/Shared/HeaderDefault.tsx

329 lines
8.3 KiB
TypeScript
Raw Normal View History

2020-11-28 17:07:30 +01:00
import React, { useCallback, useEffect, useMemo, useState } from 'react'
import { Pressable, StyleSheet, Text, View } from 'react-native'
2020-10-31 21:04:46 +01:00
import { useNavigation } from '@react-navigation/native'
2020-11-06 18:40:14 +01:00
import { Feather } from '@expo/vector-icons'
import { useMutation, useQueryCache } from 'react-query'
2020-10-25 01:35:41 +02:00
import Emojis from './Emojis'
import relativeTime from 'src/utils/relativeTime'
2020-11-06 18:40:14 +01:00
import client from 'src/api/client'
2020-11-23 00:07:32 +01:00
import { getLocalAccountId, getLocalUrl } from 'src/utils/slices/instancesSlice'
import { useTheme } from 'src/utils/styles/ThemeManager'
2020-11-28 17:07:30 +01:00
import BottomSheet from 'src/components/BottomSheet'
import BottomSheetRow from 'src/components/BottomSheet/Row'
import { toast } from 'src/components/toast'
import { useSelector } from 'react-redux'
2020-11-30 00:24:53 +01:00
import { StyleConstants } from 'src/utils/styles/constants'
2020-11-06 18:40:14 +01:00
const fireMutation = async ({
id,
type,
stateKey
}: {
id: string
type: 'mute' | 'block' | 'domain_blocks' | 'reports'
stateKey?: 'muting' | 'blocking'
}) => {
let res
switch (type) {
case 'mute':
case 'block':
res = await client({
method: 'post',
instance: 'local',
endpoint: `accounts/${id}/${type}`
})
2020-11-28 17:07:30 +01:00
if (res.body[stateKey!] === true) {
toast({ type: 'success', content: '功能成功' })
2020-11-06 18:40:14 +01:00
return Promise.resolve()
} else {
2020-11-28 17:07:30 +01:00
toast({ type: 'error', content: '功能错误', autoHide: false })
2020-11-06 18:40:14 +01:00
return Promise.reject()
}
break
case 'domain_blocks':
res = await client({
method: 'post',
instance: 'local',
endpoint: `domain_blocks`,
query: {
domain: id || ''
}
})
if (!res.body.error) {
2020-11-28 17:07:30 +01:00
toast({ type: 'success', content: '隐藏域名成功' })
return Promise.resolve()
} else {
toast({
type: 'error',
content: '隐藏域名失败,请重试',
autoHide: false
2020-11-06 18:40:14 +01:00
})
2020-11-28 17:07:30 +01:00
return Promise.reject()
}
break
case 'reports':
console.log('reporting')
res = await client({
method: 'post',
instance: 'local',
endpoint: `reports`,
query: {
account_id: id || ''
}
})
console.log(res.body)
if (!res.body.error) {
toast({ type: 'success', content: '举报账户成功' })
2020-11-06 18:40:14 +01:00
return Promise.resolve()
} else {
2020-11-28 17:07:30 +01:00
toast({
2020-11-06 18:40:14 +01:00
type: 'error',
2020-11-28 17:07:30 +01:00
content: '举报账户失败,请重试',
autoHide: false
2020-11-06 18:40:14 +01:00
})
return Promise.reject()
}
break
}
}
2020-10-25 01:35:41 +02:00
2020-10-31 21:04:46 +01:00
export interface Props {
queryKey: App.QueryKey
2020-11-06 18:40:14 +01:00
accountId: string
domain: string
2020-10-31 21:04:46 +01:00
name: string
emojis?: Mastodon.Emoji[]
2020-10-31 21:04:46 +01:00
account: string
created_at: string
2020-11-29 18:08:31 +01:00
visibility: Mastodon.Status['visibility']
application?: Mastodon.Application
2020-10-31 21:04:46 +01:00
}
2020-11-23 00:07:32 +01:00
const HeaderDefault: React.FC<Props> = ({
2020-11-06 18:40:14 +01:00
queryKey,
accountId,
domain,
2020-10-25 01:35:41 +02:00
name,
emojis,
account,
created_at,
2020-11-29 18:08:31 +01:00
visibility,
2020-10-25 01:35:41 +02:00
application
2020-10-31 21:04:46 +01:00
}) => {
2020-11-23 00:07:32 +01:00
const { theme } = useTheme()
2020-10-31 21:04:46 +01:00
const navigation = useNavigation()
const localAccountId = useSelector(getLocalAccountId)
const localDomain = useSelector(getLocalUrl)
2020-10-25 01:35:41 +02:00
const [since, setSince] = useState(relativeTime(created_at))
2020-11-06 18:40:14 +01:00
const [modalVisible, setModalVisible] = useState(false)
const queryCache = useQueryCache()
const [mutateAction] = useMutation(fireMutation, {
onMutate: () => {
queryCache.cancelQueries(queryKey)
2020-11-28 17:07:30 +01:00
const oldData = queryCache.getQueryData(queryKey)
return oldData
2020-11-06 18:40:14 +01:00
},
2020-11-28 17:07:30 +01:00
onError: (err, _, oldData) => {
toast({ type: 'error', content: '请重试', autoHide: false })
queryCache.setQueryData(queryKey, oldData)
2020-11-06 18:40:14 +01:00
},
onSettled: () => {
queryCache.invalidateQueries(queryKey)
}
})
2020-10-25 01:35:41 +02:00
2020-10-28 00:02:37 +01:00
// causing full re-render
2020-10-25 01:35:41 +02:00
useEffect(() => {
2020-10-26 00:27:53 +01:00
setTimeout(() => {
2020-10-25 01:35:41 +02:00
setSince(relativeTime(created_at))
}, 1000)
2020-10-28 00:02:37 +01:00
}, [since])
2020-10-25 01:35:41 +02:00
2020-11-28 17:07:30 +01:00
const onPressAction = useCallback(() => setModalVisible(true), [])
const onPressApplication = useCallback(() => {
navigation.navigate('Webview', {
uri: application!.website
})
}, [])
const pressableAction = useMemo(
() => (
<Feather
name='more-horizontal'
color={theme.secondary}
2020-11-30 00:24:53 +01:00
size={StyleConstants.Font.Size.M + 2}
2020-11-28 17:07:30 +01:00
/>
),
[]
)
2020-10-25 01:35:41 +02:00
return (
<View>
2020-11-06 18:40:14 +01:00
<View style={styles.nameAndAction}>
2020-10-25 01:35:41 +02:00
<View style={styles.name}>
2020-12-01 00:44:28 +01:00
{emojis?.length ? (
2020-11-23 00:07:32 +01:00
<Emojis
content={name}
emojis={emojis}
2020-11-30 00:24:53 +01:00
size={StyleConstants.Font.Size.M}
2020-11-23 00:07:32 +01:00
fontBold={true}
/>
2020-10-31 21:04:46 +01:00
) : (
2020-12-01 00:44:28 +01:00
<Text
numberOfLines={1}
style={[styles.nameWithoutEmoji, { color: theme.primary }]}
>
2020-11-23 00:07:32 +01:00
{name}
</Text>
2020-10-31 21:04:46 +01:00
)}
2020-11-23 00:07:32 +01:00
<Text
style={[styles.account, { color: theme.secondary }]}
numberOfLines={1}
>
@{account}
</Text>
2020-10-25 01:35:41 +02:00
</View>
2020-11-28 17:07:30 +01:00
{(accountId !== localAccountId || domain !== localDomain) && (
2020-11-06 18:40:14 +01:00
<Pressable
style={styles.action}
2020-11-28 17:07:30 +01:00
onPress={onPressAction}
children={pressableAction}
/>
2020-11-06 18:40:14 +01:00
)}
2020-10-25 01:35:41 +02:00
</View>
2020-12-01 00:44:28 +01:00
2020-10-25 01:35:41 +02:00
<View style={styles.meta}>
<View>
2020-11-23 00:07:32 +01:00
<Text style={[styles.created_at, { color: theme.secondary }]}>
{since}
</Text>
2020-10-25 01:35:41 +02:00
</View>
2020-11-29 18:08:31 +01:00
{visibility === 'private' && (
<Feather
name='lock'
2020-11-30 00:24:53 +01:00
size={StyleConstants.Font.Size.S}
2020-11-29 18:08:31 +01:00
color={theme.secondary}
style={styles.visibility}
/>
)}
2020-10-25 01:35:41 +02:00
{application && application.name !== 'Web' && (
<View>
<Text
2020-11-28 17:07:30 +01:00
onPress={onPressApplication}
2020-11-23 00:07:32 +01:00
style={[styles.application, { color: theme.secondary }]}
2020-10-25 01:35:41 +02:00
>
2020-11-23 00:07:32 +01:00
- {application.name}
2020-10-25 01:35:41 +02:00
</Text>
</View>
)}
</View>
2020-11-28 17:07:30 +01:00
<BottomSheet
2020-11-06 18:40:14 +01:00
visible={modalVisible}
2020-11-28 17:07:30 +01:00
handleDismiss={() => setModalVisible(false)}
2020-11-06 18:40:14 +01:00
>
2020-11-28 17:07:30 +01:00
{accountId !== localAccountId && (
<BottomSheetRow
2020-12-01 00:44:28 +01:00
onPress={() => {
2020-11-28 17:07:30 +01:00
setModalVisible(false)
mutateAction({
id: accountId,
type: 'mute',
stateKey: 'muting'
})
}}
icon='eye-off'
text={`隐藏 @${account} 的嘟嘟`}
/>
)}
{accountId !== localAccountId && (
<BottomSheetRow
2020-12-01 00:44:28 +01:00
onPress={() => {
2020-11-28 17:07:30 +01:00
setModalVisible(false)
mutateAction({
id: accountId,
type: 'block',
stateKey: 'blocking'
})
}}
icon='x-circle'
text={`屏蔽用户 @${account}`}
/>
)}
{domain !== localDomain && (
<BottomSheetRow
2020-12-01 00:44:28 +01:00
onPress={() => {
2020-11-28 17:07:30 +01:00
setModalVisible(false)
mutateAction({
id: domain,
type: 'domain_blocks'
})
}}
icon='cloud-off'
text={`屏蔽域名 ${domain}`}
/>
)}
{accountId !== localAccountId && (
<BottomSheetRow
2020-12-01 00:44:28 +01:00
onPress={() => {
2020-11-28 17:07:30 +01:00
setModalVisible(false)
mutateAction({
id: accountId,
type: 'reports'
})
}}
icon='alert-triangle'
text={`举报 @${account}`}
/>
)}
</BottomSheet>
2020-10-25 01:35:41 +02:00
</View>
)
}
const styles = StyleSheet.create({
2020-11-06 18:40:14 +01:00
nameAndAction: {
width: '100%',
flexDirection: 'row',
justifyContent: 'space-between'
2020-10-25 01:35:41 +02:00
},
name: {
2020-12-01 00:44:28 +01:00
flexBasis: '90%',
2020-11-23 00:07:32 +01:00
flexDirection: 'row'
2020-11-06 18:40:14 +01:00
},
2020-12-01 00:44:28 +01:00
nameWithoutEmoji: {
fontSize: StyleConstants.Font.Size.M,
fontWeight: StyleConstants.Font.Weight.Bold
},
2020-11-06 18:40:14 +01:00
action: {
2020-12-01 00:44:28 +01:00
alignItems: 'flex-end'
2020-10-25 01:35:41 +02:00
},
account: {
2020-11-23 00:07:32 +01:00
flexShrink: 1,
2020-12-01 00:44:28 +01:00
marginLeft: StyleConstants.Spacing.XS
// lineHeight: StyleConstants.Font.LineHeight.M
2020-10-25 01:35:41 +02:00
},
meta: {
2020-11-23 00:07:32 +01:00
flexDirection: 'row',
2020-11-29 18:08:31 +01:00
alignItems: 'center',
2020-11-30 00:24:53 +01:00
marginTop: StyleConstants.Spacing.XS,
marginBottom: StyleConstants.Spacing.S
2020-10-25 01:35:41 +02:00
},
created_at: {
2020-11-30 00:24:53 +01:00
fontSize: StyleConstants.Font.Size.S
2020-10-25 01:35:41 +02:00
},
2020-11-29 18:08:31 +01:00
visibility: {
2020-11-30 00:24:53 +01:00
marginLeft: StyleConstants.Spacing.S
2020-11-29 18:08:31 +01:00
},
2020-10-25 01:35:41 +02:00
application: {
2020-11-30 00:24:53 +01:00
fontSize: StyleConstants.Font.Size.S,
marginLeft: StyleConstants.Spacing.S
2020-10-25 01:35:41 +02:00
}
})
2020-11-28 17:07:30 +01:00
export default React.memo(HeaderDefault, () => true)