Parcourir la source

add app/pages/my/Feedback.js

wudebin il y a 5 mois
Parent
commit
ad875e4cca
2 fichiers modifiés avec 650 ajouts et 0 suppressions
  1. 515 0
      Strides-SPAPP/app/pages/my/Feedback.js
  2. 135 0
      Strides-SPAPP/app/pages/my/Referral.js

+ 515 - 0
Strides-SPAPP/app/pages/my/Feedback.js

@@ -0,0 +1,515 @@
+/**
+ * Feedback 页面
+ * @邠心vbe on 2021/04/28
+ */
+import React from 'react';
+import { View, Text, StyleSheet, ScrollView, TextInput, Image, Pressable, FlatList } from 'react-native';
+import Button from '../../components/Button';
+import apiUpload from '../../api/apiUpload';
+import apiUser from '../../api/apiUser';
+import Dialog from '../../components/Dialog';
+import ImagePicker from 'react-native-image-crop-picker';
+import Dropdown from '../../components/Dropdown';
+import Modal from 'react-native-modal';
+import { UploadThemes } from '../../components/ThemesConfig';
+import apiBase from '../../api/apiBase.js';
+import utils from '../../utils/utils';
+import MyModal from '../../components/MyModal';
+import VbeSkeleton from '../../components/VbeSkeleton';
+
+const options = {
+  cropping: false,
+  multiple: false,
+  minFiles: 1,
+  maxFiles: 3,
+  mediaType: 'photo',
+  writeTempFile: false,
+  compressImageQuality: 0.8,
+  compressImageMaxWidth: 720,
+  compressImageMaxHeight: 1280,
+  ...UploadThemes
+}
+
+export default class Feedback extends React.Component {
+
+  constructor(props) {
+    super(props);
+    this.state= {
+      typeList: [],
+      feedback: '',
+      searchId: '',
+      connectorId: '',
+      chargeBoxId: '',
+      typeOfFeedback: '',
+      imageUrl: ['', '', ''],
+      chargeBoxList: [],
+      connectorList: [],
+      showDialog: false,
+      searching: false
+    }
+  }
+
+  componentDidMount() {
+    this.pageShow = true;
+    this.props.navigation.addListener('blur', () => {
+      this.pageShow = false;
+    });
+
+    apiUser.getTypeOfFeedback().then(res => {
+      if (res.success && res.data.length > 0) {
+        this.setState({
+          typeList: res.data
+        });
+      } else {
+        if (this.pageShow) {
+          this.noTypeDialog();
+        }
+      }
+    }).catch(err => {
+      if (this.pageShow) {
+        this.noTypeDialog();
+      }
+    });
+    this.getChargeBox("");
+  }
+
+  noTypeDialog() {
+    setTimeout(() => {
+      if (this.pageShow) {
+        Dialog.showResultDialog($t('feedback.errFetchType'), $t('nav.ok'), back => {
+          goBack();
+        });
+      }
+    }, 500);
+  }
+
+  changeType(type, index) {
+    this.setState({
+      typeOfFeedback: type
+    })
+  }
+
+  listChargeBox(searchId) {
+    this.setState({
+      searching: true,
+      searchId: searchId
+    }, () => {
+      setTimeout(() => {
+        this.getChargeBox(searchId)
+      }, 300);
+    });
+  }
+
+  getChargeBox(searchId) {
+    if (searchId != this.state.searchId) {
+      return;
+    }
+    apiBase.listChargeBox(this.state.searchId).then(res => {
+      if (res.data) {
+        this.setState({
+          chargeBoxList: res.data,
+          searching: false
+        })
+      } else {
+        this.setState({
+          chargeBoxList: [],
+          searching: false,
+          connectorId: ""
+        })
+      }
+    }).catch(err => {
+      this.setState({
+        chargeBoxList: [],
+        searching: false,
+        connectorId: ""
+      })
+    })
+  }
+
+  listConnector() {
+    //Dialog.showProgressDialog()
+    apiBase.listConnector(this.state.chargeBoxId).then(res => {
+      if (res.data) {
+        this.setState({
+          connectorList: res.data
+        })
+      } else {
+        this.setState({
+          connectorList: []
+        })
+      }
+    }).catch(err => {
+      this.setState({
+        connectorList: []
+      })
+    })
+  }
+
+  uploadImage(index) {
+    ImagePicker.openPicker(options).then(image => {
+      if (image.path) {
+        apiUpload.uploadImage(image.path, image.mime, 'FEEDBACK').then(res => {
+          if (res.success && res.data.picturePath) {
+            let imageUrl = this.state.imageUrl;
+            imageUrl[index] = res.data.picturePath;
+            this.setState({
+              imageUrl: imageUrl
+            });
+            toastShort($t('common.uploadSuccess'));
+          } else {
+            toastShort($t('common.uploadFailed'));
+          }
+        }).catch(err => {
+          toastShort(err);
+        });
+      }
+    }).catch(err => {
+      //console.log(err);
+    });
+  }
+
+  submitFeedback() {
+    if (this.state.typeOfFeedback == '') {
+      toastShort($t('feedback.errFeedbackType'));
+      return;
+    }
+    if (this.state.feedback == '') {
+      toastShort($t('feedback.errFeednackContent'));
+      return;
+    }
+    const params = {
+      "typeOfFeedback": this.state.typeOfFeedback,
+      "feedback": this.state.feedback,
+      "feedbackImgOne": this.state.imageUrl[0],
+      "feedbackImgTwo": this.state.imageUrl[1],
+      "feedbackImgThree": this.state.imageUrl[2],
+      "chargeBoxId": this.state.chargeBoxId,
+      "connectorId": this.state.connectorId
+    }
+    Dialog.showProgressDialog();
+    apiUser.feedback(params).then(res => {
+      Dialog.dismissLoading();
+      Dialog.showResultDialog($t('feedback.sendSuccess'), $t('nav.ok'), back => {
+        goBack();
+      });
+    }).catch(err => {
+      Dialog.dismissLoading();
+      toastShort(err);
+    });
+  }
+
+  changeChargeBox(id) {
+    if (id) {
+      this.setState({
+        showDialog: false,
+        chargeBoxId: id
+      }, () => this.listConnector())
+    } else {
+      this.setState({
+        showDialog: false
+      })
+    }
+  }
+
+  changeConnector(id) {
+    this.setState({
+      connectorId: id
+    })
+  }
+
+  render() {
+    return (
+      <ScrollView
+        style={styles.container}
+        keyboardShouldPersistTaps={isIOS ? 'never' : 'handled'}
+        contentInsetAdjustmentBehavior='automatic'>
+        <View style={styles.headerView}>
+          <View style={ui.flex1}>
+            <Text style={styles.title}>{$t('feedback.tipsSomething')}</Text>
+            <Text style={styles.content}>{$t('feedback.tipsLetKnow')}</Text>
+          </View>
+          <Image
+            style={styles.headerImage}
+            resizeMode="contain"
+            source={require('../../images/top-feedback.png')}/>
+        </View>
+        
+        <View style={styles.contentView}>
+          <Text style={styles.typeTitle}>{$t('feedback.typeOfFeedback')}</Text>
+          <View style={styles.pickerView}>
+            <Dropdown
+              style={styles.pickerViewInfo}
+              title={$t('feedback.typeOfFeedback')}
+              list={this.state.typeList}
+              value={this.state.typeOfFeedback}
+              nameKey={'value'}
+              valueKey={'key'}
+              placeholder={$t('common.select')}
+              onChange={(value, index) => this.changeType(value, index)}/>
+          </View>
+          
+          <Text style={styles.typeTitle}>{$t('feedback.labelContent')}</Text>
+          <TextInput
+            style={styles.feedbackInput}
+            multiline={true}
+            numberOfLines={8}
+            maxLength={1000}
+            textAlignVertical='top'
+            onChangeText={text => {
+              this.setState({
+                feedback: text
+              });
+            }}/>
+          
+          <Text style={styles.typeTitle}>{$t('feedback.labelUpload')}</Text>
+          <View
+            style={styles.uploadGroup}>
+            { this.state.imageUrl.map((item, index) => {
+                return (
+                  <Pressable
+                    key={index}
+                    style={styles.uploadView}
+                    onPress={() => {
+                      this.uploadImage(index)
+                    }}>
+                    { item == ''
+                    ? <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: utils.getImageUrl(item)}}/>
+                    }
+                  </Pressable>
+                );
+              })
+            }
+          </View>
+
+          {this.state.typeOfFeedback == "csf" && <>
+            <Text style={styles.typeTitle}>{$t('feedback.labelStation')}</Text>
+            <Button
+              style={styles.pickerView}
+              viewStyle={[styles.stationView, ui.flex1]}
+              onClick={() => this.setState({showDialog: true})}>
+              <MaterialIcons
+                name="search"
+                size={24}
+                color="#00638C"
+              />
+              <Text style={styles.textStation}>{this.state.chargeBoxId}</Text>
+            </Button>
+            <Text style={styles.typeTitle}>{$t('feedback.labelConnector')}</Text>
+            <View style={styles.pickerView}>
+              <Dropdown
+                style={styles.pickerViewInfo}
+                title={$t('feedback.selectConnector')}
+                list={this.state.connectorList}
+                value={this.state.connectorId}
+                placeholder={$t('common.select')}
+                onChange={value => this.changeConnector(value)}/>
+            </View>
+          </>}
+          <Button
+            style={styles.button}
+            text={$t('feedback.submitFeedback')}
+            elevation={1.5}
+            onClick={() => {
+              this.submitFeedback();
+            }}/>
+        </View>
+        <MyModal
+          visible={this.state.showDialog}
+          onLayerPress={() => this.changeChargeBox()}>
+          <View style={$padding(8, 0)}>
+            <View style={styles.searchView}>
+              <MaterialIcons
+                name="search"
+                size={24}
+                color="#00638C"
+              />
+              <TextInput
+                style={styles.inputView}
+                maxLength={50}
+                placeholder={$t('feedback.searchingChargeBox')}
+                onChangeText={text => this.listChargeBox(text)}
+              />
+            </View>
+            { this.state.searching
+            ? <VbeSkeleton
+                style={styles.stationList}
+                layout={[
+                  {width: "80%", height: 20, ...$margin(14, 0, 14, 16)},
+                  {width: "80%", height: 20, ...$margin(14, 0, 14, 16)},
+                  {width: "80%", height: 20, ...$margin(14, 0, 14, 16)}
+                ]}/>
+            : <FlatList
+                style={styles.stationList}
+                data={this.state.chargeBoxList}
+                keyExtractor={(item,index) => index}
+                renderItem={this.listItem}
+                ListEmptyComponent={<Text style={styles.noResult}>{$t('home.noSearch')}</Text>}
+              />
+            }
+          </View>
+        </MyModal>
+      </ScrollView>
+    );
+  }
+
+  listItem = ({item, index}) => {
+    return (
+      <Button
+        key={index}
+        text={item}
+        style={styles.stationItemView}
+        textStyle={styles.stationItemText}
+        onClick={() => this.changeChargeBox(item)}
+      />
+    )
+  }
+}
+
+const styles = StyleSheet.create({
+  container: {
+    flex: 1,
+    backgroundColor: pageBackground
+  },
+  contentView: {
+    marginTop: -30,
+    borderTopLeftRadius: 30,
+    borderTopRightRadius: 30,
+    ...$padding(8, 16, 16),
+    backgroundColor: colorLight
+  },
+  headerView: {
+    paddingTop: 16,
+    paddingLeft: 16,
+    paddingRight: 8,
+    paddingBottom: 30,
+    flexDirection: 'row',
+    backgroundColor: '#F5F5F5'
+  },
+  headerImage: {
+    width: 123,
+    height: 101
+  },
+  title: {
+    color: '#056A94',
+    fontSize: 18,
+    paddingTop: 16,
+    paddingBottom: 8
+  },
+  content: {
+    color: '#056A94',
+    fontSize: 14
+  },
+  typeTitle: {
+    color: '#000',
+    fontSize: 16,
+    paddingTop: 16,
+    fontWeight: 'bold',
+    paddingBottom: 10
+  },
+  stationView: {
+    paddingLeft: 12,
+    alignItems: 'center',
+    flexDirection: 'row'
+  },
+  textStation: {
+    flex: 1,
+    color: textPrimary,
+    fontSize: 15,
+    paddingLeft: 8
+  },
+  pickerView: {
+    //width: $vw(60),
+    height: 44,
+    borderWidth: 1,
+    borderColor: '#999',
+    borderRadius: 6,
+    overflow: 'hidden',
+    justifyContent: 'center',
+    backgroundColor: '#F5F5F5'
+  },
+  inputView: {
+    flex: 1,
+    color: textPrimary,
+    fontSize: 15
+  },
+  pickerViewInfo: {
+    height: 44,
+    paddingLeft: 16,
+    paddingRight: 8,
+    alignItems: 'center',
+    flexDirection: 'row'
+  },
+  searchView: {
+    height: 44,
+    paddingLeft: 12,
+    borderWidth: 1,
+    borderColor: '#999',
+    borderRadius: 6,
+    ...$margin(8, 16, 16),
+    overflow: 'hidden',
+    alignItems: 'center',
+    flexDirection: 'row',
+    backgroundColor: '#F5F5F5'
+  },
+  feedbackInput: {
+    color: textPrimary,
+    minHeight: 100,
+    borderWidth: 1,
+    borderColor: '#999',
+    borderRadius: 6,
+    paddingLeft: 10,
+    paddingRight: 10,
+    backgroundColor: '#F5F5F5'
+  },
+  uploadGroup: {
+    //paddingTop: 16,
+    alignItems: 'center',
+    flexDirection: 'row',
+    justifyContent: 'center'
+  },
+  uploadView: {
+    flex: 1,
+    alignItems: 'center'
+  },
+  uploadIcon: {
+    width: $vw(29),
+    height: $vw(29),
+    borderRadius: 6
+  },
+  button: {
+    marginTop: 32,
+    marginBottom: 16,
+    borderRadius: 4
+  },
+  stationList: {
+    height: $vh(35)
+  },
+  noResult: {
+    color: textCancel,
+    fontSize: 12,
+    textAlign: 'center',
+    paddingTop: 32
+  },
+  stationItemView: {
+    borderRadius: 0,
+    backgroundColor: colorLight,
+    borderTopWidth: 1,
+    borderTopColor: '#F0F0F0'
+  },
+  stationItemText: {
+    flex: 1,
+    color: textPrimary,
+    fontSize: 15
+  },
+  seachingIcon: {
+    width: 50,
+    height: 50,
+    marginTop: 20
+  }
+})

+ 135 - 0
Strides-SPAPP/app/pages/my/Referral.js

@@ -0,0 +1,135 @@
+/**
+ * Referral页面
+ * @邠心vbe on 2021/05/08
+ */
+import React, { Component } from 'react';
+import { View, Text, StyleSheet, Image, ScrollView } from 'react-native';
+import Button from '../../components/Button';
+//import Share from 'react-native-share';
+
+export default class Referral extends Component {
+  constructor(props) {
+    super(props);
+    this.state = {
+    };
+  }
+
+  render() {
+    return (
+      <ScrollView
+        style={styles.container}>
+        <Image
+          style={styles.topImage}
+          source={require('../../images/user/referral-top.png')}/>
+        <View style={styles.codeView}>
+          <Text style={styles.codeTitle}>Your Referral Code</Text>
+          <Text style={styles.codeText}>{userInfo.referralCode}</Text>
+          <Text style={styles.codeTips}>Input this at the Registration page</Text>
+          {/* <View style={ui.center}>
+            <Image
+              style={styles.codeImage}
+              source={require('../../images/user/qr-referral-code.png')}/>
+          </View>
+          <Text style={styles.codeTips2}>Let your friends scan QR</Text> */}
+        </View>
+        <Text style={styles.refferalTips}>Refer a friend to the app receive <Text style={ui.mainText}>{currency}1</Text> into your Juice+ CreditWallet. You will receive <Text style={ui.mainText}>{currency}5</Text> into your Juice+ CreditWallet for your referrer's first credit top-up.</Text>
+        {/* <Button
+          style={styles.shareButton}
+          onClick={() => {
+            Share.open({
+              title: 'Share',
+              message: 'Share Juice Plus',
+              url: 'https://csms.evctechnology.com'
+            }).then((res) => {
+              console.log('share app', res);
+            }).catch((err) => {
+              err && console.info('share app', err);
+            });
+          }}>
+          <Entypo
+            name='share'
+            size={16}
+            color={'#000'}/>
+          <Text style={styles.shareText}>Share to Friends</Text>
+        </Button> */}
+      </ScrollView>
+    );
+  }
+}
+
+const styles = StyleSheet.create({
+  container: {
+    flex: 1,
+    backgroundColor: 'white'
+  },
+  topImage: {
+    width: $vw(100),
+    height: $vw(78.75)
+  },
+  codeView: {
+    width: $vw(83),
+    padding: 16,
+    marginTop: -43,
+    marginLeft: $vw(8.5),
+    borderRadius: 20,
+    borderWidth: 1,
+    borderColor: 'rgba(0,0,0,0.1)',
+    backgroundColor: 'white'
+  },
+  codeTitle: {
+    color: '#000',
+    fontSize: 16,
+    textAlign: 'center'
+  },
+  codeText: {
+    color: '#FF7A00',
+    fontSize: 26,
+    fontWeight: 'bold',
+    textAlign: 'center',
+    paddingTop: 6
+  },
+  codeTips: {
+    color: '#333',
+    fontSize: 11,
+    textAlign: 'center',
+    marginLeft: 8,
+    marginRight: 8,
+    paddingTop: 10,
+    paddingBottom: 16,
+    //borderBottomWidth: 1,
+    borderBottomColor: '#eee',
+  },
+  codeTips2: {
+    color: '#333',
+    fontSize: 12,
+    textAlign: 'center'
+  },
+  codeImage: {
+    width: 170,
+    height: 170,
+    margin: 16,
+  },
+  refferalTips: {
+    color: '#000',
+    fontSize: 14,
+    paddingTop: 16,
+    lineHeight: 22,
+    paddingLeft: 16,
+    paddingRight: 16,
+    textAlign: 'center'
+  },
+  shareButton: {
+    margin: 32,
+    elevation: 2,
+    borderRadius: 4,
+    alignItems: 'center',
+    flexDirection: 'row',
+    justifyContent: 'center',
+    backgroundColor: colorAccent
+  },
+  shareText: {
+    color: '#000',
+    fontSize: 16,
+    paddingLeft: 4
+  }
+});