Fix Sentry errors

This commit is contained in:
xmflsct 2022-12-16 22:00:22 +01:00
parent 44aff1f283
commit 3691b19a87
19 changed files with 85 additions and 74 deletions

View File

@ -54,12 +54,12 @@ const handleError =
console.error(ctx.bold(' API '), ctx.bold('request'), error) console.error(ctx.bold(' API '), ctx.bold('request'), error)
shouldReportToSentry && Sentry.captureMessage(config.message) shouldReportToSentry && Sentry.captureMessage(config.message)
return Promise.reject() return Promise.reject(error)
} else { } else {
console.error(ctx.bold(' API '), ctx.bold('internal'), error?.message) console.error(ctx.bold(' API '), ctx.bold('internal'), error?.message)
shouldReportToSentry && Sentry.captureMessage(config.message) shouldReportToSentry && Sentry.captureMessage(config.message)
return Promise.reject() return Promise.reject(error)
} }
} }

View File

@ -1,4 +1,3 @@
import * as Sentry from '@sentry/react-native'
import { mapEnvironment } from '@utils/checkEnvironment' import { mapEnvironment } from '@utils/checkEnvironment'
import axios from 'axios' import axios from 'axios'
import { ctx, handleError, userAgent } from './helpers' import { ctx, handleError, userAgent } from './helpers'
@ -37,7 +36,7 @@ const apiTooot = async <T = unknown>({
) )
return axios({ return axios({
timeout: method === 'post' ? 1000 * 60 : 1000 * 15, timeout: method === 'post' ? 1000 * 60 : 1000 * 30,
method, method,
baseURL: `https://${TOOOT_API_DOMAIN}/`, baseURL: `https://${TOOOT_API_DOMAIN}/`,
url: `${url}`, url: `${url}`,

View File

@ -276,7 +276,7 @@ const ComponentInstance: React.FC<Props> = ({
style={{ color: colors.blue }} style={{ color: colors.blue }}
onPress={async () => onPress={async () =>
WebBrowser.openBrowserAsync('https://tooot.app/privacy-policy', { WebBrowser.openBrowserAsync('https://tooot.app/privacy-policy', {
browserPackage: await browserPackage() ...(await browserPackage())
}) })
} }
/>, />,
@ -285,7 +285,7 @@ const ComponentInstance: React.FC<Props> = ({
style={{ color: colors.blue }} style={{ color: colors.blue }}
onPress={async () => onPress={async () =>
WebBrowser.openBrowserAsync('https://tooot.app/terms-of-service', { WebBrowser.openBrowserAsync('https://tooot.app/terms-of-service', {
browserPackage: await browserPackage() ...(await browserPackage())
}) })
} }
/> />

View File

@ -55,10 +55,10 @@ const TimelineDefault: React.FC<Props> = ({
const status = item.reblog ? item.reblog : item const status = item.reblog ? item.reblog : item
const ownAccount = status.account?.id === instanceAccount?.id const ownAccount = status.account?.id === instanceAccount?.id
const [spoilerExpanded, setSpoilerExpanded] = useState( const [spoilerExpanded, setSpoilerExpanded] = useState(
instanceAccount?.preferences['reading:expand:spoilers'] || false instanceAccount?.preferences?.['reading:expand:spoilers'] || false
) )
const spoilerHidden = status.spoiler_text?.length const spoilerHidden = status.spoiler_text?.length
? !instanceAccount?.preferences['reading:expand:spoilers'] && !spoilerExpanded ? !instanceAccount?.preferences?.['reading:expand:spoilers'] && !spoilerExpanded
: false : false
const copiableContent = useRef<{ content: string; complete: boolean }>({ const copiableContent = useRef<{ content: string; complete: boolean }>({
content: '', content: '',

View File

@ -42,10 +42,10 @@ const TimelineNotifications: React.FC<Props> = ({ notification, queryKey }) => {
: notification.account : notification.account
const ownAccount = notification.account?.id === instanceAccount?.id const ownAccount = notification.account?.id === instanceAccount?.id
const [spoilerExpanded, setSpoilerExpanded] = useState( const [spoilerExpanded, setSpoilerExpanded] = useState(
instanceAccount.preferences['reading:expand:spoilers'] || false instanceAccount.preferences?.['reading:expand:spoilers'] || false
) )
const spoilerHidden = notification.status?.spoiler_text?.length const spoilerHidden = notification.status?.spoiler_text?.length
? !instanceAccount.preferences['reading:expand:spoilers'] && !spoilerExpanded ? !instanceAccount.preferences?.['reading:expand:spoilers'] && !spoilerExpanded
: false : false
const copiableContent = useRef<{ content: string; complete: boolean }>({ const copiableContent = useRef<{ content: string; complete: boolean }>({
content: '', content: '',

View File

@ -31,10 +31,10 @@ const TimelineAttachment = () => {
const account = useSelector( const account = useSelector(
getInstanceAccount, getInstanceAccount,
(prev, next) => (prev, next) =>
prev.preferences['reading:expand:media'] === next.preferences['reading:expand:media'] prev.preferences?.['reading:expand:media'] === next.preferences?.['reading:expand:media']
) )
const defaultSensitive = () => { const defaultSensitive = () => {
switch (account.preferences['reading:expand:media']) { switch (account.preferences?.['reading:expand:media']) {
case 'show_all': case 'show_all':
return false return false
case 'hide_all': case 'hide_all':

View File

@ -47,7 +47,7 @@ const TimelineContent: React.FC<Props> = ({ notificationOwnToot = false, setSpoi
mentions={status.mentions} mentions={status.mentions}
tags={status.tags} tags={status.tags}
numberOfLines={ numberOfLines={
instanceAccount.preferences['reading:expand:spoilers'] || inThread instanceAccount.preferences?.['reading:expand:spoilers'] || inThread
? notificationOwnToot ? notificationOwnToot
? 2 ? 2
: 999 : 999

View File

@ -65,7 +65,7 @@ const TimelineHeaderNotification: React.FC<Props> = ({ notification }) => {
`https://${url}/admin/reports/${notification.report.id}`, `https://${url}/admin/reports/${notification.report.id}`,
'tooot://tooot', 'tooot://tooot',
{ {
browserPackage: await browserPackage(), ...(await browserPackage()),
dismissButtonStyle: 'done', dismissButtonStyle: 'done',
readerMode: false readerMode: false
} }

View File

@ -7,41 +7,40 @@ import { useTranslation } from 'react-i18next'
import { View } from 'react-native' import { View } from 'react-native'
export interface Props { export interface Props {
account: Mastodon.Account account?: Mastodon.Account
withoutName?: boolean // For notification follow request etc. withoutName?: boolean // For notification follow request etc.
} }
const HeaderSharedAccount = React.memo( const HeaderSharedAccount: React.FC<Props> = ({ account, withoutName = false }) => {
({ account, withoutName = false }: Props) => { if (!account) return null
const { t } = useTranslation('componentTimeline')
const { colors } = useTheme()
return ( const { t } = useTranslation('componentTimeline')
<View style={{ flexDirection: 'row', alignItems: 'center' }}> const { colors } = useTheme()
{withoutName ? null : (
<CustomText return (
accessibilityHint={t('shared.header.shared.account.name.accessibilityHint')} <View style={{ flexDirection: 'row', alignItems: 'center' }}>
style={{ marginRight: StyleConstants.Spacing.XS }} {withoutName ? null : (
numberOfLines={1}
>
<ParseEmojis
content={account?.display_name || account?.username}
emojis={account?.emojis}
fontBold
/>
</CustomText>
)}
<CustomText <CustomText
accessibilityHint={t('shared.header.shared.account.account.accessibilityHint')} accessibilityHint={t('shared.header.shared.account.name.accessibilityHint')}
style={{ flexShrink: 1, color: colors.secondary }} style={{ marginRight: StyleConstants.Spacing.XS }}
numberOfLines={1} numberOfLines={1}
> >
@{account.acct} <ParseEmojis
content={account.display_name || account.username}
emojis={account.emojis}
fontBold
/>
</CustomText> </CustomText>
</View> )}
) <CustomText
}, accessibilityHint={t('shared.header.shared.account.account.accessibilityHint')}
() => true style={{ flexShrink: 1, color: colors.secondary }}
) numberOfLines={1}
>
@{account.acct}
</CustomText>
</View>
)
}
export default HeaderSharedAccount export default HeaderSharedAccount

View File

@ -41,7 +41,7 @@ const menuAccount = ({
const menus: ContextMenu[][] = [[]] const menus: ContextMenu[][] = [[]]
const instanceAccount = useSelector(getInstanceAccount, (prev, next) => prev.id === next.id) const instanceAccount = useSelector(getInstanceAccount)
const ownAccount = instanceAccount?.id === account.id const ownAccount = instanceAccount?.id === account.id
const [enabled, setEnabled] = useState(openChange) const [enabled, setEnabled] = useState(openChange)

View File

@ -92,7 +92,7 @@ const openLink = async (url: string, navigation?: any) => {
await WebBrowser.openBrowserAsync(encodeURI(url), { await WebBrowser.openBrowserAsync(encodeURI(url), {
dismissButtonStyle: 'close', dismissButtonStyle: 'close',
enableBarCollapsing: true, enableBarCollapsing: true,
browserPackage: await browserPackage() ...(await browserPackage())
}) })
break break
case 'external': case 'external':

View File

@ -1,16 +1,18 @@
import * as WebBrowser from 'expo-web-browser' import * as WebBrowser from 'expo-web-browser'
import { Platform } from 'react-native' import { Platform } from 'react-native'
const browserPackage = async () => { const browserPackage = async (): Promise<{ browserPackage?: string }> => {
let browserPackage: string | undefined
if (Platform.OS === 'android') { if (Platform.OS === 'android') {
const tabsSupportingBrowsers = await WebBrowser.getCustomTabsSupportingBrowsersAsync() const tabsSupportingBrowsers = await WebBrowser.getCustomTabsSupportingBrowsersAsync()
browserPackage = return {
tabsSupportingBrowsers?.preferredBrowserPackage || browserPackage:
tabsSupportingBrowsers.browserPackages[0] || tabsSupportingBrowsers?.preferredBrowserPackage ||
tabsSupportingBrowsers.servicePackages[0] tabsSupportingBrowsers.browserPackages[0] ||
tabsSupportingBrowsers.servicePackages[0]
}
} else {
return {}
} }
return browserPackage
} }
export default browserPackage export default browserPackage

View File

@ -7,9 +7,8 @@ import { ComposeState } from './types'
const assignVisibility = ( const assignVisibility = (
target: ComposeState['visibility'] target: ComposeState['visibility']
): Pick<ComposeState, 'visibility' | 'visibilityLock'> => { ): Pick<ComposeState, 'visibility' | 'visibilityLock'> => {
const accountPreference = getInstanceAccount(store.getState())?.preferences[ const accountPreference =
'posting:default:visibility' getInstanceAccount(store.getState())?.preferences?.['posting:default:visibility'] || 'public'
]
switch (target) { switch (target) {
case 'direct': case 'direct':

View File

@ -179,7 +179,7 @@ const TabMePush: React.FC = () => {
iconBack='ExternalLink' iconBack='ExternalLink'
onPress={async () => onPress={async () =>
WebBrowser.openBrowserAsync('https://tooot.app/how-push-works', { WebBrowser.openBrowserAsync('https://tooot.app/how-push-works', {
browserPackage: await browserPackage() ...(await browserPackage())
}) })
} }
/> />

View File

@ -31,7 +31,7 @@ const Settings: React.FC = () => {
`https://${url}/settings/preferences`, `https://${url}/settings/preferences`,
'tooot://tooot', 'tooot://tooot',
{ {
browserPackage: await browserPackage(), ...(await browserPackage()),
dismissButtonStyle: 'done', dismissButtonStyle: 'done',
readerMode: false readerMode: false
} }

View File

@ -64,7 +64,7 @@ const SettingsTooot: React.FC = () => {
}) })
} else { } else {
WebBrowser.openBrowserAsync('https://social.xmflsct.com/@tooot', { WebBrowser.openBrowserAsync('https://social.xmflsct.com/@tooot', {
browserPackage: await browserPackage() ...(await browserPackage())
}) })
} }
}} }}

View File

@ -14,7 +14,7 @@ export type InstanceV11 = {
id: Mastodon.Account['id'] id: Mastodon.Account['id']
acct: Mastodon.Account['acct'] acct: Mastodon.Account['acct']
avatarStatic: Mastodon.Account['avatar_static'] avatarStatic: Mastodon.Account['avatar_static']
preferences: Mastodon.Preferences preferences?: Mastodon.Preferences
} }
version: string version: string
configuration?: Mastodon.Instance['configuration'] configuration?: Mastodon.Instance['configuration']

View File

@ -1,12 +1,13 @@
import apiGeneral from '@api/general' import apiGeneral from '@api/general'
import { handleError } from '@api/helpers'
import apiTooot from '@api/tooot' import apiTooot from '@api/tooot'
import { displayMessage } from '@components/Message' import { displayMessage } from '@components/Message'
import navigationRef from '@helpers/navigationRef' import navigationRef from '@helpers/navigationRef'
import { useAppDispatch } from '@root/store' import { useAppDispatch } from '@root/store'
import * as Sentry from '@sentry/react-native' import * as Sentry from '@sentry/react-native'
import { useQuery } from '@tanstack/react-query'
import { getExpoToken, retrieveExpoToken } from '@utils/slices/appSlice' import { getExpoToken, retrieveExpoToken } from '@utils/slices/appSlice'
import { disableAllPushes, getInstances } from '@utils/slices/instancesSlice' import { disableAllPushes, getInstances } from '@utils/slices/instancesSlice'
import { AxiosError } from 'axios'
import * as Notifications from 'expo-notifications' import * as Notifications from 'expo-notifications'
import { useEffect } from 'react' import { useEffect } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
@ -25,16 +26,22 @@ const pushUseConnect = () => {
const instances = useSelector(getInstances, (prev, next) => prev.length === next.length) const instances = useSelector(getInstances, (prev, next) => prev.length === next.length)
const pushEnabled = instances.filter(instance => instance.push.global) const pushEnabled = instances.filter(instance => instance.push.global)
const connect = () => { const connectQuery = useQuery<any, AxiosError>(
apiTooot({ ['tooot', { endpoint: 'push/connect' }],
method: 'get', () =>
url: `/push/connect/${expoToken}` apiTooot<Mastodon.Status>({
}) method: 'get',
.then(() => Notifications.setBadgeCountAsync(0)) url: `push/connect/${expoToken}`
.catch(error => { }),
handleError({ message: 'Push connect error', captureResponse: true }) {
enabled: false,
Notifications.setBadgeCountAsync(0) retry: 10,
retryOnMount: false,
refetchOnMount: false,
refetchOnWindowFocus: false,
refetchOnReconnect: false,
onSettled: () => Notifications.setBadgeCountAsync(0),
onError: error => {
if (error?.status == 404) { if (error?.status == 404) {
displayMessage({ displayMessage({
type: 'danger', type: 'danger',
@ -72,21 +79,22 @@ const pushUseConnect = () => {
} }
}) })
} }
}) }
} }
)
useEffect(() => { useEffect(() => {
Sentry.setContext('Push', { expoToken, pushEnabledCount: pushEnabled.length }) Sentry.setContext('Push', { expoToken, pushEnabledCount: pushEnabled.length })
if (expoToken && pushEnabled.length) { if (expoToken && pushEnabled.length) {
connect() connectQuery.refetch()
} }
const appStateListener = AppState.addEventListener('change', state => { const appStateListener = AppState.addEventListener('change', state => {
if (expoToken && pushEnabled.length && state === 'active') { if (expoToken && pushEnabled.length && state === 'active') {
Notifications.getBadgeCountAsync().then(count => { Notifications.getBadgeCountAsync().then(count => {
if (count > 0) { if (count > 0) {
connect() connectQuery.refetch()
} }
}) })
} }

View File

@ -220,7 +220,8 @@ const instancesSlice = createSlice({
// Update Instance Configuration // Update Instance Configuration
.addCase(updateConfiguration.fulfilled, (state, action) => { .addCase(updateConfiguration.fulfilled, (state, action) => {
const activeIndex = findInstanceActive(state.instances) const activeIndex = findInstanceActive(state.instances)
state.instances[activeIndex].version = action.payload?.version || '0' state.instances[activeIndex].version =
typeof action.payload.version === 'string' ? action.payload.version : '0'
state.instances[activeIndex].configuration = action.payload.configuration state.instances[activeIndex].configuration = action.payload.configuration
}) })
.addCase(updateConfiguration.rejected, (_, action) => { .addCase(updateConfiguration.rejected, (_, action) => {
@ -250,6 +251,9 @@ const instancesSlice = createSlice({
.addCase(checkEmojis.fulfilled, (state, action) => { .addCase(checkEmojis.fulfilled, (state, action) => {
if (!action.payload || !action.payload.length) return if (!action.payload || !action.payload.length) return
const activeIndex = findInstanceActive(state.instances) const activeIndex = findInstanceActive(state.instances)
if (!Array.isArray(state.instances[activeIndex].frequentEmojis)) {
state.instances[activeIndex].frequentEmojis = []
}
state.instances[activeIndex].frequentEmojis = state.instances[ state.instances[activeIndex].frequentEmojis = state.instances[
activeIndex activeIndex
]?.frequentEmojis?.filter(emoji => { ]?.frequentEmojis?.filter(emoji => {