OSDN Git Service

update transfer page.
[bytom/Byone.git] / src / views / sendTransaction / transfer.vue
1 <style lang="scss" scoped>
2 .header {
3   display: flex;
4   margin-bottom: 20px;
5   h1 {
6     margin-left: 12px;
7     font-size: 20px;
8   }
9 }
10 .form{
11   padding: 16px;
12 }
13 .form-item-content input, input.form-item-content {
14     background: none;
15     border-radius: 0;
16     border-bottom: 0.5px solid #EBEBEB;
17     padding: 0;
18     width:100%
19   }
20
21 .form-item-content input:focus,
22 input.form-item-content:focus,
23 input.form-item-content:active
24 {
25   border: 0;
26   border-bottom: 0.5px solid #004EE4;
27
28 }
29
30 .currency{
31     display: flex;
32     justify-content: space-between;
33     align-items: center;
34     margin-top: 16px;
35     padding-bottom: 17px;
36     border-bottom: 0.5px solid #EBEBEB;
37       cursor: pointer;
38
39
40     .symbol{
41       display:flex;
42       font-weight: 600;
43       font-size: 15px;
44     align-items: center;
45     }
46
47     .assetId{
48       font-size:13px;
49       align-items: center;
50       display: flex;
51     }
52 }
53
54 .hint{
55     font-size: 13px;
56     position: absolute;
57     right: 5px;
58     display: flex;
59     align-items:center;
60 }
61
62 .amount-input{
63   display: flex;
64   align-items: center;
65   input{
66     font-size: 28px;
67     font-weight: 600;
68   }
69 }
70
71 .form{
72   margin-bottom: 20px;
73   label{
74     color: rgba(0, 0, 0, 0.36);
75   }
76 }
77
78 .tx-fee{
79   font-size: 12px;
80   display: flex;
81
82   div{
83     margin-left: 7px;
84     color: #5C5C5C;
85   }
86 }
87
88 .max{
89   padding: 2px 12px;
90   background: #EEF4FF;
91   margin-right: 8px;
92   border-radius: 15px;
93   color: #004EE4;
94   font-size: 12px;
95   cursor: pointer;
96 }
97 </style>
98
99 <template>
100     <div class="warp-child bg-grey">
101       <section class="header">
102         <BackButton :small="true" :back="close"/>
103         <h1 class="color-black">
104           <div class="welcome-title">{{ $t('main.send') }}</div>
105         </h1>
106       </section>
107
108       <section class="bg-shadow-white form">
109
110         <div>
111             <div class="form-item">
112                 <label class="form-item-label">{{ $t('transfer.asset') }}</label>
113                 <div class="form-item-content currency"  @click="$router.push({ name: 'asset-selection' })">
114                   <div class="symbol color-black">
115                     <img :src="img(unit)" alt="" class="c-icon">
116
117                     <div class="uppercase">
118                       {{ unit }}
119                     </div>
120
121                   </div>
122
123                   <div class=" text-align-right">
124                     <div class="color-grey-36 uppercase assetId">{{ shortAddress(selectAsset.assetId) }} <i class="iconfont iconarrow_1"></i></div>
125                   </div>
126
127
128                 </div>
129             </div>
130             <div class="form-item">
131               <label class="form-item-label">{{ $t('transfer.address') }}</label>
132               <input class="form-item-content"
133               :placeholder="netType=='vapor'? $t('transfer.vaporAddress'): $t('transfer.bytomAddress')"
134               type="text"
135               id="to"
136               name="to"
137               ref="to"
138               v-model="$v.transaction.to.$model"
139               >
140             </div>
141             <div class="form-item">
142                 <label class="form-item-label" for="tx-amount">
143                   {{ unit+$t('transfer.quantity') }}
144
145                   <small class="float-right color-grey-36" style="margin-right: 8px; margin-top: 8px;">
146                     {{ `${$t('transfer.available')} ${currentBalance} ${unit}` }}
147
148                   </small>
149                 </label>
150                 <div class="form-item-content amount-input">
151                   <input
152                     type="number"
153                     id="tx-amount"
154                     placeholder="0"
155                     name="amount"
156                     ref="amount"
157                     v-model="$v.transaction.amount.$model"
158                     @keypress="limitAmount"
159                   >
160                   <div class="hint">
161                     <div class="max" @click="max()">Max</div>
162                     <span class="color-grey-36">≈ {{formatCurrency(transaction.cost||0)}}</span>
163                   </div>
164
165                 </div>
166             </div>
167
168             <div class="tx-fee">
169                 <label >{{ $t('transfer.fee') }}</label>
170                 <div>{{ transaction.fee }} BTM</div>
171             </div>
172         </div>
173       </section>
174       <section>
175           <a :class="['btn', netType ==='vapor'?'btn-vapor':'btn-bytom']" @click="validate">{{ $t('transfer.send') }}</a>
176       </section>
177
178       <modal-passwd ref="modalPasswd" @confirm="send"></modal-passwd>
179     </div>
180 </template>
181
182 <script>
183   import address from "@/utils/address";
184 import transaction from "@/models/transaction";
185 import getLang from "@/assets/language/sdk";
186 import Confirm from "./transferConfirm";
187 import { BTM } from "@/utils/constants";
188 import { Number as Num } from "@/utils/Number"
189 import { mapActions, mapGetters, mapState } from 'vuex'
190 import * as Actions from '@/store/constants';
191 import _ from 'lodash'
192 import { required } from "vuelidate/lib/validators";
193 import BigNumber from "bignumber.js"
194
195
196   const currencyInPrice = {
197     in_cny: 'cnyPrice',
198     in_usd: 'usdPrice',
199     in_btc:'btcPrice',
200     inCny: 'cnyPrice',
201     inUsd: 'usdPrice',
202     inBtc:'btcPrice'
203   }
204
205 export default {
206     components: {
207         Confirm
208     },
209     data() {
210         return {
211             show: false,
212             address: '',
213             guid: null,
214             account: {},
215             transaction: {
216                 to: "",
217                 asset: BTM,
218                 amount: "",
219                 fee: '0.00000000',
220                 cost: "",
221                 confirmations: 1
222             },
223             selectAsset:{
224               assetId: "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
225               name: "Bytom",
226               symbol: "BTM"
227             }
228         };
229     },
230     validations: {
231       transaction: {
232         to:{
233           required
234         },
235         amount:{
236           required
237         }
238       }
239   },
240     computed: {
241         assets(){
242           if(this.netType === 'vapor'){
243             if(!this.currentAccount.vpBalances ||this.currentAccount.vpBalances.length == 0){
244               return [this.selectAsset]
245             }else{
246               return this.currentAccount.vpBalances.map(b=>b.asset)
247             }
248           }else{
249             if(!this.currentAccount.balances ||this.currentAccount.balances.length == 0){
250               return [this.selectAsset]
251             }else{
252               return this.currentAccount.balances.map(b=>b.asset)
253             }
254           }
255         },
256         currentBalance(){
257           const assetId = this.selectAsset.assetId
258           let balances
259
260           if(this.netType === 'vapor'){
261             balances = this.currentAccount.vpBalances
262           }else{
263             balances = this.currentAccount.balances
264           }
265
266           const balance = balances.find(b => b.asset.assetId === assetId)
267           return balance? balance.availableBalance:0;
268         },
269         unit() {
270           return this.selectAsset.symbol;
271         },
272       ...mapState([
273         'bytom',
274         'currentAsset'
275       ]),
276       ...mapGetters([
277         'currentAccount',
278         'accountList',
279         'currency',
280         'netType'
281       ])
282     },
283     watch: {
284         "transaction.amount": function (newAmount) {
285             const singlePrice = this.selectAsset[currencyInPrice[this.currency]]||this.selectAsset[this.currency]||0
286             this.transaction.cost = Number( singlePrice * newAmount).toFixed(2);
287
288             if(newAmount){
289               this.estimateFee()
290             }else{
291               this.transaction.fee = '0.00000000'
292             }
293         },
294         account: function (newAccount) {
295             if (newAccount.guid == undefined){
296                 return;
297               }
298
299             this.guid = newAccount.guid;
300             this.address = this.netType === 'vapor'?  newAccount.vpAddress: newAccount.address;
301         }
302     },
303     methods: {
304         estimateFee: function(){
305           const asset_amount={}
306           asset_amount[this.selectAsset.assetId] = this.transaction.amount || 0;
307
308           transaction.estimateFee(this.address, asset_amount).then( (resp) =>{
309             this.transaction.fee = resp.fee
310           })
311         },
312         img:function (symbol) {
313           const _symbol = symbol.toLowerCase();
314           if(this.netType === 'vapor'){
315             return `https://cdn.blockmeta.com/resources/logo/vapor/${_symbol}.png`
316           }else{
317             return `https://cdn.blockmeta.com/resources/logo/bytom/${_symbol}.png`
318           }
319         },
320         shortAddress: function (add) {
321           return address.short(add)
322         },
323         formatCurrency: function (num) {
324           return Num.formatCurrency(num, this.currency)
325         },
326         limitAmount ($event) {
327           // restrict to 2 decimal places
328           const n = new BigNumber(this.transaction.amount)
329
330           if(this.transaction.amount!=null && this.transaction.amount.indexOf(".")>-1 && (this.transaction.amount.split('.')[1].length > (this.selectAsset.decimals-1))){
331             $event.preventDefault();
332           }
333         },
334         close: function () {
335             this.$router.push({name: 'home'});
336             this[Actions.SET_CURRENT_ASSET](undefined)
337
338             this.transaction.to = "";
339             this.transaction.amount = "";
340             if(this.$route.query.type == 'popup'){
341                window.close();
342             }
343         },
344         max: function () {
345             this.transaction.amount = this.currentBalance;
346         },
347         validate: function () {
348           this.$v.$touch();
349           if (this.$v.$invalid) {
350             const transaction = this.$v.transaction
351             for (let key in Object.keys(transaction)) {
352               const input = Object.keys(transaction)[key];
353               if (input.includes("$")) return false;
354
355               if (transaction[input].$error) {
356                 switch(input){
357                   case 'to':
358                     this.$toast.error(
359                       this.$t("transfer.emptyTo")
360                     );
361                     break;
362                   case 'amount':
363                     this.$toast.error(
364                       this.$t("transfer.noneBTM")
365                     );
366                     break;
367                 }
368                 this.$refs[input].focus();
369                 break;
370               }
371             }
372           } else {
373             const n = new BigNumber(this.transaction.amount)
374             const to  = this.transaction.to
375             if(!address.isValid(to, this.netType)){
376                 this.$toast.error(
377                     this.$t("error.BTM0006")
378                 );
379                 this.$refs['to'].focus();
380                 return
381             }
382             else if (n.gt(this.currentBalance)) {
383                 this.$toast.error(
384                     this.$t("error.BTM0005")
385                 );
386                 this.$refs['amount'].focus();
387                 return;
388             }
389
390             this.$refs.modalPasswd.open();
391         }
392       },
393       send: function (password) {
394
395             let loader = this.$loading.show({
396                 // Optional parameters
397                 container: null,
398                 canCancel: true,
399                 onCancel: this.onCancel
400             });
401
402             this.transaction.asset = this.selectAsset.assetId;
403             transaction.transfer(this.transaction, password, this.address, this).then(result => {
404                 loader.hide();
405                 this.$router.push('/')
406
407             }).catch(error => {
408                 loader.hide();
409                 this.$toast.error(
410                    getLang(error.message)
411                 );
412             });
413       },
414       ...mapActions([
415         Actions.SET_CURRENT_ASSET,
416       ])
417     }, mounted() {
418         //detect injection
419         let currentAssetId
420         if(this.$route.query.type === 'popup'){
421           if (this.$route.query.from != undefined) {
422               this.address = this.$route.query.from
423               this.guid = this.currentAccount.guid
424               this.account = this.currentAccount
425           }
426
427           if (this.$route.query.asset != undefined) {
428             currentAssetId = this.$route.query.asset
429
430             this.transaction.asset= currentAssetId
431
432             const assets = this.assets
433             this.selectAsset = assets.filter(b => b.assetId === currentAssetId.toLowerCase())[0]
434           }
435           if (this.$route.query.to != undefined) {
436               this.transaction.to = this.$route.query.to
437           }
438           if (this.$route.query.amount != undefined) {
439               this.transaction.amount = this.$route.query.amount
440           }
441           if (this.$route.query.gas != undefined) {
442               this.transaction.fee = this.$route.query.gas
443           }
444           if(this.$route.query.confirmations != undefined) {
445               this.transaction.confirmations = this.$route.query.confirmations
446           }
447         }else{
448           this.account = this.currentAccount
449
450           const currentAsset = this.currentAsset || this.selectAsset
451           currentAssetId = currentAsset.assetId
452
453         }
454
455         const that = this
456
457         transaction.asset(currentAssetId).then(ret => {
458             that.selectAsset = ret
459             if(that.transaction.amount){
460               that.transaction.cost = Number(ret[currencyInPrice[that.currency]] * that.transaction.amount).toFixed(2);
461             }
462           });
463
464     }
465 };
466 </script>