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 push-notifications 235 lines 6.6 kB view raw
1import React, {useState} from 'react' 2import * as Toast from '../util/Toast' 3import { 4 ActivityIndicator, 5 StyleSheet, 6 TouchableOpacity, 7 View, 8} from 'react-native' 9import LinearGradient from 'react-native-linear-gradient' 10import {BottomSheetScrollView, BottomSheetTextInput} from '@gorhom/bottom-sheet' 11import {Image as PickedImage} from 'react-native-image-crop-picker' 12import {Text} from '../util/text/Text' 13import {ErrorMessage} from '../util/error/ErrorMessage' 14import {useStores} from '../../../state' 15import {ProfileViewModel} from '../../../state/models/profile-view' 16import {s, colors, gradients} from '../../lib/styles' 17import { 18 enforceLen, 19 MAX_DISPLAY_NAME, 20 MAX_DESCRIPTION, 21} from '../../../lib/strings' 22import {isNetworkError} from '../../../lib/errors' 23import {compressIfNeeded} from '../../../lib/images' 24import {UserBanner} from '../util/UserBanner' 25import {UserAvatar} from '../util/UserAvatar' 26 27export const snapPoints = ['80%'] 28 29export function Component({ 30 profileView, 31 onUpdate, 32}: { 33 profileView: ProfileViewModel 34 onUpdate?: () => void 35}) { 36 const store = useStores() 37 const [error, setError] = useState<string>('') 38 const [isProcessing, setProcessing] = useState<boolean>(false) 39 const [displayName, setDisplayName] = useState<string>( 40 profileView.displayName || '', 41 ) 42 const [description, setDescription] = useState<string>( 43 profileView.description || '', 44 ) 45 const [userBanner, setUserBanner] = useState<string | undefined>( 46 profileView.banner, 47 ) 48 const [userAvatar, setUserAvatar] = useState<string | undefined>( 49 profileView.avatar, 50 ) 51 const [newUserBanner, setNewUserBanner] = useState<PickedImage | undefined>() 52 const [newUserAvatar, setNewUserAvatar] = useState<PickedImage | undefined>() 53 const onPressCancel = () => { 54 store.shell.closeModal() 55 } 56 const onSelectNewAvatar = async (img: PickedImage) => { 57 try { 58 const finalImg = await compressIfNeeded(img, 300000) 59 setNewUserAvatar(finalImg) 60 setUserAvatar(finalImg.path) 61 } catch (e: any) { 62 setError(e.message || e.toString()) 63 } 64 } 65 const onSelectNewBanner = async (img: PickedImage) => { 66 try { 67 const finalImg = await compressIfNeeded(img, 500000) 68 setNewUserBanner(finalImg) 69 setUserBanner(finalImg.path) 70 } catch (e: any) { 71 setError(e.message || e.toString()) 72 } 73 } 74 const onPressSave = async () => { 75 setProcessing(true) 76 if (error) { 77 setError('') 78 } 79 try { 80 await profileView.updateProfile( 81 { 82 displayName, 83 description, 84 }, 85 newUserAvatar, 86 newUserBanner, 87 ) 88 Toast.show('Profile updated') 89 onUpdate?.() 90 store.shell.closeModal() 91 } catch (e: any) { 92 if (isNetworkError(e)) { 93 setError( 94 'Failed to save your profile. Check your internet connection and try again.', 95 ) 96 } else { 97 setError(e.message) 98 } 99 } 100 setProcessing(false) 101 } 102 103 return ( 104 <View style={s.flex1}> 105 <BottomSheetScrollView style={styles.inner}> 106 <Text style={styles.title}>Edit my profile</Text> 107 <View style={styles.photos}> 108 <UserBanner 109 banner={userBanner} 110 onSelectNewBanner={onSelectNewBanner} 111 handle={profileView.handle} 112 /> 113 <View style={styles.avi}> 114 <UserAvatar 115 size={80} 116 avatar={userAvatar} 117 handle={profileView.handle} 118 onSelectNewAvatar={onSelectNewAvatar} 119 displayName={profileView.displayName} 120 /> 121 </View> 122 </View> 123 {error !== '' && ( 124 <View style={styles.errorContainer}> 125 <ErrorMessage message={error} /> 126 </View> 127 )} 128 <View> 129 <Text style={styles.label}>Display Name</Text> 130 <BottomSheetTextInput 131 style={styles.textInput} 132 placeholder="e.g. Alice Roberts" 133 placeholderTextColor={colors.gray4} 134 value={displayName} 135 onChangeText={v => setDisplayName(enforceLen(v, MAX_DISPLAY_NAME))} 136 /> 137 </View> 138 <View style={s.pb10}> 139 <Text style={styles.label}>Description</Text> 140 <BottomSheetTextInput 141 style={[styles.textArea]} 142 placeholder="e.g. Artist, dog-lover, and memelord." 143 placeholderTextColor={colors.gray4} 144 multiline 145 value={description} 146 onChangeText={v => setDescription(enforceLen(v, MAX_DESCRIPTION))} 147 /> 148 </View> 149 {isProcessing ? ( 150 <View style={[styles.btn, s.mt10, {backgroundColor: colors.gray2}]}> 151 <ActivityIndicator /> 152 </View> 153 ) : ( 154 <TouchableOpacity style={s.mt10} onPress={onPressSave}> 155 <LinearGradient 156 colors={[gradients.blueLight.start, gradients.blueLight.end]} 157 start={{x: 0, y: 0}} 158 end={{x: 1, y: 1}} 159 style={[styles.btn]}> 160 <Text style={[s.white, s.bold]}>Save Changes</Text> 161 </LinearGradient> 162 </TouchableOpacity> 163 )} 164 <TouchableOpacity style={s.mt5} onPress={onPressCancel}> 165 <View style={[styles.btn]}> 166 <Text style={[s.black, s.bold]}>Cancel</Text> 167 </View> 168 </TouchableOpacity> 169 </BottomSheetScrollView> 170 </View> 171 ) 172} 173 174const styles = StyleSheet.create({ 175 inner: { 176 padding: 14, 177 }, 178 title: { 179 textAlign: 'center', 180 fontWeight: 'bold', 181 fontSize: 24, 182 marginBottom: 18, 183 }, 184 label: { 185 fontWeight: 'bold', 186 paddingHorizontal: 4, 187 paddingBottom: 4, 188 marginTop: 20, 189 }, 190 textInput: { 191 borderWidth: 1, 192 borderColor: colors.gray3, 193 borderRadius: 6, 194 paddingHorizontal: 14, 195 paddingVertical: 10, 196 fontSize: 16, 197 color: colors.black, 198 }, 199 textArea: { 200 borderWidth: 1, 201 borderColor: colors.gray3, 202 borderRadius: 6, 203 paddingHorizontal: 12, 204 paddingTop: 10, 205 fontSize: 16, 206 color: colors.black, 207 height: 100, 208 textAlignVertical: 'top', 209 }, 210 btn: { 211 flexDirection: 'row', 212 alignItems: 'center', 213 justifyContent: 'center', 214 width: '100%', 215 borderRadius: 32, 216 padding: 10, 217 marginBottom: 10, 218 }, 219 avi: { 220 position: 'absolute', 221 top: 80, 222 left: 10, 223 width: 84, 224 height: 84, 225 borderWidth: 2, 226 borderRadius: 42, 227 borderColor: colors.white, 228 backgroundColor: colors.white, 229 }, 230 photos: { 231 marginBottom: 36, 232 marginHorizontal: -14, 233 }, 234 errorContainer: {marginTop: 20}, 235})