mirror of https://git.lenooby09.tech/LeNooby09/social-app.git
at session-alignment 204 lines 5.6 kB view raw
1import React, {useState} from 'react' 2import { 3 Pressable, 4 StyleProp, 5 StyleSheet, 6 TouchableOpacity, 7 View, 8 ViewStyle, 9} from 'react-native' 10import {Text} from '../util/text/Text' 11import {s, colors} from 'lib/styles' 12import {usePalette} from 'lib/hooks/usePalette' 13import {isWeb} from 'platform/detection' 14import {ScrollView} from 'view/com/modals/util' 15import {Trans, msg} from '@lingui/macro' 16import {useLingui} from '@lingui/react' 17import {useModalControls} from '#/state/modals' 18import {ThreadgateSetting} from '#/state/queries/threadgate' 19import {useMyListsQuery} from '#/state/queries/my-lists' 20import isEqual from 'lodash.isequal' 21import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' 22 23export const snapPoints = ['60%'] 24 25export function Component({ 26 settings, 27 onChange, 28}: { 29 settings: ThreadgateSetting[] 30 onChange: (settings: ThreadgateSetting[]) => void 31}) { 32 const pal = usePalette('default') 33 const {closeModal} = useModalControls() 34 const [selected, setSelected] = useState(settings) 35 const {_} = useLingui() 36 const {data: lists} = useMyListsQuery('curate') 37 38 const onPressEverybody = () => { 39 setSelected([]) 40 onChange([]) 41 } 42 43 const onPressNobody = () => { 44 setSelected([{type: 'nobody'}]) 45 onChange([{type: 'nobody'}]) 46 } 47 48 const onPressAudience = (setting: ThreadgateSetting) => { 49 // remove nobody 50 let newSelected = selected.filter(v => v.type !== 'nobody') 51 // toggle 52 const i = newSelected.findIndex(v => isEqual(v, setting)) 53 if (i === -1) { 54 newSelected.push(setting) 55 } else { 56 newSelected.splice(i, 1) 57 } 58 setSelected(newSelected) 59 onChange(newSelected) 60 } 61 62 return ( 63 <View testID="threadgateModal" style={[pal.view, styles.container]}> 64 <View style={styles.titleSection}> 65 <Text type="title-lg" style={[pal.text, styles.title]}> 66 <Trans>Who can reply</Trans> 67 </Text> 68 </View> 69 70 <ScrollView> 71 <Text style={[pal.text, styles.description]}> 72 <Trans>Choose "Everybody" or "Nobody"</Trans> 73 </Text> 74 <View style={{flexDirection: 'row', gap: 6, paddingHorizontal: 6}}> 75 <Selectable 76 label={_(msg`Everybody`)} 77 isSelected={selected.length === 0} 78 onPress={onPressEverybody} 79 style={{flex: 1}} 80 /> 81 <Selectable 82 label={_(msg`Nobody`)} 83 isSelected={!!selected.find(v => v.type === 'nobody')} 84 onPress={onPressNobody} 85 style={{flex: 1}} 86 /> 87 </View> 88 <Text style={[pal.text, styles.description]}> 89 <Trans>Or combine these options:</Trans> 90 </Text> 91 <View style={{flexDirection: 'column', gap: 4, paddingHorizontal: 6}}> 92 <Selectable 93 label={_(msg`Mentioned users`)} 94 isSelected={!!selected.find(v => v.type === 'mention')} 95 onPress={() => onPressAudience({type: 'mention'})} 96 /> 97 <Selectable 98 label={_(msg`Followed users`)} 99 isSelected={!!selected.find(v => v.type === 'following')} 100 onPress={() => onPressAudience({type: 'following'})} 101 /> 102 {lists?.length 103 ? lists.map(list => ( 104 <Selectable 105 key={list.uri} 106 label={_(msg`Users in "${list.name}"`)} 107 isSelected={ 108 !!selected.find( 109 v => v.type === 'list' && v.list === list.uri, 110 ) 111 } 112 onPress={() => 113 onPressAudience({type: 'list', list: list.uri}) 114 } 115 /> 116 )) 117 : null} 118 </View> 119 </ScrollView> 120 121 <View style={[styles.btnContainer, pal.borderDark]}> 122 <TouchableOpacity 123 testID="confirmBtn" 124 onPress={() => { 125 closeModal() 126 }} 127 style={styles.btn} 128 accessibilityRole="button" 129 accessibilityLabel={_(msg({message: `Done`, context: 'action'}))} 130 accessibilityHint=""> 131 <Text style={[s.white, s.bold, s.f18]}> 132 <Trans context="action">Done</Trans> 133 </Text> 134 </TouchableOpacity> 135 </View> 136 </View> 137 ) 138} 139 140function Selectable({ 141 label, 142 isSelected, 143 onPress, 144 style, 145}: { 146 label: string 147 isSelected: boolean 148 onPress: () => void 149 style?: StyleProp<ViewStyle> 150}) { 151 const pal = usePalette(isSelected ? 'inverted' : 'default') 152 return ( 153 <Pressable 154 onPress={onPress} 155 accessibilityLabel={label} 156 accessibilityHint="" 157 style={[styles.selectable, pal.border, pal.view, style]}> 158 <Text type="xl" style={[pal.text]}> 159 {label} 160 </Text> 161 {isSelected ? ( 162 <FontAwesomeIcon icon="check" color={pal.colors.text} size={18} /> 163 ) : null} 164 </Pressable> 165 ) 166} 167 168const styles = StyleSheet.create({ 169 container: { 170 flex: 1, 171 paddingBottom: isWeb ? 0 : 40, 172 }, 173 titleSection: { 174 paddingTop: isWeb ? 0 : 4, 175 }, 176 title: { 177 textAlign: 'center', 178 fontWeight: '600', 179 }, 180 description: { 181 textAlign: 'center', 182 paddingVertical: 16, 183 }, 184 selectable: { 185 flexDirection: 'row', 186 justifyContent: 'space-between', 187 paddingHorizontal: 18, 188 paddingVertical: 16, 189 borderWidth: 1, 190 borderRadius: 6, 191 }, 192 btn: { 193 flexDirection: 'row', 194 alignItems: 'center', 195 justifyContent: 'center', 196 borderRadius: 32, 197 padding: 14, 198 backgroundColor: colors.blue3, 199 }, 200 btnContainer: { 201 paddingTop: 20, 202 paddingHorizontal: 20, 203 }, 204})