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