mirror of https://git.lenooby09.tech/LeNooby09/social-app.git
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

at rn-stack-repro 275 lines 9.3 kB view raw
1import React from 'react' 2import {View} from 'react-native' 3import {useNavigation} from '@react-navigation/native' 4import {useLingui} from '@lingui/react' 5import {msg, Trans} from '@lingui/macro' 6 7import {atoms as a, native, useTheme} from '#/alf' 8import * as Dialog from '#/components/Dialog' 9import {Text} from '#/components/Typography' 10import {Button, ButtonText} from '#/components/Button' 11import {MagnifyingGlass2_Stroke2_Corner0_Rounded as Search} from '#/components/icons/MagnifyingGlass2' 12import {Person_Stroke2_Corner0_Rounded as Person} from '#/components/icons/Person' 13import {Mute_Stroke2_Corner0_Rounded as Mute} from '#/components/icons/Mute' 14import {Divider} from '#/components/Divider' 15import {Link} from '#/components/Link' 16import {makeSearchLink} from '#/lib/routes/links' 17import {NavigationProp} from '#/lib/routes/types' 18import { 19 usePreferencesQuery, 20 useUpsertMutedWordsMutation, 21 useRemoveMutedWordMutation, 22} from '#/state/queries/preferences' 23import {Loader} from '#/components/Loader' 24import {isInvalidHandle} from '#/lib/strings/handles' 25 26export function useTagMenuControl() { 27 return Dialog.useDialogControl() 28} 29 30export function TagMenu({ 31 children, 32 control, 33 tag, 34 authorHandle, 35}: React.PropsWithChildren<{ 36 control: Dialog.DialogOuterProps['control'] 37 /** 38 * This should be the sanitized tag value from the facet itself, not the 39 * "display" value with a leading `#`. 40 */ 41 tag: string 42 authorHandle?: string 43}>) { 44 const {_} = useLingui() 45 const t = useTheme() 46 const navigation = useNavigation<NavigationProp>() 47 const {isLoading: isPreferencesLoading, data: preferences} = 48 usePreferencesQuery() 49 const { 50 mutateAsync: upsertMutedWord, 51 variables: optimisticUpsert, 52 reset: resetUpsert, 53 } = useUpsertMutedWordsMutation() 54 const { 55 mutateAsync: removeMutedWord, 56 variables: optimisticRemove, 57 reset: resetRemove, 58 } = useRemoveMutedWordMutation() 59 const displayTag = '#' + tag 60 61 const isMuted = Boolean( 62 (preferences?.mutedWords?.find( 63 m => m.value === tag && m.targets.includes('tag'), 64 ) ?? 65 optimisticUpsert?.find( 66 m => m.value === tag && m.targets.includes('tag'), 67 )) && 68 !(optimisticRemove?.value === tag), 69 ) 70 71 return ( 72 <> 73 {children} 74 75 <Dialog.Outer control={control}> 76 <Dialog.Handle /> 77 78 <Dialog.Inner label={_(msg`Tag menu: ${displayTag}`)}> 79 {isPreferencesLoading ? ( 80 <View style={[a.w_full, a.align_center]}> 81 <Loader size="lg" /> 82 </View> 83 ) : ( 84 <> 85 <View 86 style={[ 87 a.rounded_md, 88 a.border, 89 a.mb_md, 90 t.atoms.border_contrast_low, 91 t.atoms.bg_contrast_25, 92 ]}> 93 <Link 94 label={_(msg`Search for all posts with tag ${displayTag}`)} 95 to={makeSearchLink({query: displayTag})} 96 onPress={e => { 97 e.preventDefault() 98 99 control.close(() => { 100 navigation.push('Hashtag', { 101 tag: tag.replaceAll('#', '%23'), 102 }) 103 }) 104 105 return false 106 }}> 107 <View 108 style={[ 109 a.w_full, 110 a.flex_row, 111 a.align_center, 112 a.justify_start, 113 a.gap_md, 114 a.px_lg, 115 a.py_md, 116 ]}> 117 <Search size="lg" style={[t.atoms.text_contrast_medium]} /> 118 <Text 119 numberOfLines={1} 120 ellipsizeMode="middle" 121 style={[ 122 a.flex_1, 123 a.text_md, 124 a.font_bold, 125 native({top: 2}), 126 t.atoms.text_contrast_medium, 127 ]}> 128 <Trans> 129 See{' '} 130 <Text style={[a.text_md, a.font_bold, t.atoms.text]}> 131 {displayTag} 132 </Text>{' '} 133 posts 134 </Trans> 135 </Text> 136 </View> 137 </Link> 138 139 {authorHandle && !isInvalidHandle(authorHandle) && ( 140 <> 141 <Divider /> 142 143 <Link 144 label={_( 145 msg`Search for all posts by @${authorHandle} with tag ${displayTag}`, 146 )} 147 to={makeSearchLink({ 148 query: displayTag, 149 from: authorHandle, 150 })} 151 onPress={e => { 152 e.preventDefault() 153 154 control.close(() => { 155 navigation.push('Hashtag', { 156 tag: tag.replaceAll('#', '%23'), 157 author: authorHandle, 158 }) 159 }) 160 161 return false 162 }}> 163 <View 164 style={[ 165 a.w_full, 166 a.flex_row, 167 a.align_center, 168 a.justify_start, 169 a.gap_md, 170 a.px_lg, 171 a.py_md, 172 ]}> 173 <Person 174 size="lg" 175 style={[t.atoms.text_contrast_medium]} 176 /> 177 <Text 178 numberOfLines={1} 179 ellipsizeMode="middle" 180 style={[ 181 a.flex_1, 182 a.text_md, 183 a.font_bold, 184 native({top: 2}), 185 t.atoms.text_contrast_medium, 186 ]}> 187 <Trans> 188 See{' '} 189 <Text 190 style={[a.text_md, a.font_bold, t.atoms.text]}> 191 {displayTag} 192 </Text>{' '} 193 posts by this user 194 </Trans> 195 </Text> 196 </View> 197 </Link> 198 </> 199 )} 200 201 {preferences ? ( 202 <> 203 <Divider /> 204 205 <Button 206 label={ 207 isMuted 208 ? _(msg`Unmute all ${displayTag} posts`) 209 : _(msg`Mute all ${displayTag} posts`) 210 } 211 onPress={() => { 212 control.close(() => { 213 if (isMuted) { 214 resetUpsert() 215 removeMutedWord({ 216 value: tag, 217 targets: ['tag'], 218 }) 219 } else { 220 resetRemove() 221 upsertMutedWord([{value: tag, targets: ['tag']}]) 222 } 223 }) 224 }}> 225 <View 226 style={[ 227 a.w_full, 228 a.flex_row, 229 a.align_center, 230 a.justify_start, 231 a.gap_md, 232 a.px_lg, 233 a.py_md, 234 ]}> 235 <Mute 236 size="lg" 237 style={[t.atoms.text_contrast_medium]} 238 /> 239 <Text 240 numberOfLines={1} 241 ellipsizeMode="middle" 242 style={[ 243 a.flex_1, 244 a.text_md, 245 a.font_bold, 246 native({top: 2}), 247 t.atoms.text_contrast_medium, 248 ]}> 249 {isMuted ? _(msg`Unmute`) : _(msg`Mute`)}{' '} 250 <Text style={[a.text_md, a.font_bold, t.atoms.text]}> 251 {displayTag} 252 </Text>{' '} 253 <Trans>posts</Trans> 254 </Text> 255 </View> 256 </Button> 257 </> 258 ) : null} 259 </View> 260 261 <Button 262 label={_(msg`Close this dialog`)} 263 size="small" 264 variant="ghost" 265 color="secondary" 266 onPress={() => control.close()}> 267 <ButtonText>Cancel</ButtonText> 268 </Button> 269 </> 270 )} 271 </Dialog.Inner> 272 </Dialog.Outer> 273 </> 274 ) 275}