Merge pull request #7570 from Gamboster/feat/mercadoLibre1

[V4] Feat: Mercado Libre 1
This commit is contained in:
Gabriel Edgardo Bazán 2017-12-21 10:01:02 -03:00 committed by GitHub
commit 474f79bc69
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 3666 additions and 81 deletions

View File

@ -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,

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 31 KiB

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -0,0 +1,166 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="379.138px" height="96.088px" viewBox="290.552 232.053 379.138 96.088"
enable-background="new 290.552 232.053 379.138 96.088" xml:space="preserve">
<g>
<g>
<path fill="#060E9F" d="M429.391,277.456c0-25.012-31.078-45.403-69.414-45.403c-38.339,0-69.417,20.392-69.417,45.403
c0,0.646-0.008,2.432-0.008,2.658c0,26.536,27.164,48.026,69.416,48.026c42.508,0,69.424-21.483,69.424-48.021
C429.391,279.192,429.391,278.659,429.391,277.456z"/>
<ellipse fill="#FFD100" cx="359.988" cy="277.433" rx="66.747" ry="42.7"/>
<g>
<path fill="#FFFFFF" d="M337.823,263.963c-0.034,0.066-0.7,0.755-0.268,1.309c1.053,1.346,4.306,2.117,7.597,1.379
c1.959-0.439,4.47-2.438,6.902-4.367c2.637-2.094,5.252-4.189,7.878-5.023c2.785-0.887,4.568-0.506,5.746-0.15
c1.293,0.386,2.812,1.236,5.238,3.057c4.565,3.434,22.93,19.462,26.104,22.232c2.555-1.152,13.912-6.042,29.346-9.445
c-1.342-8.228-6.344-15.756-13.936-21.919c-10.582,4.444-23.506,6.761-36.15,0.587c-0.063-0.025-6.905-3.265-13.655-3.105
c-10.032,0.233-14.378,4.574-18.977,9.17L337.823,263.963z"/>
<path fill="#FFFFFF" d="M396.275,284.143c-0.217-0.192-21.592-18.896-26.436-22.537c-2.804-2.102-4.361-2.639-5.998-2.848
c-0.853-0.109-2.029,0.048-2.854,0.273c-2.252,0.613-5.199,2.582-7.813,4.656c-2.707,2.157-5.262,4.188-7.632,4.719
c-3.026,0.679-6.723-0.123-8.409-1.264c-0.685-0.458-1.164-0.99-1.396-1.529c-0.623-1.444,0.526-2.6,0.715-2.793l5.899-6.381
c0.687-0.684,1.376-1.369,2.085-2.043c-1.904,0.248-3.664,0.733-5.378,1.211c-2.137,0.6-4.194,1.172-6.273,1.17
c-0.868,0-5.521-0.762-6.402-1.001c-5.341-1.461-10.025-2.884-17.024-6.152c-8.387,6.243-13.995,14.05-15.615,22.647
c1.204,0.318,3.146,0.896,3.962,1.078c18.979,4.22,24.89,8.566,25.961,9.474c1.161-1.293,2.837-2.109,4.705-2.109
c2.102,0.003,3.992,1.056,5.145,2.688c1.086-0.858,2.585-1.594,4.522-1.592c0.881,0,1.792,0.162,2.715,0.478
c2.142,0.733,3.246,2.16,3.819,3.451c0.717-0.324,1.602-0.564,2.642-0.562c1.021,0,2.086,0.232,3.156,0.695
c3.499,1.502,4.043,4.939,3.727,7.529c0.25-0.027,0.502-0.039,0.756-0.039c4.148,0.002,7.523,3.375,7.523,7.524
c0,1.285-0.328,2.492-0.9,3.554c1.129,0.635,4.006,2.069,6.535,1.75c2.016-0.254,2.783-0.943,3.057-1.332
c0.189-0.269,0.387-0.58,0.203-0.806l-5.354-5.946c0,0-0.882-0.834-0.591-1.154c0.302-0.332,0.847,0.143,1.232,0.465
c2.725,2.275,6.051,5.711,6.051,5.711c0.06,0.037,0.277,0.473,1.508,0.693c1.062,0.188,2.935,0.08,4.232-0.986
c0.326-0.27,0.654-0.607,0.932-0.953c-0.022,0.018-0.041,0.039-0.062,0.049c1.371-1.754-0.152-3.524-0.152-3.524l-6.252-7.021
c0,0-0.895-0.827-0.588-1.157c0.271-0.289,0.846,0.146,1.238,0.473c1.979,1.654,4.774,4.459,7.455,7.088
c0.524,0.383,2.879,1.838,6-0.209c1.895-1.242,2.272-2.77,2.219-3.918c-0.131-1.523-1.32-2.609-1.32-2.609l-8.537-8.586
c0,0-0.903-0.771-0.584-1.16c0.262-0.328,0.844,0.146,1.23,0.465c2.719,2.277,10.082,9.029,10.082,9.029
c0.106,0.074,2.649,1.887,5.795-0.115c1.125-0.721,1.844-1.803,1.901-3.062C397.814,285.439,396.275,284.143,396.275,284.143z"/>
<path fill="#FFFFFF" d="M354.853,295.025c-1.324-0.017-2.773,0.772-2.962,0.656c-0.105-0.066,0.081-0.601,0.204-0.906
c0.129-0.306,1.873-5.553-2.379-7.373c-3.253-1.398-5.243,0.174-5.928,0.883c-0.178,0.186-0.259,0.172-0.277-0.064
c-0.066-0.945-0.488-3.502-3.296-4.359c-4.014-1.227-6.595,1.572-7.249,2.585c-0.292-2.287-2.227-4.062-4.595-4.064
c-2.572-0.004-4.659,2.08-4.662,4.652c-0.002,2.571,2.084,4.659,4.657,4.659c1.25,0.005,2.385-0.495,3.221-1.299
c0.026,0.023,0.036,0.066,0.023,0.156c-0.196,1.152-0.557,5.336,3.827,7.041c1.758,0.684,3.253,0.176,4.492-0.693
c0.369-0.26,0.429-0.149,0.377,0.197c-0.158,1.076,0.043,3.381,3.273,4.689c2.458,1,3.913-0.021,4.866-0.904
c0.416-0.377,0.529-0.314,0.551,0.27c0.117,3.115,2.704,5.591,5.848,5.593c3.239,0.004,5.864-2.613,5.866-5.853
C360.713,297.654,358.09,295.062,354.853,295.025z"/>
</g>
<path fill="#060E9F" d="M397.102,281.902c-6.586-5.746-21.803-18.979-25.924-22.071c-2.355-1.772-3.963-2.706-5.373-3.127
c-0.631-0.191-1.51-0.409-2.637-0.411c-1.05,0-2.177,0.19-3.351,0.564c-2.665,0.844-5.32,2.952-7.885,4.992l-0.132,0.104
c-2.393,1.901-4.863,3.868-6.733,4.284c-0.817,0.184-1.656,0.279-2.493,0.279c-2.096-0.004-3.979-0.607-4.684-1.507
c-0.116-0.149-0.04-0.39,0.23-0.735l0.035-0.047l5.795-6.242c4.537-4.537,8.823-8.822,18.688-9.049
c0.164-0.005,0.33-0.008,0.492-0.008c6.141,0.005,12.278,2.753,12.969,3.072c5.758,2.808,11.701,4.234,17.674,4.239
c6.226,0.001,12.65-1.538,19.404-4.649c-0.756-0.635-1.541-1.252-2.349-1.857c-5.934,2.572-11.586,3.872-17.043,3.871
c-5.567-0.006-11.133-1.344-16.536-3.98c-0.285-0.136-7.062-3.332-14.115-3.335c-0.187,0-0.373,0.003-0.558,0.007
c-8.286,0.194-12.955,3.136-16.094,5.714c-3.052,0.075-5.686,0.812-8.03,1.466c-2.091,0.58-3.896,1.085-5.657,1.084
c-0.727,0-2.031-0.066-2.148-0.071c-2.026-0.062-12.229-2.564-20.348-5.638c-0.829,0.587-1.625,1.192-2.402,1.811
c8.479,3.477,18.799,6.164,22.056,6.375c0.906,0.06,1.872,0.162,2.838,0.164c2.153,0,4.305-0.604,6.386-1.187
c1.229-0.345,2.586-0.721,4.013-0.993c-0.382,0.373-0.762,0.752-1.144,1.135l-5.886,6.367c-0.463,0.467-1.469,1.715-0.806,3.252
c0.263,0.619,0.799,1.213,1.547,1.717c1.403,0.944,3.914,1.584,6.247,1.585c0.883,0.001,1.724-0.087,2.492-0.261
c2.469-0.553,5.057-2.615,7.797-4.795c2.187-1.734,5.288-3.939,7.665-4.586c0.666-0.181,1.48-0.293,2.137-0.293
c0.197,0.002,0.381,0.008,0.554,0.033c1.567,0.199,3.086,0.732,5.797,2.766c4.832,3.631,26.209,22.333,26.42,22.517
c0.014,0.013,1.377,1.188,1.283,3.144c-0.052,1.092-0.656,2.061-1.709,2.729c-0.912,0.58-1.854,0.875-2.806,0.875
c-1.43-0.004-2.412-0.672-2.479-0.719c-0.078-0.064-7.402-6.781-10.101-9.037c-0.43-0.354-0.846-0.677-1.266-0.677
c-0.228,0-0.426,0.096-0.562,0.265c-0.424,0.521,0.052,1.246,0.611,1.722l8.555,8.604c0.013,0.008,1.066,0.996,1.185,2.316
c0.065,1.426-0.613,2.618-2.031,3.547c-1.01,0.666-2.031,1.004-3.033,1.004c-1.315,0-2.235-0.599-2.44-0.742l-1.228-1.209
c-2.244-2.207-4.561-4.49-6.256-5.904c-0.414-0.344-0.854-0.662-1.274-0.662c-0.209,0-0.396,0.076-0.539,0.23
c-0.193,0.215-0.328,0.602,0.155,1.242c0.195,0.264,0.433,0.479,0.433,0.479l6.242,7.015c0.051,0.062,1.286,1.53,0.143,2.991
l-0.221,0.279c-0.189,0.205-0.39,0.396-0.582,0.562c-1.064,0.875-2.486,0.967-3.052,0.967c-0.303,0-0.592-0.025-0.844-0.07
c-0.615-0.111-1.031-0.283-1.229-0.52l-0.078-0.078c-0.34-0.354-3.486-3.566-6.09-5.74c-0.345-0.287-0.771-0.648-1.215-0.648
c-0.22,0-0.412,0.084-0.564,0.25c-0.514,0.564,0.26,1.408,0.588,1.717l5.322,5.875c-0.006,0.052-0.07,0.172-0.199,0.357
c-0.191,0.264-0.836,0.91-2.768,1.152c-0.232,0.031-0.474,0.043-0.707,0.043c-1.994,0-4.117-0.969-5.216-1.547
c0.5-1.055,0.759-2.215,0.759-3.375c0.004-4.385-3.558-7.949-7.94-7.953c-0.094,0-0.193,0.004-0.287,0.006
c0.144-2.002-0.14-5.791-4.028-7.459c-1.119-0.484-2.236-0.732-3.321-0.732c-0.85,0-1.668,0.146-2.437,0.441
c-0.805-1.566-2.145-2.707-3.889-3.303c-0.966-0.334-1.926-0.502-2.852-0.502c-1.619,0-3.111,0.477-4.44,1.424
c-1.274-1.586-3.199-2.525-5.226-2.525c-1.773,0-3.48,0.71-4.744,1.962c-1.658-1.266-8.234-5.443-25.833-9.438
c-0.854-0.193-2.809-0.754-4.007-1.105c-0.199,0.953-0.352,1.916-0.45,2.889c0,0,3.246,0.776,3.884,0.92
c17.979,3.994,23.921,8.146,24.925,8.931c-0.34,0.816-0.518,1.699-0.519,2.584c-0.002,3.717,3.019,6.742,6.735,6.746
c0.416,0,0.829-0.037,1.235-0.115c0.56,2.736,2.348,4.809,5.082,5.871c0.799,0.307,1.607,0.463,2.4,0.463
c0.514,0.004,1.028-0.061,1.533-0.189c0.506,1.281,1.641,2.88,4.183,3.912c0.889,0.357,1.778,0.545,2.646,0.545
c0.706,0,1.397-0.125,2.058-0.366c1.217,2.965,4.114,4.93,7.343,4.93c2.14,0.002,4.193-0.871,5.693-2.414
c1.281,0.716,3.99,2.007,6.728,2.011c0.352,0,0.684-0.025,1.018-0.064c2.716-0.344,3.98-1.408,4.562-2.232
c0.104-0.145,0.199-0.297,0.281-0.457c0.641,0.185,1.346,0.334,2.153,0.338c1.482,0,2.906-0.506,4.347-1.555
c1.414-1.021,2.422-2.482,2.563-3.73c0.004-0.016,0.004-0.034,0.006-0.053c0.479,0.099,0.967,0.146,1.455,0.146
c1.529,0,3.031-0.475,4.465-1.416c2.771-1.814,3.25-4.188,3.203-5.738c0.488,0.102,0.982,0.152,1.476,0.152
c1.432,0,2.842-0.432,4.182-1.287c1.717-1.098,2.752-2.777,2.91-4.732c0.104-1.328-0.226-2.672-0.924-3.824
c4.639-1.998,15.243-5.866,27.731-8.679c-0.072-0.969-0.215-1.925-0.389-2.878C411.198,275.767,399.926,280.646,397.102,281.902z
M354.853,306.326c-2.937-0.004-5.32-2.283-5.428-5.189c-0.009-0.25-0.034-0.912-0.597-0.912c-0.229,0-0.429,0.14-0.658,0.349
c-0.646,0.598-1.469,1.204-2.667,1.204c-0.547,0-1.135-0.127-1.759-0.381c-3.098-1.258-3.141-3.385-3.016-4.239
c0.034-0.229,0.046-0.466-0.113-0.65l-0.189-0.17h-0.192c-0.156,0-0.319,0.063-0.538,0.217c-0.896,0.632-1.757,0.937-2.631,0.937
c-0.48,0-0.975-0.096-1.468-0.285c-4.081-1.588-3.759-5.439-3.56-6.598c0.03-0.236-0.028-0.418-0.178-0.539l-0.288-0.236
l-0.269,0.258c-0.795,0.766-1.835,1.186-2.928,1.186c-2.338-0.002-4.238-1.899-4.237-4.239c0.001-2.336,1.905-4.231,4.242-4.229
c2.11,0,3.908,1.588,4.178,3.696l0.146,1.14l0.625-0.964c0.07-0.112,1.782-2.7,4.932-2.698c0.598,0,1.217,0.096,1.84,0.289
c2.507,0.766,2.934,3.041,2.998,3.987c0.046,0.554,0.438,0.58,0.515,0.58c0.218,0,0.377-0.139,0.49-0.258
c0.473-0.494,1.504-1.316,3.118-1.316c0.739,0.005,1.522,0.181,2.337,0.527c3.988,1.711,2.18,6.778,2.158,6.832
c-0.345,0.84-0.357,1.211-0.035,1.424l0.157,0.074h0.116c0.18,0,0.402-0.076,0.772-0.201c0.542-0.188,1.36-0.471,2.127-0.471
h0.002c3.003,0.034,5.443,2.479,5.443,5.444C360.297,303.889,357.852,306.326,354.853,306.326z"/>
</g>
<g>
<g>
<path fill="#060E9F" d="M665.93,248.525c-2.504-3.14-6.31-4.708-11.412-4.708c-5.1,0-8.904,1.568-11.408,4.708
c-2.508,3.138-3.762,6.847-3.762,11.126c0,4.355,1.254,8.077,3.762,11.176c2.504,3.088,6.31,4.638,11.408,4.638
c5.104,0,8.908-1.55,11.412-4.638c2.508-3.099,3.76-6.82,3.76-11.176C669.689,255.372,668.438,251.663,665.93,248.525z
M659.723,266.534c-1.217,1.613-2.955,2.42-5.23,2.42c-2.268,0-4.016-0.807-5.241-2.42c-1.227-1.613-1.837-3.908-1.837-6.883
c0-2.971,0.609-5.261,1.837-6.865c1.227-1.604,2.975-2.406,5.241-2.406c2.275,0,4.015,0.802,5.23,2.406
c1.213,1.604,1.824,3.895,1.824,6.865C661.547,262.625,660.936,264.92,659.723,266.534z"/>
<path fill="#060E9F" d="M601.895,245.9c-2.539-1.289-5.449-1.939-8.721-1.939c-5.031,0-8.582,1.313-10.648,3.933
c-1.299,1.679-2.029,3.817-2.199,6.422h7.519c0.184-1.149,0.553-2.06,1.106-2.732c0.775-0.909,2.093-1.364,3.957-1.364
c1.664,0,2.922,0.229,3.785,0.697c0.854,0.463,1.287,1.307,1.287,2.525c0,1.004-0.559,1.738-1.68,2.214
c-0.627,0.273-1.662,0.501-3.115,0.683l-2.664,0.327c-3.025,0.382-5.324,1.022-6.879,1.915c-2.848,1.641-4.269,4.287-4.269,7.949
c0,2.82,0.88,5.006,2.65,6.543c1.764,1.539,4.012,2.185,6.721,2.311c16.998,0.758,16.806-8.957,16.961-10.977v-11.184
C605.706,249.637,604.436,247.194,601.895,245.9z M597.947,262.868c-0.051,2.605-0.799,4.398-2.229,5.381
c-1.435,0.986-3,1.479-4.699,1.479c-1.076,0-1.986-0.299-2.736-0.889c-0.748-0.592-1.119-1.555-1.119-2.884
c0-1.492,0.609-2.593,1.836-3.305c0.729-0.418,1.919-0.776,3.58-1.062l1.775-0.329c0.883-0.168,1.578-0.346,2.086-0.538
c0.514-0.187,1.01-0.435,1.508-0.747L597.947,262.868L597.947,262.868z"/>
<path fill="#060E9F" d="M563.139,250.623c1.942,0,3.369,0.599,4.291,1.799c0.633,0.888,1.026,1.89,1.182,2.998h8.385
c-0.461-4.229-1.94-7.183-4.438-8.854c-2.506-1.667-5.717-2.506-9.644-2.506c-4.618,0-8.245,1.418-10.864,4.249
c-2.625,2.835-3.939,6.798-3.939,11.89c0,4.51,1.188,8.186,3.564,11.018c2.375,2.831,6.082,4.249,11.119,4.249
c5.043,0,8.848-1.699,11.411-5.095c1.609-2.104,2.513-4.338,2.701-6.701h-8.354c-0.17,1.562-0.658,2.835-1.467,3.814
c-0.808,0.979-2.164,1.471-4.087,1.471c-2.704,0-4.549-1.232-5.526-3.707c-0.535-1.318-0.808-3.066-0.808-5.239
c0-2.28,0.271-4.108,0.808-5.489C558.488,251.924,560.379,250.623,563.139,250.623z"/>
<path fill="#060E9F" d="M545.861,244.059c-17.221,0-16.203,15.248-16.203,15.248v15.488h7.816v-14.527
c0-2.381,0.303-4.143,0.896-5.289c1.072-2.031,3.166-3.051,6.293-3.051c0.236,0,0.545,0.013,0.929,0.03
c0.379,0.019,0.811,0.053,1.309,0.11v-7.952c-0.348-0.023-0.572-0.033-0.668-0.043
C546.131,244.065,546.008,244.059,545.861,244.059z"/>
<path fill="#060E9F" d="M517.154,266.703c-0.328,0.468-0.682,0.869-1.069,1.182c-1.104,0.909-2.604,1.188-4.369,1.188
c-1.67,0-2.978-0.254-4.16-1c-1.949-1.197-3.047-3.227-3.164-6.203h21.625c0.029-2.562-0.053-4.525-0.26-5.892
c-0.359-2.325-1.15-4.375-2.363-6.138c-1.35-2.001-3.064-3.465-5.133-4.395c-2.068-0.923-4.396-1.387-6.978-1.387
c-4.354,0-7.891,1.372-10.616,4.114c-2.728,2.748-4.097,6.688-4.097,11.83c0,5.49,1.512,9.451,4.535,11.885
c3.018,2.438,6.508,3.654,10.457,3.654c4.785,0,8.51-1.441,11.168-4.331c1.435-1.519,2.332-3.023,2.711-4.506H517.154z
M506.648,252.153c1.1-1.131,2.644-1.697,4.635-1.697c1.834,0,3.365,0.533,4.605,1.602c1.233,1.065,1.926,2.632,2.063,4.688
H504.58C504.861,254.813,505.553,253.284,506.648,252.153z"/>
<g>
<path fill="#060E9F" d="M493.434,274.793h-7.139v-17.977c0-1.641-0.543-5.547-5.252-5.547c-3.14,0-5.41,2.264-5.41,5.547v17.977
h-7.146v-17.977c0-1.641-0.488-5.547-5.192-5.547c-3.193,0-5.414,2.264-5.414,5.547v17.977h-7.144v-17.805
c0-7.422,4.924-13.033,12.558-13.033c3.788,0,6.87,1.59,8.877,4.141c2.106-2.55,5.245-4.141,8.873-4.141
c7.793,0,12.391,5.384,12.391,13.033L493.434,274.793L493.434,274.793z"/>
</g>
<path fill="#060E9F" d="M637.023,234.671c0,0-7.871-0.841-7.871,5.483l-0.008,8.372c-0.869-1.398-2.004-2.492-3.402-3.281
c-1.395-0.789-2.991-1.186-4.795-1.186c-3.903,0-7.016,1.454-9.352,4.357c-2.336,2.907-3.498,7.096-3.498,12.16
c0,4.395,1.184,7.998,3.553,10.803c2.371,2.802,7.019,4.032,11.144,4.032c14.391,0,14.225-12.341,14.225-12.341L637.023,234.671z
M627.65,266.598c-1.141,1.635-2.817,2.451-5.01,2.451c-2.201,0-3.838-0.824-4.916-2.465c-1.08-1.646-1.619-4.041-1.619-6.781
c0-2.543,0.527-4.672,1.592-6.387c1.06-1.715,2.724-2.574,4.994-2.574c1.49,0,2.797,0.472,3.926,1.415
c1.832,1.562,2.75,4.364,2.75,7.993C629.366,262.848,628.793,264.963,627.65,266.598z"/>
</g>
<g>
<path fill="#060E9F" d="M601.329,312.088c-0.321,0.465-0.678,0.859-1.059,1.168c-1.094,0.896-2.637,1.229-4.377,1.229
c-1.646,0-2.941-0.243-4.109-0.987c-1.932-1.181-2.955-3.242-3.073-6.19h21.385c0.024-2.529-0.055-4.474-0.26-5.818
c-0.357-2.303-1.14-4.33-2.336-6.074c-1.337-1.977-3.031-3.424-5.076-4.342c-2.049-0.916-4.349-1.373-6.898-1.373
c-4.311,0-7.801,1.355-10.5,4.068c-2.693,2.717-4.043,6.608-4.043,11.694c0,5.429,1.49,9.349,4.479,11.752
c2.985,2.408,6.438,3.613,10.342,3.613c4.729,0,8.412-1.429,11.041-4.281c1.416-1.506,2.307-2.991,2.684-4.457L601.329,312.088
L601.329,312.088z M590.945,297.699c1.086-1.115,2.613-1.676,4.58-1.676c1.81,0,3.328,0.524,4.551,1.584
c1.224,1.053,1.908,2.6,2.048,4.635h-13.226C589.18,300.332,589.859,298.818,590.945,297.699z"/>
<path fill="#060E9F" d="M579.45,289.676c-0.104-0.008-0.225-0.012-0.366-0.012c-17.183,0-16.164,15.205-16.164,15.205v15.211
h7.795v-14.252c0-2.375,0.299-4.135,0.899-5.275c1.064-2.023,3.156-3.043,6.271-3.043c0.242,0,0.545,0.008,0.924,0.029
c0.381,0.02,0.813,0.053,1.307,0.107v-7.931C579.77,289.695,579.547,289.686,579.45,289.676z"/>
<path fill="#060E9F" d="M510.323,285.703c0,5.889,0,34.377,0,34.377h7.314v-39.968
C517.639,280.112,510.323,279.816,510.323,285.703z"/>
<g>
<rect x="523.643" y="280.069" fill="#060E9F" width="7.828" height="7.753"/>
<rect x="523.643" y="290.469" fill="#060E9F" width="7.846" height="29.611"/>
</g>
<g>
<path fill="#060E9F" d="M552.406,320.186h-7.932l-10.394-29.717h8.271l5.918,20.891l5.25-18.207
c0.598-1.788,1.787-2.684,3.574-2.684h5.812L552.406,320.186z"/>
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 16 KiB

View File

@ -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);

View File

@ -96,11 +96,11 @@ export class AmazonCardDetailsPage {
public cancel(): void {
this.viewCtrl.dismiss();
};
}
public openExternalLink(url: string): void {
this.externalLinkProvider.open(url);
};
}
}

View File

@ -33,8 +33,8 @@ page-amazon {
display: block;
}
}
}
.integration-giftCard {
}
.integration-giftCard {
&-logo {
width: 100%;
display: inline-block;
@ -47,5 +47,5 @@ page-amazon {
&-info {
padding: 1rem;
}
}
}
}

View File

@ -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<any> {
private publishAndSign(wallet: any, txp: any, onSendStatusChange: any): Promise<any> {
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<any> {
private createTx(wallet: any, invoice: any, message: string): Promise<any> {
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);

View File

@ -0,0 +1,84 @@
<ion-header>
<ion-navbar>
<ion-title>Buy</ion-title>
</ion-navbar>
</ion-header>
<ion-content>
<ion-list>
<ion-item>
<div class="mercado-libre-title">
<img src="assets/img/mercado-libre/icon-ml.svg">
<span>Vale-Presente do Mercado Livre Brasil</span>
</div>
<div class="amount-label">
<div class="amount">{{amountUnitStr}}</div>
<div class="alternative">
{{limitPerDayMessage}}
</div>
</div>
</ion-item>
<ion-item-group class="info">
<button ion-item (click)="showWallets()" class="wallets-list">
<div translate>From</div>
<div class="wallet">
<img src="assets/img/icon-wallet.svg">
<span>{{wallet ? wallet.name : '...'}}</span>
</div>
</button>
<div *ngIf="totalAmountStr">
<ion-item-divider color="light">
Details
</ion-item-divider>
<ion-item>
<span translate>Gift Card</span>
<ion-note item-end>
{{amount | currency:'$ ':2}}<span *ngIf="amount"> {{currencyIsoCode}}</span>
</ion-note>
</ion-item>
<ion-item>
<span translate>Network Cost</span>
<ion-note item-end>
<span>{{invoiceFee | currency:'$ ':2}}<span *ngIf="invoiceFee"> {{currencyIsoCode}}</span></span>
</ion-note>
</ion-item>
<ion-item>
<span translate>Miner Fee</span>
<ion-note item-end>
<span>{{networkFee | currency:'$ ':2}}<span *ngIf="networkFee"> {{currencyIsoCode}}</span></span>
</ion-note>
</ion-item>
<ion-item>
<span translate>Total</span>
<ion-note item-end>
<span *ngIf="totalAmount">{{totalAmount | currency:'$ ':2}} {{currencyIsoCode}}</span>
<span *ngIf="totalAmountStr">({{totalAmountStr}})</span>
</ion-note>
</ion-item>
</div>
</ion-item-group>
</ion-list>
</ion-content>
<ion-footer *ngIf="!mlGiftCard">
<button ion-button block class="button-footer" (click)="buyConfirm()" [disabled]="!(wallet && totalAmountStr)" translate>Confirm purchase</button>
</ion-footer>
<ion-footer *ngIf="mlGiftCard">
<span *ngIf="mlGiftCard.status == 'FAILURE'" translate>
Sua compra não pôde ser concluída
</span>
<span *ngIf="mlGiftCard.status == 'PENDING'" translate>
Sua compra foi adicionada à lista de pendentes
</span>
<span *ngIf="mlGiftCard.status == 'SUCCESS' || mlGiftCard.status == 'active'" translate>
Comprou {{mlGiftCard.amount}} {{mlGiftCard.currency}}
</span>
<div *ngIf="mlGiftCard.status == 'SUCCESS' || mlGiftCard.cardStatus == 'active'" translate>
Vale-Presente gerado e pronto para usar
</div>
<button ion-button block class="button-footer" (click)="goBackHome()" [disabled]="!(wallet && totalAmountStr)" translate>Accept and back home</button>
</ion-footer>

View File

@ -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);
}
}
}
}

View File

@ -0,0 +1,435 @@
import { Component } from '@angular/core';
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
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 modalCtrl: ModalController,
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
}
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);
}
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<any> {
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: any, txp: any, onSendStatusChange: any): Promise<any> {
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<any> {
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<any> {
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: any, invoice: any, message: string): Promise<any> {
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.currency = dataSrc.currency;
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);
// 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);
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<any> = [];
_.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();
}
}

View File

@ -0,0 +1,78 @@
<ion-header>
<ion-navbar>
<ion-title>Details</ion-title>
<ion-buttons start>
<button (click)="close()" ion-button>
Close
</button>
</ion-buttons>
</ion-navbar>
</ion-header>
<ion-content>
<div class="header-modal">
<img src="assets/img/mercado-libre/giftcard-pt.svg" alt="Mercado Livre Brazil Gift Card">
<div class="header-modal-amount">
<span class="text-bold">
{{card.amount | currency : '$ ' : 2}} {{card.currency}}
</span>
</div>
<div *ngIf="card.pin">
<div *ngIf="card.cardStatus == 'active'">
<span class="text-bold" copy-to-clipboard="card.pin">{{card.pin}}</span>
</div>
<button (click)="openExternalLink('https://www.mercadolivre.com.br')" translate>
Redeem Now
</button>
<div *ngIf="card.cardStatus == 'inactive'">
<span class="assertive" translate>Inactive</span>
<div class="card-status-desc" translate>Gift Card is not available to use anymore</div>
</div>
<div *ngIf="card.cardStatus == 'expired'">
<span class="assertive" translate>Expired</span>
<div class="card-status-desc" translate>Gift Card is not available to use anymore</div>
</div>
<div *ngIf="card.status">
<span class="positive" *ngIf="card.status == 'PENDING'" translate>
Pending
</span>
<span class="calm" *ngIf="card.status=='invalid'" translate>
Still pending
</span>
<span class="assertive" *ngIf="card.status == 'FAILURE'" translate>
Error
</span>
<span class="dark" *ngIf="card.status == 'expired'" translate>
Invoice expired
</span>
</div>
</div>
</div>
<ion-list>
<ion-item>
<span translate>Date</span>
<ion-note item-end>
{{card.date | amTimeAgo}}
</ion-note>
</ion-item>
<button ion-item (click)="openExternalLink(card.invoiceUrl)">
<span translate>See invoice</span>
</button>
<button ion-item *ngIf="card.status == 'FAILURE'" (click)="openSupportWebsite()">
<span>{{'Help & Support' | translate }}</span>
</button>
</ion-list>
<button ion-button block *ngIf="card.cardStatus == 'inactive' || card.cardStatus == 'expired' || card.status == 'expired'"
class="button-footer assertive" (click)="remove()">Remove</button>
</ion-content>

View File

@ -0,0 +1,14 @@
page-mercado-libre-card-details {
.scroll-content {
padding: 2rem;
}
.header-modal {
text-align: center;
img {
width: 230px;
}
&-amount {
padding: 1rem;
}
}
}

View File

@ -0,0 +1,57 @@
import { Component } from '@angular/core';
import { NavParams, ViewController } from 'ionic-angular';
import { Logger } from '@nsalaun/ng-logger';
// Provider
import { MercadoLibreProvider } from '../../../../providers/mercado-libre/mercado-libre';
import { ExternalLinkProvider } from '../../../../providers/external-link/external-link';
@Component({
selector: 'page-mercado-libre-card-details',
templateUrl: 'mercado-libre-card-details.html',
})
export class MercadoLibreCardDetailsPage {
public card: any;
constructor(
private mercadoLibreProvider: MercadoLibreProvider,
private logger: Logger,
private externalLinkProvider: ExternalLinkProvider,
private navParams: NavParams,
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);
};
}

View File

@ -0,0 +1,34 @@
<ion-header>
<ion-navbar>
<ion-title>{{'Your Gift Cards'|translate}}</ion-title>
</ion-navbar>
</ion-header>
<ion-content>
<ion-card>
<ion-list *ngIf="!hideCards">
<button ion-item *ngFor="let item of giftCards | keys" (click)="openCardModal(item.value)">
<div class="mercado-libre-card">
<img src="assets/img/mercado-libre/meli-card-24px.png" alt="" class="avatar">
<div class="card-info">
<h2 *ngIf="item.value.amount">
{{item.value.amount | currency : '$ ' : 2}} {{item.value.currency}}
</h2>
<span>
<span class="assertive" *ngIf="item.value.status == 'FAILURE'">Error</span>
<span class="dark" *ngIf="item.value.status == 'expired'">Invoice expired</span>
<span class="calm" *ngIf="item.value.status == 'invalid'">Still pending</span>
<span class="positive" *ngIf="item.value.status == 'PENDING'">Pending</span>
<span class="assertive" *ngIf="item.value.cardStatus == 'inactive'" translate>Inactive</span>
<span class="assertive" *ngIf="item.value.cardStatus == 'expired'" translate>Expired</span>
</span>
<span class="dark">{{item.value.date | amTimeAgo}}</span>
</div>
</div>
</button>
</ion-list>
</ion-card>
</ion-content>

View File

@ -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;
}
}
}

View File

@ -0,0 +1,127 @@
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 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<any> {
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();
})
}
}

View File

@ -0,0 +1,53 @@
<ion-header>
<ion-navbar>
<ion-title>{{'Mercado Livre Brazil Gift Cards'|translate}}s</ion-title>
</ion-navbar>
</ion-header>
<ion-content *ngIf="!giftCards">
<div class="box-notification warning" *ngIf="network == 'testnet'">
Sandbox version. Only for testing purpose.
</div>
<div class="integration-onboarding">
<div class="integration-onboarding-logo">
<img src="assets/img/mercado-libre/mlbr.svg" alt="Mercado Libre">
</div>
<div class="integration-onboarding-description" translate>
<b>Only</b> redeemable on Mercado Livre (Brazil)
</div>
<div class="integration-onboarding-cta" *ngIf="!showOauthForm">
<button ion-button (click)="goTo('Amount')" translate>Buy a Gift Card</button>
<!-- TODO: no-low-fee -->
<button ion-button (click)="openExternalLink('https://www.mercadolivre.com.br')" translate>Visit mercadolivre.com.br &rarr;</button>
</div>
</div>
</ion-content>
<ion-content *ngIf="giftCards">
<div class="box-notification warning" *ngIf="network == 'testnet'">
Sandbox version. Only for testing purpose.
</div>
<div class="integration-giftCard-logo">
<img src="assets/img/mercado-libre/mlbr.svg" alt="Mercado Libre">
<div translate><b>Only</b> redeemable on Mercado Livre (Brazil)</div>
</div>
<ion-card>
<ion-card-content>
<ion-list>
<button ion-item (click)="goTo('Amount')">
<!-- TODO: no-low-fee -->
<ion-icon name="ios-pricetags-outline"></ion-icon>
<span translate>Buy Gift Card</span>
</button>
<button ion-item (click)="goTo('MercadoLibreCards')">
<ion-icon name="ios-folder-outline"></ion-icon>
<span translate>Your Gift Cards</span>
</button>
</ion-list>
</ion-card-content>
</ion-card>
</ion-content>

View File

@ -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;
}
}
}

View File

@ -0,0 +1,65 @@
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');
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;
}
}
}

View File

@ -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;
}

View File

@ -6,7 +6,6 @@ import { DecimalPipe } from '@angular/common';
pure: false
})
export class SatToUnitPipe implements PipeTransform {
private walletSettings: any;
constructor(
private decimalPipe: DecimalPipe,

View File

@ -30,8 +30,8 @@ export class AmazonProvider {
* Development: 'testnet'
* Production: 'livenet'
*/
//this.credentials.NETWORK = 'livenet';
this.credentials.NETWORK = 'testnet';
this.credentials.NETWORK = 'livenet';
//this.credentials.NETWORK = 'testnet';
if (this.credentials.NETWORK == 'testnet') {
this.credentials.BITPAY_API_URL = "https://test.bitpay.com";
} else {

View File

@ -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 {
@ -106,7 +106,8 @@ export class MercadoLibreProvider {
let dataSrc = {
currency: data.currency,
amount: data.amount,
clientId: data.uuid
clientId: data.uuid,
email: data.email
};
let url = this.credentials.BITPAY_API_URL + '/mercado-libre-gift/pay';
let headers: any = {
@ -114,10 +115,10 @@ export class MercadoLibreProvider {
};
this.http.post(url, dataSrc, headers).subscribe((data: any) => {
this.logger.info('BitPay Create Invoice: SUCCESS');
return cb(null, data.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,10 @@ export class MercadoLibreProvider {
this.http.get(url, headers).subscribe((data: any) => {
this.logger.info('BitPay Get Invoice: SUCCESS');
return cb(null, data.data.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 +150,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 +177,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);
});
};
*/