Sfoglia il codice sorgente

add app/pages/my/Profile.js

wudebin 5 mesi fa
parent
commit
45b39b5feb

+ 462 - 0
Strides-SPAPP/app/pages/my/Profile.js

@@ -0,0 +1,462 @@
+/**
+ * Profile Settings页面
+ * @邠心vbe on 2021/04/27
+ */
+import React, { Component } from 'react';
+import { View, Text, StyleSheet, Image, ScrollView, Switch, Pressable } from 'react-native';
+import apiUser from '../../api/apiUser';
+import { setAccessToken } from '../../api/http';
+import Button, { ElevationObject } from '../../components/Button';
+import Dialog from '../../components/Dialog';
+import { StationBack } from '../../components/Toolbar';
+import ProfileBackground from '../../icons/ProfileBackground';
+import TopChargeBackground from '../../icons/TopChargeBackground';
+import { getStorageJsonSync, setStorage, setStorageJson } from '../../utils/storage';
+import utils from '../../utils/utils';
+import { PageList } from '../Router';
+import VehicleList from './VehicleList';
+
+export default class Profile extends Component {
+  constructor(props) {
+    super(props);
+    this.state = {
+      userInfo: {
+        notifyLowBalance: true,
+        notifyChargingComplete: true,
+        notifyPromotionsOffers: true
+      },
+      refreshId: 0,
+      totalVehicle: 0
+    };
+    this.changed = false;
+  }
+
+  componentDidMount() {
+    this.props.navigation.addListener('focus', () => {
+      getUserInfo(info => {
+        this.setState({
+          userInfo: info,
+          refreshId: this.state.refreshId + 1
+        });
+      }, true);
+    });
+  }
+
+  componentWillUnmount() {
+    if (this.changed) {
+      this.setChangedSwitch();
+    }
+  }
+
+  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);
+    });
+  }
+
+  changeSwitch(key, value) {
+    userInfo[key] = value;
+    this.setState({
+      userInfo: userInfo
+    });
+    this.changed = true;
+  }
+
+  setChangedSwitch() {
+    apiUser.setNotifySwitch(userInfo);
+  }
+
+  deleteAccount() {
+    Dialog.showDialog({
+      title: $t('profile.deleteAccount'),
+      message: $t('profile.confirmDeleteAccount'),
+      ok: $t('nav.confirm'),
+      callback: button => {
+        if (button == Dialog.BUTTON_OK) {
+          this.deleteMyAccount();
+        }
+      }
+    })
+  }
+
+  deleteMyAccount() {
+    Dialog.showProgressDialog();
+    apiUser.deleteAccount().then(res => {
+      toastShort($t('profile.deleteAccountSuccess'))
+      Dialog.dismissLoading();
+      setTimeout(() => {
+        startPage(PageList.login);
+      }, 500);
+    }).catch(err => {
+      Dialog.dismissLoading();
+      toastShort(err)
+    })
+  }
+
+  logout() {
+    Dialog.showDialog({
+      title: $t('profile.signOut'),
+      message: $t('profile.tipSignOut'),
+      callback: btn => {
+        if (btn == 'ok') {
+          Dialog.showProgressDialog();
+          setTimeout(() => {
+            this.requestLogout();
+          }, 500);
+        }
+      }
+    })
+  }
+
+  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('');
+    goBack();
+    Dialog.dismissLoading();
+  }
+
+  render() {
+    return (
+      <ScrollView style={styles.container}>
+        {/* Profile Info */}
+        <View style={styles.headerView}>
+          <View style={styles.background}>
+            {/* <ProfileBackground/> */}
+          </View>
+          {/* <Image
+            style={styles.background}
+            source={require('../../images/user/bg-profile.svg')}/> */}
+          <Pressable
+            style={styles.profileView}
+            onPress={() => {
+              startPage(PageList.editProfile);
+            }}>
+            { userInfo.photoUrl
+            ? <Image
+                style={styles.avatar}
+                source={{uri: utils.getImageUrl(userInfo.photoUrl)}}/>
+            : <Image
+                style={styles.avatar}
+                source={require('../../images/user/ic-avatar-default.png')}/>
+            }
+            <View style={styles.infoContent}>
+              <Text
+                style={styles.nickname}
+                ellipsizeMode='tail'
+                numberOfLines={1}>{userInfo.nickName}</Text>
+              <Text style={styles.userText}>{userInfo.email}</Text>
+              <Text style={styles.userText}>{(utils.isNotEmpty(userInfo.callingCode) && "+" + userInfo.callingCode) + userInfo.phone}</Text>
+            </View>
+            <FontAwesome
+              size={34}
+              color={colorDark}
+              name='angle-right'/>
+          </Pressable>
+          <StationBack bottom={52} scale={0.8}/>
+        </View>
+        {/* Summary Info */}
+        <View style={styles.cardView}>
+          <View style={styles.cardItem}>
+            <Image
+              style={styles.cardIcon}
+              source={require('../../images/user/card-vehicle.png')}/>
+            <View style={styles.cardInfo}>
+              <Text style={styles.cardPrimary}>{this.state.totalVehicle}</Text>
+              <Text style={styles.cardLabel}>My Vehicles</Text>
+            </View>
+          </View>
+          <View style={[styles.cardItem, styles.cardDivide]}>
+            <Image
+              style={styles.cardIcon}
+              source={require('../../images/user/card-wallet.png')}/>
+            <Pressable
+              style={styles.cardInfo}
+              onPress={() => {
+                startPage(PageList.wallet);
+              }}>
+              <Text style={styles.cardPrimary}>{currency}{userInfo.credit}</Text>
+              <Text style={styles.cardLabel}>Credit Wallet</Text>
+            </Pressable>
+          </View>
+        </View>
+        {/* Vehicle List */}
+        <View style={styles.titleView}>
+          <Text style={styles.title}>My Vehicles</Text>
+          <Button
+            style={{backgroundColor: colorLight}}
+            borderRadius={3}
+            viewStyle={styles.titleAdd}
+            onClick={() => {
+              startPage(PageList.addVehicle)
+            }}>
+            <Entypo name='plus' size={14} color={colorDark}/>
+            <Text style={{fontSize: 12, paddingLeft: 1, color: textPrimary}}>Add Vehicle</Text>
+          </Button>
+        </View>
+        <View style={styles.verhicleList}>
+          <VehicleList
+            refreshId={this.state.refreshId}
+            onResult={count => {
+              this.setState({
+                totalVehicle: count
+              })
+            }}
+            onDelete={id => this.removeVehicle(id)}
+          />
+        </View>
+        {/* Account List */}
+        {/* <View style={styles.titleView}>
+          <Text style={styles.title}>My Cards</Text>
+          <Button
+            textColor={textPrimary}
+            style={styles.titleAdd}
+            onClick={() => {
+              startPage(PageList.addCard)
+            }}>
+            <Entypo name='plus' size={14} color={colorDark}/>
+            <Text style={{fontSize: 12, paddingLeft: 1}}>Add Card</Text>
+          </Button>
+        </View>
+        <View style={styles.accountList}>
+          <CardList refreshId={this.state.refreshId}/>
+        </View> */}
+        {/* Notifications */}
+        <View style={styles.titleView}>
+          <Text style={styles.title}>Notifications</Text>
+        </View>
+        <View style={styles.notificationView}>
+          <Pressable
+            style={styles.notificationItem}
+            android_ripple={ripple}
+            onPress={() => {
+              this.changeSwitch("notifyChargingComplete", !userInfo.notifyChargingComplete);
+            }}>
+            <Text style={styles.notiLabel}>Notify me when charging complete</Text>
+            <Switch
+              value={this.state.userInfo.notifyChargingComplete}
+              trackColor={isIOS ? { false: "#B2B2B2", true: colorAccent } : null}
+              onValueChange={v => {
+                this.changeSwitch("notifyChargingComplete", v);
+              }}/>
+          </Pressable>
+          <Pressable
+            style={[styles.notificationItem, styles.divide]}
+            android_ripple={ripple}
+            onPress={() => {
+              this.changeSwitch("notifyLowBalance", !userInfo.notifyLowBalance);
+            }}>
+            <Text style={styles.notiLabel}>Notify me when wallet is low balance</Text>
+            <Switch 
+              value={this.state.userInfo.notifyLowBalance}
+              trackColor={isIOS ? { false: "#B2B2B2", true: colorAccent } : null}
+              onValueChange={v => {
+                this.changeSwitch("notifyLowBalance", v);
+              }}/>
+          </Pressable>
+          <Pressable
+            style={[styles.notificationItem, styles.divide]}
+            android_ripple={ripple}
+            onPress={() => {
+              this.changeSwitch("notifyPromotionsOffers", !userInfo.notifyPromotionsOffers);
+            }}>
+            <Text style={styles.notiLabel}>Notify me for promotions and offers</Text>
+            <Switch
+              value={this.state.userInfo.notifyPromotionsOffers}
+              trackColor={isIOS ? { false: "#B2B2B2", true: colorAccent } : null}
+              onValueChange={v => {
+                this.changeSwitch("notifyPromotionsOffers", v);
+              }}/>
+          </Pressable>
+        </View>
+        <Button
+          style={styles.deleteButton}
+          text="DELETE MY ACCOUNT"
+          textColor={textButton}
+          onClick={() => this.deleteAccount()}
+        />
+        <Button
+          style={styles.deleteButton}
+          text="Logout"
+          textColor={textButton}
+          onClick={() => this.logout()}
+        />
+      </ScrollView>
+    );
+  }
+}
+
+const styles = StyleSheet.create({
+  container: {
+    flex: 1,
+    backgroundColor: pageBackground
+  },
+  headerView: {
+    paddingBottom: 72
+  },
+  background: {
+    left: 0,
+    right: 0,
+    bottom: 0,
+    height: $vw(62.4),
+    alignItems: 'center',
+    position: 'absolute'
+  },
+  profileView: {
+    padding: 16,
+    zIndex: 10,
+    alignItems: 'center',
+    flexDirection: 'row'
+  },
+  avatar: {
+    width: 66,
+    height: 66,
+    borderWidth: 2,
+    borderRadius: 80,
+    borderColor: colorLight
+  },
+  infoContent: {
+    flex: 1,
+    paddingLeft: 16,
+  },
+  nickname: {
+    color: '#000',
+    fontSize: 16,
+    paddingTop: 1,
+    paddingBottom: 1.5,
+  },
+  userText: {
+    color: textPrimary,
+    fontSize: 13,
+    paddingTop: 1.5
+  },
+  cardView: {
+    padding: 16,
+    marginTop: -56,
+    marginLeft: 16,
+    marginRight: 16,
+    borderRadius: 10,
+    ...ElevationObject(2),
+    alignItems: 'center',
+    flexDirection: 'row',
+    backgroundColor: colorLight,
+  },
+  cardItem: {
+    flex: 1,
+    alignItems: 'center',
+    flexDirection: 'row',
+    justifyContent: 'center'
+  },
+  cardDivide: {
+    borderLeftWidth: 1,
+    borderLeftColor: '#EEE'
+  },
+  cardIcon: {
+    width: 32,
+    height: 32
+  },
+  cardInfo: {
+    paddingLeft: 16,
+    alignItems: 'center'
+  },
+  cardPrimary: {
+    color: textPrimary,
+    fontSize: 18,
+    paddingBottom: 2
+  },
+  cardLabel: {
+    color: textPrimary,
+    fontSize: 13,
+  },
+  titleView: {
+    padding: 12,
+    alignItems: 'center',
+    flexDirection: 'row'
+  },
+  title: {
+    flex: 1,
+    padding: 8,
+    color: '#000',
+    fontSize: 16,
+  },
+  titleAdd: {
+    padding: 8,
+    color: textPrimary,
+    alignItems: 'center',
+    flexDirection: 'row'
+  },
+  verhicleList: {
+    paddingLeft: 16,
+    paddingRight: 16,
+    marginBottom: -16
+  },
+  accountList: {
+    paddingLeft: 16,
+    paddingRight: 16,
+    marginBottom: -16
+  },
+  notificationView: {
+    marginLeft: 16,
+    marginRight: 16,
+    marginBottom: 20,
+    borderRadius: 10,
+    overflow: 'hidden',
+    paddingLeft: 16,
+    paddingRight: 16,
+    borderColor: '#f5f5f5',
+    borderWidth: 1,
+    backgroundColor: colorLight,
+    ...ElevationObject(1.5)
+  },
+  notificationItem: {
+    paddingTop: 16,
+    paddingBottom: 16,
+    alignItems: 'center',
+    flexDirection: 'row'
+  },
+  notiLabel: {
+    flex: 1,
+    color: textPrimary,
+    fontSize: 14
+  },
+  divide: {
+    borderTopWidth: 1,
+    borderTopColor: '#eee'
+  },
+  deleteButton: {
+    ...$margin(32, 16, 16),
+    backgroundColor: '#EA0A2A'
+  }
+})

+ 596 - 0
Strides-SPAPP/app/pages/my/ProfileV2.js

@@ -0,0 +1,596 @@
+/**
+ * Profile Settings页面
+ * @邠心vbe on 2021/04/27
+ */
+import React, { Component } from 'react';
+import { View, StyleSheet, Image, ScrollView } from 'react-native';
+import apiUser from '../../api/apiUser';
+import { setAccessToken } from '../../api/http';
+import Button, { ElevationObject } from '../../components/Button';
+import Dialog from '../../components/Dialog';
+import TextView from '../../components/TextView';
+import { getStorageJsonSync, setStorage, setStorageJson } from '../../utils/storage';
+import utils from '../../utils/utils';
+import { PageList } from '../Router';
+import app from '../../../app.json';
+import { ShadowViewV2 } from '../../components/ShadowView';
+
+export default class ProfileV2 extends Component {
+  constructor(props) {
+    super(props);
+    this.state = {
+      userInfo: userInfo,
+      refreshId: 0,
+      totalVehicle: 0
+    };
+  }
+
+  componentDidMount() {
+    this.init();
+    this.props.navigation.addListener('focus', () => {
+      this.init();
+    });
+  }
+
+  init() {
+    getUserInfo(info => {
+      this.setState({
+        userInfo: info,
+        refreshId: this.state.refreshId + 1
+      });
+    }, true);
+  }
+
+  deleteAccount() {
+    Dialog.showDialog({
+      title: $t('profile.deleteAccount'),
+      message: $t('profile.confirmDeleteAccount'),
+      ok: $t('nav.confirm'),
+      callback: button => {
+        if (button == Dialog.BUTTON_OK) {
+          this.deleteMyAccount();
+        }
+      }
+    })
+  }
+
+  deleteMyAccount(again=false) {
+    Dialog.showProgressDialog();
+    apiUser.deleteAccount({
+      secondConfirm: again
+    }).then(res => {
+      toastShort($t('profile.deleteAccountSuccess'))
+      Dialog.dismissLoading();
+      this.requestLogout();
+      /*setTimeout(() => {
+        startPage(PageList.login);
+      }, 500);*/
+    }).catch(err => {
+      Dialog.dismissLoading();
+      //toastShort(err)
+      setTimeout(() => {
+        if (err.code == 5334) {
+          Dialog.showDialog({
+            title: $t('profile.deleteAccount'),
+            message: err.msg,
+            ok: $t("nav.confirm"),
+            callback: button => {
+              if (button == Dialog.BUTTON_OK) {
+                setTimeout(() => {
+                  this.deleteMyAccount(true);
+                }, 500)
+              }
+            }
+          })
+        } else {
+          Dialog.showResultDialog(err.msg);
+        }
+      }, 500);
+    })
+  }
+
+  logout() {
+    Dialog.showDialog({
+      title: $t('profile.signOut'),
+      message: $t('profile.tipSignOut'),
+      callback: btn => {
+        if (btn == Dialog.BUTTON_OK) {
+          Dialog.showProgressDialog();
+          setTimeout(() => {
+            this.requestLogout();
+          }, 500);
+        }
+      }
+    })
+  }
+
+  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('');
+    goBack();
+    Dialog.dismissLoading();
+  }
+
+  render() {
+    return (
+      <ScrollView style={styles.container}>
+        {/* Profile Info */}
+        <EndView half/>
+        <Button
+          style={styles.cardView}
+          viewStyle={styles.profileView}
+          android_ripple={ripple}
+          onClick={() => startPage(PageList.editProfile)}>
+          { this.state.userInfo.photoUrl
+          ? <Image
+              style={styles.avatar}
+              source={{uri: utils.getImageUrl(this.state.userInfo.photoUrl)}}/>
+          : <Image
+              style={styles.avatar}
+              source={require('../../images/user/ic-avatar-default.png')}/>
+          }
+          <View style={styles.infoContent}>
+            <TextView
+              style={styles.nickname}
+              ellipsizeMode='tail'
+              numberOfLines={1}>{this.state.userInfo.nickName}</TextView>
+            <TextView style={styles.userText}>{this.state.userInfo.email}</TextView>
+            <TextView style={styles.userText}>{(utils.isNotEmpty(this.state.userInfo.callingCode) && "+" + this.state.userInfo.callingCode + " ") + this.state.userInfo.phone}</TextView>
+            {/* <View style={styles.userTypeView}>
+              { this.state.userInfo.userType?.split(";").map((item, index) => {
+                  return <TextView key={index} style={styles.userTypeText}>{item}</TextView>
+                })
+              }
+            </View> */}
+          </View>
+          <FontAwesome
+            size={24}
+            color={textCancel}
+            name='angle-right'/>
+        </Button>
+        <ShadowViewV2/>
+        <EndView half/>
+        {/* Wallet Info */}
+        {/* app.v4.wallet
+        ? <Button 
+            style={styles.cardView}
+            viewStyle={styles.profileItem}
+            onClick={() => startPage(PageList.wallets)}>
+            <Image
+              style={styles.cardIcon}
+              source={require('../../images/user/card-wallet.png')}/>
+            <View style={styles.cardInfo}>
+              <TextView style={styles.cardLabel}>{$t('drawer.wallets')}</TextView>
+            </View>
+            <FontAwesome
+              size={24}
+              color={textCancel}
+              name='angle-right'/>
+          </Button>
+        : <Button 
+            style={styles.cardView}
+            viewStyle={styles.profileItem}
+            onClick={() => startPage(PageList.wallet)}>
+            <Image
+              style={styles.cardIcon}
+              source={require('../../images/user/card-wallet.png')}/>
+            <View style={styles.cardInfo}>
+              <TextView style={styles.cardLabel}>{$t('wallet.creditWalletLabel')}</TextView>
+              <TextView style={styles.cardPrimary}>{this.state.userInfo.creditStr}</TextView>
+            </View>
+            <FontAwesome
+              size={24}
+              color={textCancel}
+              name='angle-right'/>
+          </Button>
+        */}
+        <ShadowViewV2/>
+        { (utils.isNotEmpty(this.state.userInfo.groupWallet) && !app.v4.wallet) && <>
+          <Button 
+            style={styles.cardView}
+            viewStyle={styles.profileItem}>
+            <Image
+              style={styles.cardIcon}
+              source={require('../../images/user/card-wallet.png')}/>
+            <View style={styles.cardInfo}>
+              <TextView style={styles.cardLabel}>{this.state.userInfo.groupWallet.walletName}:</TextView>
+              <TextView style={styles.cardPrimary}>{this.state.userInfo.groupWallet.creditStr}, Expires on {this.state.userInfo.groupWallet.expireTime}</TextView>
+            </View>
+          </Button>
+          <ShadowViewV2/>
+          </>
+        }
+        {/* Vehicle Info */}
+        { app.vehicle.enable && <>
+          <Button
+            style={styles.cardView}
+            viewStyle={styles.profileItem}
+            onClick={() => startPage(app.vehicle.newVersionPage ? PageList.vehiclesListV2 : PageList.myVehicles)}>
+            <Image
+              style={styles.cardIcon}
+              source={require('../../images/user/card-vehicle.png')}/>
+            <View style={styles.cardInfo}>
+              <TextView style={styles.cardLabel}>{$t('profile.myVehicles')}</TextView>
+              <TextView style={styles.cardPrimary}>{this.state.userInfo.countVehicle}</TextView>
+            </View>
+            <FontAwesome
+              size={24}
+              color={textCancel}
+              name='angle-right'/>
+          </Button>
+          <ShadowViewV2/>
+          </>
+        }
+        {/* Vehicle List */}
+        {/* <View style={styles.titleView}>
+          <Text style={styles.title}>{$t('profile.myVehicles')}</Text>
+          <Button
+            style={{backgroundColor: colorLight}}
+            borderRadius={3}
+            viewStyle={styles.titleAdd}
+            onClick={() => {
+              startPage(PageList.addVehicle)
+            }}>
+            <Entypo name='plus' size={14} color={colorDark}/>
+            <Text style={{fontSize: 12, paddingLeft: 1, color: textPrimary}}>Add Vehicle</Text>
+          </Button>
+        </View> */}
+        {/* <View style={styles.verhicleList}>
+          <VehicleList
+            refreshId={this.state.refreshId}
+            onResult={count => {
+              this.setState({
+                totalVehicle: count
+              })
+            }}
+            onDelete={id => this.removeVehicle(id)}
+          />
+        </View> */}
+        {/* Account List */}
+        {/* <View style={styles.titleView}>
+          <Text style={styles.title}>My Cards</Text>
+          <Button
+            textColor={textPrimary}
+            style={styles.titleAdd}
+            onClick={() => {
+              startPage(PageList.addCard)
+            }}>
+            <Entypo name='plus' size={14} color={colorDark}/>
+            <Text style={{fontSize: 12, paddingLeft: 1}}>Add Card</Text>
+          </Button>
+        </View>
+        <View style={styles.accountList}>
+          <CardList refreshId={this.state.refreshId}/>
+        </View> */}
+        <Button
+          style={styles.cardView}
+          viewStyle={styles.profileItem}
+          onClick={() => this.deleteAccount()}>
+          <MaterialCommunityIcons
+            style={styles.cardIcon}
+            name="account-remove"
+            size={32}
+            color="#00638C"/>
+          <View style={styles.cardInfo}>
+            <TextView style={styles.cardLabel}>{$t('profile.deleteAccount')}</TextView>
+          </View>
+          <FontAwesome
+            size={24}
+            color={textCancel}
+            name='angle-right'/>
+        </Button>
+        <ShadowViewV2/>
+        <Button
+          style={styles.cardView}
+          viewStyle={styles.profileItem}
+          onClick={() => startPage(PageList.changePassword, {action: "change"})}>
+          <Image
+            style={styles.cardIcon}
+            source={require('../../images/user/card-account.png')}/>
+          <View style={styles.cardInfo}>
+            <TextView style={styles.cardLabel}>{$t('route.changePassword')}</TextView>
+          </View>
+          <FontAwesome
+            size={24}
+            color={textCancel}
+            name='angle-right'/>
+        </Button>
+        <ShadowViewV2/>
+        {/* Notifications */}
+        { !app.v3.drawer && <>
+          <Button
+            style={styles.cardView}
+            viewStyle={styles.profileItem}
+            onClick={() => startPage(PageList.settings)}>
+            <Image
+              style={styles.cardIcon}
+              source={require('../../images/user/card-notification.png')}/>
+            <View style={styles.cardInfo}>
+              <TextView style={styles.cardLabel}>{$t('profile.notificationSettings')}</TextView>
+            </View>
+            <FontAwesome
+              size={24}
+              color={textCancel}
+              name='angle-right'/>
+          </Button>
+          <ShadowViewV2/>
+          </>
+        }
+        { (app.modules.apply_phv && this.state.userInfo.userType.toLowerCase() == "public") && <>
+          <Button
+            style={styles.cardView}
+            viewStyle={styles.profileItem}
+            onClick={() => startPage(PageList.registerFleet)}>
+            <MaterialCommunityIcons
+              style={styles.cardIcon}
+              name="credit-card-edit"
+              size={32}
+              color="#00638C"/>
+            <View style={styles.cardInfo}>
+              <TextView style={styles.cardLabel}>{$t('profile.apply2Fleet')}</TextView>
+            </View>
+            <FontAwesome
+              size={24}
+              color={textCancel}
+              name='angle-right'/>
+          </Button>
+          <ShadowViewV2/>
+          </>
+        }
+        { app.v3.drawer && <>
+          <Button
+            style={styles.cardView}
+            viewStyle={styles.profileItem}
+            onClick={() => startPage(PageList.feedback)}>
+            <MaterialCommunityIcons
+              style={styles.cardIcon}
+              name="message-alert-outline"
+              color="#00638C"
+              size={32}
+            />
+            <View style={styles.cardInfo}>
+              <TextView style={styles.cardLabel}>{$t('drawer.feedback')}</TextView>
+            </View>
+            <FontAwesome
+              size={24}
+              color={textCancel}
+              name='angle-right'/>
+          </Button>
+          <ShadowViewV2/>
+          <Button
+            style={styles.cardView}
+            viewStyle={styles.profileItem}
+            onClick={() => startPage(PageList.settings)}>
+            <MaterialIcons
+              style={styles.cardIcon}
+              name="settings"
+              color="#00638C"
+              size={32}
+            />
+            <View style={styles.cardInfo}>
+              <TextView style={styles.cardLabel}>{$t('drawer.settings')}</TextView>
+            </View>
+            <FontAwesome
+              size={24}
+              color={textCancel}
+              name='angle-right'/>
+          </Button>
+          <ShadowViewV2/>
+        </>}
+        <Button
+            style={styles.cardView}
+            viewStyle={styles.profileItem}
+            onClick={() => startPage(PageList.about)}>
+            <MaterialCommunityIcons
+              style={styles.cardIcon}
+              name="information-outline"
+              color="#00638C"
+              size={32}
+            />
+            <View style={styles.cardInfo}>
+              <TextView style={styles.cardLabel}>{$t('drawer.about')}</TextView>
+            </View>
+            <FontAwesome
+              size={24}
+              color={textCancel}
+              name='angle-right'/>
+          </Button>
+          <ShadowViewV2/>
+        {/* <Button
+          style={styles.deleteButton}
+          text="DELETE MY ACCOUNT"
+          textColor={textButton}
+          onClick={() => this.deleteAccount()}
+        /> */}
+        <Button
+          style={styles.deleteButton}
+          text={$t('profile.logout')}
+          textColor={textLight}
+          elevation={4}
+          textSize={20}
+          onClick={() => this.logout()}
+        />
+      </ScrollView>
+    );
+  }
+}
+
+const styles = StyleSheet.create({
+  container: {
+    flex: 1,
+    backgroundColor: pageBackground
+  },
+  headerView: {
+    paddingBottom: 72
+  },
+  background: {
+    left: 0,
+    right: 0,
+    bottom: 0,
+    height: $vw(62.4),
+    alignItems: 'center',
+    position: 'absolute'
+  },
+  profileView: {
+    zIndex: 10,
+    padding: 16,
+    alignItems: 'center',
+    flexDirection: 'row'
+  },
+  avatar: {
+    width: 66,
+    height: 66,
+    borderWidth: 2,
+    borderRadius: 80,
+    borderColor: "#00638C"
+  },
+  infoContent: {
+    flex: 1,
+    paddingLeft: 16,
+  },
+  nickname: {
+    color: '#000',
+    fontSize: 20,
+    fontWeight: 'bold',
+    paddingTop: 1,
+    paddingBottom: 1,
+  },
+  userText: {
+    color: textPrimary,
+    fontSize: 13,
+    paddingTop: 1.5
+  },
+  cardView: {
+    zIndex: 2,
+    marginTop: 8,
+    marginLeft: 16,
+    marginRight: 16,
+    borderRadius: 10,
+    overflow: 'hidden',
+    //...ElevationObject(5),
+    alignItems: 'center',
+    flexDirection: 'row',
+    backgroundColor: colorLight,
+  },
+  profileItem: {
+    ...$padding(24, 16),
+    alignItems: 'center',
+    flexDirection: 'row',
+    justifyContent: 'center',
+  },
+  cardItem: {
+    flex: 1,
+    alignItems: 'center',
+    flexDirection: 'row',
+    justifyContent: 'center'
+  },
+  cardDivide: {
+    borderLeftWidth: 1,
+    borderLeftColor: '#EEE'
+  },
+  cardIcon: {
+    width: 32,
+    height: 32
+  },
+  cardInfo: {
+    flex: 1,
+    paddingLeft: 16,
+    alignItems: 'flex-start',
+    flexDirection: 'column'
+  },
+  cardPrimary: {
+    color: textPrimary,
+    fontSize: 16,
+    paddingTop: 2
+  },
+  cardLabel: {
+    color: textPrimary,
+    fontSize: 16,
+    fontWeight: 'bold'
+  },
+  titleView: {
+    padding: 12,
+    alignItems: 'center',
+    flexDirection: 'row'
+  },
+  title: {
+    flex: 1,
+    padding: 8,
+    color: '#000',
+    fontSize: 16,
+  },
+  titleAdd: {
+    padding: 8,
+    color: textPrimary,
+    alignItems: 'center',
+    flexDirection: 'row'
+  },
+  verhicleList: {
+    paddingLeft: 16,
+    paddingRight: 16,
+    marginBottom: -16
+  },
+  accountList: {
+    paddingLeft: 16,
+    paddingRight: 16,
+    marginBottom: -16
+  },
+  notificationView: {
+    marginLeft: 16,
+    marginRight: 16,
+    marginBottom: 20,
+    borderRadius: 10,
+    overflow: 'hidden',
+    paddingLeft: 16,
+    paddingRight: 16,
+    borderColor: '#f5f5f5',
+    borderWidth: 1,
+    backgroundColor: colorLight,
+    ...ElevationObject(1.5)
+  },
+  notificationItem: {
+    paddingTop: 16,
+    paddingBottom: 16,
+    alignItems: 'center',
+    flexDirection: 'row'
+  },
+  notiLabel: {
+    flex: 1,
+    color: textPrimary,
+    fontSize: 14
+  },
+  divide: {
+    borderTopWidth: 1,
+    borderTopColor: '#eee'
+  },
+  deleteButton: {
+    borderRadius: 4,
+    ...$margin(16, 16, 24),
+    backgroundColor: '#EA0A2A'
+  },
+  userTypeView: {
+    paddingTop: 2,
+    alignItems: 'center',
+    flexDirection: 'row'
+  },
+  userTypeText: {
+    color: textLight,
+    fontSize: 8,
+    marginRight: 4,
+    borderRadius: 2,
+    textAlign: "center",
+    ...$padding(2, 4),
+    backgroundColor: colorAccent
+  }
+})
+ 

+ 532 - 0
Strides-SPAPP/app/pages/my/ProfileV3.js

@@ -0,0 +1,532 @@
+/**
+ * V3版本Profile页面
+ * @邠心vbe on 2024/05/30
+ */
+import React, { Component } from 'react';
+import { View, StyleSheet, Image, ScrollView, StatusBar, Pressable } from 'react-native';
+import Button, { ElevationObject } from '../../components/Button';
+import TextView from '../../components/TextView';
+import Dialog from '../../components/Dialog';
+import apiUser from '../../api/apiUser';
+import { setAccessToken } from '../../api/http';
+import { getStorageJsonSync, setStorage, setStorageJson } from '../../utils/storage';
+import utils from '../../utils/utils';
+import { PageList } from '../Router';
+import app from '../../../app.json';
+import Svg, { Defs, Ellipse, G, LinearGradient, Path, Rect, Stop } from 'react-native-svg';
+import ShadowView from '../../components/ShadowView';
+import MyStatusBar from '../../components/MyStatusBar';
+
+export default class ProfileV3 extends Component {
+  constructor(props) {
+    super(props);
+    this.state = {
+      isHide: false,
+      userInfo: userInfo,
+      totalVehicle: 0
+    };
+  }
+
+  componentDidMount() {
+    this.init();
+    this.props.navigation.addListener('focus', () => {
+      this.init();
+      this.setState({
+        isHide: false
+      }, () => {
+        setTimeout(() => {
+          MyStatusBar.setStatusBarTheme(MyStatusBar.LIGHT_STYLE);
+        }, 100);
+      });
+      
+    });
+    this.props.navigation.addListener('blur', () => {
+      this.setState({
+        isHide: true
+      })
+      MyStatusBar.setStatusBarTheme(MyStatusBar.DARK_STYLE);
+    });
+  }
+
+  init() {
+    getUserInfo(info => {
+      this.setState({
+        userInfo: info
+      });
+    }, true);
+  }
+
+  deleteAccount() {
+    Dialog.showDialog({
+      title: $t('profile.deleteAccount'),
+      message: $t('profile.confirmDeleteAccount'),
+      ok: $t('nav.confirm'),
+      callback: button => {
+        if (button == Dialog.BUTTON_OK) {
+          this.deleteMyAccount();
+        }
+      }
+    })
+  }
+
+  deleteMyAccount(again=false) {
+    Dialog.showProgressDialog();
+    apiUser.deleteAccount({
+      secondConfirm: again
+    }).then(res => {
+      toastShort($t('profile.deleteAccountSuccess'))
+      Dialog.dismissLoading();
+      this.requestLogout();
+      /*setTimeout(() => {
+        startPage(PageList.login);
+      }, 500);*/
+    }).catch(err => {
+      Dialog.dismissLoading();
+      //toastShort(err)
+      setTimeout(() => {
+        if (err.code == 5334) {
+          Dialog.showDialog({
+            title: $t('profile.deleteAccount'),
+            message: err.msg,
+            ok: $t("nav.confirm"),
+            callback: button => {
+              if (button == Dialog.BUTTON_OK) {
+                setTimeout(() => {
+                  this.deleteMyAccount(true);
+                }, 500)
+              }
+            }
+          })
+        } else {
+          Dialog.showResultDialog(err.msg);
+        }
+      }, 500);
+    })
+  }
+
+  logout() {
+    Dialog.showDialog({
+      title: $t('profile.signOut'),
+      message: $t('profile.tipSignOut'),
+      callback: btn => {
+        if (btn == Dialog.BUTTON_OK) {
+          Dialog.showProgressDialog();
+          setTimeout(() => {
+            this.requestLogout();
+          }, 500);
+        }
+      }
+    })
+  }
+
+  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('');
+    goBack();
+    Dialog.dismissLoading();
+  }
+
+  render() {
+    return (
+      <ScrollView style={styles.container} stickyHeaderIndices={[0]}>
+        {/* <StatusBar backgroundColor={this.state.isHide ? colorLight : colorPrimary} /> */}
+        <View style={styles.headerView}>
+          <Pressable
+            style={styles.titleBar}
+            onPress={() => goBack()}>
+            <MaterialIcons
+              name={'arrow-back-ios'}
+              size={20}
+              color={textLight} />
+            <TextView style={styles.titleText}>Profile</TextView>
+          </Pressable>
+          <View style={styles.profileHeader}>
+            {this.state.userInfo.photoUrl
+              ? <Image
+                style={styles.avatarImage}
+                source={{ uri: utils.getImageUrl(this.state.userInfo.photoUrl) }} />
+              : <Image
+                style={styles.avatarImage}
+                source={require('../../images/user/ic-avatar-default.png')} />
+            }
+            <View style={styles.infoContent}>
+              <View style={ui.flexc}>
+                <TextView
+                  style={styles.nickname}
+                  ellipsizeMode='tail'
+                  numberOfLines={1}>{this.state.userInfo.nickName}</TextView>
+                <TextView
+                  style={styles.countryLabel}>Singapore</TextView>
+              </View>
+              <TextView style={styles.userText}>{this.state.userInfo.email}</TextView>
+              <View style={ui.flex}>
+                <Button
+                  text={"Edit"}
+                  textSize={12}
+                  textColor={colorPrimary}
+                  style={styles.editButton}
+                  viewStyle={styles.editButtonView}
+                  iconRight={
+                    <Feather
+                      name="edit-3"
+                      size={14}
+                      color={colorPrimary} />
+                  }
+                  onClick={() => startPage(PageList.editProfile)}
+                />
+              </View>
+            </View>
+          </View>
+        </View>
+        <View style={styles.circleButtomView}>
+          <Svg width={$vw(100)} height={$vw(42.13)} viewBox="0 0 375 158" fill="none">
+            <Ellipse cx={187.5} cy={79} rx={238.5} ry={79} fill={colorPrimary} />
+          </Svg>
+        </View>
+        <Pressable
+          style={styles.walletView}
+          onPress={() => startPage(PageList.transaction)}>
+          <Image
+            style={styles.walletIcon}
+            source={require("../../images/wallet/lumi-logo.png")}/>
+          <View style={styles.walletContent}>
+            <TextView style={styles.walletTitle}>Available Credits:</TextView>
+            <TextView style={styles.walletAmount}>{this.state.userInfo?.creditStr}</TextView>
+          </View>
+          <Button
+            text={"Buy"}
+            textSize={12}
+            textColor={textLight}
+            style={styles.topupButton}
+            viewStyle={styles.topupButtonView}
+            iconRight={
+              <MaterialIcons
+                name="chevron-right"
+                size={16}
+                color={textLight} />
+            }
+            onClick={() => startPage(PageList.topupNew)}/>
+        </Pressable>
+        <ShadowView/>
+        <Button
+          style={styles.cardView}
+          viewStyle={styles.cardItem}
+          onClick={() => startPage(app.vehicle.newVersionPage ? PageList.vehiclesListV2 : PageList.myVehicles)}>
+          {/* <Image
+            style={styles.cardIcon}
+            source={require('../../images/user/card-vehicle.png')}/> */}
+          <View style={styles.cardInfo}>
+            <TextView style={styles.cardLabel}>{$t('profile.myVehicles')}</TextView>
+            {/* <TextView style={styles.cardPrimary}>{this.state.userInfo.countVehicle}</TextView> */}
+          </View>
+          <FontAwesome
+            size={24}
+            color={textPrimary}
+            name='angle-right'/>
+        </Button>
+        {/* <ShadowView/> */}
+        <Button
+          style={styles.cardView}
+          viewStyle={styles.cardItem}
+          onClick={() => {}}>
+          <View style={styles.cardInfo}>
+            <TextView style={styles.cardLabel}>{"Saved Cards"}</TextView>
+          </View>
+          <FontAwesome
+            size={24}
+            color={textPrimary}
+            name='angle-right'/>
+        </Button>
+        {/* <ShadowView/> */}
+        <Button
+          style={styles.cardView}
+          viewStyle={styles.cardItem}
+          onClick={() => startPage(PageList.settings)}>
+          <View style={styles.cardInfo}>
+            <TextView style={styles.cardLabel}>{"App Settings"}</TextView>
+          </View>
+          <FontAwesome
+            size={24}
+            color={textPrimary}
+            name='angle-right'/>
+        </Button>
+        {/* <ShadowView/> */}
+        <Button
+          style={styles.cardView}
+          viewStyle={styles.profileItem}
+          onClick={() => startPage(PageList.changePassword, {action: "change"})}>
+          {/* <Image
+            style={styles.cardIcon}
+            source={require('../../images/user/card-account.png')}/> */}
+          <View style={styles.cardInfo}>
+            <TextView style={styles.cardLabel}>{$t('route.changePassword')}</TextView>
+          </View>
+          <FontAwesome
+            size={24}
+            color={textPrimary}
+            name='angle-right'/>
+        </Button>
+        {/* <ShadowView/> */}
+        <Button
+          style={styles.cardView}
+          viewStyle={styles.profileItem}
+          onClick={() => startPage(PageList.feedback)}>
+          {/* <MaterialCommunityIcons
+            style={styles.cardIcon}
+            name="message-alert-outline"
+            color="#00638C"
+            size={32}
+          /> */}
+          <View style={styles.cardInfo}>
+            <TextView style={styles.cardLabel}>{$t('drawer.feedback')}</TextView>
+          </View>
+          <FontAwesome
+            size={24}
+            color={textPrimary}
+            name='angle-right'/>
+        </Button>
+        {/* <ShadowView/> */}
+        <Button
+          style={styles.cardView}
+          viewStyle={styles.cardItem}
+          onClick={() => {}}>
+          <View style={styles.cardInfo}>
+            <TextView style={styles.cardLabel}>{"Contact Us"}</TextView>
+          </View>
+          <FontAwesome
+            size={24}
+            color={textPrimary}
+            name='angle-right'/>
+        </Button>
+        {/* <ShadowView/> */}
+        <Button
+          style={styles.cardView}
+          viewStyle={styles.profileItem}
+          onClick={() => startPage(PageList.about)}>
+          {/* <MaterialCommunityIcons
+            style={styles.cardIcon}
+            name="information-outline"
+            color="#00638C"
+            size={32}
+          /> */}
+          <View style={styles.cardInfo}>
+            <TextView style={styles.cardLabel}>{$t('drawer.about')}</TextView>
+          </View>
+          <FontAwesome
+            size={24}
+            color={textPrimary}
+            name='angle-right'/>
+        </Button>
+        {/* <ShadowView/> */}
+        <Button
+          style={styles.cardView}
+          viewStyle={styles.cardItem}
+          onClick={() => startPage(PageList.profile)}>
+          <View style={styles.cardInfo}>
+            <TextView style={styles.cardLabel}>{"Check For Updates"}</TextView>
+          </View>
+          <FontAwesome
+            size={24}
+            color={textPrimary}
+            name='angle-right'/>
+        </Button>
+        {/* <ShadowView/> */}
+        <Button
+          style={styles.cardView}
+          viewStyle={styles.profileItem}
+          onClick={() => this.deleteAccount()}>
+          {/* <MaterialCommunityIcons
+            style={styles.cardIcon}
+            name="account-remove"
+            size={32}
+            color="#00638C"/> */}
+          <View style={styles.cardInfo}>
+            <TextView style={styles.cardLabel}>{$t('profile.deleteAccount')}</TextView>
+          </View>
+          <FontAwesome
+            size={24}
+            color={textPrimary}
+            name='angle-right'/>
+        </Button>
+        {/* <ShadowView/> */}
+        <Button
+          style={styles.deleteButton}
+          text={'LOGOUT'}
+          textColor={textLight}
+          onClick={() => this.logout()}
+        />
+        <ShadowView/>
+        <EndView/><EndView/>
+      </ScrollView>
+    );
+  }
+}
+
+const styles = StyleSheet.create({
+  container: {
+    flex: 1,
+    backgroundColor: pageBackground
+  },
+  headerView: {
+    zIndex: 2,
+    paddingTop: statusHeight,
+    backgroundColor: colorPrimary
+  },
+  titleBar: {
+    padding: 16,
+    alignItems: 'center',
+    flexDirection: 'row'
+  },
+  titleText: {
+    color: textLight,
+    fontSize: 20,
+    fontWeight: 'bold'
+  },
+  profileHeader: {
+    padding: 16,
+    alignItems: 'center',
+    flexDirection: 'row'
+  },
+  avatarImage: {
+    width: 80,
+    height: 80,
+    borderWidth: 2,
+    borderRadius: 80,
+    borderColor: colorLight,
+    backgroundColor: colorLight
+  },
+  infoContent: {
+    flex: 1,
+    paddingLeft: 16
+  },
+  nickname: {
+    color: textLight,
+    fontSize: 20,
+    fontWeight: 'bold',
+    paddingTop: 1,
+    paddingBottom: 1
+  },
+  userText: {
+    color: textLight,
+    fontSize: 13,
+    paddingTop: 4
+  },
+  countryLabel: {
+    color: textLight,
+    fontSize: 10,
+    ...$padding(2, 8),
+    marginLeft: 8,
+    borderRadius: 4,
+    backgroundColor: "#f8a300"
+  },
+  editButton: {
+    marginTop: 8,
+    borderRadius: 4,
+    backgroundColor: colorLight
+  },
+  editButtonView: {
+    width: 65,
+    ...$padding(4, 10),
+    alignItems: 'center',
+    flexDirection: 'row'
+  },
+  circleButtomView: {
+    zIndex: 1,
+    marginTop: -$vw(30)
+  },
+  walletView: {
+    zIndex: 2,
+    padding: 12,
+    paddingRight: 6,
+    marginTop: -$vw(12),
+    marginLeft: 16,
+    marginRight: 16,
+    borderWidth: 2,
+    borderColor: colorPrimary,
+    borderRadius: 6,
+    alignItems: "center",
+    flexDirection: "row",
+    backgroundColor: colorLight,
+  },
+  walletIcon: {
+    width: 48,
+    height: 48
+  },
+  walletContent: {
+    flex: 1,
+    paddingLeft: 8
+  },
+  walletTitle: {
+    color: textPrimary,
+    fontSize: 14,
+    paddingTop: 3
+  },
+  walletAmount: {
+    color: colorPrimary,
+    fontSize: 20,
+    fontWeight: "bold",
+    paddingTop: 2
+  },
+  topupButton: {
+    marginTop: 8,
+    borderRadius: 4,
+    backgroundColor: colorPrimary
+  },
+  topupButtonView: {
+    width: 65,
+    alignItems: 'center',
+    flexDirection: 'row',
+    ...$padding(4, 8, 4, 10)
+  },
+  cardView: {
+    zIndex: 2,
+    //padding: 16,
+    marginTop: 8,
+    marginLeft: 16,
+    marginRight: 16,
+    borderRadius: 10,
+    overflow: 'hidden',
+    alignItems: 'center',
+    flexDirection: 'row',
+    borderWidth: 1,
+    borderColor: "#DADADA",
+    //...ElevationObject(2),
+    backgroundColor: colorLight
+  },
+  cardItem: {
+    padding: 16,
+    alignItems: 'center',
+    flexDirection: 'row',
+    justifyContent: 'center',
+  },
+  cardIcon: {
+    width: 32,
+    height: 32
+  },
+  cardInfo: {
+    flex: 1,
+    //paddingLeft: 16,
+    alignItems: 'center',
+    flexDirection: 'row'
+  },
+  cardLabel: {
+    color: textPrimary,
+    fontSize: 12
+  },
+  deleteButton: {
+    zIndex: 2,
+    borderRadius: 4,
+    backgroundColor: '#EA0A2A',
+    ...$margin(16, 16, 0)
+  }
+})