vbea преди 3 години
родител
ревизия
49aba89708
променени са 67 файла, в които са добавени 2115 реда и са изтрити 137 реда
  1. BIN
      Document/icon/ios1024.png
  2. BIN
      Document/icon/ios120.png
  3. BIN
      Document/icon/ios180.png
  4. BIN
      Document/icon/ios40.png
  5. BIN
      Document/icon/ios58.png
  6. BIN
      Document/icon/ios60.png
  7. BIN
      Document/icon/ios80.png
  8. BIN
      Document/icon/ios87.png
  9. 2 2
      Strides-APP/android/app/build.gradle
  10. 14 7
      Strides-APP/android/app/google-services.json
  11. 1 1
      Strides-APP/android/app/src/main/AndroidManifest.xml
  12. BIN
      Strides-APP/android/app/src/main/res/drawable-xhdpi/ic_cluster.png
  13. BIN
      Strides-APP/android/app/src/main/res/drawable-xhdpi/ic_cluster_un.png
  14. BIN
      Strides-APP/android/app/src/main/res/drawable-xhdpi/ic_marker.png
  15. BIN
      Strides-APP/android/app/src/main/res/drawable-xhdpi/ic_marker_un.png
  16. BIN
      Strides-APP/android/app/src/main/res/drawable/ic_notification.png
  17. 2 2
      Strides-APP/android/app/version.properties
  18. 2 2
      Strides-APP/app.json
  19. 2 2
      Strides-APP/app/api/http.js
  20. 9 5
      Strides-APP/app/components/Button.js
  21. 3 1
      Strides-APP/app/components/CheckBox.js
  22. 19 7
      Strides-APP/app/components/Toolbar.js
  23. 22 0
      Strides-APP/app/icons/ChargeItemSelect.js
  24. 15 0
      Strides-APP/app/icons/ProfileBackground.js
  25. 14 0
      Strides-APP/app/icons/TopChargeBackground.js
  26. BIN
      Strides-APP/app/images/charge/ic-payment.png
  27. BIN
      Strides-APP/app/images/user/card-vehicle.png
  28. BIN
      Strides-APP/app/images/user/card-wallet.png
  29. 5 4
      Strides-APP/app/pages/Router.js
  30. 13 8
      Strides-APP/app/pages/charge/Details.js
  31. 2 1
      Strides-APP/app/pages/charge/InfoDialog.js
  32. 7 6
      Strides-APP/app/pages/home/Drawer.js
  33. 5 5
      Strides-APP/app/pages/home/Home.js
  34. 2 1
      Strides-APP/app/pages/home/Notify.js
  35. 1 1
      Strides-APP/app/pages/home/Search.js
  36. 230 0
      Strides-APP/app/pages/home/maps/BottomSiteInfo.js
  37. 1 1
      Strides-APP/app/pages/home/maps/Filter.js
  38. 206 0
      Strides-APP/app/pages/home/maps/SearchTool.js
  39. 5 0
      Strides-APP/app/pages/home/maps/Test.js
  40. 2 2
      Strides-APP/app/pages/my/AddVehicle.js
  41. 3 3
      Strides-APP/app/pages/my/EditProfile.js
  42. 1 1
      Strides-APP/app/pages/my/EditVehicle.js
  43. 3 3
      Strides-APP/app/pages/my/Profile.js
  44. 2 2
      Strides-APP/app/pages/payment/FormCard.js
  45. 4 2
      Strides-APP/app/pages/payment/PayNow.js
  46. 4 2
      Strides-APP/app/pages/payment/PayPerUse.js
  47. 18 13
      Strides-APP/app/pages/payment/PaymentMethod.js
  48. 305 0
      Strides-APP/app/pages/sign/LoginV2.js
  49. 772 0
      Strides-APP/app/pages/sign/RegisterV2.js
  50. 361 0
      Strides-APP/app/pages/sign/ResetPasswordV2.js
  51. 2 2
      Strides-APP/app/pages/wallet/AddCard.js
  52. 6 3
      Strides-APP/app/pages/wallet/Overview.js
  53. 2 2
      Strides-APP/app/pages/wallet/PaythodList.js
  54. 4 4
      Strides-APP/app/pages/wallet/Topup.js
  55. 2 2
      Strides-APP/app/utils/notification.js
  56. 7 7
      Strides-APP/ios/JuicePlus/GoogleService-Info.plist
  57. 1 1
      Strides-APP/ios/JuicePlus/Info.plist
  58. 1 0
      Strides-APP/package.json
  59. 1 1
      Strides-Admin/src/layout/components/Navbar.vue
  60. 3 2
      Strides-Admin/src/layout/components/Sidebar/Logo.vue
  61. 0 1
      Strides-Admin/src/layout/components/Sidebar/SidebarItem.vue
  62. 1 0
      Strides-Admin/src/layout/components/Sidebar/index.vue
  63. 17 2
      Strides-Admin/src/settings.js
  64. 5 4
      Strides-Admin/src/utils/auth.js
  65. 0 16
      Strides-Admin/src/utils/config.js
  66. 2 2
      Strides-Admin/src/utils/getPageTitle.js
  67. 4 4
      Strides-Admin/src/views/feedback/Detail.vue

BIN
Document/icon/ios1024.png


BIN
Document/icon/ios120.png


BIN
Document/icon/ios180.png


BIN
Document/icon/ios40.png


BIN
Document/icon/ios58.png


BIN
Document/icon/ios60.png


BIN
Document/icon/ios80.png


BIN
Document/icon/ios87.png


+ 2 - 2
Strides-APP/android/app/build.gradle

@@ -3,7 +3,7 @@ apply plugin: 'com.google.gms.google-services'
 
 import com.android.build.OutputFile
 
-def myVersionName = "0.0.1 Alpha" //★★★★★版本号★★★★★
+def myVersionName = "0.2.0 Alpha" //★★★★★版本号★★★★★
 /**
  * The react.gradle file registers a task for each build variant (e.g. bundleDebugJsAndAssets
  * and bundleReleaseJsAndAssets).
@@ -212,7 +212,7 @@ android {
         }
         variant.outputs.all { output ->
             if (variant.buildType.name=="release") {
-                def fileName = "Juice Plus-V${variant.versionName}-${variant.versionCode}"
+                def fileName = "ChargEco-V${variant.versionName}-${variant.versionCode}"
                 // 加入打包时间
                 fileName = fileName + "-${releaseTime()}"
                 // 加入版本类型

+ 14 - 7
Strides-APP/android/app/google-services.json

@@ -1,34 +1,41 @@
 {
   "project_info": {
-    "project_number": "948303787961",
-    "project_id": "chargeco-c5c61",
-    "storage_bucket": "chargeco-c5c61.appspot.com"
+    "project_number": "779803805444",
+    "project_id": "strides-67073",
+    "storage_bucket": "strides-67073.appspot.com"
   },
   "client": [
     {
       "client_info": {
-        "mobilesdk_app_id": "1:948303787961:android:c732f8811a2a248f9aa868",
+        "mobilesdk_app_id": "1:779803805444:android:273dfce7b0f8c7527af251",
         "android_client_info": {
           "package_name": "com.strides.chargeco"
         }
       },
       "oauth_client": [
         {
-          "client_id": "948303787961-ns75dgg4v5va239b9ogs1t4qn914s5p5.apps.googleusercontent.com",
+          "client_id": "779803805444-0nat1fh00njdj2d6c9fc13dc9k2gr5t9.apps.googleusercontent.com",
           "client_type": 3
         }
       ],
       "api_key": [
         {
-          "current_key": "AIzaSyADWrNTAVnkyoyG9TG-xUHYcFB9q-siSEE"
+          "current_key": "AIzaSyDRsTzDbIZTd-SWlSOZ6w8mKTuiS0eGZmE"
         }
       ],
       "services": {
         "appinvite_service": {
           "other_platform_oauth_client": [
             {
-              "client_id": "948303787961-ns75dgg4v5va239b9ogs1t4qn914s5p5.apps.googleusercontent.com",
+              "client_id": "779803805444-0nat1fh00njdj2d6c9fc13dc9k2gr5t9.apps.googleusercontent.com",
               "client_type": 3
+            },
+            {
+              "client_id": "779803805444-7vilfstvrrjvolvc3mgq5iklpied7f5e.apps.googleusercontent.com",
+              "client_type": 2,
+              "ios_info": {
+                "bundle_id": "com.strides.chargeco"
+              }
             }
           ]
         }

+ 1 - 1
Strides-APP/android/app/src/main/AndroidManifest.xml

@@ -40,7 +40,7 @@
                 <action android:name="android.intent.action.VIEW" />
                 <category android:name="android.intent.category.BROWSABLE" />
                 <category android:name="android.intent.category.DEFAULT" />
-                <data android:scheme="juicep" />
+                <data android:scheme="checo" />
             </intent-filter>
         </activity>
         <!-- <provider

BIN
Strides-APP/android/app/src/main/res/drawable-xhdpi/ic_cluster.png


BIN
Strides-APP/android/app/src/main/res/drawable-xhdpi/ic_cluster_un.png


BIN
Strides-APP/android/app/src/main/res/drawable-xhdpi/ic_marker.png


BIN
Strides-APP/android/app/src/main/res/drawable-xhdpi/ic_marker_un.png


BIN
Strides-APP/android/app/src/main/res/drawable/ic_notification.png


+ 2 - 2
Strides-APP/android/app/version.properties

@@ -1,2 +1,2 @@
-#Fri Dec 23 14:30:10 CST 2022
-VERSION_CODE=51
+#Mon Dec 26 16:40:30 CST 2022
+VERSION_CODE=62

+ 2 - 2
Strides-APP/app.json

@@ -1,8 +1,8 @@
 {
   "name": "JuicePlus",
   "displayName": "ChargEco",
-  "versionCode": 10,
-  "versionName": "V0.0.1 Alpha",
+  "versionCode": 60,
+  "versionName": "V0.2.0 Alpha",
   "product": false,
   "debug": true
 }

+ 2 - 2
Strides-APP/app/api/http.js

@@ -4,8 +4,8 @@ import app from '../../app.json';
 
 //config
 //const hostUrl = 'http://161.117.183.142/';
-const hostUrl = app.product ? 'https://csms.evctechnology.com/' : 'http://161.117.183.142/';
-const service = app.product ? 'juiceplus/' : 'steve/'
+const hostUrl = app.product ? 'https://csms.evctechnology.com/' : 'http://190.92.221.143/';
+const service = 'chargeco/'
 export const host = hostUrl;
 
 const DEBUG = app.debug && !app.product;

+ 9 - 5
Strides-APP/app/components/Button.js

@@ -1,6 +1,10 @@
 import React, { useEffect } from 'react';
 import { Pressable, StyleSheet, Text, View } from 'react-native';
 
+//主题配置
+const tintColor = colorPrimary;
+const textDefault = '#fff';
+
 export default Button = ({
   style = styles.buttonView,
   text,
@@ -13,7 +17,7 @@ export default Button = ({
   onLongClick,
   disabled = false,
   elevation = 0,
-  borderRadius = 4
+  borderRadius = 4,
 }) => {
   var start = {}, end = {};
   const isSamsung = BRAND == 'samsung';
@@ -131,7 +135,7 @@ const getElevation = (style, d, e, r) => {
     s.borderRadius = r;
   }
   if (!s.backgroundColor) {
-    s.backgroundColor = colorAccent
+    s.backgroundColor = tintColor
   }
   if (!d) {
     var ele = e ? e : style.elevation ? style.elevation : 0
@@ -180,7 +184,7 @@ export const ViewHeightPadding = (height, padding=0) => {
 
 const styles = StyleSheet.create({
   buttonView: {
-    backgroundColor: colorAccent
+    backgroundColor: colorPrimary
   },
   button: {
     flex: 1,
@@ -198,10 +202,10 @@ const styles = StyleSheet.create({
     paddingRight: 16,
     alignItems: 'center',
     justifyContent: 'center',
-    backgroundColor: colorAccent
+    backgroundColor: tintColor
   },
   buttonText: {
-    color: '#333',
+    color: textDefault,
     fontSize: 16,
     fontWeight: 'bold',
     textAlign: 'center',

+ 3 - 1
Strides-APP/app/components/CheckBox.js

@@ -6,6 +6,7 @@ const CheckBox = ({
   value=false,
   disabled=false,
   onValueChange,
+  tintColor=colorPrimary,
   iosSize=24
 }) => {
   if (isIOS) {
@@ -13,7 +14,7 @@ const CheckBox = ({
       <MaterialIcons
         name={value ? "check-box" : "check-box-outline-blank"}
         size={iosSize}
-        color={value ? colorAccent : '#777'}
+        color={value ? tintColor : '#777'}
         style={styles.checkBoxView}
         onPress={() => {
           if (onValueChange)
@@ -26,6 +27,7 @@ const CheckBox = ({
       <CheckBoxBase
         value={value}
         disabled={disabled}
+        tintColors={{true: tintColor, false: '#777'}}
         onValueChange={onValueChange}
       />
     )

+ 19 - 7
Strides-APP/app/components/Toolbar.js

@@ -1,5 +1,6 @@
 import React from 'react';
 import { Image, Pressable, StyleSheet, View } from 'react-native';
+import TopChargeBackground from '../icons/TopChargeBackground';
 
 export const BackButton = () => {
   return (
@@ -22,17 +23,28 @@ export const BackIcon = () => {
   return <MaterialIcons name={isIOS ? 'arrow-back-ios' : 'arrow-back'} size={24} color={'#333333'} />
 }
 
-export const StationBack = ({bottom = 24}) => {
+export const StationBack = ({bottom = 24, scale=1.0}) => {
   return (
-    <Image
+    // <Image
+    //   style={{
+    //     right: 0,
+    //     bottom: bottom,
+    //     width: 125.8,
+    //     height: 137.64,
+    //     position: 'absolute'
+    //   }}
+    //   source={require('../images/charge/bg-top-station.png')}/>
+    <View
       style={{
         right: 0,
         bottom: bottom,
-        width: 125.8,
-        height: 137.64,
-        position: 'absolute'
-      }}
-      source={require('../images/charge/bg-top-station.png')}/>
+        width: 127.5 * scale,
+        height: 136.67 * scale,
+        position: 'absolute',
+        alignItems: 'flex-end'
+      }}>
+      <TopChargeBackground width={127.5 * scale} height={136.67 * scale}/>
+    </View>
   );
 }
 

+ 22 - 0
Strides-APP/app/icons/ChargeItemSelect.js

@@ -0,0 +1,22 @@
+import React from 'react';
+import Svg, { ClipPath, Defs, G, Path, Rect } from 'react-native-svg';
+
+const ChargeItemSelect = ({size=16, selected=false, tint=colorAccent}) => (
+  <Svg width={size} height={size} viewBox="0 0 16 16">
+    <G clip-path="url(#clip0_30_5787)">
+      <Path
+        fill={selected ? tint : "#CCCCCC"}
+        d="M8 0C9.58225 0 11.129 0.469192 12.4446 1.34824C13.7602 2.22729 14.7855 3.47672 15.391 4.93853C15.9965 6.40034 16.155 8.00887 15.8463 9.56072C15.5376 11.1126 14.7757 12.538 13.6569 13.6569C12.538 14.7757 11.1126 15.5376 9.56072 15.8463C8.00887 16.155 6.40034 15.9965 4.93853 15.391C3.47672 14.7855 2.22729 13.7602 1.34824 12.4446C0.469192 11.129 0 9.58225 0 8C0 5.87827 0.842855 3.84344 2.34315 2.34315C3.84344 0.842855 5.87827 0 8 0V0Z"/>
+      <Path
+        fill={selected ? "#FFF" : "#F0F0F0"}
+        d="M6.85716 11.6801C6.65663 11.68 6.45836 11.6378 6.27524 11.5561C6.09212 11.4744 5.92825 11.355 5.7943 11.2058L3.42859 8.5715C3.29142 8.40054 3.22495 8.18353 3.24286 7.96507C3.26076 7.74662 3.36167 7.54332 3.52484 7.39698C3.68802 7.25064 3.90106 7.17236 4.12016 7.17825C4.33927 7.18414 4.5478 7.27374 4.70287 7.42864L6.85716 9.82864L11.2972 4.94864C11.4541 4.80299 11.6598 4.72134 11.8739 4.71975C12.088 4.71816 12.2949 4.79675 12.454 4.94005C12.6131 5.08335 12.7127 5.28098 12.7334 5.49408C12.7541 5.70717 12.6943 5.92029 12.5657 6.0915L7.9143 11.2001C7.78128 11.3493 7.61852 11.4692 7.43647 11.5518C7.25442 11.6345 7.05709 11.6782 6.85716 11.6801Z"/>
+    </G>
+    <Defs>
+      <ClipPath id="clip0_30_5787">
+        <Rect width={size} height={size} fill="white"/>
+      </ClipPath>
+    </Defs>
+  </Svg>
+);
+
+export default ChargeItemSelect;

+ 15 - 0
Strides-APP/app/icons/ProfileBackground.js

@@ -0,0 +1,15 @@
+import React from 'react';
+import Svg, { Path, Rect } from 'react-native-svg';
+
+const ProfileBackground = ({color=colorAccent}) => (
+  <Svg width="385" height="234" viewBox="0 0 385 234">
+    <Path
+      fillRule="evenodd"
+      clipRule="evenodd"
+      d="M385 -10H0V197.871C-2.62204 199.849 -4 201.9 -4 204C-4 220.569 81.7385 234 187.5 234C293.263 234 389 220.569 389 204C389 201.9 387.622 199.849 385 197.871V-10Z"
+      fill={color}/>
+    <Rect x="0" y="0" width="385" height="200" fill={color}/>
+  </Svg>
+);
+
+export default ProfileBackground;

+ 14 - 0
Strides-APP/app/icons/TopChargeBackground.js

@@ -0,0 +1,14 @@
+import React from 'react';
+import Svg, { Path } from "react-native-svg";
+
+const TopChargeBackground = ({width=153, height=164, color=colorPrimary}) => (
+  <Svg width={width} height={height} viewBox="0 0 153 164">
+    <Path
+      fill={color}
+      fillOpacity="0.14"
+      d="M155.596 72.8876H147.126V36.4438H155.591V9.11238H172.53V36.4438H181V72.8876H172.53V136.663C172.53 143.912 169.853 150.865 165.089 155.991C160.324 161.117 153.862 163.997 147.124 163.997C140.385 163.997 133.923 161.117 129.158 155.991C124.394 150.865 121.717 143.912 121.717 136.663V100.219H104.783V145.781H115.624V164H0V145.77H11.6313V9.11238C11.6313 4.08171 15.4199 0 20.0958 0H96.313C100.989 0 104.783 4.08171 104.783 9.11238V82H121.722C126.214 82.0015 130.521 83.9223 133.697 87.3399C136.873 90.7576 138.657 95.3923 138.657 100.225V136.669C138.657 139.085 139.549 141.403 141.137 143.112C142.726 144.821 144.88 145.781 147.126 145.781C149.373 145.781 151.527 144.821 153.115 143.112C154.704 141.403 155.596 139.085 155.596 136.669V72.8819V72.8876ZM62.4393 72.8876V36.4438L28.5655 91.1181H53.9748V127.562L87.8432 72.8933H62.4446L62.4393 72.8876Z"
+    />
+  </Svg>
+);
+
+export default TopChargeBackground;

BIN
Strides-APP/app/images/charge/ic-payment.png


BIN
Strides-APP/app/images/user/card-vehicle.png


BIN
Strides-APP/app/images/user/card-wallet.png


+ 5 - 4
Strides-APP/app/pages/Router.js

@@ -8,8 +8,8 @@ import { createStackNavigator, TransitionPresets } from '@react-navigation/stack
 import { enableScreens } from 'react-native-screens';
 import About from './About';
 import Launcher from './Launch';
-import Login from './sign/Login';
-import Regist from './sign/Register'
+import Login from './sign/LoginV2';
+import Regist from './sign/RegisterV2'
 import Home from './home/Drawer';
 import Search from './home/Search';
 import ChargeDetails from './charge/Details';
@@ -33,11 +33,12 @@ import EditVehicle from './my/EditVehicle';
 import EditAddress from './my/EditAddress';
 import Notify from './home/Notify';
 import Test from './home/maps/Test';
-import ResetPassword from './sign/ResetPassword';
+import ResetPassword from './sign/ResetPasswordV2';
 import PaymentMethod from './payment/PaymentMethod';
 import PayPerUse from './payment/PayPerUse';
 import PaymentWeb from './payment/PaymentWeb';
 import Settings from './Settings';
+import app from '../../app.json'
 
 export var PageList = {
   'splash': {
@@ -227,7 +228,7 @@ const Router = () => {
 
 const noTitle = (opt = {}) => {
   return {
-    title: isIOS ? 'Back' : 'Juice Plus',
+    title: isIOS ? 'Back' : app.displayName,
     headerShown: false,
     ...opt
   }

+ 13 - 8
Strides-APP/app/pages/charge/Details.js

@@ -24,7 +24,7 @@ export default class Details extends Component {
     super(props);
     this.state = {
       showTab: true,
-      tabIndex: 0,
+      tabIndex: 1,
       tabView: [{
         title: 'Site Information'
       }, {
@@ -191,7 +191,7 @@ export default class Details extends Component {
                 height: 50,
                 marginTop: 8
               }}
-              source={require('../../images/charge/icon-station.png')}/>
+              source={require('../../images/charge/icon-station-no.png')}/>
             <View style={styles.stationInfo}>
               <Text
                 style={styles.stationName}
@@ -210,7 +210,7 @@ export default class Details extends Component {
               <MaterialIcons
                 name='directions'
                 size={32}
-                color='#333'/>
+                color={colorPrimary}/>
               <Text style={styles.lengthText}>{this.state.stationInfo.distance}</Text>
             </TouchableOpacity>
           </View>
@@ -262,9 +262,13 @@ export default class Details extends Component {
                           this.changeTab(index)
                         }}
                         android_ripple={ripple}>
-                        <Text style={[styles.tabText, {
-                          borderLeftWidth: index > 0 ? 1 : 0,
-                        }]} numberOfLines={1}>{view.title}</Text>
+                        <Text 
+                          style={[
+                            styles.tabText, 
+                            index == this.state.tabIndex && styles.active,
+                            { borderLeftWidth: index > 0 ? 1 : 0 }
+                          ]}
+                          numberOfLines={1}>{view.title}</Text>
                       </Pressable>
                     );
                   })
@@ -327,7 +331,7 @@ const styles = StyleSheet.create({
     paddingLeft: 16,
     paddingRight: 16,
     paddingBottom: 32,
-    backgroundColor: colorAccent
+    backgroundColor: colorThemes
   },
   summaryView: {
     paddingBottom: 16,
@@ -415,7 +419,8 @@ const styles = StyleSheet.create({
     borderLeftColor: '#eee'
   },
   active: {
-    backgroundColor: colorAccent
+    color: '#fff',
+    backgroundColor: colorPrimary
   },
   tabContent: {
     flex: 1

+ 2 - 1
Strides-APP/app/pages/charge/InfoDialog.js

@@ -9,6 +9,7 @@ import { ModalProps } from "../../components/BottomModal";
 import Button from "../../components/Button";
 import { Styles } from "../../components/Toolbar";
 import { PageList } from "../Router";
+import app from "../../../app.json"
 
 export const DialogMaxWidth = $vw(85) > 500 ? 500 : $vw(85);
 
@@ -16,7 +17,7 @@ export const LoginDialog = ({onHide, onClose}) => {
   return (
     <View style={styles.dialog}>
       <Text style={styles.title}>Oops!</Text>
-      <Text style={styles.message}>You need to be registered user of JuicePlus</Text>
+      <Text style={styles.message}>You need to be registered user of {app.displayName}</Text>
       <View style={styles.loginTipView}>
         <Text style={styles.tipText}>Login to use this feature</Text>
         <Image

+ 7 - 6
Strides-APP/app/pages/home/Drawer.js

@@ -312,7 +312,7 @@ const DrawerContent = ({isLogin, userInfo, onLogout, navigation}) => {
         </Button>
       </>}
 
-      <Button
+      {/* <Button
         style={styles.itemButton}
         viewStyle={styles.itemView}
         onClick={() => {
@@ -325,7 +325,7 @@ const DrawerContent = ({isLogin, userInfo, onLogout, navigation}) => {
           size={24}
         />
         <Text style={styles.label}>FAQs</Text>
-      </Button>
+      </Button> */}
       <Button
         style={styles.itemButton}
         viewStyle={styles.itemView}
@@ -366,7 +366,7 @@ const DrawerContent = ({isLogin, userInfo, onLogout, navigation}) => {
                 source={require('../../images/icon/draw-wallet.png')}/>
               <Text style={styles.balanceText}>{currency}{userInfo.credit}</Text>
             </Pressable>
-            <Pressable
+            {/* <Pressable
               style={styles.balanceView}
               android_ripple={ripple}
               onPress={() => {
@@ -376,7 +376,7 @@ const DrawerContent = ({isLogin, userInfo, onLogout, navigation}) => {
                 style={styles.icon}
                 source={require('../../images/icon/draw-gift.png')}/>
               <Text style={styles.referText}>Refer your friends to get $5 credit!</Text>
-            </Pressable>
+            </Pressable> */}
           </View>
         : <View style={ui.flex1}></View>
       }
@@ -388,6 +388,7 @@ const DrawerContent = ({isLogin, userInfo, onLogout, navigation}) => {
         <Button
           style={styles.logoutView}
           text='Logout'
+          textColor='#fff'
           borderRadius={0}
           onClick={() => logout()}/>
       }
@@ -478,7 +479,7 @@ const styles = StyleSheet.create({
     alignItems: 'center',
     flexDirection: 'row',
     justifyContent: 'center',
-    backgroundColor: 'rgba(255, 204, 44, 0.6)'
+    backgroundColor: 'rgba(0, 20, 137, 0.2)'
   },
   balanceText: {
     color: '#333',
@@ -498,6 +499,6 @@ const styles = StyleSheet.create({
     justifyContent: 'flex-end'
   },
   logoutView: {
-    backgroundColor: colorAccent
+    backgroundColor: colorPrimary
   }
 });

+ 5 - 5
Strides-APP/app/pages/home/Home.js

@@ -12,6 +12,7 @@ import { Styles } from '../../components/Toolbar';
 import utils from '../../utils/utils';
 import { PageList } from '../Router';
 import { SettingUtil } from '../Settings';
+import BottomSiteInfo from './maps/BottomSiteInfo';
 import Maps from './maps/Maps';
 import MapTool from './maps/MapTool';
 import SearchTool from './maps/SearchTool';
@@ -243,6 +244,7 @@ export default class HomePage extends Component {
       }
     }).catch(err => {
       Dialog.dismissLoading();
+      toastShort(err);
       this.setState({
         stopList: []
       });
@@ -301,12 +303,10 @@ export default class HomePage extends Component {
           <Pressable
             style={Styles.backIcon}
             android_ripple = {rippleLess}
-            onPress={() => {
-              this.props.navigation.toggleDrawer();
-            }}>
+            onPress={() => startPage(PageList.scanqr, {actionDetail: true})}>
             <MaterialCommunityIcons
               name='line-scan'
-              size={28}
+              size={20}
               color={colorPrimary}
             />
           </Pressable>
@@ -332,7 +332,7 @@ export default class HomePage extends Component {
               onMarkerPress={id => this.viewChargeStation(id)}
             />
           }
-          <TopInfo stationInfo={this.state.stationInfo}/>
+          <BottomSiteInfo stationInfo={this.state.stationInfo}/>
         </View>
         <View style={styles.drawerLeftTouchView}></View>
       </View>

+ 2 - 1
Strides-APP/app/pages/home/Notify.js

@@ -4,6 +4,7 @@ import Button from '../../components/Button';
 import PushNotification from "react-native-push-notification";
 import Dialog from '../../components/Dialog';
 import apiUpload from '../../api/apiUpload';
+import app from '../../../app.json'
 
 export default class Notify extends Component {
   constructor(props) {
@@ -56,7 +57,7 @@ export default class Notify extends Component {
       channelId: "10186", // (required) channelId, if the channel doesn't exist, notification will not trigger.
       showWhen: true, // (optional) default: true
       autoCancel: true, // (optional) default: true
-      title: "JuicePlus", // (optional) default: "message" prop
+      title: app.displayName, // (optional) default: "message" prop
       message: "This is a local test message", // (optional) default: none
       vibrate: true, // (optional) 振动开关default: true
       vibration: 300, // 振动长度(毫秒),如果vibrate=false,则忽略, default: 1000

+ 1 - 1
Strides-APP/app/pages/home/Search.js

@@ -158,7 +158,7 @@ export default class Search extends Component {
   }
 }
 
-const ConnectType = ({type, available, all}) => {
+export const ConnectType = ({type, available, all}) => {
   if (type) {
     return (
       <View style={styles.connectType}>

+ 230 - 0
Strides-APP/app/pages/home/maps/BottomSiteInfo.js

@@ -0,0 +1,230 @@
+/**
+ * 地图底部充电站信息组件
+ * @邠心vbe on 2022/12/23
+ */
+import React from 'react';
+import { Pressable, StyleSheet, View, Text, Image } from 'react-native';
+import { ElevationObject } from '../../../components/Button';
+import utils from '../../../utils/utils';
+import { ChargeStyle } from '../../charge/Charging';
+import { PageList } from '../../Router';
+import { ConnectType } from '../Search';
+ 
+ 
+export default TopInfo = ({stationInfo = {}}) => {
+  const getAvailable = (type) => {
+    const all = stationInfo.allConnector;
+    if (all) {
+      if (type == 'box') {
+        return all.boxAvailable + '/' + all.boxAll;
+      } else {
+        return all.available + '/' + all.all;
+      }
+    } else {
+      return '0/0';
+    }
+  }
+
+  const getOperatingHours = () => {
+    if (stationInfo.endlessService) {
+      return "24/7";
+    } else if (stationInfo.operatingHours) {
+      return stationInfo.operatingHours;
+    } else {
+      return 'To be updated';
+    }
+  }
+
+  const getParkingFee = () => {
+    if (stationInfo.parkingFeeFree) {
+      return "Free";
+    } else if (stationInfo.parkingFee) {
+      return stationInfo.parkingFee;
+    } else {
+      return 'To be updated';
+    }
+  }
+
+  if (stationInfo.id) {
+    return (
+      <View style={styles.stationBarView}>
+        <View style={ui.flexc}>
+          <Pressable
+            style={styles.stationInfo}
+            onPress={() => startPage(PageList.chargeDetail, {stationInfo: stationInfo, action: 'view'})}>
+            <Text
+              ellipsizeMode='tail'
+              numberOfLines={1}
+              style={styles.stationTitle}>{stationInfo.name}</Text>
+            <Text
+              style={styles.stationAddress}
+              ellipsizeMode='tail'
+              numberOfLines={2}>{stationInfo.address}</Text>
+          </Pressable>
+          {/* <View style={styles.stationAvailable}>
+            <Image
+              style={styles.availableIcon}
+              source={require('../../../images/charge/icon-type-stops.png')}/>
+            <Text style={styles.availableText}>{getAvailable('box')}</Text>
+          </View>
+          <View style={styles.stationAvailable}>
+            <Image
+              style={styles.availableIcon}
+              source={require('../../../images/charge/icon-type-interfaces.png')}/>
+            <Text style={styles.availableText}>{getAvailable('inc')}</Text>
+          </View> */}
+          <Pressable
+            style={styles.directView}
+            onPress={() => {
+              utils.directMaps(stationInfo.latitude, stationInfo.longitude, stationInfo.address);
+            }}>
+            <MaterialIcons
+              name='directions'
+              size={28}
+              color={colorAccent}/>
+            <Text style={styles.distanceText}>{stationInfo.distance}</Text>
+          </Pressable>
+        </View>
+        <View style={ui.flex}>
+          <View style={styles.connectView}>
+            <ConnectType {...stationInfo.acConnector}/>
+            <ConnectType {...stationInfo.dcConnector}/>
+          </View>
+          <View style={styles.stationStatusView}>
+            { stationInfo.allConnector && stationInfo.allConnector.available > 0 &&
+              <Text style={[ChargeStyle.infoStatus, ChargeStyle.statusAvailable, styles.stationStatus]}>Available</Text>
+            }
+            <Text style={[ChargeStyle.infoStatus, stationInfo.siteType == 'Public' ? ChargeStyle.statusAvailable : ChargeStyle.statusWarning, styles.siteTypes]}>{stationInfo.siteType}</Text>
+          </View>
+        </View>
+        <View style={styles.divideLine}></View>
+        <Pressable
+          style={styles.infoDetailsView}
+          onPress={() => startPage(PageList.chargeDetail, {stationInfo: stationInfo, action: 'view'})}>
+          <View style={ui.flex1}>
+            <Text style={styles.infoTitle}>Operating Hours</Text>
+            <View style={styles.infoView}>
+              <Text style={styles.infoText}>{getOperatingHours()}</Text>
+            </View>
+          </View>
+          <View style={{width: 4}}></View>
+          <View style={ui.flex1}>
+            <Text style={styles.infoTitle}>Parking Charges</Text>
+            <View style={styles.infoView}>
+              <Text style={styles.infoText}>{getParkingFee()}</Text>
+            </View>
+          </View>
+          <View style={{width: 4}}></View>
+          <View style={ui.flex1}>
+            <Text style={styles.infoTitle}>Additional Info</Text>
+            <View style={styles.infoView}>
+              <Text style={styles.infoText}>{stationInfo.additionalNotes}</Text>
+            </View>
+          </View>
+        </Pressable>
+      </View>
+    );
+  } else {
+    return <></>;
+  }
+}
+
+const styles = StyleSheet.create({
+  stationBarView: {
+    left: 16,
+    right: 16,
+    bottom: 48,
+    zIndex: 10,
+    borderRadius: 6,
+    ...$padding(12, 9),
+    position: 'absolute',
+    backgroundColor: 'white',
+    ...ElevationObject(1.5)
+  },
+  stationInfo: {
+    flex: 1,
+    height: 45,
+    paddingLeft: 4,
+    paddingRight: 8,
+    justifyContent: 'space-around'
+  },
+  stationTitle: {
+    color: '#000',
+    fontSize: 16,
+    paddingBottom: 2
+  },
+  stationAddress: {
+    color: '#999',
+    fontSize: 12,
+  },
+  stationAvailable: {
+    height: 45,
+    paddingLeft: 8,
+    paddingRight: 8,
+    alignItems: 'center',
+    justifyContent: 'space-between'
+  },
+  stationStatusView: {
+    marginRight: 4,
+    alignItems: 'center',
+    flexDirection: 'row-reverse'
+  },
+  stationStatus: {
+    fontSize: 10,
+    ...$padding(2, 6)
+  },
+  siteTypes: {
+    fontSize: 10,
+    marginTop: 0,
+    marginRight: 4,
+    ...$padding(2, 6)
+  },
+  availableIcon: {
+    width: 23,
+    height: 23,
+  },
+  availableText: {
+    color: '#333',
+    fontSize: 13,
+    textAlign: 'center'
+  },
+  directView: {
+    zIndex: 1,
+    height: 45,
+    marginLeft: 8,
+    marginRight: 4,
+    alignItems: 'center',
+    justifyContent: 'space-between'
+  },
+  distanceText: {
+    color: '#333',
+    fontSize: 12,
+  },
+  connectView: {
+    flex: 1,
+    paddingTop: 12,
+    paddingBottom: 12,
+    alignItems: 'center',
+    flexDirection: 'row'
+  },
+  divideLine: {
+    height: 1,
+    backgroundColor: '#AEAEAE'
+  },
+  infoDetailsView: {
+    flexDirection: 'row'
+  },
+  infoTitle: {
+    color: '#000',
+    fontSize: 12,
+    fontWeight: 'bold',
+    ...$padding(8, 0, 8)
+  },
+  infoView: {
+    paddingBottom: 8
+  },
+  infoText: {
+    color: '#444',
+    fontSize: 10
+  }
+})

+ 1 - 1
Strides-APP/app/pages/home/maps/Filter.js

@@ -290,7 +290,7 @@ const styles = StyleSheet.create({
     textAlign: 'center'
   },
   actived: {
-    borderColor: colorAccent
+    borderColor: colorPrimary
   },
   typeText: {
     color: '#333',

+ 206 - 0
Strides-APP/app/pages/home/maps/SearchTool.js

@@ -0,0 +1,206 @@
+/**
+ * 首页地图工具和搜索框组件
+ * @邠心vbe on 2022/12/20
+ */
+import React, { Component } from 'react';
+import { View, StyleSheet, Text, Pressable } from 'react-native';
+import BottomModal from '../../../components/BottomModal';
+import Filter from './Filter';
+import { PageList } from '../../Router';
+ 
+export default class SearchTool extends Component {
+  constructor(props) {
+    super(props);
+    this.state = {
+      showFilter: false,
+      filterIndex: {},
+      filterTotal: 0,
+    };
+  }
+
+  componentDidUpdate() {
+    if (this.props.count != this.state.filterTotal) {
+      this.setState({
+        filterTotal: this.props.count
+      })
+    }
+  }
+
+  findFilter(data, index) {
+    this.setState({
+      filterIndex: index
+    });
+    this.hideFilter();
+    if (this.props.onFilter) {
+      this.props.onFilter(data);
+    }
+  }
+
+  showFilter() {
+    this.setState({
+      showFilter: true
+    });
+  }
+
+  hideFilter() {
+    this.setState({
+      showFilter: false
+    });
+  }
+
+  /*getNearestStation() {
+    navigator.geolocation.getCurrentPosition(location => {
+      let params = {
+        lat: location.coords.latitude,
+        lng: location.coords.longitude
+      }
+      Dialog.showProgressDialog();
+      apiStation.getNearestSite(params).then(res => {
+        Dialog.dismissLoading();
+        if (res.data.sitePk) {
+          var station = {
+            id: res.data.sitePk,
+            name: res.data.siteName,
+            address: res.data.address,
+            latitude: res.data.locationLatitude,
+            longitude: res.data.locationLongitude,
+          }
+          setTimeout(() => {
+            utils.directMaps(station.latitude, station.longitude, station.address);
+          }, 500);
+        } else {
+          toastShort("您附近没有充电桩");
+        }
+      }).catch(err => {
+        toastShort(err);
+        Dialog.dismissLoading();
+      });
+    });
+  }*/
+
+  render() {
+    return (
+      <View>
+        <View style={styles.searchView}>
+          <View style={styles.searchInput}>
+            <Feather
+              name={'search'}
+              size={24}
+              color={'#444'}/>
+            <Text
+              style={styles.searchText}
+              onPress={() => {
+                startPage(PageList.search);
+              }}>
+              Search using keywords
+            </Text>
+          </View>
+          { this.props.mapReady &&
+            <Pressable
+              style={styles.mapIcon}
+              android_ripple={rippleLess}
+              onPress={() => this.showFilter()}>
+              <FontAwesome
+                name='filter'
+                size={26}
+                color={colorPrimary}/>
+            </Pressable>
+          }
+          { this.props.mapReady &&
+            <Pressable
+              style={styles.mapIcon}
+              android_ripple={rippleLess}
+              onPress={() => this.props.onLocation()}>
+              <MaterialIcons
+                name='my-location'
+                size={26}
+                color={colorPrimary}/>
+            </Pressable>
+          }
+          {/* <View style={styles.mapToolView}>
+            <TouchableOpacity
+              style={styles.mapIcon}
+              activeOpacity={0.7}
+              onPress={() => {
+                startPage(PageList.scanqr, {actionDetail: true});
+              }}>
+              <FontAwesome
+                name='qrcode'
+                size={25}
+                color={colorPrimary}/>
+            </TouchableOpacity>
+          </View> */}
+        </View>
+        <BottomModal
+          visible={this.state.showFilter}
+          onHide={() => {
+            this.hideFilter()
+          }}>
+          <Filter
+            index={this.state.filterIndex}
+            count={this.state.filterTotal}
+            onDone={(data, index) => this.findFilter(data, index)}
+            onHide={() => this.hideFilter()}/>
+        </BottomModal>
+      </View>
+    );
+  }
+}
+
+const styles = StyleSheet.create({
+  searchView: {
+    alignItems: 'center',
+    flexDirection: 'row',
+    ...$padding(8, 16, 16),
+    backgroundColor: colorThemes
+  },
+  searchInput: {
+    flex: 1,
+    alignItems: 'center',
+    borderWidth: 1,
+    borderStyle: 'solid',
+    borderRadius: 60,
+    borderColor: '#CCD0E7',
+    flexDirection: 'row',
+    paddingLeft: 16,
+    paddingRight: 16,
+    backgroundColor: 'rgba(255, 255, 255, 0.5)'
+  },
+  searchText: {
+    flex: 1,
+    color: '#444',
+    padding: 8,
+    fontSize: 15
+  },
+  mapIcon: {
+    width: 32,
+    height: 32,
+    marginLeft: 10,
+    alignItems: 'center',
+    justifyContent: 'center',
+  },
+  mapToolView: {
+    right: 24,
+    zIndex: 10,
+    bottom: 112,
+    width: 56,
+    position: 'absolute',
+    alignItems: 'center'
+  },
+  bottomView: {
+    left: 0,
+    right: 0,
+    bottom: 32,
+    zIndex: 210,
+    alignItems: 'center',
+    position: 'absolute',
+  },
+  bottomButton: {
+    elevation: 1.5,
+    paddingLeft: 32,
+    paddingRight: 32,
+    borderRadius: 54,
+    overflow: 'hidden',
+    justifyContent: 'center'
+  }
+})

+ 5 - 0
Strides-APP/app/pages/home/maps/Test.js

@@ -5,6 +5,7 @@ import Dialog from '../../../components/Dialog';
 import utils from '../../../utils/utils';
 import VbeClusterMap from 'vbe-cluster-map'
 import Button from '../../../components/Button';
+import { PageList } from '../../Router';
 
 export default class Test extends Component {
   constructor(props) {
@@ -110,6 +111,10 @@ export default class Test extends Component {
           }}
           onMarkerPress={e => this.viewChargeStation(e)}
         />
+        <Button
+          text="Test Page"
+          onClick={() => startPage(PageList.home)}
+        />
       </View>
     );
   }

+ 2 - 2
Strides-APP/app/pages/my/AddVehicle.js

@@ -105,7 +105,7 @@ export default class AddVehicle extends Component {
                     <Text style={styles.typeName}>{item.name}</Text>
                     { index==this.state.connectorIndex &&
                       <View style={styles.checkedIcon}>
-                        <ChargeItemSelect size={12} selected={true}/>
+                        <ChargeItemSelect size={12} selected={true} tint={colorPrimary}/>
                       </View>
                     }
                   </Pressable>
@@ -178,7 +178,7 @@ const styles = StyleSheet.create({
     position: 'absolute',
   },
   actived: {
-    borderColor: colorAccent
+    borderColor: colorPrimary
   },
   typeName: {
     color: '#000',

+ 3 - 3
Strides-APP/app/pages/my/EditProfile.js

@@ -108,7 +108,7 @@ const EditDialog = ({visible, title, value, keyType, countryList, areaNo, showCa
           <Button
             style={styles.btnCancel}
             viewStyle={ViewHeight(48)}
-            textColor={colorAccent}
+            textColor={colorPrimary}
             text='Cancel'
             onClick={() => {
               onChangedText('');
@@ -403,14 +403,14 @@ const styles = StyleSheet.create({
   btnCancel: {
     flex: 1,
     borderWidth: 1,
-    borderColor: colorAccent,
+    borderColor: colorPrimary,
     backgroundColor: 'white'
   },
   btnOk: {
     flex: 1,
     marginLeft: 16,
     borderWidth: 1,
-    borderColor: colorAccent,
+    borderColor: colorPrimary,
   },
   closeIcon: {
     top: 12,

+ 1 - 1
Strides-APP/app/pages/my/EditVehicle.js

@@ -171,7 +171,7 @@ export default class EditVehicle extends Component {
                       <Text style={styles.typeName}>{item.name}</Text>
                       { index==this.state.connectorIndex &&
                         <View style={styles.checkedIcon}>
-                          <ChargeItemSelect size={12} selected={true}/>
+                          <ChargeItemSelect size={12} selected={true} tint={colorPrimary}/>
                         </View>
                       }
                     </Pressable>

+ 3 - 3
Strides-APP/app/pages/my/Profile.js

@@ -10,9 +10,9 @@ 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 utils from '../../utils/utils';
 import { PageList } from '../Router';
-import { CardList } from '../wallet/CardList';
 import VehicleList from './VehicleList';
 export default class Profile extends Component {
   constructor(props) {
@@ -120,7 +120,7 @@ export default class Profile extends Component {
         {/* Profile Info */}
         <View style={styles.headerView}>
           <View style={styles.background}>
-            <ProfileBackground/>
+            {/* <ProfileBackground/> */}
           </View>
           {/* <Image
             style={styles.background}
@@ -151,7 +151,7 @@ export default class Profile extends Component {
               color='#333'
               name='angle-right'/>
           </Pressable>
-          <StationBack bottom={56}/>
+          <StationBack bottom={52} scale={0.8}/>
         </View>
         {/* Summary Info */}
         <View style={styles.cardView}>

+ 2 - 2
Strides-APP/app/pages/payment/FormCard.js

@@ -128,7 +128,7 @@ export default class FormCard extends Component {
               <FontAwesome
                 name='credit-card'
                 size={24}
-                color={colorAccent}/>
+                color={colorPrimary}/>
               <Text style={styles.leftLine}/>
               <TextInput
                 style={styles.cardNumber}
@@ -258,7 +258,7 @@ const styles = StyleSheet.create({
     flex: 1,
     color: '#333',
     fontSize: 16,
-    paddingLeft: 4,
+    paddingLeft: 8,
   },
   cardNameInput: {
     color: '#333',

+ 4 - 2
Strides-APP/app/pages/payment/PayNow.js

@@ -129,7 +129,7 @@ export default class PayNow extends Component {
           ? <Image
               style={styles.qrCode}
               source={{uri: this.state.base64}}/>
-          : <></>
+          : <View style={styles.qrCode}></View>
           }
         </ViewShot>
         <Text style={styles.title}>Top Up Amount: {currency + ' ' + this.state.amount}</Text>
@@ -164,7 +164,7 @@ const styles = StyleSheet.create({
   },
   headerView: {
     paddingBottom: 76,
-    backgroundColor: colorAccent
+    //backgroundColor: colorAccent
   },
   contentView: {
     marginTop: -88
@@ -173,6 +173,8 @@ const styles = StyleSheet.create({
     margin: 16,
     width: $vw(100) - 32,
     height: $vw(100) - 32,
+    borderRadius: 4,
+    backgroundColor: '#efefef'
   },
   title: {
     color: '#333',

+ 4 - 2
Strides-APP/app/pages/payment/PayPerUse.js

@@ -129,7 +129,7 @@ export default class PayPerUse extends Component {
           ? <Image
               style={styles.qrCode}
               source={{uri: this.state.base64}}/>
-          : <></>
+          : <View style={styles.qrCode}></View>
           }
         </ViewShot>
         <Text style={styles.title}>Amount: {currency + ' ' + this.state.amount}</Text>
@@ -164,7 +164,7 @@ const styles = StyleSheet.create({
   },
   headerView: {
     paddingBottom: 76,
-    backgroundColor: colorAccent
+    //backgroundColor: colorAccent
   },
   contentView: {
     marginTop: -88
@@ -173,6 +173,8 @@ const styles = StyleSheet.create({
     margin: 16,
     width: $vw(100) - 32,
     height: $vw(100) - 32,
+    borderRadius: 4,
+    backgroundColor: '#F0F0F0'
   },
   title: {
     color: '#333',

+ 18 - 13
Strides-APP/app/pages/payment/PaymentMethod.js

@@ -19,15 +19,15 @@ export default class PaymentMethod extends Component {
       cIndex: 0,
       selectIndex: 0,
       paymentOptions: [{
-        title: "Credit Wallet",
-        desc: '',
-        value: PAYTYPE.CREDIT_WALLET,
-        icon: require('../../images/icon/draw-wallet.png')
-      }, {
         title: "Pay Per Use",
         desc: '(SGQR)',
         value: PAYTYPE.PAY_PER_USE,
         icon: require('../../images/wallet/ic_payperuse.png')
+      }, {
+        title: "Credit Wallet",
+        desc: '',
+        value: PAYTYPE.CREDIT_WALLET,
+        icon: require('../../images/icon/draw-wallet.png')
       }],
       amountList: [{
         amount: 10,
@@ -192,7 +192,7 @@ export default class PaymentMethod extends Component {
                     {item.desc ? item.desc : '(Balance '+currency+userInfo.credit+')'}
                   </Text>
                   <View style={styles.selectIcon}>
-                    <ChargeItemSelect size={18} selected={index == this.state.cIndex}/>
+                    <ChargeItemSelect size={18} selected={index == this.state.cIndex} tint={colorPrimary}/>
                   </View>
                 </Pressable>
               );
@@ -221,7 +221,7 @@ export default class PaymentMethod extends Component {
                           style={index == this.state.selectIndex ? styles.amountActive : styles.amountText}>
                           {currency}{item.amount}
                         </Text>
-                        <Text style={styles.powerText}>~{item.power}kWh</Text>
+                        <Text style={index == this.state.selectIndex ? styles.powerTextActive : styles.powerText}>~{item.power}kWh</Text>
                       </Pressable>
                     );
                   })
@@ -249,7 +249,7 @@ const styles = StyleSheet.create({
   },
   headerView: {
     paddingBottom: 76,
-    backgroundColor: colorAccent
+    //backgroundColor: colorAccent
   },
   contentView: {
     flex: 1,
@@ -279,7 +279,7 @@ const styles = StyleSheet.create({
     backgroundColor: '#F5F5F5'
   },
   selected: {
-    borderColor: colorAccent
+    borderColor: colorPrimary
   },
   next: {
     marginTop: 16,
@@ -308,9 +308,8 @@ const styles = StyleSheet.create({
     marginLeft: 20
   },
   amountSelect: {
-    color: '#333',
-    borderColor: '#333',
-    backgroundColor: colorAccent
+    borderColor: colorPrimary,
+    backgroundColor: colorPrimary
   },
   amountText: {
     color: '#666',
@@ -320,7 +319,7 @@ const styles = StyleSheet.create({
     textAlign: 'center'
   },
   amountActive: {
-    color: '#333',
+    color: '#fff',
     fontSize: 24,
     height: 50,
     lineHeight: 60,
@@ -332,6 +331,12 @@ const styles = StyleSheet.create({
     fontSize: 12,
     textAlign: 'right',
   },
+  powerTextActive: {
+    color: '#f0f0f0',
+    padding: 6,
+    fontSize: 12,
+    textAlign: 'right',
+  },
   warningText: {
     color: '#ED4A4A',
     fontSize: 14,

+ 305 - 0
Strides-APP/app/pages/sign/LoginV2.js

@@ -0,0 +1,305 @@
+/**
+ * 登录页面V2
+ * @邠心vbe on 2022/12/23
+ */
+ import React from 'react';
+ import {View, Text, StyleSheet, Image, TextInput, ScrollView, Platform} from 'react-native';
+ import { BackButton } from '../../components/Toolbar';
+ import apiUser from '../../api/apiUser';
+ import { setAccessToken } from '../../api/http';
+ import { getStorageSync, setStorage, getStorageJsonSync, setStorageJson } from '../../utils/storage';
+ import Button from '../../components/Button';
+ import Dialog from '../../components/Dialog';
+ import { PageList } from '../Router';
+ import utils from '../../utils/utils';
+ import CheckBoxText from '../../components/CheckBoxText';
+ 
+ export const AutoLogin = async (back) => {
+   const data = await getStorageJsonSync('loginData')
+   if (data && data.email && data.password) {
+     apiUser.login(data).then(res => {
+       if (res.data.accessToken) {
+         setAccessToken(res.data.accessToken);
+         if (back) back();
+       }
+     }).catch((err) => {
+       console.warn('AutoLogin', err);
+       toastShort('Sign in failed')
+     });
+   }
+ }
+ 
+ //注册FCM通知token
+ export const RegisterToken = async () => {
+   if (getUserId() > 0 && notifyToken.token) {
+     const thisDate = utils.formatYYMM(new Date()) + "-" + getUserId();
+     const lastDate = await getStorageSync('RegisterTokenDate');
+     console.log('>>>RegisterToken<<<', thisDate, lastDate + "●");
+     if (thisDate != lastDate) {
+       const params = {
+         os: notifyToken.os ? notifyToken.os : Platform.OS,
+         googleToken: notifyToken.token
+       }
+       apiUser.setNotifyToken(params).then(res => {
+         console.log('>>>RegisterToken-Suc<<<', res);
+         setStorage('RegisterTokenDate', thisDate);
+       }).catch(err => {
+         console.log('>>>RegisterToken-Err<<<', err);
+       });
+     }
+   }
+ }
+ 
+ export default class Login extends React.Component {
+ 
+   constructor(props) {
+     super(props);
+     this.state = {
+       email: '',
+       password: '',
+       rememberMe: true
+     }
+   }
+ 
+   componentDidMount() {
+     /*if (this.props.route.params.action) {
+       this.props.navigation.addListener('beforeRemove', (e) => {
+         if (this.props.route.params.action == '401') {
+           //dispatchPage(StackActions.push('home'));
+           dispatchPage(state => {
+             console.log('routes', state);
+             const r = [];
+             var index = 0;
+             var homekey = '';
+             for (let i = 0; i < state.routes.length; i++) {
+               const item = state.routes[i];
+               if (item.name == 'home') {
+                 r.push(item);
+                 index = i;
+                 homekey = item.key;
+                 break;
+               } else {
+                 r.push(item);
+               }
+             }
+             console.log('new routes', r);
+             return {
+               ...CommonActions.goBack(),
+               source: this.props.route.key,
+               target: homekey,
+             };
+           });
+         }
+       });
+     }*/
+     this.getEmail();
+   }
+ 
+   async getEmail() {
+     const data = await getStorageJsonSync('loginData');
+     if (data && data.email) {
+       this.setState({
+         email: data.email
+       });
+     }
+   }
+ 
+   onLogin() {
+     //console.log(this.state);
+     if (this.state.email == '') {
+       toastShort('Please enter email address');
+       return;
+     }
+     if (this.state.password == '') {
+       toastShort('Please enter password');
+       return;
+     }
+     Dialog.showProgressDialog();
+     apiUser.login(this.state).then(res => {
+       console.log('res.data', res);
+       if (res.data.accessToken) {
+         setAccessToken(res.data.accessToken);
+         Dialog.dismissLoading();
+         if (this.state.rememberMe) {
+           setStorageJson('loginData', this.state);
+         } else {
+           setStorageJson('loginData', {});
+         }
+         startPage(PageList.home);
+         //this.props.navigation.goBack();
+       } else {
+         toastShort(res.msg);
+         Dialog.dismissLoading();
+       }
+     }).catch((err) => {
+       toastShort(err);
+       Dialog.dismissLoading();
+     });
+   }
+ 
+   getBackTopPosition() {
+     return isIOS ? statusHeight : 4;
+   }
+ 
+   render() {
+     return (
+       <View style={ui.flex1}>
+       <View style={[styles.backBtn, {top: this.getBackTopPosition()}]}>
+         <BackButton/>
+       </View>
+       <ScrollView
+         style={ui.container}
+         keyboardShouldPersistTaps={'handled'}>
+         <View style={styles.header}>
+           <Image
+            style={styles.headerImg}
+            resizeMode='contain'
+            source={require('../../images/app-logo.png')} />
+         </View>
+         <View style={styles.loginView}>
+           <View style={styles.loginForm}>
+             <View style={styles.inputView}>
+               <Zocial name='email' size={28} color='#999999' />
+               <TextInput 
+                 style={styles.inputText}
+                 placeholder={"E-mail"}
+                 textContentType='emailAddress'
+                 defaultValue={this.state.email}
+                 maxLength={50}
+                 onChangeText={(v) => {
+                   this.setState({
+                     email: v
+                   })
+                 }}/>
+             </View>
+             <View style={styles.inputView}>
+               <Fontisto name='locked' size={28} color='#999999' style={{marginLeft: 3, marginRight: 2}} />
+               <TextInput 
+                 style={styles.inputText}
+                 placeholder="Password"
+                 textContentType='password'
+                 secureTextEntry={true}
+                 maxLength={20}
+                 onChangeText={(v) => {
+                   this.setState({
+                     password: v
+                   })
+                 }}
+                 onSubmitEditing={() => {
+                   this.onLogin();
+                 }}/>
+             </View>
+             <View style={ui.flexcw}>
+               <View style={$padding(12, 8)}>
+                 <CheckBoxText
+                   value={this.state.rememberMe}
+                   onValueChange={(newValue) => {
+                     this.setState({ rememberMe: newValue });
+                   }}
+                   text={'Remember me'}
+                 />
+               </View>
+               <Text
+                 style={styles.linksText}
+                 onPress={() => startPage(PageList.forgotPassword)}>Forgot Password</Text>
+             </View>
+             <Button
+               style={styles.loginButton}
+               text='SIGN IN'
+               elevation={1.5}
+               onClick={() => {
+                 this.onLogin()
+               }}
+             />
+           </View>
+         </View>
+         <View style={styles.signView}>
+           <Text style={{color: '#333'}}>New User?</Text>
+           <Text
+             style={styles.linksText}
+             onPress={() => {
+               startPage(PageList.register);
+             }}
+           >Click here to sign up</Text>
+         </View>
+       </ScrollView>
+       </View>
+     );
+   }
+ };
+ 
+ const styles = StyleSheet.create({
+   backBtn:{
+     top: 4,
+     left: 2,
+     zIndex: 1,
+     position: 'absolute'
+   },
+   header: {
+     height: 260,
+     paddingTop: 56,
+     paddingBottom: 20,
+     paddingLeft: 32,
+     paddingRight: 32,
+     alignItems: 'center'
+   },
+   headerImg: {
+     width: $vw(63),
+     height: 100
+   },
+   loginView: {
+     padding: 16,
+     marginTop: -24,
+     borderTopLeftRadius: 24,
+     borderTopRightRadius: 24,
+     backgroundColor: 'white'
+   },
+   logoImg: {
+     width:136.19,
+     height: 42.85,
+     marginTop: 18
+   },
+   loginForm: {
+     paddingLeft: 16,
+     paddingRight: 16,
+   },
+   inputView: {
+     marginTop: 30,
+     borderRadius: 8,
+     paddingTop: 6,
+     paddingLeft: 16,
+     paddingRight: 16,
+     paddingBottom: 6,
+     alignItems: 'center',
+     flexDirection: 'row',
+     backgroundColor: '#F5F5F5'
+   },
+   inputText: {
+     flex: 1,
+     color: '#333',
+     fontSize: 15,
+     paddingTop: 6,
+     paddingLeft: 16,
+     paddingBottom: 6
+   },
+   loginButton: {
+     marginTop: 32,
+     borderRadius: 4
+   },
+   signView: {
+     paddingTop: 32,
+     paddingBottom: 16,
+     alignItems: 'center',
+   },
+   checkText: {
+     color: '#333',
+     fontSize: 14,
+     paddingLeft: 8
+   },
+   linksText: {
+     ...ui.link,
+     padding: 8,
+     fontSize: 14,
+     textDecorationLine: 'underline'
+   }
+ });

+ 772 - 0
Strides-APP/app/pages/sign/RegisterV2.js

@@ -0,0 +1,772 @@
+/**
+ * 注册页面V2
+ * @邠心vbe on 2022/12/23
+ */
+ import React from 'react';
+ import { View, Text, ScrollView, StyleSheet, TextInput, Pressable, Image } from 'react-native';
+ import { BackIcon } from '../../components/Toolbar';
+ import apiUser from '../../api/apiUser';
+ import Button from '../../components/Button';
+ import { PageList } from '../Router';
+ import Dialog from '../../components/Dialog';
+ import Modal from 'react-native-modal';
+ import { RegisterDialog } from '../charge/InfoDialog';
+ import Dropdown from '../../components/Dropdown';
+ import ImagePicker from 'react-native-image-crop-picker';
+ import apiUpload from '../../api/apiUpload';
+ import { host } from '../../api/http';
+ import { ModalProps } from '../../components/BottomModal';
+ import { CountryDropNum, GetCountryList } from '../../components/CountryIcon';
+import CheckBox from '../../components/CheckBox';
+ 
+ const options = {
+   width: 300,
+   height: 200,
+   cropping: true,
+   multiple: false,
+   mediaType: 'photo',
+   writeTempFile: false,
+   compressImageQuality: 0.8,
+   compressImageMaxWidth: 720,
+   compressImageMaxHeight: 1280,
+   cropperStatusBarColor: colorAccent,
+   cropperToolbarColor: colorAccent,
+   cropperActiveWidgetColor: colorAccent
+ }
+ 
+ export const StrengthView = ({strength}) => {
+   const getStyle = (num) => {
+     if (strength >= num) {
+       return {...styles.strengthItem, backgroundColor: colorAccent};
+     } else {
+       return styles.strengthItem;
+     }
+   }
+   return (
+     <>
+       <Text style={getStyle(1)}></Text>
+       <Text style={getStyle(2)}></Text>
+       <Text style={getStyle(3)}></Text>
+       {/* <Text style={getStyle(4)}></Text> */}
+       {/* <Text style={getStyle(5)}></Text> */}
+     </>
+   );
+ };
+ 
+ export default class Register extends React.Component {
+   constructor(props) {
+     super(props);
+     this.state = {
+       agree: true,
+       strength: 0,
+       countryNum: '65',
+       countryShow: false,
+       userInfo: {},
+       countryNums: [],
+       wrongCount: 0,
+       params: {...this.props.route.params},
+       email: '',
+       password: '',
+       fleetCompanyId: '',
+       visible: false,
+       isFleetDriver: false,
+       pdvImages: ['', ''],
+       companyList: []
+     };
+   }
+ 
+   componentDidMount() {
+     //console.log(this.state.params);
+     this.getCountryList();
+     this.getCompanyList();
+   }
+ 
+   applyStrength(text) {
+     var strength = 0;
+     if (text.length >= 8) {
+       strength += 1;
+     }
+     if (/\d{1,}/.test(text)) {
+       strength += 1;
+     }
+     if (/[A-z]{1,}/.test(text)) {
+       strength += 1;
+     }
+     /*if (/[A-Z]{1,}/.test(text)) {
+       strength += 1;
+     }
+     /*if (/\W{1,}/.test(text)) {
+       strength += 1;
+     }*/
+     if (this.state.strength != strength) {
+       this.setState({
+         password: text,
+         strength: strength
+       });
+     } else {
+       this.setState({
+         password: text
+       });
+     }
+   }
+ 
+   changeInfo(key, value) {
+     var info = this.state.userInfo;
+     info[key] = value;
+     this.setState({
+       'userInfo': info
+     });
+   }
+ 
+   changeTab(type) {
+     this.setState({
+       isFleetDriver: type
+     })
+   }
+ 
+   getCountryList() {
+     GetCountryList(list => {
+       this.setState({
+         countryNums: list
+       })
+     })
+   }
+ 
+   getCompanyList() {
+     apiUser.getConmpany().then(res => {
+       if (res.data) {
+         this.setState({
+           companyList: res.data
+         })
+       }
+     }).catch(err => [
+       toastShort(err)
+     ])
+   }
+ 
+   onRegister() {
+     //console.log('sign up', this.state);
+     var info = this.state.userInfo;
+     if (!info.nickName) {
+       toastShort('Please enter display name');
+       return;
+     }
+     if (!info.email) {
+       toastShort('Please enter email address');
+       return;
+     }
+     if (!/^[a-zA-Z0-9]+[\S]+@[a-zA-Z0-9_-]+[\.][\Sa-zA-Z]+$/.test(info.email)) {
+       toastShort('Email is incorrect format');
+       return;
+     }
+     if (!info.phone) {
+       toastShort('Please enter contact number');
+       return;
+     }
+     if (!/^\d{6,15}$/.test(info.phone)) {
+       toastShort('Phone Number is incorrect format');
+       return;
+     }
+     if (!this.state.password) {
+       toastShort('Please enter password');
+       return;
+     }
+     if (this.state.strength < 3) {
+       toastShort('Password is not strong');
+       return;
+     }
+     if (!info.password) {
+       toastShort('Please enter confirm password');
+       return;
+     }
+     if (info.password != this.state.password) {
+       toastShort('The twice passwords are inconsistent');
+       if (this.state.wrongCount < 3) {
+         this.setState({
+           wrongCount: this.state.wrongCount + 1
+         })
+       }
+       return;
+     }
+     if (this.state.isFleetDriver) {
+       if (!info.pdvLicence) {
+         toastShort('Please enter PDV Licence');
+         return;
+       }
+       if (this.state.pdvImages[0] == '' || this.state.pdvImages[1] == '') {
+         toastShort('Please upload PDV Licence Photos');
+         return;
+       }
+     }
+     let param = Object.assign({}, info);
+     //param.phone = this.state.countryNum + info.phone
+     param.callingCode = this.state.countryNum;
+     if (this.state.isFleetDriver) {
+       param.userType = 'Driver';
+       param.pdvLicencePictures = this.state.pdvImages;
+       param.fleetCompanyId = this.state.fleetCompanyId;
+     } else {
+       param.userType = 'Public';
+     }
+     console.log('params', param);
+     Dialog.showProgressDialog();
+     apiUser.register(param).then(res => {
+       Dialog.dismissLoading();
+       //toastShort('Sign up successfully!');
+       this.setState({
+         email: param.email,
+         visible: true
+       });
+       //this.backToLogin();
+     }).catch(err => {
+       toastShort(err);
+       Dialog.dismissLoading();
+     });
+   }
+   
+   getBackTopPosition() {
+     return isIOS ? statusHeight - 16 : 8;
+   }
+   
+   backToLogin() {
+     if (this.state.params.actionLogin) {
+       goBack()
+       startPage(PageList.login);
+     } else {
+       goBack();
+     }
+   }
+ 
+   uploadImage(index) {
+     ImagePicker.openPicker(options).then(image => {
+       if (image.path) {
+         apiUpload.uploadImage(image.path, image.mime, 'PDVL').then(res => {
+           if (res.success && res.data.picturePath) {
+             let imageUrl = this.state.pdvImages;
+             imageUrl[index] = res.data.picturePath;
+             this.setState({
+               pdvImages: imageUrl
+             });
+           } else {
+             toastShort('Upload failed, please retry');
+           }
+         }).catch(err => {
+           toastShort(err);
+         });
+       }
+     }).catch(err => {
+       //console.log(err);
+     });
+   }
+ 
+   changeAgree(ag) {
+     this.setState({
+       agree: ag
+     })
+   }
+ 
+   hideDialog() {
+     this.setState({
+       visible: false
+     });
+     this.backToLogin();
+   }
+ 
+   render() {
+     return (
+       <View style={StyleSheet.absoluteFillObject}>
+         <ScrollView
+           style={styles.scollView}
+           keyboardShouldPersistTaps={'handled'}>
+           <View style={styles.header}>
+             <View style={styles.logoView}>
+               {/* <Image
+                 style={styles.logoImg}
+                 source={require('../../images/tool-logo.png')}/> */}
+             </View>
+           </View>
+           <View style={{...styles.backView, top: this.getBackTopPosition()}}>
+             <Button
+               style={styles.backButton}
+               viewStyle={styles.backButtonView}
+               onClick={() => goBack()}>
+               <BackIcon/>
+               <Text style={{color: '#333',fontSize: 16,paddingLeft: 8}}>Back to Login</Text>
+             </Button>
+           </View>
+           <View style={styles.signView}>
+             <View style={styles.tabView}>
+               <Text 
+                 style={[
+                   styles.tabText, 
+                   this.state.isFleetDriver ? {} : styles.tabActive
+                 ]}
+                 onPress={() => this.changeTab(false)}
+               >Public Users</Text>
+               <Text
+                 style={[
+                   styles.tabText,
+                   this.state.isFleetDriver ? styles.tabActive: {}
+                 ]}
+                 onPress={() => this.changeTab(true)}
+               >Fleet/PH Drivers</Text>
+             </View>
+             <Text style={styles.title}>Registration</Text>
+             <View style={styles.signInput}>
+               <Text style={styles.inputLabel}>Display Name</Text>
+               <TextInput
+                 style={styles.inputView} 
+                 placeholder='Display Name'
+                 maxLength={50}
+                 onChangeText={v => this.changeInfo('nickName', v)}
+               />
+             </View>
+             <View style={styles.signInput}>
+               <Text style={styles.inputLabel}>Email Address</Text>
+               <TextInput
+                 style={styles.inputView}
+                 placeholder='Email Address'
+                 maxLength={50}
+                 onChangeText={v => this.changeInfo('email', v)}
+               />
+             </View>
+             <View style={styles.signInput}>
+               <Text style={styles.inputLabel}>Phone Number</Text>
+               <View style={styles.mobileView}>
+                 <View style={styles.dropView}>
+                   <TextInput style={styles.dropInput} editable={false}/>
+                   <Text style={styles.countryText}>{"+" + this.state.countryNum}</Text>
+                   <MaterialIcons name={'arrow-drop-down'} size={24} color={'#333'}/>
+                   <Dropdown
+                     style={styles.dropLayer}
+                     title='Country'
+                     prefixText="+"
+                     list={this.state.countryNums}
+                     value={this.state.countryNum}
+                     nameKey='countryNum'
+                     valueKey='countryNum'
+                     onChange={(value, index)=> {
+                       this.setState({
+                         countryNum: value
+                       })
+                     }}
+                     customerItemView={
+                       (item, index, onClick) => 
+                       <CountryDropNum
+                         key={index} 
+                         country={item}
+                         value={this.state.countryNum}
+                         onClick={onClick}/>
+                     }/>
+                 </View>
+                 <TextInput
+                   style={styles.contactView}
+                   placeholder='Mobile Number'
+                   keyboardType='phone-pad'
+                   maxLength={15}
+                   onChangeText={v => this.changeInfo('phone', v)}
+                 />
+               </View>
+             </View>
+             <View style={styles.signInput}>
+               <Text style={styles.inputLabel}>Create Password</Text>
+               <TextInput
+                 secureTextEntry={this.state.wrongCount < 3}
+                 style={styles.inputView}
+                 placeholder='Password'
+                 maxLength={20}
+                 onChangeText={(value) => {
+                   this.applyStrength(value);
+                 }}
+               />
+             </View>
+             <View style={styles.signInput}>
+               <Text style={styles.inputLabel}></Text>
+               <View style={styles.passwordView}>
+                 <View style={styles.strengthView}>
+                   <Text style={{fontSize:12, paddingRight: 4, color: '#333'}}>Password Strength</Text>
+                   <StrengthView {...this.state}/>
+                 </View>
+                 <View>
+                   <Text style={styles.passwordRole}>Your Password Must Have:</Text>
+                   <Text style={styles.passwordRole}>- 8 or more characters</Text>
+                   {/* <Text style={styles.passwordRole}>- upper and lower case letters</Text> */}
+                   <Text style={styles.passwordRole}>- at least one number</Text>
+                 </View>
+               </View>
+             </View>
+             <View style={styles.signInput}>
+               <Text style={styles.inputLabel}>Confirm Password</Text>
+               <TextInput
+                 secureTextEntry={this.state.wrongCount < 3}
+                 style={styles.inputView}
+                 placeholder='Password'
+                 maxLength={20}
+                 onChangeText={v => this.changeInfo('password', v)}
+               />
+             </View>
+             { this.state.isFleetDriver &&
+               <>
+               <View style={styles.signInput}>
+                 <Text style={styles.inputLabel}>Your Company</Text>
+                 <Dropdown
+                   style={[styles.inputView, ui.flexc]}
+                   title='Company'
+                   list={this.state.companyList}
+                   value={this.state.fleetCompanyId}
+                   valueKey='fleetCompanyId'
+                   nameKey='fleetCompanyName'
+                   onChange={(value, index)=> {
+                     this.setState({
+                       fleetCompanyId: value
+                     })
+                   }}/>
+               </View>
+               <View style={styles.signInput}>
+                 <Text style={styles.inputLabel}>{'PDV Licence'}</Text>
+                 <TextInput
+                   style={styles.inputView}
+                   placeholder='PH Driver Vocational Licence'
+                   maxLength={20}
+                   onChangeText={v => this.changeInfo('pdvLicence', v)}
+                 />
+               </View>
+               <View style={styles.signInput}>
+                 <Text style={styles.inputLabel}>{'  PDV Photos\n(Front & Back)'}</Text>
+                 <View style={styles.uploadGroup}>
+                   { this.state.pdvImages.map((item, index) => (
+                     <UploadView
+                       key={index}
+                       onPress={() => this.uploadImage(index)}
+                       url={item}/>
+                     )) 
+                   }
+                 </View>
+               </View>
+               </>
+             }
+             <View style={styles.referView}>
+               <Text style={styles.referTitle}>Have a referral code?</Text>
+               <View style={styles.referText}>
+                 <Text>You'll get</Text>
+                 <Text style={styles.weight}>$5</Text>
+                 <Text>Credit as registration bonus!</Text>
+               </View>
+               <View style={styles.codeView}>
+                 <Text style={{ color: '#333', fontSize: 16 }}>Referral Code</Text>
+                 <TextInput
+                   style={styles.codeText}
+                   maxLength={6}
+                   placeholder='Referral Code'
+                   onChangeText={v => this.changeInfo('referralCode', v)}
+                 />
+               </View>
+             </View>
+             <View style={styles.agreeView}>
+               <CheckBox
+                 value={this.state.agree}
+                 onValueChange={v => this.changeAgree(v)}
+               />
+               <View style={styles.agreeTextRow}>
+                 <Text style={styles.agreeText} onPress={() => this.changeAgree(!this.state.agree)}>
+                   {'I have read and I agree with the '}
+                 </Text>
+                 <Text style={styles.agreeLink} onPress={() => startPage(PageList.condition)}>Terms of Use</Text>
+                 <Text style={styles.agreeText}>{' '}</Text>
+                 <Text style={styles.agreeText}>{'and '}</Text>
+                 <Text style={styles.agreeLink} onPress={() => startPage(PageList.privacy)}>Privacy Policy</Text>
+                 <Text style={styles.agreeText}>.</Text>
+               </View>
+             </View>
+             <Button
+               style={styles.signButton}
+               elevation={1.5}
+               disabled={!this.state.agree}
+               text='SIGN UP'
+               fontSize={14}
+               onClick={() => {
+                 this.onRegister();
+               }}
+             />
+           </View>
+         </ScrollView>
+         <Modal
+           isVisible={this.state.visible}
+           onBackButtonPress={() => this.hideDialog()}
+           {...ModalProps}>
+           <RegisterDialog
+             address={this.state.email}
+             onClose={() => this.hideDialog()}
+           />
+         </Modal>
+       </View>
+     );
+   }
+ }
+ 
+ const UploadView = ({url, onPress}) => (
+   <Pressable
+     style={styles.uploadView}
+     onPress={onPress}>
+     { url == ''
+     ? <Image
+         style={styles.uploadIcon}
+         source={require('../../images/icon/ic-add-photo.png')}/>
+     : <Image
+         style={styles.uploadIcon}
+         defaultSource={require('../../images/icon/icon-upload-default.png')}
+         source={{uri: host + url}}/>
+     }
+   </Pressable>
+ )
+ 
+ const styles = StyleSheet.create({
+   header: {
+     paddingTop: 56,
+     backgroundColor: colorThemes
+   },
+   backView: {
+     top: 12,
+     zIndex: 5,
+     padding: 16,
+     position: 'absolute',
+     flexDirection: 'row'
+   },
+   backButton: {
+     borderRadius: 60,
+     backgroundColor: 'white'
+   },
+   backButtonView: {
+     height: 43,
+     paddingLeft: 16,
+     paddingRight: 16,
+     alignItems: 'center',
+     flexDirection: 'row'
+   },
+   scollView: {
+     flex: 1
+   },
+   logoView: {
+     paddingTop: 32,
+     paddingBottom: 56,
+     alignItems: 'center'
+   },
+   logoImg: {
+     width:165.09,
+     height: 51.94,
+   },
+   signView: {
+     flex: 1,
+     padding: 16,
+     marginTop: -30,
+     borderTopLeftRadius: 20,
+     borderTopRightRadius: 20,
+     backgroundColor: 'white'
+   },
+   tabView: {
+     marginBottom: 4,
+     borderWidth: 1,
+     borderRadius: 6,
+     overflow: 'hidden',
+     alignItems: 'center',
+     flexDirection: 'row',
+     borderColor: colorPrimary,
+   },
+   tabText: {
+     flex: 1,
+     color: '#333',
+     fontSize: 15,
+     textAlign: 'center',
+     ...$padding(10, 0),
+   },
+   tabActive: {
+     color: '#fff',
+     fontWeight: 'bold',
+     backgroundColor: colorPrimary
+   },
+   title: {
+     color: '#333',
+     fontSize: 18,
+     fontWeight: '700',
+     paddingTop: 4,
+     paddingBottom: 6,
+   },
+   signInput: {
+     marginTop: 16,
+     alignItems: 'center',
+     flexDirection: 'row'
+   },
+   inputLabel: {
+     flex: 1,
+     color: '#333',
+     fontSize: 14,
+     marginRight: 4
+   },
+   inputView: {
+     flex: 2,
+     color: '#333',
+     fontSize: 14,
+     borderRadius: 5,
+     minHeight: 40,
+     paddingTop: 6,
+     paddingLeft: 12,
+     paddingRight: 12,
+     paddingBottom: 6,
+     backgroundColor: '#F5F5F5'
+   },
+   mobileView: {
+     flex: 2,
+     marginLeft: -12,
+     alignItems: 'center',
+     flexDirection: 'row'
+   },
+   dropView: {
+     fontSize: 16,
+     borderRadius: 4,
+     paddingRight: 4,
+     flexDirection: 'row',
+     alignItems: 'center',
+     backgroundColor: '#F5F5F5'
+   },
+   dropInput: {
+     width: 12,
+     padding: 6,
+     color: '#333',
+     minHeight: 40,
+   },
+   countryText: {
+     color: '#333',
+     fontSize: 14,
+     paddingRight: 4
+   },
+   dropLayer: {
+     left: 0,
+     right: 0,
+     opacity: 0,
+     position: 'absolute'
+   },
+   contactView: {
+     flex: 1,
+     color: '#333',
+     fontSize: 15,
+     borderRadius: 4,
+     minHeight: 40,
+     paddingTop: 6,
+     paddingLeft: 12,
+     paddingRight: 12,
+     paddingBottom: 6,
+     marginLeft: 10,
+     backgroundColor: '#F5F5F5'
+   },
+   passwordView: {
+     flex: 2,
+     marginTop: -8,
+   },
+   strengthView: {
+     marginTop: -4,
+     alignItems: 'center',
+     paddingBottom: 4,
+     flexDirection: 'row'
+   },
+   passwordRole: {
+     color: '#999',
+     fontSize: 10,
+     lineHeight: 13
+   },
+   strengthItem: {
+     width: 14,
+     height: 2.5,
+     marginLeft: 8,
+     borderRadius: 3,
+     backgroundColor: '#CCC'
+   },
+   referView: {
+     padding: 16,
+     marginTop: 24,
+     borderRadius: 6,
+     alignItems: 'center',
+     backgroundColor: '#F5F5F5'
+   },
+   referTitle: {
+     color: '#333',
+     fontSize: 18,
+     fontWeight: 'bold'
+   },
+   referText: {
+     color: '#333',
+     paddingTop: 4,
+     alignItems: 'flex-end',
+     flexDirection: 'row'
+   },
+   weight: {
+     fontSize: 18,
+     paddingLeft: 4,
+     paddingRight: 4,
+     color: colorAccent,
+     fontWeight: 'bold'
+   },
+   codeView: {
+     paddingTop: 16,
+     alignItems: 'center',
+     flexDirection: 'row'
+   },
+   codeText: {
+     color: '#333',
+     fontSize: 16,
+     paddingTop: 6,
+     paddingLeft: 12,
+     paddingRight: 12,
+     paddingBottom: 6,
+     minHeight: 40,
+     marginLeft: 16,
+     borderRadius: 6,
+     textAlign: 'center',
+     backgroundColor: 'white'
+   },
+   signButton: {
+     marginTop: 24,
+     marginBottom: 8,
+   },
+   uploadGroup: {
+     flex: 2,
+     alignItems: 'center',
+     flexDirection: 'row',
+     justifyContent: 'center'
+   },
+   uploadView: {
+     flex: 1,
+     alignItems: 'center'
+   },
+   uploadIcon: {
+     width: $vw(28),
+     height: $vw(28),
+     borderRadius: 6
+   },
+   agreeView: {
+     marginTop: 24,
+     marginBottom: 16,
+     flexDirection: 'row',
+     alignItems: 'flex-start',
+   },
+   agreeTextRow: {
+     flex: 1,
+     paddingTop: 4,
+     paddingLeft: 8,
+     flexWrap: 'wrap',
+     flexDirection: 'row'
+   },
+   agreeText: {
+     color: '#333',
+     fontSize: 14,
+     paddingTop: 2,
+     paddingBottom: 2
+   },
+   agreeLink: {
+     ...ui.link,
+     fontSize: 14,
+     paddingTop: 2,
+     paddingBottom: 2,
+     textDecorationLine: 'underline'
+   }
+ });
+ 

+ 361 - 0
Strides-APP/app/pages/sign/ResetPasswordV2.js

@@ -0,0 +1,361 @@
+/**
+ * 忘记密码-重置密码页面V2
+ * @邠心vbe on 2022/12/23
+ */
+ import React, { Component } from 'react';
+ import { View, Text, StyleSheet, ScrollView, Image, TextInput } from 'react-native';
+ import apiUser from '../../api/apiUser';
+ import Button from '../../components/Button';
+ import Dialog from '../../components/Dialog';
+ import { BackIcon } from '../../components/Toolbar';
+ import { StrengthView } from './Register';
+ 
+ export default class ResetPassword extends Component {
+   constructor(props) {
+     super(props);
+     this.state = {
+       strength: 0,
+       password: '',
+       wrongCount: 0,
+       sendMinutes: 0
+     };
+     this.formInfo = {
+       email: '',
+       password: '',
+       verificationCode: ''
+     }
+   }
+ 
+   componentWillUnmount() {
+     this.setState({
+       sendMinutes: 0
+     })
+   }
+ 
+   getBackTopPosition() {
+     return isIOS ? statusHeight - 18 : 12;
+   }
+ 
+   changeInfo(key, value) {
+     this.formInfo[key] = value;
+   }
+ 
+   applyStrength(text) {
+     var strength = 0;
+     if (text.length >= 8) {
+       strength += 1;
+     }
+     if (/\d{1,}/.test(text)) {
+       strength += 1;
+     }
+     if (/[A-z]{1,}/.test(text)) {
+       strength += 1;
+     }
+     /*if (/[A-Z]{1,}/.test(text)) {
+       strength += 1;
+     }
+     if (/\W{1,}/.test(text)) {
+       strength += 1;
+     }*/
+     if (this.state.strength != strength) {
+       this.setState({
+         password: text,
+         strength: strength
+       });
+     } else {
+       this.setState({
+         password: text
+       });
+     }
+   }
+ 
+   sendVerification() {
+     var info = this.formInfo;
+     if (!info.email) {
+       toastShort('Please enter email address');
+       return;
+     }
+     if (!/^[a-zA-Z0-9]+[\S]+@[a-zA-Z0-9_-]+[\.][\Sa-zA-Z]+$/.test(info.email)) {
+       toastShort('Email is incorrect format');
+       return;
+     }
+     Dialog.showProgressDialog()
+     apiUser.sendVerificationCode(info.email).then(res => {
+       Dialog.dismissLoading()
+       this.state.sendMinutes = 60;
+       toastShort('Send verification code successfully');
+       this.contdownTime();
+     }).catch(err => {
+       Dialog.dismissLoading()
+       toastShort(err);
+     });
+   }
+ 
+   contdownTime() {
+     if (this.state.sendMinutes > 0) {
+       this.setState({
+         sendMinutes: this.state.sendMinutes - 1
+       })
+       setTimeout(() => {
+         this.contdownTime();
+       }, 1000);
+     }
+   }
+ 
+   onResetPassword() {
+     var info = this.formInfo;
+     console.log('reset info', info);
+     if (!info.email) {
+       toastShort('Please enter email address');
+       return;
+     }
+     if (!/^[a-zA-Z0-9]+[\S]+@[a-zA-Z0-9_-]+[\.][\Sa-zA-Z]+$/.test(info.email)) {
+       toastShort('Email is incorrect format');
+       return;
+     }
+     if (!this.state.password) {
+       toastShort('Please enter password');
+       return;
+     }
+     if (this.state.strength < 3) {
+       toastShort('Password is not strong');
+       return;
+     }
+     if (!info.password) {
+       toastShort('Please enter confirm password');
+       return;
+     }
+     if (info.password != this.state.password) {
+       toastShort('The twice passwords are inconsistent');
+       return;
+     }
+     if (!info.verificationCode) {
+       toastShort('Please enter verification code');
+       return;
+     }
+     Dialog.showProgressDialog()
+     apiUser.updatePassword(this.formInfo).then(res => {
+       Dialog.dismissLoading()
+       toastShort('Reset password successfully');
+       goBack();
+     }).catch(err => {
+       Dialog.dismissLoading()
+       toastShort(err);
+     });
+   }
+ 
+   render() {
+     return (
+       <View style={StyleSheet.absoluteFillObject}>
+         <ScrollView
+           style={styles.scollView}
+           keyboardShouldPersistTaps={'handled'}>
+           <View style={styles.header}>
+             <View style={styles.logoView}>
+               {/* <Image
+                 style={styles.logoImg}
+                 source={require('../../images/tool-logo.png')}/> */}
+             </View>
+           </View>
+           <View style={{...styles.backView, top: this.getBackTopPosition()}}>
+             <Button
+               style={styles.backButton}
+               viewStyle={styles.backButtonView}
+               onClick={() => goBack()}>
+               <BackIcon/>
+               <Text style={{color: '#333',fontSize: 16,paddingLeft: 8}}>Back to Login</Text>
+             </Button>
+           </View>
+           <View style={styles.resetView}>
+             <Text style={styles.title}>Reset Password</Text>
+             <View style={styles.signInput}>
+               <Text style={styles.inputLabel}>Email Address</Text>
+               <TextInput
+                 style={styles.inputView}
+                 placeholder='Email Address'
+                 maxLength={50}
+                 onChangeText={v => this.changeInfo('email', v)}
+               />
+             </View>
+             <View style={styles.signInput}>
+               <Text style={styles.inputLabel}>New Password</Text>
+               <TextInput
+                 secureTextEntry={this.state.wrongCount < 3}
+                 style={styles.inputView}
+                 placeholder='Password'
+                 maxLength={20}
+                 onChangeText={(value) => {
+                   this.applyStrength(value);
+                 }}
+               />
+             </View>
+             <View style={styles.signInput}>
+               <Text style={styles.inputLabel}></Text>
+               <View style={styles.passwordView}>
+                 <View style={styles.strengthView}>
+                   <Text style={{fontSize:12, paddingRight: 4, color: '#333'}}>Password Strength</Text>
+                   <StrengthView {...this.state}/>
+                 </View>
+                 <View>
+                   <Text style={styles.passwordRole}>Your Password Must Have:</Text>
+                   <Text style={styles.passwordRole}>- 8 or more characters</Text>
+                   {/* <Text style={styles.passwordRole}>- upper and lower case letters</Text> */}
+                   <Text style={styles.passwordRole}>- at least one number</Text>
+                 </View>
+               </View>
+             </View>
+             <View style={styles.signInput}>
+               <Text style={styles.inputLabel}>Confirm Password</Text>
+               <TextInput
+                 secureTextEntry={this.state.wrongCount < 3}
+                 style={styles.inputView}
+                 placeholder='Password'
+                 maxLength={20}
+                 onChangeText={v => this.changeInfo('password', v)}
+               />
+             </View>
+             <View style={styles.signInput}>
+               <Text style={[styles.inputLabel, ui.flex2]}>Verification Code</Text>
+               <TextInput
+                 style={[styles.inputView, {flex: 2.6, marginLeft: 2}]}
+                 placeholder='Verification Code'
+                 maxLength={6}
+                 onChangeText={v => this.changeInfo('verificationCode', v)}
+               />
+               <Button
+                 text={this.state.sendMinutes > 0 ? this.state.sendMinutes : 'Get Code'}
+                 style={styles.sendBtn}
+                 disabled={this.state.sendMinutes > 0}
+                 viewStyle={styles.sendBtnView}
+                 textStyle={styles.sendBtnText}
+                 onClick={() => this.sendVerification()}
+               />
+             </View>
+           </View>
+           <Text style={styles.divideText}>We will send you an email with the verification code.</Text>
+           <Button
+             text='Reset Password'
+             style={styles.resetButton}
+             onClick={() => this.onResetPassword()}
+           />
+         </ScrollView>
+       </View>
+     );
+   }
+ }
+ 
+ const styles = StyleSheet.create({
+   header: {
+     paddingTop: 56,
+     backgroundColor: colorThemes
+   },
+   backView: {
+     top: 12,
+     zIndex: 5,
+     padding: 16,
+     position: 'absolute',
+     flexDirection: 'row'
+   },
+   backButton: {
+     borderRadius: 60,
+     backgroundColor: 'white'
+   },
+   backButtonView: {
+     height: 43,
+     paddingLeft: 16,
+     paddingRight: 16,
+     alignItems: 'center',
+     flexDirection: 'row'
+   },
+   scollView: {
+     flex: 1,
+     backgroundColor: 'white'
+   },
+   logoView: {
+     paddingTop: 40,
+     paddingBottom: 56,
+     alignItems: 'center'
+   },
+   logoImg: {
+     width:165.09,
+     height: 51.94,
+   },
+   resetView: {
+     flex: 1,
+     padding: 16,
+     marginTop: -30,
+     borderTopLeftRadius: 20,
+     borderTopRightRadius: 20,
+     backgroundColor: 'white'
+   },
+   title: {
+     color: '#333',
+     fontSize: 18,
+     fontWeight: '700',
+     paddingTop: 4,
+     paddingBottom: 6,
+   },
+   signInput: {
+     marginTop: 16,
+     alignItems: 'center',
+     flexDirection: 'row'
+   },
+   inputLabel: {
+     flex: 1,
+     color: '#333',
+     fontSize: 14
+   },
+   inputView: {
+     flex: 2,
+     color: '#333',
+     fontSize: 14,
+     borderRadius: 5,
+     minHeight: 40,
+     paddingTop: 6,
+     paddingLeft: 12,
+     paddingRight: 12,
+     paddingBottom: 6,
+     backgroundColor: '#F5F5F5'
+   },
+   passwordView: {
+     flex: 2,
+     marginTop: -8,
+   },
+   strengthView: {
+     marginTop: -4,
+     alignItems: 'center',
+     paddingBottom: 4,
+     flexDirection: 'row'
+   },
+   passwordRole: {
+     color: '#999',
+     fontSize: 10,
+     lineHeight: 13
+   },
+   sendBtn: {
+     flex: 1.4,
+     marginLeft: 6
+   },
+   sendBtnView: {
+     flex: 1,
+     height: 40,
+     paddingLeft: 4,
+     paddingRight: 4,
+     alignItems: 'center',
+     justifyContent: 'center'
+   },
+   sendBtnText: {
+     color: '#fff',
+     fontSize: 13,
+     fontWeight: 'bold'
+   },
+   divideText: {
+     color: '#333',
+     fontSize: 14,
+     padding: 58,
+     textAlign: 'center'
+   },
+   resetButton: {
+     margin: 16
+   }
+ })

+ 2 - 2
Strides-APP/app/pages/wallet/AddCard.js

@@ -112,7 +112,7 @@ export default class AddCard extends Component {
             <FontAwesome
               name='credit-card'
               size={24}
-              color={colorAccent}/>
+              color={colorPrimary}/>
             <Text style={styles.leftLine}/>
             <TextInput
               style={styles.cardNumber}
@@ -167,7 +167,7 @@ export default class AddCard extends Component {
           <View style={styles.countryRow}>
             <MaterialIcons
               name='flag'
-              color={colorAccent}
+              color={colorPrimary}
               size={30}/>
             <Dropdown
               style={styles.countryPicker }

+ 6 - 3
Strides-APP/app/pages/wallet/Overview.js

@@ -10,6 +10,8 @@ import apiWallet from '../../api/apiWallet';
 import Svg from 'react-native-svg';
 import utils from '../../utils/utils';
 
+const chartThemes = "#6672B8"; //配置柱状图颜色
+
 export default class Overview extends Component {
   constructor(props) {
     super(props);
@@ -93,7 +95,7 @@ export default class Overview extends Component {
   barTheme = (active) => ({
     data: { 
       fill: ({datum, index}) => {
-        return (datum.y > 0 ? (index == active ? "#FFCC2C" : "#FFE080") : "#999999");
+        return (datum.y > 0 ? (index == active ? colorPrimary : chartThemes) : "#999999");
       }
     },
     labels: {
@@ -102,7 +104,7 @@ export default class Overview extends Component {
     }
   })
 
-  getFill = ({datum, index}) => (datum.y > 0 ? (index == this.state.monthIndex ? "#FFCC2C" : "#FFE080") : "#999999");
+  getFill = ({datum, index}) => (datum.y > 0 ? (index == this.state.monthIndex ? colorPrimary : chartThemes) : "#999999");
 
   render() {
     return (
@@ -227,6 +229,7 @@ const styles = StyleSheet.create({
     marginRight: 16,
     marginBottom: 4,
     ...ElevationObject(2),
+    overflow: 'hidden',
     borderTopLeftRadius: 6,
     borderTopRightRadius: 6,  
     backgroundColor: 'white'
@@ -237,7 +240,7 @@ const styles = StyleSheet.create({
     paddingTop: 4,
     paddingLeft: 16,
     paddingBottom: 4,
-    backgroundColor: '#F7EDCD'
+    backgroundColor: '#C4C8DF'
   },
   overviewRow: {
     paddingTop: 16,

+ 2 - 2
Strides-APP/app/pages/wallet/PaythodList.js

@@ -82,7 +82,7 @@ export default class PaythodList extends Component {
                 */}
                 <Text style={styles.paytypeText}>{this.getSecuryNumber(item.payName, item.cardPk)}</Text>
                 <View style={styles.selectIcon}>
-                  <ChargeItemSelect size={18} selected={index == this.state.cIndex}/>
+                  <ChargeItemSelect size={18} selected={index == this.state.cIndex} tint={colorPrimary}/>
                 </View>
               </Pressable>
             );
@@ -104,7 +104,7 @@ const styles = StyleSheet.create({
     backgroundColor: '#F5F5F5'
   },
   selected: {
-    borderColor: colorAccent
+    borderColor: colorPrimary
   },
   next: {
     marginTop: 16,

+ 4 - 4
Strides-APP/app/pages/wallet/Topup.js

@@ -185,7 +185,7 @@ const styles = StyleSheet.create({
   },
   headerView: {
     paddingBottom: 76,
-    backgroundColor: colorAccent
+    //backgroundColor: colorAccent
   },
   contentView: {
     padding: 16,
@@ -205,7 +205,7 @@ const styles = StyleSheet.create({
     width: 4,
     height: 15,
     borderRadius: 16,
-    backgroundColor: colorAccent
+    backgroundColor: colorPrimary
   },
   titleText: {
     color: '#333',
@@ -238,9 +238,9 @@ const styles = StyleSheet.create({
     marginLeft: 20
   },
   selected: {
-    color: '#333',
+    color: '#fff',
     borderColor: '#333',
-    backgroundColor: colorAccent
+    backgroundColor: colorPrimary
   },
   autoView: {
     flex: 1,

+ 2 - 2
Strides-APP/app/utils/notification.js

@@ -67,8 +67,8 @@ PushNotification.configure({
 PushNotification.createChannel(
   {
     channelId: "10186", // (required)
-    channelName: "Juice+ Messaging", // (required)
-    channelDescription: "Juice+ notification center, remind of the charging process", // (optional) default: undefined.
+    channelName: "Application Messaging", // (required)
+    channelDescription: "Application notification center, remind of the charging process", // (optional) default: undefined.
     playSound: false, // (optional) default: true
     soundName: "default", // (optional) See `soundName` parameter of `localNotification` function
     importance: Importance.HIGH, // (optional) default: Importance.HIGH. Int value of the Android notification importance

+ 7 - 7
Strides-APP/ios/JuicePlus/GoogleService-Info.plist

@@ -3,21 +3,21 @@
 <plist version="1.0">
 <dict>
 	<key>CLIENT_ID</key>
-	<string>948303787961-l2hd35gvm4cc7r5u27sufds3obf9c65l.apps.googleusercontent.com</string>
+	<string>779803805444-7vilfstvrrjvolvc3mgq5iklpied7f5e.apps.googleusercontent.com</string>
 	<key>REVERSED_CLIENT_ID</key>
-	<string>com.googleusercontent.apps.948303787961-l2hd35gvm4cc7r5u27sufds3obf9c65l</string>
+	<string>com.googleusercontent.apps.779803805444-7vilfstvrrjvolvc3mgq5iklpied7f5e</string>
 	<key>API_KEY</key>
-	<string>AIzaSyBT9s2Bgr3IpjMvubHNTnhz1DInQKcbjfg</string>
+	<string>AIzaSyC18ciIi5QnMpCphuLPyXfwasz4C7YqkKU</string>
 	<key>GCM_SENDER_ID</key>
-	<string>948303787961</string>
+	<string>779803805444</string>
 	<key>PLIST_VERSION</key>
 	<string>1</string>
 	<key>BUNDLE_ID</key>
 	<string>com.strides.chargeco</string>
 	<key>PROJECT_ID</key>
-	<string>juiceplus-c5c61</string>
+	<string>strides-67073</string>
 	<key>STORAGE_BUCKET</key>
-	<string>juiceplus-c5c61.appspot.com</string>
+	<string>strides-67073.appspot.com</string>
 	<key>IS_ADS_ENABLED</key>
 	<false></false>
 	<key>IS_ANALYTICS_ENABLED</key>
@@ -29,6 +29,6 @@
 	<key>IS_SIGNIN_ENABLED</key>
 	<true></true>
 	<key>GOOGLE_APP_ID</key>
-	<string>1:948303787961:ios:967600f6d1e089809aa868</string>
+	<string>1:779803805444:ios:c6bd33a7368d3fe07af251</string>
 </dict>
 </plist>

+ 1 - 1
Strides-APP/ios/JuicePlus/Info.plist

@@ -5,7 +5,7 @@
 	<key>CFBundleDevelopmentRegion</key>
 	<string>en</string>
 	<key>CFBundleDisplayName</key>
-	<string>Juice Plus</string>
+	<string>ChargEco</string>
 	<key>CFBundleExecutable</key>
 	<string>$(EXECUTABLE_NAME)</string>
 	<key>CFBundleIdentifier</key>

+ 1 - 0
Strides-APP/package.json

@@ -56,6 +56,7 @@
     "react-native-view-shot": "^3.1.2",
     "react-native-webview": "^11.6.4",
     "supercluster": "^7.1.3",
+    "vbe-cluster-map": "1.0",
     "victory-native": "^35.3.3"
   },
   "devDependencies": {

+ 1 - 1
Strides-Admin/src/layout/components/Navbar.vue

@@ -88,7 +88,7 @@ export default {
   },
   data() {
     return {
-      username: 'Juice Plus'
+      username: 'Admin'
     }
   },
   created() {

+ 3 - 2
Strides-Admin/src/layout/components/Sidebar/Logo.vue

@@ -1,5 +1,5 @@
 <template>
-  <div class="sidebar-logo-container">
+  <div class="sidebar-logo-container" :title="title">
     <router-link class="sidebar-logo-link" to="/">
       <img src="../../../icons/logo-app.png" class="sidebar-logo" v-if="collapse">
       <img src="../../../icons/logo.png" class="sidebar-logo" v-else>
@@ -8,6 +8,7 @@
 </template>
 
 <script>
+import settings from '../../../settings.js'
 export default {
   name: 'SidebarLogo',
   props: {
@@ -18,7 +19,7 @@ export default {
   },
   data() {
     return {
-      title: 'Vue Element Admin',
+      title: settings.title,
       logo: '@/icons/logo.png'
     }
   }

+ 0 - 1
Strides-Admin/src/layout/components/Sidebar/SidebarItem.vue

@@ -13,7 +13,6 @@
           <item
             :icon="selectedItemIndex === resolvePath(onlyOneChild.path)
               ? (onlyOneChild.meta.activeIcon || item.meta && item.meta.activeIcon)
-                || (onlyOneChild.meta.icon || (item.meta && item.meta.icon))
               : onlyOneChild.meta.icon || (item.meta && item.meta.icon)" 
             :title="onlyOneChild.meta.title"
           />

+ 1 - 0
Strides-Admin/src/layout/components/Sidebar/index.vue

@@ -38,6 +38,7 @@ export default {
   created() {
     this.authRoutesList = getAuthRoutes()
     this.filterRoutes(this.$router.options.routes)
+    this.selectedItemIndex = this.$route.path
   },
   data() {
     return {

+ 17 - 2
Strides-Admin/src/settings.js

@@ -1,11 +1,26 @@
 module.exports = {
+  /**
+   * @type {string}
+   * @description Web page title
+   */
   title: 'ChargEco Admin',
-
+  
+  /**
+   * @type {string}
+   * @description project name
+   */
+  projectName: 'ChargEco',
+  /**
+   * @type {string}
+   * @description API url base service
+   */
+  baseUrl: '/steve',
+  
   /**
    * @type {boolean} true | false
    * @description Whether show the settings right-panel
    */
-  showSettings: true,
+  showSettings: false,
 
   /**
    * @type {boolean} true | false

+ 5 - 4
Strides-Admin/src/utils/auth.js

@@ -1,10 +1,11 @@
 import Cookies from 'js-cookie'
 import { Base64 } from 'js-base64';
+import settings from '@/settings'
 
-const TokenKey = 'juice-plus-token'
-const AuthRoutesKey = 'juice-plus-ApacheResource'
-const RoleName = 'juice-plus-player'
-const UserName = 'juice-plus-game'
+const TokenKey = settings.projectName + '-TOKEN'
+const AuthRoutesKey = settings.projectName + '-ApacheResource'
+const RoleName = settings.projectName + '-Player'
+const UserName = settings.projectName + '-Gamer'
 
 export function getToken() {
   return Cookies.get(TokenKey)

+ 0 - 16
Strides-Admin/src/utils/config.js

@@ -1,16 +0,0 @@
-module.exports = {
-  baseUrl: '/steve',
-  title: 'ChargEco Admin',
-
-  /**
-   * @type {boolean} true | false
-   * @description Whether fix the header
-   */
-  fixedHeader: false,
-
-  /**
-   * @type {boolean} true | false
-   * @description Whether show the logo in sidebar
-   */
-  sidebarLogo: false
-}

+ 2 - 2
Strides-Admin/src/utils/getPageTitle.js

@@ -1,6 +1,6 @@
-import defaultSettings from './config'
+import defaultSettings from '../settings'
 
-const title = defaultSettings.title || 'Juice Plus Admin'
+const title = defaultSettings.title
 
 export default function getPageTitle(pageTitle) {
   if (pageTitle) {

+ 4 - 4
Strides-Admin/src/views/feedback/Detail.vue

@@ -56,12 +56,12 @@
             v-if="feedbackInfo.feedbackImgOne"/>
           <img
             class="feedback-img"
-            :src="baseURL + feedbackInfo.feedbackImgOne"
-            v-if="feedbackInfo.feedbackImgOne"/>
+            :src="baseURL + feedbackInfo.feedbackImgTwo"
+            v-if="feedbackInfo.feedbackImgTwo"/>
           <img
             class="feedback-img"
-            :src="baseURL + feedbackInfo.feedbackImgOne"
-            v-if="feedbackInfo.feedbackImgOne"/>
+            :src="baseURL + feedbackInfo.feedbackImgThree"
+            v-if="feedbackInfo.feedbackImgThree"/>
         </div>
         <div class="hr-full"/>
         <div class="buttons">