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