forked from
jollywhoppers.com/witchsky.app
Bluesky app fork with some witchin' additions 💫
1import {View} from 'react-native'
2import {msg} from '@lingui/core/macro'
3import {useLingui} from '@lingui/react'
4import {Trans} from '@lingui/react/macro'
5
6import {useCleanError} from '#/lib/hooks/useCleanError'
7import {atoms as a, web} from '#/alf'
8import {Admonition} from '#/components/Admonition'
9import {Button, ButtonIcon, ButtonText} from '#/components/Button'
10import * as Dialog from '#/components/Dialog'
11import {Loader} from '#/components/Loader'
12import * as Toast from '#/components/Toast'
13import {Span, Text} from '#/components/Typography'
14import {IS_NATIVE} from '#/env'
15import {useUpdateLiveEventPreferences} from '#/features/liveEvents/preferences'
16import {
17 type LiveEventFeed,
18 type LiveEventFeedMetricContext,
19} from '#/features/liveEvents/types'
20
21export {useDialogControl} from '#/components/Dialog'
22
23export function LiveEventFeedOptionsMenu({
24 control,
25 feed,
26 metricContext,
27}: {
28 control: Dialog.DialogControlProps
29 feed: LiveEventFeed
30 metricContext: LiveEventFeedMetricContext
31}) {
32 const {_} = useLingui()
33 return (
34 <Dialog.Outer control={control}>
35 <Dialog.Handle />
36 <Dialog.ScrollableInner
37 label={_(msg`Configure live event banner`)}
38 style={[web({maxWidth: 400})]}>
39 <Inner control={control} feed={feed} metricContext={metricContext} />
40 <Dialog.Close />
41 </Dialog.ScrollableInner>
42 </Dialog.Outer>
43 )
44}
45
46function Inner({
47 control,
48 feed,
49 metricContext,
50}: {
51 control: Dialog.DialogControlProps
52 feed: LiveEventFeed
53 metricContext: LiveEventFeedMetricContext
54}) {
55 const {_} = useLingui()
56 const {
57 isPending,
58 mutate: update,
59 error: rawError,
60 variables,
61 } = useUpdateLiveEventPreferences({
62 feed,
63 metricContext,
64 onUpdateSuccess({undoAction}) {
65 Toast.show(
66 <Toast.Outer>
67 <Toast.Icon />
68 <Toast.Text>
69 <Trans>Your live event preferences have been updated.</Trans>
70 </Toast.Text>
71 {undoAction && (
72 <Toast.Action
73 label={_(msg`Undo`)}
74 onPress={() => {
75 if (undoAction) {
76 update(undoAction)
77 }
78 }}>
79 <Trans>Undo</Trans>
80 </Toast.Action>
81 )}
82 </Toast.Outer>,
83 {type: 'success'},
84 )
85
86 /*
87 * If there is no `undoAction`, it means that the action was already
88 * undone, and therefore the menu would have been closed prior to the
89 * undo happening.
90 */
91 if (undoAction) {
92 control.close()
93 }
94 },
95 })
96 const cleanError = useCleanError()
97 const error = rawError ? cleanError(rawError) : undefined
98
99 const isHidingFeed = variables?.type === 'hideFeed' && isPending
100 const isHidingAllFeeds = variables?.type === 'toggleHideAllFeeds' && isPending
101
102 return (
103 <View style={[a.gap_lg]}>
104 <View style={[a.gap_sm]}>
105 <Text style={[a.text_2xl, a.font_semi_bold, a.leading_snug]}>
106 <Trans>Live event options</Trans>
107 </Text>
108
109 <Text style={[a.text_md, a.leading_snug]}>
110 <Trans>
111 Live events appear occasionally when something exciting is
112 happening. If you'd like, you can hide this particular event, or all
113 events for this placement in your app interface.
114 </Trans>
115 </Text>
116
117 <Text style={[a.text_md, a.leading_snug]}>
118 <Trans>
119 If you choose to hide all events, you can always re-enable them from{' '}
120 <Span style={[a.font_semi_bold]}>Settings → Content & Media</Span>.
121 </Trans>
122 </Text>
123 </View>
124
125 <View style={[a.gap_sm]}>
126 <Button
127 label={_(msg`Hide this event`)}
128 size="large"
129 color="primary_subtle"
130 onPress={() => {
131 update({type: 'hideFeed', id: feed.id})
132 }}>
133 <ButtonText>
134 <Trans>Hide this event</Trans>
135 </ButtonText>
136 {isHidingFeed && <ButtonIcon icon={Loader} />}
137 </Button>
138 <Button
139 label={_(msg`Hide all events`)}
140 size="large"
141 color="secondary"
142 onPress={() => {
143 update({type: 'toggleHideAllFeeds'})
144 }}>
145 <ButtonText>
146 <Trans>Hide all events</Trans>
147 </ButtonText>
148 {isHidingAllFeeds && <ButtonIcon icon={Loader} />}
149 </Button>
150 {IS_NATIVE && (
151 <Button
152 label={_(msg`Cancel`)}
153 size="large"
154 color="secondary_inverted"
155 onPress={() => control.close()}>
156 <ButtonText>
157 <Trans>Cancel</Trans>
158 </ButtonText>
159 </Button>
160 )}
161 </View>
162
163 {error && (
164 <Admonition type="error">
165 {error.clean || error.raw || _(msg`An unknown error occurred.`)}
166 </Admonition>
167 )}
168 </View>
169 )
170}