From b6eb1e132f374a8355436f17284dbe30fcf72c1d Mon Sep 17 00:00:00 2001 From: Gabriel Masclef Date: Wed, 20 Dec 2017 11:12:22 -0300 Subject: [PATCH 1/2] Feat: Mercado Libre 1 --- src/app/app.module.ts | 28 +- src/assets/img/mercado-libre/24px.svg | 24 + src/assets/img/mercado-libre/giftcard-pt.svg | 2311 +++++++++++++++++ .../img/mercado-libre/meli-card-24px.png | Bin 0 -> 1393 bytes src/assets/img/mercado-libre/mlbr.svg | 166 ++ src/pages/home/home.ts | 13 +- src/pages/integrations/amazon/amazon.scss | 88 +- .../buy-mercado-libre/buy-mercado-libre.html | 84 + .../buy-mercado-libre/buy-mercado-libre.scss | 36 + .../buy-mercado-libre/buy-mercado-libre.ts | 419 +++ .../mercado-libre-card-details.html | 18 + .../mercado-libre-card-details.scss | 3 + .../mercado-libre-card-details.ts | 35 + .../mercado-libre-cards.html | 40 + .../mercado-libre-cards.scss | 13 + .../mercado-libre-cards.ts | 128 + .../mercado-libre/mercado-libre.html | 53 + .../mercado-libre/mercado-libre.scss | 51 + .../mercado-libre/mercado-libre.ts | 68 + src/pages/send/amount/amount.ts | 5 + src/providers/mercado-libre/mercado-libre.ts | 32 +- 21 files changed, 3543 insertions(+), 72 deletions(-) create mode 100644 src/assets/img/mercado-libre/24px.svg create mode 100644 src/assets/img/mercado-libre/giftcard-pt.svg create mode 100644 src/assets/img/mercado-libre/meli-card-24px.png create mode 100644 src/assets/img/mercado-libre/mlbr.svg create mode 100644 src/pages/integrations/mercado-libre/buy-mercado-libre/buy-mercado-libre.html create mode 100644 src/pages/integrations/mercado-libre/buy-mercado-libre/buy-mercado-libre.scss create mode 100644 src/pages/integrations/mercado-libre/buy-mercado-libre/buy-mercado-libre.ts create mode 100644 src/pages/integrations/mercado-libre/mercado-libre-card-details/mercado-libre-card-details.html create mode 100644 src/pages/integrations/mercado-libre/mercado-libre-card-details/mercado-libre-card-details.scss create mode 100644 src/pages/integrations/mercado-libre/mercado-libre-card-details/mercado-libre-card-details.ts create mode 100644 src/pages/integrations/mercado-libre/mercado-libre-cards/mercado-libre-cards.html create mode 100644 src/pages/integrations/mercado-libre/mercado-libre-cards/mercado-libre-cards.scss create mode 100644 src/pages/integrations/mercado-libre/mercado-libre-cards/mercado-libre-cards.ts create mode 100644 src/pages/integrations/mercado-libre/mercado-libre.html create mode 100644 src/pages/integrations/mercado-libre/mercado-libre.scss create mode 100644 src/pages/integrations/mercado-libre/mercado-libre.ts diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 344cb29c3..80f53a8a3 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -29,32 +29,42 @@ import { CopayApp } from './app.component'; /* Pages */ import { TabsPage } from '../pages/tabs/tabs'; import { AddPage } from '../pages/add/add'; -import { AmazonCardDetailsPage } from '../pages/integrations/amazon/amazon-card-details/amazon-card-details'; -import { AmazonCardsPage } from '../pages/integrations/amazon/amazon-cards/amazon-cards'; -import { AmazonPage } from '../pages/integrations/amazon/amazon'; + + import { BackupRequestPage } from '../pages/onboarding/backup-request/backup-request'; import { BackupWarningPage } from '../pages/backup/backup-warning/backup-warning'; import { BackupGamePage } from '../pages/backup/backup-game/backup-game'; -import { BuyAmazonPage } from '../pages/integrations/amazon/buy-amazon/buy-amazon'; import { BuyAndSellPage } from '../pages/buy-and-sell/buy-and-sell'; -import { BuyGlideraPage } from '../pages/integrations/glidera/buy-glidera/buy-glidera'; + import { CreateWalletPage } from '../pages/add/create-wallet/create-wallet'; import { CopayersPage } from '../pages/add/copayers/copayers'; import { DisclaimerPage } from '../pages/onboarding/disclaimer/disclaimer'; import { EmailPage } from '../pages/onboarding/email/email'; import { FeeWarningPage } from '../pages/send/fee-warning/fee-warning'; -import { GlideraPage } from '../pages/integrations/glidera/glidera'; import { IncomingDataMenuPage } from '../pages/incoming-data-menu/incoming-data-menu'; import { ImportWalletPage } from '../pages/add/import-wallet/import-wallet'; import { JoinWalletPage } from '../pages/add/join-wallet/join-wallet'; import { OnboardingPage } from '../pages/onboarding/onboarding'; import { PaperWalletPage } from '../pages/paper-wallet/paper-wallet'; import { PayProPage } from '../pages/paypro/paypro'; -import { SellGlideraPage } from '../pages/integrations/glidera/sell-glidera/sell-glidera'; import { TourPage } from '../pages/onboarding/tour/tour'; import { WalletDetailsPage } from '../pages/wallet-details/wallet-details'; import { TxDetailsPage } from '../pages/tx-details/tx-details'; import { TxpDetailsPage } from '../pages/txp-details/txp-details'; +// Integrations: Amazon +import { AmazonCardDetailsPage } from '../pages/integrations/amazon/amazon-card-details/amazon-card-details'; +import { AmazonCardsPage } from '../pages/integrations/amazon/amazon-cards/amazon-cards'; +import { AmazonPage } from '../pages/integrations/amazon/amazon'; +import { BuyAmazonPage } from '../pages/integrations/amazon/buy-amazon/buy-amazon'; +// Integrations: Glidera +import { BuyGlideraPage } from '../pages/integrations/glidera/buy-glidera/buy-glidera'; +import { GlideraPage } from '../pages/integrations/glidera/glidera'; +import { SellGlideraPage } from '../pages/integrations/glidera/sell-glidera/sell-glidera'; +// Integrations: Mercado Libre +import { BuyMercadoLibrePage } from '../pages/integrations/mercado-libre/buy-mercado-libre/buy-mercado-libre'; +import { MercadoLibreCardDetailsPage } from '../pages/integrations/mercado-libre/mercado-libre-card-details/mercado-libre-card-details'; +import { MercadoLibreCardsPage } from '../pages/integrations/mercado-libre/mercado-libre-cards/mercado-libre-cards'; +import { MercadoLibrePage } from '../pages/integrations/mercado-libre/mercado-libre'; /*Includes */ import { WalletInfoPage } from '../pages/includes/wallet-info/wallet-info'; @@ -184,6 +194,7 @@ let pages: any = [ BuyAmazonPage, BuyAndSellPage, BuyGlideraPage, + BuyMercadoLibrePage, ChooseFeeLevelPage, CreateWalletPage, CopayersPage, @@ -211,6 +222,7 @@ let pages: any = [ HomePage, LanguagePage, LockPage, + MercadoLibrePage, OnboardingPage, PaperWalletPage, PayProPage, @@ -222,6 +234,8 @@ let pages: any = [ ScanPage, SettingsPage, TermsOfUsePage, + MercadoLibreCardDetailsPage, + MercadoLibreCardsPage, NotificationsPage, FeePolicyPage, SessionLogPage, diff --git a/src/assets/img/mercado-libre/24px.svg b/src/assets/img/mercado-libre/24px.svg new file mode 100644 index 000000000..7a667609c --- /dev/null +++ b/src/assets/img/mercado-libre/24px.svg @@ -0,0 +1,24 @@ + + + + 24px + Created with Sketch. + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/assets/img/mercado-libre/giftcard-pt.svg b/src/assets/img/mercado-libre/giftcard-pt.svg new file mode 100644 index 000000000..f980b61f6 --- /dev/null +++ b/src/assets/img/mercado-libre/giftcard-pt.svg @@ -0,0 +1,2311 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/assets/img/mercado-libre/meli-card-24px.png b/src/assets/img/mercado-libre/meli-card-24px.png new file mode 100644 index 0000000000000000000000000000000000000000..2e42ef103feb6ca9dc4b3b02bc6e031ad3b4b9f4 GIT binary patch literal 1393 zcmeAS@N?(olHy`uVBq!ia0vp^sz5Bk!3HF2t4s=?Nk^)#sNw%$0gl~X?bAC~( zf~lUVo`I4bmx4`EN}5%WiyKrkkY}ruQBqQ1rLSLJUanVete0Puu5V~*X{m2uq;F)T z3sj+7T$xvrSfQI&tPC;&VunjnD>p{1Fbu92Q01B1rI(uwD_T>?dp z+Z#J8yS22Y7-mNB{+xKwO_I|zQ)=;_TW9wCT>9+z>%B8gZff1u^vd}Y^+9|?=ru1v zO-<|Uq~>{_&s_0%cITY!{NH=O&v|DnzUJVPNtaevDNa3?)#$mtxGwQxX8j>QX&Gw;6#Uc8sTamL48x7URJyt6+{yz>=TL{^KtXy|D!f6m`wn^&ETKBViVBqC@h zSe9Mn_)t2SU;O9IClwRzeXlh&7H%-(vVOeZ;!pR~mT5xMra$&lE%th8_sm=7;+H#X zj_`dfD`E0^bo8W&aL?m~{em-XOD_BOuURqS{_n~5&Td7bGebXRtPxOm6x+VSa;4l< z31M3;WzTzW{@>sCYGdQSq|$crRr0)#w+g?R{UOw#r=R)o4=a}2%yX8X{yDQ&qE2{k zz_pm_3mf>Bi>K=D;Z2vmP_@2o%Z2_F;qAwgJ{0kM<-SnEy4CyWys6(TcQrqlRdZGK z%^RobbMhnpv7IW(5T2JklO#{N9;`YMn0y?i@MdBeLe3YQ#d3sFJ{g`xk`#X4h!a6XA;8Rjim>-dZxXe!;{f z$LUd9rzl<0^I4PItG`4gE!ihZee%iEdt+_9)Fz+V^0BOE|JkRO&;RJf?|44vx!cPf z-#-dg*{o^{R$Jt*cfT#|L)nzR=mYC=BX6^_PEWqgnzi5Sqn~ij(mT%DiHQbKXYAjX@GSP1d&Q?xt@{(|r`-wm zkxhU3+sw(8^_2LJ$1=srielx#`%YYVzU1_s%El!^MSJrNEsi~5ytLFO;B57(&jKff zil1Lk_H4axzu>iKn*TcHgYy@wd@hka$8tqV%l^PAkxRWFpU&?rx>9%ZP2^0jecK#E z*SE91*DzK2*VZGI@Hn<)uT)KLbJV;i_m)r5543T(vavLF%HkhJ&eM1Nm)sgXbKxQr z-^;qj!h(g32fGtbEmEJgUv+Kk%01OROT^6T)K+{vwrpkae~zQmXV|*Fb-xr^vLS!o zY+H{*J1u|+x?pb|J;`fKVfsyTRbb?*t2!Fx<>!S-+mE2ch?90o%YgPLgMMq*&%w9^@DH7 zzT5Xp_rLzts$UB47XHq-apmgkkp0o;OXU`QR?xm2vX4u=ylm@?ePLPe=cjkSyzTfm sf8o2gCN9llNi`kEFD>kMG`9H5@LlR?nMt&{5U8Z|boFyt=akR{0MZ$100000 literal 0 HcmV?d00001 diff --git a/src/assets/img/mercado-libre/mlbr.svg b/src/assets/img/mercado-libre/mlbr.svg new file mode 100644 index 000000000..031c72393 --- /dev/null +++ b/src/assets/img/mercado-libre/mlbr.svg @@ -0,0 +1,166 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/pages/home/home.ts b/src/pages/home/home.ts index 54a7189f8..1c8a3861e 100644 --- a/src/pages/home/home.ts +++ b/src/pages/home/home.ts @@ -3,16 +3,17 @@ import { NavController, Events, ModalController } from 'ionic-angular'; import { Logger } from '@nsalaun/ng-logger'; // Pages +import { ActivityPage } from './activity/activity'; import { AddPage } from "../add/add"; import { AmazonPage } from '../integrations/amazon/amazon'; +import { BuyAndSellPage } from '../buy-and-sell/buy-and-sell'; import { CopayersPage } from '../add/copayers/copayers'; -import { WalletDetailsPage } from '../wallet-details/wallet-details'; +import { GlideraPage } from '../integrations/glidera/glidera'; +import { MercadoLibrePage } from '../integrations/mercado-libre/mercado-libre'; +import { ProposalsPage } from './proposals/proposals'; import { TxDetailsPage } from '../tx-details/tx-details'; import { TxpDetailsPage } from '../txp-details/txp-details'; -import { ProposalsPage } from './proposals/proposals'; -import { ActivityPage } from './activity/activity'; -import { BuyAndSellPage } from '../buy-and-sell/buy-and-sell'; -import { GlideraPage } from '../integrations/glidera/glidera'; +import { WalletDetailsPage } from '../wallet-details/wallet-details'; // Providers import { BwcErrorProvider } from '../../providers/bwc-error/bwc-error'; @@ -300,7 +301,7 @@ export class HomePage { public goTo(page): void { switch (page) { case 'MercadoLibrePage': - //push MercadolibrePage + this.navCtrl.push(MercadoLibrePage); break; case 'AmazonPage': this.navCtrl.push(AmazonPage); diff --git a/src/pages/integrations/amazon/amazon.scss b/src/pages/integrations/amazon/amazon.scss index a1d1a5f7a..b4d6e40df 100644 --- a/src/pages/integrations/amazon/amazon.scss +++ b/src/pages/integrations/amazon/amazon.scss @@ -1,51 +1,51 @@ page-amazon { .integration-onboarding { - height: 100%; - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - text-align: center; - &-logo { - display: inline-block; - margin-bottom: 1em; - img { - max-width: 170px; - } - } - &-description { - margin-top: 0; - margin-left: 2rem; - margin-right: 2rem; - margin-bottom: 130px; - opacity: .6; - max-width: 300px; - } - &-cta { - position: absolute; - bottom: 5vh; - width: 100%; - button { - width: 85%; - max-width: 300px; - margin-left: auto; - margin-right: auto; - display: block; - } - } -} -.integration-giftCard { - &-logo { - width: 100%; - display: inline-block; - margin: 1em auto; + height: 100%; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; text-align: center; - img { - max-width: 200px; + &-logo { + display: inline-block; + margin-bottom: 1em; + img { + max-width: 170px; + } + } + &-description { + margin-top: 0; + margin-left: 2rem; + margin-right: 2rem; + margin-bottom: 130px; + opacity: .6; + max-width: 300px; + } + &-cta { + position: absolute; + bottom: 5vh; + width: 100%; + button { + width: 85%; + max-width: 300px; + margin-left: auto; + margin-right: auto; + display: block; + } } } - &-info { - padding: 1rem; + .integration-giftCard { + &-logo { + width: 100%; + display: inline-block; + margin: 1em auto; + text-align: center; + img { + max-width: 200px; + } + } + &-info { + padding: 1rem; + } } } -} diff --git a/src/pages/integrations/mercado-libre/buy-mercado-libre/buy-mercado-libre.html b/src/pages/integrations/mercado-libre/buy-mercado-libre/buy-mercado-libre.html new file mode 100644 index 000000000..57c08e087 --- /dev/null +++ b/src/pages/integrations/mercado-libre/buy-mercado-libre/buy-mercado-libre.html @@ -0,0 +1,84 @@ + + + + Buy + + + + + + + +
+ + Vale-Presente do Mercado Livre Brasil +
+
+
{{amountUnitStr}}
+
+ {{limitPerDayMessage}} +
+
+
+ + + +
+ + Details + + + Gift Card + + {{amount | currency:'$ ':2}} {{currencyIsoCode}} + + + + Network Cost + + {{invoiceFee | currency:'$ ':2}} {{currencyIsoCode}} + + + + Miner Fee + + {{networkFee | currency:'$ ':2}} {{currencyIsoCode}} + + + + Total + + {{totalAmount | currency:'$ ':2}} {{currencyIsoCode}} + ({{totalAmountStr}}) + + +
+
+
+
+ + + + + + + + Sua compra não pôde ser concluída + + + Sua compra foi adicionada à lista de pendentes + + + Comprou {{mlGiftCard.amount}} {{mlGiftCard.currency}} + +
+ Vale-Presente gerado e pronto para usar +
+ +
\ No newline at end of file diff --git a/src/pages/integrations/mercado-libre/buy-mercado-libre/buy-mercado-libre.scss b/src/pages/integrations/mercado-libre/buy-mercado-libre/buy-mercado-libre.scss new file mode 100644 index 000000000..4eca4a17d --- /dev/null +++ b/src/pages/integrations/mercado-libre/buy-mercado-libre/buy-mercado-libre.scss @@ -0,0 +1,36 @@ +page-buy-mercado-libre { + .mercado-libre-title { + display: flex; + align-items: center; + margin-bottom: 2rem; + img { + width: 3.5rem; + margin-right: 1.5rem; + box-shadow: 0px 6px 12px 0px rgba(0, 0, 0, 0.3); + } + } + .amount-label { + margin-bottom: 5rem; + .amount { + font-size: 38px; + margin-bottom: .5rem; + } + .alternative { + font-size: 12px; + color: #9B9B9B; + } + } + .wallets-list { + .wallet { + display: flex; + align-items: center; + margin-top: 1rem; + img { + width: 2.3rem; + margin-right: 1.5rem; + border-radius: 0.3rem; + background-color: color($colors, primary); + } + } + } +} diff --git a/src/pages/integrations/mercado-libre/buy-mercado-libre/buy-mercado-libre.ts b/src/pages/integrations/mercado-libre/buy-mercado-libre/buy-mercado-libre.ts new file mode 100644 index 000000000..6ba2ac749 --- /dev/null +++ b/src/pages/integrations/mercado-libre/buy-mercado-libre/buy-mercado-libre.ts @@ -0,0 +1,419 @@ +import { Component } from '@angular/core'; +import { NavController, NavParams, ActionSheetController } from 'ionic-angular'; +import { Logger } from '@nsalaun/ng-logger'; +import * as _ from 'lodash'; +import * as moment from 'moment'; + +// Pages +import { MercadoLibreCardsPage } from '../../../../pages/integrations/mercado-libre/mercado-libre-cards/mercado-libre-cards'; + +// Provider +import { MercadoLibreProvider } from '../../../../providers/mercado-libre/mercado-libre'; +import { BwcErrorProvider } from '../../../../providers/bwc-error/bwc-error'; +import { ConfigProvider } from '../../../../providers/config/config'; +import { EmailNotificationsProvider } from '../../../../providers/email-notifications/email-notifications'; +import { ExternalLinkProvider } from '../../../../providers/external-link/external-link'; +import { OnGoingProcessProvider } from "../../../../providers/on-going-process/on-going-process"; +import { PopupProvider } from '../../../../providers/popup/popup'; +import { ProfileProvider } from '../../../../providers/profile/profile'; +import { TxFormatProvider } from '../../../../providers/tx-format/tx-format'; +import { WalletProvider } from '../../../../providers/wallet/wallet'; + +@Component({ + selector: 'page-buy-mercado-libre', + templateUrl: 'buy-mercado-libre.html', +}) +export class BuyMercadoLibrePage { + + private coin: string; + private amount: number; + private currency: string; + private createdTx: any; + private message: string; + private invoiceId: string; + private configWallet: any; + private currencyIsoCode: string; + private FEE_TOO_HIGH_LIMIT_PER: number; + + public wallet: any; + public wallets: any; + public totalAmountStr: string; + public invoiceFee: number; + public networkFee: number; + public totalAmount: number; + public sendStatus: string; + public mlGiftCard: any; + public amountUnitStr: string; + public limitPerDayMessage: string; + public network: string; + public walletSelectorTitle: string; + + constructor( + private actionSheetCtrl: ActionSheetController, + private mercadoLibreProvider: MercadoLibreProvider, + private bwcErrorProvider: BwcErrorProvider, + private configProvider: ConfigProvider, + private emailNotificationsProvider: EmailNotificationsProvider, + private externalLinkProvider: ExternalLinkProvider, + private logger: Logger, + private navCtrl: NavController, + private navParams: NavParams, + private onGoingProcessProvider: OnGoingProcessProvider, + private popupProvider: PopupProvider, + private profileProvider: ProfileProvider, + private txFormatProvider: TxFormatProvider, + private walletProvider: WalletProvider + ) { + this.FEE_TOO_HIGH_LIMIT_PER = 15; + this.coin = 'btc'; + this.configWallet = this.configProvider.get().wallet; + this.mlGiftCard = null; + } + + ionViewDidLoad() { + this.logger.info('ionViewDidLoad BuyMercadoLibrePage'); + } + + ionViewWillEnter() { + this.amount = this.navParams.data.amountFiat; + this.currency = this.navParams.data.currency.toUpperCase(); + + if (this.amount > 2000 || this.amount < 50) { + this.showErrorAndBack(null, 'Purchase amount must be a value between 50 and 2000'); // TODO: gettextCatalog + return; + } + + this.network = this.mercadoLibreProvider.getNetwork(); + this.wallets = this.profileProvider.getWallets({ + onlyComplete: true, + network: this.network, + coin: this.coin + }); + if (_.isEmpty(this.wallets)) { + this.showErrorAndBack(null, 'No wallets available'); // TODO: gettextCatalog + return; + } + this.onWalletSelect(this.wallets[0]); // Default first wallet + } + + public openExternalLink(url: string) { + this.externalLinkProvider.open(url); + } + + private _resetValues() { + this.totalAmountStr = this.amount = this.invoiceFee = this.networkFee = this.totalAmount = this.wallet = null; + this.createdTx = this.message = this.invoiceId = null; + } + + private showErrorAndBack(title: string, msg: any) { + title = title ? title : 'Error'; // TODO: gettextCatalog + this.sendStatus = ''; + this.logger.error(msg); + msg = (msg && msg.errors) ? msg.errors[0].message : msg; + this.popupProvider.ionicAlert(title, msg).then(() => { + this.navCtrl.pop(); + }); + } + + private showError = function (title: string, msg: any): Promise { + return new Promise((resolve, reject) => { + title = title || 'Error'; // TODO: gettextCatalog + this.sendStatus = ''; + this.logger.error(msg); + msg = (msg && msg.errors) ? msg.errors[0].message : msg; + this.popupProvider.ionicAlert(title, msg).then(() => { + return resolve(); + }); + }); + } + + private publishAndSign(wallet, txp, onSendStatusChange): Promise { + return new Promise((resolve, reject) => { + if (!wallet.canSign() && !wallet.isPrivKeyExternal()) { + let err = 'No signing proposal: No private key'; // TODO: gettextCatalog + this.logger.info(err); + return reject(err); + } + + this.walletProvider.publishAndSign(wallet, txp, onSendStatusChange).then((txp: any) => { + return resolve(txp); + }).catch((err: any) => { + return reject(err); + }); + }); + } + + private statusChangeHandler(processName: string, showName: string, isOn: boolean) { + this.logger.debug('statusChangeHandler: ', processName, showName, isOn); + if (processName == 'buyingGiftCard' && !isOn) { + this.sendStatus = 'success'; + } else if (showName) { + this.sendStatus = showName; + } + } + + private satToFiat(sat: number): Promise { + return new Promise((resolve, reject) => { + this.txFormatProvider.toFiat(this.coin, sat, this.currencyIsoCode).then((value: string) => { + return resolve(value); + }); + }); + } + + private setTotalAmount(amountSat: number, invoiceFeeSat: number, networkFeeSat: number) { + this.satToFiat(amountSat).then((a: string) => { + this.amount = Number(a); + + this.satToFiat(invoiceFeeSat).then((i: string) => { + this.invoiceFee = Number(i); + + this.satToFiat(networkFeeSat).then((n: string) => { + this.networkFee = Number(n); + this.totalAmount = this.amount + this.invoiceFee + this.networkFee; + }); + }); + }); + } + + private createInvoice(data: any): Promise { + return new Promise((resolve, reject) => { + this.mercadoLibreProvider.createBitPayInvoice(data, (err: any, dataInvoice: any) => { + if (err) { + let err_title = 'Error creating the invoice'; // TODO: gettextCatalog + let err_msg; + if (err && err.message && err.message.match(/suspended/i)) { + err_title = 'Service not available'; // TODO: gettextCatalog + err_msg = 'Mercadolibre Gift Card Service is not available at this moment. Please try back later.'; // TODO: gettextCatalog + } else if (err && err.message) { + err_msg = err.message; + } else { + err_msg = 'Could not access Gift Card Service'; // TODO: gettextCatalog + }; + + return reject({ + title: err_title, + message: err_msg + }); + } + + let accessKey = dataInvoice ? dataInvoice.accessKey : null; + + if (!accessKey) { + return reject({ + message: 'No access key defined' // TODO: gettextCatalog + }); + } + + this.mercadoLibreProvider.getBitPayInvoice(dataInvoice.invoiceId, (err: any, invoice: any) => { + if (err) { + return reject({ + message: 'Could not get the invoice' // TODO: gettextCatalog + }); + } + + return resolve({ invoice: invoice, accessKey: accessKey }); + }); + }); + }); + } + + private createTx(wallet, invoice, message): Promise { + return new Promise((resolve, reject) => { + let payProUrl = (invoice && invoice.paymentUrls) ? invoice.paymentUrls.BIP73 : null; + + if (!payProUrl) { + return reject({ + title: 'Error in Payment Protocol', // TODO: gettextCatalog + message: 'Invalid URL' // TODO: gettextCatalog + }); + } + + let outputs = []; + let toAddress = invoice.bitcoinAddress; + let amountSat = parseInt((invoice.btcDue * 100000000).toFixed(0)); // BTC to Satoshi + + outputs.push({ + 'toAddress': toAddress, + 'amount': amountSat, + 'message': message + }); + + let txp = { + toAddress: toAddress, + amount: amountSat, + outputs: outputs, + message: message, + payProUrl: payProUrl, + excludeUnconfirmedUtxos: this.configWallet.spendUnconfirmed ? false : true, + feeLevel: this.configWallet.settings.feeLevel ? this.configWallet.settings.feeLevel : 'normal' + }; + + this.walletProvider.createTx(wallet, txp).then((ctxp: any) => { + return resolve(ctxp); + }).catch((err: any) => { + return reject({ + title: 'Could not create transaction', // TODO: gettextCatalog + message: this.bwcErrorProvider.msg(err) + }); + }); + }); + } + + private checkTransaction = _.throttle((count: number, dataSrc: any) => { + this.mercadoLibreProvider.createGiftCard(dataSrc, (err, giftCard) => { + this.logger.debug("creating gift card " + count); + if (err) { + this.sendStatus = ''; + this.onGoingProcessProvider.set('Comprando Vale-Presente', false, this.statusChangeHandler); + giftCard = {}; + giftCard.status = 'FAILURE'; + } + + if (giftCard && giftCard.cardStatus && (giftCard.cardStatus != 'active' && giftCard.cardStatus != 'inactive' && giftCard.cardStatus != 'expired')) { + this.sendStatus = ''; + this.onGoingProcessProvider.set('Comprando Vale-Presente', false, this.statusChangeHandler); + giftCard = {}; + giftCard.status = 'FAILURE'; + } + + if (giftCard.status == 'PENDING' && count < 3) { + this.logger.debug("Waiting for payment confirmation"); + this.checkTransaction(count + 1, dataSrc); + return; + } + + var now = moment().unix() * 1000; + + var newData = giftCard; + newData.invoiceId = dataSrc.invoiceId; + newData.accessKey = dataSrc.accessKey; + newData.invoiceUrl = dataSrc.invoiceUrl; + newData.amount = dataSrc.amount; + newData.date = dataSrc.invoiceTime || now; + newData.uuid = dataSrc.uuid; + + this.mercadoLibreProvider.savePendingGiftCard(newData, null, (err: any) => { + this.onGoingProcessProvider.set('Comprando Vale-Presente', false, this.statusChangeHandler); + this.logger.debug("Saving new gift card with status: " + newData.status); + this.mlGiftCard = newData; + }); + }); + }, 8000, { + 'leading': true + }); + + private initialize(wallet: any): void { + let email = this.emailNotificationsProvider.getEmailIfEnabled(); + let parsedAmount = this.txFormatProvider.parseAmount(this.coin, this.amount, this.currency); + this.currencyIsoCode = parsedAmount.currency; + this.amountUnitStr = parsedAmount.amountUnitStr; + let dataSrc = { + amount: parsedAmount.amount, + currency: parsedAmount.currency, + uuid: wallet.id, + email: email + }; + this.onGoingProcessProvider.set('loadingTxInfo', true); + this.createInvoice(dataSrc).then((data: any) => { + let invoice = data.invoice; + let accessKey = data.accessKey; + + // Sometimes API does not return this element; + invoice['buyerPaidBtcMinerFee'] = invoice.buyerPaidBtcMinerFee || 0; + let invoiceFeeSat = parseInt((invoice.buyerPaidBtcMinerFee * 100000000).toFixed()); + + this.message = this.amountUnitStr + " for Mercado Livre Brazil Gift Car"; // TODO: gettextCatalog + + this.createTx(wallet, invoice, this.message).then((ctxp: any) => { + this.onGoingProcessProvider.set('loadingTxInfo', false); + + + // Save in memory + this.createdTx = ctxp; + this.invoiceId = invoice.id; + + this.createdTx.giftData = { + currency: dataSrc.currency, + amount: dataSrc.amount, + uuid: dataSrc.uuid, + accessKey: accessKey, + invoiceId: invoice.id, + invoiceUrl: invoice.url, + invoiceTime: invoice.invoiceTime + }; + this.totalAmountStr = this.txFormatProvider.formatAmountStr(this.coin, ctxp.amount); + this.setTotalAmount(parsedAmount.amountSat, invoiceFeeSat, ctxp.fee); + }).catch((err: any) => { + this.onGoingProcessProvider.set('loadingTxInfo', false); + this._resetValues(); + this.showError(err.title, err.message); + return; + }); + }).catch((err: any) => { + this.onGoingProcessProvider.set('loadingTxInfo', false); + this.showErrorAndBack(err.title, err.message); + return; + }); + } + + public buyConfirm() { + if (!this.createdTx) { + this.showError(null, 'Transaction has not been created'); // TODO: gettextCatalog + return; + } + var title = 'Confirm'; // TODO: gettextCatalog + var okText = 'OK'; // TODO: gettextCatalog + var cancelText = 'Cancel'; // TODO: gettextCatalog + this.popupProvider.ionicConfirm(title, this.message, okText, cancelText).then((ok) => { + if (!ok) { + this.sendStatus = ''; + return; + } + + this.publishAndSign(this.wallet, this.createdTx, function () { }).then((txSent) => { + this.onGoingProcessProvider.set('Comprando Vale-Presente', true, this.statusChangeHandler); + this.checkTransaction(1, this.createdTx.giftData); + }).catch((err: any) => { + this._resetValues(); + this.showError('Could not send transaction', err); // TODO: gettextCatalog + return; + }); + }); + } + + public onWalletSelect(wallet: any): void { + this.wallet = wallet; + this.initialize(wallet); + } + + public goBackHome(): void { + this.sendStatus = ''; + this.navCtrl.remove(3, 1); + this.navCtrl.pop(); + this.navCtrl.push(MercadoLibreCardsPage, { invoiceId: this.invoiceId }); + } + + public showWallets(): void { + let buttons: Array = []; + + _.each(this.wallets, (w: any) => { + let walletButton: Object = { + text: w.credentials.walletName, + cssClass: 'wallet-' + w.network, + icon: 'wallet', + handler: () => { + this.onWalletSelect(w); + } + } + buttons.push(walletButton); + }); + + const actionSheet = this.actionSheetCtrl.create({ + title: 'Buy from', + buttons: buttons + }); + + actionSheet.present(); + } + +} diff --git a/src/pages/integrations/mercado-libre/mercado-libre-card-details/mercado-libre-card-details.html b/src/pages/integrations/mercado-libre/mercado-libre-card-details/mercado-libre-card-details.html new file mode 100644 index 000000000..6393c5a35 --- /dev/null +++ b/src/pages/integrations/mercado-libre/mercado-libre-card-details/mercado-libre-card-details.html @@ -0,0 +1,18 @@ + + + + + mercado-libre-card-details + + + + + + + + diff --git a/src/pages/integrations/mercado-libre/mercado-libre-card-details/mercado-libre-card-details.scss b/src/pages/integrations/mercado-libre/mercado-libre-card-details/mercado-libre-card-details.scss new file mode 100644 index 000000000..6a122a11f --- /dev/null +++ b/src/pages/integrations/mercado-libre/mercado-libre-card-details/mercado-libre-card-details.scss @@ -0,0 +1,3 @@ +page-mercado-libre-card-details { + +} diff --git a/src/pages/integrations/mercado-libre/mercado-libre-card-details/mercado-libre-card-details.ts b/src/pages/integrations/mercado-libre/mercado-libre-card-details/mercado-libre-card-details.ts new file mode 100644 index 000000000..86c24df78 --- /dev/null +++ b/src/pages/integrations/mercado-libre/mercado-libre-card-details/mercado-libre-card-details.ts @@ -0,0 +1,35 @@ +import { Component } from '@angular/core'; +import { NavParams, ViewController } from 'ionic-angular'; +import { Logger } from '@nsalaun/ng-logger'; +import * as _ from 'lodash'; + +// Provider +import { MercadoLibreProvider } from '../../../../providers/mercado-libre/mercado-libre'; +import { BwcErrorProvider } from '../../../../providers/bwc-error/bwc-error'; +import { ExternalLinkProvider } from '../../../../providers/external-link/external-link'; +import { OnGoingProcessProvider } from "../../../../providers/on-going-process/on-going-process"; +import { PopupProvider } from '../../../../providers/popup/popup'; + +@Component({ + selector: 'page-mercado-libre-card-details', + templateUrl: 'mercado-libre-card-details.html', +}) +export class MercadoLibreCardDetailsPage { + + constructor( + private mercadoLibreProvider: MercadoLibreProvider, + private bwcErrorProvider: BwcErrorProvider, + private logger: Logger, + private externalLinkProvider: ExternalLinkProvider, + private navParams: NavParams, + private onGoingProcessProvider: OnGoingProcessProvider, + private popupProvider: PopupProvider, + private viewCtrl: ViewController + ) { + } + + ionViewDidLoad() { + this.logger.info('ionViewDidLoad MercadoLibreCardDetailsPage'); + } + +} diff --git a/src/pages/integrations/mercado-libre/mercado-libre-cards/mercado-libre-cards.html b/src/pages/integrations/mercado-libre/mercado-libre-cards/mercado-libre-cards.html new file mode 100644 index 000000000..76b5b3b14 --- /dev/null +++ b/src/pages/integrations/mercado-libre/mercado-libre-cards/mercado-libre-cards.html @@ -0,0 +1,40 @@ + + + + {{'Your Gift Cards'|translate}} + + + + + + + + + + + + \ No newline at end of file diff --git a/src/pages/integrations/mercado-libre/mercado-libre-cards/mercado-libre-cards.scss b/src/pages/integrations/mercado-libre/mercado-libre-cards/mercado-libre-cards.scss new file mode 100644 index 000000000..ab4d11a01 --- /dev/null +++ b/src/pages/integrations/mercado-libre/mercado-libre-cards/mercado-libre-cards.scss @@ -0,0 +1,13 @@ +page-mercado-libre-cards { + .mercado-libre-card { + display: flex; + align-items: center; + .avatar { + width: 40px; + border-radius: 5rem; + } + .card-info { + padding-left: 1rem; + } + } +} diff --git a/src/pages/integrations/mercado-libre/mercado-libre-cards/mercado-libre-cards.ts b/src/pages/integrations/mercado-libre/mercado-libre-cards/mercado-libre-cards.ts new file mode 100644 index 000000000..2a444cca8 --- /dev/null +++ b/src/pages/integrations/mercado-libre/mercado-libre-cards/mercado-libre-cards.ts @@ -0,0 +1,128 @@ +import { Component } from '@angular/core'; +import { NavParams, ModalController } from 'ionic-angular'; +import { Logger } from '@nsalaun/ng-logger'; +import * as _ from 'lodash'; + +// Pages +import { MercadoLibreCardDetailsPage } from '../mercado-libre-card-details/mercado-libre-card-details'; + +// Provider +import { MercadoLibreProvider } from '../../../../providers/mercado-libre/mercado-libre'; +import { ExternalLinkProvider } from '../../../../providers/external-link/external-link'; +import { PopupProvider } from '../../../../providers/popup/popup'; + +@Component({ + selector: 'page-mercado-libre-cards', + templateUrl: 'mercado-libre-cards.html', +}) +export class MercadoLibreCardsPage { + + public giftCards: any; + public updatingPending: any; + public card: any; + public invoiceId; + + constructor( + private mercadoLibreProvider: MercadoLibreProvider, + private externalLinkProvider: ExternalLinkProvider, + private logger: Logger, + private modalCtrl: ModalController, + private navParams: NavParams, + private popupProvider: PopupProvider, + ) { + } + + ionViewDidLoad() { + this.logger.info('ionViewDidLoad MercadoLibreCardsPage'); + this.updatePendingGiftCards(); + } + + ionViewWillEnter() { + this.invoiceId = this.navParams.data.invoiceId; + this.updateGiftCards().then(() => { + if (this.invoiceId) { + let card = _.find(this.giftCards, { + invoiceId: this.invoiceId + }); + if (_.isEmpty(card)) { + this.popupProvider.ionicAlert(null, 'Card not found'); + return; + } + this.openCardModal(card); + } + }).catch((err: any) => { + this.logger.warn(err); + }); + } + + public openExternalLink(url: string): void { + this.externalLinkProvider.open(url); + } + + private updateGiftCards(): Promise { + return new Promise((resolve, reject) => { + this.mercadoLibreProvider.getPendingGiftCards((err: any, gcds: any) => { + if (err) { + this.popupProvider.ionicAlert('Could not get gift cards', err); + return reject(err); + } + this.giftCards = gcds; + return resolve(); + }); + }); + } + + public updatePendingGiftCards = _.debounce(() => { + this.updateGiftCards().then(() => { + let gcds = this.giftCards; + _.forEach(gcds, (dataFromStorage: any) => { + if (dataFromStorage.status == 'PENDING' || dataFromStorage.status == 'invalid') { + this.logger.debug("Creating / Updating gift card"); + + this.mercadoLibreProvider.createGiftCard(dataFromStorage, (err: any, giftCard: any) => { + + if (err) { + this.logger.error('Error creating gift card:', err); + giftCard = {}; + giftCard.status = 'FAILURE'; + } + + if (giftCard.status != 'PENDING') { + let newData: any = {}; + + if (!giftCard.status) dataFromStorage.status = null; // Fix error from server + + let cardStatus = giftCard.cardStatus; + if (cardStatus && (cardStatus != 'active' && cardStatus != 'inactive' && cardStatus != 'expired')) + giftCard.status = 'FAILURE'; + + _.merge(newData, dataFromStorage, giftCard); + + this.mercadoLibreProvider.savePendingGiftCard(newData, null, (err: any) => { + this.logger.debug("Saving new gift card"); + this.updateGiftCards(); + }); + } + }); + } + }); + }).catch((err: any) => { + this.logger.error(err); + }); + + }, 1000, { + 'leading': true + }); + + public openCardModal(card: any): void { + this.card = card; + + let modal = this.modalCtrl.create(MercadoLibreCardDetailsPage, { card: this.card }); + modal.present(); + + modal.onDidDismiss(() => { + this.updatePendingGiftCards(); + }) + } + +} diff --git a/src/pages/integrations/mercado-libre/mercado-libre.html b/src/pages/integrations/mercado-libre/mercado-libre.html new file mode 100644 index 000000000..313c99082 --- /dev/null +++ b/src/pages/integrations/mercado-libre/mercado-libre.html @@ -0,0 +1,53 @@ + + + + {{'Mercado Livre Brazil Gift Cards'|translate}}s + + + + + +
+ Sandbox version. Only for testing purpose. +
+
+ +
+ Only redeemable on Mercado Livre (Brazil) +
+
+ + + +
+
+
+ + +
+ Sandbox version. Only for testing purpose. +
+ + + + + + + + + + + +
\ No newline at end of file diff --git a/src/pages/integrations/mercado-libre/mercado-libre.scss b/src/pages/integrations/mercado-libre/mercado-libre.scss new file mode 100644 index 000000000..06101478d --- /dev/null +++ b/src/pages/integrations/mercado-libre/mercado-libre.scss @@ -0,0 +1,51 @@ +page-mercado-libre { + .integration-onboarding { + height: 100%; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + text-align: center; + &-logo { + display: inline-block; + margin-bottom: 1em; + img { + max-width: 170px; + } + } + &-description { + margin-top: 0; + margin-left: 2rem; + margin-right: 2rem; + margin-bottom: 130px; + opacity: .6; + max-width: 300px; + } + &-cta { + position: absolute; + bottom: 5vh; + width: 100%; + button { + width: 85%; + max-width: 300px; + margin-left: auto; + margin-right: auto; + display: block; + } + } + } + .integration-giftCard { + &-logo { + width: 100%; + display: inline-block; + margin: 1em auto; + text-align: center; + img { + max-width: 200px; + } + } + &-info { + padding: 1rem; + } + } +} diff --git a/src/pages/integrations/mercado-libre/mercado-libre.ts b/src/pages/integrations/mercado-libre/mercado-libre.ts new file mode 100644 index 000000000..8e6cc0a3d --- /dev/null +++ b/src/pages/integrations/mercado-libre/mercado-libre.ts @@ -0,0 +1,68 @@ +import { Component } from '@angular/core'; +import { NavController } from 'ionic-angular'; +import { Logger } from '@nsalaun/ng-logger'; + +// Pages +import { AmountPage } from '../../send/amount/amount'; +import { MercadoLibreCardsPage } from './mercado-libre-cards/mercado-libre-cards'; + +// Providers +import { MercadoLibreProvider } from '../../../providers/mercado-libre/mercado-libre'; +import { ExternalLinkProvider } from '../../../providers/external-link/external-link'; + +@Component({ + selector: 'page-mercado-libre', + templateUrl: 'mercado-libre.html', +}) +export class MercadoLibrePage { + + public giftCards: any; + public network: string; + + constructor( + private navCtrl: NavController, + private mercadoLibreProvider: MercadoLibreProvider, + private externalLinkProvider: ExternalLinkProvider, + private logger: Logger + ) { + } + + ionViewDidLoad() { + this.logger.info('ionViewDidLoad MercadoLibrePage'); + } + + ionViewWillEnter(): void { + this.network = this.mercadoLibreProvider.getNetwork(); + this.init(); + } + + public openExternalLink(url: string): void { + this.externalLinkProvider.open(url); + } + + private init(): void { + this.mercadoLibreProvider.getPendingGiftCards((err: any, gcds: any) => { + if (err) this.logger.error(err); + this.giftCards = gcds; + }); + } + + public goTo(page: string): void { + switch (page) { + case 'Amount': + this.navCtrl.push(AmountPage, { + nextPage: 'BuyMercadoLibrePage', + currency: 'BRL', + coin: 'btc', + fixedUnit: true, + }); + break; + case 'MercadoLibreCards': + this.navCtrl.push(MercadoLibreCardsPage, { + invoiceId: null + }); + break; + } + } + +} diff --git a/src/pages/send/amount/amount.ts b/src/pages/send/amount/amount.ts index 546cd2f2d..26e4826bf 100644 --- a/src/pages/send/amount/amount.ts +++ b/src/pages/send/amount/amount.ts @@ -14,6 +14,7 @@ import { BuyGlideraPage } from '../../integrations/glidera/buy-glidera/buy-glide import { SellGlideraPage } from '../../integrations/glidera/sell-glidera/sell-glidera'; import { ConfirmPage } from '../confirm/confirm'; import { CustomAmountPage } from '../../receive/custom-amount/custom-amount'; +import { BuyMercadoLibrePage } from '../../integrations/mercado-libre/buy-mercado-libre/buy-mercado-libre'; @Component({ selector: 'page-amount', @@ -133,6 +134,10 @@ export class AmountPage { case 'CustomAmountPage': nextPage = CustomAmountPage; break; + case 'BuyMercadoLibrePage': + this.showRecipient = false; + nextPage = BuyMercadoLibrePage; + break; default: nextPage = ConfirmPage; } diff --git a/src/providers/mercado-libre/mercado-libre.ts b/src/providers/mercado-libre/mercado-libre.ts index 4dd195f47..bb73ddabf 100644 --- a/src/providers/mercado-libre/mercado-libre.ts +++ b/src/providers/mercado-libre/mercado-libre.ts @@ -39,7 +39,7 @@ export class MercadoLibreProvider { */ this.credentials = {}; this.credentials.NETWORK = 'livenet'; - //credentials.NETWORK = 'testnet'; + //this.credentials.NETWORK = 'testnet'; if (this.credentials.NETWORK == 'testnet') { this.credentials.BITPAY_API_URL = "https://test.bitpay.com"; } else { @@ -114,10 +114,11 @@ export class MercadoLibreProvider { }; this.http.post(url, dataSrc, headers).subscribe((data: any) => { this.logger.info('BitPay Create Invoice: SUCCESS'); - return cb(null, data.data); + console.log("DATA-----------------1", data); + return cb(null, data); }, (data) => { - this.logger.error('BitPay Create Invoice: ERROR', JSON.stringify(data.data)); - return cb(data.data); + this.logger.error('BitPay Create Invoice: ERROR', JSON.stringify(data)); + return cb(data); }); } @@ -129,10 +130,11 @@ export class MercadoLibreProvider { this.http.get(url, headers).subscribe((data: any) => { this.logger.info('BitPay Get Invoice: SUCCESS'); - return cb(null, data.data.data); + console.log("DATA-----------------2", data); + return cb(null, data.data); }, (data) => { - this.logger.error('BitPay Get Invoice: ERROR', JSON.stringify(data.data)); - return cb(data.data); + this.logger.error('BitPay Get Invoice: ERROR', JSON.stringify(data)); + return cb(data); }); } @@ -149,13 +151,13 @@ export class MercadoLibreProvider { }; this.http.post(url, dataSrc, headers).subscribe((data: any) => { - var status = data.data.status == 'new' ? 'PENDING' : (data.data.status == 'paid') ? 'PENDING' : data.data.status; - data.data.status = status; + var status = data.status == 'new' ? 'PENDING' : (data.status == 'paid') ? 'PENDING' : data.status; + data.status = status; this.logger.info('Mercado Libre Gift Card Create/Update: ' + status); - return cb(null, data.data); + return cb(null, data); }, (data) => { - this.logger.error('Mercado Libre Gift Card Create/Update: ERROR', JSON.stringify(data.data)); - return cb(data.data); + this.logger.error('Mercado Libre Gift Card Create/Update: ERROR', JSON.stringify(data)); + return cb(data); }); } @@ -176,10 +178,10 @@ export class MercadoLibreProvider { }; this.http.post(url, dataSrc, headers).subscribe((data: any) => { this.logger.info('Mercado Libre Gift Card Cancel: SUCCESS'); - return cb(null, data.data); + return cb(null, data); }, (data) => { - this.logger.error('Mercado Libre Gift Card Cancel: ' + data.data.message); - return cb(data.data); + this.logger.error('Mercado Libre Gift Card Cancel: ' + data.message); + return cb(data); }); }; */ From 0fadbf01a2c4443c54393a0e44db41ebc9310d00 Mon Sep 17 00:00:00 2001 From: Gabriel Masclef Date: Wed, 20 Dec 2017 15:24:22 -0300 Subject: [PATCH 2/2] Mercado Libre 2, card details, fee warning and some fixes --- .../amazon-card-details.ts | 4 +- .../amazon/buy-amazon/buy-amazon.ts | 23 +++++- .../buy-mercado-libre/buy-mercado-libre.ts | 22 +++++- .../mercado-libre-card-details.html | 78 ++++++++++++++++--- .../mercado-libre-card-details.scss | 13 +++- .../mercado-libre-card-details.ts | 36 +++++++-- .../mercado-libre-cards.html | 6 -- .../mercado-libre-cards.ts | 1 - .../mercado-libre/mercado-libre.ts | 3 - src/pipes/satToUnit.ts | 1 - src/providers/amazon/amazon.ts | 4 +- src/providers/mercado-libre/mercado-libre.ts | 5 +- 12 files changed, 155 insertions(+), 41 deletions(-) diff --git a/src/pages/integrations/amazon/amazon-card-details/amazon-card-details.ts b/src/pages/integrations/amazon/amazon-card-details/amazon-card-details.ts index 62b509e42..48ed49a0c 100644 --- a/src/pages/integrations/amazon/amazon-card-details/amazon-card-details.ts +++ b/src/pages/integrations/amazon/amazon-card-details/amazon-card-details.ts @@ -96,11 +96,11 @@ export class AmazonCardDetailsPage { public cancel(): void { this.viewCtrl.dismiss(); - }; + } public openExternalLink(url: string): void { this.externalLinkProvider.open(url); - }; + } } diff --git a/src/pages/integrations/amazon/buy-amazon/buy-amazon.ts b/src/pages/integrations/amazon/buy-amazon/buy-amazon.ts index 45bc6635c..e398c7bf1 100644 --- a/src/pages/integrations/amazon/buy-amazon/buy-amazon.ts +++ b/src/pages/integrations/amazon/buy-amazon/buy-amazon.ts @@ -1,10 +1,11 @@ import { Component } from '@angular/core'; -import { NavController, NavParams, ActionSheetController } from 'ionic-angular'; +import { NavController, NavParams, ModalController, ActionSheetController } from 'ionic-angular'; import { Logger } from '@nsalaun/ng-logger'; import * as _ from 'lodash'; import * as moment from 'moment'; // Pages +import { FeeWarningPage } from '../../../../pages/send/fee-warning/fee-warning'; import { AmazonCardsPage } from '../../../../pages/integrations/amazon/amazon-cards/amazon-cards'; // Provider @@ -33,6 +34,7 @@ export class BuyAmazonPage { private invoiceId: string; private configWallet: any; private currencyIsoCode: string; + private FEE_TOO_HIGH_LIMIT_PER: number; public wallet: any; public wallets: any; @@ -55,6 +57,7 @@ export class BuyAmazonPage { private emailNotificationsProvider: EmailNotificationsProvider, private externalLinkProvider: ExternalLinkProvider, private logger: Logger, + private modalCtrl: ModalController, private navCtrl: NavController, private navParams: NavParams, private onGoingProcessProvider: OnGoingProcessProvider, @@ -63,6 +66,7 @@ export class BuyAmazonPage { private txFormatProvider: TxFormatProvider, private walletProvider: WalletProvider ) { + this.FEE_TOO_HIGH_LIMIT_PER = 15; this.coin = 'btc'; this.configWallet = this.configProvider.get().wallet; this.amazonGiftCard = null; @@ -99,6 +103,15 @@ export class BuyAmazonPage { this.onWalletSelect(this.wallets[0]); // Default first wallet } + private checkFeeHigh(amount: number, fee: number) { + let per = fee / (amount + fee) * 100; + + if (per > this.FEE_TOO_HIGH_LIMIT_PER) { + let feeWarningModal = this.modalCtrl.create(FeeWarningPage, {}, { showBackdrop: false, enableBackdropDismiss: false }); + feeWarningModal.present(); + } + } + public openExternalLink(url: string) { this.externalLinkProvider.open(url); } @@ -130,7 +143,7 @@ export class BuyAmazonPage { }); } - private publishAndSign(wallet, txp, onSendStatusChange): Promise { + private publishAndSign(wallet: any, txp: any, onSendStatusChange: any): Promise { return new Promise((resolve, reject) => { if (!wallet.canSign() && !wallet.isPrivKeyExternal()) { let err = 'No signing proposal: No private key'; // TODO: gettextCatalog @@ -221,7 +234,7 @@ export class BuyAmazonPage { }); } - private createTx(wallet, invoice, message): Promise { + private createTx(wallet: any, invoice: any, message: string): Promise { return new Promise((resolve, reject) => { let payProUrl = (invoice && invoice.paymentUrls) ? invoice.paymentUrls.BIP73 : null; @@ -354,6 +367,10 @@ export class BuyAmazonPage { invoiceTime: invoice.invoiceTime }; this.totalAmountStr = this.txFormatProvider.formatAmountStr(this.coin, ctxp.amount); + + // Warn: fee too high + this.checkFeeHigh(Number(parsedAmount.amountSat), Number(invoiceFeeSat) + Number(ctxp.fee)); + this.setTotalAmount(parsedAmount.amountSat, invoiceFeeSat, ctxp.fee); }).catch((err: any) => { this.onGoingProcessProvider.set('loadingTxInfo', false); diff --git a/src/pages/integrations/mercado-libre/buy-mercado-libre/buy-mercado-libre.ts b/src/pages/integrations/mercado-libre/buy-mercado-libre/buy-mercado-libre.ts index 6ba2ac749..be78d7718 100644 --- a/src/pages/integrations/mercado-libre/buy-mercado-libre/buy-mercado-libre.ts +++ b/src/pages/integrations/mercado-libre/buy-mercado-libre/buy-mercado-libre.ts @@ -1,10 +1,11 @@ import { Component } from '@angular/core'; -import { NavController, NavParams, ActionSheetController } from 'ionic-angular'; +import { NavController, NavParams, ModalController, ActionSheetController } from 'ionic-angular'; import { Logger } from '@nsalaun/ng-logger'; import * as _ from 'lodash'; import * as moment from 'moment'; // Pages +import { FeeWarningPage } from '../../../../pages/send/fee-warning/fee-warning'; import { MercadoLibreCardsPage } from '../../../../pages/integrations/mercado-libre/mercado-libre-cards/mercado-libre-cards'; // Provider @@ -56,6 +57,7 @@ export class BuyMercadoLibrePage { private emailNotificationsProvider: EmailNotificationsProvider, private externalLinkProvider: ExternalLinkProvider, private logger: Logger, + private modalCtrl: ModalController, private navCtrl: NavController, private navParams: NavParams, private onGoingProcessProvider: OnGoingProcessProvider, @@ -96,6 +98,15 @@ export class BuyMercadoLibrePage { this.onWalletSelect(this.wallets[0]); // Default first wallet } + private checkFeeHigh(amount: number, fee: number) { + let per = fee / (amount + fee) * 100; + + if (per > this.FEE_TOO_HIGH_LIMIT_PER) { + let feeWarningModal = this.modalCtrl.create(FeeWarningPage, {}, { showBackdrop: false, enableBackdropDismiss: false }); + feeWarningModal.present(); + } + } + public openExternalLink(url: string) { this.externalLinkProvider.open(url); } @@ -127,7 +138,7 @@ export class BuyMercadoLibrePage { }); } - private publishAndSign(wallet, txp, onSendStatusChange): Promise { + private publishAndSign(wallet: any, txp: any, onSendStatusChange: any): Promise { return new Promise((resolve, reject) => { if (!wallet.canSign() && !wallet.isPrivKeyExternal()) { let err = 'No signing proposal: No private key'; // TODO: gettextCatalog @@ -217,7 +228,7 @@ export class BuyMercadoLibrePage { }); } - private createTx(wallet, invoice, message): Promise { + private createTx(wallet: any, invoice: any, message: string): Promise { return new Promise((resolve, reject) => { let payProUrl = (invoice && invoice.paymentUrls) ? invoice.paymentUrls.BIP73 : null; @@ -288,6 +299,7 @@ export class BuyMercadoLibrePage { newData.invoiceId = dataSrc.invoiceId; newData.accessKey = dataSrc.accessKey; newData.invoiceUrl = dataSrc.invoiceUrl; + newData.currency = dataSrc.currency; newData.amount = dataSrc.amount; newData.date = dataSrc.invoiceTime || now; newData.uuid = dataSrc.uuid; @@ -342,6 +354,10 @@ export class BuyMercadoLibrePage { invoiceTime: invoice.invoiceTime }; this.totalAmountStr = this.txFormatProvider.formatAmountStr(this.coin, ctxp.amount); + + // Warn: fee too high + this.checkFeeHigh(Number(parsedAmount.amountSat), Number(invoiceFeeSat) + Number(ctxp.fee)); + this.setTotalAmount(parsedAmount.amountSat, invoiceFeeSat, ctxp.fee); }).catch((err: any) => { this.onGoingProcessProvider.set('loadingTxInfo', false); diff --git a/src/pages/integrations/mercado-libre/mercado-libre-card-details/mercado-libre-card-details.html b/src/pages/integrations/mercado-libre/mercado-libre-card-details/mercado-libre-card-details.html index 6393c5a35..e1cc19a18 100644 --- a/src/pages/integrations/mercado-libre/mercado-libre-card-details/mercado-libre-card-details.html +++ b/src/pages/integrations/mercado-libre/mercado-libre-card-details/mercado-libre-card-details.html @@ -1,18 +1,78 @@ - - mercado-libre-card-details + Details + + + - + +
+ Mercado Livre Brazil Gift Card +
+ + {{card.amount | currency : '$ ' : 2}} {{card.currency}} + +
- +
+
+ {{card.pin}} +
+ + +
+ Inactive +
Gift Card is not available to use anymore
+
+ +
+ Expired +
Gift Card is not available to use anymore
+
+ +
+ + Pending + + + Still pending + + + Error + + + Invoice expired + +
+
+
+ + + + Date + + {{card.date | amTimeAgo}} + + + + + + + + + +
\ No newline at end of file diff --git a/src/pages/integrations/mercado-libre/mercado-libre-card-details/mercado-libre-card-details.scss b/src/pages/integrations/mercado-libre/mercado-libre-card-details/mercado-libre-card-details.scss index 6a122a11f..d483fbfa1 100644 --- a/src/pages/integrations/mercado-libre/mercado-libre-card-details/mercado-libre-card-details.scss +++ b/src/pages/integrations/mercado-libre/mercado-libre-card-details/mercado-libre-card-details.scss @@ -1,3 +1,14 @@ page-mercado-libre-card-details { - + .scroll-content { + padding: 2rem; + } + .header-modal { + text-align: center; + img { + width: 230px; + } + &-amount { + padding: 1rem; + } + } } diff --git a/src/pages/integrations/mercado-libre/mercado-libre-card-details/mercado-libre-card-details.ts b/src/pages/integrations/mercado-libre/mercado-libre-card-details/mercado-libre-card-details.ts index 86c24df78..260aa74c9 100644 --- a/src/pages/integrations/mercado-libre/mercado-libre-card-details/mercado-libre-card-details.ts +++ b/src/pages/integrations/mercado-libre/mercado-libre-card-details/mercado-libre-card-details.ts @@ -1,14 +1,10 @@ import { Component } from '@angular/core'; import { NavParams, ViewController } from 'ionic-angular'; import { Logger } from '@nsalaun/ng-logger'; -import * as _ from 'lodash'; // Provider import { MercadoLibreProvider } from '../../../../providers/mercado-libre/mercado-libre'; -import { BwcErrorProvider } from '../../../../providers/bwc-error/bwc-error'; import { ExternalLinkProvider } from '../../../../providers/external-link/external-link'; -import { OnGoingProcessProvider } from "../../../../providers/on-going-process/on-going-process"; -import { PopupProvider } from '../../../../providers/popup/popup'; @Component({ selector: 'page-mercado-libre-card-details', @@ -16,20 +12,46 @@ import { PopupProvider } from '../../../../providers/popup/popup'; }) export class MercadoLibreCardDetailsPage { + public card: any; + constructor( private mercadoLibreProvider: MercadoLibreProvider, - private bwcErrorProvider: BwcErrorProvider, private logger: Logger, private externalLinkProvider: ExternalLinkProvider, private navParams: NavParams, - private onGoingProcessProvider: OnGoingProcessProvider, - private popupProvider: PopupProvider, private viewCtrl: ViewController ) { + this.card = this.navParams.data.card; } ionViewDidLoad() { this.logger.info('ionViewDidLoad MercadoLibreCardDetailsPage'); } + public remove(): void { + this.mercadoLibreProvider.savePendingGiftCard(this.card, { + remove: true + }, (err: any) => { + this.close(); + }); + } + + public close(): void { + this.viewCtrl.dismiss(); + } + + public openExternalLink(url: string): void { + this.externalLinkProvider.open(url); + } + + public openSupportWebsite(): void { + var url = 'https://help.bitpay.com/requestHelp'; + var optIn = true; + var title = null; + var message = 'Help and support information is available at the website.'; //TODO: getTextCatalog + var okText = 'Open'; //TODO: getTextCatalog + var cancelText = 'Go Back'; //TODO: getTextCatalog + this.externalLinkProvider.open(url, optIn, title, message, okText, cancelText); + }; + } diff --git a/src/pages/integrations/mercado-libre/mercado-libre-cards/mercado-libre-cards.html b/src/pages/integrations/mercado-libre/mercado-libre-cards/mercado-libre-cards.html index 76b5b3b14..8b3a8dc59 100644 --- a/src/pages/integrations/mercado-libre/mercado-libre-cards/mercado-libre-cards.html +++ b/src/pages/integrations/mercado-libre/mercado-libre-cards/mercado-libre-cards.html @@ -13,7 +13,6 @@