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