Activity notification public preference settings (#8504)
This commit is contained in:
@@ -84,6 +84,7 @@ import {SearchScreen} from '#/screens/Search'
|
||||
import {AboutSettingsScreen} from '#/screens/Settings/AboutSettings'
|
||||
import {AccessibilitySettingsScreen} from '#/screens/Settings/AccessibilitySettings'
|
||||
import {AccountSettingsScreen} from '#/screens/Settings/AccountSettings'
|
||||
import {ActivityPrivacySettingsScreen} from '#/screens/Settings/ActivityPrivacySettings'
|
||||
import {AppearanceSettingsScreen} from '#/screens/Settings/AppearanceSettings'
|
||||
import {AppIconSettingsScreen} from '#/screens/Settings/AppIconSettings'
|
||||
import {AppPasswordsScreen} from '#/screens/Settings/AppPasswords'
|
||||
@@ -391,6 +392,14 @@ function commonScreens(Stack: typeof Flat, unreadCountLabel?: string) {
|
||||
requireAuth: true,
|
||||
}}
|
||||
/>
|
||||
<Stack.Screen
|
||||
name="ActivityPrivacySettings"
|
||||
getComponent={() => ActivityPrivacySettingsScreen}
|
||||
options={{
|
||||
title: title(msg`Privacy and Security`),
|
||||
requireAuth: true,
|
||||
}}
|
||||
/>
|
||||
<Stack.Screen
|
||||
name="NotificationSettings"
|
||||
getComponent={() => NotificationSettingsScreen}
|
||||
|
||||
@@ -51,6 +51,7 @@ export type CommonNavigatorParams = {
|
||||
AppearanceSettings: undefined
|
||||
AccountSettings: undefined
|
||||
PrivacyAndSecuritySettings: undefined
|
||||
ActivityPrivacySettings: undefined
|
||||
ContentAndMediaSettings: undefined
|
||||
NotificationSettings: undefined
|
||||
ReplyNotificationSettings: undefined
|
||||
|
||||
@@ -50,6 +50,7 @@ export const router = new Router<AllNavigatableRoutes>({
|
||||
SavedFeeds: '/settings/saved-feeds',
|
||||
AccountSettings: '/settings/account',
|
||||
PrivacyAndSecuritySettings: '/settings/privacy-and-security',
|
||||
ActivityPrivacySettings: '/settings/privacy-and-security/activity',
|
||||
ContentAndMediaSettings: '/settings/content-and-media',
|
||||
InterestsSettings: '/settings/interests',
|
||||
AboutSettings: '/settings/about',
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import {msg, Trans} from '@lingui/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
import {NativeStackScreenProps} from '@react-navigation/native-stack'
|
||||
import {type NativeStackScreenProps} from '@react-navigation/native-stack'
|
||||
|
||||
import {CommonNavigatorParams} from '#/lib/routes/types'
|
||||
import {type CommonNavigatorParams} from '#/lib/routes/types'
|
||||
import {isNative} from '#/platform/detection'
|
||||
import {
|
||||
useHapticsDisabled,
|
||||
@@ -16,12 +16,10 @@ import {
|
||||
} from '#/state/preferences/large-alt-badge'
|
||||
import * as SettingsList from '#/screens/Settings/components/SettingsList'
|
||||
import {atoms as a} from '#/alf'
|
||||
import {Admonition} from '#/components/Admonition'
|
||||
import * as Toggle from '#/components/forms/Toggle'
|
||||
import {Accessibility_Stroke2_Corner2_Rounded as AccessibilityIcon} from '#/components/icons/Accessibility'
|
||||
import {Haptic_Stroke2_Corner2_Rounded as HapticIcon} from '#/components/icons/Haptic'
|
||||
import * as Layout from '#/components/Layout'
|
||||
import {InlineLinkText} from '#/components/Link'
|
||||
|
||||
type Props = NativeStackScreenProps<
|
||||
CommonNavigatorParams,
|
||||
@@ -100,19 +98,6 @@ export function AccessibilitySettingsScreen({}: Props) {
|
||||
</SettingsList.Group>
|
||||
</>
|
||||
)}
|
||||
<SettingsList.Item>
|
||||
<Admonition type="info" style={[a.flex_1]}>
|
||||
<Trans>
|
||||
Autoplay options have moved to the{' '}
|
||||
<InlineLinkText
|
||||
to="/settings/content-and-media"
|
||||
label={_(msg`Content and media`)}>
|
||||
Content and Media settings
|
||||
</InlineLinkText>
|
||||
.
|
||||
</Trans>
|
||||
</Admonition>
|
||||
</SettingsList.Item>
|
||||
</SettingsList.Container>
|
||||
</Layout.Content>
|
||||
</Layout.Screen>
|
||||
|
||||
@@ -0,0 +1,138 @@
|
||||
import {View} from 'react-native'
|
||||
import {type AppBskyNotificationDeclaration} from '@atproto/api'
|
||||
import {msg, Trans} from '@lingui/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
|
||||
import {
|
||||
type AllNavigatorParams,
|
||||
type NativeStackScreenProps,
|
||||
} from '#/lib/routes/types'
|
||||
import {
|
||||
useNotificationDeclarationMutation,
|
||||
useNotificationDeclarationQuery,
|
||||
} from '#/state/queries/activity-subscriptions'
|
||||
import {atoms as a, useTheme} from '#/alf'
|
||||
import {Admonition} from '#/components/Admonition'
|
||||
import * as Toggle from '#/components/forms/Toggle'
|
||||
import {BellRinging_Stroke2_Corner0_Rounded as BellRingingIcon} from '#/components/icons/BellRinging'
|
||||
import * as Layout from '#/components/Layout'
|
||||
import {Loader} from '#/components/Loader'
|
||||
import * as SettingsList from './components/SettingsList'
|
||||
import {ItemTextWithSubtitle} from './NotificationSettings/components/ItemTextWithSubtitle'
|
||||
|
||||
type Props = NativeStackScreenProps<
|
||||
AllNavigatorParams,
|
||||
'ActivityPrivacySettings'
|
||||
>
|
||||
export function ActivityPrivacySettingsScreen({}: Props) {
|
||||
const {
|
||||
data: notificationDeclaration,
|
||||
isPending,
|
||||
isError,
|
||||
} = useNotificationDeclarationQuery()
|
||||
|
||||
return (
|
||||
<Layout.Screen>
|
||||
<Layout.Header.Outer>
|
||||
<Layout.Header.BackButton />
|
||||
<Layout.Header.Content>
|
||||
<Layout.Header.TitleText>
|
||||
<Trans>Privacy and Security</Trans>
|
||||
</Layout.Header.TitleText>
|
||||
</Layout.Header.Content>
|
||||
<Layout.Header.Slot />
|
||||
</Layout.Header.Outer>
|
||||
<Layout.Content>
|
||||
<SettingsList.Container>
|
||||
<SettingsList.Item style={[a.align_start]}>
|
||||
<SettingsList.ItemIcon icon={BellRingingIcon} />
|
||||
<ItemTextWithSubtitle
|
||||
bold
|
||||
titleText={
|
||||
<Trans>Allow others to get notified of your posts</Trans>
|
||||
}
|
||||
subtitleText={
|
||||
<Trans>
|
||||
This feature allows users to receive notifications for your
|
||||
new posts and replies. Who do you want to enable this for?
|
||||
</Trans>
|
||||
}
|
||||
/>
|
||||
</SettingsList.Item>
|
||||
<View style={[a.px_xl, a.pt_md]}>
|
||||
{isError ? (
|
||||
<Admonition type="error">
|
||||
<Trans>Failed to load preference.</Trans>
|
||||
</Admonition>
|
||||
) : isPending ? (
|
||||
<View style={[a.w_full, a.pt_5xl, a.align_center]}>
|
||||
<Loader size="xl" />
|
||||
</View>
|
||||
) : (
|
||||
<Inner notificationDeclaration={notificationDeclaration} />
|
||||
)}
|
||||
</View>
|
||||
</SettingsList.Container>
|
||||
</Layout.Content>
|
||||
</Layout.Screen>
|
||||
)
|
||||
}
|
||||
|
||||
export function Inner({
|
||||
notificationDeclaration,
|
||||
}: {
|
||||
notificationDeclaration: {
|
||||
uri?: string
|
||||
cid?: string
|
||||
value: AppBskyNotificationDeclaration.Record
|
||||
}
|
||||
}) {
|
||||
const t = useTheme()
|
||||
const {_} = useLingui()
|
||||
const {mutate} = useNotificationDeclarationMutation()
|
||||
|
||||
const onChangeFilter = ([declaration]: string[]) => {
|
||||
mutate({
|
||||
$type: 'app.bsky.notification.declaration',
|
||||
allowSubscriptions: declaration,
|
||||
})
|
||||
}
|
||||
|
||||
return (
|
||||
<Toggle.Group
|
||||
type="radio"
|
||||
label={_('Filter who can opt to receive notifications for your activity')}
|
||||
values={[notificationDeclaration.value.allowSubscriptions]}
|
||||
onChange={onChangeFilter}>
|
||||
<View style={[a.gap_sm]}>
|
||||
<Toggle.Item
|
||||
label={_(msg`Anyone who follows me`)}
|
||||
name="followers"
|
||||
style={[a.flex_row, a.py_xs, a.gap_sm]}>
|
||||
<Toggle.Radio />
|
||||
<Toggle.LabelText style={[t.atoms.text, a.font_normal, a.text_md]}>
|
||||
<Trans>Anyone who follows me</Trans>
|
||||
</Toggle.LabelText>
|
||||
</Toggle.Item>
|
||||
<Toggle.Item
|
||||
label={_(msg`Only followers who I follow`)}
|
||||
name="mutuals"
|
||||
style={[a.flex_row, a.py_xs, a.gap_sm]}>
|
||||
<Toggle.Radio />
|
||||
<Toggle.LabelText style={[t.atoms.text, a.font_normal, a.text_md]}>
|
||||
<Trans>Only followers who I follow</Trans>
|
||||
</Toggle.LabelText>
|
||||
</Toggle.Item>
|
||||
<Toggle.Item
|
||||
label={_(msg`No one`)}
|
||||
name="none"
|
||||
style={[a.flex_row, a.py_xs, a.gap_sm]}>
|
||||
<Toggle.Radio />
|
||||
<Toggle.LabelText style={[t.atoms.text, a.font_normal, a.text_md]}>
|
||||
<Trans>No one</Trans>
|
||||
</Toggle.LabelText>
|
||||
</Toggle.Item>
|
||||
</View>
|
||||
</Toggle.Group>
|
||||
)
|
||||
}
|
||||
@@ -7,12 +7,12 @@ import Animated, {
|
||||
LinearTransition,
|
||||
StretchOutY,
|
||||
} from 'react-native-reanimated'
|
||||
import {ComAtprotoServerListAppPasswords} from '@atproto/api'
|
||||
import {type ComAtprotoServerListAppPasswords} from '@atproto/api'
|
||||
import {msg, Trans} from '@lingui/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
import {NativeStackScreenProps} from '@react-navigation/native-stack'
|
||||
import {type NativeStackScreenProps} from '@react-navigation/native-stack'
|
||||
|
||||
import {CommonNavigatorParams} from '#/lib/routes/types'
|
||||
import {type CommonNavigatorParams} from '#/lib/routes/types'
|
||||
import {cleanError} from '#/lib/strings/errors'
|
||||
import {isWeb} from '#/platform/detection'
|
||||
import {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, {useCallback} from 'react'
|
||||
import {useCallback} from 'react'
|
||||
import Animated, {
|
||||
FadeInUp,
|
||||
FadeOutUp,
|
||||
@@ -9,14 +9,17 @@ import {msg, Trans} from '@lingui/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
|
||||
import {IS_INTERNAL} from '#/lib/app-info'
|
||||
import {CommonNavigatorParams, NativeStackScreenProps} from '#/lib/routes/types'
|
||||
import {
|
||||
type CommonNavigatorParams,
|
||||
type NativeStackScreenProps,
|
||||
} from '#/lib/routes/types'
|
||||
import {useGate} from '#/lib/statsig/statsig'
|
||||
import {isNative} from '#/platform/detection'
|
||||
import {useSetThemePrefs, useThemePrefs} from '#/state/shell'
|
||||
import {SettingsListItem as AppIconSettingsListItem} from '#/screens/Settings/AppIconSettings/SettingsListItem'
|
||||
import {atoms as a, native, useAlf, useTheme} from '#/alf'
|
||||
import * as ToggleButton from '#/components/forms/ToggleButton'
|
||||
import {Props as SVGIconProps} from '#/components/icons/common'
|
||||
import {type Props as SVGIconProps} from '#/components/icons/common'
|
||||
import {Moon_Stroke2_Corner0_Rounded as MoonIcon} from '#/components/icons/Moon'
|
||||
import {Phone_Stroke2_Corner0_Rounded as PhoneIcon} from '#/components/icons/Phone'
|
||||
import {TextSize_Stroke2_Corner0_Rounded as TextSize} from '#/components/icons/TextSize'
|
||||
|
||||
@@ -2,9 +2,12 @@ import {Fragment} from 'react'
|
||||
import {View} from 'react-native'
|
||||
import {Trans} from '@lingui/macro'
|
||||
|
||||
import {CommonNavigatorParams, NativeStackScreenProps} from '#/lib/routes/types'
|
||||
import {
|
||||
EmbedPlayerSource,
|
||||
type CommonNavigatorParams,
|
||||
type NativeStackScreenProps,
|
||||
} from '#/lib/routes/types'
|
||||
import {
|
||||
type EmbedPlayerSource,
|
||||
externalEmbedLabels,
|
||||
} from '#/lib/strings/embed-player'
|
||||
import {
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
import {msg, Trans} from '@lingui/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
|
||||
import {CommonNavigatorParams, NativeStackScreenProps} from '#/lib/routes/types'
|
||||
import {
|
||||
type CommonNavigatorParams,
|
||||
type NativeStackScreenProps,
|
||||
} from '#/lib/routes/types'
|
||||
import {
|
||||
usePreferencesQuery,
|
||||
useSetFeedViewPreferencesMutation,
|
||||
|
||||
@@ -114,7 +114,7 @@ export function Inner({
|
||||
a.py_xs,
|
||||
platform({
|
||||
native: [a.justify_between],
|
||||
web: [a.flex_row_reverse, a.gap_md],
|
||||
web: [a.flex_row_reverse, a.gap_sm],
|
||||
}),
|
||||
]}>
|
||||
<Toggle.LabelText
|
||||
@@ -131,7 +131,7 @@ export function Inner({
|
||||
a.py_xs,
|
||||
platform({
|
||||
native: [a.justify_between],
|
||||
web: [a.flex_row_reverse, a.gap_md],
|
||||
web: [a.flex_row_reverse, a.gap_sm],
|
||||
}),
|
||||
]}>
|
||||
<Toggle.LabelText
|
||||
@@ -159,11 +159,7 @@ export function Inner({
|
||||
<Toggle.Item
|
||||
label={_(msg`Everyone`)}
|
||||
name="all"
|
||||
style={[
|
||||
a.flex_row,
|
||||
a.py_xs,
|
||||
platform({native: [a.gap_sm], web: [a.gap_md]}),
|
||||
]}>
|
||||
style={[a.flex_row, a.py_xs, a.gap_sm]}>
|
||||
<Toggle.Radio />
|
||||
<Toggle.LabelText
|
||||
style={[
|
||||
@@ -177,11 +173,7 @@ export function Inner({
|
||||
<Toggle.Item
|
||||
label={_(msg`People I follow`)}
|
||||
name="follows"
|
||||
style={[
|
||||
a.flex_row,
|
||||
a.py_xs,
|
||||
platform({native: [a.gap_sm], web: [a.gap_md]}),
|
||||
]}>
|
||||
style={[a.flex_row, a.py_xs, a.gap_sm]}>
|
||||
<Toggle.Radio />
|
||||
<Toggle.LabelText
|
||||
style={[
|
||||
|
||||
@@ -188,7 +188,6 @@ export function NotificationSettingsScreen({}: Props) {
|
||||
to={{screen: 'ActivityNotificationSettings'}}
|
||||
contentContainerStyle={[a.align_start]}>
|
||||
<SettingsList.ItemIcon icon={BellRingingIcon} />
|
||||
|
||||
<ItemTextWithSubtitle
|
||||
titleText={<Trans>Activity from others</Trans>}
|
||||
subtitleText={
|
||||
|
||||
@@ -1,14 +1,17 @@
|
||||
import {View} from 'react-native'
|
||||
import {type AppBskyNotificationDeclaration} from '@atproto/api'
|
||||
import {msg, Trans} from '@lingui/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
import {type NativeStackScreenProps} from '@react-navigation/native-stack'
|
||||
|
||||
import {type CommonNavigatorParams} from '#/lib/routes/types'
|
||||
import {useNotificationDeclarationQuery} from '#/state/queries/activity-subscriptions'
|
||||
import {useAppPasswordsQuery} from '#/state/queries/app-passwords'
|
||||
import {useSession} from '#/state/session'
|
||||
import * as SettingsList from '#/screens/Settings/components/SettingsList'
|
||||
import {atoms as a, useTheme} from '#/alf'
|
||||
import * as Admonition from '#/components/Admonition'
|
||||
import {BellRinging_Stroke2_Corner0_Rounded as BellRingingIcon} from '#/components/icons/BellRinging'
|
||||
import {EyeSlash_Stroke2_Corner0_Rounded as EyeSlashIcon} from '#/components/icons/EyeSlash'
|
||||
import {Key_Stroke2_Corner2_Rounded as KeyIcon} from '#/components/icons/Key'
|
||||
import {ShieldCheck_Stroke2_Corner0_Rounded as ShieldIcon} from '#/components/icons/Shield'
|
||||
@@ -16,6 +19,7 @@ import * as Layout from '#/components/Layout'
|
||||
import {InlineLinkText} from '#/components/Link'
|
||||
import {Email2FAToggle} from './components/Email2FAToggle'
|
||||
import {PwiOptOut} from './components/PwiOptOut'
|
||||
import {ItemTextWithSubtitle} from './NotificationSettings/components/ItemTextWithSubtitle'
|
||||
|
||||
type Props = NativeStackScreenProps<
|
||||
CommonNavigatorParams,
|
||||
@@ -26,6 +30,11 @@ export function PrivacyAndSecuritySettingsScreen({}: Props) {
|
||||
const t = useTheme()
|
||||
const {data: appPasswords} = useAppPasswordsQuery()
|
||||
const {currentAccount} = useSession()
|
||||
const {
|
||||
data: notificationDeclaration,
|
||||
isPending,
|
||||
isError,
|
||||
} = useNotificationDeclarationQuery()
|
||||
|
||||
return (
|
||||
<Layout.Screen>
|
||||
@@ -71,6 +80,22 @@ export function PrivacyAndSecuritySettingsScreen({}: Props) {
|
||||
</SettingsList.BadgeText>
|
||||
)}
|
||||
</SettingsList.LinkItem>
|
||||
<SettingsList.LinkItem
|
||||
label={_(msg`Settings for activity alerts`)}
|
||||
to={{screen: 'ActivityPrivacySettings'}}
|
||||
contentContainerStyle={[a.align_start]}>
|
||||
<SettingsList.ItemIcon icon={BellRingingIcon} />
|
||||
<ItemTextWithSubtitle
|
||||
titleText={<Trans>Allow others get notified of your posts</Trans>}
|
||||
subtitleText={
|
||||
<NotificationDeclaration
|
||||
data={notificationDeclaration}
|
||||
isError={isError}
|
||||
/>
|
||||
}
|
||||
showSkeleton={isPending}
|
||||
/>
|
||||
</SettingsList.LinkItem>
|
||||
<SettingsList.Divider />
|
||||
<SettingsList.Group>
|
||||
<SettingsList.ItemIcon icon={EyeSlashIcon} />
|
||||
@@ -111,3 +136,26 @@ export function PrivacyAndSecuritySettingsScreen({}: Props) {
|
||||
</Layout.Screen>
|
||||
)
|
||||
}
|
||||
|
||||
function NotificationDeclaration({
|
||||
data,
|
||||
isError,
|
||||
}: {
|
||||
data?: {
|
||||
value: AppBskyNotificationDeclaration.Record
|
||||
}
|
||||
isError?: boolean
|
||||
}) {
|
||||
if (isError) {
|
||||
return <Trans>Error loading preference</Trans>
|
||||
}
|
||||
switch (data?.value?.allowSubscriptions) {
|
||||
case 'mutuals':
|
||||
return <Trans>Only people you follow</Trans>
|
||||
case 'none':
|
||||
return <Trans>No one</Trans>
|
||||
case 'followers':
|
||||
default:
|
||||
return <Trans>Only your followers</Trans>
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ import {LayoutAnimation, Pressable, View} from 'react-native'
|
||||
import {Linking} from 'react-native'
|
||||
import {useReducedMotion} from 'react-native-reanimated'
|
||||
import {type AppBskyActorDefs, moderateProfile} from '@atproto/api'
|
||||
import {msg, t, Trans} from '@lingui/macro'
|
||||
import {msg, Trans} from '@lingui/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
import {useNavigation} from '@react-navigation/native'
|
||||
import {type NativeStackScreenProps} from '@react-navigation/native-stack'
|
||||
@@ -384,7 +384,7 @@ function DevOptions() {
|
||||
...persisted.get('reminders'),
|
||||
lastEmailConfirm: lastEmailConfirm.toISOString(),
|
||||
})
|
||||
Toast.show(t`You probably want to restart the app now.`)
|
||||
Toast.show(_(msg`You probably want to restart the app now.`))
|
||||
}
|
||||
|
||||
return (
|
||||
|
||||
@@ -1,15 +1,20 @@
|
||||
import React, {useContext, useMemo} from 'react'
|
||||
import {GestureResponderEvent, StyleProp, View, ViewStyle} from 'react-native'
|
||||
import {createContext, useContext, useMemo} from 'react'
|
||||
import {
|
||||
type GestureResponderEvent,
|
||||
type StyleProp,
|
||||
View,
|
||||
type ViewStyle,
|
||||
} from 'react-native'
|
||||
|
||||
import {HITSLOP_10} from '#/lib/constants'
|
||||
import {atoms as a, useTheme, ViewStyleProp} from '#/alf'
|
||||
import {atoms as a, useTheme, type ViewStyleProp} from '#/alf'
|
||||
import * as Button from '#/components/Button'
|
||||
import {ChevronRight_Stroke2_Corner0_Rounded as ChevronRightIcon} from '#/components/icons/Chevron'
|
||||
import {Link, LinkProps} from '#/components/Link'
|
||||
import {Link, type LinkProps} from '#/components/Link'
|
||||
import {createPortalGroup} from '#/components/Portal'
|
||||
import {Text} from '#/components/Typography'
|
||||
|
||||
const ItemContext = React.createContext({
|
||||
const ItemContext = createContext({
|
||||
destructive: false,
|
||||
withinGroup: false,
|
||||
})
|
||||
@@ -91,7 +96,7 @@ export function Item({
|
||||
a.px_xl,
|
||||
a.py_sm,
|
||||
a.align_center,
|
||||
a.gap_md,
|
||||
a.gap_sm,
|
||||
a.w_full,
|
||||
a.flex_row,
|
||||
{minHeight: 48},
|
||||
@@ -100,9 +105,9 @@ export function Item({
|
||||
// existing padding
|
||||
a.pl_xl.paddingLeft +
|
||||
// icon
|
||||
28 +
|
||||
24 +
|
||||
// gap
|
||||
a.gap_md.gap,
|
||||
a.gap_sm.gap,
|
||||
},
|
||||
style,
|
||||
]}>
|
||||
@@ -175,7 +180,7 @@ export function PressableItem({
|
||||
|
||||
export function ItemIcon({
|
||||
icon: Comp,
|
||||
size = 'xl',
|
||||
size = 'lg',
|
||||
color: colorProp,
|
||||
}: Omit<React.ComponentProps<typeof Button.ButtonIcon>, 'position'> & {
|
||||
color?: string
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
import {type AppBskyNotificationDeclaration} from '@atproto/api'
|
||||
import {t} from '@lingui/macro'
|
||||
import {useMutation, useQuery, useQueryClient} from '@tanstack/react-query'
|
||||
|
||||
import {useAgent, useSession} from '#/state/session'
|
||||
import * as Toast from '#/view/com/util/Toast'
|
||||
|
||||
const RQKEY_getNotificationDeclaration = ['notification-declaration']
|
||||
|
||||
export function useNotificationDeclarationQuery() {
|
||||
const agent = useAgent()
|
||||
const {currentAccount} = useSession()
|
||||
return useQuery({
|
||||
queryKey: RQKEY_getNotificationDeclaration,
|
||||
queryFn: async () => {
|
||||
try {
|
||||
const response = await agent.app.bsky.notification.declaration.get({
|
||||
repo: currentAccount!.did,
|
||||
rkey: 'self',
|
||||
})
|
||||
return response
|
||||
} catch (err) {
|
||||
if (
|
||||
err instanceof Error &&
|
||||
err.message.startsWith('Could not locate record')
|
||||
) {
|
||||
return {
|
||||
value: {
|
||||
$type: 'app.bsky.notification.declaration',
|
||||
allowSubscriptions: 'followers',
|
||||
} satisfies AppBskyNotificationDeclaration.Record,
|
||||
}
|
||||
} else {
|
||||
throw err
|
||||
}
|
||||
}
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
export function useNotificationDeclarationMutation() {
|
||||
const agent = useAgent()
|
||||
const {currentAccount} = useSession()
|
||||
const queryClient = useQueryClient()
|
||||
return useMutation({
|
||||
mutationFn: async (record: AppBskyNotificationDeclaration.Record) => {
|
||||
const response = await agent.com.atproto.repo.putRecord({
|
||||
repo: currentAccount!.did,
|
||||
collection: 'app.bsky.notification.declaration',
|
||||
rkey: 'self',
|
||||
record,
|
||||
})
|
||||
return response
|
||||
},
|
||||
onMutate: value => {
|
||||
queryClient.setQueryData(
|
||||
RQKEY_getNotificationDeclaration,
|
||||
(old?: {
|
||||
uri: string
|
||||
cid: string
|
||||
value: AppBskyNotificationDeclaration.Record
|
||||
}) => {
|
||||
if (!old) return old
|
||||
return {
|
||||
value,
|
||||
}
|
||||
},
|
||||
)
|
||||
},
|
||||
onError: () => {
|
||||
Toast.show(t`Failed to update notification declaration`)
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: RQKEY_getNotificationDeclaration,
|
||||
})
|
||||
},
|
||||
})
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import {AppBskyActorDefs} from '@atproto/api'
|
||||
import {type AppBskyActorDefs} from '@atproto/api'
|
||||
import {useMutation, useQueryClient} from '@tanstack/react-query'
|
||||
|
||||
import {logger} from '#/logger'
|
||||
@@ -19,7 +19,7 @@ export function useUpdateActorDeclaration({
|
||||
return useMutation({
|
||||
mutationFn: async (allowIncoming: 'all' | 'none' | 'following') => {
|
||||
if (!currentAccount) throw new Error('Not signed in')
|
||||
const result = await agent.api.com.atproto.repo.putRecord({
|
||||
const result = await agent.com.atproto.repo.putRecord({
|
||||
repo: currentAccount.did,
|
||||
collection: 'chat.bsky.actor.declaration',
|
||||
rkey: 'self',
|
||||
|
||||
Reference in New Issue
Block a user