Explorar el Código

add app/pages/sign/ResetPassword.js

wudebin hace 5 meses
padre
commit
e7025f7c69

+ 367 - 0
Strides-SPAPP/app/pages/sign/ResetPassword.js

@@ -0,0 +1,367 @@
+/**
+ * 忘记密码-重置密码页面
+ * @邠心vbe on 2021/10/18
+ */
+import React, { Component } from 'react';
+import { View, Text, StyleSheet, ScrollView, Image, TextInput } from 'react-native';
+import apiUser from '../../api/apiUser';
+import Button from '../../components/Button';
+import Dialog from '../../components/Dialog';
+import { BackIcon } from '../../components/Toolbar';
+import utils from '../../utils/utils';
+import { StrengthView } from './Register';
+
+export default class ResetPassword extends Component {
+  constructor(props) {
+    super(props);
+    this.state = {
+      strength: 0,
+      password: '',
+      wrongCount: 0,
+      sendMinutes: 0
+    };
+    this.formInfo = {
+      email: '',
+      password: '',
+      verificationCode: ''
+    }
+  }
+
+  componentWillUnmount() {
+    this.setState({
+      sendMinutes: 0
+    })
+  }
+
+  getBackTopPosition() {
+    return isIOS ? statusHeight - 18 : 12;
+  }
+
+  changeInfo(key, value) {
+    this.formInfo[key] = value;
+  }
+
+  applyStrength(text) {
+    var strength = 0;
+    if (text.length >= 8) {
+      strength += 1;
+    }
+    if (/\d{1,}/.test(text)) {
+      strength += 1;
+    }
+    if (/[A-z]{1,}/.test(text)) {
+      strength += 1;
+    }
+    /*if (/[A-Z]{1,}/.test(text)) {
+      strength += 1;
+    }
+    if (/\W{1,}/.test(text)) {
+      strength += 1;
+    }*/
+    if (this.state.strength != strength) {
+      this.setState({
+        password: text,
+        strength: strength
+      });
+    } else {
+      this.setState({
+        password: text
+      });
+    }
+  }
+
+  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 = 60;
+      toastShort('Send verification code successfully');
+      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 (!this.state.password) {
+      toastShort('Please enter password');
+      return;
+    }
+    if (this.state.strength < 3) {
+      toastShort('Password is not strong');
+      return;
+    }
+    if (!info.password) {
+      toastShort('Please enter confirm password');
+      return;
+    }
+    if (info.password != this.state.password) {
+      toastShort('The twice passwords are inconsistent');
+      return;
+    }
+    if (!info.verificationCode) {
+      toastShort('Please enter verification code');
+      return;
+    }
+    Dialog.showProgressDialog()
+    apiUser.updatePassword(this.formInfo).then(res => {
+      Dialog.dismissLoading()
+      toastShort('Reset password successfully');
+      goBack();
+    }).catch(err => {
+      Dialog.dismissLoading()
+      toastShort(err);
+    });
+  }
+
+  render() {
+    return (
+      <View style={StyleSheet.absoluteFillObject}>
+        <ScrollView
+          style={styles.scollView}
+          keyboardShouldPersistTaps={isIOS ? 'never' : 'handled'}>
+          <View style={styles.header}>
+            <View style={styles.logoView}>
+              <Image
+                style={styles.logoImg}
+                resizeMode="contain"
+                source={require('../../images/app-logo.png')}/>
+            </View>
+          </View>
+          <View style={{...styles.backView, top: this.getBackTopPosition()}}>
+            <Button
+              style={styles.backButton}
+              viewStyle={styles.backButtonView}
+              onClick={() => goBack()}>
+              <BackIcon/>
+              <Text style={{color: textPrimary,fontSize: 16,paddingLeft: 8}}>Back to Login</Text>
+            </Button>
+          </View>
+          <View style={styles.resetView}>
+            <Text style={styles.title}>Reset Password</Text>
+            <View style={styles.signInput}>
+              <Text style={styles.inputLabel}>Email Address</Text>
+              <TextInput
+                style={styles.inputView}
+                placeholder='Email Address'
+                placeholderTextColor={textPlacehoder}
+                maxLength={50}
+                onChangeText={v => this.changeInfo('email', v)}
+              />
+            </View>
+            <View style={styles.signInput}>
+              <Text style={styles.inputLabel}>New Password</Text>
+              <TextInput
+                secureTextEntry={this.state.wrongCount < 3}
+                style={styles.inputView}
+                placeholder='Password'
+                placeholderTextColor={textPlacehoder}
+                maxLength={20}
+                onChangeText={(value) => {
+                  this.applyStrength(value);
+                }}
+              />
+            </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}>
+              <Text style={styles.inputLabel}>Confirm Password</Text>
+              <TextInput
+                secureTextEntry={this.state.wrongCount < 3}
+                style={styles.inputView}
+                placeholder='Password'
+                placeholderTextColor={textPlacehoder}
+                maxLength={20}
+                onChangeText={v => this.changeInfo('password', v)}
+              />
+            </View>
+            <View style={styles.signInput}>
+              <Text style={[styles.inputLabel, ui.flex2]}>Verification Code</Text>
+              <TextInput
+                style={[styles.inputView, {flex: 2.6, marginLeft: 2}]}
+                placeholder='Verification Code'
+                placeholderTextColor={textPlacehoder}
+                maxLength={6}
+                onChangeText={v => this.changeInfo('verificationCode', v)}
+              />
+              <Button
+                text={this.state.sendMinutes > 0 ? this.state.sendMinutes : 'Get Code'}
+                style={styles.sendBtn}
+                disabled={this.state.sendMinutes > 0}
+                viewStyle={styles.sendBtnView}
+                textStyle={styles.sendBtnText}
+                onClick={() => this.sendVerification()}
+              />
+            </View>
+          </View>
+          <Text style={styles.divideText}>We will send you an email with the verification code.</Text>
+          <Button
+            text='Reset Password'
+            style={styles.resetButton}
+            onClick={() => this.onResetPassword()}
+          />
+        </ScrollView>
+      </View>
+    );
+  }
+}
+
+const styles = StyleSheet.create({
+  header: {
+    paddingTop: 56,
+    backgroundColor: colorAccent
+  },
+  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: pageBackground
+  },
+  logoView: {
+    paddingTop: 40,
+    paddingBottom: 56,
+    alignItems: 'center'
+  },
+  logoImg: {
+    width:165.09,
+    height: 51.94,
+  },
+  resetView: {
+    flex: 1,
+    padding: 16,
+    marginTop: -30,
+    borderTopLeftRadius: 20,
+    borderTopRightRadius: 20,
+    backgroundColor: colorLight
+  },
+  title: {
+    color: textPrimary,
+    fontSize: 18,
+    fontWeight: '700',
+    paddingTop: 4,
+    paddingBottom: 6,
+  },
+  signInput: {
+    marginTop: 16,
+    alignItems: 'center',
+    flexDirection: 'row'
+  },
+  inputLabel: {
+    flex: 1,
+    color: textPrimary,
+    fontSize: 14
+  },
+  inputView: {
+    flex: 2,
+    color: textPrimary,
+    fontSize: 14,
+    borderRadius: 5,
+    minHeight: 40,
+    paddingTop: 6,
+    paddingLeft: 12,
+    paddingRight: 12,
+    paddingBottom: 6,
+    backgroundColor: '#F5F5F5'
+  },
+  passwordView: {
+    flex: 2,
+    marginTop: -8,
+  },
+  strengthView: {
+    marginTop: -4,
+    alignItems: 'center',
+    paddingBottom: 4,
+    flexDirection: 'row'
+  },
+  passwordRole: {
+    color: '#999',
+    fontSize: 10,
+    lineHeight: 13
+  },
+  sendBtn: {
+    flex: 1.4,
+    marginLeft: 6
+  },
+  sendBtnView: {
+    flex: 1,
+    height: 40,
+    paddingLeft: 4,
+    paddingRight: 4,
+    alignItems: 'center',
+    justifyContent: 'center'
+  },
+  sendBtnText: {
+    color: textPrimary,
+    fontSize: 13,
+    fontWeight: 'bold'
+  },
+  divideText: {
+    color: textPrimary,
+    fontSize: 14,
+    padding: 58,
+    textAlign: 'center'
+  },
+  resetButton: {
+    margin: 16
+  }
+})

+ 454 - 0
Strides-SPAPP/app/pages/sign/ResetPasswordV2.js

@@ -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
+  }
+})