Not a member of Pastebin yet?
                        Sign Up,
                        it unlocks many cool features!                    
                - // global.css ==================================================================================================
 - ion-content {
 - --background: aliceblue;
 - }
 - ion-input {
 - --min-height: 30px !important;
 - }
 - ion-grid {
 - margin-top: 10px;
 - width: 100%;
 - height: 100%;
 - border-radius: 35px 35px 0px 0px;
 - border-top: solid 10px;
 - border-color: #14426E !important;
 - &:before {
 - background: none !important;
 - z-index: 0;
 - content: "CARGA DE SALDO";
 - position: relative;
 - top: -1px;
 - left: 18%;
 - height: 20px;
 - width: 100%;
 - //@include font(bold, 6vw, true, center);
 - color: var(--ion-color-primary);
 - }
 - }
 - ion-label {
 - //@include font(regular, 3vw, false, left);
 - color: var(--ion-color-tertiary) !important;
 - text-transform: uppercase;
 - font-weight: bold;
 - font-size: 3.5vw !important;
 - text-shadow: 1px 1px 3px #aaaa;
 - }
 - .select-text {
 - margin-left: 10px;
 - font-size: 1.4em !important;
 - font-weight: bold;
 - }
 - ion-label.errorMsg {
 - color: red !important;
 - font-size: 0.8em !important;
 - font-weight: inherit;
 - text-transform: unset;
 - }
 - }
 - // component.scss ==================================================================================================
 - @import url('https://fonts.googleapis.com/css?family=Space+Mono:400,400i,700,700i');
 - .card {
 - margin: auto;
 - margin-top: 4vw;
 - $card-width: 90vw;
 - $card-height: $card-width/1.6842;
 - * {
 - box-sizing: border-box !important;
 - font-family: 'Space Mono', monospace !important;
 - }
 - width: $card-width;
 - height: $card-height;
 - -webkit-perspective: 600px;
 - -moz-perspective: 600px;
 - perspective:600px;
 - &__part {
 - box-shadow: 1px 1px 4px #a3a6aa;
 - top: 0;
 - position: absolute;
 - z-index: 1000;
 - left: 0;
 - display: inline-block;
 - width: $card-width;
 - height: $card-height;
 - background-image: url('https://image.ibb.co/bVnMrc/g3095.png'), linear-gradient(to right bottom, #36dfb3, #3778e4);
 - // linear-gradient(to right bottom, #fd696b, #fa616e, #f65871, #f15075, #ec4879);
 - /*linear-gradient(to right bottom, #fd8369, #fc7870, #f96e78, #f56581, #ee5d8a)*/
 - /*linear-gradient(to right bottom,#20779A,#2397CA,#3ED598,#4E9949);*/
 - background-repeat: no-repeat;
 - background-position: center;
 - background-size: cover;
 - border-radius: 8px;
 - -webkit-transition: all .5s cubic-bezier(0.175, 0.885, 0.32, 1.275);
 - -moz-transition: all .5s cubic-bezier(0.175, 0.885, 0.32, 1.275);
 - -ms-transition: all .5s cubic-bezier(0.175, 0.885, 0.32, 1.275);
 - -o-transition: all .5s cubic-bezier(0.175, 0.885, 0.32, 1.275);
 - transition: all .5s cubic-bezier(0.175, 0.885, 0.32, 1.275);
 - -webkit-transform-style: preserve-3d;
 - -moz-transform-style: preserve-3d;
 - transform-style: preserve-3d;
 - -webkit-backface-visibility: hidden;
 - -moz-backface-visibility: hidden;
 - backface-visibility: hidden;
 - }
 - &__front {
 - padding: 18px;
 - -webkit-transform: rotateY(0);
 - -moz-transform: rotateY(0);
 - transform: rotateY(0);
 - &-logo {
 - position: absolute;
 - top: 18px;
 - right: 18px;
 - }
 - }
 - &__back {
 - padding: 18px 0;
 - -webkit-transform: rotateY(-180deg);
 - -moz-transform: rotateY(-180deg);
 - transform: rotateY(-180deg);
 - &-content {
 - padding: 15px 15px 0;
 - }
 - &-logo {
 - position: absolute;
 - bottom: 15px;
 - right: 15px;
 - }
 - &-square {
 - position: absolute;
 - bottom: 15px;
 - left: 15px;
 - }
 - }
 - &__black-line {
 - margin-top: 5px;
 - height: 38px;
 - background-color: #303030;
 - }
 - &__logo {
 - height: 16px;
 - }
 - &__square {
 - border-radius: 5px;
 - height: 30px;
 - }
 - &_numer {
 - display: block;
 - width: 100%;
 - word-spacing: 4px;
 - font-size: 20px;
 - letter-spacing: 2px;
 - color: #fff;
 - text-align: center;
 - margin-bottom: 20px;
 - margin-top: 20px;
 - }
 - &__space-75 {
 - width: 75%;
 - float: left;
 - }
 - &__space-25 {
 - width: 25%;
 - float: left;
 - }
 - &__label {
 - font-size: 10px;
 - text-transform: uppercase;
 - color: rgba(255, 255, 255, 0.8);
 - letter-spacing: 1px;
 - }
 - &__info {
 - margin-bottom: 0;
 - margin-top: 5px;
 - font-size: 16px;
 - line-height: 18px;
 - color: #fff;
 - letter-spacing: 1px;
 - text-transform: uppercase;
 - }
 - &__secret {
 - padding: 5px 12px;
 - background-color: #fff;
 - position: relative;
 - &:before {
 - content: '';
 - position: absolute;
 - top: -3px;
 - left: -3px;
 - height: calc(100% + 6px);
 - width: calc(100% - 42px);
 - border-radius: 4px;
 - background: repeating-linear-gradient(45deg, #ededed, #ededed 5px, #f9f9f9 5px, #f9f9f9 10px);
 - }
 - }
 - &__secret--last {
 - color: #303030;
 - text-align: right !important;
 - margin: 0;
 - font-size: 14px;
 - z-index: 10;
 - }
 - &:hover .card__front,
 - .show-back.card__front {
 - -webkit-transform: rotateY(180deg);
 - -moz-transform: rotateY(180deg);
 - transform: rotateY(180deg);
 - }
 - &:hover .card__back,
 - .show-back.card__back {
 - -webkit-transform: rotateY(0deg);
 - -moz-transform: rotateY(0deg);
 - transform: rotateY(0deg);
 - }
 - }
 - //component.html ==================================================================================================
 - <ion-content scrolly="false" class="ion-no-padding">
 - <div class="card">
 - <div class="card__front card__part" [ngClass]="{'show-back' : showingBackside }">
 - <img class="card__front-square card__square" src="https://image.ibb.co/cZeFjx/little_square.png">
 - <img class="card__front-logo card__logo"
 - src="../../../assets/images/cliente/tarjeta-saldo/mp-version-horizontal-small.png">
 - <p class="card_numer">
 - {{cardNumber | slice:0:4 }}-{{cardNumber | slice:4:8 }}-{{cardNumber | slice:8:12 }}-{{cardNumber | slice:12:16 }}
 - </p>
 - <div class="card__space-75">
 - <span class="card__label">Card holder</span>
 - <p class="card__info">{{cardHolder}}</p>
 - </div>
 - <div class="card__space-25">
 - <span class="card__label">Expires</span>
 - <p class="card__info">{{expirationMonth}}/{{expirationYear}}</p>
 - </div>
 - </div>
 - <div class="card__back card__part" [ngClass]="{'show-back' : showingBackside }">
 - <div class="card__black-line"></div>
 - <div class="card__back-content">
 - <div class="card__secret">
 - <p class="card__secret--last">{{ccv}}</p>
 - </div>
 - <img class="card__back-square card__square" src="https://image.ibb.co/cZeFjx/little_square.png">
 - <img class="card__back-logo card__logo"
 - src="../../../assets/images/cliente/tarjeta-saldo/mp-version-horizontal-small.png">
 - </div>
 - </div>
 - </div>
 - <!-- <div style="margin-top: 10em;">
 - <ng-payment-card></ng-payment-card>
 - </div> -->
 - <form [formGroup]="form" action="" method="post" id="pay" name="pay">
 - <ion-grid class="ion-padding">
 - <ion-row>
 - <ion-col>
 - <ion-item class="ion-no-padding">
 - <ion-label for="email" position="floating">Email</ion-label>
 - <ion-input [formControl]="form.controls['email']" id="email" name="email" type="email" clear-input="true"
 - [class.invalid]="!form.controls['email'].valid && submitAttempt">
 - </ion-input>
 - </ion-item>
 - <ng-container *ngIf="!form.controls['email'].valid && submitAttempt">
 - <ion-label class="errorMsg">- No puede estar vacío.</ion-label><br>
 - <ion-label class="errorMsg">- Tiene que tener formato de e-mail.</ion-label><br>
 - </ng-container>
 - </ion-col>
 - </ion-row>
 - <ion-row>
 - <ion-col>
 - <ion-item class="ion-no-padding">
 - <ion-label for="cardNumber" position="floating">Número de tarjeta</ion-label>
 - <ion-input [formControl]="form.controls['cardNumber']" (ionChange)="guessingPaymentMethod( $event )"
 - type="text" maxlength="16" id="cardNumber" data-checkout="cardNumber" onpaste="return false"
 - onCopy="return false" onCut="return false" onDrag="return false" onDrop="return false" autocomplete=off
 - clear-input="true" [class.invalid]="!form.controls['cardNumber'].valid && submitAttempt">
 - </ion-input>
 - </ion-item>
 - <ng-container *ngIf="!form.controls['cardNumber'].valid && submitAttempt">
 - <ion-label class="errorMsg">- No puede estar vacío.</ion-label><br>
 - <ion-label class="errorMsg">- Tiene que tener 16 caracteres.</ion-label><br>
 - <ion-label class="errorMsg">- Solo se permiten números.</ion-label><br>
 - </ng-container>
 - </ion-col>
 - </ion-row>
 - <ion-row>
 - <ion-col>
 - <ion-item class="ion-no-padding">
 - <ion-label for="cardholderName" position="floating">Nombre del titular</ion-label>
 - <ion-input (ionChange)="cardUpdater($event)" [formControl]="form.controls['cardholderName']" type="text"
 - id="cardholderName" data-checkout="cardholderName" clearInput maxlength="30"
 - [class.invalid]="!form.controls['cardholderName'].valid && submitAttempt">
 - </ion-input>
 - </ion-item>
 - <ng-container *ngIf="!form.controls['cardholderName'].valid && submitAttempt">
 - <ion-label class="errorMsg">- No puede estar vacío.</ion-label><br>
 - <ion-label class="errorMsg">- No puede tener más de 30 caracteres.</ion-label><br>
 - </ng-container>
 - </ion-col>
 - </ion-row>
 - <ion-row>
 - <ion-col size="4">
 - <ion-item class="ion-no-padding">
 - <ion-label for="cardExpirationMonth" position="floating">Mes Exp.</ion-label>
 - <ion-input (ionChange)="cardUpdater($event)" [formControl]="form.controls['cardExpirationMonth']"
 - type="text" maxlength="2" id="cardExpirationMonth" data-checkout="cardExpirationMonth"
 - onselectstart="return false" onpaste="return false" onCopy="return false" onCut="return false"
 - onDrag="return false" onDrop="return false" autocomplete=off clear-input="true"
 - [class.invalid]="!form.controls['cardExpirationMonth'].valid && submitAttempt">
 - </ion-input>
 - </ion-item>
 - <ng-container *ngIf="!form.controls['cardExpirationMonth'].valid && submitAttempt">
 - <ion-label class="errorMsg">- No puede estar vacío.</ion-label><br>
 - <ion-label class="errorMsg">- Solo se permiten valores entre 1 y 12.</ion-label><br>
 - </ng-container>
 - </ion-col>
 - <ion-col size="4">
 - <ion-item class="ion-no-padding">
 - <ion-label for="cardExpirationYear" position="floating">Año Exp.</ion-label>
 - <ion-input (ionChange)="cardUpdater($event)" [formControl]="form.controls['cardExpirationYear']" type="text"
 - maxlength="4" id="cardExpirationYear" data-checkout="cardExpirationYear" onselectstart="return false"
 - onpaste="return false" onCopy="return false" onCut="return false" onDrag="return false"
 - onDrop="return false" autocomplete=off clearInput
 - [class.invalid]="!form.controls['cardExpirationYear'].valid && submitAttempt">
 - </ion-input>
 - </ion-item>
 - <ng-container *ngIf="!form.controls['cardExpirationYear'].valid && submitAttempt">
 - <ion-label class="errorMsg">- No puede estar vacío.</ion-label><br>
 - <ion-label class="errorMsg">- El año tiene que ser ayor al actual.</ion-label><br>
 - <ion-label class="errorMsg">- Solo se permiten números.</ion-label><br>
 - </ng-container>
 - </ion-col>
 - <ion-col size="4">
 - <ion-item class="ion-no-padding">
 - <ion-label for="securityCode" position="floating">CVV</ion-label>
 - <ion-input (ionFocus)="flipCard('back')" (ionBlur)="flipCard('front')" (ionChange)="cardUpdater($event)" [formControl]="form.controls['securityCode']" type="text"
 - maxlength="3" id="securityCode" data-checkout="securityCode" onselectstart="return false"
 - onpaste="return false" onCopy="return false" onCut="return false" onDrag="return false"
 - onDrop="return false" autocomplete=off autoclean clearInput
 - [class.invalid]="!form.controls['securityCode'].valid && submitAttempt">
 - </ion-input>
 - </ion-item>
 - <ng-container *ngIf="!form.controls['securityCode'].valid && submitAttempt">
 - <ion-label class="errorMsg">- No puede estar vacío.</ion-label><br>
 - <ion-label class="errorMsg">- Tiene que tener 3 caracteres.</ion-label><br>
 - <ion-label class="errorMsg">- Solo se permiten números.</ion-label><br>
 - </ng-container>
 - </ion-col>
 - </ion-row>
 - <ion-row>
 - <ion-col size="5">
 - <ion-item class="ion-no-padding">
 - <ion-label for="docType" position="stacked">Tipo D.</ion-label>
 - <ion-select [formControl]="form.controls['docType']" class="select-full-width">
 - <ion-select-option *ngFor="let idType of mercadoPagoService.identifications" data-checkout="docType"
 - [value]="idType.id">{{idType.name}}</ion-select-option>
 - </ion-select>
 - </ion-item>
 - <ng-container *ngIf="!form.controls['docType'].valid && submitAttempt">
 - <ion-label class="errorMsg">- No puede estar vacío.</ion-label><br>
 - </ng-container>
 - </ion-col>
 - <ion-col size="7">
 - <ion-item class="ion-no-padding">
 - <ion-label for="docNumber" position="floating">Nro. Documento</ion-label>
 - <ion-input [formControl]="form.controls['docNumber']" type="text" maxlength="9" id="docNumber"
 - data-checkout="docNumber" clearInput [class.invalid]="!form.controls['docNumber'].valid && submitAttempt">
 - </ion-input>
 - </ion-item>
 - <ng-container *ngIf="!form.controls['docNumber'].valid && submitAttempt">
 - <ion-label class="errorMsg">- No puede estar vacío.</ion-label><br>
 - <ion-label class="errorMsg">- No se permiten números de menos de 7 dígitos.</ion-label><br>
 - <ion-label class="errorMsg">- No se permiten números de más de 8 dígitos.</ion-label>
 - <br>
 - </ng-container>
 - </ion-col>
 - </ion-row>
 - <ion-row>
 - <ion-col>
 - <ion-item class="ion-no-padding">
 - <ion-label for="amountSelected" position="stacked">Cargas de saldo disponibles</ion-label>
 - <ion-select placeholder="Elegi un monto a cargar" [formControl]="form.controls['amountSelected']" class="select-full-width">
 - <ion-select-option *ngFor="let amount of amounts" [value]="amount.id">
 - {{amount.monto}}
 - </ion-select-option>
 - </ion-select>
 - </ion-item>
 - <ng-container *ngIf="!form.controls['amountSelected'].valid && submitAttempt">
 - <ion-label class="errorMsg">- Debe seleccionar un monto a cargar.</ion-label><br>
 - </ng-container>
 - </ion-col>
 - </ion-row>
 - <ion-row>
 - <ion-col size="3">
 - <ion-button expand="block" color="danger" (click)="cancelar();">
 - <ion-icon color="light" name="chevron-back"></ion-icon>
 - </ion-button>
 - </ion-col>
 - <ion-col size="9">
 - <ion-button expand="block" color="primary" (click)="realizarPago()">
 - <b>Realizar Pago</b>
 - </ion-button>
 - </ion-col>
 - </ion-row>
 - </ion-grid>
 - </form>
 - </ion-content>
 - //component.ts ==================================================================================================
 - import { Component, OnInit, Input, ChangeDetectorRef, ChangeDetectionStrategy } from '@angular/core';
 - import { MercadoPagoService } from '../services/cliente-tarjeta-mercadopago.service';
 - import { FormBuilder, FormGroup, Validators } from '@angular/forms';
 - import { PaymentData } from 'src/app/cliente/models/payment_data';
 - import { analyzeAndValidateNgModules } from '@angular/compiler';
 - import { ModalController } from '@ionic/angular';
 - import { LoadingController } from '@ionic/angular';
 - import { ToastController } from '@ionic/angular';
 - import { LoginService } from 'src/app/auth/services/auth.service';
 - @Component({
 - selector: 'app-saldo-tarjeta',
 - templateUrl: '../views/cliente-tarjeta-saldo.html',
 - styleUrls: ['../views/cliente-tarjeta-saldo.scss'],
 - changeDetection: ChangeDetectionStrategy.OnPush
 - })
 - export class SaldoTarjetaComponent implements OnInit {
 - form: FormGroup;
 - public paymentMethod: any;
 - @Input('nro_tarjeta') nro_tarjeta: string;
 - amounts: any = [];
 - amountSelected: any;
 - submitAttempt = false;
 - cardNumber: string;
 - cardHolder: string;
 - expirationMonth: string;
 - expirationYear: string;
 - ccv: number;
 - showingBackside = false;
 - constructor(
 - private detector: ChangeDetectorRef,
 - public mercadoPagoService: MercadoPagoService,
 - public modalController: ModalController,
 - public loadingController: LoadingController,
 - public toastController: ToastController,
 - private loginService: LoginService,
 - private fb: FormBuilder
 - ) {
 - this.form = fb.group({
 - email: ['', Validators.compose([
 - Validators.required,
 - Validators.email
 - ])],
 - cardNumber: ['', Validators.compose([
 - Validators.required,
 - Validators.minLength(16),
 - Validators.maxLength(16),
 - Validators.pattern('^[0-9]*$')
 - ])],
 - cardholderName: ['', Validators.compose([
 - Validators.required,
 - Validators.minLength(1),
 - Validators.maxLength(30)
 - ])],
 - cardExpirationMonth: ['', Validators.compose([
 - Validators.required,
 - Validators.pattern('^[0-1][0-2]$')
 - ])],
 - cardExpirationYear: ['', Validators.compose([
 - Validators.required,
 - Validators.pattern('^20[1-9][0-9]$')
 - ])],
 - securityCode: ['', Validators.compose([
 - Validators.required,
 - Validators.pattern('^[0-9][0-9][0-9]$')
 - ])],
 - docType: ['DNI', Validators.required],
 - docNumber: ['', Validators.compose([
 - Validators.required,
 - Validators.pattern('^(\\d{7,8})$')
 - ])],
 - paymentMethodId: ['', Validators.required],
 - amountSelected: ['', Validators.required],
 - token: ['']
 - });
 - this.mercadoPagoService.amounts(this.loginService.usuario.numero_sala).subscribe((data: any) => {
 - this.amounts = data.response;
 - }, (error: any) => {
 - console.log(error);
 - });
 - }
 - ngOnInit() {
 - this.mercadoPagoService.getIdentificationTypes();
 - }
 - getBin() {
 - const bin = document.querySelector('ion-input[data-checkout="cardNumber"]');
 - return bin['value'].replace(/[ .-]/g, '').slice(0, 6);
 - }
 - guessingPaymentMethod(e: any) {
 - const bin = this.getBin();
 - this.cardUpdater(e);
 - if (bin.length >= 6) {
 - const paymentMethod = this.mercadoPagoService.getPaymentMethod(bin);
 - if (paymentMethod) {
 - this.paymentMethod = paymentMethod[0];
 - document.getElementById('cardName').innerHTML = this.paymentMethod.name;
 - }
 - }
 - }
 - async realizarPago() {
 - // indico que se estรก haciendo un submit del formulario
 - this.submitAttempt = true;
 - const form = this.form.getRawValue();
 - if (this.form.valid) {
 - // Activo el bloque de pantalla, para que el usuario sepa que se estรก procesando el pago
 - this.showAutoHideLoader();
 - // Esto se usa para poder generar el token sin problemas en varias cargas seguidas.
 - this.mercadoPagoService.Mercadopago.clearSession();
 - this.mercadoPagoService.Mercadopago.createToken(form, (status: any, response: any) => {
 - if (response && status == 200) {
 - const payment_data: any = {
 - // tslint:disable-next-line: triple-equals
 - transaction_amount: this.amounts.find(a => a.id == this.form.get('amountSelected').value).monto,
 - token: response.id,
 - description: 'Carga de Tarjeta desde Aplicacion',
 - installments: 1,
 - payment_method_id: this.paymentMethod.id,
 - payer: { email: this.form.get('email').value },
 - nro_tarjeta: this.nro_tarjeta
 - };
 - this.mercadoPagoService.pago(payment_data).subscribe(
 - rta => {
 - if (rta.success) {
 - const indice = this.loginService.usuario.cliente.tarjetas.findIndex(r => r.nro_tarjeta === rta.tarjetaAct.nro_tarjeta);
 - this.loginService.usuario.cliente.tarjetas[indice] = rta.tarjetaAct;
 - this.hideLoader();
 - this.modalController.dismiss({
 - 'success': true
 - });
 - this.presentToast('Carga realizada', true);
 - } else {
 - this.hideLoader();
 - this.presentToast('Error al realizar la carga', false);
 - }
 - },
 - error => {
 - this.hideLoader();
 - this.presentToast('Error al realizar la carga', false);
 - }
 - );
 - return response;
 - } else {
 - console.log(response);
 - alert('Disculpe, pero no se pudo realizar el pago');
 - return null;
 - }
 - });
 - } else {
 - return null;
 - }
 - }
 - cancelar() {
 - this.modalController.dismiss({
 - 'success': false
 - });
 - }
 - cardUpdater(e) {
 - console.log(e.srcElement.id);
 - switch (e.srcElement.id) {
 - case 'cardNumber':
 - this.cardNumber = e.detail.value;
 - break;
 - case 'cardholderName':
 - this.cardHolder = e.detail.value;
 - break;
 - case 'cardExpirationMonth':
 - this.expirationMonth = e.detail.value;
 - break;
 - case 'cardExpirationYear':
 - this.expirationYear = e.detail.value;
 - break;
 - case 'securityCode':
 - this.ccv = e.detail.value;
 - break;
 - }
 - this.detector.detectChanges();
 - }
 - flipCard(desired_side: String) {
 - if (desired_side === 'back') {
 - this.showingBackside = true;
 - } else {
 - this.showingBackside = false;
 - }
 - }
 - showAutoHideLoader() {
 - this.loadingController.create({
 - message: 'Registrando pago'
 - }).then((res) => {
 - res.present();
 - });
 - }
 - hideLoader() {
 - this.loadingController.dismiss();
 - }
 - async presentToast(message: string, success: boolean) {
 - const color = success ? 'success' : 'danger';
 - this.toastController.create({
 - message: message,
 - duration: 2000,
 - color: color,
 - // ! showCloseButton: true
 - }).then(toast => {
 - toast.present();
 - });
 - }
 - }
 
                    Add Comment                
                
                        Please, Sign In to add comment