RegisterVL.js 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532
  1. /**
  2. * LUMI版本Register页面
  3. * @邠心vbe on 2024/05/31
  4. */
  5. import React, { Component } from 'react';
  6. import { View, ScrollView, StyleSheet, TextInput, Pressable } from 'react-native';
  7. import apiUser from '../../api/apiUser';
  8. import Button from '../../components/Button';
  9. import { PageList } from '../Router';
  10. import Dialog from '../../components/Dialog';
  11. import Dropdown from '../../components/Dropdown';
  12. import { CountryDropNum, GetCountryList } from '../../components/CountryIcon';
  13. import CheckBox from '../../components/CheckBox';
  14. import TextView from '../../components/TextView';
  15. import utils from '../../utils/utils';
  16. export default class RegisterVL extends Component {
  17. constructor(props) {
  18. super(props);
  19. this.state = {
  20. agree: true,
  21. countryNum: '65',
  22. countryCode: "SG",
  23. userInfo: {
  24. email: "",
  25. phone: "",
  26. vehicle: {},
  27. password: "",
  28. verificationCode: ""
  29. },
  30. countryList: [],
  31. params: {...this.props.route.params},
  32. email: '',
  33. password: '',
  34. sendMinutes: 0,
  35. strengthCheck: {
  36. minLength: false,
  37. wordCase: false,
  38. oneNumber: false,
  39. allCheck: false
  40. },
  41. showPassword: false
  42. };
  43. }
  44. componentDidMount() {
  45. this.getCountryList();
  46. }
  47. togglePassword() {
  48. this.setState({
  49. showPassword: !this.state.showPassword
  50. })
  51. }
  52. applyStrength(text) {
  53. const strength = this.state.strengthCheck;
  54. strength.allCheck = true;
  55. if (text.length >= 8) {
  56. strength.minLength = true;
  57. } else {
  58. strength.minLength = false;
  59. strength.allCheck = false;
  60. }
  61. if (/\d{1,}/.test(text)) {
  62. strength.oneNumber = true;
  63. } else {
  64. strength.oneNumber = false;
  65. strength.allCheck = false;
  66. }
  67. if (/[a-z]{1,}/.test(text) && /[A-Z]{1,}/.test(text)) {
  68. strength.wordCase = true;
  69. } else {
  70. strength.wordCase = false;
  71. strength.allCheck = false;
  72. }
  73. this.setState({
  74. password: text,
  75. strengthCheck: strength
  76. });
  77. }
  78. changeInfo(key, value) {
  79. var info = this.state.userInfo;
  80. info[key] = value;
  81. this.setState({
  82. 'userInfo': info
  83. });
  84. }
  85. changeAgree(ag) {
  86. this.setState({
  87. agree: ag
  88. })
  89. }
  90. changeCountry(value, index) {
  91. this.setState({
  92. countryCode: value
  93. })
  94. if (this.canChangeCalling) {
  95. const country = this.state.countryList[index]
  96. this.changeCalling(country.countryNum, -1);
  97. }
  98. }
  99. changeCalling(value, index) {
  100. this.setState({
  101. countryNum: value
  102. })
  103. if (index >= 0) {
  104. this.canChangeCalling = false;
  105. }
  106. }
  107. getCountryList() {
  108. GetCountryList(list => {
  109. this.setState({
  110. countryList: list
  111. })
  112. })
  113. }
  114. sendVerification() {
  115. var info = this.state.userInfo;
  116. if (!info.email) {
  117. toastShort($t('sign.plsInputEmail'));
  118. return;
  119. }
  120. if (!utils.isValidEmail(info.email)) {
  121. toastShort($t('sign.errEmailFormat'));
  122. return;
  123. }
  124. Dialog.showProgressDialog()
  125. apiUser.sendVerificationCodeV2({email: info.email, type: "register"}).then(res => {
  126. Dialog.dismissLoading()
  127. //this.state.sendMinutes = 60;
  128. this.state.sendMinutes = res.data?.resendTime ?? 60;
  129. toastShort($t('sign.sendOTPSuccess'));
  130. this.contdownTime();
  131. }).catch(err => {
  132. Dialog.dismissLoading()
  133. toastShort(err);
  134. });
  135. }
  136. contdownTime() {
  137. if (this.state.sendMinutes > 0) {
  138. this.setState({
  139. sendMinutes: this.state.sendMinutes - 1
  140. })
  141. setTimeout(() => {
  142. this.contdownTime();
  143. }, 1000);
  144. }
  145. }
  146. onRegister() {
  147. //console.log('sign up', this.state);
  148. var info = this.state.userInfo;
  149. if (!info.nickName) {
  150. toastShort($t('sign.plsInputDiaplayName'));
  151. return;
  152. }
  153. if (!info.email) {
  154. toastShort($t('sign.plsInputEmail'));
  155. return;
  156. }
  157. if (!utils.isValidEmail(info.email)) {
  158. toastShort($t('sign.errEmailFormat'));
  159. return;
  160. }
  161. /*if (!info.verificationCode) {
  162. toastShort($t('sign.plsInputOTP'));
  163. return;
  164. }*/
  165. if (!info.phone) {
  166. toastShort($t('sign.plsInputContactNo'));
  167. return;
  168. }
  169. if (!/^\d{6,15}$/.test(info.phone)) {
  170. toastShort($t('sign.errContactNoFormat'));
  171. return;
  172. }
  173. if (!this.state.password) {
  174. toastShort($t('sign.plsInputPassword'));
  175. return;
  176. }
  177. if (!this.state.strengthCheck.allCheck) {
  178. toastShort($t('sign.errPasswordStrong'));
  179. return;
  180. }
  181. if (!info.password) {
  182. toastShort($t('sign.plsInputPassword2'));
  183. return;
  184. }
  185. if (info.password != this.state.password) {
  186. toastShort($t('sign.errPasswordConfirm'));
  187. return;
  188. }
  189. if (this.state.isFleetDriver) {
  190. if (!info.pdvLicence) {
  191. toastShort($t('sign.plsInputPDVLicence'));
  192. return;
  193. }
  194. if (this.state.pdvImages[0] == '' || this.state.pdvImages[1] == '') {
  195. toastShort($t('sign.plsUploadLicencePhotos'));
  196. return;
  197. }
  198. }
  199. let param = Object.assign({}, info);
  200. //param.phone = this.state.countryNum + info.phone
  201. param.callingCode = this.state.countryNum;
  202. param.countryCode = this.state.countryCode;
  203. if (this.state.isFleetDriver) {
  204. param.userType = 'Driver';
  205. param.pdvLicencePictures = this.state.pdvImages;
  206. param.fleetCompanyId = this.state.fleetCompanyId;
  207. } else {
  208. param.userType = 'Public';
  209. }
  210. param.otp = param.verificationCode;
  211. param.vehicle = this.state.vehicleInfo;
  212. console.log('params', param);
  213. Dialog.showProgressDialog();
  214. apiUser.register(param).then(res => {
  215. Dialog.dismissLoading();
  216. //toastShort('Sign up successfully!');
  217. if (isIOS) {
  218. setTimeout(() => {
  219. this.showSuccessDialog();
  220. }, 600);
  221. } else {
  222. this.showSuccessDialog();
  223. }
  224. }).catch(err => {
  225. toastShort(err);
  226. Dialog.dismissLoading();
  227. });
  228. }
  229. render() {
  230. return (
  231. <ScrollView
  232. style={styles.container}
  233. contentContainerStyle={$padding(16)}
  234. keyboardShouldPersistTaps={isIOS ? 'never' : 'handled'}>
  235. {/* <TextView style={styles.textTitle}>Registration details</TextView>
  236. <TextView style={styles.textSubTitle}>Please input relevant info as stated</TextView> */}
  237. <View style={styles.signInput}>
  238. <TextInput
  239. style={styles.inputView}
  240. placeholder={$t('sign.labelDisplayName')}
  241. placeholderTextColor={textPlacehoder}
  242. maxLength={50}
  243. onChangeText={v => this.changeInfo('nickName', v)}
  244. />
  245. </View>
  246. <View style={styles.signInput}>
  247. <TextInput
  248. style={styles.inputView}
  249. placeholder={$t('sign.labelEmail')}
  250. placeholderTextColor={textPlacehoder}
  251. maxLength={50}
  252. keyboardType="email-address"
  253. textContentType='emailAddress'
  254. onChangeText={v => this.changeInfo('email', v)}
  255. />
  256. </View>
  257. {/* <View style={ui.flexc}>
  258. <View style={[styles.signInput, ui.flex2]}>
  259. <TextInput
  260. style={[styles.inputView, {flex: 2.2, marginLeft: 2}]}
  261. placeholder={"Validate OTP"}
  262. placeholderTextColor={textPlacehoder}
  263. maxLength={6}
  264. keyboardType="number-pad"
  265. textContentType="telephoneNumber"
  266. onChangeText={v => this.changeInfo('verificationCode', v)}
  267. />
  268. </View>
  269. <Button
  270. text={this.state.sendMinutes > 0 ? (this.state.sendMinutes + " s") : $t('sign.btnSendOTP')}
  271. style={styles.sendBtn}
  272. disabled={this.state.sendMinutes > 0}
  273. viewStyle={styles.sendBtnView}
  274. textStyle={styles.sendBtnText}
  275. onClick={() => this.sendVerification()}
  276. />
  277. </View> */}
  278. <View style={ui.flexc}>
  279. <View style={[styles.signInput, styles.dropView]}>
  280. <TextInput style={styles.dropInput} editable={false}/>
  281. <TextView style={styles.countryText}>{"+" + this.state.countryNum}</TextView>
  282. <MaterialIcons name={'keyboard-arrow-down'} size={24} color={colorDark}/>
  283. <Dropdown
  284. style={styles.dropLayer}
  285. prefixText="+"
  286. list={this.state.countryList}
  287. value={this.state.countryNum}
  288. nameKey='countryNum'
  289. valueKey='countryNum'
  290. onChange={(value, index)=> this.changeCalling(value, index)}
  291. customerItemView={
  292. (item, index, onClick) =>
  293. <CountryDropNum
  294. key={index}
  295. country={item}
  296. value={this.state.countryNum}
  297. onClick={onClick}/>
  298. }/>
  299. </View>
  300. <View style={[styles.signInput, ui.flex2]}>
  301. <TextInput
  302. style={styles.inputView}
  303. placeholder={$t('sign.labelMobileNumber')}
  304. placeholderTextColor={textPlacehoder}
  305. keyboardType='phone-pad'
  306. maxLength={15}
  307. onChangeText={v => this.changeInfo('phone', v)}
  308. />
  309. </View>
  310. </View>
  311. <View style={styles.signInput}>
  312. <TextInput
  313. secureTextEntry={!this.state.showPassword}
  314. style={styles.inputView}
  315. placeholder={$t('sign.labelPassword')}
  316. placeholderTextColor={textPlacehoder}
  317. maxLength={20}
  318. onChangeText={(value) => this.applyStrength(value)}/>
  319. <MaterialCommunityIcons
  320. name={this.state.showPassword ? "eye" : "eye-off"}
  321. size={16}
  322. color={"#DADADA"}
  323. onPress={() => this.togglePassword()}/>
  324. </View>
  325. <View style={styles.passwordTipView}>
  326. {/* <TextView style={styles.passwordTipText}>Your password must have:</TextView> */}
  327. <View style={ui.flexc}>
  328. <MaterialIcons
  329. name="check-circle-outline"
  330. color={this.state.strengthCheck.minLength ? colorAccent : colorCancel}
  331. size={18}/>
  332. <TextView style={styles.passwordTipText}>8 or more characters</TextView>
  333. </View>
  334. <View style={ui.flexc}>
  335. <MaterialIcons
  336. name="check-circle-outline"
  337. color={this.state.strengthCheck.wordCase ? colorAccent : colorCancel}
  338. size={18}/>
  339. <TextView style={styles.passwordTipText}>Upper and Lower case letters</TextView>
  340. </View>
  341. <View style={ui.flexc}>
  342. <MaterialIcons
  343. name="check-circle-outline"
  344. color={this.state.strengthCheck.oneNumber ? colorAccent : colorCancel}
  345. size={18}/>
  346. <TextView style={styles.passwordTipText}>At least one number</TextView>
  347. </View>
  348. </View>
  349. <View style={styles.signInput}>
  350. <TextInput
  351. secureTextEntry={!this.state.showPassword}
  352. style={styles.inputView}
  353. placeholder={$t('sign.labelConfirmPassword')}
  354. placeholderTextColor={textPlacehoder}
  355. maxLength={20}
  356. onChangeText={v => this.changeInfo('password', v)}/>
  357. <MaterialCommunityIcons
  358. name={this.state.showPassword ? "eye" : "eye-off"}
  359. size={16}
  360. color={"#DADADA"}
  361. onPress={() => this.togglePassword()}/>
  362. </View>
  363. <EndView/><EndView half/>
  364. {/* <TextView style={styles.textTitle}>Got A Referral Code?</TextView>
  365. <TextView style={styles.textSubTitle}>Please input the code from your referrer</TextView>
  366. <View style={styles.signInput}>
  367. <TextInput
  368. style={styles.inputView}
  369. placeholder={"Referral Code"}
  370. placeholderTextColor={textPlacehoder}
  371. maxLength={6}
  372. onChangeText={v => this.changeInfo('referralCode', v)}/>
  373. </View> */}
  374. <View style={styles.agreeView}>
  375. <CheckBox
  376. value={this.state.agree}
  377. onValueChange={v => this.changeAgree(v)}
  378. />
  379. <View style={styles.agreeTextRow}>
  380. <TextView style={styles.agreeText} onPress={() => this.changeAgree(!this.state.agree)}>
  381. {$t('sign.iHaveReadAndAgree')}
  382. </TextView>
  383. <TextView style={styles.agreeLink} onPress={() => startPage(PageList.condition)}>{$t('drawer.termsOfUse')}</TextView>
  384. <TextView style={styles.agreeText}>{' '}</TextView>
  385. <TextView style={styles.agreeText}>{$t('sign.linkAndLink')}</TextView>
  386. <TextView style={styles.agreeLink} onPress={() => startPage(PageList.privacy)}>{$t('drawer.privacyPolicy')}</TextView>
  387. <TextView style={styles.agreeText}>{$t('sign.linkAndLinkEnd')}</TextView>
  388. </View>
  389. </View>
  390. <Button
  391. style={styles.signButton}
  392. elevation={0}
  393. disabled={!this.state.agree}
  394. text={$t('sign.btnRegister')}
  395. fontSize={14}
  396. onClick={() => this.onRegister()}/>
  397. </ScrollView>
  398. );
  399. }
  400. }
  401. const styles = StyleSheet.create({
  402. container: {
  403. flex: 1,
  404. backgroundColor: colorLight
  405. },
  406. textTitle: {
  407. color: textPrimary,
  408. fontSize: 16,
  409. fontWeight: "bold"
  410. },
  411. textSubTitle: {
  412. color: textSecondary,
  413. fontSize: 12
  414. },
  415. signInput: {
  416. marginTop: 16,
  417. borderRadius: 0,
  418. paddingLeft: 16,
  419. paddingRight: 16,
  420. alignItems: 'center',
  421. flexDirection: 'row',
  422. borderWidth: 1,
  423. borderRadius: 4,
  424. borderColor: "#DADADA"
  425. },
  426. inputView: {
  427. flex: 1,
  428. height: 48,
  429. color: textPrimary,
  430. fontSize: 12
  431. },
  432. sendBtn: {
  433. flex: 1.2,
  434. marginLeft: 16,
  435. marginRight: 0,
  436. marginTop: 16,
  437. borderRadius: 6,
  438. backgroundColor: colorPrimary
  439. },
  440. sendBtnView: {
  441. flex: 1,
  442. height: 48,
  443. paddingLeft: 4,
  444. paddingRight: 4,
  445. alignItems: 'center',
  446. justifyContent: 'center'
  447. },
  448. sendBtnText: {
  449. color: textButton,
  450. fontSize: 13,
  451. fontWeight: 'bold'
  452. },
  453. dropView: {
  454. flex: 1,
  455. marginRight: 16,
  456. paddingRight: 8,
  457. alignItems: "center",
  458. flexDirection: "row"
  459. },
  460. dropLayer: {
  461. left: 0,
  462. right: 0,
  463. opacity: 0,
  464. position: 'absolute'
  465. },
  466. dropInput: {
  467. width: 8,
  468. color: textPrimary,
  469. height: 48
  470. },
  471. countryText: {
  472. flex: 1,
  473. color: "#9D9D9D",
  474. fontSize: 14,
  475. paddingRight: 4
  476. },
  477. passwordTipView: {
  478. paddingTop: 8
  479. },
  480. passwordTipText: {
  481. color: "#666",
  482. fontSize: 14,
  483. paddingTop: 2,
  484. paddingLeft: 8,
  485. paddingBottom: 2
  486. },
  487. agreeView: {
  488. marginTop: 48,
  489. marginBottom: 16,
  490. alignItems: 'center',
  491. flexDirection: 'row'
  492. },
  493. agreeTextRow: {
  494. flex: 1,
  495. paddingTop: 4,
  496. paddingLeft: 8,
  497. flexWrap: 'wrap',
  498. flexDirection: 'row'
  499. },
  500. agreeText: {
  501. color: textPrimary,
  502. fontSize: 14,
  503. paddingTop: 2,
  504. paddingBottom: 2
  505. },
  506. agreeLink: {
  507. ...ui.link,
  508. fontSize: 14,
  509. paddingTop: 2,
  510. paddingBottom: 2,
  511. textDecorationLine: 'underline'
  512. },
  513. signButton: {
  514. marginBottom: 24,
  515. borderRadius: 4,
  516. backgroundColor: colorPrimary
  517. }
  518. })