Bluesky app fork with some witchin' additions 💫
at feat/tealfm 169 lines 4.9 kB view raw
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}