196 lines
5.6 KiB
TypeScript
196 lines
5.6 KiB
TypeScript
import {useMemo} from 'react'
|
|
import {View} from 'react-native'
|
|
import {Trans, useLingui} from '@lingui/react/macro'
|
|
|
|
import {
|
|
type NotificationSettingsPreference,
|
|
type NotificationSettingsPreferenceName,
|
|
useNotificationSettingsUpdateMutation,
|
|
} from '#/state/queries/notifications/settings'
|
|
import {atoms as a, platform, useTheme} from '#/alf'
|
|
import * as Toggle from '#/components/forms/Toggle'
|
|
import {Loader} from '#/components/Loader'
|
|
import {Text} from '#/components/Typography'
|
|
import {useAnalytics} from '#/analytics'
|
|
import {Divider} from '../../components/SettingsList'
|
|
|
|
export function PreferenceControls({
|
|
name,
|
|
syncOthers,
|
|
preference,
|
|
allowDisableInApp = true,
|
|
}: {
|
|
name: NotificationSettingsPreferenceName
|
|
/**
|
|
* Keep other prefs in sync with `name`. For use in the "everything else" category
|
|
* which groups starterpack joins + verified + unverified notifications into a single toggle.
|
|
*/
|
|
syncOthers?: NotificationSettingsPreferenceName[]
|
|
preference?: NotificationSettingsPreference
|
|
allowDisableInApp?: boolean
|
|
}) {
|
|
if (!preference)
|
|
return (
|
|
<View style={[a.w_full, a.pt_5xl, a.align_center]}>
|
|
<Loader size="xl" />
|
|
</View>
|
|
)
|
|
|
|
return (
|
|
<Inner
|
|
name={name}
|
|
syncOthers={syncOthers}
|
|
preference={preference}
|
|
allowDisableInApp={allowDisableInApp}
|
|
/>
|
|
)
|
|
}
|
|
|
|
export function Inner({
|
|
name,
|
|
syncOthers = [],
|
|
preference,
|
|
allowDisableInApp,
|
|
}: {
|
|
name: NotificationSettingsPreferenceName
|
|
syncOthers?: NotificationSettingsPreferenceName[]
|
|
preference: NotificationSettingsPreference
|
|
allowDisableInApp: boolean
|
|
}) {
|
|
const t = useTheme()
|
|
const {t: l} = useLingui()
|
|
const ax = useAnalytics()
|
|
const {mutate} = useNotificationSettingsUpdateMutation()
|
|
|
|
const channels = useMemo(() => {
|
|
const arr = []
|
|
if ('list' in preference && preference.list) arr.push('list')
|
|
if (preference.push) arr.push('push')
|
|
return arr
|
|
}, [preference])
|
|
|
|
const onChangeChannels = (change: string[]) => {
|
|
const newPreference = {
|
|
...preference,
|
|
...('list' in preference ? {list: change.includes('list')} : {}),
|
|
push: change.includes('push'),
|
|
} as typeof preference
|
|
|
|
const metrics: {name: string; push: boolean; list?: boolean} = {
|
|
name,
|
|
push: newPreference.push,
|
|
}
|
|
if ('list' in newPreference) {
|
|
metrics.list = newPreference.list
|
|
}
|
|
ax.metric('activityPreference:changeChannels', metrics)
|
|
|
|
mutate({
|
|
[name]: newPreference,
|
|
...Object.fromEntries(syncOthers.map(key => [key, newPreference])),
|
|
})
|
|
}
|
|
|
|
const onChangeFilter = ([change]: string[]) => {
|
|
if (change !== 'all' && change !== 'follows')
|
|
throw new Error('Invalid filter')
|
|
|
|
const newPreference = {
|
|
...preference,
|
|
include: change,
|
|
} satisfies typeof preference
|
|
|
|
ax.metric('activityPreference:changeFilter', {name, value: change})
|
|
|
|
mutate({
|
|
[name]: newPreference,
|
|
...Object.fromEntries(syncOthers.map(key => [key, newPreference])),
|
|
})
|
|
}
|
|
|
|
return (
|
|
<View style={[a.gap_sm]}>
|
|
<Toggle.Group
|
|
type="checkbox"
|
|
label={l`Select your preferred notification channels`}
|
|
values={channels}
|
|
onChange={onChangeChannels}>
|
|
<View style={[a.gap_sm]}>
|
|
<Toggle.Item
|
|
label={l`Receive push notifications`}
|
|
name="push"
|
|
style={[
|
|
a.py_xs,
|
|
platform({
|
|
native: [a.justify_between],
|
|
web: [a.flex_row_reverse, a.gap_sm],
|
|
}),
|
|
]}>
|
|
<Toggle.LabelText
|
|
style={[t.atoms.text, a.font_normal, a.text_md, a.flex_1]}>
|
|
<Trans>Push notifications</Trans>
|
|
</Toggle.LabelText>
|
|
<Toggle.Platform />
|
|
</Toggle.Item>
|
|
{allowDisableInApp && 'list' in preference && (
|
|
<Toggle.Item
|
|
label={l`Receive in-app notifications`}
|
|
name="list"
|
|
style={[
|
|
a.py_xs,
|
|
platform({
|
|
native: [a.justify_between],
|
|
web: [a.flex_row_reverse, a.gap_sm],
|
|
}),
|
|
]}>
|
|
<Toggle.LabelText
|
|
style={[t.atoms.text, a.font_normal, a.text_md, a.flex_1]}>
|
|
<Trans>In-app notifications</Trans>
|
|
</Toggle.LabelText>
|
|
<Toggle.Platform />
|
|
</Toggle.Item>
|
|
)}
|
|
</View>
|
|
</Toggle.Group>
|
|
{'include' in preference && (
|
|
<>
|
|
<Divider />
|
|
<Text style={[a.font_semi_bold, a.text_md]}>
|
|
<Trans comment="Filter who you receive notifications from">
|
|
From
|
|
</Trans>
|
|
</Text>
|
|
<Toggle.Group
|
|
type="radio"
|
|
label={l`Filter who you receive notifications from`}
|
|
values={[preference.include]}
|
|
onChange={onChangeFilter}
|
|
disabled={channels.length === 0}>
|
|
<View style={[a.gap_sm]}>
|
|
<Toggle.Item highlightRow label={l`Everyone`} name="all">
|
|
{({selected}) => (
|
|
<Toggle.RadioWithLabel
|
|
label={l`Everyone`}
|
|
selected={selected}
|
|
/>
|
|
)}
|
|
</Toggle.Item>
|
|
<Toggle.Item
|
|
highlightRow
|
|
label={l`People I follow`}
|
|
name="follows">
|
|
{({selected}) => (
|
|
<Toggle.RadioWithLabel
|
|
label={l`People I follow`}
|
|
selected={selected}
|
|
/>
|
|
)}
|
|
</Toggle.Item>
|
|
</View>
|
|
</Toggle.Group>
|
|
</>
|
|
)}
|
|
</View>
|
|
)
|
|
}
|