viernes, 29 de mayo de 2020

Push Notification - ONESIGNAL

1. instalar:

ionic cordova plugin add onesignal-cordova-pluginnpm install @ionic-native/onesignal
2. Importar el servicio en los privders MODULO PRINCIPAL (app.module.ts)
import { OneSignal } from '@ionic-native/onesignal/ngx';
    
providers: [
StatusBar,
SplashScreen,
OneSignal,
{ provide: RouteReuseStrategy, useClass: IonicRouteStrategy }
],


3. KEY EN VARIABLES DE ENTORNO    ONESIGNAL APP IDEJM-f799-4ced-b221-84c8297adca3    FIREBASE_SENDER_ID: ej3523024246

4. Crear servicio PushService
import { OneSignal, OSNotification } from '@ionic-native/onesignal/ngx';
import { Injectable } from '@angular/core';

@Injectable({
providedIn: 'root'
})
export class PushService {

constructor(private oneSignal: OneSignal) { }

mensajes:any[] = [
{
title: 'Titulo de la push',
body: 'Este es el body de la push',
date: new Date()
}
];

configuracionInicial(){

this.oneSignal.startInit(ONESIGNAL_APP_ID, FIREBASE_SENDER_ID);

this.oneSignal.inFocusDisplaying(this.oneSignal.OSInFocusDisplayOption.Notification );

this.oneSignal.handleNotificationReceived().subscribe((noti) => {
// do something when notification is received
console.log('Notificación recibida', noti);
this.notificacionRecibida( noti );
});

this.oneSignal.handleNotificationOpened().subscribe((noti) => {
// do something when a notification is opened
console.log('Notificación abierta', noti)
});

this.oneSignal.endInit();

};

notificacionRecibida( noti: OSNotification ){

const payload = noti.payload;
const existePush = this.mensajes.find( mensaje=> mensaje.notificationID === payload.notificationID );

if( existePush ){
return;
}

this.mensajes.unshift( payload );

};

}


5. INYECTAR EN APP.COMPONENT.TS
private pushService: PushService

initializeApp() {
this.platform.ready().then(() => {
this.statusBar.styleDefault();
this.splashScreen.hide();
this.pushService.configuracionInicial();
});
}




































Crear Servicio de 0 - Angular

1.- crear archivo .service

2. crear clase del servicio

import { Injectable } from '@angular/core';
import { HttpClient , HttpHeaders, HttpErrorResponse } from '@angular/common/http';
import { Observable, throwError } from 'rxjs';
import { catchError, retry } from 'rxjs/operators';
import { LoadingController } from '@ionic/angular';

import { appConfig } from 'src/app/global/app.config';
const URL = appConfig.api;

@Injectable({ providedIn:'root' })

export class PushPatient {
constructor(private http: HttpClient, public loadingController: LoadingController){ }

};


3. crear funciones para optimizar
    3.1 suscripcion
    3.2 cabezera
    3.3 menejador de errores
    3.4 preload (only ionic)

3.1 
private subscribe( request:any ){
return new Promise((resolve, reject )=>{
request.subscribe(res=>resolve(res), err=> reject(err));
});
};


3.2 (si solo valida token x storage , si va manejar otro tipo de cabezera modificar codigo)
private _httpOption( current_user:string ){
let token = "";
if( current_user ) token = localStorage.getItem( current_user );
return { headers: new HttpHeaders({
'Content-Type': 'application/json',
'Authorization': token })
};
};

3.3
private handleError(error: HttpErrorResponse) {
if (error.error instanceof ErrorEvent) {
// A client-side or network error occurred. Handle it accordingly.
console.error('An error occurred:', error.error.message);
} else {
// The backend returned an unsuccessful response code, The response body may contain clues as to what went wrong,
console.error( `Backend returned code ${error.status}, ` + `body was: ${error.error}`);
}
// return an observable with a user-facing error message
return throwError( error.error.message );
};

3.4
async loading() {
const loading = await this.loadingController.create({
duration: 3000,
message: 'Please wait...',
});
return await loading.present();
}


===================== EJEMPLO COMPLETO =====================



import { Injectable } from '@angular/core';
import { HttpClient , HttpHeaders, HttpErrorResponse } from '@angular/common/http';
import { Observable, throwError } from 'rxjs';
import { catchError, retry } from 'rxjs/operators';
import { LoadingController } from '@ionic/angular';

import { appConfig } from 'src/app/global/app.config';
const URL = appConfig.api;

@Injectable({ providedIn:'root' })

export class PushPatient {
constructor(private http: HttpClient, public loadingController: LoadingController){ }

// Envia notificación push
async _sendPush(data: any) {
const api = "https://onesignal.com/api/v1/notifications";
const resp = await this._post(data, api, appConfig.REST_API_KEY );
return resp;
};

//========== CUSTOM FUNCTIONS ============//
async _post( data: any, _router:string, _options?:any ){
await this.loading();
let url = _router;
_options = this._httpOption( _options );
let req = await this.http.post( url, data, _options ).pipe( catchError(this.handleError) );
let resp = await this.subscribe( req );
return resp;
};

private subscribe( request:any ){
return new Promise((resolve, reject )=>{
request.subscribe(res=>resolve(res), err=> reject(err));
});
};

private _httpOption( key:string ){
return { headers: new HttpHeaders({
'Content-Type': 'application/json',
'Authorization': key })
};
};

private handleError(error: HttpErrorResponse) {
if (error.error instanceof ErrorEvent) {
// A client-side or network error occurred. Handle it accordingly.
console.error('An error occurred:', error.error.message);
} else {
// The backend returned an unsuccessful response code, The response body may contain clues as to what went wrong,
console.error( `Backend returned code ${error.status}, ` + `body was: ${error.error}`);
}
// return an observable with a user-facing error message
return throwError( error.error.message );
};

async loading() {
const loading = await this.loadingController.create({
duration: 3000,
message: 'Please wait...',
});
return await loading.present();
};

};













domingo, 17 de mayo de 2020

Parametros por Rutas


1.- Agregar en la ruta
  {
    path: 'follow/:idplan',
    loadChildren: () => import('./follow/follow.module').then( m => m.FollowPageModule)
  },

2. Obtener el dato en la ruta
import { Router, ActivatedRoute } from '@angular/router';

  constructor( private _router:ActivatedRoute ) { }

  ngOnInit() {
    console.log(this._router.snapshot.params.idplan);          
  }

domingo, 10 de mayo de 2020

Pipes ( search, pagination, order )

Referencias:

Librerias a instalar: 

 "ng2-filter-pipe": "^0.1.10",
 "ng2-order-pipe": "^0.1.5",
 "ngx-paginate": "^1.0.5",
 "ngx-pagination": "^3.0.1",

2. npm install

3. agregar en modulo shared components para exportar
// Pipes de filtrados para las busquedas
import { Ng2FilterPipeModule } from "ng2-filter-pipe";
import { NgxPaginationModule } from "ngx-pagination";
import { Ng2OrderModule } from "ng2-order-pipe";
import { FormsModule, ReactiveFormsModule } from "@angular/forms";
const pack_shared = [
                // BrowserModule,
                Ng2FilterPipeModule,
                NgxPaginationModule,
                Ng2OrderModule,
                NgxSpinnerModule,
                FormsModule,
                ReactiveFormsModule,
                HttpClientModule,
                ];
@NgModule({
  imports: [ IonicModule, CommonModule, RouterModule, pack_shared],
  declarations: [components],
  exports: [components, pack_shared],
  schemas: [CUSTOM_ELEMENTS_SCHEMA]
})
export class ComponentsModule {}



-------

4. agregar el modulo components
import { ComponentsModule } from '../components/components.module';
@NgModule({
  imports: [
    CommonModule,
    FormsModule,
    IonicModule,
    ReportsPageRoutingModule,
    ComponentsModule
  ],
  declarations: [ReportsPage, 
    AttentionComponent,
    BinnaclesComponent,
    MeasurementComponent,
    PatientTagsComponent, ]
})
export class ReportsPageModule {}


4. En el componente a usar, se debe crear un objeto con los mismos atributos que tiene un item de mi array de objetos 
ej. 
  public filter    = {
                      accion : "",  
                      user: {
                        username: ""
                      }                    
  };

Luego Crear el html y ponerle un ngModel asi
        <small class="text-muted form-text" >Acciones: </small>
        <select class="form-control" [(ngModel)]="filter.accion" >
          <option value=""  > - Todos - </option>
          <option *ngFor="let item of actionList"  [ngValue]="item"  >{{ item }}</option>
        </select>
  
        <small class="text-muted form-text" >Usuarios: </small>
        <select class="form-control" [(ngModel)]="filter.user.username" >
          <option value=""  > - Todos - </option>
          <option *ngFor="let item of userList"  [ngValue]="item.username"  >{{ item.username }}</option>
        </select>

5. Para finalizar se pone estas condiciones en el For de su listado y las cosas se filtran en tiempo real.
  <tbody>
        <tr *ngFor="let item of dataList | filterBy: filter | paginate:{ itemsPerPage: itemsPage, currentPage:pageActual }; let i=index;">
          <td>{{ (i+1) }}</td>
          <td>{{ item.accion }}</td>
          <td>{{ getUser(item) }}</td>
          <td>{{ item.created_at }}</td>
        </tr>
      </tbody>
























lunes, 4 de mayo de 2020

Rango de fecha

Referencia fechas: https://momentjs.com/docs/#/query/is-same-or-before/

Búsqueda por rango de fecha:

import:
import * as moment from 'moment';
declare var $:any;


crear html
<div style="display: inherit;" >

<div>
<small class="text-muted form-text" >Fecha inicio: </small>
<input class="form-control" id="f_ini" type="date">
</div>
<div>
<small class="text-muted form-text" >Fecha fin: </small>
<input class="form-control" id="f_end" type="date">
</div>
<div>
<ion-button style=" margin-top: 25px;" (click)="searchPlanning()" >
<ion-icon name="search" ></ion-icon>
</ion-button>
</div>
</div>


Función parametrisada getRango
//04-05-2020
getDateBetween( dataList:Array<any>, keyDate , f_ini , f_end ){
return dataList = dataList.filter(elemento=>
moment( elemento[keyDate] ).isBetween( f_ini , f_end ) );
};



Validacion de fechas
//04-05-2020
isValidRangeDate( f1,f2 ){
let isValid = false
if( (f1 && f1.trim() !== "" ) && (f2 && f2.trim() !== "" ))
if( ( moment(f1).isSameOrBefore( f2 ) ))//es f1<=f2 true
isValid = true;
return isValid;
}



Implementacion de funciones
//04-05-2020
searchPlanning(){
let f_ini = $("#f_ini").val();
let f_end = $("#f_end").val();
//filter date
if( this.isValidRangeDate( f_ini, f_end ) )
this.plannings = this.getDateBetween( this.planningsInit , "created_at" , f_ini, f_end );
else alert('Fechas incorrectas');
};























Help Utils

Problemas con el Background del modal de Bootstrap
Agregar esto al boton data-backdrop="false"
<button type="button" class="btn btn-danger danger" data-dismiss="modal" data-backdrop="false">Action</button>
Y para que no se cierre el modal con : data-backdrop="static"
en la primera linea del modal.


=================================================



import * as moment from 'moment';


calImc( altura, peso ){
var result = 0;
altura = Math.pow((altura/100), 2); //altura se eleva al cuadrado
result = (peso / altura); // resultado con decimales
result = Number(result.toFixed(1)); // resultado con 1 decimal
return result;
}


calcularEdad( birthdate ){
var nacimiento=moment(birthdate);
var hoy=moment();
var anios=hoy.diff(nacimiento,"years");
return anios;


Obtener el mayor y menor de un array
var measure = [80,50,30,100,99,1,250];
var p_max= Math.max.apply(null, measure );
var p_min= Math.min.apply(null, measure) ;