vbea 2 лет назад
Родитель
Сommit
b29d727da3

+ 15 - 0
Strides-APP/app/api/apiMember.js

@@ -0,0 +1,15 @@
+import { get, post } from "./http";
+
+const prefix = 'devicesApi/group/';
+
+export default {
+  getMembersOption() {
+    return get(prefix + "memberships")
+  },
+  applyMembers(params) {
+    return post(prefix + "user-memberships", params)
+  },
+  getMyMemberList() {
+    return get(prefix + "user-memberships")
+  }
+}

+ 17 - 2
Strides-APP/app/i18n/locales/en.js

@@ -73,7 +73,9 @@ export default {
     termsOfUse: "Terms of Use",
     topUp: "Purchase Credits",
     topUpWithCard: "Top Up with Card",
-    wallet: "Transactions"
+    wallet: "Transactions",
+    applyMember: "Apply Membership",
+    yourMembers: "Your Membership"
   },
   sign: {
     aConfirmationEmailTo: "a confirmation email has been sent to",
@@ -168,7 +170,8 @@ export default {
     termsOfUse: "Terms of Use",
     mapsTest: "Maps Test",
     debugOnly: "Debug Mode Options Only",
-    noChargingSession: "No charging session found"
+    noChargingSession: "No charging session found",
+    members: "Members",
   },
   profile: {
     address: "Address",
@@ -414,5 +417,17 @@ export default {
     tipsLetKnow: "Please let us know below!",
     tipsSomething: "Have something to tell us?",
     typeOfFeedback: "Type of Feedback"
+  },
+  members: {
+    membership: "Membership",
+    membershipNo: "Membership No.",
+    status: "Status",
+    statusApproved: "Approved",
+    statusPending: "Pending",
+    statusRejected: "Rejected",
+    labelUpload: "Upload\nMembership Card\n(Front)",
+    noData: "You not have any membership",
+    errMembershipNo: "Please type Membership No",
+    errUploadCard: "Please upload Membership Card"
   }
 }

+ 17 - 2
Strides-APP/app/i18n/locales/zh-TW.js

@@ -73,7 +73,9 @@
     termsOfUse: "使用條款",
     topUp: "餘額充值",
     topUpWithCard: "使用信用卡充值",
-    wallet: "餘額"
+    wallet: "餘額",
+    applyMember: "申請會員",
+    yourMembers: "我的會員"
   },
   sign: {
     aConfirmationEmailTo: "我們已向以下信箱發送壹封確認電子郵件",
@@ -168,7 +170,8 @@
     termsOfUse: "使用條款",
     mapsTest: "地圖測試",
     debugOnly: "以下爲調試模式獨有項",
-    noChargingSession: "您未在充電"
+    noChargingSession: "您未在充電",
+    members: "我的會員",
   },
   profile: {
     address: "地區",
@@ -414,5 +417,17 @@
     tipsLetKnow: "請在下面告訴我們!",
     tipsSomething: "有遇到什麽問題嗎?",
     typeOfFeedback: "反饋類型"
+  },
+  members: {
+    membership: "發卡商",
+    membershipNo: "會員卡號",
+    status: "狀態",
+    statusApproved: "審核通過",
+    statusPending: "等待審核",
+    statusRejected: "審核拒絕",
+    labelUpload: "請上載會員卡\n前面相片",
+    noData: "你還没有申請任何会员",
+    errMembershipNo: "請鍵入會員卡號",
+    errUploadCard: "請上載會員卡相片"
   }
 }

+ 17 - 2
Strides-APP/app/i18n/locales/zh.js

@@ -73,7 +73,9 @@ export default {
     termsOfUse: "使用条款",
     topUp: "余额充值",
     topUpWithCard: "使用信用卡充值",
-    wallet: "余额"
+    wallet: "余额",
+    applyMember: "申请会员",
+    yourMembers: "我的会员"
   },
   sign: {
     aConfirmationEmailTo: "我们已向以下邮箱发送一封确认电子邮件",
@@ -168,7 +170,8 @@ export default {
     termsOfUse: "使用条款",
     mapsTest: "地图测试",
     debugOnly: "以下为调试模式独有项",
-    noChargingSession: "您未在充电"
+    noChargingSession: "您未在充电",
+    members: "我的会员",
   },
   profile: {
     address: "地址",
@@ -414,5 +417,17 @@ export default {
     tipsLetKnow: "请在下面告诉我们!",
     tipsSomething: "有遇到什么问题吗?",
     typeOfFeedback: "反馈类型"
+  },
+  members: {
+    membership: "发卡方",
+    membershipNo: "会员卡号",
+    status: "状态",
+    statusApproved: "审核通过",
+    statusPending: "待审核",
+    statusRejected: "审核未通过",
+    labelUpload: "请上传会员卡\n正面照片",
+    noData: "你还没有申请任何会员",
+    errMembershipNo: "请输入会员卡号",
+    errUploadCard: "请上传会员卡照片"
   }
 }

+ 27 - 0
Strides-APP/app/pages/Router.js

@@ -53,6 +53,8 @@ import ChargingPage from './chargingV2/ChargingPage';
 import { BridgePage } from '../utils/routeUtil';
 import HeaderTitle from '../components/HeaderTitle';
 import Bookmarks from './bookmark/Bookmarks';
+import MembersList from './member/MembersList';
+import ApplyMember from './member/ApplyMember';
 
 export var PageList = {
   'splash': {
@@ -266,6 +268,31 @@ export var PageList = {
     titleScope: 'route.bookmarks',
     component: Bookmarks
   },
+  'membersList': {
+    title: "Your Membership",
+    titleScope: 'route.yourMembers',
+    component: MembersList,
+    options: {
+      headerRight: () => (
+        <Pressable
+          style={Styles.backIcon}
+          android_ripple={rippleLessIcon}
+          onPress={() => startPage(PageList.applyMember)}>
+          <MaterialCommunityIcons
+            name='plus'
+            color={pageTitleTint}
+            size={24}
+            style={Styles.iconOpacity}
+          />
+        </Pressable>
+      )
+    }
+  },
+  'applyMember': {
+    title: "Apply Membership",
+    titleScope: 'route.applyMember',
+    component: ApplyMember
+  },
   'settings': {
     title: 'Settings',
     titleScope: 'route.settings',

+ 16 - 2
Strides-APP/app/pages/home/Drawer.js

@@ -15,8 +15,8 @@ import { getStorageJsonSync, setStorage, setStorageJson } from '../../utils/stor
 import Button from '../../components/Button';
 import { AutoLogin } from '../sign/Login';
 import apiCharge from '../../api/apiCharge';
-import { toTopupPage } from '../wallet/Payment';
 import { TouchableWithoutFeedback } from 'react-native-gesture-handler';
+import { toTopupPage } from '../payment/PaymentConfig';
 import utils from '../../utils/utils';
 
 const Drawer = createDrawerNavigator();
@@ -346,7 +346,21 @@ const DrawerContent = ({isLogin, userInfo, onLogout, navigation}) => {
         </Button>
       }
       {/*附加功能-结束*/}
-
+      { isLogin &&
+        <Button
+          style={styles.itemButton}
+          viewStyle={styles.itemView}
+          onClick={() => {
+            startPage(PageList.membersList);
+          }}>
+          <MaterialIcons
+            style={styles.icon}
+            name="card-membership"
+            color="#222"
+            size={26}/>
+          <Text style={styles.label}>{$t('drawer.members')}</Text>
+        </Button>
+      }
       <Button
         style={styles.itemButton}
         viewStyle={styles.itemView}

+ 253 - 0
Strides-APP/app/pages/member/ApplyMember.js

@@ -0,0 +1,253 @@
+/**
+ * 申请会员页面
+ * @邠心vbe on 2023/07/14
+ */
+import React, { Component } from 'react';
+import { View, Text, StyleSheet, TextInput } from 'react-native';
+import apiMember from '../../api/apiMember';
+import apiUpload from '../../api/apiUpload';
+import { GetCountryList } from '../../components/CountryIcon';
+import Dropdown from '../../components/Dropdown';
+import { UploadThemes } from '../../components/ThemesConfig';
+import { UploadView } from '../sign/RegisterDriver';
+import ImagePicker from 'react-native-image-crop-picker';
+import CheckBoxText from '../../components/CheckBoxText';
+import Button from '../../components/Button';
+
+const options = {
+  width: 300,
+  height: 200,
+  cropping: true,
+  multiple: false,
+  mediaType: 'photo',
+  writeTempFile: false,
+  compressImageQuality: 0.8,
+  compressImageMaxWidth: 720,
+  compressImageMaxHeight: 1280,
+  ...UploadThemes
+}
+
+export default class ApplyMember extends Component {
+  constructor(props) {
+    super(props);
+    this.state = {
+      agree: true,
+      groupList: [],
+      memberForm: {
+        groupPk: "",
+        membershipNo: "",
+        cardFront: ""
+      }
+    };
+  }
+
+  componentDidMount() {
+    //console.log(this.state.params);
+    //this.getCountryList();
+    this.getGroupList();
+  }
+
+  changeForm(key, value) {
+    const form = {...this.state.memberForm};
+    form[key] = value;
+    this.setState({
+      memberForm: form
+    })
+  }
+
+  getCountryList() {
+    GetCountryList(list => {
+      this.setState({
+        countryNums: list
+      })
+    })
+  }
+
+  getGroupList() {
+    apiMember.getMembersOption().then(res => {
+      if (res.data) {
+        this.setState({
+          groupList: res.data
+        })
+      }
+    }).catch(err => [
+      toastShort(err)
+    ])
+  }
+
+  uploadImage() {
+    ImagePicker.openPicker({
+      ...options,
+      cropperToolbarTitle: $t('common.cropperTitle')
+    }).then(image => {
+      if (image.path) {
+        apiUpload.uploadImage(image.path, image.mime, 'MEMBERSHIP').then(res => {
+          if (res.success && res.data.picturePath) {
+            this.changeForm("cardFront", res.data.picturePath)
+            toastShort($t('common.uploadSuccess'));
+          } else {
+            toastShort($t('common.uploadFailed'));
+          }
+        }).catch(err => {
+          toastShort(err);
+        });
+      }
+    }).catch(err1 => {
+      //console.log(err1);
+    });
+  }
+
+  changeAgree(ag) {
+    this.setState({
+      agree: ag
+    })
+  }
+
+  onApplyMember() {
+    if (!this.state.memberForm.membershipNo) {
+      toastShort($t('members.errMembershipNo'));
+      return;
+    }
+    if (!this.state.memberForm.cardFront) {
+      toastShort($t('members.errUploadCard'));
+      return;
+    }
+    console.log('params', this.state.memberForm);
+    Dialog.showProgressDialog();
+    apiMember.applyMembers(this.state.memberForm).then(res => {
+      Dialog.dismissLoading();
+      toastLong(res.msg ?? $t('common.submitSuccess'));
+      goBack();
+    }).catch(err => {
+      toastLong(err);
+      Dialog.dismissLoading();
+    })
+  }
+
+  render() {
+    return (
+      <View style={styles.container}>
+        <View style={styles.applyForm}>
+          <View style={styles.formItem}>
+            <Text style={styles.inputLabel}>{$t('members.membership')}</Text>
+            <Dropdown
+              style={[styles.inputView, ui.flexc]}
+              title={$t('members.membership')}
+              list={this.state.groupList}
+              value={this.state.memberForm.groupPk}
+              valueKey='groupPk'
+              nameKey='groupName'
+              onChange={(value, index)=> {
+                this.changeForm("groupPk", value);
+              }}/>
+          </View>
+          <View style={styles.formItem}>
+            <Text style={styles.inputLabel}>{$t('members.membershipNo')}</Text>
+            <TextInput
+              style={styles.inputView}
+              placeholder={$t('members.membershipNo')}
+              placeholderTextColor={textPlacehoder}
+              maxLength={50}
+              keyboardType='phone-pad'
+              onChangeText={v => this.changeForm('membershipNo', v)}
+            />
+          </View>
+          <View style={styles.formItem}>
+            <Text style={styles.inputLabel}>{$t('members.labelUpload')}</Text>
+            <View style={styles.uploadGroup}>
+              <UploadView
+                style={styles.uploadView}
+                imageStyle={styles.uploadImage}
+                onPress={() => this.uploadImage()}
+                url={this.state.memberForm.cardFront}/>
+            </View>
+          </View>
+        </View>
+        <View style={styles.agreeView}>
+          <View style={styles.formItem}>
+            <CheckBoxText
+              value={this.state.agree}
+              text={$t('sign.agreePDVInfoAccurate')}
+              textStyle={styles.agreeText}
+              onValueChange={v => this.changeAgree(v)}
+            />
+          </View>
+          <Button
+            style={styles.submitButton}
+            elevation={1.5}
+            disabled={!this.state.agree}
+            text={$t('nav.submit')}
+            fontSize={14}
+            onClick={() => {
+              this.onApplyMember();
+            }}
+          />
+        </View>
+      </View>
+    );
+  }
+}
+
+const styles = StyleSheet.create({
+  container: {
+    flex: 1,
+    backgroundColor: colorLight
+  },
+  applyForm: {
+    flex: 1,
+    paddingLeft: 16,
+    paddingRight: 16
+  },
+  formItem: {
+    marginTop: 16,
+    alignItems: 'center',
+    flexDirection: 'row'
+  },
+  inputLabel: {
+    flex: 1,
+    color: textPrimary,
+    fontSize: 14,
+    marginRight: 4
+  },
+  inputView: {
+    flex: 2,
+    color: textPrimary,
+    fontSize: 14,
+    borderRadius: 5,
+    minHeight: 40,
+    paddingTop: 6,
+    paddingLeft: 12,
+    paddingRight: 12,
+    paddingBottom: 6,
+    backgroundColor: '#F5F5F5'
+  },
+  uploadGroup: {
+    flex: 2,
+    marginLeft: -16,
+    alignItems: 'center',
+    flexDirection: 'row'
+  },
+  uploadView: {
+    //flex: 1,
+    alignItems: 'center'
+  },
+  uploadImage: {
+    width: $vw(28),
+    height: $vw(18.7),
+    borderRadius: 6
+  },
+  agreeView: {
+    padding: 16,
+  },
+  agreeText: {
+    color: textPrimary,
+    fontSize: 14,
+    paddingTop: 2,
+    paddingLeft: 4,
+    paddingBottom: 2
+  },
+  submitButton: {
+    marginTop: 16,
+    marginBottom: 8
+  }
+})

+ 132 - 0
Strides-APP/app/pages/member/MembersList.js

@@ -0,0 +1,132 @@
+/**
+ * 我的会员列表页面
+ * @邠心vbe on 2023/07/14
+ */
+import React, { Component } from 'react';
+import { View, Text, StyleSheet, Pressable } from 'react-native';
+import apiMember from '../../api/apiMember';
+import { ElevationObject } from '../../components/Button';
+
+export default class MembersList extends Component {
+  constructor(props) {
+    super(props);
+    this.state = {
+      memberList: []
+
+    };
+  }
+
+  componentDidMount() {
+    this.getMyMemberList();
+    this.props.navigation.addListener('focus', () => {
+      this.getMyMemberList();
+    })
+  }
+
+  getMyMemberList() {
+    apiMember.getMyMemberList().then(res => {
+      if (res.data) {
+        this.setState({
+          memberList: res.data
+        });
+      }
+    }).catch(err => {
+      this.setState({
+        memberList: []
+      });
+      toastShort(err)
+    });
+  }
+
+  getMembershipStatus(status) {
+    switch (status) {
+      case "Pending":
+        return $t("members.statusPending");
+      case "Approved":
+        return $t("members.statusApproved");
+      case "Rejected":
+        return $t("members.statusRejected");
+      default:
+        return $t("charging.statusUnavailable");
+    }
+  }
+
+  render() {
+    return (
+      this.state.memberList.length > 0
+      ? this.state.memberList.map((item, index) => (
+        <Pressable
+          key={index}
+          style={styles.memberView}
+          onPress={() => {
+            //startPage(PageList.editVehicle, {id: item.vehiclePk});
+          }}>
+          <View style={styles.itemBackground}>
+            <MaterialIcons
+              style={styles.icon}
+              name="card-membership"
+              color={colorAccent}
+              size={56}/>
+          </View>
+          <View style={styles.memberItem}>
+            <Text style={styles.textLabel2}>{$t('members.membership')}:</Text>
+            <Text style={styles.textValue2}>{item.membership}</Text>
+          </View>
+          <View style={styles.memberItem}>
+            <Text style={styles.textLabel}>{$t('members.membershipNo')}:</Text>
+            <Text style={styles.textValue}>{item.membershipNo}</Text>
+          </View>
+          <View style={styles.memberItem}>
+            <Text style={styles.textLabel}>{$t('members.status')}:</Text>
+            <Text style={styles.textValue}>{this.getMembershipStatus(item.membershipStatus)}</Text>
+          </View>
+        </Pressable>
+      ))
+      : <Text style={ui.noData}>{$t('members.noData')}</Text>
+    );
+  }
+}
+
+const styles = StyleSheet.create({
+  memberView: {
+    borderRadius: 8,
+    overflow: 'hidden',
+    ...ElevationObject(5),
+    ...$margin(16, 16, 0),
+    ...$padding(16),
+    backgroundColor: colorLight
+  },
+  memberItem: {
+    paddingTop: 1,
+    paddingBottom: 1,
+    flexDirection: 'row'
+  },
+  textLabel: {
+    color: textPrimary,
+    fontSize: 14,
+    paddingRight: 6,
+    fontWeight: 'bold'
+  },
+  textValue: {
+    color: textPrimary,
+    fontSize: 14
+  },
+  textLabel2: {
+    color: textPrimary,
+    fontSize: 16,
+    paddingRight: 5,
+    marginBottom: 2,
+    fontWeight: 'bold'
+  },
+  textValue2: {
+    color: textPrimary,
+    fontSize: 16,
+    marginBottom: 2,
+  },
+  itemBackground: {
+    right: 0,
+    bottom: 0,
+    opacity: 0.1,
+    position: 'absolute'
+  }
+})

+ 35 - 54
Strides-APP/app/pages/my/ProfileV2.js

@@ -38,40 +38,11 @@ export default class ProfileV2 extends Component {
     }, true);
   }
 
-  removeVehicle(id) {
-    Dialog.showDialog({
-      title: 'Remove Vehicle',
-      message: 'Are you sure you want to remove this vehicle?',
-      callback: btn => {
-        if (btn == 'ok') {
-          Dialog.dismissLoading();
-          this.deleteVehicle(id);
-        }
-      }
-    })
-  }
-
-  deleteVehicle(id) {
-    Dialog.showProgressDialog();
-    apiUser.deleteVehicle({
-      vehiclePk: id
-    }).then(res => {
-      Dialog.dismissLoading();
-      toastShort('Delete successfully');
-      this.setState({
-        refreshId: this.state.refreshId + 1
-      })
-    }).catch(err => {
-      Dialog.dismissLoading();
-      toastShort(err);
-    });
-  }
-
   deleteAccount() {
     Dialog.showDialog({
-      title: 'Delete Account',
-      message: 'Are you sure you want to delete your account? This operation cannot be revoke.',
-      ok: 'CONFIRM',
+      title: $t('profile.deleteAccount'),
+      message: $t('profile.confirmDeleteAccount'),
+      ok: $t('nav.confirm'),
       callback: button => {
         if (button == Dialog.BUTTON_OK) {
           this.deleteMyAccount();
@@ -83,10 +54,12 @@ export default class ProfileV2 extends Component {
   deleteMyAccount() {
     Dialog.showProgressDialog();
     apiUser.deleteAccount().then(res => {
-      toastShort('Successfully deleted!')
+      toastShort($t('profile.deleteAccountSuccess'))
       Dialog.dismissLoading();
-      //startPage(PageList.login);
       this.requestLogout();
+      /*setTimeout(() => {
+        startPage(PageList.login);
+      }, 500);*/
     }).catch(err => {
       Dialog.dismissLoading();
       toastShort(err)
@@ -95,10 +68,10 @@ export default class ProfileV2 extends Component {
 
   logout() {
     Dialog.showDialog({
-      title: 'Sign out',
-      message: 'Are you sure you want to sign out?',
+      title: $t('profile.signOut'),
+      message: $t('profile.tipSignOut'),
       callback: btn => {
-        if (btn == 'ok') {
+        if (btn == Dialog.BUTTON_OK) {
           Dialog.showProgressDialog();
           setTimeout(() => {
             this.requestLogout();
@@ -132,6 +105,7 @@ export default class ProfileV2 extends Component {
         <Button
           style={styles.cardView}
           viewStyle={styles.profileView}
+          android_ripple={ripple}
           onClick={() => startPage(PageList.editProfile)}>
           { this.state.userInfo.photoUrl
           ? <Image
@@ -157,14 +131,14 @@ export default class ProfileV2 extends Component {
         {/* Wallet Info */}
         <Button 
           style={styles.cardView}
-          viewStyle={styles.profileView}
+          viewStyle={styles.profileItem}
           onClick={() => startPage(PageList.wallet)}>
           <Image
             style={styles.cardIcon}
             source={require('../../images/user/card-wallet.png')}/>
           <View style={styles.cardInfo}>
-            <Text style={styles.cardLabel}>Credits: </Text>
-            <Text style={styles.cardPrimary}>{currency}{this.state.userInfo.credit}</Text>
+            <Text style={styles.cardLabel}>{$t('wallet.creditWalletLabel')}</Text>
+            <Text style={styles.cardPrimary}>{currency}{this.state.userInfo.creditStr}</Text>
           </View>
           <FontAwesome
             size={28}
@@ -174,13 +148,13 @@ export default class ProfileV2 extends Component {
         {/* Vehicle Info */}
         <Button
           style={styles.cardView}
-          viewStyle={styles.profileView}
+          viewStyle={styles.profileItem}
           onClick={() => startPage(PageList.myVehicles)}>
           <Image
             style={styles.cardIcon}
             source={require('../../images/user/card-vehicle.png')}/>
           <View style={styles.cardInfo}>
-            <Text style={styles.cardLabel}>My Vehicles: </Text>
+            <Text style={styles.cardLabel}>{$t('profile.myVehicles')}</Text>
             <Text style={styles.cardPrimary}>{this.state.userInfo.countVehicle}</Text>
           </View>
           <FontAwesome
@@ -190,7 +164,7 @@ export default class ProfileV2 extends Component {
         </Button>
         {/* Vehicle List */}
         {/* <View style={styles.titleView}>
-          <Text style={styles.title}>My Vehicles</Text>
+          <Text style={styles.title}>{$t('profile.myVehicles')}</Text>
           <Button
             style={{backgroundColor: colorLight}}
             borderRadius={3}
@@ -231,13 +205,13 @@ export default class ProfileV2 extends Component {
         </View> */}
         <Button
           style={styles.cardView}
-          viewStyle={styles.profileView}
+          viewStyle={styles.profileItem}
           onClick={() => startPage(PageList.changePassword, {action: "change"})}>
           <Image
             style={styles.cardIcon}
             source={require('../../images/user/card-account.png')}/>
           <View style={styles.cardInfo}>
-            <Text style={styles.cardLabel}>Account Security</Text>
+            <Text style={styles.cardLabel}>{$t('route.changePassword')}</Text>
           </View>
           <FontAwesome
             size={28}
@@ -247,23 +221,23 @@ export default class ProfileV2 extends Component {
         {/* Notifications */}
         <Button
           style={styles.cardView}
-          viewStyle={styles.profileView}
+          viewStyle={styles.profileItem}
           onClick={() => startPage(PageList.settings)}>
           <Image
             style={styles.cardIcon}
             source={require('../../images/user/card-notification.png')}/>
           <View style={styles.cardInfo}>
-            <Text style={styles.cardLabel}>Notification Settings</Text>
+            <Text style={styles.cardLabel}>{$t('profile.notificationSettings')}</Text>
           </View>
           <FontAwesome
             size={28}
             color={textCancel}
             name='angle-right'/>
         </Button>
-        { this.state.userInfo.userType == "Public" &&
+        {/* this.state.userInfo.userType == "Public" &&
           <Button
             style={styles.cardView}
-            viewStyle={styles.profileView}
+            viewStyle={styles.profileItem}
             onClick={() => startPage(PageList.registerFleet)}>
             <MaterialCommunityIcons
               style={styles.cardIcon}
@@ -271,17 +245,17 @@ export default class ProfileV2 extends Component {
               size={32}
               color="#00638C"/>
             <View style={styles.cardInfo}>
-              <Text style={styles.cardLabel}>Apply as PHV/Fleet</Text>
+              <Text style={styles.cardLabel}>{$t('profile.apply2Fleet')}</Text>
             </View>
             <FontAwesome
               size={28}
               color={textCancel}
               name='angle-right'/>
           </Button>
-        }
+        */}
         <Button
           style={styles.cardView}
-          viewStyle={styles.profileView}
+          viewStyle={styles.profileItem}
           onClick={() => this.deleteAccount()}>
           <MaterialCommunityIcons
             style={styles.cardIcon}
@@ -289,7 +263,7 @@ export default class ProfileV2 extends Component {
             size={32}
             color="#00638C"/>
           <View style={styles.cardInfo}>
-            <Text style={styles.cardLabel}>Delete Account</Text>
+            <Text style={styles.cardLabel}>{$t('profile.deleteAccount')}</Text>
           </View>
           <FontAwesome
             size={28}
@@ -304,7 +278,7 @@ export default class ProfileV2 extends Component {
         /> */}
         <Button
           style={styles.deleteButton}
-          text="Logout"
+          text={$t('profile.logout')}
           textColor={textButton}
           onClick={() => this.logout()}
         />
@@ -364,11 +338,18 @@ const styles = StyleSheet.create({
     marginLeft: 16,
     marginRight: 16,
     borderRadius: 10,
+    overflow: 'hidden',
     ...ElevationObject(5),
     alignItems: 'center',
     flexDirection: 'row',
     backgroundColor: colorLight,
   },
+  profileItem: {
+    padding: 16,
+    alignItems: 'center',
+    flexDirection: 'row',
+    justifyContent: 'center',
+  },
   cardItem: {
     flex: 1,
     alignItems: 'center',

+ 5 - 6
Strides-APP/app/pages/my/VehicleList.js

@@ -8,7 +8,6 @@ import apiUser from '../../api/apiUser';
 import { ElevationObject } from '../../components/Button';
 import Dialog from '../../components/Dialog';
 import VehicleType from '../../icons/VehicleType';
-import { getConnectTypeByKey } from '../charge/Charging';
 import { PageList } from '../Router';
 
 export default class VehicleList extends Component {
@@ -21,7 +20,7 @@ export default class VehicleList extends Component {
   }
 
   componentDidMount() {
-    this.getVehicleList();
+    //this.getVehicleList();
     this.props.navigation.addListener('focus', () => {
       this.getVehicleList();
     })
@@ -58,8 +57,8 @@ export default class VehicleList extends Component {
 
   removeVehicle(id) {
     Dialog.showDialog({
-      title: 'Remove Vehicle',
-      message: 'Are you sure you want to remove this vehicle?',
+      title: $t('profile.removeVehicle'),
+      message: $t('profile.tipRemoveVehicle'),
       callback: btn => {
         if (btn == 'ok') {
           Dialog.dismissLoading();
@@ -75,7 +74,7 @@ export default class VehicleList extends Component {
       vehiclePk: id
     }).then(res => {
       Dialog.dismissLoading();
-      toastShort('Delete successfully');
+      toastShort($t('common.deleteSuccess'));
       this.getVehicleList();
     }).catch(err => {
       Dialog.dismissLoading();
@@ -138,7 +137,7 @@ export default class VehicleList extends Component {
           </Pressable>
         );
       })
-      : <Text style={ui.noData}>No Vehicles</Text>
+      : <Text style={ui.noData}>{$t('profile.noVehicles')}</Text>
     );
   }
 }

+ 22 - 17
Strides-APP/app/pages/sign/RegisterDriver.js

@@ -151,11 +151,11 @@ export default class RegisterDriver extends React.Component {
     }*/
     if (this.state.isFleetDriver) {
       if (!info.pdvLicence) {
-        toastShort('Please enter PDV Licence');
+        toastShort($t('sign.plsInputPDVLicence'));
         return;
       }
       if (this.state.pdvImages[0] == '' || this.state.pdvImages[1] == '') {
-        toastShort('Please upload PDV Licence Photos');
+        toastShort($t('sign.plsUploadLicencePhotos'));
         return;
       }
     }
@@ -173,7 +173,7 @@ export default class RegisterDriver extends React.Component {
     Dialog.showProgressDialog();
     apiUser.registerDriver(param).then(res => {
       Dialog.dismissLoading();
-      toastLong(res.msg ?? 'Submit successfully!');
+      toastLong(res.msg ?? $t('common.submitSuccess'));
       this.backToLogin();
     }).catch(err => {
       toastLong(err);
@@ -195,7 +195,10 @@ export default class RegisterDriver extends React.Component {
   }
 
   uploadImage(index) {
-    ImagePicker.openPicker(options).then(image => {
+    ImagePicker.openPicker({
+      ...options,
+      cropperToolbarTitle: $t('common.cropperTitle')
+    }).then(image => {
       if (image.path) {
         apiUpload.uploadImage(image.path, image.mime, 'PDVL').then(res => {
           if (res.success && res.data.picturePath) {
@@ -204,15 +207,16 @@ export default class RegisterDriver extends React.Component {
             this.setState({
               pdvImages: imageUrl
             });
+            toastShort($t('common.uploadSuccess'));
           } else {
-            toastShort('Upload failed, please retry');
+            toastShort($t('common.uploadFailed'));
           }
         }).catch(err => {
           toastShort(err);
         });
       }
-    }).catch(err => {
-      //console.log(err);
+    }).catch(err1 => {
+      //console.log(err1);
     });
   }
 
@@ -330,10 +334,10 @@ export default class RegisterDriver extends React.Component {
             { this.state.isFleetDriver &&
               <>
               <View style={styles.signInput}>
-                <Text style={styles.inputLabel}>Your Company</Text>
+                <Text style={styles.inputLabel}>{$t('sign.labelYourCompany')}</Text>
                 <Dropdown
                   style={[styles.inputView, ui.flexc]}
-                  title='Company'
+                  title={$t('sign.labelCompany')}
                   list={this.state.companyList}
                   value={this.state.fleetCompanyId}
                   valueKey='fleetCompanyId'
@@ -345,17 +349,17 @@ export default class RegisterDriver extends React.Component {
                   }}/>
               </View>
               <View style={styles.signInput}>
-                <Text style={styles.inputLabel}>{'PDV Licence'}</Text>
+                <Text style={styles.inputLabel}>{$t('sign.labelPDVLicence')}</Text>
                 <TextInput
                   style={styles.inputView}
-                  placeholder='PH Driver Vocational Licence'
+                  placeholder={$t('sign.hintPDVLicence')}
                   placeholderTextColor={textPlacehoder}
                   maxLength={20}
                   onChangeText={v => this.changeInfo('pdvLicence', v)}
                 />
               </View>
               <View style={styles.signInput}>
-                <Text style={styles.inputLabel}>{'  PDV Photos\n(Front & Back)'}</Text>
+                <Text style={styles.inputLabel}>{$t('sign.labelPDVPhotos')}</Text>
                 <View style={styles.uploadGroup}>
                   { this.state.pdvImages.map((item, index) => (
                     <UploadView
@@ -393,7 +397,7 @@ export default class RegisterDriver extends React.Component {
               />
               <View style={styles.agreeTextRow}>
                 <Text style={styles.agreeText} onPress={() => this.changeAgree(!this.state.agree)}>
-                  {'I agree that the information that i’m submitting is the latest and accurate.'}
+                  {$t('sign.agreePDVInfoAccurate')}
                 </Text>
                 {/* <Text style={styles.agreeLink} onPress={() => startPage(PageList.condition)}>Terms of Use</Text>
                 <Text style={styles.agreeText}>{' '}</Text>
@@ -406,7 +410,7 @@ export default class RegisterDriver extends React.Component {
               style={styles.signButton}
               elevation={1.5}
               disabled={!this.state.agree}
-              text='SUBMIT'
+              text={$t('nav.submit')}
               fontSize={14}
               onClick={() => {
                 this.onRegister();
@@ -428,16 +432,17 @@ export default class RegisterDriver extends React.Component {
   }
 }
 
-const UploadView = ({url, onPress}) => (
+export const UploadView = ({style=styles.uploadView, imageStyle=styles.uploadIcon, url, onPress}) => (
   <Pressable
-    style={styles.uploadView}
+    style={style}
     onPress={onPress}>
     { url == ''
     ? <Image
         style={styles.uploadIcon}
         source={require('../../images/icon/ic-add-photo.png')}/>
     : <Image
-        style={styles.uploadIcon}
+        style={imageStyle}
+        resizeMode="cover"
         defaultSource={require('../../images/icon/icon-upload-default.png')}
         source={{uri: host + url}}/>
     }