RegisterVL.js 15 KB

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