Bluesky app fork with some witchin' additions 馃挮
0
fork

Configure Feed

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

at c906fea77adb2daad28a521f06e68d5bbc4bce4d 198 lines 5.8 kB view raw
1import {useState} from 'react' 2import {View} from 'react-native' 3import {msg, Trans} from '@lingui/macro' 4import {useLingui} from '@lingui/react' 5 6import {cleanError, isNetworkError} from '#/lib/strings/errors' 7import {checkAndFormatResetCode} from '#/lib/strings/password' 8import {logger} from '#/logger' 9import {Agent} from '#/state/session/agent' 10import {atoms as a, web} from '#/alf' 11import {Button, ButtonIcon, ButtonText} from '#/components/Button' 12import {FormError} from '#/components/forms/FormError' 13import * as TextField from '#/components/forms/TextField' 14import {Lock_Stroke2_Corner0_Rounded as Lock} from '#/components/icons/Lock' 15import {Ticket_Stroke2_Corner0_Rounded as Ticket} from '#/components/icons/Ticket' 16import {Loader} from '#/components/Loader' 17import {Text} from '#/components/Typography' 18import {useAnalytics} from '#/analytics' 19import {IS_WEB} from '#/env' 20import {FormContainer} from './FormContainer' 21 22export const SetNewPasswordForm = ({ 23 error, 24 serviceUrl, 25 setError, 26 onPressBack, 27 onPasswordSet, 28}: { 29 error: string 30 serviceUrl: string 31 setError: (v: string) => void 32 onPressBack: () => void 33 onPasswordSet: () => void 34}) => { 35 const {_} = useLingui() 36 const ax = useAnalytics() 37 38 const [isProcessing, setIsProcessing] = useState<boolean>(false) 39 const [resetCode, setResetCode] = useState<string>('') 40 const [password, setPassword] = useState<string>('') 41 42 const onPressNext = async () => { 43 // Check that the code is correct. We do this again just incase the user enters the code after their pw and we 44 // don't get to call onBlur first 45 const formattedCode = checkAndFormatResetCode(resetCode) 46 47 if (!formattedCode) { 48 setError( 49 _( 50 msg`You have entered an invalid code. It should look like XXXXX-XXXXX.`, 51 ), 52 ) 53 ax.metric('signin:passwordResetFailure', {}) 54 return 55 } 56 57 // TODO Better password strength check 58 if (!password) { 59 setError(_(msg`Please enter a password.`)) 60 return 61 } 62 63 setError('') 64 setIsProcessing(true) 65 66 try { 67 const agent = new Agent(null, {service: serviceUrl}) 68 await agent.com.atproto.server.resetPassword({ 69 token: formattedCode, 70 password, 71 }) 72 onPasswordSet() 73 ax.metric('signin:passwordResetSuccess', {}) 74 } catch (e: any) { 75 const errMsg = e.toString() 76 logger.warn('Failed to set new password', {error: e}) 77 ax.metric('signin:passwordResetFailure', {}) 78 setIsProcessing(false) 79 if (isNetworkError(e)) { 80 setError( 81 _( 82 msg`Unable to contact your service. Please check your Internet connection.`, 83 ), 84 ) 85 } else { 86 setError(cleanError(errMsg)) 87 } 88 } 89 } 90 91 const onBlur = () => { 92 const formattedCode = checkAndFormatResetCode(resetCode) 93 if (!formattedCode) { 94 setError( 95 _( 96 msg`You have entered an invalid code. It should look like XXXXX-XXXXX.`, 97 ), 98 ) 99 return 100 } 101 setResetCode(formattedCode) 102 } 103 104 return ( 105 <FormContainer 106 testID="setNewPasswordForm" 107 titleText={<Trans>Set new password</Trans>}> 108 <Text style={[a.leading_snug, a.mb_sm]}> 109 <Trans> 110 You will receive an email with a "reset code." Enter that code here, 111 then enter your new password. 112 </Trans> 113 </Text> 114 115 <View> 116 <TextField.LabelText> 117 <Trans>Reset code</Trans> 118 </TextField.LabelText> 119 <TextField.Root> 120 <TextField.Icon icon={Ticket} /> 121 <TextField.Input 122 testID="resetCodeInput" 123 label={_(msg`Looks like XXXXX-XXXXX`)} 124 autoCapitalize="none" 125 autoFocus={true} 126 autoCorrect={false} 127 autoComplete="off" 128 value={resetCode} 129 onChangeText={setResetCode} 130 onFocus={() => setError('')} 131 onBlur={onBlur} 132 editable={!isProcessing} 133 accessibilityHint={_( 134 msg`Input code sent to your email for password reset`, 135 )} 136 /> 137 </TextField.Root> 138 </View> 139 140 <View> 141 <TextField.LabelText> 142 <Trans>New password</Trans> 143 </TextField.LabelText> 144 <TextField.Root> 145 <TextField.Icon icon={Lock} /> 146 <TextField.Input 147 testID="newPasswordInput" 148 label={_(msg`Enter a password`)} 149 autoCapitalize="none" 150 autoCorrect={false} 151 returnKeyType="done" 152 secureTextEntry={true} 153 autoComplete="new-password" 154 passwordRules="minlength: 8;" 155 clearButtonMode="while-editing" 156 value={password} 157 onChangeText={setPassword} 158 onSubmitEditing={onPressNext} 159 editable={!isProcessing} 160 accessibilityHint={_(msg`Input new password`)} 161 /> 162 </TextField.Root> 163 </View> 164 165 <FormError error={error} /> 166 167 <View style={[web([a.flex_row, a.align_center]), a.pt_lg]}> 168 {IS_WEB && ( 169 <> 170 <Button 171 label={_(msg`Back`)} 172 variant="solid" 173 color="secondary" 174 size="large" 175 onPress={onPressBack}> 176 <ButtonText> 177 <Trans>Back</Trans> 178 </ButtonText> 179 </Button> 180 <View style={a.flex_1} /> 181 </> 182 )} 183 184 <Button 185 label={_(msg`Next`)} 186 color="primary" 187 size="large" 188 onPress={onPressNext} 189 disabled={isProcessing}> 190 <ButtonText> 191 <Trans>Next</Trans> 192 </ButtonText> 193 {isProcessing && <ButtonIcon icon={Loader} />} 194 </Button> 195 </View> 196 </FormContainer> 197 ) 198}