mirror of
https://github.com/tooot-app/app
synced 2025-03-11 00:50:14 +01:00
Fix Sentry errors
This commit is contained in:
parent
44aff1f283
commit
3691b19a87
src
api
components
helpers
screens
utils
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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}`,
|
||||||
|
@ -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())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
@ -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: '',
|
||||||
|
@ -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: '',
|
||||||
|
@ -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':
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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)
|
||||||
|
@ -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':
|
||||||
|
@ -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
|
||||||
|
@ -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':
|
||||||
|
@ -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())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
|
@ -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']
|
||||||
|
@ -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()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -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 => {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user