|
@@ -0,0 +1,454 @@
|
|
|
|
|
+/**
|
|
|
|
|
+ * 忘记密码-重置密码页面V2
|
|
|
|
|
+ * @邠心vbe on 2023/02/02
|
|
|
|
|
+ */
|
|
|
|
|
+import React, { Component } from 'react';
|
|
|
|
|
+import { View, StyleSheet, ScrollView, Image, TextInput, Pressable } from 'react-native';
|
|
|
|
|
+import apiUser from '../../api/apiUser';
|
|
|
|
|
+import { setAccessToken } from '../../api/http';
|
|
|
|
|
+import Button from '../../components/Button';
|
|
|
|
|
+import Dialog from '../../components/Dialog';
|
|
|
|
|
+import { Styles } from '../../components/Toolbar';
|
|
|
|
|
+import routeUtil from '../../utils/routeUtil';
|
|
|
|
|
+import { getStorageJsonSync, setStorage, setStorageJson } from '../../utils/storage';
|
|
|
|
|
+import utils from '../../utils/utils';
|
|
|
|
|
+import { PageList } from '../Router';
|
|
|
|
|
+import StrengthView from './StrengthView';
|
|
|
|
|
+
|
|
|
|
|
+export default class ResetPassword extends Component {
|
|
|
|
|
+ constructor(props) {
|
|
|
|
|
+ super(props);
|
|
|
|
|
+ this.StrengthView = StrengthView.V2
|
|
|
|
|
+ this.strengthColor = ["#F5F5F5", "#F7C4CD", "#F2F8AC", "#F8DBAC", "#ACF8F6", "#A6E782"]
|
|
|
|
|
+ this.state = {
|
|
|
|
|
+ email: '',
|
|
|
|
|
+ strength: 0,
|
|
|
|
|
+ password: '',
|
|
|
|
|
+ isChange: false,
|
|
|
|
|
+ wrongCount: true,
|
|
|
|
|
+ sendMinutes: 0,
|
|
|
|
|
+ confirmStatusColor: "#F5F5F5"
|
|
|
|
|
+ };
|
|
|
|
|
+ this.formInfo = {
|
|
|
|
|
+ email: '',
|
|
|
|
|
+ password: '',
|
|
|
|
|
+ verificationCode: ''
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ componentDidMount() {
|
|
|
|
|
+ const action = this.props.route?.params?.action ?? "";
|
|
|
|
|
+ if (action == "change") {
|
|
|
|
|
+ this.setState({
|
|
|
|
|
+ isChange: true
|
|
|
|
|
+ });
|
|
|
|
|
+ const email = userInfo.email;
|
|
|
|
|
+ this.formInfo.email = email;
|
|
|
|
|
+ this.setState({
|
|
|
|
|
+ email: email
|
|
|
|
|
+ });
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ componentWillUnmount() {
|
|
|
|
|
+ this.setState({
|
|
|
|
|
+ sendMinutes: 0
|
|
|
|
|
+ })
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ getBackTopPosition() {
|
|
|
|
|
+ return isIOS ? statusHeight - 18 : 12;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ getConfirmStatusColor() {
|
|
|
|
|
+ var color = "#F5F5F5";
|
|
|
|
|
+ if (this.formInfo.password) {
|
|
|
|
|
+ if (this.state.password == this.formInfo.password) {
|
|
|
|
|
+ color = "#A6E782";
|
|
|
|
|
+ } else {
|
|
|
|
|
+ color = "#FA7B7B"
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ this.setState({
|
|
|
|
|
+ confirmStatusColor: color
|
|
|
|
|
+ })
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ changeInfo(key, value) {
|
|
|
|
|
+ this.formInfo[key] = value;
|
|
|
|
|
+ if (key == "password") {
|
|
|
|
|
+ this.getConfirmStatusColor();
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ applyStrength(text) {
|
|
|
|
|
+ this.StrengthView.apply(text, strength => {
|
|
|
|
|
+ if (this.state.strength != strength) {
|
|
|
|
|
+ this.setState({
|
|
|
|
|
+ password: text,
|
|
|
|
|
+ strength: strength
|
|
|
|
|
+ });
|
|
|
|
|
+ } else {
|
|
|
|
|
+ this.setState({
|
|
|
|
|
+ password: text
|
|
|
|
|
+ });
|
|
|
|
|
+ }
|
|
|
|
|
+ setTimeout(() => this.getConfirmStatusColor(), 300);
|
|
|
|
|
+ });
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ sendVerification() {
|
|
|
|
|
+ var info = this.formInfo;
|
|
|
|
|
+ if (!info.email) {
|
|
|
|
|
+ toastShort($t('sign.plsInputEmail'));
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ if (!utils.isValidEmail(info.email)) {
|
|
|
|
|
+ toastShort($t('sign.errEmailFormat'));
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ Dialog.showProgressDialog()
|
|
|
|
|
+ apiUser.sendVerificationCode(info.email).then(res => {
|
|
|
|
|
+ Dialog.dismissLoading()
|
|
|
|
|
+ this.state.sendMinutes = res.data?.resendTime ?? 60;
|
|
|
|
|
+ toastShort($t('sign.sendOTPSuccess'));
|
|
|
|
|
+ this.contdownTime();
|
|
|
|
|
+ }).catch(err => {
|
|
|
|
|
+ Dialog.dismissLoading()
|
|
|
|
|
+ toastShort(err);
|
|
|
|
|
+ });
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ contdownTime() {
|
|
|
|
|
+ if (this.state.sendMinutes > 0) {
|
|
|
|
|
+ this.setState({
|
|
|
|
|
+ sendMinutes: this.state.sendMinutes - 1
|
|
|
|
|
+ })
|
|
|
|
|
+ setTimeout(() => {
|
|
|
|
|
+ this.contdownTime();
|
|
|
|
|
+ }, 1000);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ onResetPassword() {
|
|
|
|
|
+ var info = this.formInfo;
|
|
|
|
|
+ console.log('reset info', info);
|
|
|
|
|
+ if (!info.email) {
|
|
|
|
|
+ toastShort($t('sign.plsInputEmail'));
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ if (!utils.isValidEmail(info.email)) {
|
|
|
|
|
+ toastShort($t('sign.errEmailFormat'));
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ if (!info.verificationCode) {
|
|
|
|
|
+ toastShort($t('sign.plsInputOTP'));
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ if (!this.state.password) {
|
|
|
|
|
+ toastShort($t('sign.plsInputPassword'));
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ if (this.state.strength < this.StrengthView.maxStrength) {
|
|
|
|
|
+ toastShort($t('sign.errPasswordStrong'));
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ if (!info.password) {
|
|
|
|
|
+ toastShort($t('sign.plsInputPassword2'));
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ if (info.password != this.state.password) {
|
|
|
|
|
+ toastShort($t('sign.errPasswordConfirm'));
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ Dialog.showProgressDialog()
|
|
|
|
|
+ apiUser.updatePassword(this.formInfo).then(res => {
|
|
|
|
|
+ Dialog.dismissLoading()
|
|
|
|
|
+ toastShort($t('sign.resetPasswordSuccess'));
|
|
|
|
|
+ if (this.state.isChange) {
|
|
|
|
|
+ this.requestLogout();
|
|
|
|
|
+ } else {
|
|
|
|
|
+ goBack();
|
|
|
|
|
+ }
|
|
|
|
|
+ }).catch(err => {
|
|
|
|
|
+ Dialog.dismissLoading()
|
|
|
|
|
+ toastShort(err);
|
|
|
|
|
+ });
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ async requestLogout() {
|
|
|
|
|
+ const data = await getStorageJsonSync('loginData');
|
|
|
|
|
+ if (data && data.email) {
|
|
|
|
|
+ delete data.password
|
|
|
|
|
+ setStorageJson('loginData', data);
|
|
|
|
|
+ setStorage('RegisterTokenDate', "");
|
|
|
|
|
+ }
|
|
|
|
|
+ global.userInfo = {}
|
|
|
|
|
+ /*this.setState({
|
|
|
|
|
+ isLogin: false,
|
|
|
|
|
+ userInfo: {}
|
|
|
|
|
+ });*/
|
|
|
|
|
+ setAccessToken('');
|
|
|
|
|
+ routeUtil.bridge2Page(PageList.login);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ getStrengthStyle() {
|
|
|
|
|
+ const persent = ((this.StrengthView.maxStrength - this.state.strength) / this.StrengthView.maxStrength) * 100
|
|
|
|
|
+ return {
|
|
|
|
|
+ left: 0,
|
|
|
|
|
+ right: 0,
|
|
|
|
|
+ height: 1,
|
|
|
|
|
+ bottom: -1,
|
|
|
|
|
+ marginRight: persent + "%",
|
|
|
|
|
+ position: 'absolute',
|
|
|
|
|
+ backgroundColor: "#A6E782"
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ changeSecurety() {
|
|
|
|
|
+ this.setState({
|
|
|
|
|
+ wrongCount: !this.state.wrongCount
|
|
|
|
|
+ })
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ render() {
|
|
|
|
|
+ return (
|
|
|
|
|
+ <View style={StyleSheet.absoluteFillObject}>
|
|
|
|
|
+ <ScrollView
|
|
|
|
|
+ style={styles.scollView}
|
|
|
|
|
+ keyboardShouldPersistTaps={isIOS ? 'never' : 'handled'}>
|
|
|
|
|
+ <View style={styles.resetView}>
|
|
|
|
|
+ {/* <Text style={styles.title}>Reset Password</Text> */}
|
|
|
|
|
+ <View style={styles.signInput}>
|
|
|
|
|
+ {/* <Text style={styles.inputLabel}>Email Address</Text> */}
|
|
|
|
|
+ <Image
|
|
|
|
|
+ style={styles.inputIcon}
|
|
|
|
|
+ source={require('../../images/user/sign-email.png')}
|
|
|
|
|
+ />
|
|
|
|
|
+ { this.state.isChange
|
|
|
|
|
+ ? <TextInput
|
|
|
|
|
+ style={styles.inputView}
|
|
|
|
|
+ placeholder={$t('sign.labelEmail')}
|
|
|
|
|
+ placeholderTextColor={textPlacehoder}
|
|
|
|
|
+ value={this.state.email}
|
|
|
|
|
+ editable={false}
|
|
|
|
|
+ maxLength={50}/>
|
|
|
|
|
+ : <TextInput
|
|
|
|
|
+ style={styles.inputView}
|
|
|
|
|
+ placeholder={$t('sign.labelEmail')}
|
|
|
|
|
+ placeholderTextColor={textPlacehoder}
|
|
|
|
|
+ maxLength={50}
|
|
|
|
|
+ keyboardType="email-address"
|
|
|
|
|
+ textContentType='emailAddress'
|
|
|
|
|
+ clearButtonMode='while-editing'
|
|
|
|
|
+ onChangeText={v => this.changeInfo('email', v)}/>
|
|
|
|
|
+ }
|
|
|
|
|
+ </View>
|
|
|
|
|
+ <View style={styles.signInput}>
|
|
|
|
|
+ {/* <Text style={[styles.inputLabel, ui.flex2]}>Verification Code</Text> */}
|
|
|
|
|
+ <Image
|
|
|
|
|
+ style={styles.inputIcon}
|
|
|
|
|
+ source={require('../../images/user/sign-otp.png')}
|
|
|
|
|
+ />
|
|
|
|
|
+ <TextInput
|
|
|
|
|
+ style={[styles.inputView, {flex: 2.6, marginLeft: 2}]}
|
|
|
|
|
+ placeholder={$t('sign.labelOtp')}
|
|
|
|
|
+ placeholderTextColor={textPlacehoder}
|
|
|
|
|
+ maxLength={6}
|
|
|
|
|
+ keyboardType="number-pad"
|
|
|
|
|
+ textContentType="telephoneNumber"
|
|
|
|
|
+ onChangeText={v => this.changeInfo('verificationCode', v)}
|
|
|
|
|
+ />
|
|
|
|
|
+ <Button
|
|
|
|
|
+ text={this.state.sendMinutes > 0 ? (this.state.sendMinutes + " s") : $t('sign.btnSendOTP')}
|
|
|
|
|
+ style={styles.sendBtn}
|
|
|
|
|
+ disabled={this.state.sendMinutes > 0}
|
|
|
|
|
+ viewStyle={styles.sendBtnView}
|
|
|
|
|
+ textStyle={styles.sendBtnText}
|
|
|
|
|
+ onClick={() => this.sendVerification()}
|
|
|
|
|
+ />
|
|
|
|
|
+ </View>
|
|
|
|
|
+ <View style={styles.signInput}>
|
|
|
|
|
+ {/* <Text style={styles.inputLabel}>New Password</Text> */}
|
|
|
|
|
+ <Image
|
|
|
|
|
+ style={styles.inputIcon}
|
|
|
|
|
+ source={require('../../images/user/sign-password.png')}
|
|
|
|
|
+ />
|
|
|
|
|
+ <TextInput
|
|
|
|
|
+ secureTextEntry={this.state.wrongCount}
|
|
|
|
|
+ style={styles.inputView}
|
|
|
|
|
+ placeholder={$t('sign.labelNewPassword')}
|
|
|
|
|
+ placeholderTextColor={textPlacehoder}
|
|
|
|
|
+ maxLength={20}
|
|
|
|
|
+ onChangeText={(value) => this.applyStrength(value)}
|
|
|
|
|
+ />
|
|
|
|
|
+ <Pressable
|
|
|
|
|
+ style={[Styles.backIcon, {position: 'absolute', right: 0}]}
|
|
|
|
|
+ android_ripple={rippleLess}
|
|
|
|
|
+ onPress={() => this.changeSecurety()}>
|
|
|
|
|
+ <MaterialCommunityIcons
|
|
|
|
|
+ name={this.state.wrongCount ? "eye-off" : "eye"}
|
|
|
|
|
+ size={20}
|
|
|
|
|
+ color={textCancel}/>
|
|
|
|
|
+ </Pressable>
|
|
|
|
|
+ <View style={this.getStrengthStyle()}></View>
|
|
|
|
|
+ </View>
|
|
|
|
|
+ {/* <View style={styles.signInput}>
|
|
|
|
|
+ <Text style={styles.inputLabel}></Text>
|
|
|
|
|
+ <View style={styles.passwordView}>
|
|
|
|
|
+ <View style={styles.strengthView}>
|
|
|
|
|
+ <Text style={{fontSize:12, paddingRight: 4, color: textPrimary}}>Password Strength</Text>
|
|
|
|
|
+ <StrengthView {...this.state}/>
|
|
|
|
|
+ </View>
|
|
|
|
|
+ <View>
|
|
|
|
|
+ <Text style={styles.passwordRole}>Your Password Must Have:</Text>
|
|
|
|
|
+ <Text style={styles.passwordRole}>- 8 or more characters</Text>
|
|
|
|
|
+ {/* <Text style={styles.passwordRole}>- upper and lower case letters</Text> *}
|
|
|
|
|
+ <Text style={styles.passwordRole}>- at least one number</Text>
|
|
|
|
|
+ </View>
|
|
|
|
|
+ </View>
|
|
|
|
|
+ </View> */}
|
|
|
|
|
+ <View style={[styles.signInput, {borderBottomColor: this.state.confirmStatusColor}]}>
|
|
|
|
|
+ {/* <Text style={styles.inputLabel}>Confirm Password</Text> */}
|
|
|
|
|
+ <Image
|
|
|
|
|
+ style={styles.inputIcon}
|
|
|
|
|
+ source={require('../../images/user/sign-password.png')}
|
|
|
|
|
+ />
|
|
|
|
|
+ <TextInput
|
|
|
|
|
+ secureTextEntry={this.state.wrongCount}
|
|
|
|
|
+ style={styles.inputView}
|
|
|
|
|
+ placeholder={$t('sign.labelConfirmPassword')}
|
|
|
|
|
+ placeholderTextColor={textPlacehoder}
|
|
|
|
|
+ maxLength={20}
|
|
|
|
|
+ onChangeText={v => this.changeInfo('password', v)}
|
|
|
|
|
+ />
|
|
|
|
|
+ </View>
|
|
|
|
|
+ <Button
|
|
|
|
|
+ text={$t('common.confirm')}
|
|
|
|
|
+ style={styles.resetButton}
|
|
|
|
|
+ onClick={() => this.onResetPassword()}
|
|
|
|
|
+ />
|
|
|
|
|
+ </View>
|
|
|
|
|
+ {/* <Text style={styles.divideText}>We will send you an email with the verification code.</Text> */}
|
|
|
|
|
+ </ScrollView>
|
|
|
|
|
+ </View>
|
|
|
|
|
+ );
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+const styles = StyleSheet.create({
|
|
|
|
|
+ header: {
|
|
|
|
|
+ paddingTop: 56,
|
|
|
|
|
+ backgroundColor: colorThemes
|
|
|
|
|
+ },
|
|
|
|
|
+ backView: {
|
|
|
|
|
+ top: 12,
|
|
|
|
|
+ zIndex: 5,
|
|
|
|
|
+ padding: 16,
|
|
|
|
|
+ position: 'absolute',
|
|
|
|
|
+ flexDirection: 'row'
|
|
|
|
|
+ },
|
|
|
|
|
+ backButton: {
|
|
|
|
|
+ borderRadius: 60,
|
|
|
|
|
+ backgroundColor: colorLight
|
|
|
|
|
+ },
|
|
|
|
|
+ backButtonView: {
|
|
|
|
|
+ height: 43,
|
|
|
|
|
+ paddingLeft: 16,
|
|
|
|
|
+ paddingRight: 16,
|
|
|
|
|
+ alignItems: 'center',
|
|
|
|
|
+ flexDirection: 'row'
|
|
|
|
|
+ },
|
|
|
|
|
+ scollView: {
|
|
|
|
|
+ flex: 1,
|
|
|
|
|
+ backgroundColor: colorLight
|
|
|
|
|
+ },
|
|
|
|
|
+ logoView: {
|
|
|
|
|
+ paddingTop: 40,
|
|
|
|
|
+ paddingBottom: 56,
|
|
|
|
|
+ alignItems: 'center'
|
|
|
|
|
+ },
|
|
|
|
|
+ logoImg: {
|
|
|
|
|
+ width:165.09,
|
|
|
|
|
+ height: 51.94,
|
|
|
|
|
+ },
|
|
|
|
|
+ resetView: {
|
|
|
|
|
+ flex: 1,
|
|
|
|
|
+ padding: 16,
|
|
|
|
|
+ marginTop: -12,
|
|
|
|
|
+ borderTopLeftRadius: 20,
|
|
|
|
|
+ borderTopRightRadius: 20,
|
|
|
|
|
+ backgroundColor: colorLight
|
|
|
|
|
+ },
|
|
|
|
|
+ inputIcon: {
|
|
|
|
|
+ width: 24,
|
|
|
|
|
+ height: 24
|
|
|
|
|
+ },
|
|
|
|
|
+ title: {
|
|
|
|
|
+ color: textPrimary,
|
|
|
|
|
+ fontSize: 18,
|
|
|
|
|
+ fontWeight: '700',
|
|
|
|
|
+ paddingTop: 4,
|
|
|
|
|
+ paddingBottom: 6,
|
|
|
|
|
+ },
|
|
|
|
|
+ signInput: {
|
|
|
|
|
+ marginTop: 16,
|
|
|
|
|
+ ...$padding(6, 16),
|
|
|
|
|
+ alignItems: 'center',
|
|
|
|
|
+ flexDirection: 'row',
|
|
|
|
|
+ borderBottomWidth: 1,
|
|
|
|
|
+ borderBottomColor: '#F5F5F5'
|
|
|
|
|
+ },
|
|
|
|
|
+ inputLabel: {
|
|
|
|
|
+ flex: 1,
|
|
|
|
|
+ color: textPrimary,
|
|
|
|
|
+ fontSize: 14
|
|
|
|
|
+ },
|
|
|
|
|
+ inputView: {
|
|
|
|
|
+ flex: 2,
|
|
|
|
|
+ color: textPrimary,
|
|
|
|
|
+ fontSize: 14,
|
|
|
|
|
+ borderRadius: 5,
|
|
|
|
|
+ minHeight: 40,
|
|
|
|
|
+ ...$padding(6, 16),
|
|
|
|
|
+ //backgroundColor: '#F5F5F5'
|
|
|
|
|
+ },
|
|
|
|
|
+ passwordView: {
|
|
|
|
|
+ flex: 2,
|
|
|
|
|
+ marginTop: -8,
|
|
|
|
|
+ },
|
|
|
|
|
+ passwordRole: {
|
|
|
|
|
+ color: '#999',
|
|
|
|
|
+ fontSize: 10,
|
|
|
|
|
+ lineHeight: 13
|
|
|
|
|
+ },
|
|
|
|
|
+ sendBtn: {
|
|
|
|
|
+ flex: 1.4,
|
|
|
|
|
+ marginLeft: 6,
|
|
|
|
|
+ marginRight: -6,
|
|
|
|
|
+ borderRadius: 6
|
|
|
|
|
+ },
|
|
|
|
|
+ sendBtnView: {
|
|
|
|
|
+ flex: 1,
|
|
|
|
|
+ height: 40,
|
|
|
|
|
+ paddingLeft: 4,
|
|
|
|
|
+ paddingRight: 4,
|
|
|
|
|
+ alignItems: 'center',
|
|
|
|
|
+ justifyContent: 'center'
|
|
|
|
|
+ },
|
|
|
|
|
+ sendBtnText: {
|
|
|
|
|
+ color: textButton,
|
|
|
|
|
+ fontSize: 13,
|
|
|
|
|
+ fontWeight: 'bold'
|
|
|
|
|
+ },
|
|
|
|
|
+ divideText: {
|
|
|
|
|
+ color: textPrimary,
|
|
|
|
|
+ fontSize: 14,
|
|
|
|
|
+ padding: 58,
|
|
|
|
|
+ textAlign: 'center'
|
|
|
|
|
+ },
|
|
|
|
|
+ resetButton: {
|
|
|
|
|
+ marginTop: 32,
|
|
|
|
|
+ marginBottom: 16
|
|
|
|
|
+ }
|
|
|
|
|
+})
|